tests
This commit is contained in:
@@ -74,8 +74,6 @@ describe('createArchives', () => {
|
||||
expect(zipSHA).toEqual(systemZipHash)
|
||||
expect(tarSHA).toEqual(systemTarHash)
|
||||
})
|
||||
|
||||
// TODO: Test the failure cases
|
||||
})
|
||||
|
||||
describe('createTempDir', () => {
|
||||
@@ -189,11 +187,15 @@ describe('bundleFilesintoDirectory', () => {
|
||||
// Create some test files and folders in the sourceDir
|
||||
const file1 = `${sourceDir}/file1.txt`
|
||||
const folder1 = `${sourceDir}/folder1`
|
||||
const file2 = `${folder1}/file3.txt`
|
||||
const file2 = `${folder1}/file2.txt`
|
||||
const folder2 = `${folder1}/folder2`
|
||||
const file3 = `${folder2}/file3.txt`
|
||||
|
||||
fs.mkdirSync(folder1)
|
||||
fs.mkdirSync(folder2)
|
||||
fs.writeFileSync(file1, fileContent)
|
||||
fs.writeFileSync(file2, fileContent)
|
||||
fs.writeFileSync(file3, fileContent)
|
||||
|
||||
// Bundle the files and folders into the targetDir
|
||||
fsHelper.bundleFilesintoDirectory([file1, folder1], targetDir)
|
||||
@@ -206,6 +208,10 @@ describe('bundleFilesintoDirectory', () => {
|
||||
|
||||
expect(fs.existsSync(file2)).toEqual(true)
|
||||
expect(fsHelper.readFileContents(file2).toString()).toEqual(fileContent)
|
||||
|
||||
expect(fs.existsSync(`${targetDir}/folder1/folder2`)).toEqual(true)
|
||||
expect(fs.existsSync(file3)).toEqual(true)
|
||||
expect(fsHelper.readFileContents(file3).toString()).toEqual(fileContent)
|
||||
})
|
||||
|
||||
it('throws an error if a file or directory does not exist', () => {
|
||||
|
||||
+107
-32
@@ -9,20 +9,21 @@ let axiosPostMock: jest.SpyInstance
|
||||
let axiosPutMock: jest.SpyInstance
|
||||
let axiosHeadMock: jest.SpyInstance
|
||||
|
||||
const token = '1234567890'
|
||||
const token = 'test-token'
|
||||
const registry = new URL('https://ghcr.io')
|
||||
const repository = 'test/test'
|
||||
const releaseId = '1234567890'
|
||||
const semver = '1.0.0'
|
||||
const repository = 'test-org/test-repo'
|
||||
const releaseId = 'test-release-id'
|
||||
const semver = '1.2.3'
|
||||
const genericSha = '1234567890' // We should look at using different shas here to catch bug, but that make location validation harder
|
||||
const zipFile: fsHelper.FileMetadata = {
|
||||
path: 'test-repo-1.0.0.zip',
|
||||
size: 100,
|
||||
sha256: '1234567890'
|
||||
path: `test-repo-${semver}.zip`,
|
||||
size: 123,
|
||||
sha256: genericSha
|
||||
}
|
||||
const tarFile: fsHelper.FileMetadata = {
|
||||
path: 'test-repo-1.0.0.tar.gz',
|
||||
size: 100,
|
||||
sha256: '1234567890'
|
||||
path: `test-repo-${semver}.tar.gz`,
|
||||
size: 456,
|
||||
sha256: genericSha
|
||||
}
|
||||
|
||||
const testManifest: ociContainer.Manifest = {
|
||||
@@ -50,25 +51,25 @@ const testManifest: ociContainer.Manifest = {
|
||||
},
|
||||
{
|
||||
mediaType: 'application/vnd.github.actions.package.layer.v1.tar+gzip',
|
||||
size: 100,
|
||||
digest: 'sha256:1234567890',
|
||||
size: tarFile.size,
|
||||
digest: `sha256:${tarFile.sha256}`,
|
||||
annotations: {
|
||||
'org.opencontainers.image.title': 'test-repo-1.0.0.tar.gz'
|
||||
'org.opencontainers.image.title': tarFile.path
|
||||
}
|
||||
},
|
||||
{
|
||||
mediaType: 'application/vnd.github.actions.package.layer.v1.zip',
|
||||
size: 100,
|
||||
digest: 'sha256:1234567890',
|
||||
size: zipFile.size,
|
||||
digest: `sha256:${zipFile.sha256}`,
|
||||
annotations: {
|
||||
'org.opencontainers.image.title': 'test-repo-1.0.0.zip'
|
||||
'org.opencontainers.image.title': zipFile.path
|
||||
}
|
||||
}
|
||||
],
|
||||
annotations: {
|
||||
'org.opencontainers.image.created': '2021-01-01T00:00:00.000Z',
|
||||
'action.tar.gz.digest': '1234567890',
|
||||
'action.zip.digest': '1234567890',
|
||||
'action.tar.gz.digest': tarFile.sha256,
|
||||
'action.zip.digest': zipFile.sha256,
|
||||
'com.github.package.type': 'actions_oci_pkg'
|
||||
}
|
||||
}
|
||||
@@ -101,7 +102,7 @@ describe('publishOCIArtifact', () => {
|
||||
return {
|
||||
status: 202,
|
||||
headers: {
|
||||
location: 'https://ghcr.io/v2/test/test/blobs/uploads/1234567890'
|
||||
location: `https://ghcr.io/v2/${repository}/blobs/uploads/${genericSha}`
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -133,11 +134,9 @@ describe('publishOCIArtifact', () => {
|
||||
expect(axiosHeadMock).toHaveBeenCalledTimes(3)
|
||||
expect(axiosPostMock).toHaveBeenCalledTimes(3)
|
||||
expect(axiosPutMock).toHaveBeenCalledTimes(4)
|
||||
|
||||
// TODO: Check that the base64 encoded token is sent in the Authorization header
|
||||
})
|
||||
|
||||
it('skips uploading layer blobs that already exist', async () => {
|
||||
it('skips uploading all layer blobs when they all already exist', async () => {
|
||||
// Simulate all blobs already existing
|
||||
axiosHeadMock.mockImplementation(async (url, config) => {
|
||||
validateRequestConfig(200, url, config)
|
||||
@@ -152,7 +151,7 @@ describe('publishOCIArtifact', () => {
|
||||
return {
|
||||
status: 202,
|
||||
headers: {
|
||||
location: 'https://ghcr.io/v2/test/test/blobs/uploads/1234567890'
|
||||
location: `https://ghcr.io/v2/${repository}/blobs/uploads/${genericSha}`
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -187,6 +186,68 @@ describe('publishOCIArtifact', () => {
|
||||
expect(axiosPutMock).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('skips uploading layer blobs that already exist', async () => {
|
||||
// Simulate some blobs already existing
|
||||
|
||||
let count = 0
|
||||
axiosHeadMock.mockImplementation(async (url, config) => {
|
||||
count++
|
||||
if (count === 1) {
|
||||
// report the first blob as being there
|
||||
validateRequestConfig(200, url, config)
|
||||
return {
|
||||
status: 200
|
||||
}
|
||||
} else {
|
||||
// report all others are missing
|
||||
validateRequestConfig(404, url, config)
|
||||
return {
|
||||
status: 404
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Simulate successful initiation of uploads for all blobs & return location
|
||||
axiosPostMock.mockImplementation(async (url, data, config) => {
|
||||
validateRequestConfig(202, url, config)
|
||||
return {
|
||||
status: 202,
|
||||
headers: {
|
||||
location: `https://ghcr.io/v2/${repository}/blobs/uploads/${genericSha}`
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Simulate successful reading of all the files
|
||||
fsReadFileSyncMock.mockImplementation(() => {
|
||||
return Buffer.from('test')
|
||||
})
|
||||
|
||||
// Simulate successful upload of all blobs & then the manifest
|
||||
axiosPutMock.mockImplementation(async (url, data, config) => {
|
||||
validateRequestConfig(201, url, config)
|
||||
return {
|
||||
status: 201
|
||||
}
|
||||
})
|
||||
|
||||
await publishOCIArtifact(
|
||||
token,
|
||||
registry,
|
||||
repository,
|
||||
releaseId,
|
||||
semver,
|
||||
zipFile,
|
||||
tarFile,
|
||||
testManifest
|
||||
)
|
||||
|
||||
// We should only head all the blobs and then upload the missing blobs and manifest
|
||||
expect(axiosHeadMock).toHaveBeenCalledTimes(3)
|
||||
expect(axiosPostMock).toHaveBeenCalledTimes(2)
|
||||
expect(axiosPutMock).toHaveBeenCalledTimes(3)
|
||||
})
|
||||
|
||||
it('throws an error if checking for existing blobs fails', async () => {
|
||||
// Simulate failed response code
|
||||
axiosHeadMock.mockImplementation(async (url, config) => {
|
||||
@@ -288,7 +349,7 @@ describe('publishOCIArtifact', () => {
|
||||
return {
|
||||
status: 202,
|
||||
headers: {
|
||||
location: 'https://ghcr.io/v2/test/test/blobs/uploads/1234567890'
|
||||
location: `https://ghcr.io/v2/${repository}/blobs/uploads/${genericSha}`
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -335,7 +396,7 @@ describe('publishOCIArtifact', () => {
|
||||
return {
|
||||
status: 202,
|
||||
headers: {
|
||||
location: 'https://ghcr.io/v2/test/test/blobs/uploads/1234567890'
|
||||
location: `https://ghcr.io/v2/${repository}/blobs/uploads/${genericSha}`
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -389,7 +450,7 @@ describe('publishOCIArtifact', () => {
|
||||
return {
|
||||
status: 202,
|
||||
headers: {
|
||||
location: 'https://ghcr.io/v2/test/test/blobs/uploads/1234567890'
|
||||
location: `https://ghcr.io/v2/${repository}/blobs/uploads/${genericSha}`
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -422,9 +483,15 @@ describe('publishOCIArtifact', () => {
|
||||
})
|
||||
|
||||
it('throws an error if one of the layers has the wrong media type', async () => {
|
||||
const modifiedTestManifest = testManifest
|
||||
const modifiedTestManifest = { ...testManifest } // This is _NOT_ a deep clone
|
||||
modifiedTestManifest.layers = cloneLayers(modifiedTestManifest.layers)
|
||||
modifiedTestManifest.layers[0].mediaType = 'application/json'
|
||||
|
||||
// just checking to make sure we are not changing the shared object
|
||||
expect(modifiedTestManifest.layers[0].mediaType).not.toEqual(
|
||||
testManifest.layers[0].mediaType
|
||||
)
|
||||
|
||||
await expect(
|
||||
publishOCIArtifact(
|
||||
token,
|
||||
@@ -434,7 +501,7 @@ describe('publishOCIArtifact', () => {
|
||||
semver,
|
||||
zipFile,
|
||||
tarFile,
|
||||
testManifest
|
||||
modifiedTestManifest
|
||||
)
|
||||
).rejects.toThrow('Unknown media type application/json')
|
||||
})
|
||||
@@ -446,12 +513,12 @@ describe('publishOCIArtifact', () => {
|
||||
function validateRequestConfig(status: number, url: string, config: any): void {
|
||||
// Basic URL checks
|
||||
expect(url).toBeDefined()
|
||||
|
||||
if (!url.startsWith(registry.toString())) {
|
||||
console.log(url)
|
||||
console.log(`${url} does not start with ${registry}`)
|
||||
}
|
||||
|
||||
expect(url.startsWith(registry.toString())).toBe(true)
|
||||
// if these expect fails, run the test again with `-- --silent=false`
|
||||
// the console.log above should give a clue about which URL is failing
|
||||
expect(url.startsWith(registry.toString())).toBeTruthy()
|
||||
|
||||
// Config checks
|
||||
expect(config).toBeDefined()
|
||||
@@ -472,3 +539,11 @@ function validateRequestConfig(status: number, url: string, config: any): void {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function cloneLayers(layers: ociContainer.Layer[]): ociContainer.Layer[] {
|
||||
const result: ociContainer.Layer[] = []
|
||||
for (const layer of layers) {
|
||||
result.push({ ...layer }) // this is _NOT_ a deep clone
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
+12
-12
@@ -69,7 +69,7 @@ describe('action', () => {
|
||||
|
||||
it('fails if event is not a release', async () => {
|
||||
// Mock the environment
|
||||
process.env.GITHUB_REPOSITORY = 'test/test'
|
||||
process.env.GITHUB_REPOSITORY = 'test-org/test-repo'
|
||||
github.context.eventName = 'push'
|
||||
|
||||
// Run the action
|
||||
@@ -83,7 +83,7 @@ describe('action', () => {
|
||||
|
||||
it('fails if release tag is not a valid semantic version', async () => {
|
||||
// Mock the environment
|
||||
process.env.GITHUB_REPOSITORY = 'test/test'
|
||||
process.env.GITHUB_REPOSITORY = 'test-org/test-repo'
|
||||
github.context.eventName = 'release'
|
||||
github.context.payload = {
|
||||
release: {
|
||||
@@ -103,12 +103,12 @@ describe('action', () => {
|
||||
|
||||
it('fails if multiple paths are provided and staging files fails', async () => {
|
||||
// Mock the environment
|
||||
process.env.GITHUB_REPOSITORY = 'test/test'
|
||||
process.env.GITHUB_REPOSITORY = 'test-org/test-repo'
|
||||
github.context.eventName = 'release'
|
||||
github.context.payload = {
|
||||
release: {
|
||||
id: '123',
|
||||
tag_name: 'v1.0.0'
|
||||
tag_name: 'v1.2.3'
|
||||
}
|
||||
}
|
||||
getInputMock.mockImplementation((name: string) => {
|
||||
@@ -135,12 +135,12 @@ describe('action', () => {
|
||||
|
||||
it('fails if an error is thrown from dependent code', async () => {
|
||||
// Mock the environment
|
||||
process.env.GITHUB_REPOSITORY = 'test/test'
|
||||
process.env.GITHUB_REPOSITORY = 'test-org/test-repo'
|
||||
github.context.eventName = 'release'
|
||||
github.context.payload = {
|
||||
release: {
|
||||
id: '123',
|
||||
tag_name: 'v1.0.0'
|
||||
tag_name: 'v1.2.3'
|
||||
}
|
||||
}
|
||||
getInputMock.mockImplementation((name: string) => {
|
||||
@@ -172,22 +172,22 @@ describe('action', () => {
|
||||
})
|
||||
|
||||
it('successfully uploads if the release tag is a semver without v prefix', async () => {
|
||||
await testHappyPath('1.0.0', 'test')
|
||||
await testHappyPath('1.2.3', 'test')
|
||||
})
|
||||
|
||||
it('successfully uploads if the release tag is a semver with v prefix', async () => {
|
||||
await testHappyPath('v1.0.0', 'test')
|
||||
await testHappyPath('v1.2.3', 'test')
|
||||
})
|
||||
|
||||
it('successfully uploads if multiple paths are provided', async () => {
|
||||
await testHappyPath('v1.0.0', 'test test2')
|
||||
await testHappyPath('v1.2.3', 'test test2')
|
||||
})
|
||||
})
|
||||
|
||||
// Test that main successfully uploads and returns the manifest & package URL
|
||||
async function testHappyPath(version: string, path: string): Promise<void> {
|
||||
// Mock the environment
|
||||
process.env.GITHUB_REPOSITORY = 'test/test'
|
||||
process.env.GITHUB_REPOSITORY = 'test-org/test-repo'
|
||||
github.context.eventName = 'release'
|
||||
github.context.payload = {
|
||||
release: {
|
||||
@@ -228,7 +228,7 @@ async function testHappyPath(version: string, path: string): Promise<void> {
|
||||
})
|
||||
|
||||
publishOCIArtifactMock.mockImplementation(() => {
|
||||
return new URL('https://ghcr.io/v2/test/test:1.0.0')
|
||||
return new URL('https://ghcr.io/v2/test-org/test-repo:1.2.3')
|
||||
})
|
||||
|
||||
// Run the action
|
||||
@@ -239,7 +239,7 @@ async function testHappyPath(version: string, path: string): Promise<void> {
|
||||
// Check manifest is in output
|
||||
expect(setOutputMock).toHaveBeenCalledWith(
|
||||
'package-url',
|
||||
'https://ghcr.io/v2/test/test:1.0.0'
|
||||
'https://ghcr.io/v2/test-org/test-repo:1.2.3'
|
||||
)
|
||||
expect(setOutputMock).toHaveBeenCalledWith(
|
||||
'package-manifest',
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import { createActionPackageManifest } from '../src/oci-container'
|
||||
import { FileMetadata } from '../src/fs-helper'
|
||||
|
||||
describe('createActionPackageManigest', () => {
|
||||
describe('createActionPackageManifest', () => {
|
||||
it('creates a manifest containing the provided information', () => {
|
||||
const date = new Date()
|
||||
const repo = 'test-org/test-repo'
|
||||
const sanitizedRepo = 'test-org-test-repo'
|
||||
const version = '1.0.0'
|
||||
const version = '1.2.3'
|
||||
const tarFile: FileMetadata = {
|
||||
path: '/test/test/test',
|
||||
sha256: '1234567890',
|
||||
size: 100
|
||||
path: '/test/test/test.tar.gz',
|
||||
sha256: 'tarSha',
|
||||
size: 123
|
||||
}
|
||||
const zipFile: FileMetadata = {
|
||||
path: '/test/test/test',
|
||||
sha256: '1234567890',
|
||||
size: 100
|
||||
path: '/test/test/test.zip',
|
||||
sha256: 'zipSha',
|
||||
size: 456
|
||||
}
|
||||
|
||||
const expectedJSON = `{
|
||||
@@ -49,8 +49,8 @@ describe('createActionPackageManigest', () => {
|
||||
},
|
||||
{
|
||||
"mediaType":"application/vnd.github.actions.package.layer.v1.zip",
|
||||
"size":${tarFile.size},
|
||||
"digest":"${tarFile.sha256}",
|
||||
"size":${zipFile.size},
|
||||
"digest":"${zipFile.sha256}",
|
||||
"annotations":{
|
||||
"org.opencontainers.image.title":"${sanitizedRepo}_${version}.zip"
|
||||
}
|
||||
@@ -67,13 +67,13 @@ describe('createActionPackageManigest', () => {
|
||||
const manifest = createActionPackageManifest(
|
||||
{
|
||||
path: 'test.tar.gz',
|
||||
size: 100,
|
||||
sha256: '1234567890'
|
||||
size: tarFile.size,
|
||||
sha256: tarFile.sha256
|
||||
},
|
||||
{
|
||||
path: 'test.zip',
|
||||
size: 100,
|
||||
sha256: '1234567890'
|
||||
size: zipFile.size,
|
||||
sha256: zipFile.sha256
|
||||
},
|
||||
repo,
|
||||
version,
|
||||
|
||||
Reference in New Issue
Block a user