Skip to content

Commit 91f45ad

Browse files
committed
fix exo tests
1 parent c034056 commit 91f45ad

File tree

3 files changed

+155
-108
lines changed

3 files changed

+155
-108
lines changed

packages/kernel-test/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,7 @@
4747
"test:watch": "vitest --config vitest.config.ts"
4848
},
4949
"devDependencies": {
50-
"@agoric/store": "0.9.3-u19.0",
5150
"@arethetypeswrong/cli": "^0.17.4",
52-
"@endo/exo": "^1.5.9",
53-
"@endo/patterns": "^1.5.0",
5451
"@metamask/auto-changelog": "^5.0.1",
5552
"@metamask/eslint-config": "^14.0.0",
5653
"@metamask/eslint-config-nodejs": "^14.0.0",
@@ -85,8 +82,11 @@
8582
"node": "^20 || >=22"
8683
},
8784
"dependencies": {
85+
"@agoric/store": "0.9.3-u19.0",
8886
"@endo/eventual-send": "^1.3.1",
87+
"@endo/exo": "^1.5.9",
8988
"@endo/marshal": "^1.6.4",
89+
"@endo/patterns": "^1.5.0",
9090
"@endo/promise-kit": "^1.1.10",
9191
"@ocap/kernel": "workspace:^",
9292
"@ocap/nodejs": "workspace:^",
Lines changed: 132 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import '@ocap/shims/endoify';
22
import { Kernel, kunser } from '@ocap/kernel';
3+
import type { KRef } from '@ocap/kernel';
34
import type { KernelDatabase } from '@ocap/store';
45
import { makeSQLKernelDatabase } from '@ocap/store/sqlite/nodejs';
56
import { waitUntilQuiescent } from '@ocap/utils';
@@ -45,99 +46,78 @@ describe('virtual objects functionality', async () => {
4546
kernel = await makeKernel(kernelDatabase, true);
4647
buffered = '';
4748
bootstrapResult = await runTestVats(kernel, testSubcluster);
48-
await waitUntilQuiescent();
49+
await waitUntilQuiescent(100);
4950
});
5051

5152
it('successfully creates and uses exo objects and scalar stores', async () => {
5253
expect(bootstrapResult).toBe('exo-test-complete');
5354
const vatLogs = extractVatLogs(buffered);
54-
// Verify exo objects were created and used
55-
expect(vatLogs).toContain('ExoTest: initializing state');
56-
expect(vatLogs).toContain('ExoTest: counter value from baggage: 0');
57-
expect(vatLogs).toContain(
58-
'::> ExoTest: Created counter with initial value: 10',
59-
);
60-
expect(vatLogs).toContain('::> ExoTest: Incremented counter by 5 to: 15');
61-
// Verify scalar map store functionality
62-
expect(vatLogs).toContain('::> ExoTest: Added 2 entries to map store');
63-
expect(vatLogs).toContain('::> ExoTest: Retrieved Alice from map store');
64-
// Verify scalar set store functionality
65-
expect(vatLogs).toContain('::> ExoTest: Added 2 entries to set store');
66-
// Verify exo validation works
67-
expect(vatLogs).toContain(
68-
'::> ExoTest: Successfully caught error on negative increment',
69-
);
70-
// Verify exoClassKit temperature converter
71-
expect(vatLogs).toContain('::> ExoTest: Temperature at 25°C =');
72-
expect(vatLogs).toContain('::> ExoTest: After setting to 68°F, celsius is');
73-
// Verify makeExo direct instance
74-
expect(vatLogs).toContain('::> ExoTest: SimpleCounter initial value:');
75-
expect(vatLogs).toContain('::> ExoTest: SimpleCounter after +7:');
76-
}, 30000);
77-
78-
it('preserves state across vat restarts', async () => {
79-
// Restart the vat
80-
await kernel.restartVat('v1');
81-
buffered = '';
82-
// Create and send a message to the root
83-
await kernel.queueMessageFromKernel('ko1', 'resume', []);
84-
await waitUntilQuiescent();
85-
const vatLogs = extractVatLogs(buffered);
86-
// Verify state was preserved
87-
expect(vatLogs).toContain('ExoTest: state already initialized');
88-
expect(vatLogs).toContain('ExoTest: Counter value after restart: 7');
89-
// Verify stores persistence
90-
expect(vatLogs).toContain('::> ExoTest: Map store size after restart: 2');
91-
expect(vatLogs).toContain('::> ExoTest: Set store size after restart: 2');
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+
]);
9272
}, 30000);
9373

9474
it('tests scalar store functionality', async () => {
75+
buffered = '';
9576
const storeResult = await kernel.queueMessageFromKernel(
9677
'ko1',
9778
'testScalarStore',
9879
[],
9980
);
100-
await waitUntilQuiescent();
101-
const vatLogs = extractVatLogs(buffered);
102-
// Verify test result
81+
await waitUntilQuiescent(100);
10382
expect(kunser(storeResult)).toBe('scalar-store-tests-complete');
104-
// Verify map store operations
105-
expect(vatLogs).toContain('::> ExoTest: Map store size:');
106-
expect(vatLogs).toContain('::> ExoTest: Map store keys:');
107-
expect(vatLogs).toContain("::> ExoTest: Map has 'charlie': true");
108-
// Verify set store operations
109-
expect(vatLogs).toContain('::> ExoTest: Set store size:');
110-
expect(vatLogs).toContain('::> ExoTest: Set has Charlie: true');
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+
]);
11191
}, 30000);
11292

11393
it('can create and use objects through messaging', async () => {
114-
// Create a counter through messaging
94+
buffered = '';
11595
const counterResult = await kernel.queueMessageFromKernel(
11696
'ko1',
11797
'createCounter',
11898
[42],
11999
);
120100
await waitUntilQuiescent();
121-
122-
// Use the returned counter object
123-
const counterRef = JSON.parse(counterResult.body).slots[0];
101+
const counterRef = counterResult.slots[0] as KRef;
124102
const incrementResult = await kernel.queueMessageFromKernel(
125103
counterRef,
126104
'increment',
127105
[5],
128106
);
107+
// Verify the increment result
108+
expect(kunser(incrementResult)).toBe(47);
129109
await waitUntilQuiescent();
130-
131-
// Add object to map store
132110
const personResult = await kernel.queueMessageFromKernel(
133111
'ko1',
134112
'createPerson',
135113
['Dave', 35],
136114
);
137115
await waitUntilQuiescent();
138-
139-
const personRef = JSON.parse(personResult.body).slots[0];
140-
await kernel.queueMessageFromKernel('ko1', 'addToMap', ['dave', personRef]);
116+
const personRef = personResult.slots[0] as KRef;
117+
await kernel.queueMessageFromKernel('ko1', 'createOrUpdateInMap', [
118+
'dave',
119+
personRef,
120+
]);
141121
await waitUntilQuiescent();
142122

143123
// Get object from map store
@@ -147,19 +127,103 @@ describe('virtual objects functionality', async () => {
147127
['dave'],
148128
);
149129
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);
150137
const vatLogs = extractVatLogs(buffered);
151-
152138
// 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);
153225
expect(vatLogs).toContain(
154-
'::> ExoTest: Created new counter with value: 42',
226+
'ExoTest: Created temperature converter starting at 100°C',
155227
);
156-
expect(JSON.parse(incrementResult.body).body).toBe(47);
157-
// Verify map store operations through messaging
158-
expect(vatLogs).toContain('::> ExoTest: Created person Dave, age 35');
159-
expect(vatLogs).toContain('::> ExoTest: Added dave to map');
160-
expect(vatLogs).toContain('::> ExoTest: Found dave in map');
161-
// Verify the retrieved person object
162-
const personSlot = JSON.parse(retrievedPerson.body).slots[0];
163-
expect(personSlot).toBeDefined();
164228
}, 30000);
165229
});

packages/kernel-test/src/vats/exo-vat.js

Lines changed: 20 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,16 @@ export function buildRootObject(_vatPowers, parameters, baggage) {
4646
// Define interfaces for our Exo objects
4747
const CounterI = M.interface('Counter', {
4848
getValue: M.call().returns(M.number()),
49-
increment: M.call(M.optional(M.number())).returns(M.number()),
50-
decrement: M.call(M.optional(M.number())).returns(M.number()),
49+
increment: M.call(M.number()).returns(M.number()),
50+
decrement: M.call(M.number()).returns(M.number()),
5151
});
5252

5353
const PersonI = M.interface('Person', {
5454
getName: M.call().returns(M.string()),
5555
getAge: M.call().returns(M.number()),
5656
birthday: M.call().returns(M.number()),
57-
addFriend: M.call(M.object()).returns(M.number()),
58-
getFriends: M.call().returns(M.arrayOf(M.object())),
57+
addFriend: M.call(M.any()).returns(M.number()),
58+
getFriends: M.call().returns(M.arrayOf(M.any())),
5959
});
6060

6161
// Define two facets for a Temperature converter
@@ -196,14 +196,14 @@ export function buildRootObject(_vatPowers, parameters, baggage) {
196196
tlog(`${alice.getName()} has ${alice.getFriends().length} friends`);
197197

198198
// Test map store
199-
mapStore.set('alice', alice);
200-
mapStore.set('bob', bob);
201-
tlog(`Added ${mapStore.size} entries to map store`);
199+
mapStore.init('alice', alice);
200+
mapStore.init('bob', bob);
201+
tlog(`Added ${mapStore.getSize()} entries to map store`);
202202

203203
// Test set store
204204
setStore.add(alice);
205205
setStore.add(bob);
206-
tlog(`Added ${setStore.size} entries to set store`);
206+
tlog(`Added ${setStore.getSize()} entries to set store`);
207207

208208
// Test retrieving from stores
209209
const retrievedAlice = mapStore.get('alice');
@@ -247,10 +247,15 @@ export function buildRootObject(_vatPowers, parameters, baggage) {
247247
return temperature;
248248
},
249249

250-
addToMap(key, value) {
251-
mapStore.set(key, value);
252-
tlog(`Added ${key} to map, size now: ${mapStore.size}`);
253-
return mapStore.size;
250+
createOrUpdateInMap(key, value) {
251+
if (mapStore.has(key)) {
252+
mapStore.set(key, value);
253+
tlog(`Updated ${key} in map`);
254+
} else {
255+
mapStore.init(key, value);
256+
tlog(`Added ${key} to map, size now: ${mapStore.getSize()}`);
257+
}
258+
return mapStore.getSize();
254259
},
255260

256261
getFromMap(key) {
@@ -262,18 +267,6 @@ export function buildRootObject(_vatPowers, parameters, baggage) {
262267
return null;
263268
},
264269

265-
addToSet(value) {
266-
setStore.add(value);
267-
tlog(`Added item to set, size now: ${setStore.size}`);
268-
return setStore.size;
269-
},
270-
271-
hasInSet(value) {
272-
const result = setStore.has(value);
273-
tlog(`Checking if item exists in set: ${result}`);
274-
return result;
275-
},
276-
277270
testExoClass() {
278271
const counter = Counter(3);
279272
let result = counter.increment(5);
@@ -316,27 +309,17 @@ export function buildRootObject(_vatPowers, parameters, baggage) {
316309
testScalarStore() {
317310
// Test map store operations
318311
const person = Person('Charlie', 40);
319-
mapStore.set('charlie', person);
320-
tlog(`Map store size: ${mapStore.size}`);
312+
mapStore.init('charlie', person);
313+
tlog(`Map store size: ${mapStore.getSize()}`);
321314
tlog(`Map store keys: ${[...mapStore.keys()].join(', ')}`);
322315
tlog(`Map has 'charlie': ${mapStore.has('charlie')}`);
323316

324317
// Test set store operations
325318
setStore.add(person);
326-
tlog(`Set store size: ${setStore.size}`);
319+
tlog(`Set store size: ${setStore.getSize()}`);
327320
tlog(`Set has Charlie: ${setStore.has(person)}`);
328321

329322
return 'scalar-store-tests-complete';
330323
},
331-
332-
resume() {
333-
tlog(`resume()`);
334-
tlog(`Counter value after restart: ${counterValue}`);
335-
tlog(`SimpleCounter value after restart: ${simpleCounter.getValue()}`);
336-
tlog(`Map store size after restart: ${mapStore.size}`);
337-
tlog(`Set store size after restart: ${setStore.size}`);
338-
339-
return `resume ${vatName}`;
340-
},
341324
});
342325
}

0 commit comments

Comments
 (0)