import { expect, tap } from '@git.zone/tstest/tapbundle'; import { SmartRegistry } from '../ts/index.js'; import { createTestRegistry, createTestTokens, calculateDigest, createTestManifest } from './helpers/registry.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'); }); tap.postTask('cleanup registry', async () => { if (registry) { registry.destroy(); } }); export default tap.start();