mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-04 16:09:05 +00:00
test:pipeline-core-tests (#7404)
### **PR Type** Tests, Enhancement ___ ### **Description** - Introduce core pipeline Playwright test suite - Skip redundant pipeline tests in pipelines.spec.js - Increase CI workers count in config - Add helper functions for login and ingestion ___ ### **Changes diagram** ```mermaid flowchart LR CT["pipeline-core.spec.js"] PT["pipelines.spec.js"] PC["playwright.config.js"] CI["CI pipeline"] CT -- "adds core tests" --> CI PT -- "skip redundant tests" --> CI PC -- "increase CI workers" --> CI ``` ___ ### **Changes walkthrough** 📝 <table><thead><tr><th></th><th align="left">Relevant files</th></tr></thead><tbody><tr><td><strong>Tests</strong></td><td><table> <tr> <td> <details> <summary><strong>pipeline-core.spec.js</strong><dd><code>Add core pipeline UI tests</code> </dd></summary> <hr> tests/ui-testing/playwright-tests/pipeline-core.spec.js <li>Add new Playwright tests for core pipeline flows<br> <li> Implement helper functions: login, ingestion, exploration<br> <li> Test source-destination, function, and condition nodes<br> <li> Configure tests to run in parallel mode </details> </td> <td><a href="https://github.com/openobserve/openobserve/pull/7404/files#diff-e6249b045437e7f087b825dc0ee2d8ccebed0894d10c84b7bc9b12dca7a25754">+269/-0</a> </td> </tr> <tr> <td> <details> <summary><strong>pipelines.spec.js</strong><dd><code>Skip redundant pipeline tests</code> </dd></summary> <hr> tests/ui-testing/playwright-tests/pipelines.spec.js <li>Mark three pipeline tests as skipped<br> <li> Update tests: source & destination, function, condition flows<br> <li> Retain old tests but disable execution </details> </td> <td><a href="https://github.com/openobserve/openobserve/pull/7404/files#diff-9b48f5edc53f2413789549b189d4a80f134a320dd5beebf96d738069eb43033a">+3/-3</a> </td> </tr> </table></td></tr><tr><td><strong>Configuration changes</strong></td><td><table> <tr> <td> <details> <summary><strong>playwright.config.js</strong><dd><code>Increase CI workers count</code> </dd></summary> <hr> tests/ui-testing/playwright.config.js - Increase CI `workers` from 1 to 2 for parallel runs </details> </td> <td><a href="https://github.com/openobserve/openobserve/pull/7404/files#diff-91cb9615068914b2e4f5d66fcbed50d3e9771ea2d882f8e8048bbe54eab3c414">+1/-1</a> </td> </tr> </table></td></tr></tr></tbody></table> ___ > <details> <summary> Need help?</summary><li>Type <code>/help how to ...</code> in the comments thread for any questions about PR-Agent usage.</li><li>Check out the <a href="https://qodo-merge-docs.qodo.ai/usage-guide/">documentation</a> for more information.</li></details>
This commit is contained in:
@@ -143,7 +143,8 @@ jobs:
|
||||
"usersOrg.spec.js",
|
||||
"websocket.spec.js",
|
||||
"pipeline-dynamic.spec.js",
|
||||
"searchpartition.spec.js"
|
||||
"searchpartition.spec.js",
|
||||
"pipeline-core.spec.js"
|
||||
# "remotepipeline.spec.js",
|
||||
|
||||
]
|
||||
|
||||
@@ -0,0 +1,268 @@
|
||||
import { test, expect } from "./baseFixtures";
|
||||
import logData from "../../ui-testing/cypress/fixtures/log.json";
|
||||
import logsdata from "../../test-data/logs_data.json";
|
||||
import PipelinePage from "../pages/pipelinePage";
|
||||
import { LogsPage } from '../pages/logsPage.js';
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
|
||||
|
||||
const randomFunctionName = `Pipeline${Math.floor(Math.random() * 1000)}`;
|
||||
|
||||
async function login(page) {
|
||||
await page.goto(process.env["ZO_BASE_URL"]);
|
||||
if (await page.getByText('Login as internal user').isVisible()) {
|
||||
await page.getByText('Login as internal user').click();
|
||||
}
|
||||
await page.waitForTimeout(1000);
|
||||
await page
|
||||
.locator('[data-cy="login-user-id"]')
|
||||
.fill(process.env["ZO_ROOT_USER_EMAIL"]);
|
||||
await page.locator("label").filter({ hasText: "Password *" }).click();
|
||||
await page
|
||||
.locator('[data-cy="login-password"]')
|
||||
.fill(process.env["ZO_ROOT_USER_PASSWORD"]);
|
||||
await page.locator('[data-cy="login-sign-in"]').click();
|
||||
}
|
||||
|
||||
async function ingestion(page) {
|
||||
const orgId = process.env["ORGNAME"];
|
||||
const streamNames = ["e2e_automate", "e2e_automate1", "e2e_automate2", "e2e_automate3"];
|
||||
const basicAuthCredentials = Buffer.from(
|
||||
`${process.env["ZO_ROOT_USER_EMAIL"]}:${process.env["ZO_ROOT_USER_PASSWORD"]}`
|
||||
).toString('base64');
|
||||
|
||||
const headers = {
|
||||
"Authorization": `Basic ${basicAuthCredentials}`,
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
for (const streamName of streamNames) {
|
||||
const response = await page.evaluate(async ({ url, headers, orgId, streamName, logsdata }) => {
|
||||
const fetchResponse = await fetch(`${url}/api/${orgId}/${streamName}/_json`, {
|
||||
method: 'POST',
|
||||
headers: headers,
|
||||
body: JSON.stringify(logsdata)
|
||||
});
|
||||
return await fetchResponse.json();
|
||||
}, {
|
||||
url: process.env.INGESTION_URL,
|
||||
headers: headers,
|
||||
orgId: orgId,
|
||||
streamName: streamName,
|
||||
logsdata: logsdata
|
||||
});
|
||||
console.log(response);
|
||||
}
|
||||
}
|
||||
|
||||
async function exploreStreamAndNavigateToPipeline(page, streamName) {
|
||||
await page.locator('[data-test="menu-link-\\/streams-item"]').click();
|
||||
await page.waitForTimeout(1000);
|
||||
await page.locator('[data-test="log-stream-refresh-stats-btn"]').click();
|
||||
await page.waitForTimeout(1000);
|
||||
await page.getByPlaceholder('Search Stream').click();
|
||||
await page.getByPlaceholder('Search Stream').fill(streamName);
|
||||
await page.waitForTimeout(1000);
|
||||
await page.getByRole('button', { name: 'Explore' }).first().click();
|
||||
await page.locator('[data-test="log-table-column-1-_timestamp"] [data-test="table-row-expand-menu"]').click();
|
||||
await page.locator('[data-test="menu-link-\\/pipeline-item"]').click();
|
||||
}
|
||||
|
||||
async function exploreStreamAndInteractWithLogDetails(page, streamName) {
|
||||
await page.locator('[data-test="menu-link-\\/streams-item"]').click();
|
||||
await page.getByPlaceholder('Search Stream').click();
|
||||
await page.getByPlaceholder('Search Stream').fill(streamName);
|
||||
await page.waitForTimeout(1000);
|
||||
await page.getByRole('button', { name: 'Explore' }).first().click();
|
||||
await page.locator('[data-test="log-table-column-1-_timestamp"] [data-test="table-row-expand-menu"]').click();
|
||||
await page.locator('[data-test="log-expand-detail-key-a-text"]').click();
|
||||
await page.locator('[data-test="menu-link-\\/pipeline-item"]').click();
|
||||
}
|
||||
|
||||
async function applyQueryButton(page) {
|
||||
const search = page.waitForResponse(logData.applyQuery);
|
||||
await page.waitForTimeout(3000);
|
||||
await page.locator("[data-test='logs-search-bar-refresh-btn']").click({
|
||||
force: true,
|
||||
});
|
||||
await expect.poll(async () => (await search).status()).toBe(200);
|
||||
}
|
||||
|
||||
test.describe("Core Pipeline Tests", () => {
|
||||
let logsPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await login(page);
|
||||
logsPage = new LogsPage(page);
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
const orgId = process.env["ORGNAME"];
|
||||
const streamName = "e2e_automate";
|
||||
const basicAuthCredentials = Buffer.from(
|
||||
`${process.env["ZO_ROOT_USER_EMAIL"]}:${process.env["ZO_ROOT_USER_PASSWORD"]}`
|
||||
).toString("base64");
|
||||
|
||||
const headers = {
|
||||
Authorization: `Basic ${basicAuthCredentials}`,
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
|
||||
await ingestion(page);
|
||||
await page.goto(
|
||||
`${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}`
|
||||
);
|
||||
await logsPage.selectStreamAndStreamTypeForLogs("e2e_automate");
|
||||
await applyQueryButton(page);
|
||||
});
|
||||
|
||||
test("should add source & destination node and then delete the pipeline", async ({ page }) => {
|
||||
const pipelinePage = new PipelinePage(page);
|
||||
|
||||
await pipelinePage.openPipelineMenu();
|
||||
await page.waitForTimeout(1000);
|
||||
await pipelinePage.addPipeline();
|
||||
await pipelinePage.selectStream();
|
||||
await pipelinePage.dragStreamToTarget(pipelinePage.streamButton);
|
||||
await pipelinePage.selectLogs();
|
||||
|
||||
await pipelinePage.enterStreamName("e2e");
|
||||
await pipelinePage.enterStreamName("e2e_automate3");
|
||||
await page.waitForTimeout(2000);
|
||||
await page.getByRole("option", { name: "e2e_automate3", exact: true }).click();
|
||||
await pipelinePage.saveInputNodeStream();
|
||||
await page.waitForTimeout(3000);
|
||||
await page.locator("button").filter({ hasText: "delete" }).nth(1).click();
|
||||
await page.locator('[data-test="confirm-button"]').click();
|
||||
await page.locator("button").filter({ hasText: "edit" }).hover();
|
||||
await page.getByRole("img", { name: "Output Stream" }).click();
|
||||
await page.getByLabel("Stream Name *").click();
|
||||
await page.getByLabel("Stream Name *").fill("destination-node");
|
||||
await page.waitForTimeout(1000);
|
||||
await pipelinePage.clickInputNodeStreamSave();
|
||||
const pipelineName = `pipeline-${Math.random().toString(36).substring(7)}`;
|
||||
await pipelinePage.enterPipelineName(pipelineName);
|
||||
await pipelinePage.savePipeline();
|
||||
await ingestion(page);
|
||||
|
||||
await exploreStreamAndNavigateToPipeline(page, 'destination_node');
|
||||
await pipelinePage.searchPipeline(pipelineName);
|
||||
await page.waitForTimeout(1000);
|
||||
const deletePipelineButton = page.locator(
|
||||
`[data-test="pipeline-list-${pipelineName}-delete-pipeline"]`
|
||||
);
|
||||
await deletePipelineButton.waitFor({ state: "visible" });
|
||||
await deletePipelineButton.click();
|
||||
await pipelinePage.confirmDeletePipeline();
|
||||
await pipelinePage.verifyPipelineDeleted();
|
||||
});
|
||||
|
||||
test("should add source, function, destination and then delete pipeline", async ({ page }) => {
|
||||
const pipelinePage = new PipelinePage(page);
|
||||
|
||||
await pipelinePage.openPipelineMenu();
|
||||
await page.waitForTimeout(1000);
|
||||
await pipelinePage.addPipeline();
|
||||
await pipelinePage.selectStream();
|
||||
await pipelinePage.dragStreamToTarget(pipelinePage.streamButton);
|
||||
await pipelinePage.selectLogs();
|
||||
await pipelinePage.enterStreamName("e2e");
|
||||
await pipelinePage.enterStreamName("e2e_automate1");
|
||||
await page.waitForTimeout(2000);
|
||||
await page.getByRole("option", { name: "e2e_automate1", exact: true }).click();
|
||||
await pipelinePage.saveInputNodeStream();
|
||||
await page.waitForTimeout(2000);
|
||||
await page.locator("button").filter({ hasText: "delete" }).nth(1).click();
|
||||
await page.locator('[data-test="confirm-button"]').click();
|
||||
await page.locator("button").filter({ hasText: "edit" }).hover();
|
||||
await page.getByRole("img", { name: "Function", exact: true }).click();
|
||||
await pipelinePage.toggleCreateFunction();
|
||||
await pipelinePage.enterFunctionName(randomFunctionName);
|
||||
await page.locator('[data-test="logs-vrl-function-editor"]').locator(".view-lines").click();
|
||||
await page.keyboard.type(".a=41", { delay: 100 });
|
||||
await page.keyboard.press("Enter");
|
||||
await page.keyboard.type(".", { delay: 100 });
|
||||
await page.getByText("Note: The function will be").click();
|
||||
await page.getByText(".a=41 .");
|
||||
await page.waitForTimeout(1000);
|
||||
await pipelinePage.saveNewFunction();
|
||||
await page.waitForTimeout(3000);
|
||||
await pipelinePage.saveFunction();
|
||||
await page.waitForTimeout(3000);
|
||||
await page.getByRole("button", { name: randomFunctionName }).hover();
|
||||
await page.getByRole("img", { name: "Output Stream" }).click();
|
||||
await page.getByLabel("Stream Name *").click();
|
||||
await page.getByLabel("Stream Name *").fill("destination-node");
|
||||
await page.waitForTimeout(100);
|
||||
await pipelinePage.clickInputNodeStreamSave();
|
||||
const pipelineName = `pipeline-${Math.random().toString(36).substring(7)}`;
|
||||
await pipelinePage.enterPipelineName(pipelineName);
|
||||
await pipelinePage.savePipeline();
|
||||
await ingestion(page);
|
||||
|
||||
await exploreStreamAndInteractWithLogDetails(page, 'destination_node');
|
||||
await pipelinePage.searchPipeline(pipelineName);
|
||||
await page.waitForTimeout(1000);
|
||||
const deletePipelineButton = page.locator(
|
||||
`[data-test="pipeline-list-${pipelineName}-delete-pipeline"]`
|
||||
);
|
||||
await deletePipelineButton.waitFor({ state: "visible" });
|
||||
await deletePipelineButton.click();
|
||||
await pipelinePage.confirmDeletePipeline();
|
||||
await pipelinePage.verifyPipelineDeleted();
|
||||
});
|
||||
|
||||
test("should add source, condition & destination node and then delete the pipeline", async ({ page }) => {
|
||||
const pipelinePage = new PipelinePage(page);
|
||||
|
||||
await pipelinePage.openPipelineMenu();
|
||||
await page.waitForTimeout(1000);
|
||||
await pipelinePage.addPipeline();
|
||||
await pipelinePage.selectStream();
|
||||
await pipelinePage.dragStreamToTarget(pipelinePage.streamButton);
|
||||
await pipelinePage.selectLogs();
|
||||
|
||||
await pipelinePage.enterStreamName("e2e");
|
||||
await pipelinePage.enterStreamName("e2e_automate2");
|
||||
await page.waitForTimeout(2000);
|
||||
await page.getByRole("option", { name: "e2e_automate2", exact: true }).click();
|
||||
await pipelinePage.saveInputNodeStream();
|
||||
await page.waitForTimeout(2000);
|
||||
await page.locator("button").filter({ hasText: "delete" }).nth(1).click();
|
||||
await page.locator('[data-test="confirm-button"]').click();
|
||||
await page.locator("button").filter({ hasText: "edit" }).hover();
|
||||
await page.getByRole("img", { name: "Stream", exact: true }).click();
|
||||
await page.getByPlaceholder("Column").click();
|
||||
await page.getByPlaceholder("Column").fill("container_name");
|
||||
await page.getByRole("option", { name: "kubernetes_container_name" }).click();
|
||||
await page.locator(
|
||||
"div:nth-child(2) > div:nth-child(2) > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native"
|
||||
).click();
|
||||
await page.getByText("Contains", { exact: true }).click();
|
||||
await page.getByPlaceholder("Value").click();
|
||||
await page.getByPlaceholder("Value").fill("prometheus");
|
||||
await pipelinePage.saveCondition();
|
||||
await page.waitForTimeout(2000);
|
||||
await page.getByRole("button", { name: "kubernetes_container_name" }).hover();
|
||||
await page.getByRole("img", { name: "Output Stream" }).click();
|
||||
await page.getByLabel("Stream Name *").click();
|
||||
await page.getByLabel("Stream Name *").fill("destination-node");
|
||||
await page.waitForTimeout(1000);
|
||||
await pipelinePage.clickInputNodeStreamSave();
|
||||
const pipelineName = `pipeline-${Math.random().toString(36).substring(7)}`;
|
||||
await pipelinePage.enterPipelineName(pipelineName);
|
||||
await pipelinePage.savePipeline();
|
||||
await ingestion(page);
|
||||
|
||||
await exploreStreamAndNavigateToPipeline(page, 'destination_node');
|
||||
await page.waitForTimeout(1000);
|
||||
await pipelinePage.searchPipeline(pipelineName);
|
||||
await page.waitForTimeout(1000);
|
||||
const deletePipelineButton = page.locator(
|
||||
`[data-test="pipeline-list-${pipelineName}-delete-pipeline"]`
|
||||
);
|
||||
await deletePipelineButton.waitFor({ state: "visible" });
|
||||
await deletePipelineButton.click();
|
||||
await pipelinePage.confirmDeletePipeline();
|
||||
await pipelinePage.verifyPipelineDeleted();
|
||||
});
|
||||
});
|
||||
@@ -270,7 +270,7 @@ test.describe("Pipeline testcases", () => {
|
||||
await pipelinePage.confirmDelete();
|
||||
});
|
||||
|
||||
test("should add source & destination node and then delete the pipeline", async ({
|
||||
test.skip("should add source & destination node and then delete the pipeline", async ({
|
||||
page,
|
||||
}) => {
|
||||
const pipelinePage = new PipelinePage(page);
|
||||
@@ -378,7 +378,7 @@ test.describe("Pipeline testcases", () => {
|
||||
await pipelinePage.confirmDelete();
|
||||
});
|
||||
|
||||
test("should add source, function,destination and then delete pipeline", async ({
|
||||
test.skip("should add source, function,destination and then delete pipeline", async ({
|
||||
page,
|
||||
}) => {
|
||||
const pipelinePage = new PipelinePage(page);
|
||||
@@ -525,7 +525,7 @@ test.describe("Pipeline testcases", () => {
|
||||
await pipelinePage.assertStreamSelectionErrorVisible();
|
||||
});
|
||||
|
||||
test("should add source, condition & destination node and then delete the pipeline", async ({
|
||||
test.skip("should add source, condition & destination node and then delete the pipeline", async ({
|
||||
page,
|
||||
}) => {
|
||||
const pipelinePage = new PipelinePage(page);
|
||||
|
||||
@@ -21,7 +21,7 @@ module.exports = defineConfig({
|
||||
/* Retry on CI only */
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
/* Opt out of parallel tests on CI. */
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
workers: process.env.CI ? 2 : undefined,
|
||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||
reporter: 'html',
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
|
||||
Reference in New Issue
Block a user