Skip to content

Commit

Permalink
Merge pull request #120 from yashkohli88/yk/add-origins-tests
Browse files Browse the repository at this point in the history
Add Test Case for Origins API
  • Loading branch information
elrayle authored Jan 15, 2025
2 parents 223409b + b5defbf commit 4da865b
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 1 deletion.
2 changes: 1 addition & 1 deletion tools/integration/lib/fetch.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ async function fetchWithRetry(fetcher, retryOpts) {
const response = await withRetry(async () => {
const resp = await fetcher()
// retry on 5xx
if (resp.status >= 500) verifyResponse(resp)
if (resp?.status >= 500) verifyResponse(resp)
return resp
}, retryOpts)
return verifyResponse(response)
Expand Down
115 changes: 115 additions & 0 deletions tools/integration/test/integration/e2e-test-service/originsTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// (c) Copyright 2024, SAP SE and ClearlyDefined contributors. Licensed under the MIT license.
// SPDX-License-Identifier: MIT

const assert = require('assert')
const { callFetchWithRetry: callFetch } = require('../../../lib/fetch')
const { devApiBaseUrl, prodApiBaseUrl, getComponents, origins } = require('../testConfig')

const ORIGIN_EXCLUSION_LIST = ['go/golang', 'debsrc/debian', 'maven/mavengoogle']
const ORIGIN_REVISIONS_EXCLUSION_LIST = ['debsrc/debian']

const MAVEN_COMPONENT_GROUP_ID = 'maven/mavencentral/org.apache.httpcomponents'
const MAVEN_COMPONENT_PARTIAL_GROUP_ID = 'maven/mavencentral/org.apache.httpcompon'
const GRADLE_COMPONENT_ENDPOINT = 'gradleplugin/io.github.lognet.grpc-spring-boot'

;(async function validateOriginsApi() {
const components = await getComponents()

describe('Validate Origins API Between Dev and Prod', function () {
this.timeout(origins.timeout)

afterEach(() => new Promise(resolve => setTimeout(resolve, origins.timeout / 2)))

components.filter(isOriginAllowed).forEach(component => {
it(`Validates Origins API response for ${component}`, () => compareOrigins(component))
})

components.filter(isOriginWithRevisionsAllowed).forEach(component => {
it(`Validates Origins API response with revisions for ${component}`, () => compareOriginsWithRevisions(component))
})

it('Validates Origins API response for a Maven component with only a group ID', () =>
compareOrigins(MAVEN_COMPONENT_GROUP_ID))

it('Validates Origins API response for a Maven component with a partial group ID for suggestion checks', () =>
compareOrigins(MAVEN_COMPONENT_PARTIAL_GROUP_ID))

it('Validates Origins API response for a Gradle plugin component', () =>
compareEndpoints(GRADLE_COMPONENT_ENDPOINT))

it('Validates Origins API with revisions response for a Gradle plugin component', () =>
compareEndpoints(`${GRADLE_COMPONENT_ENDPOINT}/revisions`))
})
})()

function extractIds(response) {
return response.map(item => item.id)
}

function assertResponsesMatch(actual, expected) {
const sortedActualIds = extractIds(actual).sort()
const sortedExpectedIds = extractIds(expected).sort()

assert.deepStrictEqual(sortedActualIds, sortedExpectedIds)
}

function isCoordinateAllowed(coordinate, exclusionList) {
return !exclusionList.some(excluded => coordinate.includes(excluded))
}

function isOriginAllowed(coordinate) {
return isCoordinateAllowed(coordinate, ORIGIN_EXCLUSION_LIST)
}

function isOriginWithRevisionsAllowed(coordinate) {
return isCoordinateAllowed(coordinate, ORIGIN_REVISIONS_EXCLUSION_LIST)
}

function getProviderType(type, provider) {
switch (type) {
case 'git':
case 'gem':
return provider
case 'conda':
return `conda/${provider}`
case 'maven':
return provider === 'mavengoogle' ? provider : type
default:
return type
}
}

function parseCoordinates(coordinates) {
const [type, provider, namespaceOrEmpty, name, version] = coordinates.split('/')
const namespace = namespaceOrEmpty === '-' ? '' : namespaceOrEmpty
return { type, provider, namespace, name, version }
}

function buildCondaUrl(coordinates) {
const { type, provider, name } = parseCoordinates(coordinates)
return `${type}/${provider}/${name}`
}

function buildOriginUrl(coordinates) {
const { type, provider, namespace, name } = parseCoordinates(coordinates)
const resolvedType = getProviderType(type, provider)
return `${resolvedType}${namespace ? `/${namespace}` : ''}${name ? `/${name}` : ''}`
}

async function compareEndpoints(endpoint) {
const [devResponse, prodResponse] = await Promise.all([
callFetch(`${devApiBaseUrl}/origins/${endpoint}`).then(res => res.json()),
callFetch(`${prodApiBaseUrl}/origins/${endpoint}`).then(res => res.json())
])
assertResponsesMatch(devResponse, prodResponse)
}

async function compareOriginsWithRevisions(coordinates) {
const originUrl = buildOriginUrl(coordinates)
await compareEndpoints(`${originUrl}/revisions`)
}

async function compareOrigins(coordinates) {
const originUrl = coordinates.startsWith('conda/') ? buildCondaUrl(coordinates) : buildOriginUrl(coordinates)
await compareEndpoints(`${originUrl}`)
}
3 changes: 3 additions & 0 deletions tools/integration/test/integration/testConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,5 +87,8 @@ module.exports = {
},
definition: {
timeout: 1000 * 60 // for each component
},
origins: {
timeout: 1000 * 60 * 2
}
}

0 comments on commit 4da865b

Please sign in to comment.