Skip to content

Commit e7bf72b

Browse files
brooke-hamiltonchrmarti
authored andcommitted
additional tests
Signed-off-by: Brooke Hamilton <[email protected]>
1 parent 9c3426b commit e7bf72b

3 files changed

Lines changed: 75 additions & 0 deletions

File tree

src/spec-configuration/lockfile.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,15 @@ export async function writeLockfile(params: ContainerFeatureInternalParams, conf
5353
return;
5454
}
5555

56+
// Trailing newline per POSIX convention
5657
const newLockfileContentString = JSON.stringify(lockfile, null, 2) + '\n';
5758
const newLockfileContent = Buffer.from(newLockfileContentString);
5859
if (params.experimentalFrozenLockfile && !oldLockfileContent) {
5960
throw new Error('Lockfile does not exist.');
6061
}
62+
// Normalize the existing lockfile through JSON.parse -> JSON.stringify to produce
63+
// the same canonical format as newLockfileContentString, so that the string comparison
64+
// below ignores cosmetic differences (indentation, key order, trailing whitespace, etc.).
6165
let oldLockfileNormalized: string | undefined;
6266
if (oldLockfileContent) {
6367
try {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
3+
"features": {
4+
"ghcr.io/codspace/features/flower:1": {},
5+
"ghcr.io/codspace/features/color:1": {}
6+
}
7+
}

src/test/container-features/lockfile.test.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,4 +336,68 @@ describe('Lockfile', function () {
336336
process.chdir(originalCwd);
337337
}
338338
});
339+
340+
it('frozen lockfile fails when lockfile does not exist', async () => {
341+
const workspaceFolder = path.join(__dirname, 'configs/lockfile-frozen-no-lockfile');
342+
const lockfilePath = path.join(workspaceFolder, '.devcontainer-lock.json');
343+
await rmLocal(lockfilePath, { force: true });
344+
345+
try {
346+
throw await shellExec(`${cli} build --workspace-folder ${workspaceFolder} --experimental-lockfile --experimental-frozen-lockfile`);
347+
} catch (res) {
348+
const response = JSON.parse(res.stdout);
349+
assert.equal(response.outcome, 'error');
350+
assert.equal(response.message, 'Lockfile does not exist.');
351+
}
352+
});
353+
354+
it('corrupt lockfile causes build error', async () => {
355+
const workspaceFolder = path.join(__dirname, 'configs/lockfile');
356+
const lockfilePath = path.join(workspaceFolder, '.devcontainer-lock.json');
357+
const expectedPath = path.join(workspaceFolder, 'expected.devcontainer-lock.json');
358+
359+
try {
360+
// Write invalid JSON to the lockfile
361+
await writeLocalFile(lockfilePath, Buffer.from('this is not valid json{{{'));
362+
363+
try {
364+
throw await shellExec(`${cli} build --workspace-folder ${workspaceFolder} --experimental-lockfile`);
365+
} catch (res) {
366+
const response = JSON.parse(res.stdout);
367+
assert.equal(response.outcome, 'error');
368+
}
369+
} finally {
370+
// Restore from the known-good expected lockfile
371+
await cpLocal(expectedPath, lockfilePath);
372+
}
373+
});
374+
375+
it('no lockfile flags and no existing lockfile is a no-op', async () => {
376+
const workspaceFolder = path.join(__dirname, 'configs/lockfile');
377+
const lockfilePath = path.join(workspaceFolder, '.devcontainer-lock.json');
378+
const expectedPath = path.join(workspaceFolder, 'expected.devcontainer-lock.json');
379+
380+
try {
381+
await rmLocal(lockfilePath, { force: true });
382+
383+
// Build without any lockfile flags
384+
const res = await shellExec(`${cli} build --workspace-folder ${workspaceFolder}`);
385+
const response = JSON.parse(res.stdout);
386+
assert.equal(response.outcome, 'success');
387+
388+
// Lockfile should not have been created
389+
let exists = true;
390+
await readLocalFile(lockfilePath).catch(err => {
391+
if (err?.code === 'ENOENT') {
392+
exists = false;
393+
} else {
394+
throw err;
395+
}
396+
});
397+
assert.equal(exists, false, 'Lockfile should not be created when no lockfile flags are set');
398+
} finally {
399+
// Restore from the known-good expected lockfile
400+
await cpLocal(expectedPath, lockfilePath);
401+
}
402+
});
339403
});

0 commit comments

Comments
 (0)