import { expect, tap } from '@git.zone/tstest/tapbundle'; import { SmartRegistry } from '../ts/index.js'; import { createTestRegistry, createTestTokens, createPythonWheel, createRubyGem, } from './helpers/registry.js'; let registry: SmartRegistry; let pypiToken: string; let rubygemsToken: string; tap.test('Integration: should initialize registry with all protocols', async () => { registry = await createTestRegistry(); const tokens = await createTestTokens(registry); pypiToken = tokens.pypiToken; rubygemsToken = tokens.rubygemsToken; expect(registry).toBeInstanceOf(SmartRegistry); expect(registry.isInitialized()).toEqual(true); expect(pypiToken).toBeTypeOf('string'); expect(rubygemsToken).toBeTypeOf('string'); }); tap.test('Integration: should correctly route PyPI requests', async () => { const wheelData = await createPythonWheel('integration-test-py', '1.0.0'); const response = await registry.handleRequest({ method: 'POST', path: '/pypi/', headers: { Authorization: `Bearer ${pypiToken}`, 'Content-Type': 'multipart/form-data', }, query: {}, body: { ':action': 'file_upload', protocol_version: '1', name: 'integration-test-py', version: '1.0.0', filetype: 'bdist_wheel', pyversion: 'py3', metadata_version: '2.1', content: wheelData, filename: 'integration_test_py-1.0.0-py3-none-any.whl', }, }); expect(response.status).toEqual(201); }); tap.test('Integration: should correctly route RubyGems requests', async () => { const gemData = await createRubyGem('integration-test-gem', '1.0.0'); const response = await registry.handleRequest({ method: 'POST', path: '/rubygems/api/v1/gems', headers: { Authorization: rubygemsToken, 'Content-Type': 'application/octet-stream', }, query: {}, body: gemData, }); expect(response.status).toEqual(201); }); tap.test('Integration: should handle /simple path for PyPI', async () => { const response = await registry.handleRequest({ method: 'GET', path: '/simple/', headers: { Accept: 'text/html', }, query: {}, }); expect(response.status).toEqual(200); expect(response.headers['Content-Type']).toStartWith('text/html'); expect(response.body).toContain('integration-test-py'); }); tap.test('Integration: should reject PyPI token for RubyGems endpoint', async () => { const gemData = await createRubyGem('unauthorized-gem', '1.0.0'); const response = await registry.handleRequest({ method: 'POST', path: '/rubygems/api/v1/gems', headers: { Authorization: pypiToken, // Using PyPI token for RubyGems endpoint 'Content-Type': 'application/octet-stream', }, query: {}, body: gemData, }); expect(response.status).toEqual(401); }); tap.test('Integration: should reject RubyGems token for PyPI endpoint', async () => { const wheelData = await createPythonWheel('unauthorized-py', '1.0.0'); const response = await registry.handleRequest({ method: 'POST', path: '/pypi/', headers: { Authorization: `Bearer ${rubygemsToken}`, // Using RubyGems token for PyPI endpoint 'Content-Type': 'multipart/form-data', }, query: {}, body: { ':action': 'file_upload', protocol_version: '1', name: 'unauthorized-py', version: '1.0.0', filetype: 'bdist_wheel', pyversion: 'py3', metadata_version: '2.1', content: wheelData, filename: 'unauthorized_py-1.0.0-py3-none-any.whl', }, }); expect(response.status).toEqual(401); }); tap.test('Integration: should return 404 for unknown paths', async () => { const response = await registry.handleRequest({ method: 'GET', path: '/unknown-protocol/endpoint', headers: {}, query: {}, }); expect(response.status).toEqual(404); expect(response.body).toHaveProperty('error'); expect((response.body as any).error).toEqual('NOT_FOUND'); }); tap.test('Integration: should retrieve PyPI registry instance', async () => { const pypiRegistry = registry.getRegistry('pypi'); expect(pypiRegistry).toBeDefined(); expect(pypiRegistry).not.toBeNull(); }); tap.test('Integration: should retrieve RubyGems registry instance', async () => { const rubygemsRegistry = registry.getRegistry('rubygems'); expect(rubygemsRegistry).toBeDefined(); expect(rubygemsRegistry).not.toBeNull(); }); tap.test('Integration: should retrieve all other protocol instances', async () => { const ociRegistry = registry.getRegistry('oci'); const npmRegistry = registry.getRegistry('npm'); const mavenRegistry = registry.getRegistry('maven'); const composerRegistry = registry.getRegistry('composer'); const cargoRegistry = registry.getRegistry('cargo'); expect(ociRegistry).toBeDefined(); expect(npmRegistry).toBeDefined(); expect(mavenRegistry).toBeDefined(); expect(composerRegistry).toBeDefined(); expect(cargoRegistry).toBeDefined(); }); tap.test('Integration: should share storage across protocols', async () => { const storage = registry.getStorage(); expect(storage).toBeDefined(); // Verify storage has methods for all protocols expect(typeof storage.getPypiPackageMetadata).toEqual('function'); expect(typeof storage.getRubyGemsVersions).toEqual('function'); expect(typeof storage.getNpmPackument).toEqual('function'); expect(typeof storage.getOciBlob).toEqual('function'); }); tap.test('Integration: should share auth manager across protocols', async () => { const authManager = registry.getAuthManager(); expect(authManager).toBeDefined(); // Verify auth manager has methods for all protocols expect(typeof authManager.createPypiToken).toEqual('function'); expect(typeof authManager.createRubyGemsToken).toEqual('function'); expect(typeof authManager.createNpmToken).toEqual('function'); expect(typeof authManager.createOciToken).toEqual('function'); }); tap.test('Integration: should handle concurrent requests to different protocols', async () => { const pypiRequest = registry.handleRequest({ method: 'GET', path: '/simple/', headers: {}, query: {}, }); const rubygemsRequest = registry.handleRequest({ method: 'GET', path: '/rubygems/versions', headers: {}, query: {}, }); const [pypiResponse, rubygemsResponse] = await Promise.all([pypiRequest, rubygemsRequest]); expect(pypiResponse.status).toEqual(200); expect(rubygemsResponse.status).toEqual(200); }); tap.test('Integration: should handle package name conflicts across protocols', async () => { const packageName = 'conflict-test'; // Upload PyPI package const wheelData = await createPythonWheel(packageName, '1.0.0'); const pypiResponse = await registry.handleRequest({ method: 'POST', path: '/pypi/', headers: { Authorization: `Bearer ${pypiToken}`, 'Content-Type': 'multipart/form-data', }, query: {}, body: { ':action': 'file_upload', protocol_version: '1', name: packageName, version: '1.0.0', filetype: 'bdist_wheel', pyversion: 'py3', metadata_version: '2.1', content: wheelData, filename: `${packageName.replace(/-/g, '_')}-1.0.0-py3-none-any.whl`, }, }); expect(pypiResponse.status).toEqual(201); // Upload RubyGems package with same name const gemData = await createRubyGem(packageName, '1.0.0'); const rubygemsResponse = await registry.handleRequest({ method: 'POST', path: '/rubygems/api/v1/gems', headers: { Authorization: rubygemsToken, 'Content-Type': 'application/octet-stream', }, query: {}, body: gemData, }); expect(rubygemsResponse.status).toEqual(201); // Both should exist independently const pypiGetResponse = await registry.handleRequest({ method: 'GET', path: `/simple/${packageName}/`, headers: {}, query: {}, }); const rubygemsGetResponse = await registry.handleRequest({ method: 'GET', path: `/rubygems/gems/${packageName}-1.0.0.gem`, headers: {}, query: {}, }); expect(pypiGetResponse.status).toEqual(200); expect(rubygemsGetResponse.status).toEqual(200); }); tap.test('Integration: should properly clean up resources on destroy', async () => { // Destroy should clean up all registries expect(() => registry.destroy()).not.toThrow(); }); tap.postTask('cleanup registry', async () => { if (registry && registry.isInitialized()) { registry.destroy(); } }); export default tap.start();