import { expect, tap } from '@git.zone/tstest/tapbundle'; import { SmartRegistry } from '../ts/index.js'; import { createTestRegistry, createTestTokens, createTestPom, createTestJar, calculateMavenChecksums, } from './helpers/registry.js'; let registry: SmartRegistry; let mavenToken: string; let userId: string; // Test data const testGroupId = 'com.example.test'; const testArtifactId = 'test-artifact'; const testVersion = '1.0.0'; const testJarData = createTestJar(); const testPomData = Buffer.from( createTestPom(testGroupId, testArtifactId, testVersion), 'utf-8' ); tap.test('Maven: should create registry instance', async () => { registry = await createTestRegistry(); const tokens = await createTestTokens(registry); mavenToken = tokens.mavenToken; userId = tokens.userId; expect(registry).toBeInstanceOf(SmartRegistry); expect(mavenToken).toBeTypeOf('string'); // Clean up any existing metadata from previous test runs const storage = registry.getStorage(); try { await storage.deleteMavenMetadata(testGroupId, testArtifactId); } catch (error) { // Ignore error if metadata doesn't exist } }); tap.test('Maven: should upload POM file (PUT /{groupPath}/{artifactId}/{version}/*.pom)', async () => { const groupPath = testGroupId.replace(/\./g, '/'); const pomFilename = `${testArtifactId}-${testVersion}.pom`; const response = await registry.handleRequest({ method: 'PUT', path: `/maven/${groupPath}/${testArtifactId}/${testVersion}/${pomFilename}`, headers: { Authorization: `Bearer ${mavenToken}`, 'Content-Type': 'application/xml', }, query: {}, body: testPomData, }); expect(response.status).toEqual(201); }); tap.test('Maven: should upload JAR file (PUT /{groupPath}/{artifactId}/{version}/*.jar)', async () => { const groupPath = testGroupId.replace(/\./g, '/'); const jarFilename = `${testArtifactId}-${testVersion}.jar`; const response = await registry.handleRequest({ method: 'PUT', path: `/maven/${groupPath}/${testArtifactId}/${testVersion}/${jarFilename}`, headers: { Authorization: `Bearer ${mavenToken}`, 'Content-Type': 'application/java-archive', }, query: {}, body: testJarData, }); expect(response.status).toEqual(201); }); tap.test('Maven: should retrieve uploaded POM file (GET)', async () => { const groupPath = testGroupId.replace(/\./g, '/'); const pomFilename = `${testArtifactId}-${testVersion}.pom`; const response = await registry.handleRequest({ method: 'GET', path: `/maven/${groupPath}/${testArtifactId}/${testVersion}/${pomFilename}`, headers: {}, query: {}, }); expect(response.status).toEqual(200); expect(response.body).toBeInstanceOf(Buffer); expect((response.body as Buffer).toString('utf-8')).toContain(testGroupId); expect((response.body as Buffer).toString('utf-8')).toContain(testArtifactId); expect((response.body as Buffer).toString('utf-8')).toContain(testVersion); expect(response.headers['Content-Type']).toEqual('application/xml'); }); tap.test('Maven: should retrieve uploaded JAR file (GET)', async () => { const groupPath = testGroupId.replace(/\./g, '/'); const jarFilename = `${testArtifactId}-${testVersion}.jar`; const response = await registry.handleRequest({ method: 'GET', path: `/maven/${groupPath}/${testArtifactId}/${testVersion}/${jarFilename}`, headers: {}, query: {}, }); expect(response.status).toEqual(200); expect(response.body).toBeInstanceOf(Buffer); expect(response.headers['Content-Type']).toEqual('application/java-archive'); }); tap.test('Maven: should retrieve MD5 checksum for JAR (GET *.jar.md5)', async () => { const groupPath = testGroupId.replace(/\./g, '/'); const jarFilename = `${testArtifactId}-${testVersion}.jar`; const checksums = calculateMavenChecksums(testJarData); const response = await registry.handleRequest({ method: 'GET', path: `/maven/${groupPath}/${testArtifactId}/${testVersion}/${jarFilename}.md5`, headers: {}, query: {}, }); expect(response.status).toEqual(200); expect(response.body).toBeInstanceOf(Buffer); expect((response.body as Buffer).toString('utf-8')).toEqual(checksums.md5); expect(response.headers['Content-Type']).toEqual('text/plain'); }); tap.test('Maven: should retrieve SHA1 checksum for JAR (GET *.jar.sha1)', async () => { const groupPath = testGroupId.replace(/\./g, '/'); const jarFilename = `${testArtifactId}-${testVersion}.jar`; const checksums = calculateMavenChecksums(testJarData); const response = await registry.handleRequest({ method: 'GET', path: `/maven/${groupPath}/${testArtifactId}/${testVersion}/${jarFilename}.sha1`, headers: {}, query: {}, }); expect(response.status).toEqual(200); expect(response.body).toBeInstanceOf(Buffer); expect((response.body as Buffer).toString('utf-8')).toEqual(checksums.sha1); expect(response.headers['Content-Type']).toEqual('text/plain'); }); tap.test('Maven: should retrieve SHA256 checksum for JAR (GET *.jar.sha256)', async () => { const groupPath = testGroupId.replace(/\./g, '/'); const jarFilename = `${testArtifactId}-${testVersion}.jar`; const checksums = calculateMavenChecksums(testJarData); const response = await registry.handleRequest({ method: 'GET', path: `/maven/${groupPath}/${testArtifactId}/${testVersion}/${jarFilename}.sha256`, headers: {}, query: {}, }); expect(response.status).toEqual(200); expect(response.body).toBeInstanceOf(Buffer); expect((response.body as Buffer).toString('utf-8')).toEqual(checksums.sha256); expect(response.headers['Content-Type']).toEqual('text/plain'); }); tap.test('Maven: should retrieve SHA512 checksum for JAR (GET *.jar.sha512)', async () => { const groupPath = testGroupId.replace(/\./g, '/'); const jarFilename = `${testArtifactId}-${testVersion}.jar`; const checksums = calculateMavenChecksums(testJarData); const response = await registry.handleRequest({ method: 'GET', path: `/maven/${groupPath}/${testArtifactId}/${testVersion}/${jarFilename}.sha512`, headers: {}, query: {}, }); expect(response.status).toEqual(200); expect(response.body).toBeInstanceOf(Buffer); expect((response.body as Buffer).toString('utf-8')).toEqual(checksums.sha512); expect(response.headers['Content-Type']).toEqual('text/plain'); }); tap.test('Maven: should retrieve maven-metadata.xml (GET)', async () => { const groupPath = testGroupId.replace(/\./g, '/'); const response = await registry.handleRequest({ method: 'GET', path: `/maven/${groupPath}/${testArtifactId}/maven-metadata.xml`, headers: {}, query: {}, }); expect(response.status).toEqual(200); expect(response.body).toBeInstanceOf(Buffer); const xml = (response.body as Buffer).toString('utf-8'); expect(xml).toContain(''); expect(xml).toContain(''); expect(xml).toContain('1.0.0'); expect(xml).toContain('1.0.0'); expect(xml).toContain('1.0.0'); expect(response.headers['Content-Type']).toEqual('application/xml'); }); tap.test('Maven: should upload a second version and update metadata', async () => { const groupPath = testGroupId.replace(/\./g, '/'); const newVersion = '2.0.0'; const pomFilename = `${testArtifactId}-${newVersion}.pom`; const jarFilename = `${testArtifactId}-${newVersion}.jar`; const newPomData = Buffer.from( createTestPom(testGroupId, testArtifactId, newVersion), 'utf-8' ); // Upload POM await registry.handleRequest({ method: 'PUT', path: `/maven/${groupPath}/${testArtifactId}/${newVersion}/${pomFilename}`, headers: { Authorization: `Bearer ${mavenToken}`, 'Content-Type': 'application/xml', }, query: {}, body: newPomData, }); // Upload JAR await registry.handleRequest({ method: 'PUT', path: `/maven/${groupPath}/${testArtifactId}/${newVersion}/${jarFilename}`, headers: { Authorization: `Bearer ${mavenToken}`, 'Content-Type': 'application/java-archive', }, query: {}, body: testJarData, }); // Retrieve metadata and verify both versions are present const response = await registry.handleRequest({ method: 'GET', path: `/maven/${groupPath}/${testArtifactId}/maven-metadata.xml`, headers: {}, query: {}, }); expect(response.status).toEqual(200); const xml = (response.body as Buffer).toString('utf-8'); expect(xml).toContain('1.0.0'); expect(xml).toContain('2.0.0'); expect(xml).toContain('2.0.0'); expect(xml).toContain('2.0.0'); }); tap.test('Maven: should upload WAR file with correct content type', async () => { const groupPath = testGroupId.replace(/\./g, '/'); const warVersion = '1.0.0-war'; const warFilename = `${testArtifactId}-${warVersion}.war`; const warData = Buffer.from('fake war content', 'utf-8'); const response = await registry.handleRequest({ method: 'PUT', path: `/maven/${groupPath}/${testArtifactId}/${warVersion}/${warFilename}`, headers: { Authorization: `Bearer ${mavenToken}`, 'Content-Type': 'application/x-webarchive', }, query: {}, body: warData, }); expect(response.status).toEqual(201); }); tap.test('Maven: should return 404 for non-existent artifact', async () => { const groupPath = 'com/example/nonexistent'; const response = await registry.handleRequest({ method: 'GET', path: `/maven/${groupPath}/fake-artifact/1.0.0/fake-artifact-1.0.0.jar`, headers: {}, query: {}, }); expect(response.status).toEqual(404); expect(response.body).toHaveProperty('error'); }); tap.test('Maven: should return 401 for unauthorized upload', async () => { const groupPath = testGroupId.replace(/\./g, '/'); const jarFilename = `${testArtifactId}-3.0.0.jar`; const response = await registry.handleRequest({ method: 'PUT', path: `/maven/${groupPath}/${testArtifactId}/3.0.0/${jarFilename}`, headers: { // No authorization header 'Content-Type': 'application/java-archive', }, query: {}, body: testJarData, }); expect(response.status).toEqual(401); expect(response.body).toHaveProperty('error'); }); tap.test('Maven: should reject POM upload with mismatched GAV', async () => { const groupPath = 'com/mismatch/test'; const pomFilename = `different-artifact-1.0.0.pom`; // POM contains different GAV than the path const mismatchedPom = Buffer.from( createTestPom('com.other.group', 'other-artifact', '1.0.0'), 'utf-8' ); const response = await registry.handleRequest({ method: 'PUT', path: `/maven/${groupPath}/different-artifact/1.0.0/${pomFilename}`, headers: { Authorization: `Bearer ${mavenToken}`, 'Content-Type': 'application/xml', }, query: {}, body: mismatchedPom, }); expect(response.status).toEqual(400); expect(response.body).toHaveProperty('error'); }); tap.test('Maven: should delete an artifact (DELETE)', async () => { const groupPath = testGroupId.replace(/\./g, '/'); const jarFilename = `${testArtifactId}-${testVersion}.jar`; const response = await registry.handleRequest({ method: 'DELETE', path: `/maven/${groupPath}/${testArtifactId}/${testVersion}/${jarFilename}`, headers: { Authorization: `Bearer ${mavenToken}`, }, query: {}, }); expect(response.status).toEqual(204); // 204 No Content is correct for DELETE // Verify artifact was deleted const getResponse = await registry.handleRequest({ method: 'GET', path: `/maven/${groupPath}/${testArtifactId}/${testVersion}/${jarFilename}`, headers: {}, query: {}, }); expect(getResponse.status).toEqual(404); }); tap.test('Maven: should return 404 for checksum of deleted artifact', async () => { const groupPath = testGroupId.replace(/\./g, '/'); const jarFilename = `${testArtifactId}-${testVersion}.jar`; const response = await registry.handleRequest({ method: 'GET', path: `/maven/${groupPath}/${testArtifactId}/${testVersion}/${jarFilename}.md5`, headers: {}, query: {}, }); expect(response.status).toEqual(404); }); tap.postTask('cleanup registry', async () => { if (registry) { registry.destroy(); } }); export default tap.start();