feat(migration): add lock heartbeats, predictive dry-run planning, and stricter ledger option validation
This commit is contained in:
@@ -4,6 +4,24 @@ import * as smartbucket from '@push.rocks/smartbucket';
|
||||
|
||||
const qenv = new Qenv(process.cwd(), process.cwd() + '/.nogit/');
|
||||
|
||||
async function createSmartBucket(): Promise<smartbucket.SmartBucket> {
|
||||
return 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,
|
||||
});
|
||||
}
|
||||
|
||||
function buildUniqueBucketName(baseName: string, suffix: string): string {
|
||||
const safeBase = baseName.toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
||||
const safeSuffix = suffix.toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
||||
const uniquePart = `${Date.now().toString(36)}-${Math.floor(Math.random() * 1e6).toString(36)}`;
|
||||
const combined = `${safeBase}-${safeSuffix}-${uniquePart}`.replace(/-+/g, '-');
|
||||
return combined.slice(0, 63).replace(/^-+|-+$/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -45,13 +63,7 @@ export async function makeTestDb(suffix: string) {
|
||||
* 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 sb = await createSmartBucket();
|
||||
const bucketName = await qenv.getEnvVarOnDemandStrict('S3_BUCKET');
|
||||
|
||||
// The bucket may not exist yet — try to fetch it; if missing, create it.
|
||||
@@ -64,3 +76,29 @@ export async function makeTestBucket() {
|
||||
}
|
||||
return { sb, bucket, bucketName };
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a unique bucket for tests that need a truly empty object store.
|
||||
*/
|
||||
export async function makeIsolatedTestBucket(suffix: string) {
|
||||
const sb = await createSmartBucket();
|
||||
const baseBucketName = await qenv.getEnvVarOnDemandStrict('S3_BUCKET');
|
||||
const bucketName = buildUniqueBucketName(baseBucketName, suffix);
|
||||
|
||||
const bucket = await sb.createBucket(bucketName);
|
||||
|
||||
const cleanup = async () => {
|
||||
try {
|
||||
await bucket.cleanAllContents();
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
try {
|
||||
await sb.removeBucket(bucketName);
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
};
|
||||
|
||||
return { sb, bucket, bucketName, cleanup };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user