feat(smartmigration): add initial smartmigration package with MongoDB and S3 migration runner

This commit is contained in:
2026-04-07 17:35:05 +00:00
commit d96c6bcee8
33 changed files with 11443 additions and 0 deletions

66
test/helpers/services.ts Normal file
View File

@@ -0,0 +1,66 @@
import { Qenv } from '@push.rocks/qenv';
import * as smartdata from '@push.rocks/smartdata';
import * as smartbucket from '@push.rocks/smartbucket';
const qenv = new Qenv(process.cwd(), process.cwd() + '/.nogit/');
/**
* Spin up a fresh `SmartdataDb` connected to the local mongo from .nogit/env.json,
* scoped to a unique database name so tests cannot collide. Returns the db plus
* a `cleanup` function that drops the database and closes the connection.
*/
export async function makeTestDb(suffix: string) {
const baseUrl = await qenv.getEnvVarOnDemandStrict('MONGODB_URL');
const dbName = `smartmigration_test_${suffix}_${Date.now()}_${Math.floor(Math.random() * 1e6)}`;
// Replace the path component of the connection URL with our unique db name.
// Format from env.json:
// mongodb://defaultadmin:defaultpass@localhost:27970/push-rocks-smartmigration?authSource=admin
const url = new URL(baseUrl);
url.pathname = `/${dbName}`;
const db = new smartdata.SmartdataDb({
mongoDbUrl: url.toString(),
mongoDbName: dbName,
});
await db.init();
const cleanup = async () => {
try {
await db.mongoDb.dropDatabase();
} catch {
/* ignore */
}
try {
await db.close();
} catch {
/* ignore */
}
};
return { db, dbName, cleanup };
}
/**
* Connect to the local minio bucket from .nogit/env.json. The bucket is
* shared across tests, so each test should namespace its keys with a
* unique prefix and clean them up afterwards.
*/
export async function makeTestBucket() {
const sb = new smartbucket.SmartBucket({
accessKey: await qenv.getEnvVarOnDemandStrict('S3_ACCESSKEY'),
accessSecret: await qenv.getEnvVarOnDemandStrict('S3_SECRETKEY'),
endpoint: await qenv.getEnvVarOnDemandStrict('S3_ENDPOINT'),
port: parseInt(await qenv.getEnvVarOnDemandStrict('S3_PORT'), 10),
useSsl: false,
});
const bucketName = await qenv.getEnvVarOnDemandStrict('S3_BUCKET');
// The bucket may not exist yet — try to fetch it; if missing, create it.
let bucket: smartbucket.Bucket;
try {
bucket = await sb.getBucketByName(bucketName);
} catch {
bucket = (await sb.createBucket(bucketName)) as unknown as smartbucket.Bucket;
bucket = await sb.getBucketByName(bucketName);
}
return { sb, bucket, bucketName };
}