1
0
Fork 0
mirror of https://github.com/actions/toolkit synced 2025-05-08 16:17:40 +00:00

Use Azure storage SDK to download cache (#497)

* Adds option to download using AzCopy

* Bump version number and add release notes

* Ensure we use at least v10

* Negate env var so it disables AzCopy

* Use Azure storage SDK to download cache

* Use same level of parallelism as AzCopy

* Fix naming of variable

* React to feedback

* Bump Node types to Node 12

* Make linter happy

* Pass options into restoreCache method

* Fix tests

* Restructure files and add tests

* Add method to get the default download and upload options

* Include breaking changes in RELEASES.md

Co-authored-by: Josh Gross <joshmgross@github.com>
This commit is contained in:
David Hadka 2020-07-10 10:09:32 -05:00 committed by GitHub
parent cee7d92d1d
commit 4964b0cc7c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 968 additions and 290 deletions

View file

@ -1,5 +1,9 @@
import {getCacheVersion, retry} from '../src/internal/cacheHttpClient'
import {downloadCache, getCacheVersion} from '../src/internal/cacheHttpClient'
import {CompressionMethod} from '../src/internal/constants'
import * as downloadUtils from '../src/internal/downloadUtils'
import {DownloadOptions, getDownloadOptions} from '../src/options'
jest.mock('../src/internal/downloadUtils')
test('getCacheVersion with one path returns version', async () => {
const paths = ['node_modules']
@ -35,141 +39,103 @@ test('getCacheVersion with gzip compression does not change vesion', async () =>
)
})
interface TestResponse {
statusCode: number
result: string | null
}
async function handleResponse(
response: TestResponse | undefined
): Promise<TestResponse> {
if (!response) {
// eslint-disable-next-line no-undef
fail('Retry method called too many times')
}
if (response.statusCode === 999) {
throw Error('Test Error')
} else {
return Promise.resolve(response)
}
}
async function testRetryExpectingResult(
responses: TestResponse[],
expectedResult: string | null
): Promise<void> {
responses = responses.reverse() // Reverse responses since we pop from end
const actualResult = await retry(
'test',
async () => handleResponse(responses.pop()),
(response: TestResponse) => response.statusCode
test('downloadCache uses http-client for non-Azure URLs', async () => {
const downloadCacheHttpClientMock = jest.spyOn(
downloadUtils,
'downloadCacheHttpClient'
)
const downloadCacheStorageSDKMock = jest.spyOn(
downloadUtils,
'downloadCacheStorageSDK'
)
expect(actualResult.result).toEqual(expectedResult)
}
const archiveLocation = 'http://www.actionscache.test/download'
const archivePath = '/foo/bar'
async function testRetryExpectingError(
responses: TestResponse[]
): Promise<void> {
responses = responses.reverse() // Reverse responses since we pop from end
await downloadCache(archiveLocation, archivePath)
expect(
retry(
'test',
async () => handleResponse(responses.pop()),
(response: TestResponse) => response.statusCode
)
).rejects.toBeInstanceOf(Error)
}
test('retry works on successful response', async () => {
await testRetryExpectingResult(
[
{
statusCode: 200,
result: 'Ok'
}
],
'Ok'
expect(downloadCacheHttpClientMock).toHaveBeenCalledTimes(1)
expect(downloadCacheHttpClientMock).toHaveBeenCalledWith(
archiveLocation,
archivePath
)
expect(downloadCacheStorageSDKMock).toHaveBeenCalledTimes(0)
})
test('retry works after retryable status code', async () => {
await testRetryExpectingResult(
[
{
statusCode: 503,
result: null
},
{
statusCode: 200,
result: 'Ok'
}
],
'Ok'
test('downloadCache uses storage SDK for Azure storage URLs', async () => {
const downloadCacheHttpClientMock = jest.spyOn(
downloadUtils,
'downloadCacheHttpClient'
)
})
test('retry fails after exhausting retries', async () => {
await testRetryExpectingError([
{
statusCode: 503,
result: null
},
{
statusCode: 503,
result: null
},
{
statusCode: 200,
result: 'Ok'
}
])
})
test('retry fails after non-retryable status code', async () => {
await testRetryExpectingError([
{
statusCode: 500,
result: null
},
{
statusCode: 200,
result: 'Ok'
}
])
})
test('retry works after error', async () => {
await testRetryExpectingResult(
[
{
statusCode: 999,
result: null
},
{
statusCode: 200,
result: 'Ok'
}
],
'Ok'
const downloadCacheStorageSDKMock = jest.spyOn(
downloadUtils,
'downloadCacheStorageSDK'
)
const archiveLocation = 'http://foo.blob.core.windows.net/bar/baz'
const archivePath = '/foo/bar'
await downloadCache(archiveLocation, archivePath)
expect(downloadCacheStorageSDKMock).toHaveBeenCalledTimes(1)
expect(downloadCacheStorageSDKMock).toHaveBeenCalledWith(
archiveLocation,
archivePath,
getDownloadOptions()
)
expect(downloadCacheHttpClientMock).toHaveBeenCalledTimes(0)
})
test('retry returns after client error', async () => {
await testRetryExpectingResult(
[
{
statusCode: 400,
result: null
},
{
statusCode: 200,
result: 'Ok'
}
],
null
test('downloadCache passes options to download methods', async () => {
const downloadCacheHttpClientMock = jest.spyOn(
downloadUtils,
'downloadCacheHttpClient'
)
const downloadCacheStorageSDKMock = jest.spyOn(
downloadUtils,
'downloadCacheStorageSDK'
)
const archiveLocation = 'http://foo.blob.core.windows.net/bar/baz'
const archivePath = '/foo/bar'
const options: DownloadOptions = {downloadConcurrency: 4}
await downloadCache(archiveLocation, archivePath, options)
expect(downloadCacheStorageSDKMock).toHaveBeenCalledTimes(1)
expect(downloadCacheStorageSDKMock).toHaveBeenCalled()
expect(downloadCacheStorageSDKMock).toHaveBeenCalledWith(
archiveLocation,
archivePath,
getDownloadOptions(options)
)
expect(downloadCacheHttpClientMock).toHaveBeenCalledTimes(0)
})
test('downloadCache uses http-client when overridden', async () => {
const downloadCacheHttpClientMock = jest.spyOn(
downloadUtils,
'downloadCacheHttpClient'
)
const downloadCacheStorageSDKMock = jest.spyOn(
downloadUtils,
'downloadCacheStorageSDK'
)
const archiveLocation = 'http://foo.blob.core.windows.net/bar/baz'
const archivePath = '/foo/bar'
const options: DownloadOptions = {useAzureSdk: false}
await downloadCache(archiveLocation, archivePath, options)
expect(downloadCacheHttpClientMock).toHaveBeenCalledTimes(1)
expect(downloadCacheHttpClientMock).toHaveBeenCalledWith(
archiveLocation,
archivePath
)
expect(downloadCacheStorageSDKMock).toHaveBeenCalledTimes(0)
})