/** * Module Test Utilities * * Provides functions for importing and cleaning up test modules. * Simplifies integration test setup/teardown. */ import { eq } from 'drizzle-orm'; import type { DbClient } from '../db/client'; import { modules } from '../db/schema'; import { importModule } from '../module/import'; import { setModuleConfigValue } from '../services/module-config'; /** * Options for importing test modules */ export interface ImportTestModuleOptions { /** * Module configuration (key-value pairs) */ config?: Record; /** * Module secrets (will be encrypted) */ secrets?: Record; /** * Skip validation (useful for testing error cases) */ skipValidation?: boolean; } /** * Import test module from fixtures * * Imports module, applies configuration, and validates. * Use for integration tests that need real modules. * * @param modulePath - Path to module directory * @param db - Test database * @param options - Import options * @returns Module ID * * @example * ```typescript * const moduleId = await importTestModule( * './test-fixtures/modules/artifact-test', * db, * { * config: { vmid: '100', hostname: 'test' }, * secrets: { api_key: 'test-key' } * } * ); * await cleanupTestModule(moduleId, db); * ``` */ export async function importTestModule( modulePath: string, db: DbClient, options: ImportTestModuleOptions = {}, ): Promise { // Import module const result = await importModule({ sourcePath: modulePath, db }); // Check if import was successful if (!result.success) { throw new Error(`Failed to import module: ${result.error}`); } // Apply configuration if provided if (options.config) { for (const [key, value] of Object.entries(options.config)) { await setModuleConfigValue(result.moduleId, key, String(value), db); } } // TODO: Apply secrets when secret management is implemented if (options.secrets) { // For now, secrets are not yet implemented // This will be added in the future } return result.moduleId; } /** * Clean up test module * * Deletes module and all related data (configs, capabilities, secrets). * Use in test cleanup to prevent state leakage. * * @param moduleId - Module ID to delete * @param db - Test database * * @example * ```typescript * const moduleId = await importTestModule('./test-fixtures/modules/artifact-test', db); * // ... tests ... * await cleanupTestModule(moduleId, db); * ``` */ export async function cleanupTestModule(moduleId: string, db: DbClient): Promise { await db.delete(modules).where(eq(modules.id, moduleId)); } /** * Import multiple test modules * * Imports multiple modules in sequence. * Useful for tests that need multiple modules. * * @param moduleSpecs - Array of module specs * @param db - Test database * @returns Array of module IDs * * @example * ```typescript * const [module1, module2] = await importMultipleTestModules([ * { path: './test-fixtures/modules/artifact-test' }, * { path: './test-fixtures/modules/caddy', config: { hostname: 'www' } } * ], db); * await cleanupMultipleTestModules([module1, module2], db); * ``` */ export async function importMultipleTestModules( moduleSpecs: Array<{ path: string; options?: ImportTestModuleOptions; }>, db: DbClient, ): Promise { const moduleIds: string[] = []; for (const spec of moduleSpecs) { const moduleId = await importTestModule(spec.path, db, spec.options); moduleIds.push(moduleId); } return moduleIds; } /** * Clean up multiple test modules * * @param moduleIds - Array of module IDs to delete * @param db - Test database * * @example * ```typescript * const moduleIds = await importMultipleTestModules([...], db); * // ... tests ... * await cleanupMultipleTestModules(moduleIds, db); * ``` */ export async function cleanupMultipleTestModules(moduleIds: string[], db: DbClient): Promise { for (const moduleId of moduleIds) { await cleanupTestModule(moduleId, db); } } /** * Get module state * * Retrieves current module state from database. * Useful for asserting state transitions in tests. * * @param moduleId - Module ID * @param db - Test database * @returns Module state or null if not found * * @example * ```typescript * const state = await getModuleState('artifact-test', db); * expect(state).toBe('IMPORTED'); * ``` */ export async function getModuleState(moduleId: string, db: DbClient): Promise { const result = await db .select({ state: modules.state }) .from(modules) .where(eq(modules.id, moduleId)); return result.length > 0 ? result[0].state : null; }