W / test /auth-migration.test.js
Ac66's picture
Upload folder using huggingface_hub
2b64d42 verified
import { describe, it, beforeEach, afterEach } from 'node:test';
import assert from 'node:assert/strict';
import { mkdirSync, mkdtempSync, rmSync, writeFileSync, readFileSync, existsSync } from 'fs';
import { join } from 'path';
import { tmpdir } from 'os';
import { migrateReplicaAccountsTo } from '../src/auth.js';
// Issue #67 — `accounts.json` used to live under per-replica `dataDir`
// (replica-${HOSTNAME}/), so each docker-compose upgrade orphaned the
// previous run's accounts. The migration helper unions all
// `replica-*/accounts.json` files under the shared dir and writes them
// to the shared path on startup.
const silentLogger = { warn() {}, error() {}, info() {} };
describe('migrateReplicaAccountsTo (issue #67)', () => {
let tmp;
let accountsFile;
beforeEach(() => {
tmp = mkdtempSync(join(tmpdir(), 'wfapi-mig-'));
accountsFile = join(tmp, 'accounts.json');
});
afterEach(() => {
try { rmSync(tmp, { recursive: true, force: true }); } catch {}
});
it('skips when no replica-* subdir exists', () => {
const r = migrateReplicaAccountsTo({ sharedDir: tmp, accountsFile, logger: silentLogger });
assert.equal(r.migrated, 0);
assert.equal(r.skipped, true);
assert.equal(existsSync(accountsFile), false);
});
it('skips when shared accounts.json already exists', () => {
mkdirSync(join(tmp, 'replica-h1'));
writeFileSync(join(tmp, 'replica-h1', 'accounts.json'), JSON.stringify([
{ apiKey: 'k1', email: 'a@b.com' },
]));
writeFileSync(accountsFile, '[]');
const r = migrateReplicaAccountsTo({ sharedDir: tmp, accountsFile, logger: silentLogger });
assert.equal(r.migrated, 0);
assert.equal(r.skipped, true);
assert.equal(readFileSync(accountsFile, 'utf-8'), '[]');
});
it('migrates accounts from a single replica-*/accounts.json', () => {
mkdirSync(join(tmp, 'replica-h1'));
writeFileSync(join(tmp, 'replica-h1', 'accounts.json'), JSON.stringify([
{ apiKey: 'k1', email: 'a@b.com', method: 'api_key' },
{ apiKey: 'k2', email: 'b@b.com', method: 'api_key' },
]));
const r = migrateReplicaAccountsTo({ sharedDir: tmp, accountsFile, logger: silentLogger });
assert.equal(r.migrated, 2);
assert.equal(r.scanned, 1);
assert.equal(r.skipped, false);
const out = JSON.parse(readFileSync(accountsFile, 'utf-8'));
assert.equal(out.length, 2);
assert.deepEqual(out.map(a => a.apiKey).sort(), ['k1', 'k2']);
});
it('unions multiple replica-* subdirs and dedupes by apiKey', () => {
for (const host of ['h1', 'h2', 'h3']) mkdirSync(join(tmp, `replica-${host}`));
writeFileSync(join(tmp, 'replica-h1', 'accounts.json'), JSON.stringify([
{ apiKey: 'k1', email: 'a@b.com' },
{ apiKey: 'k2', email: 'b@b.com' },
]));
writeFileSync(join(tmp, 'replica-h2', 'accounts.json'), JSON.stringify([
{ apiKey: 'k2', email: 'b-second@b.com' }, // duplicate apiKey, should be ignored
{ apiKey: 'k3', email: 'c@b.com' },
]));
writeFileSync(join(tmp, 'replica-h3', 'accounts.json'), JSON.stringify([
{ apiKey: 'k4', email: 'd@b.com' },
]));
const r = migrateReplicaAccountsTo({ sharedDir: tmp, accountsFile, logger: silentLogger });
assert.equal(r.migrated, 4);
assert.equal(r.scanned, 3);
const out = JSON.parse(readFileSync(accountsFile, 'utf-8'));
assert.equal(out.length, 4);
assert.deepEqual(out.map(a => a.apiKey).sort(), ['k1', 'k2', 'k3', 'k4']);
// First-seen wins on duplicate apiKey
assert.equal(out.find(a => a.apiKey === 'k2').email, 'b@b.com');
});
it('tolerates a corrupt replica-*/accounts.json without aborting other replicas', () => {
mkdirSync(join(tmp, 'replica-bad'));
mkdirSync(join(tmp, 'replica-good'));
writeFileSync(join(tmp, 'replica-bad', 'accounts.json'), '{not json');
writeFileSync(join(tmp, 'replica-good', 'accounts.json'), JSON.stringify([
{ apiKey: 'k1', email: 'a@b.com' },
]));
const r = migrateReplicaAccountsTo({ sharedDir: tmp, accountsFile, logger: silentLogger });
assert.equal(r.migrated, 1);
assert.equal(r.scanned, 2);
const out = JSON.parse(readFileSync(accountsFile, 'utf-8'));
assert.equal(out.length, 1);
assert.equal(out[0].apiKey, 'k1');
});
it('skips replica-* subdirs that have no accounts.json', () => {
mkdirSync(join(tmp, 'replica-empty'));
mkdirSync(join(tmp, 'replica-with-data'));
writeFileSync(join(tmp, 'replica-with-data', 'accounts.json'), JSON.stringify([
{ apiKey: 'k1', email: 'a@b.com' },
]));
const r = migrateReplicaAccountsTo({ sharedDir: tmp, accountsFile, logger: silentLogger });
assert.equal(r.migrated, 1);
assert.equal(r.scanned, 1);
});
it('does nothing when sharedDir does not exist', () => {
const r = migrateReplicaAccountsTo({
sharedDir: join(tmp, 'does-not-exist'),
accountsFile,
logger: silentLogger,
});
assert.equal(r.migrated, 0);
assert.equal(r.skipped, true);
});
});