import * as qenv from '@push.rocks/qenv'; import * as smartbucket from '@push.rocks/smartbucket'; import { generateTestRunId } from './ids.js'; const testQenv = new qenv.Qenv('./', './.nogit'); /** * Create a SmartBucket storage backend for upstream cache testing. */ export async function createTestStorageBackend(): Promise<{ storage: { getObject: (key: string) => Promise; putObject: (key: string, data: Buffer) => Promise; deleteObject: (key: string) => Promise; listObjects: (prefix: string) => Promise; }; bucket: smartbucket.Bucket; cleanup: () => Promise; }> { const s3AccessKey = await testQenv.getEnvVarOnDemand('S3_ACCESSKEY'); const s3SecretKey = await testQenv.getEnvVarOnDemand('S3_SECRETKEY'); const s3Endpoint = await testQenv.getEnvVarOnDemand('S3_ENDPOINT'); const s3Port = await testQenv.getEnvVarOnDemand('S3_PORT'); const s3 = new smartbucket.SmartBucket({ accessKey: s3AccessKey || 'minioadmin', accessSecret: s3SecretKey || 'minioadmin', endpoint: s3Endpoint || 'localhost', port: parseInt(s3Port || '9000', 10), useSsl: false, }); const testRunId = generateTestRunId(); const bucketName = 'test-cache-' + testRunId.substring(0, 8); const bucket = await s3.createBucket(bucketName); const storage = { getObject: async (key: string): Promise => { try { return await bucket.fastGet({ path: key }); } catch { return null; } }, putObject: async (key: string, data: Buffer): Promise => { await bucket.fastPut({ path: key, contents: data, overwrite: true }); }, deleteObject: async (key: string): Promise => { await bucket.fastRemove({ path: key }); }, listObjects: async (prefix: string): Promise => { const paths: string[] = []; for await (const path of bucket.listAllObjects(prefix)) { paths.push(path); } return paths; }, }; const cleanup = async () => { try { for await (const path of bucket.listAllObjects()) { await bucket.fastRemove({ path }); } await s3.removeBucket(bucketName); } catch { // Ignore cleanup errors } }; return { storage, bucket, cleanup }; }