Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions e2e/tests/api/features/importer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import { expect, test } from "../fixtures";

const BASE_IMPORTER_CONFIG = {
osv: {
disabled: true,
period: "1day",
description: "GitHub Advisory Database",
source: "https://github.com/matejnesuta/sample_advisories",
Comment thread
helio-frota marked this conversation as resolved.
path: "advisories",
},
};

test.describe("Importer CRUD operations", () => {
test("Create importer and verify it exists", async ({ axios }) => {
const importerName = "api-test-create-importer";

await axios
.delete(`/api/v3/importer/${importerName}`, {
validateStatus: () => true,
})
.catch(() => undefined);
Comment on lines +17 to +21

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): The initial cleanup deletes a fixed importer name and suppresses every failure, then creation proceeds; if deletion is rejected by authorization, unavailable due to a transient server error, or otherwise does not remove an existing importer, the subsequent POST fails with a conflict rather than establishing the test's clean fixture.

Triggers: When a stale importer with the fixed name exists and the cleanup DELETE does not actually succeed.

Suggested fix: Use unique names per run, or verify the cleanup response and fail explicitly when an existing fixture cannot be removed.


try {
const createResponse = await axios.post(
`/api/v3/importer/${importerName}`,
BASE_IMPORTER_CONFIG,
);
expect(createResponse.status).toBe(201);

const getResponse = await axios.get(`/api/v3/importer/${importerName}`);
expect(getResponse.status).toBe(200);
expect(getResponse.data.name).toBe(importerName);
expect(getResponse.data.configuration.osv.source).toBe(
BASE_IMPORTER_CONFIG.osv.source,
);
expect(getResponse.data.configuration.osv.disabled).toBe(true);
} finally {
await axios
.delete(`/api/v3/importer/${importerName}`)
.catch(() => undefined);
}
});

test("Edit importer using PATCH request", async ({ axios }) => {
const importerName = "api-test-patch-importer";

await axios
.delete(`/api/v3/importer/${importerName}`, {
validateStatus: () => true,
})
.catch(() => undefined);
await axios.post(`/api/v3/importer/${importerName}`, BASE_IMPORTER_CONFIG);

try {
const getResponse = await axios.get(`/api/v3/importer/${importerName}`);
const revision = getResponse.data.revision;

const patchResponse = await axios.patch(
`/api/v3/importer/${importerName}`,
{ osv: { description: "Updated description via PATCH" } },
{
headers: {
"Content-Type": "application/merge-patch+json",
"if-match": revision,
},
},
);
expect(patchResponse.status).toBe(204);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): These tests require PATCH, PUT, and DELETE to return 204, but the checked-in OpenAPI contract declares 201 for all three importer operations, so the tests fail against an implementation that follows the documented API even when the mutation succeeds.

Suggested fix: Align the assertions with the actual API contract, or update the API/OpenAPI contract if 204 is the intended response.


const verifyResponse = await axios.get(
`/api/v3/importer/${importerName}`,
);
expect(verifyResponse.data.configuration.osv.description).toBe(
"Updated description via PATCH",
);
expect(verifyResponse.data.configuration.osv.source).toBe(
BASE_IMPORTER_CONFIG.osv.source,
);
} finally {
await axios
.delete(`/api/v3/importer/${importerName}`)
.catch(() => undefined);
}
});

test("Edit importer using PUT request", async ({ axios }) => {
const importerName = "api-test-put-importer";

await axios
.delete(`/api/v3/importer/${importerName}`, {
validateStatus: () => true,
})
.catch(() => undefined);
await axios.post(`/api/v3/importer/${importerName}`, BASE_IMPORTER_CONFIG);

try {
const getResponse = await axios.get(`/api/v3/importer/${importerName}`);
const revision = getResponse.data.revision;

const updatedConfig = {
osv: {
...BASE_IMPORTER_CONFIG.osv,
description: "Updated description via PUT",
},
};

const putResponse = await axios.put(
`/api/v3/importer/${importerName}`,
updatedConfig,
{ headers: { "if-match": revision } },
);
expect(putResponse.status).toBe(204);

const verifyResponse = await axios.get(
`/api/v3/importer/${importerName}`,
);
expect(verifyResponse.data.configuration.osv.description).toBe(
"Updated description via PUT",
);
} finally {
await axios
.delete(`/api/v3/importer/${importerName}`)
.catch(() => undefined);
}
});

test("Delete importer and verify it is no longer present", async ({
axios,
}) => {
const importerName = "api-test-delete-importer";

await axios
.delete(`/api/v3/importer/${importerName}`, {
validateStatus: () => true,
})
.catch(() => undefined);
await axios.post(`/api/v3/importer/${importerName}`, BASE_IMPORTER_CONFIG);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): The delete test has no try/finally cleanup, so any failure after creation leaves api-test-delete-importer persisted in the environment; the next run's pre-delete hides the leftover state, but a failed run pollutes shared test data and can affect other consumers.

Triggers: When the creation or any assertion in the delete test fails before the explicit delete completes.

Suggested fix: Put the create/read/delete assertions in a try block and delete the importer in finally, as the create, PATCH, and PUT tests do.


const beforeDeleteResponse = await axios.get(
`/api/v3/importer/${importerName}`,
);
expect(beforeDeleteResponse.status).toBe(200);

const deleteResponse = await axios.delete(
`/api/v3/importer/${importerName}`,
);
expect(deleteResponse.status).toBe(204);

const notFoundResponse = await axios.get(
`/api/v3/importer/${importerName}`,
{ validateStatus: () => true },
);
expect(notFoundResponse.status).toBe(404);
});
});