From 1b7664da7b6c3d8228600762d4ee0616f06c47d7 Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Sun, 10 Mar 2024 19:46:24 +0100 Subject: [PATCH] ci: e2e testing --- .github/workflows/main.yml | 117 +++++++++++++++++- .../service/ReportProcessingServiceTest.java | 2 +- .../rest/K6ReportIngressApiResourceTest.java | 13 +- cli/src/main.rs | 1 - settings.gradle | 3 +- src/test/k6/.gitignore | 1 + src/test/k6/script.js | 2 +- 7 files changed, 121 insertions(+), 18 deletions(-) create mode 100644 src/test/k6/.gitignore diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index aec1905..8dc1010 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,7 +2,6 @@ name: Application CI on: push: branches: - - '!main' concurrency: group: application-ci-${{ github.ref }} cancel-in-progress: true @@ -26,15 +25,125 @@ jobs: distribution: 'temurin' java-version: 21 - name: Build & Test - run: ./gradlew :apps:k6-report-ingress:build + run: ./gradlew --no-daemon :apps:k6-report-ingress:build + - uses: actions/upload-artifact@v4 + with: + name: k6-report-ingress + path: apps/k6-report-ingress/build/libs/*.jar cli: - name: 'cli' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: 21 + - name: Generate Client + run: ./gradlew --no-daemon :cli:openApiGenerateClient - name: Build working-directory: cli run: cargo build --verbose - - name: Run tests + - name: Test working-directory: cli run: cargo test --verbose + - uses: actions/upload-artifact@v4 + with: + name: cli + path: cli/target/debug/cli + integration-test: + runs-on: ubuntu-latest + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + needs: + - k6-report-ingress + - cli + env: + POSTGRES_PASSWORD: KrPPCHdYSXz6wMct5tUK + POSTGRES_USER: k6_dashboard + POSTGRES_DB: k6_dashboard + services: + timescaledb: + image: timescale/timescaledb:latest-pg16 + ports: + - 5432:5432 + env: + POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }} + POSTGRES_USER: ${{ env.POSTGRES_USER }} + POSTGRES_DB: ${{ env.POSTGRES_DB }} + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + with: + path: build/artifacts + - name: Create additional database + run: | + PGPASSWORD=${{ env.POSTGRES_PASSWORD }} psql -h localhost -U ${{ env.POSTGRES_USER }} -d ${{ env.POSTGRES_DB }} -c "CREATE DATABASE k6_output;" + - name: Run K6 Tests and Post Report + run: | + docker run --network host -e TIMESCALEDB_JDBC_URL=postgresql://${{ env.POSTGRES_USER }}:${{ env.POSTGRES_PASSWORD }}@localhost:5432/k6_output --name k6 -v ${{ github.workspace }}/src/test/k6:/scripts -v ${{ github.workspace }}/dev/k6:/mountpoint golang:alpine3.19 /mountpoint/entrypoint.sh + docker cp k6:/go/report.json ${{ github.workspace }}/src/test/k6/report.json + - name: Set up JDK 11 + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '21' + - name: Migrate Database + run: ./gradlew :apps:k6-report-ingress:flywayMigrate + - name: Start Application and Upload JSON Report + timeout-minutes: 5 + run: | + # Start the application in the background + java -jar "$(find build/artifacts -type f -name '*.jar' -not -name '*-plain.jar')" & + APP_PID=$! + + # Wait for the application to be ready + echo "Waiting for application to start..." + while ! nc -z localhost 8080; do + sleep 1 # wait for 1 second before check again + done + + echo "Application started. Uploading JSON Report..." + + # Upload the JSON report + chmod 755 build/artifacts/cli/cli + build/artifacts/cli/cli upload -u http://localhost:8080 ${{ github.workspace }}/src/test/k6/report.json || exit 1 + + echo "Uploading done. Waiting for processing to finish..." + + # Wait until processing finished + count=1 + while [ $count -ne 0 ]; do + sleep 5 + echo "Processing not done yet. Retrying..." + output=$(docker run --rm --network host -e PGPASSWORD=${{ env.POSTGRES_PASSWORD }} postgres:16.2-alpine psql -h localhost -U ${{ env.POSTGRES_USER }} -d ${{ env.POSTGRES_DB }} -c "select count(*) from report_processing where processing_status != 1;") + count=$(echo "$output" | grep -Eo '[0-9]+' | head -n 1) + done + + echo "Done." + + # Optionally, you might want to gracefully shut down your application + kill $APP_PID + env: + SPRING_DATASOURCE_URL: jdbc:postgresql://localhost:5432/${{ env.POSTGRES_DB }} + SPRING_DATASOURCE_USERNAME: ${{ env.POSTGRES_USER }} + SPRING_DATASOURCE_PASSWORD: ${{ env.POSTGRES_PASSWORD }} + SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE: 1GB + - name: Create Database Dumps + run: | + mkdir -p build/artifacts/database + + docker run --rm --network host -e PGPASSWORD=${{ env.POSTGRES_PASSWORD }} postgres:16.2-alpine psql -h localhost -U ${{ env.POSTGRES_USER }} -d k6_output -c "COPY (SELECT date_trunc('milliseconds', ts), metric, tags, value FROM samples ORDER BY metric, ts) TO STDOUT WITH CSV HEADER;" > build/artifacts/database/k6_output.csv + cat build/artifacts/database/k6_output.csv | sort > build/artifacts/database/k6_output.csv + + docker run --rm --network host -e PGPASSWORD=${{ env.POSTGRES_PASSWORD }} postgres:16.2-alpine psql -h localhost -U ${{ env.POSTGRES_USER }} -d ${{ env.POSTGRES_DB }} -c "COPY (SELECT date_trunc('milliseconds', ts), metric, tags, value FROM samples ORDER BY metric, ts) TO STDOUT WITH CSV HEADER;" > build/artifacts/database/${{ env.POSTGRES_DB }}.csv + cat build/artifacts/database/${{ env.POSTGRES_DB }}.csv | sort > build/artifacts/database/${{ env.POSTGRES_DB }}.csv + - uses: actions/upload-artifact@v4 + with: + name: data + path: build/artifacts/database/*.csv + - name: Compare Tables + run: diff build/artifacts/database/k6_output.csv build/artifacts/database/${{ env.POSTGRES_DB }}.csv diff --git a/apps/k6-report-ingress/src/test/java/io/github/bbortt/k6/report/ingress/service/ReportProcessingServiceTest.java b/apps/k6-report-ingress/src/test/java/io/github/bbortt/k6/report/ingress/service/ReportProcessingServiceTest.java index 0b14c49..cdac834 100644 --- a/apps/k6-report-ingress/src/test/java/io/github/bbortt/k6/report/ingress/service/ReportProcessingServiceTest.java +++ b/apps/k6-report-ingress/src/test/java/io/github/bbortt/k6/report/ingress/service/ReportProcessingServiceTest.java @@ -48,7 +48,7 @@ void generateProcessingIdShouldReturnId() { var result = reportProcessingService.generateProcessingId(); assertThat(result) - .isEqualTo(PROCESSING_UUID); + .isEqualTo(reportProcessing); } @Test diff --git a/apps/k6-report-ingress/src/test/java/io/github/bbortt/k6/report/ingress/web/rest/K6ReportIngressApiResourceTest.java b/apps/k6-report-ingress/src/test/java/io/github/bbortt/k6/report/ingress/web/rest/K6ReportIngressApiResourceTest.java index 4a2f322..b6b7926 100644 --- a/apps/k6-report-ingress/src/test/java/io/github/bbortt/k6/report/ingress/web/rest/K6ReportIngressApiResourceTest.java +++ b/apps/k6-report-ingress/src/test/java/io/github/bbortt/k6/report/ingress/web/rest/K6ReportIngressApiResourceTest.java @@ -9,11 +9,10 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.multipart.MultipartFile; -import java.util.concurrent.CompletableFuture; +import java.util.UUID; import static io.github.bbortt.k6.report.ingress.web.rest.K6ReportIngressApiResource.PROCESSING_ID_HEADER_NAME; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.mockito.Mockito.doReturn; import static org.springframework.http.HttpStatus.ACCEPTED; @@ -35,10 +34,9 @@ void setUp() { @Test void uploadJSONReportRespondsDespiteBeingProcessedAsynchronously() { - var mockProcessingId = "mockId"; + var mockProcessingId = UUID.fromString("20c8fc34-934e-47ee-9f33-c6325e479d58"); - var processingFuture = new CompletableFuture<>(); - doReturn(processingFuture).when(k6ReportServiceMock).processFileAsync(reportFileMock); + doReturn(mockProcessingId).when(k6ReportServiceMock).processFileAsync(reportFileMock); ResponseEntity responseEntity = k6ReportIngressApiResource.uploadJSONReport(reportFileMock); @@ -50,10 +48,7 @@ void uploadJSONReportRespondsDespiteBeingProcessedAsynchronously() { r -> assertThat(r) .extracting(ResponseEntity::getHeaders) .extracting(header -> header.getFirst(PROCESSING_ID_HEADER_NAME)) - .isEqualTo(mockProcessingId) + .isEqualTo(mockProcessingId.toString()) ); - - assertFalse(processingFuture.isDone()); - processingFuture.complete(mockProcessingId); } } diff --git a/cli/src/main.rs b/cli/src/main.rs index f125be6..eef1689 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,7 +1,6 @@ use std::path::PathBuf; use clap::{Arg, Command}; -use futures::stream::TryStreamExt; use futures::TryFutureExt; use openapi::apis::{configuration, configuration::Configuration, Error, ResponseContent}; use openapi::apis::k6_report_ingress_api::UploadJsonReportError; diff --git a/settings.gradle b/settings.gradle index 8d702a6..9d5a1b0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,6 +2,7 @@ pluginManagement { repositories { gradlePluginPortal() maven { url "https://repo.spring.io/release" } + maven { url 'https://repo.spring.io/milestone' } } plugins { @@ -27,5 +28,3 @@ rootProject.name = "${rootProject.name}" include 'apps:k6-report-ingress', 'cli' -findProject(':apps:k6-report-ingress')?.name = 'k6-report-ingress' -findProject(':cli')?.name = 'k6-report-cli' diff --git a/src/test/k6/.gitignore b/src/test/k6/.gitignore new file mode 100644 index 0000000..1167acc --- /dev/null +++ b/src/test/k6/.gitignore @@ -0,0 +1 @@ +report.json diff --git a/src/test/k6/script.js b/src/test/k6/script.js index f8f1161..61d38b7 100644 --- a/src/test/k6/script.js +++ b/src/test/k6/script.js @@ -11,5 +11,5 @@ export const options = { }; export default function() { - http.get('https://test.k6.io'); + http.get('https://httpbin.test.k6.io/get'); }