import { tap, expect } from '@git.zone/tstest/tapbundle'; import { RegistryStorage } from '../ts/core/classes.registrystorage.js'; import { CargoRegistry } from '../ts/cargo/classes.cargoregistry.js'; import { AuthManager } from '../ts/core/classes.authmanager.js'; import { streamToJson } from '../ts/core/helpers.stream.js'; // Test index path calculation tap.test('should calculate correct index paths for different crate names', async () => { const storage = new RegistryStorage({ accessKey: 'test', accessSecret: 'test', endpoint: 's3.test.com', bucketName: 'test-bucket', }); // Access private method for testing const getPath = (storage as any).getCargoIndexPath.bind(storage); // 1-character names expect(getPath('a')).toEqual('cargo/index/1/a'); expect(getPath('z')).toEqual('cargo/index/1/z'); // 2-character names expect(getPath('io')).toEqual('cargo/index/2/io'); expect(getPath('ab')).toEqual('cargo/index/2/ab'); // 3-character names expect(getPath('axo')).toEqual('cargo/index/3/a/axo'); expect(getPath('foo')).toEqual('cargo/index/3/f/foo'); // 4+ character names expect(getPath('serde')).toEqual('cargo/index/se/rd/serde'); expect(getPath('tokio')).toEqual('cargo/index/to/ki/tokio'); expect(getPath('my-crate')).toEqual('cargo/index/my/--/my-crate'); }); // Test crate file path calculation tap.test('should calculate correct crate file paths', async () => { const storage = new RegistryStorage({ accessKey: 'test', accessSecret: 'test', endpoint: 's3.test.com', bucketName: 'test-bucket', }); // Access private method for testing const getPath = (storage as any).getCargoCratePath.bind(storage); expect(getPath('serde', '1.0.0')).toEqual('cargo/crates/serde/serde-1.0.0.crate'); expect(getPath('tokio', '1.28.0')).toEqual('cargo/crates/tokio/tokio-1.28.0.crate'); expect(getPath('my-crate', '0.1.0')).toEqual('cargo/crates/my-crate/my-crate-0.1.0.crate'); }); // Test crate name validation tap.test('should validate crate names correctly', async () => { const storage = new RegistryStorage({ accessKey: 'test', accessSecret: 'test', endpoint: 's3.test.com', bucketName: 'test-bucket', }); const authManager = new AuthManager({ jwtSecret: 'test-secret', tokenStore: 'memory', npmTokens: { enabled: true }, ociTokens: { enabled: false, realm: '', service: '' }, }); const registry = new CargoRegistry(storage, authManager, '/cargo', 'http://localhost:5000/cargo'); // Access private method for testing const validate = (registry as any).validateCrateName.bind(registry); // Valid names expect(validate('serde')).toBeTrue(); expect(validate('tokio')).toBeTrue(); expect(validate('my-crate')).toBeTrue(); expect(validate('my_crate')).toBeTrue(); expect(validate('crate123')).toBeTrue(); expect(validate('a')).toBeTrue(); // Invalid names (uppercase not allowed) expect(validate('Serde')).toBeFalse(); expect(validate('MyCreate')).toBeFalse(); // Invalid names (special characters) expect(validate('my.crate')).toBeFalse(); expect(validate('my@crate')).toBeFalse(); expect(validate('my crate')).toBeFalse(); // Invalid names (too long) const longName = 'a'.repeat(65); expect(validate(longName)).toBeFalse(); // Invalid names (empty) expect(validate('')).toBeFalse(); }); // Test config.json response tap.test('should return valid config.json', async () => { const storage = new RegistryStorage({ accessKey: 'test', accessSecret: 'test', endpoint: 's3.test.com', bucketName: 'test-bucket', }); const authManager = new AuthManager({ jwtSecret: 'test-secret', tokenStore: 'memory', npmTokens: { enabled: true }, ociTokens: { enabled: false, realm: '', service: '' }, }); const registry = new CargoRegistry(storage, authManager, '/cargo', 'http://localhost:5000/cargo'); const response = await registry.handleRequest({ method: 'GET', path: '/cargo/config.json', headers: {}, query: {}, }); expect(response.status).toEqual(200); expect(response.headers['Content-Type']).toEqual('application/json'); const body = await streamToJson(response.body); expect(body).toBeTypeOf('object'); expect(body.dl).toInclude('/api/v1/crates/{crate}/{version}/download'); expect(body.api).toEqual('http://localhost:5000/cargo'); }); export default tap.start();