Files
smartregistry/test/test.integration.pypi-rubygems.ts

289 lines
8.3 KiB
TypeScript
Raw Normal View History

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']).toEqual('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();