2021-05-28 19:50:16 +09:00
|
|
|
import { setTimeout } from 'timers'
|
|
|
|
import { promisify } from 'util'
|
|
|
|
|
2023-01-19 01:32:52 +09:00
|
|
|
import * as chalk from 'colorette'
|
2021-05-28 19:50:16 +09:00
|
|
|
import Dockerode from 'dockerode'
|
|
|
|
import prettyBytes from 'pretty-bytes'
|
|
|
|
|
|
|
|
const sleep = promisify(setTimeout)
|
|
|
|
|
|
|
|
const client = new Dockerode()
|
|
|
|
|
|
|
|
export async function createSuite(testFile, maxMemoryUsage) {
|
2022-10-02 13:23:35 +09:00
|
|
|
console.info(chalk.cyanBright(`Create container to test ${testFile}`))
|
2021-05-28 19:50:16 +09:00
|
|
|
|
|
|
|
const container = await client.createContainer({
|
|
|
|
Image: 'node:lts-slim',
|
2022-04-07 00:00:21 +09:00
|
|
|
Cmd: ['/bin/bash', '-c', `node --expose-gc memory-testing/${testFile}.mjs`],
|
2021-05-28 19:50:16 +09:00
|
|
|
AttachStdout: true,
|
|
|
|
AttachStderr: true,
|
|
|
|
Tty: true,
|
|
|
|
WorkingDir: '/napi-rs',
|
|
|
|
Env: ['MAX_OLD_SPACE_SIZE=256', 'FORCE_COLOR=1'],
|
|
|
|
HostConfig: {
|
|
|
|
Binds: [`${process.cwd()}:/napi-rs:rw`],
|
|
|
|
Memory: 256 * 1024 * 1024,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
console.info(chalk.cyanBright('Container created, starting ...'))
|
|
|
|
|
|
|
|
await container.start()
|
|
|
|
|
|
|
|
container.attach(
|
|
|
|
{ stream: true, stdout: true, stderr: true },
|
|
|
|
function (err, stream) {
|
|
|
|
if (err) {
|
|
|
|
console.error(err)
|
|
|
|
process.exit(1)
|
|
|
|
}
|
|
|
|
stream.pipe(process.stdout)
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
const stats = await container.stats()
|
|
|
|
|
2021-05-30 00:36:49 +09:00
|
|
|
let shouldAssertMemoryUsage = false
|
2022-12-28 23:28:47 +09:00
|
|
|
let initialMemoryUsage
|
|
|
|
await new Promise((resolve, reject) => {
|
|
|
|
const initialDate = Date.now()
|
2021-05-28 19:50:16 +09:00
|
|
|
stats.on('data', (d) => {
|
|
|
|
const { memory_stats } = JSON.parse(d.toString('utf8'))
|
2022-12-28 23:28:47 +09:00
|
|
|
if (Date.now() - initialDate > 10000 && !shouldAssertMemoryUsage) {
|
|
|
|
resolve()
|
|
|
|
initialMemoryUsage = memory_stats.usage
|
|
|
|
shouldAssertMemoryUsage = true
|
|
|
|
}
|
2021-05-30 00:36:49 +09:00
|
|
|
if (shouldAssertMemoryUsage && memory_stats?.usage) {
|
2021-05-28 19:50:16 +09:00
|
|
|
const memoryGrowth = memory_stats.usage - initialMemoryUsage
|
2022-12-28 23:28:47 +09:00
|
|
|
if (memoryGrowth > (maxMemoryUsage ?? initialMemoryUsage)) {
|
2021-05-28 19:50:16 +09:00
|
|
|
console.info(
|
|
|
|
chalk.redBright(
|
|
|
|
`Potential memory leak, memory growth: ${prettyBytes(
|
|
|
|
memoryGrowth,
|
|
|
|
)}`,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
process.exit(1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
stats.on('error', reject)
|
|
|
|
})
|
|
|
|
|
|
|
|
console.info(
|
|
|
|
chalk.red(`Initial memory usage: ${prettyBytes(initialMemoryUsage)}`),
|
|
|
|
)
|
|
|
|
|
|
|
|
await sleep(60000)
|
|
|
|
|
2022-10-02 12:14:52 +09:00
|
|
|
try {
|
|
|
|
await container.stop()
|
|
|
|
await container.remove()
|
|
|
|
} catch (e) {
|
|
|
|
console.error(e)
|
|
|
|
}
|
2021-05-28 19:50:16 +09:00
|
|
|
}
|