Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/lint-build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ jobs:
cd node_modules/better-sqlite3
yarn build-release
cd -
- run: npm rebuild @ipshipyard/node-datachannel
- run: yarn build
- run: yarn test:ci
- name: Require clean working directory
Expand Down Expand Up @@ -157,6 +158,7 @@ jobs:
cd node_modules/better-sqlite3
yarn build-release
cd -
- run: npm rebuild @ipshipyard/node-datachannel
- run: VITE_DB_FOLDER=e2e yarn build
- name: Run E2E tests
id: e2e
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
diff --git a/dist/src/decode.js b/dist/src/decode.js
index b2906243c57e0fe838e4510cd4b53d36b6e17ebf..2bfe711cde98de5a0ba4aaea75861f7389c4307b 100644
--- a/dist/src/decode.js
+++ b/dist/src/decode.js
@@ -112,14 +112,14 @@ export class Decoder {
export function returnlessSource(source) {
if (source[Symbol.iterator] !== undefined) {
const iterator = source[Symbol.iterator]();
- iterator.return = undefined;
+ Object.defineProperty(iterator, 'return', {});
return {
[Symbol.iterator]() { return iterator; }
};
}
else if (source[Symbol.asyncIterator] !== undefined) {
const iterator = source[Symbol.asyncIterator]();
- iterator.return = undefined;
+ Object.defineProperty(iterator, 'return', {});
return {
[Symbol.asyncIterator]() { return iterator; }
};
diff --git a/src/decode.ts b/src/decode.ts
index 56440b95afba0330d5ece77a2f737c79a80155b2..2429fa8cf3206389b9a4b5ae395c8d402872eae9 100644
--- a/src/decode.ts
+++ b/src/decode.ts
@@ -128,13 +128,13 @@ export class Decoder {
export function returnlessSource<T> (source: Source<T>): Source<T> {
if ((source as Iterable<T>)[Symbol.iterator] !== undefined) {
const iterator = (source as Iterable<T>)[Symbol.iterator]()
- iterator.return = undefined
+ Object.defineProperty(iterator, 'return', {});
return {
[Symbol.iterator] () { return iterator }
}
} else if ((source as AsyncIterable<T>)[Symbol.asyncIterator] !== undefined) {
const iterator = (source as AsyncIterable<T>)[Symbol.asyncIterator]()
- iterator.return = undefined
+ Object.defineProperty(iterator, 'return', {});
return {
[Symbol.asyncIterator] () { return iterator }
}
2 changes: 1 addition & 1 deletion packages/brow-2-brow/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
},
"dependencies": {
"@chainsafe/libp2p-noise": "^16.1.3",
"@chainsafe/libp2p-yamux": "^6.0.2",
"@chainsafe/libp2p-yamux": "patch:@chainsafe/libp2p-yamux@npm%3A6.0.2#~/.yarn/patches/@chainsafe-libp2p-yamux-npm-6.0.2-ca843b3f79.patch",
"@libp2p/autonat": "^2.0.30",
"@libp2p/bootstrap": "^11.0.35",
"@libp2p/circuit-relay-v2": "^3.2.11",
Expand Down
4 changes: 2 additions & 2 deletions packages/extension/src/offscreen.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
makeIframeVatWorker,
VatWorkerServer,
PlatformServicesServer,
} from '@metamask/kernel-browser-runtime';
import { delay, isJsonRpcCall } from '@metamask/kernel-utils';
import type { JsonRpcCall } from '@metamask/kernel-utils';
Expand Down Expand Up @@ -62,7 +62,7 @@ async function makeKernelWorker(): Promise<
JsonRpcCall
>(port, isJsonRpcResponse);

await VatWorkerServer.make(worker as PostMessageTarget, (vatId) =>
await PlatformServicesServer.make(worker as PostMessageTarget, (vatId) =>
makeIframeVatWorker({
id: vatId,
iframeUri: 'iframe.html',
Expand Down
22 changes: 21 additions & 1 deletion packages/extension/src/vats/sample-vat.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,20 @@ import { makeDefaultExo } from '@metamask/kernel-utils/exo';
export function buildRootObject(_vatPowers, parameters, _baggage) {
const name = parameters?.name ?? 'anonymous';
console.log(`buildRootObject "${name}"`);
let redeemer;

return makeDefaultExo('root', {
async bootstrap(vats) {
async bootstrap(vats, services) {
console.log(`vat ${name} is bootstrap`);
const issuer = services.ocapURLIssuerService;
redeemer = services.ocapURLRedemptionService;
console.log(`in bootstrap redeemer=${redeemer}`);
if (issuer) {
const url = await E(issuer).issue(vats.bob);
console.log(`url for bob: ${url}`);
} else {
console.log(`no ocapURLIssuerService found`);
}
const pb = E(vats.bob).hello(name);
const pc = E(vats.carol).hello(name);
console.log(`vat ${name} got "hello" answer from Bob: '${await pb}'`);
Expand All @@ -26,5 +36,15 @@ export function buildRootObject(_vatPowers, parameters, _baggage) {
console.log(message);
return message;
},
async doRunRun(url) {
console.log(`in doRunRun redeemer=${redeemer}`);
if (redeemer) {
const remote = await E(redeemer).redeem(url);
console.log(`redeemed ${url} successfully (?)`);
await E(remote).hello(`remote ${name}`);
} else {
console.log('no ocapURLRedemptionService found');
}
},
});
}
62 changes: 18 additions & 44 deletions packages/extension/test/e2e/control-panel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,33 +162,6 @@ test.describe('Control Panel', () => {
popupPage.locator('[data-testid="message-output"]'),
).toContainText('State cleared');
await expect(popupPage.locator('table')).not.toBeVisible();
// ensure kernel state was cleared
await popupPage.locator('[data-testid="clear-logs-button"]').click();
await expect(
popupPage.locator('[data-testid="message-output"]'),
).toContainText('');
await popupPage.click('button:text("Database Inspector")');
const expectedValues = JSON.stringify([
{ key: 'queue.run.head', value: '1' },
{ key: 'queue.run.tail', value: '1' },
{ key: 'gcActions', value: '[]' },
{ key: 'reapQueue', value: '[]' },
{ key: 'vats.terminated', value: '[]' },
{ key: 'nextObjectId', value: '1' },
{ key: 'nextPromiseId', value: '1' },
{ key: 'nextVatId', value: '1' },
{ key: 'nextRemoteId', value: '1' },
{ key: 'subclusters', value: '[]' },
{ key: 'nextSubclusterId', value: '1' },
{ key: 'vatToSubclusterMap', value: '{}' },
]);
await expect(
popupPage.locator('[data-testid="message-output"]'),
).toContainText(expectedValues);
await expect(
popupPage.locator('[data-testid="message-output"]'),
).not.toContainText('"initialized":true');
await popupPage.click('button:text("Control Panel")');
});

test('should reload kernel state and load default vats', async () => {
Expand Down Expand Up @@ -218,18 +191,19 @@ test.describe('Control Panel', () => {
const v3Values = [
'{"key":"e.nextPromiseId.v3","value":"2"}',
'{"key":"e.nextObjectId.v3","value":"1"}',
'{"key":"ko3.owner","value":"v3"}',
'{"key":"v3.c.ko3","value":"R o+0"}',
'{"key":"v3.c.o+0","value":"ko3"}',
'{"key":"v3.c.kp3","value":"R p-1"}',
'{"key":"v3.c.p-1","value":"kp3"}',
'{"key":"ko3.refCount","value":"1,1"}',
'{"key":"ko5.owner","value":"v3"}',
'{"key":"v3.c.ko5","value":"R o+0"}',
'{"key":"v3.c.o+0","value":"ko5"}',
'{"key":"v3.c.kp4","value":"R p-1"}',
'{"key":"v3.c.p-1","value":"kp4"}',
'{"key":"ko5.refCount","value":"1,1"}',
'{"key":"kp4.refCount","value":"2"}',
];
const v1ko3Values = [
'{"key":"v1.c.ko3","value":"R o-2"}',
'{"key":"v1.c.o-2","value":"ko3"}',
'{"key":"kp3.state","value":"fulfilled"}',
'{"key":"kp3.value","value"',
const v1koValues = [
'{"key":"v1.c.ko4","value":"R o-1"}',
'{"key":"v1.c.o-1","value":"ko4"}',
'{"key":"v1.c.ko5","value":"R o-2"}',
'{"key":"v1.c.o-2","value":"ko5"}',
];
await expect(
popupPage.locator('[data-testid="message-output"]'),
Expand All @@ -242,7 +216,7 @@ test.describe('Control Panel', () => {
popupPage.locator('[data-testid="message-output"]'),
).toContainText(value);
}
for (const value of v1ko3Values) {
for (const value of v1koValues) {
await expect(
popupPage.locator('[data-testid="message-output"]'),
).toContainText(value);
Expand Down Expand Up @@ -289,16 +263,16 @@ test.describe('Control Panel', () => {
popupPage.locator('[data-testid="message-output"]'),
).not.toContainText(value);
}
// ko3 reference still exists for v1
for (const value of v1ko3Values) {
// ko3 (vat root) reference still exists for v1
for (const value of v1koValues) {
await expect(
popupPage.locator('[data-testid="message-output"]'),
).toContainText(value);
}
// kp3 reference dropped to 1
// kp4 reference dropped to 1
await expect(
popupPage.locator('[data-testid="message-output"]'),
).toContainText('{"key":"kp3.refCount","value":"1"}');
).toContainText('{"key":"kp4.refCount","value":"1"}');
await popupPage.click('button:text("Control Panel")');
await popupPage.locator('[data-testid="accordion-header"]').first().click();
// delete v1
Expand All @@ -321,7 +295,7 @@ test.describe('Control Panel', () => {
await expect(
popupPage.locator('[data-testid="message-output"]'),
).toContainText('{"key":"vats.terminated","value":"[]"}');
for (const value of v1ko3Values) {
for (const value of v1koValues) {
await expect(
popupPage.locator('[data-testid="message-output"]'),
).not.toContainText(value);
Expand Down
9 changes: 5 additions & 4 deletions packages/extension/test/e2e/object-registry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ test.describe('Object Registry', () => {
await clearLogsButton.click();
await popupPage.click('button:text("Object Registry")');
await expect(
popupPage.locator('text=Alice (v1) - 3 objects, 3 promises'),
popupPage.locator('text=Alice (v1) - 5 objects, 4 promises'),
).toBeVisible();
const targetSelect = popupPage.locator('[data-testid="message-target"]');
await expect(targetSelect).toBeVisible();
Expand All @@ -92,7 +92,7 @@ test.describe('Object Registry', () => {
);
await expect(messageResponse).toBeVisible();
await expect(messageResponse).toContainText(
'"body":"#[\\"__getInterfaceGuard__\\",\\"__getMethodNames__\\",\\"bootstrap\\",\\"hello\\"]"',
'"body":"#[\\"__getInterfaceGuard__\\",\\"__getMethodNames__\\",\\"bootstrap\\",\\"doRunRun\\",\\"hello\\"]"',
);
await expect(messageResponse).toContainText('"slots":[]');
await clearLogsButton.click();
Expand All @@ -102,13 +102,14 @@ test.describe('Object Registry', () => {
await expect(messageResponse).toContainText('"body":"#\\"vat Alice got');
await expect(messageResponse).toContainText('"slots":[');
await expect(
popupPage.locator('text=Alice (v1) - 3 objects, 5 promises'),
popupPage.locator('text=Alice (v1) - 5 objects, 6 promises'),
).toBeVisible();
});

test('should revoke an object', async () => {
const owner = 'v1';
const [target, method, params] = ['ko1', 'hello', '["Bob"]'];
const v1Root = 'ko3';
const [target, method, params] = [v1Root, 'hello', '["Bob"]'];

// Before revoking, we should be able to send a message to the object
let response = await sendMessage(popupPage, target, method, params);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { makeMockMessageTarget } from '@ocap/test-utils';
import { TestDuplexStream } from '@ocap/test-utils/streams';
import { describe, it, expect, beforeEach, vi } from 'vitest';

import type { VatWorkerClientStream } from './VatWorkerClient.ts';
import { VatWorkerClient } from './VatWorkerClient.ts';
import type { PlatformServicesClientStream } from './PlatformServicesClient.ts';
import { PlatformServicesClient } from './PlatformServicesClient.ts';

vi.mock('@metamask/streams/browser', async (importOriginal) => {
// eslint-disable-next-line @typescript-eslint/no-shadow
Expand Down Expand Up @@ -54,34 +54,33 @@ const makeNullReply = (messageId: `m${number}`): MessageEvent =>
result: null,
});

describe('VatWorkerClient', () => {
describe('PlatformServicesClient', () => {
it('constructs with default logger', async () => {
const stream = await TestDuplexStream.make(() => undefined);
await stream.synchronize();
const client = new VatWorkerClient(
stream as unknown as VatWorkerClientStream,
const client = new PlatformServicesClient(
stream as unknown as PlatformServicesClientStream,
);
expect(client).toBeDefined();
});

it('constructs using static factory method', async () => {
const mockMessageTarget = makeMockMessageTarget();
const client = await VatWorkerClient.make(mockMessageTarget);
const client = await PlatformServicesClient.make(makeMockMessageTarget());
expect(client).toBeDefined();
expect(client).toBeInstanceOf(VatWorkerClient);
expect(client).toBeInstanceOf(PlatformServicesClient);
});

describe('message handling', () => {
let stream: TestDuplexStream;
let clientLogger: Logger;
let client: VatWorkerClient;
let client: PlatformServicesClient;

beforeEach(async () => {
stream = await TestDuplexStream.make(() => undefined);
await stream.synchronize();
clientLogger = new Logger('test-client');
client = new VatWorkerClient(
stream as unknown as VatWorkerClientStream,
client = new PlatformServicesClient(
stream as unknown as PlatformServicesClientStream,
clientLogger,
);
});
Expand Down Expand Up @@ -139,8 +138,8 @@ describe('VatWorkerClient', () => {
it('can be called before client is started', async () => {
const newStream = await TestDuplexStream.make(() => undefined);
await newStream.synchronize();
const newClient = new VatWorkerClient(
newStream as unknown as VatWorkerClientStream,
const newClient = new PlatformServicesClient(
newStream as unknown as PlatformServicesClientStream,
);

// Call launch before starting the client
Expand Down
Loading
Loading