@@ -61,35 +61,35 @@ describe('DatabaseCopier', () => {
6161 expect ( copier ) . toBeDefined ( ) ;
6262 } ) ;
6363
64- it ( 'should copy a database to the destination' , ( ) => {
64+ it ( 'should copy a database to the destination' , async ( ) => {
6565 createFakeDatabase ( sourceDir , 'my-db' ) ;
6666
6767 const copier = new DatabaseCopier ( destDir , logger ) ;
68- const results = copier . syncAll ( [ sourceDir ] ) ;
68+ const results = await copier . syncAll ( [ sourceDir ] ) ;
6969
7070 expect ( results ) . toHaveLength ( 1 ) ;
7171 expect ( results [ 0 ] ) . toBe ( join ( destDir , 'my-db' ) ) ;
7272 expect ( existsSync ( join ( destDir , 'my-db' , 'codeql-database.yml' ) ) ) . toBe ( true ) ;
7373 } ) ;
7474
75- it ( 'should create the destination directory if it does not exist' , ( ) => {
75+ it ( 'should create the destination directory if it does not exist' , async ( ) => {
7676 createFakeDatabase ( sourceDir , 'db-1' ) ;
7777
7878 const copier = new DatabaseCopier ( destDir , logger ) ;
79- copier . syncAll ( [ sourceDir ] ) ;
79+ await copier . syncAll ( [ sourceDir ] ) ;
8080
8181 expect ( existsSync ( destDir ) ) . toBe ( true ) ;
8282 } ) ;
8383
84- it ( 'should remove .lock files from the copy' , ( ) => {
84+ it ( 'should remove .lock files from the copy' , async ( ) => {
8585 createFakeDatabase ( sourceDir , 'locked-db' , { withLock : true } ) ;
8686
8787 // Verify lock exists in source
8888 const srcLock = join ( sourceDir , 'locked-db' , 'db-javascript' , 'default' , 'cache' , '.lock' ) ;
8989 expect ( existsSync ( srcLock ) ) . toBe ( true ) ;
9090
9191 const copier = new DatabaseCopier ( destDir , logger ) ;
92- copier . syncAll ( [ sourceDir ] ) ;
92+ await copier . syncAll ( [ sourceDir ] ) ;
9393
9494 // Lock file should NOT exist in the copy
9595 const destLock = join ( destDir , 'locked-db' , 'db-javascript' , 'default' , 'cache' , '.lock' ) ;
@@ -100,94 +100,100 @@ describe('DatabaseCopier', () => {
100100 expect ( existsSync ( join ( destDir , 'locked-db' , 'db-javascript' , 'default' , 'cache' ) ) ) . toBe ( true ) ;
101101 } ) ;
102102
103- it ( 'should not re-copy a database that has not changed' , ( ) => {
103+ it ( 'should not re-copy a database that has not changed' , async ( ) => {
104104 createFakeDatabase ( sourceDir , 'stable-db' ) ;
105105
106106 const copier = new DatabaseCopier ( destDir , logger ) ;
107- copier . syncAll ( [ sourceDir ] ) ;
107+ await copier . syncAll ( [ sourceDir ] ) ;
108108 expect ( logger . info ) . toHaveBeenCalledWith ( expect . stringContaining ( 'Copying database' ) ) ;
109109
110110 logger . info . mockClear ( ) ;
111- copier . syncAll ( [ sourceDir ] ) ;
111+ await copier . syncAll ( [ sourceDir ] ) ;
112112
113113 // Second call should NOT log a copy (database unchanged)
114114 expect ( logger . info ) . not . toHaveBeenCalledWith ( expect . stringContaining ( 'Copying database' ) ) ;
115115 } ) ;
116116
117- it ( 'should re-copy a database when source is newer' , ( ) => {
117+ it ( 'should re-copy a database when source is newer' , async ( ) => {
118118 createFakeDatabase ( sourceDir , 'updated-db' ) ;
119119
120120 const copier = new DatabaseCopier ( destDir , logger ) ;
121- copier . syncAll ( [ sourceDir ] ) ;
121+ await copier . syncAll ( [ sourceDir ] ) ;
122122
123123 // Advance the source codeql-database.yml mtime into the future
124124 const srcYml = join ( sourceDir , 'updated-db' , 'codeql-database.yml' ) ;
125125 const future = new Date ( Date . now ( ) + 10_000 ) ;
126126 utimesSync ( srcYml , future , future ) ;
127127
128128 logger . info . mockClear ( ) ;
129- copier . syncAll ( [ sourceDir ] ) ;
129+ await copier . syncAll ( [ sourceDir ] ) ;
130130
131131 expect ( logger . info ) . toHaveBeenCalledWith ( expect . stringContaining ( 'Copying database' ) ) ;
132132 } ) ;
133133
134- it ( 'should handle multiple source directories' , ( ) => {
134+ it ( 'should handle multiple source directories' , async ( ) => {
135135 const sourceDir2 = join ( tmpDir , 'source2' ) ;
136136 mkdirSync ( sourceDir2 , { recursive : true } ) ;
137137
138138 createFakeDatabase ( sourceDir , 'db-a' ) ;
139139 createFakeDatabase ( sourceDir2 , 'db-b' ) ;
140140
141141 const copier = new DatabaseCopier ( destDir , logger ) ;
142- const results = copier . syncAll ( [ sourceDir , sourceDir2 ] ) ;
142+ const results = await copier . syncAll ( [ sourceDir , sourceDir2 ] ) ;
143143
144144 expect ( results ) . toHaveLength ( 2 ) ;
145145 expect ( existsSync ( join ( destDir , 'db-a' , 'codeql-database.yml' ) ) ) . toBe ( true ) ;
146146 expect ( existsSync ( join ( destDir , 'db-b' , 'codeql-database.yml' ) ) ) . toBe ( true ) ;
147147 } ) ;
148148
149- it ( 'should skip non-existent source directories' , ( ) => {
149+ it ( 'should skip non-existent source directories' , async ( ) => {
150150 const copier = new DatabaseCopier ( destDir , logger ) ;
151- const results = copier . syncAll ( [ '/nonexistent/path' ] ) ;
151+ const results = await copier . syncAll ( [ '/nonexistent/path' ] ) ;
152152
153153 expect ( results ) . toHaveLength ( 0 ) ;
154154 } ) ;
155155
156- it ( 'should skip directories that are not CodeQL databases' , ( ) => {
156+ it ( 'should skip directories that are not CodeQL databases' , async ( ) => {
157157 // Create a regular directory (no codeql-database.yml)
158158 const notADb = join ( sourceDir , 'not-a-db' ) ;
159159 mkdirSync ( notADb , { recursive : true } ) ;
160160 writeFileSync ( join ( notADb , 'README.md' ) , '# Not a database' ) ;
161161
162162 const copier = new DatabaseCopier ( destDir , logger ) ;
163- const results = copier . syncAll ( [ sourceDir ] ) ;
163+ const results = await copier . syncAll ( [ sourceDir ] ) ;
164164
165165 expect ( results ) . toHaveLength ( 0 ) ;
166166 } ) ;
167167
168- it ( 'should not modify the source .lock files' , ( ) => {
168+ it ( 'should not modify the source .lock files' , async ( ) => {
169169 createFakeDatabase ( sourceDir , 'locked-db' , { withLock : true } ) ;
170170 const srcLock = join ( sourceDir , 'locked-db' , 'db-javascript' , 'default' , 'cache' , '.lock' ) ;
171171
172172 const copier = new DatabaseCopier ( destDir , logger ) ;
173- copier . syncAll ( [ sourceDir ] ) ;
173+ await copier . syncAll ( [ sourceDir ] ) ;
174174
175175 // Source lock file must remain untouched
176176 expect ( existsSync ( srcLock ) ) . toBe ( true ) ;
177177 } ) ;
178178
179- it ( 'should log an error when copy fails' , ( ) => {
179+ it ( 'should log an error and exclude database when copy fails' , async ( ) => {
180180 createFakeDatabase ( sourceDir , 'bad-db' ) ;
181181
182- // Make destination read-only to cause a copy failure
183- mkdirSync ( destDir , { recursive : true } ) ;
184- const blockerPath = join ( destDir , 'bad-db' ) ;
185- writeFileSync ( blockerPath , 'I am a file, not a directory' ) ;
182+ // Make the destination base directory read-only to prevent cp from writing
183+ mkdirSync ( destDir , { mode : 0o444 , recursive : true } ) ;
186184
187185 const copier = new DatabaseCopier ( destDir , logger ) ;
188- // rmSync on a file should succeed, then cpSync should work — but
189- // this tests the error path if something goes truly wrong.
190- // Actually, since rmSync handles files, let's just verify no throw:
191- expect ( ( ) => copier . syncAll ( [ sourceDir ] ) ) . not . toThrow ( ) ;
186+ const results = await copier . syncAll ( [ sourceDir ] ) ;
187+
188+ // Restore permissions for cleanup
189+ const { chmod } = await import ( 'fs/promises' ) ;
190+ await chmod ( destDir , 0o755 ) ;
191+
192+ // Should have logged the error
193+ expect ( logger . error ) . toHaveBeenCalledWith (
194+ expect . stringContaining ( 'Failed to copy database' ) ,
195+ ) ;
196+ // Should NOT include the failed database in results
197+ expect ( results ) . toHaveLength ( 0 ) ;
192198 } ) ;
193199} ) ;
0 commit comments