@@ -6,7 +6,12 @@ import { makeSQLKernelDatabase } from '@ocap/store/sqlite/nodejs';
66import { waitUntilQuiescent } from '@ocap/utils' ;
77import { expect , beforeEach , afterEach , describe , it } from 'vitest' ;
88
9- import { getBundleSpec , makeKernel , runTestVats } from './utils.ts' ;
9+ import {
10+ getBundleSpec ,
11+ makeKernel ,
12+ parseReplyBody ,
13+ runTestVats ,
14+ } from './utils.ts' ;
1015
1116/**
1217 * Make a test subcluster with vats for GC testing
@@ -103,7 +108,7 @@ describe('Garbage Collection E2E Tests', () => {
103108 [ ] ,
104109 ) ;
105110 await waitUntilQuiescent ( ) ;
106- expect ( useResult . body ) . toContain ( objectId ) ;
111+ expect ( parseReplyBody ( useResult . body ) ) . toBe ( objectId ) ;
107112 } ) ;
108113
109114 it ( 'should trigger GC syscalls through bringOutYourDead' , async ( ) => {
@@ -114,88 +119,91 @@ describe('Garbage Collection E2E Tests', () => {
114119 'createObject' ,
115120 [ objectId ] ,
116121 ) ;
117- const objectRef = createObjectData . slots [ 0 ] as KRef ;
122+ const createObjectRef = createObjectData . slots [ 0 ] as KRef ;
118123
119124 // Store initial reference count information
120- const initialRefCounts = kernelStore . getObjectRefCount ( objectRef ) ;
125+ const initialRefCounts = kernelStore . getObjectRefCount ( createObjectRef ) ;
126+ console . log ( 'Initial ref counts:' , createObjectRef , initialRefCounts ) ;
121127 expect ( initialRefCounts . reachable ) . toBe ( 1 ) ;
122128 expect ( initialRefCounts . recognizable ) . toBe ( 1 ) ;
123129
124130 // 2. Store the reference in the importer vat
131+ const objectRef = kunser ( createObjectData ) ;
125132 await kernel . queueMessageFromKernel ( importerKRef , 'storeImport' , [
126133 objectRef ,
127134 objectId ,
128135 ] ) ;
129136 await waitUntilQuiescent ( ) ;
130137
138+ // Get reference counts after storing in importer
139+ const afterStoreRefCounts = kernelStore . getObjectRefCount ( createObjectRef ) ;
140+ console . log ( 'After store ref counts:' , objectRef , afterStoreRefCounts ) ;
141+
131142 // 3. Verify object is tracked in both vats
132143 const importerHasObject = await kernel . queueMessageFromKernel (
133144 importerKRef ,
134145 'listImportedObjects' ,
135146 [ ] ,
136147 ) ;
137148 console . log ( '$$$ importerHasObject' , importerHasObject ) ;
138- expect ( importerHasObject . body ) . toContain ( objectId ) ;
149+ expect ( parseReplyBody ( importerHasObject . body ) ) . toContain ( objectId ) ;
139150
140151 const exporterHasObject = await kernel . queueMessageFromKernel (
141152 exporterKRef ,
142153 'isObjectPresent' ,
143154 [ objectId ] ,
144155 ) ;
145156 console . log ( '$$$ exporterHasObject' , exporterHasObject ) ;
146- expect ( exporterHasObject . body ) . toBe ( '# true' ) ;
157+ expect ( parseReplyBody ( exporterHasObject . body ) ) . toBe ( true ) ;
147158
148159 // 4. Make a weak reference to the object in the importer vat
149160 // This should eventually trigger dropImports when GC runs
150161 await kernel . queueMessageFromKernel ( importerKRef , 'makeWeak' , [ objectId ] ) ;
151162 await waitUntilQuiescent ( ) ;
152163
153- // 5. Schedule reap to trigger bringOutYourDead on next crank
154- kernelStore . scheduleReap ( exporterVatId ) ;
164+ console . log ( '$$$ kernelStore.getGCActions(1)' , kernelStore . getGCActions ( ) ) ;
165+
166+ // // 5. Schedule reap to trigger bringOutYourDead on next crank
167+ kernel . reapAllVats ( ) ;
155168
156- // 6. Run a crank to allow bringOutYourDead to be processed
169+ // // 6. Run a crank to allow bringOutYourDead to be processed
157170 await kernel . queueMessageFromKernel ( exporterKRef , 'noop' , [ ] ) ;
158171 await waitUntilQuiescent ( 100 ) ;
159172
160- // Check reference counts after dropImports (should be decreased reachable but same recognizable)
161- const afterWeakRefCounts = kernelStore . getObjectRefCount ( objectRef ) ;
162- expect ( afterWeakRefCounts . reachable ) . toBeLessThan (
163- initialRefCounts . reachable ,
164- ) ;
165- expect ( afterWeakRefCounts . recognizable ) . toBe ( initialRefCounts . recognizable ) ;
173+ console . log ( '$$$ kernelStore.getGCActions(2)' , kernelStore . getGCActions ( ) ) ;
174+
175+ // // Check reference counts after dropImports
176+ const afterWeakRefCounts = kernelStore . getObjectRefCount ( createObjectRef ) ;
177+ console . log ( 'After weak ref counts:' , afterWeakRefCounts ) ;
178+ expect ( afterWeakRefCounts . reachable ) . toBe ( 0 ) ;
179+ expect ( afterWeakRefCounts . recognizable ) . toBe ( 1 ) ;
166180
167181 // 7. Now completely forget the import in the importer vat
168182 // This should trigger retireImports when GC runs
169- await kernel . queueMessageFromKernel ( importerKRef , 'forgetImport' , [
170- objectId ,
171- ] ) ;
183+ await kernel . queueMessageFromKernel ( importerKRef , 'forgetImport' , [ ] ) ;
172184 await waitUntilQuiescent ( ) ;
173185
174186 // 8. Schedule another reap
175- kernelStore . scheduleReap ( importerVatId ) ;
187+ kernel . reapAllVats ( ) ;
176188
177189 // 9. Run a crank to allow bringOutYourDead to be processed
178190 await kernel . queueMessageFromKernel ( importerKRef , 'noop' , [ ] ) ;
179191 await waitUntilQuiescent ( 100 ) ;
180192
181193 // Check reference counts after retireImports (both should be decreased)
182- const afterForgetRefCounts = kernelStore . getObjectRefCount ( objectRef ) ;
183- expect ( afterForgetRefCounts . reachable ) . toBeLessThan (
184- initialRefCounts . reachable ,
185- ) ;
186- expect ( afterForgetRefCounts . recognizable ) . toBeLessThan (
187- initialRefCounts . recognizable ,
188- ) ;
194+ const afterForgetRefCounts = kernelStore . getObjectRefCount ( createObjectRef ) ;
195+ expect ( afterForgetRefCounts . reachable ) . toBe ( 0 ) ;
196+ expect ( afterForgetRefCounts . recognizable ) . toBe ( 0 ) ;
189197
190- // 10. Now forget the object in the exporter vat
191- // This should trigger retireExports when GC runs
198+ // // 10. Now forget the object in the exporter vat
199+ // // This should trigger retireExports when GC runs
192200 await kernel . queueMessageFromKernel ( exporterKRef , 'forgetObject' , [
193201 objectId ,
194202 ] ) ;
195203 await waitUntilQuiescent ( ) ;
196204
197205 // 11. Schedule a final reap
198- kernelStore . scheduleReap ( exporterVatId ) ;
206+ kernel . reapAllVats ( ) ;
199207
200208 // 12. Run multiple cranks to ensure GC completes
201209 for ( let i = 0 ; i < 3 ; i ++ ) {
@@ -210,77 +218,79 @@ describe('Garbage Collection E2E Tests', () => {
210218 [ objectId ] ,
211219 ) ;
212220 console . log ( '$$$ exporterFinalCheck' , exporterFinalCheck ) ;
213- expect ( exporterFinalCheck . body ) . toBe ( '# false' ) ;
221+ expect ( parseReplyBody ( exporterFinalCheck . body ) ) . toBe ( false ) ;
214222
215223 // Check if reference still exists in the kernel store at all
216- const refExists = kernelStore . kernelRefExists ( objectRef ) ;
217- expect ( refExists ) . toBe ( false ) ;
218-
219- // 13. Test abandonExports by creating a new object and forcing its removal
220- const abandonObjectId = 'abandon-test' ;
221- const abandonObjData = await kernel . queueMessageFromKernel (
222- exporterKRef ,
223- 'createObject' ,
224- [ abandonObjectId ] ,
225- ) ;
226- console . log ( '$$$ abandonObjData' , abandonObjData ) ;
227- const abandonObjRef = abandonObjData . slots [ 0 ] as KRef ;
228-
229- // Store in importer to make it reachable from both vats
230- await kernel . queueMessageFromKernel ( importerKRef , 'storeImport' , [
231- abandonObjRef ,
232- abandonObjectId ,
233- ] ) ;
234- await waitUntilQuiescent ( ) ;
235-
236- // Verify it's reachable from both vats
237- const abandonRefCounts = kernelStore . getObjectRefCount ( abandonObjRef ) ;
238- expect ( abandonRefCounts . reachable ) . toBe ( 1 ) ;
239-
240- // Force remove in exporter (this simulates abandonExports)
241- await kernel . queueMessageFromKernel ( exporterKRef , 'forgetObject' , [
242- abandonObjectId ,
243- ] ) ;
244- await waitUntilQuiescent ( ) ;
245-
246- // Schedule reap to trigger abandonExports
247- kernelStore . scheduleReap ( exporterVatId ) ;
248-
249- // Run multiple cranks to ensure GC completes
250- for ( let i = 0 ; i < 3 ; i ++ ) {
251- await kernel . queueMessageFromKernel ( exporterKRef , 'noop' , [ ] ) ;
252- await waitUntilQuiescent ( 50 ) ;
253- }
254-
255- // Verify object is gone from exporter
256- const exporterAbandonCheck = await kernel . queueMessageFromKernel (
257- exporterKRef ,
258- 'isObjectPresent' ,
259- [ abandonObjectId ] ,
260- ) ;
261- console . log ( '$$$ exporterAbandonCheck' , exporterAbandonCheck ) ;
262- expect ( exporterAbandonCheck . body ) . toBe ( '#false' ) ;
263-
264- // But it should still be in the importer's list
265- const importerAbandonCheck = await kernel . queueMessageFromKernel (
266- importerKRef ,
267- 'listImportedObjects' ,
268- [ ] ,
269- ) ;
270- console . log ( '$$$ importerAbandonCheck' , importerAbandonCheck ) ;
271- expect ( importerAbandonCheck . body ) . toContain ( abandonObjectId ) ;
272-
273- // However, using the object should now fail
274- try {
275- await kernel . queueMessageFromKernel ( importerKRef , 'useImport' , [
276- abandonObjectId ,
277- ] ) ;
278- // Should not reach here
279- expect ( false ) . toBe ( true ) ;
280- } catch ( error ) {
281- // We expect an error
282- // eslint-disable-next-line vitest/no-conditional-expect
283- expect ( error ) . toBeDefined ( ) ;
284- }
224+ // const refExists = kernelStore.kernelRefExists(createObjectRef);
225+ // expect(refExists).toBe(false);
226+
227+ // // 13. Test abandonExports by creating a new object and forcing its removal
228+ // const abandonObjectId = 'abandon-test';
229+ // const abandonObjData = await kernel.queueMessageFromKernel(
230+ // exporterKRef,
231+ // 'createObject',
232+ // [abandonObjectId],
233+ // );
234+ // console.log('$$$ abandonObjData', abandonObjData);
235+ // const abandonObjRef = abandonObjData.slots[0] as KRef;
236+
237+ // // Store in importer to make it reachable from both vats
238+ // await kernel.queueMessageFromKernel(importerKRef, 'storeImport', [
239+ // abandonObjRef,
240+ // abandonObjectId,
241+ // ]);
242+ // await waitUntilQuiescent();
243+
244+ // // Verify it's reachable from both vats
245+ // const abandonRefCounts = kernelStore.getObjectRefCount(abandonObjRef);
246+ // expect(abandonRefCounts.reachable).toBe(1);
247+
248+ // // Force remove in exporter (this simulates abandonExports)
249+ // await kernel.queueMessageFromKernel(exporterKRef, 'forgetObject', [
250+ // abandonObjectId,
251+ // ]);
252+ // await waitUntilQuiescent();
253+
254+ // // Schedule reap to trigger abandonExports
255+ // kernelStore.scheduleReap(exporterVatId);
256+
257+ // // Run multiple cranks to ensure GC completes
258+ // for (let i = 0; i < 3; i++) {
259+ // await kernel.queueMessageFromKernel(exporterKRef, 'noop', []);
260+ // await waitUntilQuiescent(50);
261+ // }
262+
263+ // // Verify object is gone from exporter
264+ // const exporterAbandonCheck = await kernel.queueMessageFromKernel(
265+ // exporterKRef,
266+ // 'isObjectPresent',
267+ // [abandonObjectId],
268+ // );
269+ // console.log('$$$ exporterAbandonCheck', exporterAbandonCheck);
270+ // expect(parseReplyBody(exporterAbandonCheck.body)).toBe(false);
271+
272+ // // But it should still be in the importer's list
273+ // const importerAbandonCheck = await kernel.queueMessageFromKernel(
274+ // importerKRef,
275+ // 'listImportedObjects',
276+ // [],
277+ // );
278+ // console.log('$$$ importerAbandonCheck', importerAbandonCheck);
279+ // expect(parseReplyBody(importerAbandonCheck.body)).toContain(
280+ // abandonObjectId,
281+ // );
282+
283+ // // However, using the object should now fail
284+ // try {
285+ // await kernel.queueMessageFromKernel(importerKRef, 'useImport', [
286+ // abandonObjectId,
287+ // ]);
288+ // // Should not reach here
289+ // expect(false).toBe(true);
290+ // } catch (error) {
291+ // // We expect an error
292+ // // eslint-disable-next-line vitest/no-conditional-expect
293+ // expect(error).toBeDefined();
294+ // }
285295 } ) ;
286296} ) ;
0 commit comments