2019-11-15 01:14:16 +03:00
import * as core from "@actions/core" ;
import * as path from "path" ;
2020-03-18 16:35:13 +03:00
2019-11-15 01:14:16 +03:00
import * as cacheHttpClient from "../src/cacheHttpClient" ;
2020-03-20 23:02:11 +03:00
import { CacheFilename , Events , Inputs } from "../src/constants" ;
2019-11-15 01:14:16 +03:00
import { ArtifactCacheEntry } from "../src/contracts" ;
import run from "../src/save" ;
2019-12-14 01:24:37 +03:00
import * as tar from "../src/tar" ;
2019-11-15 01:14:16 +03:00
import * as actionUtils from "../src/utils/actionUtils" ;
import * as testUtils from "../src/utils/testUtils" ;
jest . mock ( "@actions/core" ) ;
jest . mock ( "../src/cacheHttpClient" ) ;
2019-12-14 01:24:37 +03:00
jest . mock ( "../src/tar" ) ;
jest . mock ( "../src/utils/actionUtils" ) ;
2019-11-15 01:14:16 +03:00
beforeAll ( ( ) = > {
jest . spyOn ( core , "getInput" ) . mockImplementation ( ( name , options ) = > {
return jest . requireActual ( "@actions/core" ) . getInput ( name , options ) ;
} ) ;
jest . spyOn ( actionUtils , "getCacheState" ) . mockImplementation ( ( ) = > {
return jest . requireActual ( "../src/utils/actionUtils" ) . getCacheState ( ) ;
} ) ;
jest . spyOn ( actionUtils , "isExactKeyMatch" ) . mockImplementation (
( key , cacheResult ) = > {
return jest
. requireActual ( "../src/utils/actionUtils" )
. isExactKeyMatch ( key , cacheResult ) ;
}
) ;
2019-11-21 22:37:54 +03:00
jest . spyOn ( actionUtils , "isValidEvent" ) . mockImplementation ( ( ) = > {
const actualUtils = jest . requireActual ( "../src/utils/actionUtils" ) ;
return actualUtils . isValidEvent ( ) ;
} ) ;
jest . spyOn ( actionUtils , "getSupportedEvents" ) . mockImplementation ( ( ) = > {
const actualUtils = jest . requireActual ( "../src/utils/actionUtils" ) ;
return actualUtils . getSupportedEvents ( ) ;
} ) ;
2020-03-20 23:02:11 +03:00
jest . spyOn ( actionUtils , "resolvePaths" ) . mockImplementation (
async filePaths = > {
return filePaths . map ( x = > path . resolve ( x ) ) ;
}
) ;
2019-11-15 01:14:16 +03:00
jest . spyOn ( actionUtils , "createTempDirectory" ) . mockImplementation ( ( ) = > {
return Promise . resolve ( "/foo/bar" ) ;
} ) ;
} ) ;
2019-11-21 22:37:54 +03:00
beforeEach ( ( ) = > {
process . env [ Events . Key ] = Events . Push ;
} ) ;
2019-11-15 01:14:16 +03:00
afterEach ( ( ) = > {
testUtils . clearInputs ( ) ;
2019-11-21 22:37:54 +03:00
delete process . env [ Events . Key ] ;
} ) ;
test ( "save with invalid event outputs warning" , async ( ) = > {
const logWarningMock = jest . spyOn ( actionUtils , "logWarning" ) ;
const failedMock = jest . spyOn ( core , "setFailed" ) ;
const invalidEvent = "commit_comment" ;
process . env [ Events . Key ] = invalidEvent ;
await run ( ) ;
expect ( logWarningMock ) . toHaveBeenCalledWith (
` Event Validation Error: The event type ${ invalidEvent } is not supported. Only push, pull_request events are supported at this time. `
) ;
expect ( failedMock ) . toHaveBeenCalledTimes ( 0 ) ;
2019-11-15 01:14:16 +03:00
} ) ;
test ( "save with no primary key in state outputs warning" , async ( ) = > {
2019-11-21 22:37:54 +03:00
const logWarningMock = jest . spyOn ( actionUtils , "logWarning" ) ;
2019-11-15 01:14:16 +03:00
const failedMock = jest . spyOn ( core , "setFailed" ) ;
const cacheEntry : ArtifactCacheEntry = {
cacheKey : "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43" ,
scope : "refs/heads/master" ,
creationTime : "2019-11-13T19:18:02+00:00" ,
archiveLocation : "www.actionscache.test/download"
} ;
jest . spyOn ( core , "getState" )
// Cache Entry State
. mockImplementationOnce ( ( ) = > {
return JSON . stringify ( cacheEntry ) ;
} )
// Cache Key State
. mockImplementationOnce ( ( ) = > {
return "" ;
} ) ;
await run ( ) ;
2019-11-21 22:37:54 +03:00
expect ( logWarningMock ) . toHaveBeenCalledWith (
2019-11-15 01:14:16 +03:00
` Error retrieving key from state. `
) ;
2019-11-21 22:37:54 +03:00
expect ( logWarningMock ) . toHaveBeenCalledTimes ( 1 ) ;
2019-11-15 01:14:16 +03:00
expect ( failedMock ) . toHaveBeenCalledTimes ( 0 ) ;
} ) ;
test ( "save with exact match returns early" , async ( ) = > {
const infoMock = jest . spyOn ( core , "info" ) ;
const failedMock = jest . spyOn ( core , "setFailed" ) ;
const primaryKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43" ;
const cacheEntry : ArtifactCacheEntry = {
cacheKey : primaryKey ,
scope : "refs/heads/master" ,
creationTime : "2019-11-13T19:18:02+00:00" ,
archiveLocation : "www.actionscache.test/download"
} ;
jest . spyOn ( core , "getState" )
// Cache Entry State
. mockImplementationOnce ( ( ) = > {
return JSON . stringify ( cacheEntry ) ;
} )
// Cache Key State
. mockImplementationOnce ( ( ) = > {
return primaryKey ;
} ) ;
2019-12-14 01:24:37 +03:00
const createTarMock = jest . spyOn ( tar , "createTar" ) ;
2019-11-15 01:14:16 +03:00
await run ( ) ;
expect ( infoMock ) . toHaveBeenCalledWith (
` Cache hit occurred on the primary key ${ primaryKey } , not saving cache. `
) ;
2019-12-14 01:24:37 +03:00
expect ( createTarMock ) . toHaveBeenCalledTimes ( 0 ) ;
2019-11-15 01:14:16 +03:00
expect ( failedMock ) . toHaveBeenCalledTimes ( 0 ) ;
} ) ;
test ( "save with missing input outputs warning" , async ( ) = > {
2019-11-21 22:37:54 +03:00
const logWarningMock = jest . spyOn ( actionUtils , "logWarning" ) ;
2019-11-15 01:14:16 +03:00
const failedMock = jest . spyOn ( core , "setFailed" ) ;
const primaryKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43" ;
const cacheEntry : ArtifactCacheEntry = {
cacheKey : "Linux-node-" ,
scope : "refs/heads/master" ,
creationTime : "2019-11-13T19:18:02+00:00" ,
archiveLocation : "www.actionscache.test/download"
} ;
jest . spyOn ( core , "getState" )
// Cache Entry State
. mockImplementationOnce ( ( ) = > {
return JSON . stringify ( cacheEntry ) ;
} )
// Cache Key State
. mockImplementationOnce ( ( ) = > {
return primaryKey ;
} ) ;
await run ( ) ;
2019-11-21 22:37:54 +03:00
expect ( logWarningMock ) . toHaveBeenCalledWith (
2019-11-15 01:14:16 +03:00
"Input required and not supplied: path"
) ;
2019-11-21 22:37:54 +03:00
expect ( logWarningMock ) . toHaveBeenCalledTimes ( 1 ) ;
2019-11-15 01:14:16 +03:00
expect ( failedMock ) . toHaveBeenCalledTimes ( 0 ) ;
} ) ;
test ( "save with large cache outputs warning" , async ( ) = > {
2019-11-21 22:37:54 +03:00
const logWarningMock = jest . spyOn ( actionUtils , "logWarning" ) ;
2019-11-15 01:14:16 +03:00
const failedMock = jest . spyOn ( core , "setFailed" ) ;
const primaryKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43" ;
const cacheEntry : ArtifactCacheEntry = {
cacheKey : "Linux-node-" ,
scope : "refs/heads/master" ,
creationTime : "2019-11-13T19:18:02+00:00" ,
archiveLocation : "www.actionscache.test/download"
} ;
jest . spyOn ( core , "getState" )
// Cache Entry State
. mockImplementationOnce ( ( ) = > {
return JSON . stringify ( cacheEntry ) ;
} )
// Cache Key State
. mockImplementationOnce ( ( ) = > {
return primaryKey ;
} ) ;
const inputPath = "node_modules" ;
2020-03-20 23:02:11 +03:00
const cachePaths = [ path . resolve ( inputPath ) ] ;
2019-11-15 01:14:16 +03:00
testUtils . setInput ( Inputs . Path , inputPath ) ;
2019-12-14 01:24:37 +03:00
const createTarMock = jest . spyOn ( tar , "createTar" ) ;
2019-11-15 01:14:16 +03:00
2020-02-02 00:11:02 +03:00
const cacheSize = 6 * 1024 * 1024 * 1024 ; //~6GB, over the 5GB limit
2019-11-15 01:14:16 +03:00
jest . spyOn ( actionUtils , "getArchiveFileSize" ) . mockImplementationOnce ( ( ) = > {
return cacheSize ;
} ) ;
await run ( ) ;
2020-03-20 23:02:11 +03:00
const archiveFolder = "/foo/bar" ;
2019-11-15 01:14:16 +03:00
2019-12-14 01:24:37 +03:00
expect ( createTarMock ) . toHaveBeenCalledTimes ( 1 ) ;
2020-03-20 23:02:11 +03:00
expect ( createTarMock ) . toHaveBeenCalledWith ( archiveFolder , cachePaths ) ;
2019-11-15 01:14:16 +03:00
2019-11-21 22:37:54 +03:00
expect ( logWarningMock ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( logWarningMock ) . toHaveBeenCalledWith (
2020-02-02 00:11:02 +03:00
"Cache size of ~6144 MB (6442450944 B) is over the 5GB limit, not saving cache."
2019-11-15 01:14:16 +03:00
) ;
expect ( failedMock ) . toHaveBeenCalledTimes ( 0 ) ;
} ) ;
2020-01-06 21:05:50 +03:00
test ( "save with reserve cache failure outputs warning" , async ( ) = > {
const infoMock = jest . spyOn ( core , "info" ) ;
const logWarningMock = jest . spyOn ( actionUtils , "logWarning" ) ;
const failedMock = jest . spyOn ( core , "setFailed" ) ;
const primaryKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43" ;
const cacheEntry : ArtifactCacheEntry = {
cacheKey : "Linux-node-" ,
scope : "refs/heads/master" ,
creationTime : "2019-11-13T19:18:02+00:00" ,
archiveLocation : "www.actionscache.test/download"
} ;
jest . spyOn ( core , "getState" )
// Cache Entry State
. mockImplementationOnce ( ( ) = > {
return JSON . stringify ( cacheEntry ) ;
} )
// Cache Key State
. mockImplementationOnce ( ( ) = > {
return primaryKey ;
} ) ;
const inputPath = "node_modules" ;
testUtils . setInput ( Inputs . Path , inputPath ) ;
const reserveCacheMock = jest
. spyOn ( cacheHttpClient , "reserveCache" )
. mockImplementationOnce ( ( ) = > {
return Promise . resolve ( - 1 ) ;
} ) ;
const createTarMock = jest . spyOn ( tar , "createTar" ) ;
const saveCacheMock = jest . spyOn ( cacheHttpClient , "saveCache" ) ;
await run ( ) ;
expect ( reserveCacheMock ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( reserveCacheMock ) . toHaveBeenCalledWith ( primaryKey ) ;
expect ( infoMock ) . toHaveBeenCalledWith (
` Unable to reserve cache with key ${ primaryKey } , another job may be creating this cache. `
) ;
expect ( createTarMock ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( saveCacheMock ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( logWarningMock ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( failedMock ) . toHaveBeenCalledTimes ( 0 ) ;
} ) ;
2019-11-15 01:14:16 +03:00
test ( "save with server error outputs warning" , async ( ) = > {
2019-11-21 22:37:54 +03:00
const logWarningMock = jest . spyOn ( actionUtils , "logWarning" ) ;
2019-11-15 01:14:16 +03:00
const failedMock = jest . spyOn ( core , "setFailed" ) ;
const primaryKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43" ;
const cacheEntry : ArtifactCacheEntry = {
cacheKey : "Linux-node-" ,
scope : "refs/heads/master" ,
creationTime : "2019-11-13T19:18:02+00:00" ,
archiveLocation : "www.actionscache.test/download"
} ;
jest . spyOn ( core , "getState" )
// Cache Entry State
. mockImplementationOnce ( ( ) = > {
return JSON . stringify ( cacheEntry ) ;
} )
// Cache Key State
. mockImplementationOnce ( ( ) = > {
return primaryKey ;
} ) ;
const inputPath = "node_modules" ;
2020-03-20 23:02:11 +03:00
const cachePaths = [ path . resolve ( inputPath ) ] ;
2019-11-15 01:14:16 +03:00
testUtils . setInput ( Inputs . Path , inputPath ) ;
2020-01-06 21:05:50 +03:00
const cacheId = 4 ;
const reserveCacheMock = jest
. spyOn ( cacheHttpClient , "reserveCache" )
. mockImplementationOnce ( ( ) = > {
return Promise . resolve ( cacheId ) ;
} ) ;
2019-12-14 01:24:37 +03:00
const createTarMock = jest . spyOn ( tar , "createTar" ) ;
2019-11-15 01:14:16 +03:00
const saveCacheMock = jest
. spyOn ( cacheHttpClient , "saveCache" )
. mockImplementationOnce ( ( ) = > {
throw new Error ( "HTTP Error Occurred" ) ;
} ) ;
await run ( ) ;
2020-01-06 21:05:50 +03:00
expect ( reserveCacheMock ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( reserveCacheMock ) . toHaveBeenCalledWith ( primaryKey ) ;
2020-03-20 23:02:11 +03:00
const archiveFolder = "/foo/bar" ;
const archiveFile = path . join ( archiveFolder , CacheFilename ) ;
2019-11-15 01:14:16 +03:00
2019-12-14 01:24:37 +03:00
expect ( createTarMock ) . toHaveBeenCalledTimes ( 1 ) ;
2020-03-20 23:02:11 +03:00
expect ( createTarMock ) . toHaveBeenCalledWith ( archiveFolder , cachePaths ) ;
2019-11-15 01:14:16 +03:00
expect ( saveCacheMock ) . toHaveBeenCalledTimes ( 1 ) ;
2020-03-20 23:02:11 +03:00
expect ( saveCacheMock ) . toHaveBeenCalledWith ( cacheId , archiveFile ) ;
2019-11-15 01:14:16 +03:00
2019-11-21 22:37:54 +03:00
expect ( logWarningMock ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( logWarningMock ) . toHaveBeenCalledWith ( "HTTP Error Occurred" ) ;
2019-11-15 01:14:16 +03:00
expect ( failedMock ) . toHaveBeenCalledTimes ( 0 ) ;
} ) ;
test ( "save with valid inputs uploads a cache" , async ( ) = > {
const failedMock = jest . spyOn ( core , "setFailed" ) ;
const primaryKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43" ;
const cacheEntry : ArtifactCacheEntry = {
cacheKey : "Linux-node-" ,
scope : "refs/heads/master" ,
creationTime : "2019-11-13T19:18:02+00:00" ,
archiveLocation : "www.actionscache.test/download"
} ;
jest . spyOn ( core , "getState" )
// Cache Entry State
. mockImplementationOnce ( ( ) = > {
return JSON . stringify ( cacheEntry ) ;
} )
// Cache Key State
. mockImplementationOnce ( ( ) = > {
return primaryKey ;
} ) ;
const inputPath = "node_modules" ;
2020-03-20 23:02:11 +03:00
const cachePaths = [ path . resolve ( inputPath ) ] ;
2019-11-15 01:14:16 +03:00
testUtils . setInput ( Inputs . Path , inputPath ) ;
2020-01-06 21:05:50 +03:00
const cacheId = 4 ;
const reserveCacheMock = jest
. spyOn ( cacheHttpClient , "reserveCache" )
. mockImplementationOnce ( ( ) = > {
return Promise . resolve ( cacheId ) ;
} ) ;
2019-12-14 01:24:37 +03:00
const createTarMock = jest . spyOn ( tar , "createTar" ) ;
2020-01-06 21:05:50 +03:00
2019-11-15 01:14:16 +03:00
const saveCacheMock = jest . spyOn ( cacheHttpClient , "saveCache" ) ;
await run ( ) ;
2020-01-06 21:05:50 +03:00
expect ( reserveCacheMock ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( reserveCacheMock ) . toHaveBeenCalledWith ( primaryKey ) ;
2020-03-20 23:02:11 +03:00
const archiveFolder = "/foo/bar" ;
const archiveFile = path . join ( archiveFolder , CacheFilename ) ;
2019-11-15 01:14:16 +03:00
2019-12-14 01:24:37 +03:00
expect ( createTarMock ) . toHaveBeenCalledTimes ( 1 ) ;
2020-03-20 23:02:11 +03:00
expect ( createTarMock ) . toHaveBeenCalledWith ( archiveFolder , cachePaths ) ;
2019-11-15 01:14:16 +03:00
expect ( saveCacheMock ) . toHaveBeenCalledTimes ( 1 ) ;
2020-03-20 23:02:11 +03:00
expect ( saveCacheMock ) . toHaveBeenCalledWith ( cacheId , archiveFile ) ;
2019-11-15 01:14:16 +03:00
expect ( failedMock ) . toHaveBeenCalledTimes ( 0 ) ;
} ) ;