@@ -14,6 +14,7 @@ import {
1414 getCacheRestoreKeyPrefix ,
1515 getCacheSaveKey ,
1616 getCacheWorkflowKeyPrefix ,
17+ getCodeQLVersionFromOverlayBaseDatabase ,
1718 OverlayDatabaseMode ,
1819 writeBaseDatabaseOidsFile ,
1920 writeOverlayChangesFile ,
@@ -315,3 +316,146 @@ test("overlay-base database cache keys remain stable", async (t) => {
315316 `Expected restore key prefix "${ restoreKeyPrefix } " to start with workflow key prefix "${ workflowKeyPrefix } "` ,
316317 ) ;
317318} ) ;
319+
320+ /**
321+ * Helper function to generate a cache save key for testing.
322+ * Sets up the necessary sinon stubs and returns the generated cache key.
323+ */
324+ async function generateTestCacheKey ( codeQlVersion : string ) : Promise < string > {
325+ const config = createTestConfig ( { languages : [ "python" , "javascript" ] } ) ;
326+ const commitOid = "abc123def456" ;
327+
328+ sinon . stub ( apiClient , "getAutomationID" ) . resolves ( "test-automation-id/" ) ;
329+ sinon . stub ( gitUtils , "getCommitOid" ) . resolves ( commitOid ) ;
330+
331+ return await getCacheSaveKey ( config , codeQlVersion , "checkout-path" ) ;
332+ }
333+
334+ /**
335+ * Helper function to stub getMostRecentActionsCacheEntry with a given key and creation date.
336+ * Returns the stubbed function for cleanup if needed.
337+ */
338+ function stubMostRecentActionsCacheEntry ( key ?: string , createdAt ?: Date ) {
339+ const cacheItem =
340+ key !== undefined || createdAt !== undefined
341+ ? {
342+ key,
343+ created_at : createdAt ?. toISOString ( ) ,
344+ }
345+ : undefined ;
346+
347+ return sinon
348+ . stub ( apiClient , "getMostRecentActionsCacheEntry" )
349+ . resolves ( cacheItem ) ;
350+ }
351+
352+ test ( "getCodeQLVersionFromOverlayBaseDatabase returns version when cache entry is valid" , async ( t ) => {
353+ const logger = getRunnerLogger ( true ) ;
354+ const cacheKey = await generateTestCacheKey ( "2.23.0" ) ;
355+
356+ stubMostRecentActionsCacheEntry ( cacheKey , new Date ( ) ) ;
357+
358+ const result = await getCodeQLVersionFromOverlayBaseDatabase ( logger ) ;
359+ t . is ( result , "2.23.0" , "Should return the extracted CodeQL version" ) ;
360+ } ) ;
361+
362+ test ( "getCodeQLVersionFromOverlayBaseDatabase returns undefined when no cache entries found" , async ( t ) => {
363+ const logger = getRunnerLogger ( true ) ;
364+
365+ sinon . stub ( apiClient , "getAutomationID" ) . resolves ( "test-automation-id/" ) ;
366+ stubMostRecentActionsCacheEntry ( ) ;
367+
368+ const result = await getCodeQLVersionFromOverlayBaseDatabase ( logger ) ;
369+ t . is (
370+ result ,
371+ undefined ,
372+ "Should return undefined when no cache entries found" ,
373+ ) ;
374+ } ) ;
375+
376+ test ( "getCodeQLVersionFromOverlayBaseDatabase returns undefined when cache entry is too old" , async ( t ) => {
377+ const logger = getRunnerLogger ( true ) ;
378+ const cacheKey = await generateTestCacheKey ( "2.23.0" ) ;
379+
380+ const oldDate = new Date ( ) ;
381+ oldDate . setDate ( oldDate . getDate ( ) - 15 ) ; // 15 days ago (older than 14 day limit)
382+
383+ stubMostRecentActionsCacheEntry ( cacheKey , oldDate ) ;
384+
385+ const result = await getCodeQLVersionFromOverlayBaseDatabase ( logger ) ;
386+ t . is (
387+ result ,
388+ undefined ,
389+ "Should return undefined when cache entry is too old" ,
390+ ) ;
391+ } ) ;
392+
393+ test ( "getCodeQLVersionFromOverlayBaseDatabase returns undefined when cache key format is invalid" , async ( t ) => {
394+ const logger = getRunnerLogger ( true ) ;
395+
396+ sinon . stub ( apiClient , "getAutomationID" ) . resolves ( "test-automation-id/" ) ;
397+ stubMostRecentActionsCacheEntry ( "invalid-key-format" , new Date ( ) ) ;
398+
399+ const result = await getCodeQLVersionFromOverlayBaseDatabase ( logger ) ;
400+ t . is (
401+ result ,
402+ undefined ,
403+ "Should return undefined when cache key format is invalid" ,
404+ ) ;
405+ } ) ;
406+
407+ test ( "getCodeQLVersionFromOverlayBaseDatabase returns undefined when CodeQL version is invalid semver" , async ( t ) => {
408+ const logger = getRunnerLogger ( true ) ;
409+ const invalidCacheKey = await generateTestCacheKey ( "invalid.version" ) ;
410+
411+ stubMostRecentActionsCacheEntry ( invalidCacheKey , new Date ( ) ) ;
412+
413+ const result = await getCodeQLVersionFromOverlayBaseDatabase ( logger ) ;
414+ t . is (
415+ result ,
416+ undefined ,
417+ "Should return undefined when CodeQL version is invalid semver" ,
418+ ) ;
419+ } ) ;
420+
421+ test ( "getCodeQLVersionFromOverlayBaseDatabase returns undefined when CodeQL version is too old" , async ( t ) => {
422+ const logger = getRunnerLogger ( true ) ;
423+ const cacheKey = await generateTestCacheKey ( "2.20.0" ) ; // Older than minimum required version (2.22.4)
424+
425+ stubMostRecentActionsCacheEntry ( cacheKey , new Date ( ) ) ;
426+
427+ const result = await getCodeQLVersionFromOverlayBaseDatabase ( logger ) ;
428+ t . is (
429+ result ,
430+ undefined ,
431+ "Should return undefined when CodeQL version is older than minimum required version" ,
432+ ) ;
433+ } ) ;
434+
435+ test ( "getCodeQLVersionFromOverlayBaseDatabase returns undefined when cache entry has no key" , async ( t ) => {
436+ const logger = getRunnerLogger ( true ) ;
437+
438+ sinon . stub ( apiClient , "getAutomationID" ) . resolves ( "test-automation-id/" ) ;
439+ stubMostRecentActionsCacheEntry ( undefined , new Date ( ) ) ;
440+
441+ const result = await getCodeQLVersionFromOverlayBaseDatabase ( logger ) ;
442+ t . is (
443+ result ,
444+ undefined ,
445+ "Should return undefined when cache entry has no key" ,
446+ ) ;
447+ } ) ;
448+
449+ test ( "getCodeQLVersionFromOverlayBaseDatabase returns undefined when cache entry has no created_at" , async ( t ) => {
450+ const logger = getRunnerLogger ( true ) ;
451+ const cacheKey = await generateTestCacheKey ( "2.23.0" ) ;
452+
453+ stubMostRecentActionsCacheEntry ( cacheKey , undefined ) ;
454+
455+ const result = await getCodeQLVersionFromOverlayBaseDatabase ( logger ) ;
456+ t . is (
457+ result ,
458+ undefined ,
459+ "Should return undefined when cache entry has no created_at" ,
460+ ) ;
461+ } ) ;
0 commit comments