update tests to remove axios mocks and mock fetch instead
This commit is contained in:
+267
-235
@@ -1,13 +1,10 @@
|
|||||||
import { publishOCIArtifact } from '../src/ghcr-client'
|
import { publishOCIArtifact } from '../src/ghcr-client'
|
||||||
import axios from 'axios'
|
|
||||||
import * as fsHelper from '../src/fs-helper'
|
import * as fsHelper from '../src/fs-helper'
|
||||||
import * as ociContainer from '../src/oci-container'
|
import * as ociContainer from '../src/oci-container'
|
||||||
|
|
||||||
// Mocks
|
// Mocks
|
||||||
let fsReadFileSyncMock: jest.SpyInstance
|
let fsReadFileSyncMock: jest.SpyInstance
|
||||||
let axiosPostMock: jest.SpyInstance
|
let fetchMock: jest.SpyInstance
|
||||||
let axiosPutMock: jest.SpyInstance
|
|
||||||
let axiosHeadMock: jest.SpyInstance
|
|
||||||
|
|
||||||
const token = 'test-token'
|
const token = 'test-token'
|
||||||
const registry = new URL('https://ghcr.io')
|
const registry = new URL('https://ghcr.io')
|
||||||
@@ -81,28 +78,48 @@ describe('publishOCIArtifact', () => {
|
|||||||
.spyOn(fsHelper, 'readFileContents')
|
.spyOn(fsHelper, 'readFileContents')
|
||||||
.mockImplementation()
|
.mockImplementation()
|
||||||
|
|
||||||
axiosPostMock = jest.spyOn(axios, 'post').mockImplementation()
|
fetchMock = jest.spyOn(global, 'fetch').mockImplementation()
|
||||||
axiosPutMock = jest.spyOn(axios, 'put').mockImplementation()
|
|
||||||
axiosHeadMock = jest.spyOn(axios, 'head').mockImplementation()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('publishes layer blobs & then a manifest to the provided registry', async () => {
|
it('publishes layer blobs & then a manifest to the provided registry', async () => {
|
||||||
// Simulate none of the blobs existing currently
|
fetchMock.mockImplementation(async (url, options) => {
|
||||||
axiosHeadMock.mockImplementation(async (url, config) => {
|
if (options.method === 'HEAD') {
|
||||||
validateRequestConfig(404, url, config)
|
validateRequestConfig(url, options)
|
||||||
return {
|
// Simulate none of the blobs existing currently
|
||||||
status: 404
|
return Promise.resolve({
|
||||||
}
|
status: 404
|
||||||
})
|
})
|
||||||
|
} else if (options.method === 'POST') {
|
||||||
// Simulate successful initiation of uploads for all blobs & return location
|
// Simulate successful initiation of uploads for all blobs & return location
|
||||||
axiosPostMock.mockImplementation(async (url, data, config) => {
|
validateRequestConfig(url, options)
|
||||||
validateRequestConfig(202, url, config)
|
return Promise.resolve({
|
||||||
return {
|
status: 202,
|
||||||
status: 202,
|
headers: {
|
||||||
headers: {
|
get: (header: string) => {
|
||||||
location: `https://ghcr.io/v2/${repository}/blobs/uploads/${genericSha}`
|
if (header === 'location') {
|
||||||
|
return `https://ghcr.io/v2/${repository}/blobs/uploads/${genericSha}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (options.method === 'PUT') {
|
||||||
|
// Simulate successful upload of all blobs & then the manifest
|
||||||
|
validateRequestConfig(url, options)
|
||||||
|
if ((url as string).includes('manifest')) {
|
||||||
|
return Promise.resolve({
|
||||||
|
status: 201,
|
||||||
|
headers: {
|
||||||
|
get: (header: string) => {
|
||||||
|
if (header === 'docker-content-digest') {
|
||||||
|
return '1234567678'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
return Promise.resolve({
|
||||||
|
status: 201
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -111,22 +128,6 @@ describe('publishOCIArtifact', () => {
|
|||||||
return Buffer.from('test')
|
return Buffer.from('test')
|
||||||
})
|
})
|
||||||
|
|
||||||
// Simulate successful upload of all blobs & then the manifest
|
|
||||||
axiosPutMock.mockImplementation(async (url, data, config) => {
|
|
||||||
validateRequestConfig(201, url, config)
|
|
||||||
|
|
||||||
if ((url as string).includes('manifest')) {
|
|
||||||
return {
|
|
||||||
status: 201,
|
|
||||||
headers: { 'docker-content-digest': '1234567678' }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
status: 201
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
await publishOCIArtifact(
|
await publishOCIArtifact(
|
||||||
token,
|
token,
|
||||||
registry,
|
registry,
|
||||||
@@ -137,28 +138,58 @@ describe('publishOCIArtifact', () => {
|
|||||||
testManifest
|
testManifest
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(axiosHeadMock).toHaveBeenCalledTimes(3)
|
expect(fetchMock).toHaveBeenCalledTimes(10)
|
||||||
expect(axiosPostMock).toHaveBeenCalledTimes(3)
|
expect(
|
||||||
expect(axiosPutMock).toHaveBeenCalledTimes(4)
|
fetchMock.mock.calls.filter(call => call[1].method === 'HEAD')
|
||||||
|
).toHaveLength(3)
|
||||||
|
expect(
|
||||||
|
fetchMock.mock.calls.filter(call => call[1].method === 'POST')
|
||||||
|
).toHaveLength(3)
|
||||||
|
expect(
|
||||||
|
fetchMock.mock.calls.filter(call => call[1].method === 'PUT')
|
||||||
|
).toHaveLength(4)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('skips uploading all layer blobs when they all already exist', async () => {
|
it('skips uploading all layer blobs when they all already exist', async () => {
|
||||||
// Simulate all blobs already existing
|
// Simulate all blobs already existing
|
||||||
axiosHeadMock.mockImplementation(async (url, config) => {
|
fetchMock.mockImplementation(async (url, options) => {
|
||||||
validateRequestConfig(200, url, config)
|
if (options.method === 'HEAD') {
|
||||||
return {
|
// Simulate none of the blobs existing currently
|
||||||
status: 200
|
validateRequestConfig(url, options)
|
||||||
}
|
return Promise.resolve({
|
||||||
})
|
status: 200
|
||||||
|
})
|
||||||
// Simulate successful initiation of uploads for all blobs & return location
|
} else if (options.method === 'POST') {
|
||||||
axiosPostMock.mockImplementation(async (url, data, config) => {
|
// Simulate successful initiation of uploads for all blobs & return location
|
||||||
validateRequestConfig(202, url, config)
|
validateRequestConfig(url, options)
|
||||||
return {
|
return Promise.resolve({
|
||||||
status: 202,
|
status: 202,
|
||||||
headers: {
|
headers: {
|
||||||
location: `https://ghcr.io/v2/${repository}/blobs/uploads/${genericSha}`
|
get: (header: string) => {
|
||||||
|
if (header === 'location') {
|
||||||
|
return `https://ghcr.io/v2/${repository}/blobs/uploads/${genericSha}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (options.method === 'PUT') {
|
||||||
|
// Simulate successful upload of all blobs & then the manifest
|
||||||
|
validateRequestConfig(url, options)
|
||||||
|
if ((url as string).includes('manifest')) {
|
||||||
|
return Promise.resolve({
|
||||||
|
status: 201,
|
||||||
|
headers: {
|
||||||
|
get: (header: string) => {
|
||||||
|
if (header === 'docker-content-digest') {
|
||||||
|
return '1234567678'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
return Promise.resolve({
|
||||||
|
status: 201
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -167,22 +198,6 @@ describe('publishOCIArtifact', () => {
|
|||||||
return Buffer.from('test')
|
return Buffer.from('test')
|
||||||
})
|
})
|
||||||
|
|
||||||
// Simulate successful upload of all blobs & then the manifest
|
|
||||||
axiosPutMock.mockImplementation(async (url, data, config) => {
|
|
||||||
validateRequestConfig(201, url, config)
|
|
||||||
|
|
||||||
if ((url as string).includes('manifest')) {
|
|
||||||
return {
|
|
||||||
status: 201,
|
|
||||||
headers: { 'docker-content-digest': '1234567678' }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
status: 201
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
await publishOCIArtifact(
|
await publishOCIArtifact(
|
||||||
token,
|
token,
|
||||||
registry,
|
registry,
|
||||||
@@ -194,40 +209,66 @@ describe('publishOCIArtifact', () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// We should only head all the blobs and then upload the manifest
|
// We should only head all the blobs and then upload the manifest
|
||||||
expect(axiosHeadMock).toHaveBeenCalledTimes(3)
|
expect(fetchMock).toHaveBeenCalledTimes(4)
|
||||||
expect(axiosPostMock).toHaveBeenCalledTimes(0)
|
expect(
|
||||||
expect(axiosPutMock).toHaveBeenCalledTimes(1)
|
fetchMock.mock.calls.filter(call => call[1].method === 'HEAD')
|
||||||
|
).toHaveLength(3)
|
||||||
|
expect(
|
||||||
|
fetchMock.mock.calls.filter(call => call[1].method === 'POST')
|
||||||
|
).toHaveLength(0)
|
||||||
|
expect(
|
||||||
|
fetchMock.mock.calls.filter(call => call[1].method === 'PUT')
|
||||||
|
).toHaveLength(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('skips uploading layer blobs that already exist', async () => {
|
it('skips uploading layer blobs that already exist', async () => {
|
||||||
// Simulate some blobs already existing
|
// Simulate some blobs already existing
|
||||||
|
|
||||||
let count = 0
|
let count = 0
|
||||||
axiosHeadMock.mockImplementation(async (url, config) => {
|
fetchMock.mockImplementation(async (url, options) => {
|
||||||
count++
|
count++
|
||||||
if (count === 1) {
|
if (options.method === 'HEAD') {
|
||||||
// report the first blob as being there
|
validateRequestConfig(url, options)
|
||||||
validateRequestConfig(200, url, config)
|
if (count === 1) {
|
||||||
return {
|
return Promise.resolve({
|
||||||
status: 200
|
status: 200
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// report all others are missing
|
||||||
|
return Promise.resolve({
|
||||||
|
status: 404
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else if (options.method === 'POST') {
|
||||||
// report all others are missing
|
// Simulate successful initiation of uploads for all blobs & return location
|
||||||
validateRequestConfig(404, url, config)
|
validateRequestConfig(url, options)
|
||||||
return {
|
return Promise.resolve({
|
||||||
status: 404
|
status: 202,
|
||||||
}
|
headers: {
|
||||||
}
|
get: (header: string) => {
|
||||||
})
|
if (header === 'location') {
|
||||||
|
return `https://ghcr.io/v2/${repository}/blobs/uploads/${genericSha}`
|
||||||
// Simulate successful initiation of uploads for all blobs & return location
|
}
|
||||||
axiosPostMock.mockImplementation(async (url, data, config) => {
|
}
|
||||||
validateRequestConfig(202, url, config)
|
}
|
||||||
return {
|
})
|
||||||
status: 202,
|
} else if (options.method === 'PUT') {
|
||||||
headers: {
|
// Simulate successful upload of all blobs & then the manifest
|
||||||
location: `https://ghcr.io/v2/${repository}/blobs/uploads/${genericSha}`
|
validateRequestConfig(url, options)
|
||||||
|
if ((url as string).includes('manifest')) {
|
||||||
|
return Promise.resolve({
|
||||||
|
status: 201,
|
||||||
|
headers: {
|
||||||
|
get: (header: string) => {
|
||||||
|
if (header === 'docker-content-digest') {
|
||||||
|
return '1234567678'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
return Promise.resolve({
|
||||||
|
status: 201
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -236,22 +277,6 @@ describe('publishOCIArtifact', () => {
|
|||||||
return Buffer.from('test')
|
return Buffer.from('test')
|
||||||
})
|
})
|
||||||
|
|
||||||
// Simulate successful upload of all blobs & then the manifest
|
|
||||||
axiosPutMock.mockImplementation(async (url, data, config) => {
|
|
||||||
validateRequestConfig(201, url, config)
|
|
||||||
|
|
||||||
if ((url as string).includes('manifest')) {
|
|
||||||
return {
|
|
||||||
status: 201,
|
|
||||||
headers: { 'docker-content-digest': '1234567678' }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
status: 201
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
await publishOCIArtifact(
|
await publishOCIArtifact(
|
||||||
token,
|
token,
|
||||||
registry,
|
registry,
|
||||||
@@ -262,18 +287,27 @@ describe('publishOCIArtifact', () => {
|
|||||||
testManifest
|
testManifest
|
||||||
)
|
)
|
||||||
|
|
||||||
|
expect(fetchMock).toHaveBeenCalledTimes(8)
|
||||||
// We should only head all the blobs and then upload the missing blobs and manifest
|
// We should only head all the blobs and then upload the missing blobs and manifest
|
||||||
expect(axiosHeadMock).toHaveBeenCalledTimes(3)
|
expect(
|
||||||
expect(axiosPostMock).toHaveBeenCalledTimes(2)
|
fetchMock.mock.calls.filter(call => call[1].method === 'HEAD')
|
||||||
expect(axiosPutMock).toHaveBeenCalledTimes(3)
|
).toHaveLength(3)
|
||||||
|
expect(
|
||||||
|
fetchMock.mock.calls.filter(call => call[1].method === 'POST')
|
||||||
|
).toHaveLength(2)
|
||||||
|
expect(
|
||||||
|
fetchMock.mock.calls.filter(call => call[1].method === 'PUT')
|
||||||
|
).toHaveLength(3)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('throws an error if checking for existing blobs fails', async () => {
|
it('throws an error if checking for existing blobs fails', async () => {
|
||||||
// Simulate failed response code
|
fetchMock.mockImplementation(async (url, options) => {
|
||||||
axiosHeadMock.mockImplementation(async (url, config) => {
|
if (options.method === 'HEAD') {
|
||||||
validateRequestConfig(503, url, config)
|
validateRequestConfig(url, options)
|
||||||
return {
|
// Simulate failed response code
|
||||||
status: 503
|
return Promise.resolve({
|
||||||
|
status: 503
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -291,19 +325,18 @@ describe('publishOCIArtifact', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('throws an error if initiating layer upload fails', async () => {
|
it('throws an error if initiating layer upload fails', async () => {
|
||||||
// Simulate none of the blobs existing currently
|
fetchMock.mockImplementation(async (url, options) => {
|
||||||
axiosHeadMock.mockImplementation(async (url, config) => {
|
if (options.method === 'HEAD') {
|
||||||
validateRequestConfig(404, url, config)
|
// Simulate none of the blobs existing currently
|
||||||
return {
|
validateRequestConfig(url, options)
|
||||||
status: 404
|
return Promise.resolve({
|
||||||
}
|
status: 404
|
||||||
})
|
})
|
||||||
|
} else if (options.method === 'POST') {
|
||||||
// Simulate failed initiation of uploads
|
// Simulate failed initiation of uploads
|
||||||
axiosPostMock.mockImplementation(async (url, data, config) => {
|
return Promise.resolve({
|
||||||
validateRequestConfig(503, url, config)
|
status: 503
|
||||||
return {
|
})
|
||||||
status: 503
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -321,20 +354,21 @@ describe('publishOCIArtifact', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('throws an error if the upload endpoint does not return a location', async () => {
|
it('throws an error if the upload endpoint does not return a location', async () => {
|
||||||
// Simulate none of the blobs existing currently
|
fetchMock.mockImplementation(async (url, options) => {
|
||||||
axiosHeadMock.mockImplementation(async (url, config) => {
|
validateRequestConfig(url, options)
|
||||||
validateRequestConfig(404, url, config)
|
if (options.method === 'HEAD') {
|
||||||
return {
|
// Simulate none of the blobs existing currently
|
||||||
status: 404
|
return Promise.resolve({
|
||||||
}
|
status: 404
|
||||||
})
|
})
|
||||||
|
} else if (options.method === 'POST') {
|
||||||
// Simulate successful response code but no location header
|
// Simulate successful response code but no location header
|
||||||
axiosPostMock.mockImplementation(async (url, data, config) => {
|
return Promise.resolve({
|
||||||
validateRequestConfig(202, url, config)
|
status: 202,
|
||||||
return {
|
headers: {
|
||||||
status: 202,
|
get: () => {}
|
||||||
headers: {}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -352,22 +386,32 @@ describe('publishOCIArtifact', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('throws an error if a layer upload fails', async () => {
|
it('throws an error if a layer upload fails', async () => {
|
||||||
// Simulate none of the blobs existing currently
|
fetchMock.mockImplementation(async (url, options) => {
|
||||||
axiosHeadMock.mockImplementation(async (url, config) => {
|
if (options.method === 'HEAD') {
|
||||||
validateRequestConfig(404, url, config)
|
validateRequestConfig(url, options)
|
||||||
return {
|
// Simulate none of the blobs existing currently
|
||||||
status: 404
|
return Promise.resolve({
|
||||||
}
|
status: 404
|
||||||
})
|
})
|
||||||
|
} else if (options.method === 'POST') {
|
||||||
// Simulate successful initiation of uploads for all blobs & return location
|
// Simulate successful initiation of uploads for all blobs & return location
|
||||||
axiosPostMock.mockImplementation(async (url, data, config) => {
|
validateRequestConfig(url, options)
|
||||||
validateRequestConfig(202, url, config)
|
return Promise.resolve({
|
||||||
return {
|
status: 202,
|
||||||
status: 202,
|
headers: {
|
||||||
headers: {
|
get: (header: string) => {
|
||||||
location: `https://ghcr.io/v2/${repository}/blobs/uploads/${genericSha}`
|
if (header === 'location') {
|
||||||
}
|
return `https://ghcr.io/v2/${repository}/blobs/uploads/${genericSha}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (options.method === 'PUT') {
|
||||||
|
// Simulate fails upload of all blobs & manifest
|
||||||
|
validateRequestConfig(url, options)
|
||||||
|
return Promise.resolve({
|
||||||
|
status: 500
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -376,14 +420,6 @@ describe('publishOCIArtifact', () => {
|
|||||||
return Buffer.from('test')
|
return Buffer.from('test')
|
||||||
})
|
})
|
||||||
|
|
||||||
// Simulate fails upload of all blobs & manifest
|
|
||||||
axiosPutMock.mockImplementation(async (url, data, config) => {
|
|
||||||
validateRequestConfig(500, url, config)
|
|
||||||
return {
|
|
||||||
status: 500
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
publishOCIArtifact(
|
publishOCIArtifact(
|
||||||
token,
|
token,
|
||||||
@@ -398,22 +434,37 @@ describe('publishOCIArtifact', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('throws an error if a manifest upload fails', async () => {
|
it('throws an error if a manifest upload fails', async () => {
|
||||||
// Simulate none of the blobs existing currently
|
fetchMock.mockImplementation(async (url, options) => {
|
||||||
axiosHeadMock.mockImplementation(async (url, config) => {
|
if (options.method === 'HEAD') {
|
||||||
validateRequestConfig(404, url, config)
|
// Simulate none of the blobs existing currently
|
||||||
return {
|
validateRequestConfig(url, options)
|
||||||
status: 404
|
return Promise.resolve({
|
||||||
}
|
status: 404
|
||||||
})
|
})
|
||||||
|
} else if (options.method === 'POST') {
|
||||||
// Simulate successful initiation of uploads for all blobs & return location
|
// Simulate successful initiation of uploads for all blobs & return location
|
||||||
axiosPostMock.mockImplementation(async (url, data, config) => {
|
validateRequestConfig(url, options)
|
||||||
validateRequestConfig(202, url, config)
|
return Promise.resolve({
|
||||||
return {
|
status: 202,
|
||||||
status: 202,
|
headers: {
|
||||||
headers: {
|
get: (header: string) => {
|
||||||
location: `https://ghcr.io/v2/${repository}/blobs/uploads/${genericSha}`
|
if (header === 'location') {
|
||||||
|
return `https://ghcr.io/v2/${repository}/blobs/uploads/${genericSha}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (options.method === 'PUT') {
|
||||||
|
// Simulate unsuccessful upload of all blobs & then the manifest
|
||||||
|
validateRequestConfig(url, options)
|
||||||
|
if (url.includes('manifest')) {
|
||||||
|
return Promise.resolve({
|
||||||
|
status: 500
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
return Promise.resolve({
|
||||||
|
status: 201
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -422,21 +473,6 @@ describe('publishOCIArtifact', () => {
|
|||||||
return Buffer.from('test')
|
return Buffer.from('test')
|
||||||
})
|
})
|
||||||
|
|
||||||
// Simulate successful upload of all blobs & then the manifest
|
|
||||||
axiosPutMock.mockImplementation(async (url, data, config) => {
|
|
||||||
if (url.includes('manifest')) {
|
|
||||||
validateRequestConfig(500, url, config)
|
|
||||||
return {
|
|
||||||
status: 500
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
validateRequestConfig(201, url, config)
|
|
||||||
return {
|
|
||||||
status: 201
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
publishOCIArtifact(
|
publishOCIArtifact(
|
||||||
token,
|
token,
|
||||||
@@ -451,22 +487,32 @@ describe('publishOCIArtifact', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('throws an error if reading one of the files fails', async () => {
|
it('throws an error if reading one of the files fails', async () => {
|
||||||
// Simulate none of the blobs existing currently
|
fetchMock.mockImplementation(async (url, options) => {
|
||||||
axiosHeadMock.mockImplementation(async (url, config) => {
|
if (options.method === 'HEAD') {
|
||||||
validateRequestConfig(404, url, config)
|
// Simulate none of the blobs existing currently
|
||||||
return {
|
validateRequestConfig(url, options)
|
||||||
status: 404
|
return Promise.resolve({
|
||||||
}
|
status: 404
|
||||||
})
|
})
|
||||||
|
} else if (options.method === 'POST') {
|
||||||
// Simulate successful initiation of uploads for all blobs & return location
|
// Simulate successful initiation of uploads for all blobs & return location
|
||||||
axiosPostMock.mockImplementation(async (url, data, config) => {
|
validateRequestConfig(url, options)
|
||||||
validateRequestConfig(202, url, config)
|
return Promise.resolve({
|
||||||
return {
|
status: 202,
|
||||||
status: 202,
|
headers: {
|
||||||
headers: {
|
get: (header: string) => {
|
||||||
location: `https://ghcr.io/v2/${repository}/blobs/uploads/${genericSha}`
|
if (header === 'location') {
|
||||||
}
|
return `https://ghcr.io/v2/${repository}/blobs/uploads/${genericSha}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (options.method === 'PUT') {
|
||||||
|
// Simulate successful upload of all blobs & then the manifest
|
||||||
|
validateRequestConfig(url, options)
|
||||||
|
return Promise.resolve({
|
||||||
|
status: 201
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -475,14 +521,6 @@ describe('publishOCIArtifact', () => {
|
|||||||
throw new Error('failed to read a file: test')
|
throw new Error('failed to read a file: test')
|
||||||
})
|
})
|
||||||
|
|
||||||
// Simulate successful upload of all blobs & then the manifest
|
|
||||||
axiosPutMock.mockImplementation(async (url, data, config) => {
|
|
||||||
validateRequestConfig(201, url, config)
|
|
||||||
return {
|
|
||||||
status: 201
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
publishOCIArtifact(
|
publishOCIArtifact(
|
||||||
token,
|
token,
|
||||||
@@ -520,10 +558,10 @@ describe('publishOCIArtifact', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// We expect all axios calls to have auth headers set and to not intercept any status codes so we can handle them.
|
// We expect all fetch calls to have auth headers set
|
||||||
// This function verifies that given an axios request config.
|
// This function verifies that given an request config.
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
function validateRequestConfig(status: number, url: string, config: any): void {
|
function validateRequestConfig(url: string, config: any): void {
|
||||||
// Basic URL checks
|
// Basic URL checks
|
||||||
expect(url).toBeDefined()
|
expect(url).toBeDefined()
|
||||||
if (!url.startsWith(registry.toString())) {
|
if (!url.startsWith(registry.toString())) {
|
||||||
@@ -536,12 +574,6 @@ function validateRequestConfig(status: number, url: string, config: any): void {
|
|||||||
// Config checks
|
// Config checks
|
||||||
expect(config).toBeDefined()
|
expect(config).toBeDefined()
|
||||||
|
|
||||||
expect(config.validateStatus).toBeDefined()
|
|
||||||
if (config.validateStatus) {
|
|
||||||
// Check axios will not intercept this status
|
|
||||||
expect(config.validateStatus(status)).toBe(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(config.headers).toBeDefined()
|
expect(config.headers).toBeDefined()
|
||||||
if (config.headers) {
|
if (config.headers) {
|
||||||
// Check the auth header is set
|
// Check the auth header is set
|
||||||
|
|||||||
Reference in New Issue
Block a user