Files
smartregistry/test/test.oci.ts

298 lines
8.9 KiB
TypeScript

import { expect, tap } from '@git.zone/tstest/tapbundle';
import { SmartRegistry } from '../ts/index.js';
import { createTestRegistry, createTestTokens, calculateDigest, createTestManifest } from './test.helper.js';
let registry: SmartRegistry;
let ociToken: string;
let testBlobDigest: string;
let testConfigDigest: string;
let testManifestDigest: string;
// Test data
const testBlobData = Buffer.from('Hello from OCI test blob!', 'utf-8');
const testConfigData = Buffer.from(JSON.stringify({ arch: 'amd64', os: 'linux' }), 'utf-8');
tap.test('OCI: should create registry instance', async () => {
registry = await createTestRegistry();
const tokens = await createTestTokens(registry);
ociToken = tokens.ociToken;
expect(registry).toBeInstanceOf(SmartRegistry);
expect(ociToken).toBeTypeOf('string');
});
tap.test('OCI: should handle version check (GET /v2/)', async () => {
const response = await registry.handleRequest({
method: 'GET',
path: '/oci/v2/',
headers: {},
query: {},
});
expect(response.status).toEqual(200);
expect(response.headers['Docker-Distribution-API-Version']).toEqual('registry/2.0');
});
tap.test('OCI: should initiate blob upload (POST /v2/{name}/blobs/uploads/)', async () => {
const response = await registry.handleRequest({
method: 'POST',
path: '/oci/v2/test-repo/blobs/uploads/',
headers: {
Authorization: `Bearer ${ociToken}`,
},
query: {},
});
expect(response.status).toEqual(202);
expect(response.headers).toHaveProperty('Location');
expect(response.headers).toHaveProperty('Docker-Upload-UUID');
});
tap.test('OCI: should upload blob in single PUT', async () => {
testBlobDigest = calculateDigest(testBlobData);
const response = await registry.handleRequest({
method: 'POST',
path: '/oci/v2/test-repo/blobs/uploads/',
headers: {
Authorization: `Bearer ${ociToken}`,
},
query: {
digest: testBlobDigest,
},
body: testBlobData,
});
expect(response.status).toEqual(201);
expect(response.headers).toHaveProperty('Location');
expect(response.headers['Docker-Content-Digest']).toEqual(testBlobDigest);
});
tap.test('OCI: should upload config blob', async () => {
testConfigDigest = calculateDigest(testConfigData);
const response = await registry.handleRequest({
method: 'POST',
path: '/oci/v2/test-repo/blobs/uploads/',
headers: {
Authorization: `Bearer ${ociToken}`,
},
query: {
digest: testConfigDigest,
},
body: testConfigData,
});
expect(response.status).toEqual(201);
expect(response.headers['Docker-Content-Digest']).toEqual(testConfigDigest);
});
tap.test('OCI: should check if blob exists (HEAD /v2/{name}/blobs/{digest})', async () => {
const response = await registry.handleRequest({
method: 'HEAD',
path: `/oci/v2/test-repo/blobs/${testBlobDigest}`,
headers: {
Authorization: `Bearer ${ociToken}`,
},
query: {},
});
expect(response.status).toEqual(200);
expect(response.headers['Content-Length']).toEqual(testBlobData.length.toString());
expect(response.headers['Docker-Content-Digest']).toEqual(testBlobDigest);
});
tap.test('OCI: should retrieve blob (GET /v2/{name}/blobs/{digest})', async () => {
const response = await registry.handleRequest({
method: 'GET',
path: `/oci/v2/test-repo/blobs/${testBlobDigest}`,
headers: {
Authorization: `Bearer ${ociToken}`,
},
query: {},
});
expect(response.status).toEqual(200);
expect(response.body).toBeInstanceOf(Buffer);
expect((response.body as Buffer).toString('utf-8')).toEqual('Hello from OCI test blob!');
expect(response.headers['Docker-Content-Digest']).toEqual(testBlobDigest);
});
tap.test('OCI: should upload manifest (PUT /v2/{name}/manifests/{reference})', async () => {
const manifest = createTestManifest(testConfigDigest, testBlobDigest);
const manifestJson = JSON.stringify(manifest);
const manifestBuffer = Buffer.from(manifestJson, 'utf-8');
testManifestDigest = calculateDigest(manifestBuffer);
const response = await registry.handleRequest({
method: 'PUT',
path: '/oci/v2/test-repo/manifests/v1.0.0',
headers: {
Authorization: `Bearer ${ociToken}`,
'Content-Type': 'application/vnd.oci.image.manifest.v1+json',
},
query: {},
body: manifestBuffer,
});
expect(response.status).toEqual(201);
expect(response.headers).toHaveProperty('Location');
expect(response.headers['Docker-Content-Digest']).toMatch(/^sha256:[a-f0-9]{64}$/);
});
tap.test('OCI: should retrieve manifest by tag (GET /v2/{name}/manifests/{reference})', async () => {
const response = await registry.handleRequest({
method: 'GET',
path: '/oci/v2/test-repo/manifests/v1.0.0',
headers: {
Authorization: `Bearer ${ociToken}`,
Accept: 'application/vnd.oci.image.manifest.v1+json',
},
query: {},
});
expect(response.status).toEqual(200);
expect(response.body).toBeInstanceOf(Buffer);
const manifest = JSON.parse((response.body as Buffer).toString('utf-8'));
expect(manifest.schemaVersion).toEqual(2);
expect(manifest.config.digest).toEqual(testConfigDigest);
expect(manifest.layers[0].digest).toEqual(testBlobDigest);
});
tap.test('OCI: should retrieve manifest by digest (GET /v2/{name}/manifests/{digest})', async () => {
const response = await registry.handleRequest({
method: 'GET',
path: `/oci/v2/test-repo/manifests/${testManifestDigest}`,
headers: {
Authorization: `Bearer ${ociToken}`,
Accept: 'application/vnd.oci.image.manifest.v1+json',
},
query: {},
});
expect(response.status).toEqual(200);
expect(response.headers['Docker-Content-Digest']).toEqual(testManifestDigest);
});
tap.test('OCI: should check if manifest exists (HEAD /v2/{name}/manifests/{reference})', async () => {
const response = await registry.handleRequest({
method: 'HEAD',
path: '/oci/v2/test-repo/manifests/v1.0.0',
headers: {
Authorization: `Bearer ${ociToken}`,
Accept: 'application/vnd.oci.image.manifest.v1+json',
},
query: {},
});
expect(response.status).toEqual(200);
expect(response.headers['Docker-Content-Digest']).toMatch(/^sha256:[a-f0-9]{64}$/);
});
tap.test('OCI: should list tags (GET /v2/{name}/tags/list)', async () => {
const response = await registry.handleRequest({
method: 'GET',
path: '/oci/v2/test-repo/tags/list',
headers: {
Authorization: `Bearer ${ociToken}`,
},
query: {},
});
expect(response.status).toEqual(200);
expect(response.body).toHaveProperty('tags');
const tagList = response.body as any;
expect(tagList.name).toEqual('test-repo');
expect(tagList.tags).toBeInstanceOf(Array);
expect(tagList.tags).toContain('v1.0.0');
});
tap.test('OCI: should handle pagination for tag list', async () => {
const response = await registry.handleRequest({
method: 'GET',
path: '/oci/v2/test-repo/tags/list',
headers: {
Authorization: `Bearer ${ociToken}`,
},
query: {
n: '10',
},
});
expect(response.status).toEqual(200);
expect(response.body).toHaveProperty('tags');
});
tap.test('OCI: should return 404 for non-existent blob', async () => {
const response = await registry.handleRequest({
method: 'GET',
path: '/oci/v2/test-repo/blobs/sha256:0000000000000000000000000000000000000000000000000000000000000000',
headers: {
Authorization: `Bearer ${ociToken}`,
},
query: {},
});
expect(response.status).toEqual(404);
expect(response.body).toHaveProperty('errors');
});
tap.test('OCI: should return 404 for non-existent manifest', async () => {
const response = await registry.handleRequest({
method: 'GET',
path: '/oci/v2/test-repo/manifests/non-existent-tag',
headers: {
Authorization: `Bearer ${ociToken}`,
Accept: 'application/vnd.oci.image.manifest.v1+json',
},
query: {},
});
expect(response.status).toEqual(404);
expect(response.body).toHaveProperty('errors');
});
tap.test('OCI: should delete manifest (DELETE /v2/{name}/manifests/{digest})', async () => {
const response = await registry.handleRequest({
method: 'DELETE',
path: `/oci/v2/test-repo/manifests/${testManifestDigest}`,
headers: {
Authorization: `Bearer ${ociToken}`,
},
query: {},
});
expect(response.status).toEqual(202);
});
tap.test('OCI: should delete blob (DELETE /v2/{name}/blobs/{digest})', async () => {
const response = await registry.handleRequest({
method: 'DELETE',
path: `/oci/v2/test-repo/blobs/${testBlobDigest}`,
headers: {
Authorization: `Bearer ${ociToken}`,
},
query: {},
});
expect(response.status).toEqual(202);
});
tap.test('OCI: should handle unauthorized requests', async () => {
const response = await registry.handleRequest({
method: 'GET',
path: '/oci/v2/test-repo/manifests/v1.0.0',
headers: {
// No authorization header
},
query: {},
});
expect(response.status).toEqual(401);
expect(response.headers['WWW-Authenticate']).toInclude('Bearer');
});
export default tap.start();