@@ -30,6 +30,23 @@ type FaultInjection = { wasInjected: () => boolean };
3030
3131const FILESYSTEM_ERRNOS : readonly FilesystemErrno [ ] = [ 'EIO' , 'ENOSPC' , 'EMFILE' ] ;
3232const FAULT_POINTS : readonly FaultPoint [ ] = [ 'write' , 'rename' ] ;
33+ const REQUIRED_DAEMON_MATRIX_MODULES = [
34+ 'durable-capture-resource-store/screen-recording' ,
35+ 'durable-capture-resource-store/app-log' ,
36+ 'device-claims' ,
37+ 'session-script-writer' ,
38+ 'daemon-shutdown-report' ,
39+ 'session-store' ,
40+ ] as const ;
41+ const DURABLE_RESOURCE_CONFIGS = [
42+ {
43+ resourceKind : 'screen-recording' ,
44+ fileName : 'screen-recording.resource.json' ,
45+ displayName : 'Screen recording' ,
46+ } ,
47+ { resourceKind : 'app-log' , fileName : 'app-log.resource.json' , displayName : 'App-log' } ,
48+ ] as const ;
49+ const registeredDaemonMatrixRows : string [ ] = [ ] ;
3350
3451type BoundaryFixture = {
3552 targetPath : string ;
@@ -44,25 +61,23 @@ afterEach(() => {
4461 delete process . env . AGENT_DEVICE_CLAIMS_DIR ;
4562} ) ;
4663
47- registerFilesystemMatrix ( 'durable-capture-resource-store' , ( root ) => {
48- const store = createDurableCaptureResourceStore ( {
49- resourceKind : 'screen-recording' ,
50- fileName : 'screen-recording.resource.json' ,
51- displayName : 'Screen recording' ,
52- } ) ;
53- const targetPath = store . resolvePath ( path . join ( root , 'sessions' , 'default' ) ) ;
64+ for ( const config of DURABLE_RESOURCE_CONFIGS ) {
65+ registerFilesystemMatrix ( `durable-capture-resource-store/${ config . resourceKind } ` , ( root ) => {
66+ const store = createDurableCaptureResourceStore ( config ) ;
67+ const targetPath = store . resolvePath ( path . join ( root , 'sessions' , 'default' ) ) ;
5468
55- return {
56- targetPath,
57- // The durable store opens the temporary path and writes through its file
58- // descriptor, so the write-side fault is identified by the descriptor.
59- // This fixture performs no other writes after the fault is installed.
60- matchesPublishPath : ( value ) =>
61- typeof value === 'number' || matchesTargetOrTemporary ( value , targetPath ) ,
62- run : async ( ) => store . write ( targetPath , resourceEnvelope ( 'filesystem-fault' ) ) ,
63- expected : 'throw' ,
64- } ;
65- } ) ;
69+ return {
70+ targetPath,
71+ // The durable store opens the temporary path and writes through its file
72+ // descriptor, so the write-side fault is identified by the descriptor.
73+ matchesPublishPath : ( value ) =>
74+ typeof value === 'number' || matchesTargetOrTemporary ( value , targetPath ) ,
75+ run : async ( ) =>
76+ store . write ( targetPath , resourceEnvelope ( config . resourceKind , 'filesystem-fault' ) ) ,
77+ expected : 'throw' ,
78+ } ;
79+ } ) ;
80+ }
6681
6782registerFilesystemMatrix ( 'device-claims' , ( root ) => {
6883 const device : DeviceInfo = {
@@ -153,14 +168,26 @@ registerFilesystemMatrix('session-store', (root) => {
153168 } ;
154169} ) ;
155170
171+ test ( 'filesystem errno matrix declares every scoped daemon row' , ( ) => {
172+ const expectedRows = REQUIRED_DAEMON_MATRIX_MODULES . flatMap ( ( moduleName ) =>
173+ FAULT_POINTS . flatMap ( ( faultPoint ) =>
174+ FILESYSTEM_ERRNOS . map ( ( errno ) => `${ moduleName } :${ faultPoint } :${ errno } ` ) ,
175+ ) ,
176+ ) ;
177+ assert . deepEqual ( [ ...registeredDaemonMatrixRows ] . sort ( ) , expectedRows . sort ( ) ) ;
178+ } ) ;
179+
156180function registerFilesystemMatrix (
157181 moduleName : string ,
158182 createFixture : ( root : string ) => BoundaryFixture ,
159183) : void {
160184 for ( const faultPoint of FAULT_POINTS ) {
161185 for ( const errno of FILESYSTEM_ERRNOS ) {
186+ registeredDaemonMatrixRows . push ( `${ moduleName } :${ faultPoint } :${ errno } ` ) ;
162187 test ( `${ moduleName } ${ faultPoint } ${ errno } leaves no unpublished temporary file` , async ( ) => {
163- const root = mkdtempForTestSync ( `agent-device-${ moduleName } -boundary-` ) ;
188+ const root = mkdtempForTestSync (
189+ `agent-device-${ moduleName . replaceAll ( '/' , '-' ) } -boundary-` ,
190+ ) ;
164191 const fixture = createFixture ( root ) ;
165192 const fault = installFilesystemFault ( faultPoint , errno , fixture . matchesPublishPath ) ;
166193
@@ -199,6 +226,7 @@ function installFilesystemFault(
199226 vi . spyOn ( fs , 'writeFileSync' ) . mockImplementation ( ( ...args ) => {
200227 if ( matchesPublishPath ( args [ 0 ] ) ) {
201228 injected = true ;
229+ Reflect . apply ( originalWriteFileSync , fs , args ) ;
202230 throw failure ;
203231 }
204232 return Reflect . apply ( originalWriteFileSync , fs , args ) ;
@@ -251,9 +279,12 @@ function listTemporaryFiles(root: string): string[] {
251279 }
252280}
253281
254- function resourceEnvelope ( sessionId : string ) {
282+ function resourceEnvelope < ResourceKind extends 'screen-recording' | 'app-log' > (
283+ resourceKind : ResourceKind ,
284+ sessionId : string ,
285+ ) {
255286 return createDurableResourceEnvelope ( {
256- resourceKind : 'screen-recording' ,
287+ resourceKind,
257288 sessionId,
258289 device : { id : 'emulator-5554' , family : 'android' , kind : 'emulator' } ,
259290 owner : localRuntimeOwner ( 'android' ) ,
0 commit comments