2020-05-15 16:18:50 +00:00
|
|
|
import * as core from '@actions/core'
|
2020-05-06 15:10:18 +00:00
|
|
|
import * as path from 'path'
|
|
|
|
import {saveCache} from '../src/cache'
|
|
|
|
import * as cacheHttpClient from '../src/internal/cacheHttpClient'
|
|
|
|
import * as cacheUtils from '../src/internal/cacheUtils'
|
|
|
|
import {CacheFilename, CompressionMethod} from '../src/internal/constants'
|
|
|
|
import * as tar from '../src/internal/tar'
|
2022-03-30 07:57:36 +00:00
|
|
|
import {ITypedResponse} from '@actions/http-client/interfaces'
|
2022-03-31 09:42:59 +00:00
|
|
|
import {ReserveCacheResponse, ITypedResponseWithErrorMessage} from '../src/internal/contracts'
|
2020-05-06 15:10:18 +00:00
|
|
|
|
|
|
|
jest.mock('../src/internal/cacheHttpClient')
|
|
|
|
jest.mock('../src/internal/cacheUtils')
|
|
|
|
jest.mock('../src/internal/tar')
|
|
|
|
|
|
|
|
beforeAll(() => {
|
2020-05-15 16:18:50 +00:00
|
|
|
jest.spyOn(console, 'log').mockImplementation(() => {})
|
|
|
|
jest.spyOn(core, 'debug').mockImplementation(() => {})
|
|
|
|
jest.spyOn(core, 'info').mockImplementation(() => {})
|
|
|
|
jest.spyOn(core, 'warning').mockImplementation(() => {})
|
|
|
|
jest.spyOn(core, 'error').mockImplementation(() => {})
|
|
|
|
|
2020-05-06 15:10:18 +00:00
|
|
|
jest.spyOn(cacheUtils, 'getCacheFileName').mockImplementation(cm => {
|
|
|
|
const actualUtils = jest.requireActual('../src/internal/cacheUtils')
|
|
|
|
return actualUtils.getCacheFileName(cm)
|
|
|
|
})
|
|
|
|
|
|
|
|
jest.spyOn(cacheUtils, 'resolvePaths').mockImplementation(async filePaths => {
|
|
|
|
return filePaths.map(x => path.resolve(x))
|
|
|
|
})
|
|
|
|
|
|
|
|
jest.spyOn(cacheUtils, 'createTempDirectory').mockImplementation(async () => {
|
|
|
|
return Promise.resolve('/foo/bar')
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2020-05-06 21:53:22 +00:00
|
|
|
test('save with missing input should fail', async () => {
|
|
|
|
const paths: string[] = []
|
2020-05-06 15:10:18 +00:00
|
|
|
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
2020-05-06 21:53:22 +00:00
|
|
|
await expect(saveCache(paths, primaryKey)).rejects.toThrowError(
|
|
|
|
`Path Validation Error: At least one directory or file path is required`
|
2020-05-06 15:10:18 +00:00
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2020-05-06 21:53:22 +00:00
|
|
|
test('save with large cache outputs should fail', async () => {
|
|
|
|
const filePath = 'node_modules'
|
2020-05-06 15:10:18 +00:00
|
|
|
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
2020-05-06 21:53:22 +00:00
|
|
|
const cachePaths = [path.resolve(filePath)]
|
2020-05-06 15:10:18 +00:00
|
|
|
|
|
|
|
const createTarMock = jest.spyOn(tar, 'createTar')
|
|
|
|
|
2021-11-19 11:04:33 +00:00
|
|
|
const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit
|
2020-05-15 16:18:50 +00:00
|
|
|
jest
|
2021-05-03 15:09:44 +00:00
|
|
|
.spyOn(cacheUtils, 'getArchiveFileSizeInBytes')
|
2020-05-15 16:18:50 +00:00
|
|
|
.mockReturnValueOnce(cacheSize)
|
2020-05-06 15:10:18 +00:00
|
|
|
const compression = CompressionMethod.Gzip
|
|
|
|
const getCompressionMock = jest
|
|
|
|
.spyOn(cacheUtils, 'getCompressionMethod')
|
2020-05-06 21:53:22 +00:00
|
|
|
.mockReturnValueOnce(Promise.resolve(compression))
|
2022-03-30 07:57:36 +00:00
|
|
|
|
|
|
|
const reserveCacheMock = jest
|
|
|
|
.spyOn(cacheHttpClient, 'reserveCache')
|
|
|
|
.mockImplementation(async () => {
|
2022-03-31 09:42:59 +00:00
|
|
|
let response: ITypedResponseWithErrorMessage<ReserveCacheResponse> = {statusCode:400, result: null, headers:{}, typeKey:"InvalidReserveCacheRequestException"}
|
2022-03-30 07:57:36 +00:00
|
|
|
return response
|
|
|
|
})
|
2020-05-06 15:10:18 +00:00
|
|
|
|
2020-05-06 21:53:22 +00:00
|
|
|
await expect(saveCache([filePath], primaryKey)).rejects.toThrowError(
|
2022-03-30 07:57:36 +00:00
|
|
|
'Cache size of ~11264 MB (11811160064 B) is over the data cap limit, not saving cache.'
|
2020-05-06 21:53:22 +00:00
|
|
|
)
|
2020-05-06 15:10:18 +00:00
|
|
|
|
|
|
|
const archiveFolder = '/foo/bar'
|
|
|
|
|
|
|
|
expect(createTarMock).toHaveBeenCalledTimes(1)
|
|
|
|
expect(createTarMock).toHaveBeenCalledWith(
|
|
|
|
archiveFolder,
|
|
|
|
cachePaths,
|
|
|
|
compression
|
|
|
|
)
|
|
|
|
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
|
|
|
})
|
|
|
|
|
2020-05-06 21:53:22 +00:00
|
|
|
test('save with reserve cache failure should fail', async () => {
|
|
|
|
const paths = ['node_modules']
|
2020-05-06 15:10:18 +00:00
|
|
|
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
|
|
|
|
|
|
|
const reserveCacheMock = jest
|
|
|
|
.spyOn(cacheHttpClient, 'reserveCache')
|
|
|
|
.mockImplementation(async () => {
|
2022-03-31 09:42:59 +00:00
|
|
|
let response: ITypedResponseWithErrorMessage<ReserveCacheResponse> = {statusCode:500, result: null, headers:{}}
|
2022-03-30 07:57:36 +00:00
|
|
|
return response
|
2020-05-06 15:10:18 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
const createTarMock = jest.spyOn(tar, 'createTar')
|
|
|
|
const saveCacheMock = jest.spyOn(cacheHttpClient, 'saveCache')
|
|
|
|
const compression = CompressionMethod.Zstd
|
|
|
|
const getCompressionMock = jest
|
|
|
|
.spyOn(cacheUtils, 'getCompressionMethod')
|
2020-05-06 21:53:22 +00:00
|
|
|
.mockReturnValueOnce(Promise.resolve(compression))
|
2020-05-06 15:10:18 +00:00
|
|
|
|
2020-05-06 21:53:22 +00:00
|
|
|
await expect(saveCache(paths, primaryKey)).rejects.toThrowError(
|
|
|
|
`Unable to reserve cache with key ${primaryKey}, another job may be creating this cache.`
|
|
|
|
)
|
2020-05-06 15:10:18 +00:00
|
|
|
expect(reserveCacheMock).toHaveBeenCalledTimes(1)
|
2020-05-06 21:53:22 +00:00
|
|
|
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, paths, {
|
2020-05-06 15:10:18 +00:00
|
|
|
compressionMethod: compression
|
|
|
|
})
|
2022-03-30 07:57:36 +00:00
|
|
|
expect(createTarMock).toHaveBeenCalledTimes(1)
|
2020-05-06 15:10:18 +00:00
|
|
|
expect(saveCacheMock).toHaveBeenCalledTimes(0)
|
|
|
|
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
|
|
|
})
|
|
|
|
|
2020-05-06 21:53:22 +00:00
|
|
|
test('save with server error should fail', async () => {
|
|
|
|
const filePath = 'node_modules'
|
2020-05-06 15:10:18 +00:00
|
|
|
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
2020-05-06 21:53:22 +00:00
|
|
|
const cachePaths = [path.resolve(filePath)]
|
2020-05-06 15:10:18 +00:00
|
|
|
|
|
|
|
const cacheId = 4
|
|
|
|
const reserveCacheMock = jest
|
|
|
|
.spyOn(cacheHttpClient, 'reserveCache')
|
|
|
|
.mockImplementation(async () => {
|
2022-03-30 07:57:36 +00:00
|
|
|
let response: ITypedResponse<ReserveCacheResponse> = {statusCode:500, result: {cacheId}, headers:{}}
|
|
|
|
return response
|
2020-05-06 15:10:18 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
const createTarMock = jest.spyOn(tar, 'createTar')
|
|
|
|
|
|
|
|
const saveCacheMock = jest
|
|
|
|
.spyOn(cacheHttpClient, 'saveCache')
|
2020-05-07 00:07:39 +00:00
|
|
|
.mockImplementationOnce(() => {
|
2020-05-06 15:10:18 +00:00
|
|
|
throw new Error('HTTP Error Occurred')
|
|
|
|
})
|
|
|
|
const compression = CompressionMethod.Zstd
|
|
|
|
const getCompressionMock = jest
|
|
|
|
.spyOn(cacheUtils, 'getCompressionMethod')
|
2020-05-06 21:53:22 +00:00
|
|
|
.mockReturnValueOnce(Promise.resolve(compression))
|
2020-05-06 15:10:18 +00:00
|
|
|
|
2020-05-07 00:07:39 +00:00
|
|
|
await expect(saveCache([filePath], primaryKey)).rejects.toThrowError(
|
2020-05-06 21:53:22 +00:00
|
|
|
'HTTP Error Occurred'
|
|
|
|
)
|
2020-05-06 15:10:18 +00:00
|
|
|
expect(reserveCacheMock).toHaveBeenCalledTimes(1)
|
2020-05-06 21:53:22 +00:00
|
|
|
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, [filePath], {
|
2020-05-06 15:10:18 +00:00
|
|
|
compressionMethod: compression
|
|
|
|
})
|
|
|
|
|
|
|
|
const archiveFolder = '/foo/bar'
|
|
|
|
const archiveFile = path.join(archiveFolder, CacheFilename.Zstd)
|
|
|
|
|
|
|
|
expect(createTarMock).toHaveBeenCalledTimes(1)
|
|
|
|
expect(createTarMock).toHaveBeenCalledWith(
|
|
|
|
archiveFolder,
|
|
|
|
cachePaths,
|
|
|
|
compression
|
|
|
|
)
|
|
|
|
|
|
|
|
expect(saveCacheMock).toHaveBeenCalledTimes(1)
|
2020-05-12 16:37:03 +00:00
|
|
|
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archiveFile, undefined)
|
2020-05-06 15:10:18 +00:00
|
|
|
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
|
|
|
})
|
|
|
|
|
|
|
|
test('save with valid inputs uploads a cache', async () => {
|
2020-05-06 21:53:22 +00:00
|
|
|
const filePath = 'node_modules'
|
2020-05-06 15:10:18 +00:00
|
|
|
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
2020-05-06 21:53:22 +00:00
|
|
|
const cachePaths = [path.resolve(filePath)]
|
2020-05-06 15:10:18 +00:00
|
|
|
|
|
|
|
const cacheId = 4
|
|
|
|
const reserveCacheMock = jest
|
|
|
|
.spyOn(cacheHttpClient, 'reserveCache')
|
|
|
|
.mockImplementation(async () => {
|
2022-03-30 07:57:36 +00:00
|
|
|
let response: ITypedResponse<ReserveCacheResponse> = {statusCode:500, result: {cacheId}, headers:{}}
|
|
|
|
return response
|
2020-05-06 15:10:18 +00:00
|
|
|
})
|
|
|
|
const createTarMock = jest.spyOn(tar, 'createTar')
|
|
|
|
|
|
|
|
const saveCacheMock = jest.spyOn(cacheHttpClient, 'saveCache')
|
|
|
|
const compression = CompressionMethod.Zstd
|
|
|
|
const getCompressionMock = jest
|
|
|
|
.spyOn(cacheUtils, 'getCompressionMethod')
|
|
|
|
.mockReturnValue(Promise.resolve(compression))
|
|
|
|
|
2020-05-06 21:53:22 +00:00
|
|
|
await saveCache([filePath], primaryKey)
|
2020-05-06 15:10:18 +00:00
|
|
|
|
|
|
|
expect(reserveCacheMock).toHaveBeenCalledTimes(1)
|
2020-05-06 21:53:22 +00:00
|
|
|
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, [filePath], {
|
2020-05-06 15:10:18 +00:00
|
|
|
compressionMethod: compression
|
|
|
|
})
|
|
|
|
|
|
|
|
const archiveFolder = '/foo/bar'
|
|
|
|
const archiveFile = path.join(archiveFolder, CacheFilename.Zstd)
|
|
|
|
|
|
|
|
expect(createTarMock).toHaveBeenCalledTimes(1)
|
|
|
|
expect(createTarMock).toHaveBeenCalledWith(
|
|
|
|
archiveFolder,
|
|
|
|
cachePaths,
|
|
|
|
compression
|
|
|
|
)
|
|
|
|
|
|
|
|
expect(saveCacheMock).toHaveBeenCalledTimes(1)
|
2020-05-12 16:37:03 +00:00
|
|
|
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archiveFile, undefined)
|
2020-05-06 15:10:18 +00:00
|
|
|
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
|
|
|
})
|