vitest-pool-assemblyscript 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"test-runner-B2BpyPNK.mjs","names":[],"sources":["../src/pool-thread/runner/test-runner.ts"],"sourcesContent":["/**\n * Worker thread test runner logic for AssemblyScript Pool\n */\n\nimport type { MessagePort } from 'node:worker_threads';\nimport type { File, Suite, Task, Test } from '@vitest/runner/types';\nimport type { SerializedDiffOptions } from '@vitest/utils/diff';\n\nimport type {\n AssemblyScriptConsoleLog,\n AssemblyScriptConsoleLogHandler,\n AssemblyScriptSuiteTaskMeta,\n AssemblyScriptTestTaskMeta,\n ResolvedAssemblyScriptPoolOptions,\n TestExecutionEnd,\n TestExecutionStart,\n ThreadImports,\n VitestVersion,\n WASMCompilation,\n WorkerRPC,\n} from '../../types/types.js';\nimport { AS_POOL_WORKER_MSG_FLAG } from '../../types/constants.js';\nimport { executeWASMTest } from '../../wasm-executor/index.js';\nimport { debug } from '../../util/debug.js';\nimport {\n reportTestPrepare,\n reportTestFinished,\n reportTestRetried,\n reportUserConsoleLogs,\n reportSuitePrepare,\n reportSuiteFinished,\n} from '../rpc-reporter.js';\nimport {\n checkFailsAndInvertResult,\n finalizeSuiteResult,\n flagTestFinalized,\n getRunnableTasks,\n getTaskLogPrefix,\n resetTestForRetry,\n setSuitePrepareResult,\n setTestResultForTestPrepare,\n shouldRetryTask,\n updateSuiteFinishedResult,\n updateTestResultAfterRun,\n isSuiteOwnFile\n} from '../../util/vitest-tasks.js';\nimport { mergeCoverageData } from '../../coverage-provider/coverage-merge.js';\n\nasync function bailIfNeeded(\n rpc: WorkerRPC,\n bailConfig: number | undefined,\n testWithResult: Test,\n logPrefix: string,\n logModule: string,\n): Promise<void> {\n if (bailConfig && testWithResult.result?.state !== 'pass') {\n const previousFailures = await rpc.getCountOfFailedTests();\n const currentFailures = 1 + previousFailures;\n\n if (currentFailures >= bailConfig) {\n debug(`${logPrefix} bailing: ${currentFailures} failures >= ${bailConfig} to bail`);\n debug(`[${logModule}] -------- BAIL! ${currentFailures} failures >= ${bailConfig} to bail --------`);\n return rpc.onCancel('test-failure');\n }\n }\n}\n\nasync function postProcessTestResult(\n rpc: WorkerRPC,\n bailConfig: number | undefined,\n testWithResult: Test,\n logPrefix: string,\n logModule: string,\n): Promise<void> {\n // invert result if test configured as 'fails'\n checkFailsAndInvertResult(testWithResult, logPrefix);\n\n // bail now if this is a failed test above bail threshold\n return bailIfNeeded(rpc, bailConfig, testWithResult, logPrefix, logModule);\n}\n\nfunction notifyTestStart(port: MessagePort, test: Test): void {\n port.postMessage({\n executionStart: Date.now(),\n test,\n type: 'execution-start',\n [AS_POOL_WORKER_MSG_FLAG]: true\n } satisfies TestExecutionStart);\n}\n\nfunction notifyTestEnd(port: MessagePort, test: Test): void {\n port.postMessage({\n executionEnd: Date.now(),\n testTaskId: test.id,\n type: 'execution-end',\n [AS_POOL_WORKER_MSG_FLAG]: true\n } satisfies TestExecutionEnd);\n}\n\nasync function runTest(\n rpc: WorkerRPC,\n port: MessagePort,\n base: string,\n collectCoverage: boolean,\n compilation: WASMCompilation,\n test: Test,\n logModule: string,\n poolOptions: ResolvedAssemblyScriptPoolOptions,\n threadImports: ThreadImports,\n bail?: number,\n diffOptions?: SerializedDiffOptions,\n): Promise<void> {\n const testLogPrefix = getTaskLogPrefix(logModule, base, test);\n const logMessages: AssemblyScriptConsoleLog[] = [];\n const handleLog: AssemblyScriptConsoleLogHandler = (msg: string, isError: boolean = false): void => {\n logMessages.push({ msg, time: Date.now(), isError });\n };\n\n const executionStart = Date.now();\n\n let thisRunIsARetry: boolean = false;\n let testPreparePromise: Promise<void> = Promise.resolve();\n \n if (!test.retry || !test.result) {\n debug(`${testLogPrefix} - Beginning test run`);\n\n // first/only attempt: create test result and report test-prepare\n setTestResultForTestPrepare(test, executionStart);\n testPreparePromise = reportTestPrepare(rpc, test, logModule, base);\n } else if (test.retry && test.result ) {\n debug(`${testLogPrefix} - Beginning test retry run`);\n thisRunIsARetry = true;\n\n // this is a retry, reset the result state and meta\n resetTestForRetry(test, executionStart);\n }\n \n // inform pool of test task start so it can enforce timeouts\n notifyTestStart(port, test);\n\n const [_reported, { testTimings }] = await Promise.all([\n testPreparePromise,\n executeWASMTest(\n test,\n compilation,\n base,\n poolOptions,\n collectCoverage,\n handleLog,\n logModule,\n threadImports,\n diffOptions\n )\n ]);\n\n // inform pool of test task end to stop timeout if under threshold\n notifyTestEnd(port, test);\n\n // update run->pass if appropriate, accumulate duration using executor timings\n updateTestResultAfterRun(test, testTimings);\n\n let willRetry = shouldRetryTask(test);\n\n await Promise.all([\n reportUserConsoleLogs(rpc, logMessages, logModule, base, test),\n\n willRetry ? reportTestRetried(rpc, test, logModule, base) : Promise.resolve(),\n ]);\n\n if (thisRunIsARetry) {\n debug(`${testLogPrefix} - Completed test retry run`);\n return;\n }\n\n // non-timeout retry handling\n while (willRetry) {\n // increment the retry count\n test.result!.retryCount = (test.result?.retryCount ?? 0) + 1;\n\n debug(`${testLogPrefix} - Retrying after failure`\n + ` | Retry ${test.result?.retryCount || 0} / ${test.retry} ` \n + ` | ${test.result?.errors?.length ?? 0} errors`\n );\n\n await runTest(\n rpc, port, base, collectCoverage, compilation,\n test, logModule, poolOptions, threadImports, bail, diffOptions\n );\n\n willRetry = shouldRetryTask(test);\n\n if (!willRetry) {\n debug(`${testLogPrefix} - Max retries ${test.result?.retryCount || 0} / ${test.retry} ` \n + ` | ${test.result?.errors?.length ?? 0} errors`\n );\n }\n }\n\n await Promise.all([\n // as needed: invert if `fails`, bail\n postProcessTestResult(rpc, bail, test, testLogPrefix, logModule),\n\n reportTestFinished(rpc, test, logModule, base),\n ]);\n\n // ensure completed test will not be run again if another test\n // times out later and the file worker thread gets re-launched\n flagTestFinalized(test);\n\n debug(`${testLogPrefix} - Completed test run`);\n}\n\nexport async function runSuite(\n rpc: WorkerRPC,\n port: MessagePort,\n base: string,\n collectCoverage: boolean,\n compilation: WASMCompilation,\n suite: Suite | File,\n logModule: string,\n poolOptions: ResolvedAssemblyScriptPoolOptions,\n threadImports: ThreadImports,\n vitestVersion: VitestVersion,\n bail?: number,\n diffOptions?: SerializedDiffOptions,\n timedOutTest?: Test,\n): Promise<Suite> {\n const suiteStart = performance.now();\n const suiteMeta = suite.meta as AssemblyScriptSuiteTaskMeta;\n const suiteLogPrefix = getTaskLogPrefix(logModule, base, suite);\n const isTimedOutTestInSuite: boolean = timedOutTest?.suite?.id === suite.id;\n\n if (suiteMeta.resultFinal) {\n debug(`${suiteLogPrefix} - Skipping completed suite | state: \"${suite.result?.state}\"`);\n\n return suite;\n } else {\n const threadRestartTime = Date.now() - ((timedOutTest?.meta as AssemblyScriptTestTaskMeta)?.lastTimeoutTerminationTime ?? 0);\n const showRestart = !!timedOutTest && isSuiteOwnFile(suite)\n debug(`${showRestart ? `(thread resumed in ${threadRestartTime} ms) ` : ''}${suiteLogPrefix} - runSuite ${!!timedOutTest\n ? `resuming after timeout \"${timedOutTest.name}\" | isTestInSuite: ${isTimedOutTestInSuite}`\n : 'beginning'\n }`);\n }\n\n if (!suiteMeta.suitePreparedSent) {\n setSuitePrepareResult(suite);\n await reportSuitePrepare(rpc, suite, logModule, base);\n\n // ensure suite-prepare will only be sent once if a test\n // times out and the file worker thread gets re-launched\n suiteMeta.suitePreparedSent = true;\n }\n\n // restore suite coverage collected so far from the timed out test, if provided.\n // otherwise create a suite-level coverage data object to aggregate all subtask coverage\n if (isTimedOutTestInSuite) {\n suiteMeta.coverageData = (timedOutTest!.suite!.meta as AssemblyScriptSuiteTaskMeta).coverageData;\n \n const coverageKeys: number = Object.keys(suiteMeta.coverageData ?? {}).length;\n debug(`${suiteLogPrefix} - Restored suite coverage data after timeout (${coverageKeys} unique positions)`);\n } {\n // initialize aggregated coverage data for suite, which gets updated as each subtask completes\n suiteMeta.coverageData = { hitCountsByFileAndPosition: {} };\n }\n\n let tasksToRun: Task[] = getRunnableTasks(suite);\n debug(`${suiteLogPrefix} - Runnable tasks:`, tasksToRun.length);\n\n for (const task of tasksToRun) {\n if (task.type === 'suite') {\n const suiteTaskMeta = task.meta as AssemblyScriptSuiteTaskMeta;\n\n await runSuite(\n rpc, port, base, collectCoverage, compilation, task, logModule,\n poolOptions, threadImports, vitestVersion, bail, diffOptions, timedOutTest\n );\n\n // merge suite task coverage into parent suite coverage\n if (suiteMeta.coverageData && suiteTaskMeta.coverageData) {\n mergeCoverageData(suiteMeta.coverageData, suiteTaskMeta.coverageData);\n }\n \n } else {\n const testLogPrefix = getTaskLogPrefix(logModule, base, task);\n const testTaskMeta = task.meta as AssemblyScriptTestTaskMeta;\n\n const testCompleted = testTaskMeta.resultFinal;\n const testTimedOutPreviously = !!timedOutTest && task.id === timedOutTest.id;\n\n if (testCompleted) {\n debug(`${testLogPrefix} - Skipping completed test | state: \"${task.result?.state}\"`);\n } else if (testTimedOutPreviously) {\n if (shouldRetryTask(task)) {\n const previousRetryCount = task.result?.retryCount ?? 0;\n const newRetryCount = previousRetryCount + 1;\n\n debug(`${testLogPrefix} - Retrying after test timeout`\n + ` | retry attempt ${newRetryCount} / ${task.retry} ` \n + ` | ${task.result?.errors?.length ?? 0} errors`\n + ` | state: \"${task.result?.state}\"`\n );\n \n // report retried for the previous timeout failure, which won't\n // have been reported because the thread was killed to timeout\n await reportTestRetried(rpc, task, logModule, base);\n\n // increment the retry count (after reporting retried)\n task.result!.retryCount = newRetryCount;\n \n // retry timed out test\n // - if it passes, process as normal\n // - if it fails again, it will end up in the else block below\n await runTest(\n rpc, port, base, collectCoverage, compilation,\n task, logModule, poolOptions, threadImports, bail, diffOptions\n );\n } else {\n debug(`${testLogPrefix} - Timed-out test has no retries left`\n + ` | retries attempted ${task.result?.retryCount || 0} / ${task.retry} ` \n + ` | ${task.result?.errors?.length ?? 0} errors`\n + ` | state: \"${task.result?.state}\"`\n );\n\n await Promise.all([\n // as needed: invert if `fails`, bail\n postProcessTestResult(rpc, bail, task, testLogPrefix, logModule),\n \n reportTestFinished(rpc, task, logModule, base),\n ]);\n\n // ensure completed test will not be run again if another test\n // times out later and the file worker thread gets re-launched\n flagTestFinalized(task);\n\n debug(`${testLogPrefix} - Completed timed out test run`);\n }\n } else {\n debug(`${testLogPrefix} - Running test task | state: \"${task.result?.state}\"`);\n await runTest(\n rpc, port, base, collectCoverage, compilation,\n task, logModule, poolOptions, threadImports, bail, diffOptions\n );\n }\n\n // merge test coverage into suite coverage\n if (suiteMeta.coverageData && testTaskMeta.coverageData) {\n mergeCoverageData(suiteMeta.coverageData, testTaskMeta.coverageData);\n }\n }\n }\n\n // update suite result based on its tasks, report coverage data, report suite task result\n updateSuiteFinishedResult(suite, suiteLogPrefix);\n await reportSuiteFinished(rpc, suite, logModule, base, vitestVersion);\n\n // ensure completed test will not be run again if another test\n // times out later and the file worker thread gets re-launched\n finalizeSuiteResult(suite);\n\n const suiteTime = performance.now() - suiteStart;\n debug(`${suiteLogPrefix} - Suite Run Complete | TIMING ${suiteTime.toFixed(2)} ms`);\n\n return suite;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"test-runner-BR4XyhMA.mjs","names":[],"sources":["../src/pool-thread/runner/test-runner.ts"],"sourcesContent":["/**\n * Worker thread test runner logic for AssemblyScript Pool\n */\n\nimport type { MessagePort } from 'node:worker_threads';\nimport type { File, Suite, Task, Test } from '@vitest/runner/types';\nimport type { SerializedDiffOptions } from '@vitest/utils/diff';\n\nimport type {\n AssemblyScriptConsoleLog,\n AssemblyScriptConsoleLogHandler,\n AssemblyScriptSuiteTaskMeta,\n AssemblyScriptTestTaskMeta,\n ResolvedAssemblyScriptPoolOptions,\n TestExecutionEnd,\n TestExecutionStart,\n ThreadImports,\n VitestVersion,\n WASMCompilation,\n WorkerRPC,\n} from '../../types/types.js';\nimport { AS_POOL_WORKER_MSG_FLAG } from '../../types/constants.js';\nimport { executeWASMTest } from '../../wasm-executor/index.js';\nimport { debug } from '../../util/debug.js';\nimport {\n reportTestPrepare,\n reportTestFinished,\n reportTestRetried,\n reportUserConsoleLogs,\n reportSuitePrepare,\n reportSuiteFinished,\n} from '../rpc-reporter.js';\nimport {\n checkFailsAndInvertResult,\n finalizeSuiteResult,\n flagTestFinalized,\n getRunnableTasks,\n getTaskLogPrefix,\n resetTestForRetry,\n setSuitePrepareResult,\n setTestResultForTestPrepare,\n shouldRetryTask,\n updateSuiteFinishedResult,\n updateTestResultAfterRun,\n isSuiteOwnFile\n} from '../../util/vitest-tasks.js';\nimport { mergeCoverageData } from '../../coverage-provider/coverage-merge.js';\n\nasync function bailIfNeeded(\n rpc: WorkerRPC,\n bailConfig: number | undefined,\n testWithResult: Test,\n logPrefix: string,\n logModule: string,\n): Promise<void> {\n if (bailConfig && testWithResult.result?.state !== 'pass') {\n const previousFailures = await rpc.getCountOfFailedTests();\n const currentFailures = 1 + previousFailures;\n\n if (currentFailures >= bailConfig) {\n debug(`${logPrefix} bailing: ${currentFailures} failures >= ${bailConfig} to bail`);\n debug(`[${logModule}] -------- BAIL! ${currentFailures} failures >= ${bailConfig} to bail --------`);\n return rpc.onCancel('test-failure');\n }\n }\n}\n\nasync function postProcessTestResult(\n rpc: WorkerRPC,\n bailConfig: number | undefined,\n testWithResult: Test,\n logPrefix: string,\n logModule: string,\n): Promise<void> {\n // invert result if test configured as 'fails'\n checkFailsAndInvertResult(testWithResult, logPrefix);\n\n // bail now if this is a failed test above bail threshold\n return bailIfNeeded(rpc, bailConfig, testWithResult, logPrefix, logModule);\n}\n\nfunction notifyTestStart(port: MessagePort, test: Test): void {\n port.postMessage({\n executionStart: Date.now(),\n test,\n type: 'execution-start',\n [AS_POOL_WORKER_MSG_FLAG]: true\n } satisfies TestExecutionStart);\n}\n\nfunction notifyTestEnd(port: MessagePort, test: Test): void {\n port.postMessage({\n executionEnd: Date.now(),\n testTaskId: test.id,\n type: 'execution-end',\n [AS_POOL_WORKER_MSG_FLAG]: true\n } satisfies TestExecutionEnd);\n}\n\nasync function runTest(\n rpc: WorkerRPC,\n port: MessagePort,\n base: string,\n collectCoverage: boolean,\n compilation: WASMCompilation,\n test: Test,\n logModule: string,\n poolOptions: ResolvedAssemblyScriptPoolOptions,\n threadImports: ThreadImports,\n bail?: number,\n diffOptions?: SerializedDiffOptions,\n): Promise<void> {\n const testLogPrefix = getTaskLogPrefix(logModule, base, test);\n const logMessages: AssemblyScriptConsoleLog[] = [];\n const handleLog: AssemblyScriptConsoleLogHandler = (msg: string, isError: boolean = false): void => {\n logMessages.push({ msg, time: Date.now(), isError });\n };\n\n const executionStart = Date.now();\n\n let thisRunIsARetry: boolean = false;\n let testPreparePromise: Promise<void> = Promise.resolve();\n \n if (!test.retry || !test.result) {\n debug(`${testLogPrefix} - Beginning test run`);\n\n // first/only attempt: create test result and report test-prepare\n setTestResultForTestPrepare(test, executionStart);\n testPreparePromise = reportTestPrepare(rpc, test, logModule, base);\n } else if (test.retry && test.result ) {\n debug(`${testLogPrefix} - Beginning test retry run`);\n thisRunIsARetry = true;\n\n // this is a retry, reset the result state and meta\n resetTestForRetry(test, executionStart);\n }\n \n // inform pool of test task start so it can enforce timeouts\n notifyTestStart(port, test);\n\n const [_reported, { testTimings }] = await Promise.all([\n testPreparePromise,\n executeWASMTest(\n test,\n compilation,\n base,\n poolOptions,\n collectCoverage,\n handleLog,\n logModule,\n threadImports,\n diffOptions\n )\n ]);\n\n // inform pool of test task end to stop timeout if under threshold\n notifyTestEnd(port, test);\n\n // update run->pass if appropriate, accumulate duration using executor timings\n updateTestResultAfterRun(test, testTimings);\n\n let willRetry = shouldRetryTask(test);\n\n await Promise.all([\n reportUserConsoleLogs(rpc, logMessages, logModule, base, test),\n\n willRetry ? reportTestRetried(rpc, test, logModule, base) : Promise.resolve(),\n ]);\n\n if (thisRunIsARetry) {\n debug(`${testLogPrefix} - Completed test retry run`);\n return;\n }\n\n // non-timeout retry handling\n while (willRetry) {\n // increment the retry count\n test.result!.retryCount = (test.result?.retryCount ?? 0) + 1;\n\n debug(`${testLogPrefix} - Retrying after failure`\n + ` | Retry ${test.result?.retryCount || 0} / ${test.retry} ` \n + ` | ${test.result?.errors?.length ?? 0} errors`\n );\n\n await runTest(\n rpc, port, base, collectCoverage, compilation,\n test, logModule, poolOptions, threadImports, bail, diffOptions\n );\n\n willRetry = shouldRetryTask(test);\n\n if (!willRetry) {\n debug(`${testLogPrefix} - Max retries ${test.result?.retryCount || 0} / ${test.retry} ` \n + ` | ${test.result?.errors?.length ?? 0} errors`\n );\n }\n }\n\n await Promise.all([\n // as needed: invert if `fails`, bail\n postProcessTestResult(rpc, bail, test, testLogPrefix, logModule),\n\n reportTestFinished(rpc, test, logModule, base),\n ]);\n\n // ensure completed test will not be run again if another test\n // times out later and the file worker thread gets re-launched\n flagTestFinalized(test);\n\n debug(`${testLogPrefix} - Completed test run`);\n}\n\nexport async function runSuite(\n rpc: WorkerRPC,\n port: MessagePort,\n base: string,\n collectCoverage: boolean,\n compilation: WASMCompilation,\n suite: Suite | File,\n logModule: string,\n poolOptions: ResolvedAssemblyScriptPoolOptions,\n threadImports: ThreadImports,\n vitestVersion: VitestVersion,\n bail?: number,\n diffOptions?: SerializedDiffOptions,\n timedOutTest?: Test,\n): Promise<Suite> {\n const suiteStart = performance.now();\n const suiteMeta = suite.meta as AssemblyScriptSuiteTaskMeta;\n const suiteLogPrefix = getTaskLogPrefix(logModule, base, suite);\n const isTimedOutTestInSuite: boolean = timedOutTest?.suite?.id === suite.id;\n\n if (suiteMeta.resultFinal) {\n debug(`${suiteLogPrefix} - Skipping completed suite | state: \"${suite.result?.state}\"`);\n\n return suite;\n } else {\n const threadRestartTime = Date.now() - ((timedOutTest?.meta as AssemblyScriptTestTaskMeta)?.lastTimeoutTerminationTime ?? 0);\n const showRestart = !!timedOutTest && isSuiteOwnFile(suite)\n debug(`${showRestart ? `(thread resumed in ${threadRestartTime} ms) ` : ''}${suiteLogPrefix} - runSuite ${!!timedOutTest\n ? `resuming after timeout \"${timedOutTest.name}\" | isTestInSuite: ${isTimedOutTestInSuite}`\n : 'beginning'\n }`);\n }\n\n if (!suiteMeta.suitePreparedSent) {\n setSuitePrepareResult(suite);\n await reportSuitePrepare(rpc, suite, logModule, base);\n\n // ensure suite-prepare will only be sent once if a test\n // times out and the file worker thread gets re-launched\n suiteMeta.suitePreparedSent = true;\n }\n\n // restore suite coverage collected so far from the timed out test, if provided.\n // otherwise create a suite-level coverage data object to aggregate all subtask coverage\n if (isTimedOutTestInSuite) {\n suiteMeta.coverageData = (timedOutTest!.suite!.meta as AssemblyScriptSuiteTaskMeta).coverageData;\n \n const coverageKeys: number = Object.keys(suiteMeta.coverageData ?? {}).length;\n debug(`${suiteLogPrefix} - Restored suite coverage data after timeout (${coverageKeys} unique positions)`);\n } {\n // initialize aggregated coverage data for suite, which gets updated as each subtask completes\n suiteMeta.coverageData = { hitCountsByFileAndPosition: {} };\n }\n\n let tasksToRun: Task[] = getRunnableTasks(suite);\n debug(`${suiteLogPrefix} - Runnable tasks:`, tasksToRun.length);\n\n for (const task of tasksToRun) {\n if (task.type === 'suite') {\n const suiteTaskMeta = task.meta as AssemblyScriptSuiteTaskMeta;\n\n await runSuite(\n rpc, port, base, collectCoverage, compilation, task, logModule,\n poolOptions, threadImports, vitestVersion, bail, diffOptions, timedOutTest\n );\n\n // merge suite task coverage into parent suite coverage\n if (suiteMeta.coverageData && suiteTaskMeta.coverageData) {\n mergeCoverageData(suiteMeta.coverageData, suiteTaskMeta.coverageData);\n }\n \n } else {\n const testLogPrefix = getTaskLogPrefix(logModule, base, task);\n const testTaskMeta = task.meta as AssemblyScriptTestTaskMeta;\n\n const testCompleted = testTaskMeta.resultFinal;\n const testTimedOutPreviously = !!timedOutTest && task.id === timedOutTest.id;\n\n if (testCompleted) {\n debug(`${testLogPrefix} - Skipping completed test | state: \"${task.result?.state}\"`);\n } else if (testTimedOutPreviously) {\n if (shouldRetryTask(task)) {\n const previousRetryCount = task.result?.retryCount ?? 0;\n const newRetryCount = previousRetryCount + 1;\n\n debug(`${testLogPrefix} - Retrying after test timeout`\n + ` | retry attempt ${newRetryCount} / ${task.retry} ` \n + ` | ${task.result?.errors?.length ?? 0} errors`\n + ` | state: \"${task.result?.state}\"`\n );\n \n // report retried for the previous timeout failure, which won't\n // have been reported because the thread was killed to timeout\n await reportTestRetried(rpc, task, logModule, base);\n\n // increment the retry count (after reporting retried)\n task.result!.retryCount = newRetryCount;\n \n // retry timed out test\n // - if it passes, process as normal\n // - if it fails again, it will end up in the else block below\n await runTest(\n rpc, port, base, collectCoverage, compilation,\n task, logModule, poolOptions, threadImports, bail, diffOptions\n );\n } else {\n debug(`${testLogPrefix} - Timed-out test has no retries left`\n + ` | retries attempted ${task.result?.retryCount || 0} / ${task.retry} ` \n + ` | ${task.result?.errors?.length ?? 0} errors`\n + ` | state: \"${task.result?.state}\"`\n );\n\n await Promise.all([\n // as needed: invert if `fails`, bail\n postProcessTestResult(rpc, bail, task, testLogPrefix, logModule),\n \n reportTestFinished(rpc, task, logModule, base),\n ]);\n\n // ensure completed test will not be run again if another test\n // times out later and the file worker thread gets re-launched\n flagTestFinalized(task);\n\n debug(`${testLogPrefix} - Completed timed out test run`);\n }\n } else {\n debug(`${testLogPrefix} - Running test task | state: \"${task.result?.state}\"`);\n await runTest(\n rpc, port, base, collectCoverage, compilation,\n task, logModule, poolOptions, threadImports, bail, diffOptions\n );\n }\n\n // merge test coverage into suite coverage\n if (suiteMeta.coverageData && testTaskMeta.coverageData) {\n mergeCoverageData(suiteMeta.coverageData, testTaskMeta.coverageData);\n }\n }\n }\n\n // update suite result based on its tasks, report coverage data, report suite task result\n updateSuiteFinishedResult(suite, suiteLogPrefix);\n await reportSuiteFinished(rpc, suite, logModule, base, vitestVersion);\n\n // ensure completed test will not be run again if another test\n // times out later and the file worker thread gets re-launched\n finalizeSuiteResult(suite);\n\n const suiteTime = performance.now() - suiteStart;\n debug(`${suiteLogPrefix} - Suite Run Complete | TIMING ${suiteTime.toFixed(2)} ms`);\n\n return suite;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,23 @@
1
1
  {
2
2
  "name": "vitest-pool-assemblyscript",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "AssemblyScript testing with Vitest - Simple, fast, familiar, AS-native, with full coverage output",
5
+ "author": "Matt Ritter <matthew.d.ritter@gmail.com>",
6
+ "license": "MIT",
7
+ "keywords": [
8
+ "assemblyscript",
9
+ "vitest",
10
+ "unit test",
11
+ "unit testing",
12
+ "webassembly",
13
+ "wasm",
14
+ "testing",
15
+ "testing framework",
16
+ "test runner",
17
+ "compile-to-wasm",
18
+ "custom pool",
19
+ "vitest plugin"
20
+ ],
5
21
  "type": "module",
6
22
  "main": "./dist/index.mjs",
7
23
  "types": "./dist/index.d.mts",
@@ -67,7 +83,7 @@
67
83
  "//------------ Native Addon ------------": "",
68
84
  "setup-binaryen": "node scripts/setup-binaryen.js",
69
85
  "build:native": "node-gyp rebuild",
70
- "build:prebuilds": "prebuildify --napi --strip --tag-libc",
86
+ "build:prebuild": "prebuildify --napi --strip --tag-libc",
71
87
  "install": "node scripts/install.js"
72
88
  },
73
89
  "dependencies": {
@@ -1,4 +1,5 @@
1
1
  import fs from 'fs';
2
+ import os from 'os';
2
3
  import path from 'path';
3
4
  import https from 'https';
4
5
  import { execSync } from 'child_process';
@@ -9,7 +10,9 @@ const BINARYEN_VERSION = fs.readFileSync(
9
10
  'utf8'
10
11
  ).trim();
11
12
 
12
- // Detect platform for prebuilt binaries
13
+ const IS_MACOS = process.platform === 'darwin';
14
+
15
+ // Detect platform for prebuilt binaries (non-macOS only)
13
16
  function detectPlatform() {
14
17
  const platform = process.platform;
15
18
  const arch = process.arch;
@@ -31,6 +34,36 @@ function detectPlatform() {
31
34
  }
32
35
  }
33
36
 
37
+ // Map Node.js arch to CMake OSX architecture identifier
38
+ function getCmakeOsxArch() {
39
+ if (process.arch === 'arm64') return 'arm64';
40
+ if (process.arch === 'x64') return 'x86_64';
41
+ throw new Error(`Unsupported macOS architecture: ${process.arch}`);
42
+ }
43
+
44
+ // Run a command quietly, but print its output if it fails
45
+ function execQuiet(command) {
46
+ try {
47
+ execSync(command, { stdio: 'pipe' });
48
+ } catch (err) {
49
+ const output = err.stderr?.toString() || err.stdout?.toString() || '';
50
+ if (output) {
51
+ console.error(output);
52
+ }
53
+ throw err;
54
+ }
55
+ }
56
+
57
+ // Check if a command is available on PATH
58
+ function isCommandAvailable(command) {
59
+ try {
60
+ execSync(`which ${command}`, { stdio: 'pipe' });
61
+ return true;
62
+ } catch {
63
+ return false;
64
+ }
65
+ }
66
+
34
67
  const PLATFORM = detectPlatform();
35
68
  const PREBUILT_URL = `https://github.com/WebAssembly/binaryen/releases/download/${BINARYEN_VERSION}/binaryen-${BINARYEN_VERSION}-${PLATFORM}.tar.gz`;
36
69
  const SOURCE_URL = `https://github.com/WebAssembly/binaryen/archive/refs/tags/${BINARYEN_VERSION}.tar.gz`;
@@ -42,88 +75,162 @@ const TEMP_DIR = path.join(THIRD_PARTY_DIR, 'binaryen-temp');
42
75
 
43
76
  console.log(`Setting up Binaryen ${BINARYEN_VERSION}...`);
44
77
  console.log(`Platform: ${PLATFORM}`);
78
+
79
+ if (IS_MACOS) {
80
+ console.log('macOS detected: will build static library from source');
81
+ }
82
+
45
83
  console.log('');
46
84
 
47
- // Step 1: Download prebuilt binaries
48
- console.log('Step 1: Downloading prebuilt binaries...');
49
- console.log(`URL: ${PREBUILT_URL}`);
50
- downloadFile(PREBUILT_URL, PREBUILT_ARCHIVE, () => {
51
- console.log('✓ Prebuilt binaries downloaded');
52
- console.log('');
85
+ if (IS_MACOS) {
86
+ // macOS: Build Binaryen from source to produce libbinaryen.a
87
+ // The official macOS prebuilt release only ships libbinaryen.dylib (shared),
88
+ // which cannot be statically linked into our .node addon. Building from source
89
+ // with BUILD_STATIC_LIB=ON produces the .a file our binding.gyp expects.
90
+ setupMacOS();
91
+ } else {
92
+ // Linux/Windows: Download prebuilt static library + source headers
93
+ setupWithPrebuilt();
94
+ }
53
95
 
54
- // Step 2: Download source code (for C++ headers)
55
- console.log('Step 2: Downloading source code for headers...');
96
+ // ---------------------------------------------------------------------------
97
+ // macOS: build from source
98
+ // ---------------------------------------------------------------------------
99
+
100
+ function setupMacOS() {
101
+ if (!isCommandAvailable('cmake')) {
102
+ console.error('Error: cmake is required to build Binaryen on macOS but was not found.');
103
+ console.error('Install it with: brew install cmake');
104
+ process.exit(1);
105
+ }
106
+
107
+ console.log('Step 1: Downloading source code...');
56
108
  console.log(`URL: ${SOURCE_URL}`);
57
109
  downloadFile(SOURCE_URL, SOURCE_ARCHIVE, () => {
58
110
  console.log('✓ Source code downloaded');
59
111
  console.log('');
60
-
61
- extractAndCombine();
112
+ extractAndBuildFromSource();
62
113
  });
63
- });
114
+ }
64
115
 
65
- function downloadFile(url, dest, callback) {
66
- const file = fs.createWriteStream(dest);
116
+ function extractAndBuildFromSource() {
117
+ console.log('Step 2: Extracting source code...');
67
118
 
68
- const handleResponse = (response) => {
69
- response.pipe(file);
70
- file.on('finish', () => {
71
- file.close(() => {
72
- response.destroy();
73
- callback();
74
- });
75
- });
76
- file.on('error', (err) => {
77
- response.destroy();
78
- if (fs.existsSync(dest)) {
79
- fs.unlinkSync(dest);
80
- }
81
- console.error(`File write failed: ${err.message}`);
82
- process.exit(1);
83
- });
84
- };
119
+ ensureCleanDirs();
85
120
 
86
- const request = https.get(url, (response) => {
87
- if (response.statusCode === 302 || response.statusCode === 301) {
88
- // Follow redirect
89
- response.destroy();
90
- const redirectRequest = https.get(response.headers.location, handleResponse);
91
- redirectRequest.on('error', (err) => {
92
- if (fs.existsSync(dest)) {
93
- fs.unlinkSync(dest);
94
- }
95
- console.error(`Download failed: ${err.message}`);
96
- process.exit(1);
97
- });
98
- } else {
99
- handleResponse(response);
121
+ try {
122
+ execSync(`tar -xzf "${SOURCE_ARCHIVE}" -C "${TEMP_DIR}"`, { stdio: 'pipe' });
123
+ const sourceDir = path.join(TEMP_DIR, `binaryen-${BINARYEN_VERSION}`);
124
+
125
+ if (!fs.existsSync(sourceDir)) {
126
+ throw new Error(`Expected source directory not found: ${sourceDir}`);
100
127
  }
101
- });
102
128
 
103
- request.on('error', (err) => {
104
- if (fs.existsSync(dest)) {
105
- fs.unlinkSync(dest);
129
+ console.log(' Source code extracted');
130
+ console.log('');
131
+
132
+ // Build static library with cmake
133
+ console.log('Step 3: Building static library with cmake...');
134
+
135
+ const buildDir = path.join(sourceDir, 'build');
136
+ const osxArch = getCmakeOsxArch();
137
+ const cpuCount = os.cpus().length;
138
+ const useNinja = isCommandAvailable('ninja');
139
+ const generatorArgs = useNinja ? ['-G', 'Ninja'] : [];
140
+
141
+ console.log(` Architecture: ${osxArch}`);
142
+ console.log(` Generator: ${useNinja ? 'Ninja' : 'Unix Makefiles (default)'}`);
143
+ console.log(` Parallel jobs: ${cpuCount}`);
144
+ console.log('');
145
+
146
+ // Configure
147
+ console.log(' Configuring...');
148
+ const configureArgs = [
149
+ 'cmake',
150
+ '-S', sourceDir,
151
+ '-B', buildDir,
152
+ ...generatorArgs,
153
+ '-DCMAKE_BUILD_TYPE=Release',
154
+ '-DBUILD_STATIC_LIB=ON',
155
+ '-DBUILD_TESTS=OFF',
156
+ '-DBUILD_TOOLS=OFF',
157
+ '-DENABLE_WERROR=OFF',
158
+ `-DCMAKE_OSX_ARCHITECTURES=${osxArch}`,
159
+ ];
160
+ execQuiet(configureArgs.join(' '));
161
+ console.log(' ✓ Configure complete');
162
+
163
+ // Build (only the binaryen library target, not CLI tools)
164
+ console.log(' Building (this may take several minutes)...');
165
+ execQuiet(`cmake --build "${buildDir}" --target binaryen -j${cpuCount}`);
166
+ console.log(' ✓ Build complete');
167
+ console.log('');
168
+
169
+ // Assemble third_party/binaryen/ with lib/ and src/
170
+ console.log('Step 4: Installing to third_party/binaryen/...');
171
+
172
+ fs.mkdirSync(BINARYEN_DIR, { recursive: true });
173
+
174
+ // Copy static library
175
+ const builtLib = path.join(buildDir, 'lib', 'libbinaryen.a');
176
+ if (!fs.existsSync(builtLib)) {
177
+ throw new Error(`Built static library not found at ${builtLib}`);
106
178
  }
107
- console.error(`Download failed: ${err.message}`);
179
+ const destLibDir = path.join(BINARYEN_DIR, 'lib');
180
+ fs.mkdirSync(destLibDir, { recursive: true });
181
+ fs.cpSync(builtLib, path.join(destLibDir, 'libbinaryen.a'));
182
+ console.log(' ✓ Copied libbinaryen.a');
183
+
184
+ // Copy C++ headers from source
185
+ const sourceSrcDir = path.join(sourceDir, 'src');
186
+ const destSrcDir = path.join(BINARYEN_DIR, 'src');
187
+ if (fs.existsSync(sourceSrcDir)) {
188
+ fs.cpSync(sourceSrcDir, destSrcDir, { recursive: true });
189
+ console.log(' ✓ Copied C++ headers');
190
+ } else {
191
+ throw new Error('Source src/ directory not found');
192
+ }
193
+
194
+ // Clean up
195
+ console.log(' Cleaning up...');
196
+ fs.rmSync(TEMP_DIR, { recursive: true, force: true });
197
+ fs.unlinkSync(SOURCE_ARCHIVE);
198
+
199
+ printResult();
200
+ } catch (err) {
201
+ console.error('macOS source build failed:', err.message);
202
+ console.error('Ensure cmake is installed: brew install cmake');
203
+ console.error('For faster builds, also install ninja: brew install ninja');
108
204
  process.exit(1);
205
+ }
206
+ }
207
+
208
+ // ---------------------------------------------------------------------------
209
+ // Linux/Windows: download prebuilt static library + source headers
210
+ // ---------------------------------------------------------------------------
211
+
212
+ function setupWithPrebuilt() {
213
+ console.log('Step 1: Downloading prebuilt binaries...');
214
+ console.log(`URL: ${PREBUILT_URL}`);
215
+ downloadFile(PREBUILT_URL, PREBUILT_ARCHIVE, () => {
216
+ console.log('✓ Prebuilt binaries downloaded');
217
+ console.log('');
218
+
219
+ console.log('Step 2: Downloading source code for headers...');
220
+ console.log(`URL: ${SOURCE_URL}`);
221
+ downloadFile(SOURCE_URL, SOURCE_ARCHIVE, () => {
222
+ console.log('✓ Source code downloaded');
223
+ console.log('');
224
+
225
+ extractAndCombine();
226
+ });
109
227
  });
110
228
  }
111
229
 
112
230
  function extractAndCombine() {
113
231
  console.log('Step 3: Extracting and combining...');
114
232
 
115
- // Create directories
116
- if (!fs.existsSync(THIRD_PARTY_DIR)) {
117
- fs.mkdirSync(THIRD_PARTY_DIR, { recursive: true });
118
- }
119
- if (!fs.existsSync(TEMP_DIR)) {
120
- fs.mkdirSync(TEMP_DIR, { recursive: true });
121
- }
122
-
123
- // Remove existing binaryen directory if it exists
124
- if (fs.existsSync(BINARYEN_DIR)) {
125
- fs.rmSync(BINARYEN_DIR, { recursive: true, force: true });
126
- }
233
+ ensureCleanDirs();
127
234
 
128
235
  try {
129
236
  // Extract prebuilt binaries
@@ -154,26 +261,93 @@ function extractAndCombine() {
154
261
  fs.unlinkSync(PREBUILT_ARCHIVE);
155
262
  fs.unlinkSync(SOURCE_ARCHIVE);
156
263
 
157
- console.log('');
158
- console.log(`✓ Binaryen ${BINARYEN_VERSION} installed to third_party/binaryen`);
159
- console.log('');
160
- console.log('Contents:');
161
- const contents = fs.readdirSync(BINARYEN_DIR);
162
- console.log(contents.map(f => ` ${f}`).join('\n'));
163
-
164
- const libDir = path.join(BINARYEN_DIR, 'lib');
165
- if (fs.existsSync(libDir)) {
166
- console.log('');
167
- console.log('Library files:');
168
- const libFiles = fs.readdirSync(libDir);
169
- console.log(libFiles.map(f => ` ${f}`).join('\n'));
170
- }
171
-
172
- console.log('');
173
- console.log('Setup complete!');
264
+ printResult();
174
265
  } catch (err) {
175
266
  console.error('Extraction/combination failed:', err.message);
176
267
  console.error('Make sure tar is available on your system.');
177
268
  process.exit(1);
178
269
  }
179
270
  }
271
+
272
+ // ---------------------------------------------------------------------------
273
+ // Shared helpers
274
+ // ---------------------------------------------------------------------------
275
+
276
+ function ensureCleanDirs() {
277
+ if (!fs.existsSync(THIRD_PARTY_DIR)) {
278
+ fs.mkdirSync(THIRD_PARTY_DIR, { recursive: true });
279
+ }
280
+ if (!fs.existsSync(TEMP_DIR)) {
281
+ fs.mkdirSync(TEMP_DIR, { recursive: true });
282
+ }
283
+ if (fs.existsSync(BINARYEN_DIR)) {
284
+ fs.rmSync(BINARYEN_DIR, { recursive: true, force: true });
285
+ }
286
+ }
287
+
288
+ function printResult() {
289
+ console.log('');
290
+ console.log(`✓ Binaryen ${BINARYEN_VERSION} installed to third_party/binaryen`);
291
+ console.log('');
292
+ console.log('Contents:');
293
+ const contents = fs.readdirSync(BINARYEN_DIR);
294
+ console.log(contents.map(f => ` ${f}`).join('\n'));
295
+
296
+ const libDir = path.join(BINARYEN_DIR, 'lib');
297
+ if (fs.existsSync(libDir)) {
298
+ console.log('');
299
+ console.log('Library files:');
300
+ const libFiles = fs.readdirSync(libDir);
301
+ console.log(libFiles.map(f => ` ${f}`).join('\n'));
302
+ }
303
+
304
+ console.log('');
305
+ console.log('Setup complete!');
306
+ }
307
+
308
+ function downloadFile(url, dest, callback) {
309
+ const file = fs.createWriteStream(dest);
310
+
311
+ const handleResponse = (response) => {
312
+ response.pipe(file);
313
+ file.on('finish', () => {
314
+ file.close(() => {
315
+ response.destroy();
316
+ callback();
317
+ });
318
+ });
319
+ file.on('error', (err) => {
320
+ response.destroy();
321
+ if (fs.existsSync(dest)) {
322
+ fs.unlinkSync(dest);
323
+ }
324
+ console.error(`File write failed: ${err.message}`);
325
+ process.exit(1);
326
+ });
327
+ };
328
+
329
+ const request = https.get(url, (response) => {
330
+ if (response.statusCode === 302 || response.statusCode === 301) {
331
+ // Follow redirect
332
+ response.destroy();
333
+ const redirectRequest = https.get(response.headers.location, handleResponse);
334
+ redirectRequest.on('error', (err) => {
335
+ if (fs.existsSync(dest)) {
336
+ fs.unlinkSync(dest);
337
+ }
338
+ console.error(`Download failed: ${err.message}`);
339
+ process.exit(1);
340
+ });
341
+ } else {
342
+ handleResponse(response);
343
+ }
344
+ });
345
+
346
+ request.on('error', (err) => {
347
+ if (fs.existsSync(dest)) {
348
+ fs.unlinkSync(dest);
349
+ }
350
+ console.error(`Download failed: ${err.message}`);
351
+ process.exit(1);
352
+ });
353
+ }
@@ -258,7 +258,7 @@ SourceDebugLocation getRepresentativeLocationInBlockBody(
258
258
  Block* blockBody,
259
259
  const std::unordered_map<wasm::Expression*, std::optional<wasm::Function::DebugLocation>> debugLocations
260
260
  ) {
261
- SourceDebugLocation repLoc = { exists: false, fileIndex: 0, lineNumber: 0, columnNumber: 0 };
261
+ SourceDebugLocation repLoc = { .exists = false, .fileIndex = 0, .lineNumber = 0, .columnNumber = 0 };
262
262
 
263
263
  if (DEBUG) {
264
264
  std::cout << LOG_PREFIX << " - Checking func Block body: " << blockBody->list.size() << " body expressions" << std::endl;
@@ -296,7 +296,7 @@ SourceDebugLocation getRepresentativeLocationInBlockBody(
296
296
  }
297
297
 
298
298
  SourceDebugLocation getRepresentativeLocation(Function* func) {
299
- SourceDebugLocation repLoc = { exists: false, fileIndex: 0, lineNumber: 0, columnNumber: 0 };
299
+ SourceDebugLocation repLoc = { .exists = false, .fileIndex = 0, .lineNumber = 0, .columnNumber = 0 };
300
300
 
301
301
  // Get body expression debug location
302
302
  Expression* body = func->body;
@@ -1 +0,0 @@
1
- {"version":3,"file":"pool-runner-init-d5qScS41.mjs","names":[],"sources":["../src/pool/pool-worker.ts","../src/pool/pool-runner-init.ts"],"sourcesContent":["import { availableParallelism } from 'node:os';\nimport { resolve } from 'node:path';\nimport { access } from 'node:fs/promises';\nimport type { MessagePort } from 'node:worker_threads';\nimport type { Test } from '@vitest/runner/types';\nimport type { SerializedConfig } from 'vitest';\nimport type { PoolWorker, PoolOptions, WorkerRequest, PoolTask, WorkerResponse } from 'vitest/node';\nimport Tinypool from 'tinypool';\n\nimport type {\n AssemblyScriptPoolWorkerMessage,\n ResolvedAssemblyScriptPoolOptions,\n ResolvedHybridProviderOptions,\n RunCompileAndDiscoverTask,\n RunTestsTask,\n TestExecutionEnd,\n TestExecutionStart,\n TestRunRecord,\n ThreadSpec,\n WorkerThreadInitData,\n} from '../types/types.js';\nimport { createInitialFileTask } from '../util/vitest-file-tasks.js';\nimport { failTestWithTimeoutError, flagTestTerminated } from '../util/vitest-tasks.js';\nimport {\n AS_POOL_WORKER_MSG_FLAG,\n ASSEMBLYSCRIPT_POOL_NAME,\n POOL_ERROR_NAMES,\n VITEST_WORKER_RESPONSE_MSG_FLAG\n} from '../types/constants.js';\nimport { debug, setGlobalDebugMode } from '../util/debug.js';\nimport { createPoolError, createPoolErrorFromAnyError, isAbortError } from '../util/pool-errors.js';\nimport { createWorkerRPCChannel } from './worker-rpc-channel.js';\n\ntype GlobalThreadPools = { compilePool: Tinypool, runPool: Tinypool };\ntype EventCallback = (arg: any) => void;\n\nconst THREAD_RESOLVE_TIMEOUT_MS = 2000 as const;\nconst POOL_THREAD_IDLE_TIMEOUT_MS = 3_600_000 as const;\nconst IDLE_RUN_THREADS_FACTOR = 1 as const;\n// @ts-ignore - see note in getGlobalThreadPools\nconst IDLE_COMPILE_THREADS_FACTOR = 0.25 as const;\n\n// path assumes that we're running from dist/\nconst COMPILE_WORKER_PATH = resolve(import.meta.dirname, 'pool-thread/compile-worker-thread.mjs');\nconst TEST_WORKER_PATH = resolve(import.meta.dirname, 'pool-thread/test-worker-thread.mjs');\n\nvar GLOBAL_POOLS_PROMISE: Promise<GlobalThreadPools> | undefined;\nvar GLOBAL_POOL_ABORT_CONTROLLER: AbortController | undefined;\nvar GLOBAL_RUNNING_POOLWORKER_COUNT: number = 0;\n\nexport class AssemblyScriptPoolWorker implements PoolWorker {\n readonly logModule = 'PoolWorker' as const;\n readonly name: typeof ASSEMBLYSCRIPT_POOL_NAME = ASSEMBLYSCRIPT_POOL_NAME;\n readonly poolOptions: PoolOptions;\n readonly asPoolOptions: ResolvedAssemblyScriptPoolOptions;\n readonly asCoverageOptions: ResolvedHybridProviderOptions;\n\n // for the currently running thread preforming a test run (if any)\n private threadAbortController: AbortController | undefined;\n private threadControlPort: MessagePort | undefined;\n private threadRunPromise: Promise<void> | undefined;\n\n private threadSpecs: ThreadSpec[] = [];\n \n // cached data for possible timeout resume\n private currentTestRun: TestRunRecord | undefined;\n \n // for this particular PoolWorker instance (1 per `maxWorkers`)\n private currentWorkerId: number | undefined;\n private isWorkerRunning: boolean = false;\n private config: SerializedConfig | undefined; // provided with \"start\" message\n\n // registry holding vitest callbacks so we can communicate on behalf of the worker thread\n private listenerRegistry: Map<string, Set<EventCallback>>;\n\n constructor(\n options: PoolOptions,\n resolvedUserPoolOptions: ResolvedAssemblyScriptPoolOptions,\n resolvedCoverageOptions: ResolvedHybridProviderOptions,\n ) {\n const start = performance.now();\n\n this.poolOptions = options;\n this.asPoolOptions = resolvedUserPoolOptions;\n this.asCoverageOptions = resolvedCoverageOptions;\n this.listenerRegistry = new Map<string, Set<EventCallback>>();\n\n setImmediate(async () => {\n const userImportsFactoryPath = resolve(\n this.poolOptions.project.config.root,\n this.asPoolOptions.wasmImportsFactory ?? ''\n );\n\n const results = await Promise.allSettled([\n access(COMPILE_WORKER_PATH),\n access(TEST_WORKER_PATH),\n this.asPoolOptions.wasmImportsFactory ? access(userImportsFactoryPath) : Promise.resolve()\n ]);\n\n const failedThreadAccess: string[] = [];\n if (results[0].status === 'rejected') failedThreadAccess.push(COMPILE_WORKER_PATH);\n if (results[1].status === 'rejected') failedThreadAccess.push(TEST_WORKER_PATH);\n\n if (failedThreadAccess.length) {\n throw new Error(`Cannot access worker thread file(s) at path(s): ${failedThreadAccess}`);\n }\n if (results[2].status === 'rejected') {\n throw new Error(`Cannot access user WasmImportsFactory at path: \"${userImportsFactoryPath}\".`\n + ` Ensure that your module path is relative to the project root (location of shallowest vitest config),`\n + ` and that it has a default export matching () => WebAssembly.Imports`\n );\n }\n });\n \n setGlobalDebugMode(this.asPoolOptions.debug);\n\n debug(`[${this.logModule}] Created AssemblyScriptPoolWorker in ${(performance.now() - start).toFixed(2)} ms`\n + ` | method: \"${this.poolOptions.method}\" | project: \"${this.poolOptions.project.name}\"`\n );\n }\n\n private get isCollectTestsMode(): boolean {\n return this.poolOptions.method === 'collect';\n }\n\n async start(): Promise<void> {\n // do all work in send() message intercept handler so we have access to the config\n }\n\n async stop(): Promise<void> {\n debug(`[${this.logModuleWithId}] stop | running PoolWorker count: ${GLOBAL_RUNNING_POOLWORKER_COUNT}`);\n\n this.listenerRegistry.clear();\n GLOBAL_RUNNING_POOLWORKER_COUNT--;\n this.isWorkerRunning = false;\n\n debug(`[${this.logModuleWithId}] AssemblyScriptPoolWorker STOPPED | running PoolWorker count: ${GLOBAL_RUNNING_POOLWORKER_COUNT}`);\n this.currentWorkerId = undefined;\n }\n\n send(message: WorkerRequest): void {\n switch(message.type) {\n \n // this happens AFTER start() is called (start() is for PoolWorker, \"start\" is for thread)\n case 'start':\n this.currentWorkerId = message.workerId;\n this.config = message.context.config;\n debug(`[${this.logModuleWithId}] send: vitest sent \"start\" message | Captured workerId and config`);\n\n setImmediate(async () => {\n const start = performance.now();\n const { compilePool, runPool } = await this.getGlobalThreadPools(this.config?.maxWorkers);\n \n debug(`[${this.logModuleWithId}] start: fetched global thread pools in ${(performance.now() - start).toFixed(2)} ms`\n + ` | compilePool queueSize: ${compilePool.queueSize} | runPool queueSize: ${runPool.queueSize}`\n );\n \n this.isWorkerRunning = true;\n GLOBAL_RUNNING_POOLWORKER_COUNT++;\n debug(`[${this.logModuleWithId}] start | new running PoolWorker count: ${GLOBAL_RUNNING_POOLWORKER_COUNT}`);\n \n this.notifyVitest('started');\n debug(`[${this.logModuleWithId}] send: responded \"started\" to vitest`);\n });\n \n break;\n \n // this happens BEFORE stop() is called (stop() is for PoolWorker, \"stop\" is for thread)\n case 'stop':\n setImmediate(async () => {\n await this.stopThread();\n this.notifyVitest('stopped');\n });\n break;\n \n case 'cancel':\n debug(`[${this.logModuleWithId}] send: got \"cancel\" unexpectedly`, message);\n break;\n \n case 'collect':\n case 'run':\n this.currentWorkerId = message.context.workerId;\n this.threadSpecs = message.context.files.map((fileSpec): ThreadSpec => ({\n file: createInitialFileTask(\n fileSpec.filepath,\n this.config!.name ?? '',\n this.config!.root,\n this.config!.testTimeout,\n this.config!.retry\n )\n }));\n\n debug(`[${this.logModuleWithId}] send: vitest sent \"${message.type}\" message`\n + ` | files: \"${this.threadSpecs.map(s => s.file.filepath).join(',')}\"`\n );\n\n setImmediate(async () => {\n debug(`[${this.logModuleWithId}] send: dispatched \"${message.type}\" job to worker thread`\n + ` | files: \"${this.threadSpecs.map(s => s.file.filepath).join(',')}\"`\n );\n \n this.threadRunPromise = this.orchestrateFileRuns();\n\n try {\n await this.threadRunPromise;\n this.notifyVitest('testfileFinished');\n debug(`[${this.logModuleWithId}] send: responded \"testfileFinished\" to vitest`\n + ` | files: \"${this.threadSpecs.map(s => s.file.filepath).join(',')}\"`\n );\n\n this.threadSpecs = [];\n } catch (error) {\n if (!isAbortError(error)) {\n throw createPoolErrorFromAnyError(`PoolWorker send() \"${message.type}\"`, POOL_ERROR_NAMES.PoolError, error);\n }\n } finally {\n this.threadControlPort?.close();\n this.threadAbortController = undefined;\n this.threadControlPort = undefined;\n this.threadRunPromise = undefined;\n }\n });\n break;\n }\n }\n\n on(event: string, callback: EventCallback): void {\n this.addEventCallback(event, callback);\n debug(`[${this.logModuleWithId}] ON \"${event}\" - saved listener`);\n }\n\n off(event: string, callback: EventCallback): void {\n if (this.removeEventCallback(event, callback)) {\n debug(`[${this.logModuleWithId}] OFF \"${event}\" - removed callback from registry`);\n } else {\n debug(`[${this.logModuleWithId}] OFF \"${event}\" - callback not found in registry`);\n }\n }\n\n deserialize(data: unknown): unknown {\n return data;\n }\n\n canReuse(_task: PoolTask): boolean {\n return true;\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Thread Pool Management\n // ─────────────────────────────────────────────────────────────────────────────\n\n private async getGlobalThreadPools(workerCount?: number): Promise<GlobalThreadPools> {\n if (GLOBAL_POOLS_PROMISE) {\n return GLOBAL_POOLS_PROMISE;\n }\n\n GLOBAL_POOLS_PROMISE = new Promise<GlobalThreadPools>(async (resolve, _reject) => {\n const workers = workerCount ?? availableParallelism();\n\n // TODO - decide which is better when scaling\n // Empirical observations seem to show that minimum parallelization for compilation\n // tends to *dramatically* improve compilation times because of v8 warmpup on repeated calls to asc.main,\n // so much so that this time savings **almost always** outweighs the benefits of speading over many\n // available threads. The **almost** is the key word here- this needs to be tested on platforms with\n // higher available paralellism (> 8) to see if it holds true.\n const actualCompileThreadCount = workers > 1 ? 2 : 1;\n // const actualCompileThreadCount = Math.max(Math.ceil(workers * IDLE_COMPILE_THREADS_FACTOR), 1);\n\n debug(`[${this.logModuleWithId}] Creating global compile thread pool | ${actualCompileThreadCount} threads`);\n \n const start = performance.now();\n \n const compilePool = new Tinypool({\n filename: COMPILE_WORKER_PATH,\n minThreads: 1,\n maxThreads: actualCompileThreadCount,\n isolateWorkers: false,\n idleTimeout: POOL_THREAD_IDLE_TIMEOUT_MS,\n env: this.poolOptions.env as Record<string, string>,\n execArgv: this.poolOptions.execArgv,\n workerData: {\n asPoolOptions: this.asPoolOptions,\n asCoverageOptions: this.asCoverageOptions,\n projectRoot: this.poolOptions.project.config.root,\n } satisfies WorkerThreadInitData\n });\n\n const actualRunThreadCount = Math.max(Math.ceil(workers * IDLE_RUN_THREADS_FACTOR), 1);\n debug(`[${this.logModuleWithId}] Creating global run thread pool | ${actualRunThreadCount} threads`);\n\n const runPool = new Tinypool({\n filename: TEST_WORKER_PATH,\n minThreads: 1,\n maxThreads: actualRunThreadCount,\n isolateWorkers: false,\n idleTimeout: POOL_THREAD_IDLE_TIMEOUT_MS,\n env: this.poolOptions.env as Record<string, string>,\n execArgv: this.poolOptions.execArgv,\n workerData: {\n asPoolOptions: this.asPoolOptions,\n asCoverageOptions: this.asCoverageOptions,\n projectRoot: this.poolOptions.project.config.root\n } satisfies WorkerThreadInitData\n });\n\n debug(`[${this.logModuleWithId}] Created global thread pools in ${(performance.now() - start).toFixed(2)} ms`);\n\n GLOBAL_POOL_ABORT_CONTROLLER = new AbortController();\n resolve({ compilePool, runPool });\n });\n \n return GLOBAL_POOLS_PROMISE;\n }\n\n // @ts-ignore\n private async destroyGlobalPoolsIfNeeded(): Promise<void> {\n if (GLOBAL_RUNNING_POOLWORKER_COUNT === 0 && GLOBAL_POOLS_PROMISE) {\n const destroyStart = performance.now();\n debug(`[${this.logModuleWithId}] Destroying Tinypools...`);\n\n try {\n const { compilePool, runPool } = await GLOBAL_POOLS_PROMISE;\n await Promise.all([ compilePool.destroy(), runPool.destroy() ]);\n } catch {}\n\n GLOBAL_POOLS_PROMISE = undefined;\n GLOBAL_POOL_ABORT_CONTROLLER = undefined;\n\n debug(`[${this.logModuleWithId}] Destroyed tinypools in ${(performance.now() - destroyStart).toFixed(2)} ms`);\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Listener Registry Helpers\n // ─────────────────────────────────────────────────────────────────────────────\n\n private getEventCallbacks(event: string): Set<EventCallback> {\n let callbacks: Set<EventCallback> | undefined = this.listenerRegistry.get(event);\n if (!callbacks) {\n callbacks = new Set<EventCallback>();\n this.listenerRegistry.set(event, callbacks);\n }\n return callbacks;\n }\n\n private addEventCallback(event: string, callback: EventCallback): void {\n this.getEventCallbacks(event).add(callback);\n }\n \n private removeEventCallback(event: string, callback: EventCallback): boolean {\n const callbacks = this.getEventCallbacks(event);\n if (callbacks) {\n return callbacks.delete(callback);\n } else {\n return false;\n }\n }\n\n private notifyVitest(responseType: WorkerResponse['type']): void {\n const messageCallbacks = this.getEventCallbacks('message');\n for (const cb of messageCallbacks) {\n cb({ type: responseType, [VITEST_WORKER_RESPONSE_MSG_FLAG]: true } satisfies WorkerResponse)\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Worker Thread Control/Orchestration\n // ─────────────────────────────────────────────────────────────────────────────\n \n private async dispatchCompile(\n spec: ThreadSpec,\n compilePool: Tinypool,\n ): Promise<void> {\n const { workerPort, poolPort } = createWorkerRPCChannel(this.poolOptions.project, this.isCollectTestsMode);\n this.threadControlPort = poolPort;\n \n const compilePromise: Promise<ThreadSpec> = compilePool.run({\n dispatchStart: Date.now(),\n workerId: this.currentWorkerId!,\n port: workerPort,\n file: spec.file,\n config: this.config!,\n isCollectTestsMode: this.isCollectTestsMode,\n } satisfies RunCompileAndDiscoverTask, {\n name: 'runCompileAndDisoverSpec',\n transferList: [workerPort],\n signal: GLOBAL_POOL_ABORT_CONTROLLER!.signal,\n });\n\n try {\n const { compilation, file } = await compilePromise;\n spec.file = file;\n spec.compilation = compilation;\n } finally {\n this.threadControlPort.close();\n this.threadControlPort = undefined;\n }\n }\n \n private async dispatchRunTests(\n spec: ThreadSpec,\n runPool: Tinypool,\n timedOutTest?: Test,\n ): Promise<void> {\n const { workerPort, poolPort } = createWorkerRPCChannel(this.poolOptions.project, this.isCollectTestsMode);\n \n this.threadAbortController = new AbortController();\n this.threadControlPort = poolPort;\n this.threadControlPort.on('message', this.getWorkerThreadMessageHandler());\n\n const runPromise: Promise<void> = !spec.compilation ? Promise.resolve() : runPool.run({\n dispatchStart: Date.now(),\n workerId: this.currentWorkerId!,\n port: workerPort,\n file: timedOutTest?.file ?? spec.file,\n compilation: spec.compilation,\n config: this.config!,\n isCollectTestsMode: this.isCollectTestsMode,\n timedOutTest,\n } satisfies RunTestsTask, {\n name: 'runFileSpec',\n transferList: [workerPort],\n signal: AbortSignal.any([this.threadAbortController.signal, GLOBAL_POOL_ABORT_CONTROLLER!.signal]),\n });\n\n try {\n return await runPromise;\n } finally {\n this.threadControlPort.close();\n this.threadControlPort = undefined;\n }\n }\n\n private async orchestrateFileRuns(timedOutTest?: Test): Promise<void> {\n const modeStr = this.isCollectTestsMode ? 'collectTests' : 'runTests';\n const isResume: boolean = !!timedOutTest;\n const desc = `${modeStr} ${isResume ? '(RESUME)' : '(INITIAL)'}`;\n\n debug(`[${this.logModuleWithId}] orchestrateFileRuns: dispatching ${desc} to worker thread`\n + ` | files: \"${this.threadSpecs.map(s => s.file.filepath).join(',')}\"`\n );\n\n const { compilePool, runPool } = await this.getGlobalThreadPools(this.config?.maxWorkers);\n\n // compile\n if (!isResume) {\n await Promise.all(\n this.threadSpecs.map(spec => this.dispatchCompile(spec, compilePool))\n );\n }\n\n // test\n if (!this.isCollectTestsMode) {\n await Promise.all(\n this.threadSpecs.map(spec => this.dispatchRunTests(spec, runPool, timedOutTest))\n );\n }\n\n debug(`[${this.logModuleWithId}] orchestrateFileRuns: ${desc} thread work complete`\n + ` | files: \"${this.threadSpecs.map(s => s.file.filepath).join(',')}\"`\n );\n }\n\n private async stopThread(): Promise<void> {\n this.clearTestTimeoutTimer(); // if any\n this.currentTestRun = undefined;\n \n const mod = this.logModuleWithId;\n const start = performance.now();\n\n debug('setting graceful resolve timeout');\n const abortTimeout = setTimeout(() => {\n debug(`[${mod}] stop: timed out waiting on pool worker run resolve ${(performance.now() - start).toFixed(2)} ms | Aborting thread`);\n this.threadAbortController?.abort();\n }, THREAD_RESOLVE_TIMEOUT_MS);\n \n try {\n debug(`[${mod}] stop: awaiting pool worker run resolve: ${!!this.threadRunPromise}`);\n await this.threadRunPromise;\n clearTimeout(abortTimeout);\n debug(`[${this.logModuleWithId}] stop: pool worker run resolved cleanly after ${(performance.now() - start).toFixed(2)} ms`);\n } catch {\n } finally {\n this.threadControlPort?.close();\n debug(`[${this.logModuleWithId}] stop: closed pool port`);\n }\n \n this.threadAbortController = undefined;\n this.threadControlPort = undefined;\n this.threadRunPromise = undefined;\n this.threadSpecs = [];\n }\n\n private getWorkerThreadMessageHandler(): EventCallback {\n return (message: any): void => {\n if (message[AS_POOL_WORKER_MSG_FLAG]) {\n const poolMessage = message as AssemblyScriptPoolWorkerMessage;\n\n switch (poolMessage.type) {\n case 'execution-start':\n this.handleTestExecutionStart(message);\n break;\n case 'execution-end':\n this.handleTestExecutionEnd(message);\n break;\n }\n\n return;\n }\n };\n }\n\n private handleTestExecutionStart(msg: TestExecutionStart): void {\n if (!this.isWorkerRunning) return;\n \n const { executionStart, test } = msg;\n const now = Date.now();\n const transitDuration = now - executionStart;\n const adjustedTimeout = Math.max(test.timeout - transitDuration, 0);\n\n this.currentTestRun = {\n test,\n executionStart,\n timeoutId: setTimeout(() => this.handleTimeout(), adjustedTimeout)\n };\n\n debug(`[${this.logModuleWithId}] START test timeout timer for \"${this.currentTestRun.test.name}\"`);\n }\n\n private handleTestExecutionEnd(_msg: TestExecutionEnd): void {\n this.clearTestTimeoutTimer();\n this.currentTestRun = undefined;\n }\n\n private clearTestTimeoutTimer(): void {\n if (this.currentTestRun) {\n const elapsed = Date.now() - this.currentTestRun.executionStart;\n debug(`[${this.logModuleWithId}] CLEAR test timeout timer (${elapsed.toFixed(2)} ms) for \"${this.currentTestRun?.test.name}\"`);\n clearTimeout(this.currentTestRun.timeoutId);\n }\n }\n\n private async handleTimeout(): Promise<void> {\n if (!this.isWorkerRunning) return;\n\n if (!this.threadSpecs.length || !this.currentTestRun || !this.currentTestRun.test) {\n const missingStr = \n + (this.threadSpecs.length ? '' : 'threadSpecs')\n + (this.currentTestRun ? '' : ' currentTestRecord')\n + (this.currentTestRun?.test ? '' : ' currentTestRecord.test')\n throw createPoolError(\n `Cannot timeout/resume worker thread for workerId ${this.currentWorkerId} - missing data: ${missingStr}`,\n POOL_ERROR_NAMES.PoolError\n );\n }\n\n const duration = Date.now() - this.currentTestRun.executionStart;\n failTestWithTimeoutError(this.currentTestRun.test, this.currentTestRun.executionStart, duration);\n\n // set termination time metadata for measuring resume latency\n flagTestTerminated(this.currentTestRun.test);\n\n debug(`[${this.logModuleWithId}] handleTimeout: TEST TIMEOUT \"${this.currentTestRun.test.name}\" after ${duration.toFixed(2)} ms`\n +` - Terminating worker thread job`\n );\n\n const termStart = performance.now();\n \n try {\n this.threadAbortController?.abort();\n await this.threadRunPromise;\n } catch (error) {\n if (!isAbortError(error)) {\n throw createPoolErrorFromAnyError(`PoolWorker handleTimeout`, POOL_ERROR_NAMES.PoolError, error);\n }\n } finally {\n this.threadControlPort?.close();\n this.threadAbortController = undefined;\n this.threadControlPort = undefined;\n this.threadRunPromise = undefined;\n }\n\n debug(`[${this.logModuleWithId}] handleTimeout: Worker thread job aborted for timeout in ${(performance.now() - termStart).toFixed(2)} ms`);\n \n if (!this.isWorkerRunning) return;\n\n // supply timed-out test (includes entire file hierarchy & coverage)\n // to resume testing where we leftoff when aborting for timeout\n this.threadRunPromise = this.orchestrateFileRuns(this.currentTestRun.test);\n\n debug(`[${this.logModuleWithId}] handleTimeout: re-dispatched job to worker thread`\n + ` | files: \"${this.threadSpecs.map(s => s.file.filepath).join(',')}\"`\n );\n\n try {\n await this.threadRunPromise;\n this.notifyVitest('testfileFinished');\n debug(`[${this.logModuleWithId}] handleTimeout: file run completed - responded \"testfileFinished\" to vitest`\n + ` | files: \"${this.threadSpecs.map(s => s.file.filepath).join(',')}\"`\n );\n \n this.threadSpecs = [];\n } catch (error) {\n if (!isAbortError(error)) {\n throw createPoolErrorFromAnyError(`PoolWorker handleTimeout`, POOL_ERROR_NAMES.PoolError, error);\n } else {\n debug(`[${this.logModuleWithId}] send: caught and ignored timeout awaiting timeout re-run`\n + ` | files: \"${this.threadSpecs.map(s => s.file.filepath).join(',')}\"`\n );\n }\n } finally {\n //@ts-ignore\n this.threadControlPort?.close();\n this.threadControlPort = undefined;\n this.threadAbortController = undefined;\n this.threadRunPromise = undefined;\n }\n }\n\n private get logModuleWithId(): string {\n return `${this.logModule}${this.currentWorkerId === undefined ? '' : ` ${this.currentWorkerId}`}`;\n }\n}\n","import type { PoolOptions, PoolRunnerInitializer } from 'vitest/node';\n\nimport type {\n AssemblyScriptPoolOptions,\n ResolvedHybridProviderOptions\n} from '../types/types.js';\nimport { ASSEMBLYSCRIPT_POOL_NAME } from '../types/constants.js';\nimport { resolvePoolOptions } from '../util/resolve-config.js';\nimport { AssemblyScriptPoolWorker } from './pool-worker.js';\n\nexport function createAssemblyScriptPool(userPoolOptions?: AssemblyScriptPoolOptions): PoolRunnerInitializer {\n const resolvedUserPoolOptions = resolvePoolOptions(userPoolOptions);\n\n return {\n name: ASSEMBLYSCRIPT_POOL_NAME,\n createPoolWorker: (opts: PoolOptions) => {\n const resolvedCoverageOptions = opts.project.config.coverage as ResolvedHybridProviderOptions;\n return new AssemblyScriptPoolWorker(opts, resolvedUserPoolOptions, resolvedCoverageOptions);\n },\n };\n}\n"],"mappings":"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"}