2019-11-14 00:13:00 +03:00
import * as core from "@actions/core" ;
2020-03-20 23:02:11 +03:00
import * as io from "@actions/io" ;
import { promises as fs } from "fs" ;
2019-11-14 00:13:00 +03:00
import * as os from "os" ;
import * as path from "path" ;
import { Events , Outputs , State } from "../src/constants" ;
import { ArtifactCacheEntry } from "../src/contracts" ;
import * as actionUtils from "../src/utils/actionUtils" ;
2020-03-20 23:02:11 +03:00
import uuid = require ( "uuid" ) ;
2019-11-14 00:13:00 +03:00
jest . mock ( "@actions/core" ) ;
jest . mock ( "os" ) ;
2020-03-20 23:02:11 +03:00
function getTempDir ( ) : string {
return path . join ( __dirname , "_temp" , "actionUtils" ) ;
}
2019-11-14 00:13:00 +03:00
afterEach ( ( ) = > {
delete process . env [ Events . Key ] ;
} ) ;
2020-03-20 23:02:11 +03:00
afterAll ( async ( ) = > {
delete process . env [ "GITHUB_WORKSPACE" ] ;
await io . rmRF ( getTempDir ( ) ) ;
} ) ;
2019-11-14 00:13:00 +03:00
test ( "getArchiveFileSize returns file size" , ( ) = > {
const filePath = path . join ( __dirname , "__fixtures__" , "helloWorld.txt" ) ;
const size = actionUtils . getArchiveFileSize ( filePath ) ;
expect ( size ) . toBe ( 11 ) ;
} ) ;
test ( "isExactKeyMatch with undefined cache entry returns false" , ( ) = > {
const key = "linux-rust" ;
const cacheEntry = undefined ;
expect ( actionUtils . isExactKeyMatch ( key , cacheEntry ) ) . toBe ( false ) ;
} ) ;
test ( "isExactKeyMatch with empty cache entry returns false" , ( ) = > {
const key = "linux-rust" ;
const cacheEntry : ArtifactCacheEntry = { } ;
expect ( actionUtils . isExactKeyMatch ( key , cacheEntry ) ) . toBe ( false ) ;
} ) ;
test ( "isExactKeyMatch with different keys returns false" , ( ) = > {
const key = "linux-rust" ;
const cacheEntry : ArtifactCacheEntry = {
cacheKey : "linux-"
} ;
expect ( actionUtils . isExactKeyMatch ( key , cacheEntry ) ) . toBe ( false ) ;
} ) ;
test ( "isExactKeyMatch with different key accents returns false" , ( ) = > {
const key = "linux-áccent" ;
const cacheEntry : ArtifactCacheEntry = {
cacheKey : "linux-accent"
} ;
expect ( actionUtils . isExactKeyMatch ( key , cacheEntry ) ) . toBe ( false ) ;
} ) ;
test ( "isExactKeyMatch with same key returns true" , ( ) = > {
const key = "linux-rust" ;
const cacheEntry : ArtifactCacheEntry = {
cacheKey : "linux-rust"
} ;
expect ( actionUtils . isExactKeyMatch ( key , cacheEntry ) ) . toBe ( true ) ;
} ) ;
test ( "isExactKeyMatch with same key and different casing returns true" , ( ) = > {
const key = "linux-rust" ;
const cacheEntry : ArtifactCacheEntry = {
cacheKey : "LINUX-RUST"
} ;
expect ( actionUtils . isExactKeyMatch ( key , cacheEntry ) ) . toBe ( true ) ;
} ) ;
test ( "setOutputAndState with undefined entry to set cache-hit output" , ( ) = > {
const key = "linux-rust" ;
const cacheEntry = undefined ;
const setOutputMock = jest . spyOn ( core , "setOutput" ) ;
const saveStateMock = jest . spyOn ( core , "saveState" ) ;
actionUtils . setOutputAndState ( key , cacheEntry ) ;
expect ( setOutputMock ) . toHaveBeenCalledWith ( Outputs . CacheHit , "false" ) ;
expect ( setOutputMock ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( saveStateMock ) . toHaveBeenCalledTimes ( 0 ) ;
} ) ;
test ( "setOutputAndState with exact match to set cache-hit output and state" , ( ) = > {
const key = "linux-rust" ;
const cacheEntry : ArtifactCacheEntry = {
cacheKey : "linux-rust"
} ;
const setOutputMock = jest . spyOn ( core , "setOutput" ) ;
const saveStateMock = jest . spyOn ( core , "saveState" ) ;
actionUtils . setOutputAndState ( key , cacheEntry ) ;
expect ( setOutputMock ) . toHaveBeenCalledWith ( Outputs . CacheHit , "true" ) ;
expect ( setOutputMock ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( saveStateMock ) . toHaveBeenCalledWith (
State . CacheResult ,
JSON . stringify ( cacheEntry )
) ;
expect ( saveStateMock ) . toHaveBeenCalledTimes ( 1 ) ;
} ) ;
test ( "setOutputAndState with no exact match to set cache-hit output and state" , ( ) = > {
const key = "linux-rust" ;
const cacheEntry : ArtifactCacheEntry = {
cacheKey : "linux-rust-bb828da54c148048dd17899ba9fda624811cfb43"
} ;
const setOutputMock = jest . spyOn ( core , "setOutput" ) ;
const saveStateMock = jest . spyOn ( core , "saveState" ) ;
actionUtils . setOutputAndState ( key , cacheEntry ) ;
expect ( setOutputMock ) . toHaveBeenCalledWith ( Outputs . CacheHit , "false" ) ;
expect ( setOutputMock ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( saveStateMock ) . toHaveBeenCalledWith (
State . CacheResult ,
JSON . stringify ( cacheEntry )
) ;
expect ( saveStateMock ) . toHaveBeenCalledTimes ( 1 ) ;
} ) ;
test ( "getCacheState with no state returns undefined" , ( ) = > {
const getStateMock = jest . spyOn ( core , "getState" ) ;
getStateMock . mockImplementation ( ( ) = > {
return "" ;
} ) ;
const state = actionUtils . getCacheState ( ) ;
expect ( state ) . toBe ( undefined ) ;
expect ( getStateMock ) . toHaveBeenCalledWith ( State . CacheResult ) ;
expect ( getStateMock ) . toHaveBeenCalledTimes ( 1 ) ;
} ) ;
test ( "getCacheState with valid state" , ( ) = > {
const cacheEntry : ArtifactCacheEntry = {
cacheKey : "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43" ,
scope : "refs/heads/master" ,
creationTime : "2019-11-13T19:18:02+00:00" ,
archiveLocation : "www.actionscache.test/download"
} ;
const getStateMock = jest . spyOn ( core , "getState" ) ;
getStateMock . mockImplementation ( ( ) = > {
return JSON . stringify ( cacheEntry ) ;
} ) ;
const state = actionUtils . getCacheState ( ) ;
expect ( state ) . toEqual ( cacheEntry ) ;
expect ( getStateMock ) . toHaveBeenCalledWith ( State . CacheResult ) ;
expect ( getStateMock ) . toHaveBeenCalledTimes ( 1 ) ;
} ) ;
2019-11-21 22:37:54 +03:00
test ( "logWarning logs a message with a warning prefix" , ( ) = > {
const message = "A warning occurred." ;
const infoMock = jest . spyOn ( core , "info" ) ;
actionUtils . logWarning ( message ) ;
expect ( infoMock ) . toHaveBeenCalledWith ( ` [warning] ${ message } ` ) ;
} ) ;
2019-11-14 00:13:00 +03:00
test ( "isValidEvent returns false for unknown event" , ( ) = > {
const event = "foo" ;
process . env [ Events . Key ] = event ;
const isValidEvent = actionUtils . isValidEvent ( ) ;
expect ( isValidEvent ) . toBe ( false ) ;
} ) ;
2020-03-20 23:02:11 +03:00
test ( "resolvePaths with no ~ in path" , async ( ) = > {
const filePath = ".cache" ;
// Create the following layout:
// cwd
// cwd/.cache
// cwd/.cache/file.txt
const root = path . join ( getTempDir ( ) , "no-tilde" ) ;
// tarball entries will be relative to workspace
process . env [ "GITHUB_WORKSPACE" ] = root ;
await fs . mkdir ( root , { recursive : true } ) ;
const cache = path . join ( root , ".cache" ) ;
await fs . mkdir ( cache , { recursive : true } ) ;
await fs . writeFile ( path . join ( cache , "file.txt" ) , "cached" ) ;
2019-11-14 00:13:00 +03:00
2020-03-20 23:02:11 +03:00
const originalCwd = process . cwd ( ) ;
2019-11-14 00:13:00 +03:00
2020-03-20 23:02:11 +03:00
try {
process . chdir ( root ) ;
const resolvedPath = await actionUtils . resolvePaths ( [ filePath ] ) ;
const expectedPath = [ filePath ] ;
expect ( resolvedPath ) . toStrictEqual ( expectedPath ) ;
} finally {
process . chdir ( originalCwd ) ;
}
2019-11-14 00:13:00 +03:00
} ) ;
2020-03-20 23:02:11 +03:00
test ( "resolvePaths with ~ in path" , async ( ) = > {
const cacheDir = uuid ( ) ;
const filePath = ` ~/ ${ cacheDir } ` ;
// Create the following layout:
// ~/uuid
// ~/uuid/file.txt
2019-11-14 00:13:00 +03:00
const homedir = jest . requireActual ( "os" ) . homedir ( ) ;
const homedirMock = jest . spyOn ( os , "homedir" ) ;
homedirMock . mockImplementation ( ( ) = > {
return homedir ;
} ) ;
2020-03-20 23:02:11 +03:00
const target = path . join ( homedir , cacheDir ) ;
await fs . mkdir ( target , { recursive : true } ) ;
await fs . writeFile ( path . join ( target , "file.txt" ) , "cached" ) ;
const root = getTempDir ( ) ;
process . env [ "GITHUB_WORKSPACE" ] = root ;
2019-11-14 00:13:00 +03:00
2020-03-20 23:02:11 +03:00
try {
const resolvedPath = await actionUtils . resolvePaths ( [ filePath ] ) ;
const expectedPath = [ path . relative ( root , target ) ] ;
expect ( resolvedPath ) . toStrictEqual ( expectedPath ) ;
} finally {
await io . rmRF ( target ) ;
}
2019-11-14 00:13:00 +03:00
} ) ;
2020-03-20 23:02:11 +03:00
test ( "resolvePaths with home not found" , async ( ) = > {
2019-11-14 00:13:00 +03:00
const filePath = "~/.cache/yarn" ;
const homedirMock = jest . spyOn ( os , "homedir" ) ;
homedirMock . mockImplementation ( ( ) = > {
return "" ;
} ) ;
2020-03-20 23:02:11 +03:00
await expect ( actionUtils . resolvePaths ( [ filePath ] ) ) . rejects . toThrow (
"Unable to determine HOME directory"
2019-11-14 00:13:00 +03:00
) ;
} ) ;
2020-03-20 23:02:11 +03:00
test ( "resolvePaths inclusion pattern returns found" , async ( ) = > {
const pattern = "*.ts" ;
// Create the following layout:
// inclusion-patterns
// inclusion-patterns/miss.txt
// inclusion-patterns/test.ts
const root = path . join ( getTempDir ( ) , "inclusion-patterns" ) ;
// tarball entries will be relative to workspace
process . env [ "GITHUB_WORKSPACE" ] = root ;
await fs . mkdir ( root , { recursive : true } ) ;
await fs . writeFile ( path . join ( root , "miss.txt" ) , "no match" ) ;
await fs . writeFile ( path . join ( root , "test.ts" ) , "match" ) ;
const originalCwd = process . cwd ( ) ;
try {
process . chdir ( root ) ;
const resolvedPath = await actionUtils . resolvePaths ( [ pattern ] ) ;
const expectedPath = [ "test.ts" ] ;
expect ( resolvedPath ) . toStrictEqual ( expectedPath ) ;
} finally {
process . chdir ( originalCwd ) ;
}
} ) ;
test ( "resolvePaths exclusion pattern returns not found" , async ( ) = > {
const patterns = [ "*.ts" , "!test.ts" ] ;
// Create the following layout:
// exclusion-patterns
// exclusion-patterns/miss.txt
// exclusion-patterns/test.ts
const root = path . join ( getTempDir ( ) , "exclusion-patterns" ) ;
// tarball entries will be relative to workspace
process . env [ "GITHUB_WORKSPACE" ] = root ;
await fs . mkdir ( root , { recursive : true } ) ;
await fs . writeFile ( path . join ( root , "miss.txt" ) , "no match" ) ;
await fs . writeFile ( path . join ( root , "test.ts" ) , "no match" ) ;
const originalCwd = process . cwd ( ) ;
try {
process . chdir ( root ) ;
const resolvedPath = await actionUtils . resolvePaths ( patterns ) ;
const expectedPath = [ ] ;
expect ( resolvedPath ) . toStrictEqual ( expectedPath ) ;
} finally {
process . chdir ( originalCwd ) ;
}
} ) ;
2019-11-14 00:13:00 +03:00
test ( "isValidEvent returns true for push event" , ( ) = > {
const event = Events . Push ;
process . env [ Events . Key ] = event ;
const isValidEvent = actionUtils . isValidEvent ( ) ;
expect ( isValidEvent ) . toBe ( true ) ;
} ) ;
test ( "isValidEvent returns true for pull request event" , ( ) = > {
const event = Events . PullRequest ;
process . env [ Events . Key ] = event ;
const isValidEvent = actionUtils . isValidEvent ( ) ;
expect ( isValidEvent ) . toBe ( true ) ;
} ) ;
2020-03-18 16:43:56 +03:00
test ( "unlinkFile unlinks file" , async ( ) = > {
2020-03-20 23:02:11 +03:00
const testDirectory = await fs . mkdtemp ( "unlinkFileTest" ) ;
2020-03-18 16:43:56 +03:00
const testFile = path . join ( testDirectory , "test.txt" ) ;
2020-03-20 23:02:11 +03:00
await fs . writeFile ( testFile , "hello world" ) ;
2020-03-18 16:43:56 +03:00
await actionUtils . unlinkFile ( testFile ) ;
2020-03-20 23:02:11 +03:00
// This should throw as testFile should not exist
await expect ( fs . stat ( testFile ) ) . rejects . toThrow ( ) ;
2020-03-18 16:43:56 +03:00
2020-03-20 23:02:11 +03:00
await fs . rmdir ( testDirectory ) ;
2020-03-18 16:43:56 +03:00
} ) ;