mirror of https://github.com/actions/toolkit
update download-artifact tests for public and internal impl
parent
22b7aeb707
commit
32549e8197
|
@ -3,7 +3,7 @@ import * as net from 'net'
|
||||||
import {HttpClient} from '@actions/http-client'
|
import {HttpClient} from '@actions/http-client'
|
||||||
import * as config from '../src/internal/shared/config'
|
import * as config from '../src/internal/shared/config'
|
||||||
import {internalArtifactTwirpClient} from '../src/internal/shared/artifact-twirp-client'
|
import {internalArtifactTwirpClient} from '../src/internal/shared/artifact-twirp-client'
|
||||||
import {noopLogs} from './common.test'
|
import {noopLogs} from './common'
|
||||||
|
|
||||||
jest.mock('@actions/http-client')
|
jest.mock('@actions/http-client')
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import * as core from '@actions/core'
|
||||||
|
|
||||||
// noopLogs mocks the console.log and core.* functions to prevent output in the console while testing
|
// noopLogs mocks the console.log and core.* functions to prevent output in the console while testing
|
||||||
export const noopLogs = (): void => {
|
export const noopLogs = (): void => {
|
||||||
// jest.spyOn(console, 'log').mockImplementation(() => {})
|
jest.spyOn(console, 'log').mockImplementation(() => {})
|
||||||
jest.spyOn(core, 'debug').mockImplementation(() => {})
|
jest.spyOn(core, 'debug').mockImplementation(() => {})
|
||||||
jest.spyOn(core, 'info').mockImplementation(() => {})
|
jest.spyOn(core, 'info').mockImplementation(() => {})
|
||||||
jest.spyOn(core, 'warning').mockImplementation(() => {})
|
jest.spyOn(core, 'warning').mockImplementation(() => {})
|
|
@ -7,9 +7,15 @@ import {HttpClient} from '@actions/http-client'
|
||||||
import type {RestEndpointMethods} from '@octokit/plugin-rest-endpoint-methods/dist-types/generated/method-types'
|
import type {RestEndpointMethods} from '@octokit/plugin-rest-endpoint-methods/dist-types/generated/method-types'
|
||||||
import archiver from 'archiver'
|
import archiver from 'archiver'
|
||||||
|
|
||||||
import {downloadArtifactPublic} from '../src/internal/download/download-artifact'
|
import {
|
||||||
|
downloadArtifactInternal,
|
||||||
|
downloadArtifactPublic
|
||||||
|
} from '../src/internal/download/download-artifact'
|
||||||
import {getUserAgentString} from '../src/internal/shared/user-agent'
|
import {getUserAgentString} from '../src/internal/shared/user-agent'
|
||||||
import {noopLogs} from './common.test'
|
import {noopLogs} from './common'
|
||||||
|
import * as config from '../src/internal/shared/config'
|
||||||
|
import {ArtifactServiceClientJSON} from '../src/generated'
|
||||||
|
import * as util from '../src/internal/shared/util'
|
||||||
|
|
||||||
type MockedDownloadArtifact = jest.MockedFunction<
|
type MockedDownloadArtifact = jest.MockedFunction<
|
||||||
RestEndpointMethods['actions']['downloadArtifact']
|
RestEndpointMethods['actions']['downloadArtifact']
|
||||||
|
@ -32,10 +38,16 @@ const fixtures = {
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
artifactID: 1234,
|
artifactID: 1234,
|
||||||
|
artifactName: 'my-artifact',
|
||||||
|
artifactSize: 123456,
|
||||||
repositoryOwner: 'actions',
|
repositoryOwner: 'actions',
|
||||||
repositoryName: 'toolkit',
|
repositoryName: 'toolkit',
|
||||||
token: 'ghp_1234567890',
|
token: 'ghp_1234567890',
|
||||||
blobStorageUrl: 'https://blob-storage.local?signed=true'
|
blobStorageUrl: 'https://blob-storage.local?signed=true',
|
||||||
|
backendIds: {
|
||||||
|
workflowRunBackendId: 'c4d7c21f-ba3f-4ddc-a8c8-6f2f626f8422',
|
||||||
|
workflowJobRunBackendId: '760803a1-f890-4d25-9a6e-a3fc01a0c7cf'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jest.mock('@actions/github', () => ({
|
jest.mock('@actions/github', () => ({
|
||||||
|
@ -88,6 +100,24 @@ const cleanup = async (): Promise<void> => {
|
||||||
delete process.env['GITHUB_WORKSPACE']
|
delete process.env['GITHUB_WORKSPACE']
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const mockGetArtifactSuccess = jest.fn(() => {
|
||||||
|
const message = new http.IncomingMessage(new net.Socket())
|
||||||
|
message.statusCode = 200
|
||||||
|
message.push(fs.readFileSync(fixtures.exampleArtifact.path))
|
||||||
|
return {
|
||||||
|
message
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const mockGetArtifactFailure = jest.fn(() => {
|
||||||
|
const message = new http.IncomingMessage(new net.Socket())
|
||||||
|
message.statusCode = 500
|
||||||
|
message.push('Internal Server Error')
|
||||||
|
return {
|
||||||
|
message
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
describe('download-artifact', () => {
|
describe('download-artifact', () => {
|
||||||
describe('public', () => {
|
describe('public', () => {
|
||||||
beforeEach(setup)
|
beforeEach(setup)
|
||||||
|
@ -105,18 +135,10 @@ describe('download-artifact', () => {
|
||||||
data: Buffer.from('')
|
data: Buffer.from('')
|
||||||
})
|
})
|
||||||
|
|
||||||
const getMock = jest.fn(() => {
|
const mockHttpClient = (HttpClient as jest.Mock).mockImplementation(
|
||||||
const message = new http.IncomingMessage(new net.Socket())
|
|
||||||
message.statusCode = 200
|
|
||||||
message.push(fs.readFileSync(fixtures.exampleArtifact.path))
|
|
||||||
return {
|
|
||||||
message
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const httpClientMock = (HttpClient as jest.Mock).mockImplementation(
|
|
||||||
() => {
|
() => {
|
||||||
return {
|
return {
|
||||||
get: getMock
|
get: mockGetArtifactSuccess
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -137,11 +159,11 @@ describe('download-artifact', () => {
|
||||||
redirect: 'manual'
|
redirect: 'manual'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
expect(httpClientMock).toHaveBeenCalledWith(getUserAgentString())
|
expect(mockHttpClient).toHaveBeenCalledWith(getUserAgentString())
|
||||||
expect(getMock).toHaveBeenCalledWith(fixtures.blobStorageUrl)
|
expect(mockGetArtifactSuccess).toHaveBeenCalledWith(
|
||||||
|
fixtures.blobStorageUrl
|
||||||
|
)
|
||||||
expectExtractedArchive(fixtures.workspaceDir)
|
expectExtractedArchive(fixtures.workspaceDir)
|
||||||
|
|
||||||
expect(response.success).toBe(true)
|
expect(response.success).toBe(true)
|
||||||
expect(response.downloadPath).toBe(fixtures.workspaceDir)
|
expect(response.downloadPath).toBe(fixtures.workspaceDir)
|
||||||
})
|
})
|
||||||
|
@ -160,18 +182,10 @@ describe('download-artifact', () => {
|
||||||
data: Buffer.from('')
|
data: Buffer.from('')
|
||||||
})
|
})
|
||||||
|
|
||||||
const getMock = jest.fn(() => {
|
const mockHttpClient = (HttpClient as jest.Mock).mockImplementation(
|
||||||
const message = new http.IncomingMessage(new net.Socket())
|
|
||||||
message.statusCode = 200
|
|
||||||
message.push(fs.readFileSync(fixtures.exampleArtifact.path))
|
|
||||||
return {
|
|
||||||
message
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const httpClientMock = (HttpClient as jest.Mock).mockImplementation(
|
|
||||||
() => {
|
() => {
|
||||||
return {
|
return {
|
||||||
get: getMock
|
get: mockGetArtifactSuccess
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -195,11 +209,11 @@ describe('download-artifact', () => {
|
||||||
redirect: 'manual'
|
redirect: 'manual'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
expect(httpClientMock).toHaveBeenCalledWith(getUserAgentString())
|
expect(mockHttpClient).toHaveBeenCalledWith(getUserAgentString())
|
||||||
expect(getMock).toHaveBeenCalledWith(fixtures.blobStorageUrl)
|
expect(mockGetArtifactSuccess).toHaveBeenCalledWith(
|
||||||
|
fixtures.blobStorageUrl
|
||||||
|
)
|
||||||
expectExtractedArchive(customPath)
|
expectExtractedArchive(customPath)
|
||||||
|
|
||||||
expect(response.success).toBe(true)
|
expect(response.success).toBe(true)
|
||||||
expect(response.downloadPath).toBe(customPath)
|
expect(response.downloadPath).toBe(customPath)
|
||||||
})
|
})
|
||||||
|
@ -246,18 +260,10 @@ describe('download-artifact', () => {
|
||||||
data: Buffer.from('')
|
data: Buffer.from('')
|
||||||
})
|
})
|
||||||
|
|
||||||
const getMock = jest.fn(() => {
|
const mockHttpClient = (HttpClient as jest.Mock).mockImplementation(
|
||||||
const message = new http.IncomingMessage(new net.Socket())
|
|
||||||
message.statusCode = 500
|
|
||||||
message.push('Internal Server Error')
|
|
||||||
return {
|
|
||||||
message
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const httpClientMock = (HttpClient as jest.Mock).mockImplementation(
|
|
||||||
() => {
|
() => {
|
||||||
return {
|
return {
|
||||||
get: getMock
|
get: mockGetArtifactFailure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -280,8 +286,176 @@ describe('download-artifact', () => {
|
||||||
redirect: 'manual'
|
redirect: 'manual'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
expect(httpClientMock).toHaveBeenCalledWith(getUserAgentString())
|
expect(mockHttpClient).toHaveBeenCalledWith(getUserAgentString())
|
||||||
expect(getMock).toHaveBeenCalledWith(fixtures.blobStorageUrl)
|
expect(mockGetArtifactFailure).toHaveBeenCalledWith(
|
||||||
|
fixtures.blobStorageUrl
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('internal', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await setup()
|
||||||
|
|
||||||
|
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('test-token')
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(util, 'getBackendIdsFromToken')
|
||||||
|
.mockReturnValue(fixtures.backendIds)
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(config, 'getResultsServiceUrl')
|
||||||
|
.mockReturnValue('https://results.local')
|
||||||
|
})
|
||||||
|
afterEach(async () => {
|
||||||
|
await cleanup()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should successfully download an artifact to $GITHUB_WORKSPACE', async () => {
|
||||||
|
const mockListArtifacts = jest
|
||||||
|
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
|
||||||
|
.mockResolvedValue({
|
||||||
|
artifacts: [
|
||||||
|
{
|
||||||
|
...fixtures.backendIds,
|
||||||
|
databaseId: fixtures.artifactID.toString(),
|
||||||
|
name: fixtures.artifactName,
|
||||||
|
size: fixtures.artifactSize.toString()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const mockGetSignedArtifactURL = jest
|
||||||
|
.spyOn(ArtifactServiceClientJSON.prototype, 'GetSignedArtifactURL')
|
||||||
|
.mockReturnValue(
|
||||||
|
Promise.resolve({
|
||||||
|
signedUrl: fixtures.blobStorageUrl
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
const mockHttpClient = (HttpClient as jest.Mock).mockImplementation(
|
||||||
|
() => {
|
||||||
|
return {
|
||||||
|
get: mockGetArtifactSuccess
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const response = await downloadArtifactInternal(fixtures.artifactID)
|
||||||
|
|
||||||
|
expectExtractedArchive(fixtures.workspaceDir)
|
||||||
|
expect(response.success).toBe(true)
|
||||||
|
expect(response.downloadPath).toBe(fixtures.workspaceDir)
|
||||||
|
expect(mockHttpClient).toHaveBeenCalledWith(getUserAgentString())
|
||||||
|
expect(mockListArtifacts).toHaveBeenCalledWith({
|
||||||
|
...fixtures.backendIds
|
||||||
|
})
|
||||||
|
expect(mockGetSignedArtifactURL).toHaveBeenCalledWith({
|
||||||
|
...fixtures.backendIds,
|
||||||
|
name: fixtures.artifactName
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should successfully download an artifact to user defined path', async () => {
|
||||||
|
const customPath = path.join(testDir, 'custom')
|
||||||
|
|
||||||
|
const mockListArtifacts = jest
|
||||||
|
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
|
||||||
|
.mockResolvedValue({
|
||||||
|
artifacts: [
|
||||||
|
{
|
||||||
|
...fixtures.backendIds,
|
||||||
|
databaseId: fixtures.artifactID.toString(),
|
||||||
|
name: fixtures.artifactName,
|
||||||
|
size: fixtures.artifactSize.toString()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const mockGetSignedArtifactURL = jest
|
||||||
|
.spyOn(ArtifactServiceClientJSON.prototype, 'GetSignedArtifactURL')
|
||||||
|
.mockReturnValue(
|
||||||
|
Promise.resolve({
|
||||||
|
signedUrl: fixtures.blobStorageUrl
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
const mockHttpClient = (HttpClient as jest.Mock).mockImplementation(
|
||||||
|
() => {
|
||||||
|
return {
|
||||||
|
get: mockGetArtifactSuccess
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const response = await downloadArtifactInternal(fixtures.artifactID, {
|
||||||
|
path: customPath
|
||||||
|
})
|
||||||
|
|
||||||
|
expectExtractedArchive(customPath)
|
||||||
|
expect(response.success).toBe(true)
|
||||||
|
expect(response.downloadPath).toBe(customPath)
|
||||||
|
expect(mockHttpClient).toHaveBeenCalledWith(getUserAgentString())
|
||||||
|
expect(mockListArtifacts).toHaveBeenCalledWith({
|
||||||
|
...fixtures.backendIds
|
||||||
|
})
|
||||||
|
expect(mockGetSignedArtifactURL).toHaveBeenCalledWith({
|
||||||
|
...fixtures.backendIds,
|
||||||
|
name: fixtures.artifactName
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should fail if download artifact API does not respond with location', async () => {
|
||||||
|
jest
|
||||||
|
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
|
||||||
|
.mockRejectedValue(new Error('boom'))
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
downloadArtifactInternal(fixtures.artifactID)
|
||||||
|
).rejects.toBeInstanceOf(Error)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should fail if blob storage response is non-200', async () => {
|
||||||
|
const mockListArtifacts = jest
|
||||||
|
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
|
||||||
|
.mockResolvedValue({
|
||||||
|
artifacts: [
|
||||||
|
{
|
||||||
|
...fixtures.backendIds,
|
||||||
|
databaseId: fixtures.artifactID.toString(),
|
||||||
|
name: fixtures.artifactName,
|
||||||
|
size: fixtures.artifactSize.toString()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const mockGetSignedArtifactURL = jest
|
||||||
|
.spyOn(ArtifactServiceClientJSON.prototype, 'GetSignedArtifactURL')
|
||||||
|
.mockReturnValue(
|
||||||
|
Promise.resolve({
|
||||||
|
signedUrl: fixtures.blobStorageUrl
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
const mockHttpClient = (HttpClient as jest.Mock).mockImplementation(
|
||||||
|
() => {
|
||||||
|
return {
|
||||||
|
get: mockGetArtifactFailure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
downloadArtifactInternal(fixtures.artifactID)
|
||||||
|
).rejects.toBeInstanceOf(Error)
|
||||||
|
expect(mockHttpClient).toHaveBeenCalledWith(getUserAgentString())
|
||||||
|
expect(mockListArtifacts).toHaveBeenCalledWith({
|
||||||
|
...fixtures.backendIds
|
||||||
|
})
|
||||||
|
expect(mockGetSignedArtifactURL).toHaveBeenCalledWith({
|
||||||
|
...fixtures.backendIds,
|
||||||
|
name: fixtures.artifactName
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {
|
||||||
validateFilePath
|
validateFilePath
|
||||||
} from '../src/internal/upload/path-and-artifact-name-validation'
|
} from '../src/internal/upload/path-and-artifact-name-validation'
|
||||||
|
|
||||||
import {noopLogs} from './common.test'
|
import {noopLogs} from './common'
|
||||||
|
|
||||||
describe('Path and artifact name validation', () => {
|
describe('Path and artifact name validation', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import * as config from '../src/internal/shared/config'
|
||||||
import {Timestamp, ArtifactServiceClientJSON} from '../src/generated'
|
import {Timestamp, ArtifactServiceClientJSON} from '../src/generated'
|
||||||
import * as blobUpload from '../src/internal/upload/blob-upload'
|
import * as blobUpload from '../src/internal/upload/blob-upload'
|
||||||
import {uploadArtifact} from '../src/internal/upload/upload-artifact'
|
import {uploadArtifact} from '../src/internal/upload/upload-artifact'
|
||||||
import {noopLogs} from './common.test'
|
import {noopLogs} from './common'
|
||||||
|
|
||||||
describe('upload-artifact', () => {
|
describe('upload-artifact', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -127,7 +127,7 @@ describe('upload-artifact', () => {
|
||||||
expect(uploadResp).resolves.toEqual({success: false})
|
expect(uploadResp).resolves.toEqual({success: false})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return false if no backend IDs are found', () => {
|
it('should reject if no backend IDs are found', () => {
|
||||||
jest
|
jest
|
||||||
.spyOn(uploadZipSpecification, 'validateRootDirectory')
|
.spyOn(uploadZipSpecification, 'validateRootDirectory')
|
||||||
.mockReturnValue()
|
.mockReturnValue()
|
||||||
|
@ -151,9 +151,6 @@ describe('upload-artifact', () => {
|
||||||
jest
|
jest
|
||||||
.spyOn(zip, 'createZipUploadStream')
|
.spyOn(zip, 'createZipUploadStream')
|
||||||
.mockReturnValue(Promise.resolve(new zip.ZipUploadStream(1)))
|
.mockReturnValue(Promise.resolve(new zip.ZipUploadStream(1)))
|
||||||
jest
|
|
||||||
.spyOn(util, 'getBackendIdsFromToken')
|
|
||||||
.mockReturnValue({workflowRunBackendId: '', workflowJobRunBackendId: ''})
|
|
||||||
|
|
||||||
const uploadResp = uploadArtifact(
|
const uploadResp = uploadArtifact(
|
||||||
'test-artifact',
|
'test-artifact',
|
||||||
|
@ -165,7 +162,7 @@ describe('upload-artifact', () => {
|
||||||
'/home/user/files/plz-upload'
|
'/home/user/files/plz-upload'
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(uploadResp).resolves.toEqual({success: false})
|
expect(uploadResp).rejects.toThrow()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return false if the creation request fails', () => {
|
it('should return false if the creation request fails', () => {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {
|
||||||
getUploadZipSpecification,
|
getUploadZipSpecification,
|
||||||
validateRootDirectory
|
validateRootDirectory
|
||||||
} from '../src/internal/upload/upload-zip-specification'
|
} from '../src/internal/upload/upload-zip-specification'
|
||||||
import {noopLogs} from './common.test'
|
import {noopLogs} from './common'
|
||||||
|
|
||||||
const root = path.join(__dirname, '_temp', 'upload-specification')
|
const root = path.join(__dirname, '_temp', 'upload-specification')
|
||||||
const goodItem1Path = path.join(
|
const goodItem1Path = path.join(
|
||||||
|
|
Loading…
Reference in New Issue