blob: 098df1980061a6ed887aebba265d8151c921f830 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import assert from 'node:assert/strict';
import test from 'node:test';
import {
createAttachedWorkspaceExecutionProfile,
createRuntimeHostWorkspaceExecutionComposition,
RuntimeHostWorkspaceExecutionError,
} from '../server/workspace-execution-composition.js';
test('executes read-only operations in the attached checkout', async () => {
const calls: string[] = [];
const composition = createRuntimeHostWorkspaceExecutionComposition({
filesystemWorker: {
async execute(input) {
calls.push(`${input.cwd}:${input.operation.kind}`);
return {
kind: 'read',
content: 'attached',
offset: 0,
returnedLines: 1,
totalLines: 1,
next: null,
};
},
},
});
const profile = createAttachedWorkspaceExecutionProfile('/attached');
assert.deepEqual(
await composition.executeReadOnly(profile, { kind: 'read', path: 'README.md' }),
{ kind: 'read', content: 'attached', offset: 0, returnedLines: 1, totalLines: 1, next: null },
);
assert.deepEqual(calls, ['/attached:read']);
await composition.close();
});
test('rejects malformed profiles and mutating operations before worker dispatch', async () => {
let workerCalls = 0;
const composition = createRuntimeHostWorkspaceExecutionComposition({
filesystemWorker: {
async execute() {
workerCalls += 1;
return {
kind: 'read',
content: 'unsafe',
offset: 0,
returnedLines: 1,
totalLines: 1,
next: null,
};
},
},
});
for (const profile of [
{ kind: 'unknown_profile', cwd: '/attached' },
{ kind: 'attached_checkout_v1', cwd: '' },
]) {
await assert.rejects(
() => composition.executeReadOnly(profile as never, { kind: 'read', path: 'README.md' }),
(error) =>
error instanceof RuntimeHostWorkspaceExecutionError &&
error.code === 'workspace_operation_denied',
);
}
await assert.rejects(
() =>
composition.executeReadOnly(createAttachedWorkspaceExecutionProfile('/attached'), {
kind: 'write',
path: 'unsafe.txt',
} as never),
(error) =>
error instanceof RuntimeHostWorkspaceExecutionError &&
error.code === 'workspace_operation_denied',
);
assert.equal(workerCalls, 0);
await composition.close();
});
test('drains active attached operations before closing', async () => {
let releaseWorker!: () => void;
const workerBlocked = new Promise<void>((resolve) => {
releaseWorker = resolve;
});
const composition = createRuntimeHostWorkspaceExecutionComposition({
filesystemWorker: {
async execute() {
await workerBlocked;
return {
kind: 'read',
content: 'attached',
offset: 0,
returnedLines: 1,
totalLines: 1,
next: null,
};
},
},
});
const profile = createAttachedWorkspaceExecutionProfile('/attached');
const executing = composition.executeReadOnly(profile, { kind: 'read', path: 'README.md' });
await new Promise((resolve) => setImmediate(resolve));
const closing = composition.close();
await assert.rejects(
() => composition.executeReadOnly(profile, { kind: 'read', path: 'other.md' }),
(error) =>
error instanceof RuntimeHostWorkspaceExecutionError &&
error.code === 'workspace_execution_draining',
);
assert.equal(composition.state, 'draining');
releaseWorker();
await executing;
await closing;
assert.equal(composition.state, 'closed');
});