Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add E2E workflow #20

Merged
merged 10 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
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
54 changes: 54 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: E2E

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
tests:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Start Grafana
run: docker compose up -d grafana

- name: Wait Grafana Started
run: sleep 5

- name: Create Engine Service Account
id: serviceAccount
run: |
source ./test/generate-token.sh
echo "grafana-token=${GRAFANA_TOKEN}" >> $GITHUB_OUTPUT

- name: Insert env variables
run: echo "GRAFANA_TOKEN=${{ steps.serviceAccount.outputs.grafana-token }}" >> .env

- name: Start Platform
run: docker compose up -d

- name: Run e2e tests
run: cp .env test && docker compose -f test/docker-compose.yml build && docker compose -f test/docker-compose.yml up --exit-code-from test

- name: Stop Platform
run: docker compose down

- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: test/playwright-report/
retention-days: 30
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
### Features / Enhancements

- Updated Business Intelligence 1.8.0 (#18)
- Updated Business Intelligence 2.0.0 (#12)
- Updated Business Intelligence 2.0.0 (#19)
- Add E2E workflow (#20)
- [Manager] Removed create annotations metric and replace calculation to execution (#131)
- [Manager] Added evaluation apply mode (#132)
- [Manager] Added percentage of values evaluation (#133)
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Business Intelligence

![Grafana](https://img.shields.io/badge/Grafana-11.2-orange)
![E2E](https://github.com/volkovlabs/business-intelligence/workflows/E2E/badge.svg)

## Introduction

The Business Intelligence provides an accessible platform for business users.
Expand All @@ -14,7 +17,7 @@ The Business Intelligence provides an accessible platform for business users.
## Highlights

- Manage alerts based on panel queries with thresholds with Business Alerting
- High performance Business Engine with HA support
- High performance Business Engine with HA

## Includes

Expand Down
3 changes: 0 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ services:
ports:
- 3000:3000
volumes:
- ./grafana:/var/lib/grafana
- ./volkovlabs-manager-app:/var/lib/grafana/plugins/volkovlabs-manager-app
- ./provisioning:/etc/grafana/provisioning

Expand All @@ -16,8 +15,6 @@ services:
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
volumes:
- ./database:/var/lib/postgresql/data

engine:
depends_on:
Expand Down
Binary file modified img/unscripted-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions test/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Get the latest version of Playwright
FROM mcr.microsoft.com/playwright:focal

# Set the work directory for the application
WORKDIR app

# COPY the needed files to the app folder in Docker image
COPY playwright.config.ts .

# Install the dependencies in Node environment
RUN npm install @grafana/plugin-e2e

# Install browsers
RUN npx playwright install --with-deps chromium

# Run tests
CMD ["npx", "playwright", "test"]
8 changes: 8 additions & 0 deletions test/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
services:
test:
build:
context: .
env_file: .env
volumes:
- ./playwright-report:/app/playwright-report
network_mode: host
21 changes: 21 additions & 0 deletions test/general.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { test, expect } from "@grafana/plugin-e2e";
import { EngineServerHelper } from "./utils";

test.describe("General", () => {
test("Check grafana version", async ({ grafanaVersion }) => {
console.log("Grafana version: ", grafanaVersion);
expect(grafanaVersion).toEqual(grafanaVersion);
});

test("Check engine health", async () => {
const engine = new EngineServerHelper();

await engine.checkHealth();
});

test("Check engine has access to grafana dashboard", async () => {
const engine = new EngineServerHelper();

await engine.checkDashboardAccess("bd0aabe4-3d2d-4d2e-a34d-d6260b06e10b");
});
});
19 changes: 19 additions & 0 deletions test/generate-token.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env bash

# Generate a new token
serviceAccount=$(curl -s -X POST -H "Content-Type: application/json" -d '{"name": "business-engine", "role": "Editor"}' http://admin:admin@localhost:3000/api/serviceaccounts)

echo "Service Account: $serviceAccount"

serviceAccountId=$(echo "$serviceAccount" | jq '.id')

echo "Request: http://admin:admin@localhost:3000/api/serviceaccounts/${serviceAccountId}/tokens"

# create the service account token with the service account id 1 - /serviceaccounts/{id} returned from the previous step
token=$(curl -s -X POST -H "Content-Type: application/json" -d '{"name": "engine"}' http://admin:admin@localhost:3000/api/serviceaccounts/${serviceAccountId}/tokens)

echo "Token: $token"

export GRAFANA_TOKEN=$(echo "$token" | jq '.key')
exec "$@"

73 changes: 73 additions & 0 deletions test/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { dirname } from "path";
import { defineConfig, devices } from "@playwright/test";

const pluginE2eAuth = `${dirname(require.resolve("@grafana/plugin-e2e"))}/auth`;

/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
/**
* Directory with tests
*/
testDir: "./",

/**
* Run tests in files in parallel
*/
fullyParallel: true,

/**
* Number of retry.
*/
retries: 6,

/**
* Number of workers.
*/
workers: 1,

/**
* Reporter to use. See https://playwright.dev/docs/test-reporters
*/
reporter: [["html", { open: "never" }]],

/**
* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions.
*/
use: {
/**
* Base URL to use in actions like `await page.goto('/')`.
*/
baseURL: process.env.E2E_GRAFANA_URL || "http://localhost:3000",

/**
* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer.
*/
trace: "on-first-retry",
},

/**
* Configure projects for major browsers
*/
projects: [
{
name: "auth",
testDir: pluginE2eAuth,
testMatch: [/.*\.js/],
},
{
name: "run-tests",
use: {
...devices["Desktop Chrome"],

/**
* @grafana/plugin-e2e writes the auth state to this file,
* the path should not be modified
*/
storageState: "playwright/.auth/admin.json",
},
dependencies: ["auth"],
},
],
});
1 change: 1 addition & 0 deletions test/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './server';
57 changes: 57 additions & 0 deletions test/utils/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { expect, request } from "@playwright/test";

/**
* Engine Server Helper
*/
export class EngineServerHelper {
private readonly url = process.env.E2E_ENGINE_URL || "http://localhost:3001";
private readonly token = process.env.ENGINE_TOKEN;

/**
* Request
*/
private async request<TResult>(
path: string,
options?: RequestInit
): Promise<TResult> {
try {
const context = await request.newContext({
baseURL: this.url,
});

const response = await context.fetch(`${this.url}${path}`, {
...options,
headers: {
Authorization: `Bearer ${this.token}`,
},
});

return (await response.json()) as TResult;
} catch (error) {
console.error("Request Error", error);
throw error;
}
}

/**
* Check Health
*/
public async checkHealth() {
const result = await this.request<{ message: "string" }>("/health");

return expect(result).toEqual({
message: "pong",
});
}

/**
* Check dashboard access
*/
public async checkDashboardAccess(id: string) {
const result = await this.request<{ uid: "string" }>(
`/grafana/dashboards/uid/${id}`
);

return expect(result.uid).toEqual(id);
}
}