2020-05-14 17:27:38 -04:00
import * as cache from "@actions/cache" ;
2019-11-06 13:41:45 -05:00
import * as core from "@actions/core" ;
2020-05-14 17:27:38 -04:00
import { Events , Inputs , RefKey } from "../src/constants" ;
2019-11-06 13:41:45 -05:00
import run from "../src/restore" ;
import * as actionUtils from "../src/utils/actionUtils" ;
import * as testUtils from "../src/utils/testUtils" ;
2019-12-13 17:24:37 -05:00
jest . mock ( "../src/utils/actionUtils" );
2019-11-06 13:41:45 -05:00
beforeAll (() => {
jest . spyOn ( actionUtils , "isExactKeyMatch" ). mockImplementation (
( key , cacheResult ) => {
const actualUtils = jest . requireActual ( "../src/utils/actionUtils" );
return actualUtils . isExactKeyMatch ( key , cacheResult );
}
);
2019-11-13 10:54:39 -05:00
jest . spyOn ( actionUtils , "isValidEvent" ). mockImplementation (() => {
const actualUtils = jest . requireActual ( "../src/utils/actionUtils" );
return actualUtils . isValidEvent ();
});
2020-06-02 10:21:03 -05:00
jest . spyOn ( actionUtils , "getInputAsArray" ). mockImplementation (
( name , options ) => {
const actualUtils = jest . requireActual ( "../src/utils/actionUtils" );
return actualUtils . getInputAsArray ( name , options );
}
);
2019-11-06 13:41:45 -05:00
});
2019-11-13 10:54:39 -05:00
beforeEach (() => {
process . env [ Events . Key ] = Events . Push ;
2020-04-17 15:46:46 -04:00
process . env [ RefKey ] = "refs/heads/feature-branch" ;
2020-09-29 10:23:21 -05:00
jest . spyOn ( actionUtils , "isGhes" ). mockImplementation (() => false );
2022-03-23 18:39:24 +05:30
jest . spyOn ( cache , "isAvailable" ). mockImplementation (() => true );
2019-11-13 10:54:39 -05:00
});
2019-11-06 13:41:45 -05:00
afterEach (() => {
testUtils . clearInputs ();
2019-11-13 10:54:39 -05:00
delete process . env [ Events . Key ];
2020-04-17 15:46:46 -04:00
delete process . env [ RefKey ];
2019-11-13 10:54:39 -05:00
});
2019-11-21 14:37:54 -05:00
test ( "restore with invalid event outputs warning" , async () => {
const logWarningMock = jest . spyOn ( actionUtils , "logWarning" );
2019-11-13 10:54:39 -05:00
const failedMock = jest . spyOn ( core , "setFailed" );
const invalidEvent = "commit_comment" ;
process . env [ Events . Key ] = invalidEvent ;
2020-04-17 15:46:46 -04:00
delete process . env [ RefKey ];
2019-11-13 10:54:39 -05:00
await run ();
2019-11-21 14:37:54 -05:00
expect ( logWarningMock ). toHaveBeenCalledWith (
2020-04-17 15:46:46 -04:00
`Event Validation Error: The event type ${ invalidEvent } is not supported because it's not tied to a branch or tag ref.`
2019-11-13 10:54:39 -05:00
);
2019-11-21 14:37:54 -05:00
expect ( failedMock ). toHaveBeenCalledTimes ( 0 );
2019-11-06 13:41:45 -05:00
});
2022-03-23 18:39:24 +05:30
test ( "restore without AC available should no-op" , async () => {
jest . spyOn ( actionUtils , "isGhes" ). mockImplementation (() => false );
jest . spyOn ( cache , "isAvailable" ). mockImplementation (() => false );
const logWarningMock = jest . spyOn ( actionUtils , "logWarning" );
const restoreCacheMock = jest . spyOn ( cache , "restoreCache" );
const setCacheHitOutputMock = jest . spyOn ( actionUtils , "setCacheHitOutput" );
await run ();
expect ( restoreCacheMock ). toHaveBeenCalledTimes ( 0 );
expect ( setCacheHitOutputMock ). toHaveBeenCalledTimes ( 1 );
expect ( setCacheHitOutputMock ). toHaveBeenCalledWith ( false );
expect ( logWarningMock ). toHaveBeenCalledWith (
"Something is going wrong with ArtifactCache service which supports cache actions. Please check https://www.githubstatus.com/ for any ongoing issue in actions."
);
});
test ( "restore on GHES without AC available should no-op" , async () => {
2020-09-29 10:23:21 -05:00
jest . spyOn ( actionUtils , "isGhes" ). mockImplementation (() => true );
2022-03-23 18:39:24 +05:30
jest . spyOn ( cache , "isAvailable" ). mockImplementation (() => false );
2020-09-29 09:58:32 -05:00
2020-09-30 08:47:16 -05:00
const logWarningMock = jest . spyOn ( actionUtils , "logWarning" );
2020-09-29 10:23:21 -05:00
const restoreCacheMock = jest . spyOn ( cache , "restoreCache" );
const setCacheHitOutputMock = jest . spyOn ( actionUtils , "setCacheHitOutput" );
2020-09-29 09:58:32 -05:00
2020-09-29 10:23:21 -05:00
await run ();
2020-09-29 09:58:32 -05:00
2020-09-29 10:23:21 -05:00
expect ( restoreCacheMock ). toHaveBeenCalledTimes ( 0 );
expect ( setCacheHitOutputMock ). toHaveBeenCalledTimes ( 1 );
expect ( setCacheHitOutputMock ). toHaveBeenCalledWith ( false );
2020-09-30 08:47:16 -05:00
expect ( logWarningMock ). toHaveBeenCalledWith (
2022-03-23 18:39:24 +05:30
"Cache action is only supported on GHES version >= 3.5. If you are on version >=3.5 Please check with GHES admin if ArtifactCache service is enabled or not."
2020-09-29 10:23:21 -05:00
);
2020-09-29 09:58:32 -05:00
});
2022-03-23 18:39:24 +05:30
test ( "restore on GHES with AC available " , async () => {
jest . spyOn ( actionUtils , "isGhes" ). mockImplementation (() => true );
const path = "node_modules" ;
const key = "node-test" ;
testUtils . setInputs ({
path : path ,
key
});
const infoMock = jest . spyOn ( core , "info" );
const failedMock = jest . spyOn ( core , "setFailed" );
const stateMock = jest . spyOn ( core , "saveState" );
const setCacheHitOutputMock = jest . spyOn ( actionUtils , "setCacheHitOutput" );
const restoreCacheMock = jest
. spyOn ( cache , "restoreCache" )
. mockImplementationOnce (() => {
return Promise . resolve ( key );
});
await run ();
expect ( restoreCacheMock ). toHaveBeenCalledTimes ( 1 );
expect ( restoreCacheMock ). toHaveBeenCalledWith ([ path ], key , []);
expect ( stateMock ). toHaveBeenCalledWith ( "CACHE_KEY" , key );
expect ( setCacheHitOutputMock ). toHaveBeenCalledTimes ( 1 );
expect ( setCacheHitOutputMock ). toHaveBeenCalledWith ( true );
expect ( infoMock ). toHaveBeenCalledWith ( `Cache restored from key: ${ key } ` );
expect ( failedMock ). toHaveBeenCalledTimes ( 0 );
});
2019-11-06 13:41:45 -05:00
test ( "restore with no path should fail" , async () => {
const failedMock = jest . spyOn ( core , "setFailed" );
2020-05-14 17:27:38 -04:00
const restoreCacheMock = jest . spyOn ( cache , "restoreCache" );
2019-11-06 13:41:45 -05:00
await run ();
2020-05-14 17:27:38 -04:00
expect ( restoreCacheMock ). toHaveBeenCalledTimes ( 0 );
2020-03-20 13:02:11 -07:00
// this input isn't necessary for restore b/c tarball contains entries relative to workspace
expect ( failedMock ). not . toHaveBeenCalledWith (
2019-11-06 13:41:45 -05:00
"Input required and not supplied: path"
);
});
test ( "restore with no key" , async () => {
testUtils . setInput ( Inputs . Path , "node_modules" );
const failedMock = jest . spyOn ( core , "setFailed" );
2020-05-14 17:27:38 -04:00
const restoreCacheMock = jest . spyOn ( cache , "restoreCache" );
2019-11-06 13:41:45 -05:00
await run ();
2020-05-14 17:27:38 -04:00
expect ( restoreCacheMock ). toHaveBeenCalledTimes ( 0 );
2019-11-06 13:41:45 -05:00
expect ( failedMock ). toHaveBeenCalledWith (
"Input required and not supplied: key"
);
});
test ( "restore with too many keys should fail" , async () => {
2020-05-14 17:27:38 -04:00
const path = "node_modules" ;
2019-11-06 13:41:45 -05:00
const key = "node-test" ;
const restoreKeys = [... Array ( 20 ). keys ()]. map ( x => x . toString ());
testUtils . setInputs ({
2020-05-14 17:27:38 -04:00
path : path ,
2019-11-06 13:41:45 -05:00
key ,
restoreKeys
});
const failedMock = jest . spyOn ( core , "setFailed" );
2020-05-14 17:27:38 -04:00
const restoreCacheMock = jest . spyOn ( cache , "restoreCache" );
2019-11-06 13:41:45 -05:00
await run ();
2020-05-14 17:27:38 -04:00
expect ( restoreCacheMock ). toHaveBeenCalledTimes ( 1 );
expect ( restoreCacheMock ). toHaveBeenCalledWith ([ path ], key , restoreKeys );
2019-11-06 13:41:45 -05:00
expect ( failedMock ). toHaveBeenCalledWith (
`Key Validation Error: Keys are limited to a maximum of 10.`
);
});
test ( "restore with large key should fail" , async () => {
2020-05-14 17:27:38 -04:00
const path = "node_modules" ;
2019-11-06 13:41:45 -05:00
const key = "foo" . repeat ( 512 ); // Over the 512 character limit
testUtils . setInputs ({
2020-05-14 17:27:38 -04:00
path : path ,
2019-11-06 13:41:45 -05:00
key
});
const failedMock = jest . spyOn ( core , "setFailed" );
2020-05-14 17:27:38 -04:00
const restoreCacheMock = jest . spyOn ( cache , "restoreCache" );
2019-11-06 13:41:45 -05:00
await run ();
2020-05-14 17:27:38 -04:00
expect ( restoreCacheMock ). toHaveBeenCalledTimes ( 1 );
expect ( restoreCacheMock ). toHaveBeenCalledWith ([ path ], key , []);
2019-11-06 13:41:45 -05:00
expect ( failedMock ). toHaveBeenCalledWith (
`Key Validation Error: ${ key } cannot be larger than 512 characters.`
);
});
test ( "restore with invalid key should fail" , async () => {
2020-05-14 17:27:38 -04:00
const path = "node_modules" ;
2019-11-06 13:41:45 -05:00
const key = "comma,comma" ;
testUtils . setInputs ({
2020-05-14 17:27:38 -04:00
path : path ,
2019-11-06 13:41:45 -05:00
key
});
const failedMock = jest . spyOn ( core , "setFailed" );
2020-05-14 17:27:38 -04:00
const restoreCacheMock = jest . spyOn ( cache , "restoreCache" );
2019-11-06 13:41:45 -05:00
await run ();
2020-05-14 17:27:38 -04:00
expect ( restoreCacheMock ). toHaveBeenCalledTimes ( 1 );
expect ( restoreCacheMock ). toHaveBeenCalledWith ([ path ], key , []);
2019-11-06 13:41:45 -05:00
expect ( failedMock ). toHaveBeenCalledWith (
`Key Validation Error: ${ key } cannot contain commas.`
);
});
test ( "restore with no cache found" , async () => {
2020-05-14 17:27:38 -04:00
const path = "node_modules" ;
2019-11-06 13:41:45 -05:00
const key = "node-test" ;
testUtils . setInputs ({
2020-05-14 17:27:38 -04:00
path : path ,
2019-11-06 13:41:45 -05:00
key
});
const infoMock = jest . spyOn ( core , "info" );
const failedMock = jest . spyOn ( core , "setFailed" );
const stateMock = jest . spyOn ( core , "saveState" );
2020-05-14 17:27:38 -04:00
const restoreCacheMock = jest
. spyOn ( cache , "restoreCache" )
. mockImplementationOnce (() => {
return Promise . resolve ( undefined );
});
2019-11-06 13:41:45 -05:00
await run ();
2020-05-14 17:27:38 -04:00
expect ( restoreCacheMock ). toHaveBeenCalledTimes ( 1 );
expect ( restoreCacheMock ). toHaveBeenCalledWith ([ path ], key , []);
2019-11-06 13:41:45 -05:00
expect ( stateMock ). toHaveBeenCalledWith ( "CACHE_KEY" , key );
expect ( failedMock ). toHaveBeenCalledTimes ( 0 );
expect ( infoMock ). toHaveBeenCalledWith (
2020-02-25 19:16:36 +00:00
`Cache not found for input keys: ${ key } `
2019-11-06 13:41:45 -05:00
);
});
test ( "restore with server error should fail" , async () => {
2020-05-14 17:27:38 -04:00
const path = "node_modules" ;
2019-11-06 13:41:45 -05:00
const key = "node-test" ;
testUtils . setInputs ({
2020-05-14 17:27:38 -04:00
path : path ,
2019-11-06 13:41:45 -05:00
key
});
2019-11-21 14:37:54 -05:00
const logWarningMock = jest . spyOn ( actionUtils , "logWarning" );
2019-11-06 13:41:45 -05:00
const failedMock = jest . spyOn ( core , "setFailed" );
const stateMock = jest . spyOn ( core , "saveState" );
2020-05-14 17:27:38 -04:00
const restoreCacheMock = jest
. spyOn ( cache , "restoreCache" )
. mockImplementationOnce (() => {
throw new Error ( "HTTP Error Occurred" );
});
2019-11-06 13:41:45 -05:00
const setCacheHitOutputMock = jest . spyOn ( actionUtils , "setCacheHitOutput" );
await run ();
2020-05-14 17:27:38 -04:00
expect ( restoreCacheMock ). toHaveBeenCalledTimes ( 1 );
expect ( restoreCacheMock ). toHaveBeenCalledWith ([ path ], key , []);
2019-11-06 13:41:45 -05:00
expect ( stateMock ). toHaveBeenCalledWith ( "CACHE_KEY" , key );
2019-11-21 14:37:54 -05:00
expect ( logWarningMock ). toHaveBeenCalledTimes ( 1 );
expect ( logWarningMock ). toHaveBeenCalledWith ( "HTTP Error Occurred" );
2019-11-06 13:41:45 -05:00
expect ( setCacheHitOutputMock ). toHaveBeenCalledTimes ( 1 );
expect ( setCacheHitOutputMock ). toHaveBeenCalledWith ( false );
expect ( failedMock ). toHaveBeenCalledTimes ( 0 );
});
test ( "restore with restore keys and no cache found" , async () => {
2020-05-14 17:27:38 -04:00
const path = "node_modules" ;
2019-11-06 13:41:45 -05:00
const key = "node-test" ;
const restoreKey = "node-" ;
testUtils . setInputs ({
2020-05-14 17:27:38 -04:00
path : path ,
2019-11-06 13:41:45 -05:00
key ,
restoreKeys : [ restoreKey ]
});
const infoMock = jest . spyOn ( core , "info" );
const failedMock = jest . spyOn ( core , "setFailed" );
const stateMock = jest . spyOn ( core , "saveState" );
2020-05-14 17:27:38 -04:00
const restoreCacheMock = jest
. spyOn ( cache , "restoreCache" )
. mockImplementationOnce (() => {
return Promise . resolve ( undefined );
});
2019-11-06 13:41:45 -05:00
await run ();
2020-05-14 17:27:38 -04:00
expect ( restoreCacheMock ). toHaveBeenCalledTimes ( 1 );
expect ( restoreCacheMock ). toHaveBeenCalledWith ([ path ], key , [ restoreKey ]);
2019-11-06 13:41:45 -05:00
expect ( stateMock ). toHaveBeenCalledWith ( "CACHE_KEY" , key );
expect ( failedMock ). toHaveBeenCalledTimes ( 0 );
expect ( infoMock ). toHaveBeenCalledWith (
2020-02-25 19:16:36 +00:00
`Cache not found for input keys: ${ key } , ${ restoreKey } `
2019-11-06 13:41:45 -05:00
);
});
2020-05-14 17:27:38 -04:00
test ( "restore with cache found for key" , async () => {
const path = "node_modules" ;
2019-11-06 13:41:45 -05:00
const key = "node-test" ;
testUtils . setInputs ({
2020-05-14 17:27:38 -04:00
path : path ,
2019-11-06 13:41:45 -05:00
key
});
const infoMock = jest . spyOn ( core , "info" );
const failedMock = jest . spyOn ( core , "setFailed" );
const stateMock = jest . spyOn ( core , "saveState" );
const setCacheHitOutputMock = jest . spyOn ( actionUtils , "setCacheHitOutput" );
2020-05-14 17:27:38 -04:00
const restoreCacheMock = jest
. spyOn ( cache , "restoreCache" )
. mockImplementationOnce (() => {
return Promise . resolve ( key );
});
2020-04-22 16:36:34 -04:00
2019-11-06 13:41:45 -05:00
await run ();
2020-05-14 17:27:38 -04:00
expect ( restoreCacheMock ). toHaveBeenCalledTimes ( 1 );
expect ( restoreCacheMock ). toHaveBeenCalledWith ([ path ], key , []);
2019-11-13 10:54:39 -05:00
expect ( stateMock ). toHaveBeenCalledWith ( "CACHE_KEY" , key );
2019-11-06 13:41:45 -05:00
expect ( setCacheHitOutputMock ). toHaveBeenCalledTimes ( 1 );
expect ( setCacheHitOutputMock ). toHaveBeenCalledWith ( true );
expect ( infoMock ). toHaveBeenCalledWith ( `Cache restored from key: ${ key } ` );
expect ( failedMock ). toHaveBeenCalledTimes ( 0 );
});
test ( "restore with cache found for restore key" , async () => {
2020-05-14 17:27:38 -04:00
const path = "node_modules" ;
2019-11-06 13:41:45 -05:00
const key = "node-test" ;
const restoreKey = "node-" ;
testUtils . setInputs ({
2020-05-14 17:27:38 -04:00
path : path ,
2019-11-06 13:41:45 -05:00
key ,
restoreKeys : [ restoreKey ]
});
const infoMock = jest . spyOn ( core , "info" );
const failedMock = jest . spyOn ( core , "setFailed" );
const stateMock = jest . spyOn ( core , "saveState" );
const setCacheHitOutputMock = jest . spyOn ( actionUtils , "setCacheHitOutput" );
2020-05-14 17:27:38 -04:00
const restoreCacheMock = jest
. spyOn ( cache , "restoreCache" )
. mockImplementationOnce (() => {
return Promise . resolve ( restoreKey );
});
2019-11-06 13:41:45 -05:00
await run ();
2020-05-14 17:27:38 -04:00
expect ( restoreCacheMock ). toHaveBeenCalledTimes ( 1 );
expect ( restoreCacheMock ). toHaveBeenCalledWith ([ path ], key , [ restoreKey ]);
2019-11-06 13:41:45 -05:00
2020-05-14 17:27:38 -04:00
expect ( stateMock ). toHaveBeenCalledWith ( "CACHE_KEY" , key );
2019-11-06 13:41:45 -05:00
expect ( setCacheHitOutputMock ). toHaveBeenCalledTimes ( 1 );
expect ( setCacheHitOutputMock ). toHaveBeenCalledWith ( false );
expect ( infoMock ). toHaveBeenCalledWith (
`Cache restored from key: ${ restoreKey } `
);
expect ( failedMock ). toHaveBeenCalledTimes ( 0 );
});