Skip to content

Commit bdfe256

Browse files
authored
test(exo): Add liveslots virtual object tests (#475)
Closes #335 Add tests for liveslots virtual object functionality
1 parent 4c78148 commit bdfe256

File tree

4 files changed

+593
-19
lines changed

4 files changed

+593
-19
lines changed

packages/kernel-test/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,11 @@
8282
"node": "^20 || >=22"
8383
},
8484
"dependencies": {
85+
"@agoric/store": "0.9.3-u19.0",
8586
"@endo/eventual-send": "^1.3.1",
87+
"@endo/exo": "^1.5.9",
8688
"@endo/marshal": "^1.6.4",
89+
"@endo/patterns": "^1.5.0",
8790
"@endo/promise-kit": "^1.1.10",
8891
"@ocap/kernel": "workspace:^",
8992
"@ocap/nodejs": "workspace:^",
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
import '@ocap/shims/endoify';
2+
import { Kernel, kunser } from '@ocap/kernel';
3+
import type { KRef } from '@ocap/kernel';
4+
import type { KernelDatabase } from '@ocap/store';
5+
import { makeSQLKernelDatabase } from '@ocap/store/sqlite/nodejs';
6+
import { waitUntilQuiescent } from '@ocap/utils';
7+
import { beforeEach, describe, expect, it } from 'vitest';
8+
9+
import {
10+
extractVatLogs,
11+
getBundleSpec,
12+
makeKernel,
13+
runTestVats,
14+
} from './utils.ts';
15+
16+
const origStdoutWrite = process.stdout.write.bind(process.stdout);
17+
let buffered: string = '';
18+
// @ts-expect-error Some type def used by lint is just wrong (compiler likes it ok, but lint whines)
19+
process.stdout.write = (buffer: string, encoding, callback): void => {
20+
buffered += buffer;
21+
origStdoutWrite(buffer, encoding, callback);
22+
};
23+
24+
const testSubcluster = {
25+
bootstrap: 'exoTest',
26+
forceReset: true,
27+
vats: {
28+
exoTest: {
29+
bundleSpec: getBundleSpec('exo-vat'),
30+
parameters: {
31+
name: 'ExoTest',
32+
},
33+
},
34+
},
35+
};
36+
37+
describe('virtual objects functionality', async () => {
38+
let kernel: Kernel;
39+
let kernelDatabase: KernelDatabase;
40+
let bootstrapResult: unknown;
41+
42+
beforeEach(async () => {
43+
kernelDatabase = await makeSQLKernelDatabase({
44+
dbFilename: ':memory:',
45+
});
46+
kernel = await makeKernel(kernelDatabase, true);
47+
buffered = '';
48+
bootstrapResult = await runTestVats(kernel, testSubcluster);
49+
await waitUntilQuiescent(100);
50+
});
51+
52+
it('successfully creates and uses exo objects and scalar stores', async () => {
53+
expect(bootstrapResult).toBe('exo-test-complete');
54+
const vatLogs = extractVatLogs(buffered);
55+
expect(vatLogs).toStrictEqual([
56+
'ExoTest: initializing state',
57+
'ExoTest: counter value from baggage: 0',
58+
'ExoTest: bootstrap()',
59+
'ExoTest: Created counter with initial value: 10',
60+
'ExoTest: Incremented counter by 5 to: 15',
61+
'ExoTest: ERROR: Increment with negative value should have failed',
62+
'ExoTest: Alice has 1 friends',
63+
'ExoTest: Added 2 entries to map store',
64+
'ExoTest: Added 2 entries to set store',
65+
'ExoTest: Retrieved Alice from map store',
66+
'ExoTest: Temperature at 25°C = 77°F',
67+
'ExoTest: After setting to 68°F, celsius is 20°C',
68+
'ExoTest: SimpleCounter initial value: 0',
69+
'ExoTest: SimpleCounter after +7: 7',
70+
'ExoTest: Updated baggage counter to: 7',
71+
]);
72+
}, 30000);
73+
74+
it('tests scalar store functionality', async () => {
75+
buffered = '';
76+
const storeResult = await kernel.queueMessageFromKernel(
77+
'ko1',
78+
'testScalarStore',
79+
[],
80+
);
81+
await waitUntilQuiescent(100);
82+
expect(kunser(storeResult)).toBe('scalar-store-tests-complete');
83+
const vatLogs = extractVatLogs(buffered);
84+
expect(vatLogs).toStrictEqual([
85+
'ExoTest: Map store size: 3',
86+
'ExoTest: Map store keys: alice, bob, charlie',
87+
"ExoTest: Map has 'charlie': true",
88+
'ExoTest: Set store size: 3',
89+
'ExoTest: Set has Charlie: true',
90+
]);
91+
}, 30000);
92+
93+
it('can create and use objects through messaging', async () => {
94+
buffered = '';
95+
const counterResult = await kernel.queueMessageFromKernel(
96+
'ko1',
97+
'createCounter',
98+
[42],
99+
);
100+
await waitUntilQuiescent();
101+
const counterRef = counterResult.slots[0] as KRef;
102+
const incrementResult = await kernel.queueMessageFromKernel(
103+
counterRef,
104+
'increment',
105+
[5],
106+
);
107+
// Verify the increment result
108+
expect(kunser(incrementResult)).toBe(47);
109+
await waitUntilQuiescent();
110+
const personResult = await kernel.queueMessageFromKernel(
111+
'ko1',
112+
'createPerson',
113+
['Dave', 35],
114+
);
115+
await waitUntilQuiescent();
116+
const personRef = personResult.slots[0] as KRef;
117+
await kernel.queueMessageFromKernel('ko1', 'createOrUpdateInMap', [
118+
'dave',
119+
personRef,
120+
]);
121+
await waitUntilQuiescent();
122+
123+
// Get object from map store
124+
const retrievedPerson = await kernel.queueMessageFromKernel(
125+
'ko1',
126+
'getFromMap',
127+
['dave'],
128+
);
129+
await waitUntilQuiescent();
130+
// Verify the retrieved person object
131+
expect(kunser(retrievedPerson)).toBe(personRef);
132+
await kernel.queueMessageFromKernel('ko1', 'createOrUpdateInMap', [
133+
'dave',
134+
personRef,
135+
]);
136+
await waitUntilQuiescent(100);
137+
const vatLogs = extractVatLogs(buffered);
138+
// Verify counter was created and used
139+
expect(vatLogs).toStrictEqual([
140+
'ExoTest: Created new counter with value: 42',
141+
'ExoTest: Created person Dave, age 35',
142+
'ExoTest: Added dave to map, size now: 3',
143+
'ExoTest: Found dave in map',
144+
'ExoTest: Updated dave in map',
145+
]);
146+
}, 30000);
147+
148+
it('tests exoClass type validation and behavior', async () => {
149+
buffered = '';
150+
const exoClassResult = await kernel.queueMessageFromKernel(
151+
'ko1',
152+
'testExoClass',
153+
[],
154+
);
155+
await waitUntilQuiescent(100);
156+
expect(kunser(exoClassResult)).toBe('exoClass-tests-complete');
157+
const vatLogs = extractVatLogs(buffered);
158+
expect(vatLogs).toStrictEqual([
159+
'ExoTest: Counter: 3 + 5 = 8',
160+
'ExoTest: Counter: 8 - 2 = 6',
161+
'ExoTest: Successfully caught type error: In "increment" method of (Counter): arg 0: string "foo" - Must be a number',
162+
]);
163+
}, 30000);
164+
165+
it('tests exoClassKit with multiple facets', async () => {
166+
buffered = '';
167+
const exoClassKitResult = await kernel.queueMessageFromKernel(
168+
'ko1',
169+
'testExoClassKit',
170+
[],
171+
);
172+
await waitUntilQuiescent(100);
173+
expect(kunser(exoClassKitResult)).toBe('exoClassKit-tests-complete');
174+
const vatLogs = extractVatLogs(buffered);
175+
expect(vatLogs).toStrictEqual([
176+
'ExoTest: 20°C = 68°F',
177+
'ExoTest: 32°F = 0°C',
178+
'ExoTest: Successfully caught cross-facet error: celsius.getFahrenheit is not a function',
179+
]);
180+
}, 30000);
181+
182+
it('tests temperature converter through messaging', async () => {
183+
buffered = '';
184+
// Create a temperature converter starting at 100°C
185+
const tempResult = await kernel.queueMessageFromKernel(
186+
'ko1',
187+
'createTemperature',
188+
[100],
189+
);
190+
await waitUntilQuiescent();
191+
// Get both facets from the result
192+
const tempKit = tempResult;
193+
const celsiusRef = tempKit.slots[0] as KRef;
194+
const fahrenheitRef = tempKit.slots[1] as KRef;
195+
// Get the celsius value
196+
const celsiusResult = await kernel.queueMessageFromKernel(
197+
celsiusRef,
198+
'getCelsius',
199+
[],
200+
);
201+
expect(kunser(celsiusResult)).toBe(100);
202+
// Get the fahrenheit value
203+
const fahrenheitResult = await kernel.queueMessageFromKernel(
204+
fahrenheitRef,
205+
'getFahrenheit',
206+
[],
207+
);
208+
expect(kunser(fahrenheitResult)).toBe(212);
209+
// Change the temperature using the fahrenheit facet
210+
const setFahrenheitResult = await kernel.queueMessageFromKernel(
211+
fahrenheitRef,
212+
'setFahrenheit',
213+
[32],
214+
);
215+
expect(kunser(setFahrenheitResult)).toBe(32);
216+
// Verify that the celsius value changed
217+
const newCelsiusResult = await kernel.queueMessageFromKernel(
218+
celsiusRef,
219+
'getCelsius',
220+
[],
221+
);
222+
expect(kunser(newCelsiusResult)).toBe(0);
223+
await waitUntilQuiescent(100);
224+
const vatLogs = extractVatLogs(buffered);
225+
expect(vatLogs).toContain(
226+
'ExoTest: Created temperature converter starting at 100°C',
227+
);
228+
}, 30000);
229+
});

0 commit comments

Comments
 (0)