From daa6bc46fe4b38bcc66a19f0a2765f474120dbfa Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 8 Feb 2026 18:38:09 +0100 Subject: [PATCH 01/18] changed test container to a maven container --- .gitea/workflows/test.yml | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index 4e187eb..b1cc2b0 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -14,19 +14,12 @@ jobs: test: runs-on: ubuntu-latest container: - image: catthehacker/ubuntu:act-latest + image: maven:3.9-eclipse-temurin-23 steps: - name: Checkout uses: actions/checkout@v4 - - name: Setup Java 23 - uses: actions/setup-java@v4 - with: - distribution: 'temurin' - java-version: '23' - cache: 'maven' - - name: Run Tests run: mvn verify -B --no-transfer-progress env: @@ -35,6 +28,7 @@ jobs: - name: Prepare Allure Results if: always() run: | + mkdir -p target/allure-results cat > target/allure-results/executor.json << EOF { "name": "Gitea Actions", @@ -48,19 +42,16 @@ jobs: - name: Upload to Allure if: always() run: | - # Projekt anlegen falls nicht vorhanden curl -s -o /dev/null \ -u admin:${{ secrets.ALLURE_PASSWORD }} \ -X POST "${ALLURE_SERVER}/allure-docker-service/projects" \ -H "Content-Type: application/json" \ -d '{"id": "'${ALLURE_PROJECT}'"}' || true - # Results aufräumen curl -s \ -u admin:${{ secrets.ALLURE_PASSWORD }} \ "${ALLURE_SERVER}/allure-docker-service/clean-results?project_id=${ALLURE_PROJECT}" - # Results hochladen for f in target/allure-results/*; do [ -f "$f" ] && curl -s \ -u admin:${{ secrets.ALLURE_PASSWORD }} \ @@ -68,7 +59,6 @@ jobs: -F "results[]=@$f" done - # Report generieren curl -s \ -u admin:${{ secrets.ALLURE_PASSWORD }} \ "${ALLURE_SERVER}/allure-docker-service/generate-report?project_id=${ALLURE_PROJECT}" \ No newline at end of file -- 2.45.3 From be231d1c9d705c5c4184baaf0c13f3232ea8835c Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 8 Feb 2026 18:44:38 +0100 Subject: [PATCH 02/18] fixed test.yml --- .gitea/workflows/test.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index b1cc2b0..a15646e 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -13,13 +13,18 @@ env: jobs: test: runs-on: ubuntu-latest - container: - image: maven:3.9-eclipse-temurin-23 steps: - name: Checkout uses: actions/checkout@v4 + - name: Setup Java 23 + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '23' + cache: 'maven' + - name: Run Tests run: mvn verify -B --no-transfer-progress env: -- 2.45.3 From b2af7a2718c7cdcafa6553e28a10d1f6a0ac5037 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 8 Feb 2026 18:50:48 +0100 Subject: [PATCH 03/18] fixed test.yml --- .gitea/workflows/test.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index a15646e..a07157f 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -25,6 +25,11 @@ jobs: java-version: '23' cache: 'maven' + - name: Install Maven + run: | + curl -fsSL https://dlcdn.apache.org/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.tar.gz | tar xz -C /opt + echo "/opt/apache-maven-3.9.9/bin" >> $GITHUB_PATH + - name: Run Tests run: mvn verify -B --no-transfer-progress env: -- 2.45.3 From 2832e28790d02df9f1faf4bae550d91f8848a143 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 8 Feb 2026 18:54:10 +0100 Subject: [PATCH 04/18] fixed test.yml --- .gitea/workflows/test.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index a07157f..d56b1b7 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -27,8 +27,7 @@ jobs: - name: Install Maven run: | - curl -fsSL https://dlcdn.apache.org/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.tar.gz | tar xz -C /opt - echo "/opt/apache-maven-3.9.9/bin" >> $GITHUB_PATH + apt-get update && apt-get install -y maven - name: Run Tests run: mvn verify -B --no-transfer-progress -- 2.45.3 From 65094b6cff0250e94bc135ce60e769c6bdd1c9c6 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 8 Feb 2026 19:20:53 +0100 Subject: [PATCH 05/18] fixed aspect j version in argline --- pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a861829..bcaf401 100644 --- a/pom.xml +++ b/pom.xml @@ -32,6 +32,7 @@ 5.20.0 11.18.0 analysis + 1.9.21 @@ -306,7 +307,7 @@ -javaagent:${settings.localRepository}/org/mockito/mockito-core/${mockito.version}/mockito-core-${mockito.version}.jar - -javaagent:${settings.localRepository}/org/aspectj/aspectjweaver/1.9.22/aspectjweaver-1.9.22.jar + -javaagent:${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar ${project.build.directory}/allure-results -- 2.45.3 From 1563be72607f6194af781549b01eaafa7a45fe46 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 8 Feb 2026 19:36:53 +0100 Subject: [PATCH 06/18] fixed test.yml and pom.xml (excludes controller tests) --- .gitea/workflows/test.yml | 52 ++++++++++++++++++++++----------------- pom.xml | 3 +++ 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index d56b1b7..db159a8 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -48,26 +48,32 @@ jobs: } EOF - - name: Upload to Allure - if: always() - run: | - curl -s -o /dev/null \ - -u admin:${{ secrets.ALLURE_PASSWORD }} \ - -X POST "${ALLURE_SERVER}/allure-docker-service/projects" \ - -H "Content-Type: application/json" \ - -d '{"id": "'${ALLURE_PROJECT}'"}' || true - - curl -s \ - -u admin:${{ secrets.ALLURE_PASSWORD }} \ - "${ALLURE_SERVER}/allure-docker-service/clean-results?project_id=${ALLURE_PROJECT}" - - for f in target/allure-results/*; do - [ -f "$f" ] && curl -s \ - -u admin:${{ secrets.ALLURE_PASSWORD }} \ - -X POST "${ALLURE_SERVER}/allure-docker-service/send-results?project_id=${ALLURE_PROJECT}" \ - -F "results[]=@$f" - done - - curl -s \ - -u admin:${{ secrets.ALLURE_PASSWORD }} \ - "${ALLURE_SERVER}/allure-docker-service/generate-report?project_id=${ALLURE_PROJECT}" \ No newline at end of file + - name: Upload to Allure + if: always() + run: | + # Login und Cookie speichern + curl -s -c cookies.txt \ + -X POST "${ALLURE_SERVER}/allure-docker-service/login" \ + -H "Content-Type: application/json" \ + -d '{"username":"admin","password":"${{ secrets.ALLURE_PASSWORD }}"}' + + # Create project + curl -s -o /dev/null -b cookies.txt \ + -X POST "${ALLURE_SERVER}/allure-docker-service/projects" \ + -H "Content-Type: application/json" \ + -d '{"id": "'${ALLURE_PROJECT}'"}' || true + + # Clean results + curl -s -b cookies.txt \ + "${ALLURE_SERVER}/allure-docker-service/clean-results?project_id=${ALLURE_PROJECT}" + + # Upload files + for f in target/allure-results/*; do + [ -f "$f" ] && curl -s -b cookies.txt \ + -X POST "${ALLURE_SERVER}/allure-docker-service/send-results?project_id=${ALLURE_PROJECT}" \ + -F "results[]=@$f" + done + + # Generate report + curl -s -b cookies.txt \ + "${ALLURE_SERVER}/allure-docker-service/generate-report?project_id=${ALLURE_PROJECT}" \ No newline at end of file diff --git a/pom.xml b/pom.xml index bcaf401..c3892d6 100644 --- a/pom.xml +++ b/pom.xml @@ -314,6 +314,9 @@ ${surefire.excludedGroups} + + **/controller/**/*Test.java + -- 2.45.3 From 448943dfe25cc40a21565259493b370d9d706545 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 8 Feb 2026 19:37:59 +0100 Subject: [PATCH 07/18] fixed indentation of test.yml --- .gitea/workflows/test.yml | 58 +++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index db159a8..86732b0 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -48,32 +48,32 @@ jobs: } EOF - - name: Upload to Allure - if: always() - run: | - # Login und Cookie speichern - curl -s -c cookies.txt \ - -X POST "${ALLURE_SERVER}/allure-docker-service/login" \ - -H "Content-Type: application/json" \ - -d '{"username":"admin","password":"${{ secrets.ALLURE_PASSWORD }}"}' - - # Create project - curl -s -o /dev/null -b cookies.txt \ - -X POST "${ALLURE_SERVER}/allure-docker-service/projects" \ - -H "Content-Type: application/json" \ - -d '{"id": "'${ALLURE_PROJECT}'"}' || true - - # Clean results - curl -s -b cookies.txt \ - "${ALLURE_SERVER}/allure-docker-service/clean-results?project_id=${ALLURE_PROJECT}" - - # Upload files - for f in target/allure-results/*; do - [ -f "$f" ] && curl -s -b cookies.txt \ - -X POST "${ALLURE_SERVER}/allure-docker-service/send-results?project_id=${ALLURE_PROJECT}" \ - -F "results[]=@$f" - done - - # Generate report - curl -s -b cookies.txt \ - "${ALLURE_SERVER}/allure-docker-service/generate-report?project_id=${ALLURE_PROJECT}" \ No newline at end of file + - name: Upload to Allure + if: always() + run: | + # Login und Cookie speichern + curl -s -c cookies.txt \ + -X POST "${ALLURE_SERVER}/allure-docker-service/login" \ + -H "Content-Type: application/json" \ + -d '{"username":"admin","password":"${{ secrets.ALLURE_PASSWORD }}"}' + + # Create project + curl -s -o /dev/null -b cookies.txt \ + -X POST "${ALLURE_SERVER}/allure-docker-service/projects" \ + -H "Content-Type: application/json" \ + -d '{"id": "'${ALLURE_PROJECT}'"}' || true + + # Clean results + curl -s -b cookies.txt \ + "${ALLURE_SERVER}/allure-docker-service/clean-results?project_id=${ALLURE_PROJECT}" + + # Upload files + for f in target/allure-results/*; do + [ -f "$f" ] && curl -s -b cookies.txt \ + -X POST "${ALLURE_SERVER}/allure-docker-service/send-results?project_id=${ALLURE_PROJECT}" \ + -F "results[]=@$f" + done + + # Generate report + curl -s -b cookies.txt \ + "${ALLURE_SERVER}/allure-docker-service/generate-report?project_id=${ALLURE_PROJECT}" \ No newline at end of file -- 2.45.3 From d2960bc8927045cc690be6f50235aa9e91eb9aae Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 8 Feb 2026 19:51:15 +0100 Subject: [PATCH 08/18] fixed csfr token for allure in test.yml --- .gitea/workflows/test.yml | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index 86732b0..510248a 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -51,29 +51,38 @@ jobs: - name: Upload to Allure if: always() run: | - # Login und Cookie speichern + # Login und Cookies speichern curl -s -c cookies.txt \ -X POST "${ALLURE_SERVER}/allure-docker-service/login" \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"${{ secrets.ALLURE_PASSWORD }}"}' - + + # CSRF Token aus Cookie extrahieren + CSRF_TOKEN=$(grep csrf_access_token cookies.txt | awk '{print $7}') + # Create project curl -s -o /dev/null -b cookies.txt \ + -H "X-CSRF-TOKEN: ${CSRF_TOKEN}" \ -X POST "${ALLURE_SERVER}/allure-docker-service/projects" \ -H "Content-Type: application/json" \ - -d '{"id": "'${ALLURE_PROJECT}'"}' || true - + -d '{"id":"'${ALLURE_PROJECT}'"}' || true + # Clean results - curl -s -b cookies.txt \ + curl -s -o /dev/null -b cookies.txt \ + -H "X-CSRF-TOKEN: ${CSRF_TOKEN}" \ "${ALLURE_SERVER}/allure-docker-service/clean-results?project_id=${ALLURE_PROJECT}" - + # Upload files for f in target/allure-results/*; do - [ -f "$f" ] && curl -s -b cookies.txt \ + [ -f "$f" ] && curl -s -o /dev/null -b cookies.txt \ + -H "X-CSRF-TOKEN: ${CSRF_TOKEN}" \ -X POST "${ALLURE_SERVER}/allure-docker-service/send-results?project_id=${ALLURE_PROJECT}" \ -F "results[]=@$f" done - + # Generate report curl -s -b cookies.txt \ - "${ALLURE_SERVER}/allure-docker-service/generate-report?project_id=${ALLURE_PROJECT}" \ No newline at end of file + -H "X-CSRF-TOKEN: ${CSRF_TOKEN}" \ + "${ALLURE_SERVER}/allure-docker-service/generate-report?project_id=${ALLURE_PROJECT}" + + echo "Allure upload complete" \ No newline at end of file -- 2.45.3 From 8f7b132dd4ee9b21df2255bfad0c1142593bf438 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 8 Feb 2026 20:08:08 +0100 Subject: [PATCH 09/18] added debug log to test execution --- .gitea/workflows/test.yml | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index 510248a..d6e1ad6 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -51,38 +51,47 @@ jobs: - name: Upload to Allure if: always() run: | - # Login und Cookies speichern + # Debug: Check if results exist + echo "=== Allure results directory ===" + ls -la target/allure-results/ || echo "Directory not found" + + # Login curl -s -c cookies.txt \ -X POST "${ALLURE_SERVER}/allure-docker-service/login" \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"${{ secrets.ALLURE_PASSWORD }}"}' - - # CSRF Token aus Cookie extrahieren + CSRF_TOKEN=$(grep csrf_access_token cookies.txt | awk '{print $7}') - + # Create project curl -s -o /dev/null -b cookies.txt \ -H "X-CSRF-TOKEN: ${CSRF_TOKEN}" \ -X POST "${ALLURE_SERVER}/allure-docker-service/projects" \ -H "Content-Type: application/json" \ -d '{"id":"'${ALLURE_PROJECT}'"}' || true - - # Clean results + + # Clean old results curl -s -o /dev/null -b cookies.txt \ -H "X-CSRF-TOKEN: ${CSRF_TOKEN}" \ "${ALLURE_SERVER}/allure-docker-service/clean-results?project_id=${ALLURE_PROJECT}" - - # Upload files + + # Upload files with debug + FILE_COUNT=0 for f in target/allure-results/*; do - [ -f "$f" ] && curl -s -o /dev/null -b cookies.txt \ - -H "X-CSRF-TOKEN: ${CSRF_TOKEN}" \ - -X POST "${ALLURE_SERVER}/allure-docker-service/send-results?project_id=${ALLURE_PROJECT}" \ - -F "results[]=@$f" + if [ -f "$f" ]; then + echo "Uploading: $f" + curl -s -o /dev/null -b cookies.txt \ + -H "X-CSRF-TOKEN: ${CSRF_TOKEN}" \ + -X POST "${ALLURE_SERVER}/allure-docker-service/send-results?project_id=${ALLURE_PROJECT}" \ + -F "results[]=@$f" + FILE_COUNT=$((FILE_COUNT + 1)) + fi done - + echo "Uploaded ${FILE_COUNT} files" + # Generate report curl -s -b cookies.txt \ -H "X-CSRF-TOKEN: ${CSRF_TOKEN}" \ "${ALLURE_SERVER}/allure-docker-service/generate-report?project_id=${ALLURE_PROJECT}" - echo "Allure upload complete" \ No newline at end of file + echo "✅ Allure upload complete" \ No newline at end of file -- 2.45.3 From 9b958696b4b36f287eb9fb9002fc19d9939ad3a4 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 8 Feb 2026 20:20:22 +0100 Subject: [PATCH 10/18] batch upload allure --- .gitea/workflows/test.yml | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index d6e1ad6..2823e0a 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -51,44 +51,39 @@ jobs: - name: Upload to Allure if: always() run: | - # Debug: Check if results exist - echo "=== Allure results directory ===" - ls -la target/allure-results/ || echo "Directory not found" - # Login curl -s -c cookies.txt \ -X POST "${ALLURE_SERVER}/allure-docker-service/login" \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"${{ secrets.ALLURE_PASSWORD }}"}' - + CSRF_TOKEN=$(grep csrf_access_token cookies.txt | awk '{print $7}') - + # Create project curl -s -o /dev/null -b cookies.txt \ -H "X-CSRF-TOKEN: ${CSRF_TOKEN}" \ -X POST "${ALLURE_SERVER}/allure-docker-service/projects" \ -H "Content-Type: application/json" \ -d '{"id":"'${ALLURE_PROJECT}'"}' || true - + # Clean old results curl -s -o /dev/null -b cookies.txt \ -H "X-CSRF-TOKEN: ${CSRF_TOKEN}" \ "${ALLURE_SERVER}/allure-docker-service/clean-results?project_id=${ALLURE_PROJECT}" - - # Upload files with debug - FILE_COUNT=0 + + # Upload ALL files in one request + FILES="" for f in target/allure-results/*; do - if [ -f "$f" ]; then - echo "Uploading: $f" - curl -s -o /dev/null -b cookies.txt \ - -H "X-CSRF-TOKEN: ${CSRF_TOKEN}" \ - -X POST "${ALLURE_SERVER}/allure-docker-service/send-results?project_id=${ALLURE_PROJECT}" \ - -F "results[]=@$f" - FILE_COUNT=$((FILE_COUNT + 1)) - fi + [ -f "$f" ] && FILES="$FILES -F results[]=@$f" done - echo "Uploaded ${FILE_COUNT} files" + curl -s -o /dev/null -b cookies.txt \ + -H "X-CSRF-TOKEN: ${CSRF_TOKEN}" \ + -X POST "${ALLURE_SERVER}/allure-docker-service/send-results?project_id=${ALLURE_PROJECT}" \ + $FILES + + echo "Uploaded files" + # Generate report curl -s -b cookies.txt \ -H "X-CSRF-TOKEN: ${CSRF_TOKEN}" \ -- 2.45.3 From 34df33bdea62eae7126d0ddb50c44e78250c7e00 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 8 Feb 2026 20:42:08 +0100 Subject: [PATCH 11/18] fixed allure again. --- .gitea/workflows/test.yml | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index 2823e0a..6bfb535 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -54,7 +54,7 @@ jobs: # Login curl -s -c cookies.txt \ -X POST "${ALLURE_SERVER}/allure-docker-service/login" \ - -H "Content-Type: application/json" \ + -H 'Content-Type: application/json' \ -d '{"username":"admin","password":"${{ secrets.ALLURE_PASSWORD }}"}' CSRF_TOKEN=$(grep csrf_access_token cookies.txt | awk '{print $7}') @@ -71,18 +71,29 @@ jobs: -H "X-CSRF-TOKEN: ${CSRF_TOKEN}" \ "${ALLURE_SERVER}/allure-docker-service/clean-results?project_id=${ALLURE_PROJECT}" - # Upload ALL files in one request - FILES="" + # Build JSON payload with base64 + echo '{"results":[' > payload.json + FIRST=true for f in target/allure-results/*; do - [ -f "$f" ] && FILES="$FILES -F results[]=@$f" + if [ -f "$f" ]; then + FILENAME=$(basename "$f") + CONTENT=$(base64 -w 0 "$f") + if [ "$FIRST" = true ]; then + FIRST=false + else + echo ',' >> payload.json + fi + echo '{"file_name":"'"$FILENAME"'","content_base64":"'"$CONTENT"'"}' >> payload.json + fi done - + echo ']}' >> payload.json + + # Upload via JSON curl -s -o /dev/null -b cookies.txt \ -H "X-CSRF-TOKEN: ${CSRF_TOKEN}" \ + -H "Content-Type: application/json" \ -X POST "${ALLURE_SERVER}/allure-docker-service/send-results?project_id=${ALLURE_PROJECT}" \ - $FILES - - echo "Uploaded files" + -d @payload.json # Generate report curl -s -b cookies.txt \ -- 2.45.3 From 2314892be471f9c105a6c05950103cc2d09d8d01 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 8 Feb 2026 20:44:48 +0100 Subject: [PATCH 12/18] use branch as project name --- .gitea/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index 6bfb535..55565fb 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -8,7 +8,7 @@ on: env: ALLURE_SERVER: "http://10.80.0.6:5050" - ALLURE_PROJECT: "lcc" + ALLURE_PROJECT: "lcc-${{ gitea.ref_name }}" jobs: test: -- 2.45.3 From 96d877d2ef682bb53b01d23f9956fba9cd1c5ce2 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 8 Feb 2026 21:28:55 +0100 Subject: [PATCH 13/18] added npm build to test.yml, reduced verbosity of jdbc in tests --- .gitea/workflows/test.yml | 8 ++++++++ src/test/resources/application-test.properties | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index 55565fb..eb971b9 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -29,6 +29,14 @@ jobs: run: | apt-get update && apt-get install -y maven + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Build Frontend + run: cd src/frontend && npm ci && BUILD_FOR_SPRING=true npm run build + - name: Run Tests run: mvn verify -B --no-transfer-progress env: diff --git a/src/test/resources/application-test.properties b/src/test/resources/application-test.properties index dfd0130..d72347d 100644 --- a/src/test/resources/application-test.properties +++ b/src/test/resources/application-test.properties @@ -55,7 +55,7 @@ spring.task.scheduling.enabled=false logging.level.org.flywaydb=INFO logging.level.org.testcontainers=INFO logging.level.de.avatic.lcc=DEBUG -logging.level.org.springframework.jdbc=DEBUG +#logging.level.org.springframework.jdbc=DEBUG -- 2.45.3 From 3af4b675ebe40826a8900f658ec9258d34acc829 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 8 Feb 2026 22:11:07 +0100 Subject: [PATCH 14/18] added playwright browsers to test.yml --- .gitea/workflows/test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index eb971b9..2a6c5d7 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -37,6 +37,9 @@ jobs: - name: Build Frontend run: cd src/frontend && npm ci && BUILD_FOR_SPRING=true npm run build + - name: Install Playwright Browsers + run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps chromium" + - name: Run Tests run: mvn verify -B --no-transfer-progress env: -- 2.45.3 From 2d8cbae7a546ab107240388866fc446fba279f2e Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 10 Feb 2026 09:17:10 +0100 Subject: [PATCH 15/18] added Allure annotations (Epic, Feature, Story) to integration tests --- CLAUDE.md | 51 +++++++++++++++ .../CalculationIntegrationTests.java | 6 ++ .../DestinationIntegrationTest.java | 14 ++++- .../PremiseControllerIntegrationTest.java | 41 ++++++++++++ .../PremiseControllerSetIntegrationTest.java | 10 +++ .../CountryControllerIntegrationTest.java | 21 +++++++ .../MaterialControllerIntegrationTest.java | 32 +++++++++- .../NodeControllerIntegrationTest.java | 33 +++++++++- .../PropertyControllerIntegrationTest.java | 18 +++++- ...RateControllerAdvancedIntegrationTest.java | 34 +++++++++- .../RateControllerIntegrationTest.java | 43 ++++++++++++- .../ReportingControllerIntegrationTest.java | 5 ++ .../dialect/MSSQLDialectProviderTest.java | 32 ++++++++++ .../dialect/MySQLDialectProviderTest.java | 32 +++++++++- .../e2e/tests/CalculationWorkflowE2ETest.java | 6 ++ .../e2e/tests/DeviationAnalysisE2ETest.java | 6 ++ .../de/avatic/lcc/e2e/tests/SmokeE2ETest.java | 10 +++ .../CountryRepositoryIntegrationTest.java | 28 +++++++++ .../DatabaseConfigurationSmokeTest.java | 20 ++++++ ...stanceMatrixRepositoryIntegrationTest.java | 24 +++++++ .../MaterialRepositoryIntegrationTest.java | 38 ++++++++++++ .../NodeRepositoryIntegrationTest.java | 22 +++++++ ...NomenclatureRepositoryIntegrationTest.java | 20 ++++++ ...ingDimensionRepositoryIntegrationTest.java | 20 ++++++ .../PackagingRepositoryIntegrationTest.java | 28 +++++++++ ...ulkOperationRepositoryIntegrationTest.java | 34 ++++++++++ ...bDestinationRepositoryIntegrationTest.java | 20 ++++++ ...lculationJobRepositoryIntegrationTest.java | 40 ++++++++++++ ...RouteSectionRepositoryIntegrationTest.java | 30 +++++++++ ...ntryPropertyRepositoryIntegrationTest.java | 22 +++++++ .../SysErrorRepositoryIntegrationTest.java | 24 +++++++ ...ngPropertiesRepositoryIntegrationTest.java | 34 ++++++++++ .../DestinationRepositoryIntegrationTest.java | 62 +++++++++++++++++++ .../PremiseRepositoryIntegrationTest.java | 48 ++++++++++++++ .../RouteNodeRepositoryIntegrationTest.java | 32 ++++++++++ .../RouteRepositoryIntegrationTest.java | 30 +++++++++ ...RouteSectionRepositoryIntegrationTest.java | 28 +++++++++ .../PropertyRepositoryIntegrationTest.java | 24 +++++++ .../PropertySetRepositoryIntegrationTest.java | 44 ++++++++++++- ...ontainerRateRepositoryIntegrationTest.java | 38 ++++++++++++ .../MatrixRateRepositoryIntegrationTest.java | 34 ++++++++++ ...lidityPeriodRepositoryIntegrationTest.java | 42 +++++++++++++ .../users/AppRepositoryIntegrationTest.java | 30 +++++++++ .../users/GroupRepositoryIntegrationTest.java | 30 +++++++++ .../UserNodeRepositoryIntegrationTest.java | 32 ++++++++++ .../users/UserRepositoryIntegrationTest.java | 44 +++++++++++++ 46 files changed, 1307 insertions(+), 9 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 9e6f588..85b4b5f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -41,6 +41,10 @@ mvn clean install -DskipTests # Generate JAXB classes from WSDL (EU taxation service) mvn jaxb:generate + +# Generate Allure test report (requires allure-commandline) +mvn clean test +allure serve target/allure-results ``` ## Development Environment (Distrobox) @@ -238,6 +242,53 @@ mvn test -Dtest="*RepositoryIntegrationTest" -Dspring.profiles.active=test,mssql - Repository tests use inline SQL with `executeRawSql()` for database-agnostic test data setup - Test data cleanup in `@BeforeEach` respects foreign key constraints +### Allure Test Reporting + +**Overview:** +All tests (46 test classes, ~624 test methods) are annotated with Allure reporting framework annotations for comprehensive test documentation and reporting. + +**Annotation Hierarchy:** +```java +@Epic("Controller") // Test layer: Controller, Repository, Database Layer, End-to-End +@Feature("Calculation") // Domain/subpackage: Calculation, Configuration, Master Data, etc. +@DisplayName("Test Suite Name") // Human-readable test suite name +class ExampleTest { + + @Test + @Story("Create new calculation") // Test scenario description + @DisplayName("Should create calculation with valid data") + void testCreateCalculation() { ... } +} +``` + +**Annotation Coverage by Layer:** + +| Layer | Epic | Features | Test Classes | Test Methods | +|-------|------|----------|--------------|--------------| +| **Controller** | `@Epic("Controller")` | Configuration, Calculation, Report | 11 | ~100 | +| **Repository** | `@Epic("Repository")` | Calculation, Master Data, Premise, Rates, Properties, Country, Packaging, Users, Bulk, Error, Infrastructure | 28 | ~400 | +| **Database Layer** | `@Epic("Database Layer")` | MySQL Dialect, MSSQL Dialect | 2 | ~42 | +| **End-to-End** | `@Epic("End-to-End")` | Smoke Tests, Calculation Workflow, Deviation Analysis | 3 | ~7 | + +**Local Report Generation:** +```bash +# Run tests and generate Allure results +mvn clean test -Dspring.profiles.active=test,mysql + +# Generate and view Allure report (requires allure-commandline) +allure serve target/allure-results +``` + +**CI/CD Integration:** +- Gitea Actions workflow (`.gitea/workflows/test.yml`) automatically uploads Allure results to Allure server +- Reports available at: `http://10.80.0.6:5050` (project: `lcc-{branch}`) +- Each CI run generates a new report with execution metadata + +**Allure Configuration:** +- Dependency: `io.qameta.allure:allure-junit5` (version 2.29.0) +- Results directory: `target/allure-results` +- Report includes: test duration, stack traces, categorization by Epic/Feature/Story + ## Database ### Multi-Database Support diff --git a/src/test/java/de/avatic/lcc/controller/calculation/CalculationIntegrationTests.java b/src/test/java/de/avatic/lcc/controller/calculation/CalculationIntegrationTests.java index 921bee6..a1d6ea0 100644 --- a/src/test/java/de/avatic/lcc/controller/calculation/CalculationIntegrationTests.java +++ b/src/test/java/de/avatic/lcc/controller/calculation/CalculationIntegrationTests.java @@ -6,6 +6,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import de.avatic.lcc.dto.calculation.DestinationDTO; import de.avatic.lcc.dto.calculation.edit.destination.DestinationCreateDTO; import de.avatic.lcc.dto.calculation.edit.destination.DestinationUpdateDTO; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; @@ -27,6 +30,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @AutoConfigureMockMvc @Transactional @Import({PremiseControllerTestData.class, PremiseTestsHelper.class}) +@Epic("Controller") +@Feature("Calculation") public class CalculationIntegrationTests { @Autowired @@ -49,6 +54,7 @@ public class CalculationIntegrationTests { class StartCalculationTests { @Test + @Story("Start calculation happy path") @DisplayName("POST /api/calculation/start - happy path") public void startCalculationCase1() throws Exception { diff --git a/src/test/java/de/avatic/lcc/controller/calculation/DestinationIntegrationTest.java b/src/test/java/de/avatic/lcc/controller/calculation/DestinationIntegrationTest.java index 043b2b2..fc11032 100644 --- a/src/test/java/de/avatic/lcc/controller/calculation/DestinationIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/controller/calculation/DestinationIntegrationTest.java @@ -4,6 +4,9 @@ package de.avatic.lcc.controller.calculation; import com.fasterxml.jackson.databind.ObjectMapper; import de.avatic.lcc.dto.calculation.edit.destination.DestinationCreateDTO; import de.avatic.lcc.dto.calculation.edit.destination.DestinationUpdateDTO; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; @@ -30,7 +33,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @AutoConfigureMockMvc @Transactional @Import({PremiseControllerTestData.class, PremiseTestsHelper.class}) - +@Epic("Controller") +@Feature("Calculation") public class DestinationIntegrationTest { @Autowired @@ -52,6 +56,7 @@ public class DestinationIntegrationTest { class CreateDestinationTests { @Test + @Story("Create destination happy path") @DisplayName("POST /api/calculation/destination/ - happy path (create destination)") public void createDestinationCase1() throws Exception { @@ -95,6 +100,7 @@ public class DestinationIntegrationTest { } @Test + @Story("Get destination happy path") @DisplayName("GET /api/calculation/destination - happy path (get destination)") public void getDestinationCase1() throws Exception { @@ -130,6 +136,7 @@ public class DestinationIntegrationTest { } @Test + @Story("Update destination happy path") @DisplayName("PUT /api/calculation/destination - happy path (update destination)") public void getDestinationCase1() throws Exception { @@ -165,6 +172,7 @@ public class DestinationIntegrationTest { } @Test + @Story("Partial update destination happy path") @DisplayName("PUT /api/calculation/destination - happy path (partial update destination)") public void getDestinationCase2() throws Exception { @@ -200,6 +208,7 @@ public class DestinationIntegrationTest { } @Test + @Story("Update destination error case with negative value") @DisplayName("PUT /api/calculation/destination - error case (negative value)") public void getDestinationCase3() throws Exception { @@ -255,6 +264,7 @@ public class DestinationIntegrationTest { @Test + @Story("Delete single destination happy path") @DisplayName("DELETE /api/calculation/destination - happy path (delete single destination)") public void deleteDestinationCase1() throws Exception { @@ -279,6 +289,7 @@ public class DestinationIntegrationTest { @Test + @Story("Delete all destinations happy path") @DisplayName("DELETE /api/calculation/destination - happy path (delete all destination)") public void deleteDestinationCase2() throws Exception { @@ -314,6 +325,7 @@ public class DestinationIntegrationTest { @Test + @Story("Delete destination error case with unknown id") @DisplayName("DELETE /api/calculation/destination - error case (unknown id)") public void deleteDestinationCase3() throws Exception { diff --git a/src/test/java/de/avatic/lcc/controller/calculation/PremiseControllerIntegrationTest.java b/src/test/java/de/avatic/lcc/controller/calculation/PremiseControllerIntegrationTest.java index a374f13..dcc97e8 100644 --- a/src/test/java/de/avatic/lcc/controller/calculation/PremiseControllerIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/controller/calculation/PremiseControllerIntegrationTest.java @@ -10,6 +10,9 @@ import de.avatic.lcc.dto.generic.DimensionDTO; import de.avatic.lcc.model.db.premises.Premise; import de.avatic.lcc.model.db.utils.DimensionUnit; import de.avatic.lcc.model.db.utils.WeightUnit; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; @@ -39,6 +42,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @AutoConfigureMockMvc @Transactional @Import({PremiseControllerTestData.class, PremiseTestsHelper.class}) +@Epic("Controller") +@Feature("Calculation") public class PremiseControllerIntegrationTest { @@ -64,6 +69,7 @@ public class PremiseControllerIntegrationTest { // Test for GET /api/calculation/view @Test + @Story("GET /api/calculation/view - happy path (no filter)") @DisplayName("GET /api/calculation/view - happy path (no filter)") public void viewMaterialTest() throws Exception { mockMvc.perform(get("/api/calculation/view")).andExpect(status().isOk()).andDo(print()).andExpect(jsonPath("$", isA(List.class))); @@ -73,6 +79,7 @@ public class PremiseControllerIntegrationTest { @Test + @Story("GET /api/calculation/view - happy path (filtering part number)") @DisplayName("GET /api/calculation/view - happy path (filtering part number)") public void viewMaterialFilterTest() throws Exception { mockMvc.perform(get("/api/calculation/view").param("filter", "28152640129")).andExpect(status().isOk()).andDo(print()).andExpect(jsonPath("$", isA(List.class))).andExpect(jsonPath("$[*].material.part_number", everyItem(equalTo("28152640129")))); @@ -81,6 +88,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("GET /api/calculation/view - happy path (filtering supplier name)") @DisplayName("GET /api/calculation/view - happy path (filtering supplier name)") public void viewMaterialFilterSupplierTest() throws Exception { mockMvc.perform(get("/api/calculation/view").param("filter", "My Supplier 1")).andExpect(status().isOk()).andDo(print()).andExpect(jsonPath("$", isA(List.class))).andExpect(jsonPath("$[*].supplier.name").value(everyItem(equalTo("My Supplier 1")))); @@ -105,6 +113,7 @@ public class PremiseControllerIntegrationTest { // Test for GET /api/calculation/search @Test + @Story("GET /api/calculation/search - happy path (single)") @DisplayName("GET /api/calculation/search - happy path (single)") public void searchSingleMaterialTest() throws Exception { mockMvc.perform(get("/api/calculation/search").param("search", "28152640129")).andExpect(status().isOk()).andDo(print()).andExpect(jsonPath("$.materials", isA(List.class))).andExpect(jsonPath("$.materials", hasSize(1))).andExpect(jsonPath("$.supplier", hasSize(1))).andExpect(jsonPath("$.user_supplier", hasSize(1))).andExpect(jsonPath("$.user_supplier[?(@.name == 'My Supplier 1')]").exists()).andExpect(jsonPath("$.user_supplier[?(@.name == 'My Supplier 2')]").isEmpty()); @@ -112,6 +121,7 @@ public class PremiseControllerIntegrationTest { @Test + @Story("GET /api/calculation/search - happy path (muliple)") @DisplayName("GET /api/calculation/search - happy path (muliple)") public void searchMultiMaterialTest() throws Exception { mockMvc.perform(get("/api/calculation/search").param("search", "28152640129 Material 4222640803 bla4222640104bla bla")).andExpect(status().isOk()).andDo(print()).andExpect(jsonPath("$.materials", isA(List.class))).andExpect(jsonPath("$.materials", hasSize(2))).andExpect(jsonPath("$.supplier", hasSize(1))).andExpect(jsonPath("$.user_supplier", hasSize(1))).andExpect(jsonPath("$.user_supplier[?(@.name == 'My Supplier 1')]").exists()).andExpect(jsonPath("$.supplier[?(@.name == 'Linde (China) Forklift Truck (Supplier)')]").exists()).andExpect(jsonPath("$.materials[?(@.part_number == '28152640129')]").exists()).andExpect(jsonPath("$.materials[?(@.part_number == '4222640803')]").exists()); @@ -322,6 +332,7 @@ public class PremiseControllerIntegrationTest { @Test + @Story("POST /api/calculation/create - Copies COMPLETED with lowest age") @DisplayName("POST /api/calculation/create - Copies COMPLETED with lowest age") public void createPremiseCase1() throws Exception { @@ -365,6 +376,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/create - Recycles DRAFT from same user") @DisplayName("POST /api/calculation/create - Recycles DRAFT from same user") public void createPremiseCase2() throws Exception { @@ -393,6 +405,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/create - Recycles COMPLETED from other user") @DisplayName("POST /api/calculation/create - Recycles COMPLETED from other user") public void createPremiseCase3() throws Exception { var supplierId = testsHelper.getNodeIdByExternalMappingId("LX"); @@ -419,6 +432,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/create - Creates new Premise if no old data") @DisplayName("POST /api/calculation/create - Creates new Premise if no old data") public void createPremiseCase4() throws Exception { var supplierId = testsHelper.getNodeIdByExternalMappingId("LX"); @@ -446,6 +460,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/create - Uses UserSupplier DRAFT") @DisplayName("POST /api/calculation/create - Uses UserSupplier DRAFT") public void createPremiseCase5() throws Exception { var supplierId = testsHelper.getUserNodeIdByName("My Supplier 1"); @@ -472,6 +487,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/create - Access Violation UserSupplier") @DisplayName("POST /api/calculation/create - Access Violation UserSupplier") public void createPremiseCase6() throws Exception { var supplierId = testsHelper.getUserNodeIdByName("My Supplier 2"); @@ -493,6 +509,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/create - From Scratch behavior test") @DisplayName("POST /api/calculation/create - From Scratch behavior test") public void createPremiseCase7() throws Exception { var supplierId = testsHelper.getNodeIdByExternalMappingId("LX"); @@ -526,6 +543,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/create - Faulty material id") @DisplayName("POST /api/calculation/create - Faulty material id") public void createPremiseCase8() throws Exception { @@ -548,6 +566,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/create - Faulty supplier id") @DisplayName("POST /api/calculation/create - Faulty supplier id") public void createPremiseCase9() throws Exception { @@ -569,6 +588,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/create - Faulty user supplier id") @DisplayName("POST /api/calculation/create - Faulty user supplier id") public void createPremiseCase10() throws Exception { var premisesBeforeCreate = testsHelper.getPremisesFromDb(); @@ -624,6 +644,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("GET /api/calculation/edit - Get Single Premiss") @DisplayName("GET /api/calculation/edit - Get Single Premiss") public void getPremiseCase1() throws Exception { @@ -655,6 +676,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("GET /api/calculation/edit - Get Multiple Premisses") @DisplayName("GET /api/calculation/edit - Get Multiple Premisses") public void getPremiseCase2() throws Exception { @@ -699,6 +721,7 @@ public class PremiseControllerIntegrationTest { @Test + @Story("POST /api/calculation/material - happy path (update tariff_rate)") @DisplayName("POST /api/calculation/material - happy path (update tariff_rate)") public void updateMaterialCase1() throws Exception { @@ -731,6 +754,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/material - happy path (update hs_code)") @DisplayName("POST /api/calculation/material - happy path (update hs_code)") public void updateMaterialCase2() throws Exception { @@ -763,6 +787,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/material - happy path (update both)") @DisplayName("POST /api/calculation/material - happy path (update both)") public void updateMaterialCase3() throws Exception { @@ -797,6 +822,7 @@ public class PremiseControllerIntegrationTest { @Test + @Story("POST /api/calculation/material - error (invalid hs_code - to long)") @DisplayName("POST /api/calculation/material - error (invalid hs_code - to long)") public void updateMaterialCase4() throws Exception { @@ -829,6 +855,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/material - error (invalid hs_code - to short)") @DisplayName("POST /api/calculation/material - error (invalid hs_code - to short)") public void updateMaterialCase5() throws Exception { @@ -861,6 +888,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/material - error (invalid hs_code - invalid characters)") @DisplayName("POST /api/calculation/material - error (invalid hs_code - invalid characters)") public void updateMaterialCase6() throws Exception { @@ -894,6 +922,7 @@ public class PremiseControllerIntegrationTest { @Test + @Story("POST /api/calculation/material - error (invalid hs_code - negative number)") @DisplayName("POST /api/calculation/material - error (invalid hs_code - negative number)") public void updateMaterialCase7() throws Exception { @@ -926,6 +955,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/material - error (invalid tariff_rate values)") @DisplayName("POST /api/calculation/material - error (invalid tariff_rate values)") public void updateMaterialCase8() throws Exception { @@ -987,6 +1017,7 @@ public class PremiseControllerIntegrationTest { class UpdatePackagingTests { @Test + @Story("POST /api/calculation/packaging - happy path (update mixable)") @DisplayName("POST /api/calculation/packaging - happy path (update mixable)") public void updatePackagingCase1() throws Exception { @@ -1041,6 +1072,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/packaging - happy path (update stackable)") @DisplayName("POST /api/calculation/packaging - happy path (update stackable)") public void updatePackagingCase2() throws Exception { @@ -1095,6 +1127,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/packaging - happy path (update dimensions)") @DisplayName("POST /api/calculation/packaging - happy path (update dimensions)") public void updatePackagingCase3() throws Exception { @@ -1156,6 +1189,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/packaging - error (partial update dimensions)") @DisplayName("POST /api/calculation/packaging - error (partial update dimensions)") public void updatePackagingCase4() throws Exception { @@ -1217,6 +1251,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/packaging - happy path (API read-back)") @DisplayName("POST /api/calculation/packaging - happy path (API read-back)") public void updatePackagingCase5() throws Exception { @@ -1255,6 +1290,7 @@ public class PremiseControllerIntegrationTest { class UpdatePriceTests { @Test + @Story("POST /api/calculation/price - happy path (update price only)") @DisplayName("POST /api/calculation/price - happy path (update price only)") public void updatePriceCase1() throws Exception { @@ -1289,6 +1325,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/price - error case (set invalid prices)") @DisplayName("POST /api/calculation/price - error case (set invalid prices)") public void updatePriceCase2() throws Exception { @@ -1336,6 +1373,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/price - happy path (update oversea share only)") @DisplayName("POST /api/calculation/price - happy path (update oversea share only)") public void updatePriceCase4() throws Exception { @@ -1370,6 +1408,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/price - error case (set invalid oversea share)") @DisplayName("POST /api/calculation/price - error case (set invalid oversea share)") public void updatePriceCase5() throws Exception { @@ -1414,6 +1453,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/price - happy path (update include fca fee)") @DisplayName("POST /api/calculation/price - happy path (update include fca fee)") public void updatePriceCase6() throws Exception { @@ -1467,6 +1507,7 @@ public class PremiseControllerIntegrationTest { } @Test + @Story("POST /api/calculation/price - happy path (update all values)") @DisplayName("POST /api/calculation/price - happy path (update all values)") public void updatePriceCase7() throws Exception { diff --git a/src/test/java/de/avatic/lcc/controller/calculation/PremiseControllerSetIntegrationTest.java b/src/test/java/de/avatic/lcc/controller/calculation/PremiseControllerSetIntegrationTest.java index bf732ae..ee5ddf7 100644 --- a/src/test/java/de/avatic/lcc/controller/calculation/PremiseControllerSetIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/controller/calculation/PremiseControllerSetIntegrationTest.java @@ -2,6 +2,9 @@ package de.avatic.lcc.controller.calculation; import com.fasterxml.jackson.databind.ObjectMapper; import de.avatic.lcc.dto.calculation.edit.SetDataDTO; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; @@ -28,6 +31,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @AutoConfigureMockMvc @Transactional @Import({PremiseControllerTestData.class, PremiseTestsHelper.class}) +@Epic("Controller") +@Feature("Calculation") public class PremiseControllerSetIntegrationTest { @Autowired @@ -59,6 +64,7 @@ public class PremiseControllerSetIntegrationTest { } @Test + @Story("Set supplier with master data update and no user node") @DisplayName("PUT /api/calculation/supplier - happy path (update master data, no user node)") public void setSupplierTestCase1() throws Exception { @@ -84,6 +90,7 @@ public class PremiseControllerSetIntegrationTest { @Test + @Story("Set supplier without master data update and no user node") @DisplayName("PUT /api/calculation/supplier - happy path (no master data update, no user node)") public void setSupplierTestCase2() throws Exception { @@ -106,6 +113,7 @@ public class PremiseControllerSetIntegrationTest { } @Test + @Story("Set supplier with master data update and user node") @DisplayName("PUT /api/calculation/supplier - happy path (master data update, user node)") public void setSupplierTestCase3() throws Exception { @@ -150,6 +158,7 @@ public class PremiseControllerSetIntegrationTest { } @Test + @Story("Set material without master data update") @DisplayName("PUT /api/calculation/material - happy path (no master data update)") public void setMaterialTestCase1() throws Exception { @@ -171,6 +180,7 @@ public class PremiseControllerSetIntegrationTest { } @Test + @Story("Set material with master data update") @DisplayName("PUT /api/calculation/material - happy path (master data update)") public void setMaterialTestCase2() throws Exception { diff --git a/src/test/java/de/avatic/lcc/controller/configuration/CountryControllerIntegrationTest.java b/src/test/java/de/avatic/lcc/controller/configuration/CountryControllerIntegrationTest.java index 8696494..7b3fd23 100644 --- a/src/test/java/de/avatic/lcc/controller/configuration/CountryControllerIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/controller/configuration/CountryControllerIntegrationTest.java @@ -2,6 +2,9 @@ package de.avatic.lcc.controller.configuration; import com.fasterxml.jackson.databind.ObjectMapper; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Test; @@ -25,6 +28,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @Sql(scripts = {"classpath:master_data/countries_properties.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) +@Epic("Controller") +@Feature("Configuration") public class CountryControllerIntegrationTest { protected static final String BASE_URL = "/api/countries"; @@ -36,6 +41,7 @@ public class CountryControllerIntegrationTest { protected ObjectMapper objectMapper; @Test + @Story("Get countries with default pagination") @DisplayName("get countries with default pagination") void countriesDefaultPagination() throws Exception { mockMvc.perform(get(BASE_URL + "/")) @@ -49,6 +55,7 @@ public class CountryControllerIntegrationTest { } @Test + @Story("Get countries with custom pagination") @DisplayName("get countries with custom pagination") void countriesCustomPagination() throws Exception { mockMvc.perform(get(BASE_URL + "/") @@ -62,6 +69,7 @@ public class CountryControllerIntegrationTest { } @Test + @Story("Get countries with filter region, non empty") @DisplayName("get countries with filter region, non empty") void countriesFilteredByNAM() throws Exception { mockMvc.perform(get(BASE_URL + "/") @@ -72,6 +80,7 @@ public class CountryControllerIntegrationTest { } @Test + @Story("Get countries with filter, empty result") @DisplayName("get countries with filter, empty result") void countriesFilteredByXyz() throws Exception { mockMvc.perform(get(BASE_URL + "/") @@ -82,6 +91,7 @@ public class CountryControllerIntegrationTest { } @Test + @Story("Get countries with filter country, non empty") @DisplayName("get countries with filter country, non empty") void countriesFilteredByDe() throws Exception { mockMvc.perform(get(BASE_URL + "/") @@ -92,6 +102,7 @@ public class CountryControllerIntegrationTest { } @Test + @Story("Get all countries without pagination") @DisplayName("get all countries without pagination") void allCountries() throws Exception { mockMvc.perform(get(BASE_URL + "/all")) @@ -101,6 +112,7 @@ public class CountryControllerIntegrationTest { } @Test + @Story("Get all countries filtered by EMEA region") @DisplayName("get all countries filtered by EMEA region") void allCountriesFilteredByEmea() throws Exception { mockMvc.perform(get(BASE_URL + "/all") @@ -110,6 +122,7 @@ public class CountryControllerIntegrationTest { } @Test + @Story("Get country details by ID") @DisplayName("get country details by ID") void getCountryDetailsById() throws Exception { final String isoCode = "DE"; @@ -130,6 +143,7 @@ public class CountryControllerIntegrationTest { } @Test + @Story("Get country details by ISO code") @DisplayName("get country details by ISO code") void getCountryDetailsByIsoCode() throws Exception { final String isoCode = "US"; @@ -146,6 +160,7 @@ public class CountryControllerIntegrationTest { } @Test + @Story("Get country with specific property set") @DisplayName("get country with specific property set") void getWithPropertySet() throws Exception { final String isoCode = "US"; @@ -159,6 +174,7 @@ public class CountryControllerIntegrationTest { } @Test + @Story("Get country with invalid property set should return bad request") @DisplayName("get country with invalid property set should return bad request") void getWithBadPropertySet() throws Exception { final String isoCode = "US"; @@ -176,6 +192,7 @@ public class CountryControllerIntegrationTest { } @Test + @Story("Get country with invalid ID should return bad request") @DisplayName("get country with invalid ID should return bad request") void getCountryWithBadId() throws Exception { mockMvc.perform(get(BASE_URL + "/999")) @@ -183,6 +200,7 @@ public class CountryControllerIntegrationTest { } @Test + @Story("Get country with invalid ISO code should return bad request") @DisplayName("get country with invalid ISO code should return bad request") void getCountryWithBadIsoCode() throws Exception { mockMvc.perform(get(BASE_URL + "/XY")) @@ -190,6 +208,7 @@ public class CountryControllerIntegrationTest { } @Test + @Story("Get countries with invalid pagination parameters should return bad request") @DisplayName("get countries with invalid pagination parameters should return bad request") void countriesPaginationWithBadParams() throws Exception { mockMvc.perform(get(BASE_URL + "/") @@ -199,6 +218,7 @@ public class CountryControllerIntegrationTest { } @Test + @Story("Get countries with large pagination limit should return all countries") @DisplayName("get countries with large pagination limit should return all countries") void countriesPaginationWithLargeParams() throws Exception { mockMvc.perform(get(BASE_URL + "/") @@ -208,6 +228,7 @@ public class CountryControllerIntegrationTest { } @Test + @Story("Get countries with SQL injection attempt should be safe") @DisplayName("get countries with SQL injection attempt should be safe") void countriesSqlInjection() throws Exception { String maliciousFilter = "'; DROP TABLE country; --"; diff --git a/src/test/java/de/avatic/lcc/controller/configuration/MaterialControllerIntegrationTest.java b/src/test/java/de/avatic/lcc/controller/configuration/MaterialControllerIntegrationTest.java index 64f9c61..b910d7b 100644 --- a/src/test/java/de/avatic/lcc/controller/configuration/MaterialControllerIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/controller/configuration/MaterialControllerIntegrationTest.java @@ -2,6 +2,9 @@ package de.avatic.lcc.controller.configuration; import com.fasterxml.jackson.databind.ObjectMapper; import de.avatic.lcc.dto.generic.MaterialDTO; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -24,6 +27,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @AutoConfigureMockMvc @Transactional @DisplayName("MaterialController Integration Tests") +@Epic("Controller") +@Feature("Configuration") class MaterialControllerIntegrationTest { @Autowired @@ -39,6 +44,7 @@ class MaterialControllerIntegrationTest { class ListMaterialsTests { @Test + @Story("Return all materials with default pagination") @DisplayName("Should return all materials with default pagination") void shouldReturnAllMaterialsWithDefaultPagination() throws Exception { mockMvc.perform(get("/api/materials/") @@ -57,6 +63,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Return materials with custom pagination") @DisplayName("Should return materials with custom pagination") void shouldReturnMaterialsWithCustomPagination() throws Exception { mockMvc.perform(get("/api/materials/") @@ -73,6 +80,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Return second page of materials") @DisplayName("Should return second page of materials") void shouldReturnSecondPageOfMaterials() throws Exception { mockMvc.perform(get("/api/materials/") @@ -89,6 +97,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Filter materials by part number") @DisplayName("Should filter materials by part number") void shouldFilterMaterialsByPartNumber() throws Exception { mockMvc.perform(get("/api/materials/") @@ -106,6 +115,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Filter materials by name") @DisplayName("Should filter materials by name") void shouldFilterMaterialsByName() throws Exception { mockMvc.perform(get("/api/materials/") @@ -119,6 +129,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Return empty list when filter matches no materials") @DisplayName("Should return empty list when filter matches no materials") void shouldReturnEmptyListWhenFilterMatchesNoMaterials() throws Exception { mockMvc.perform(get("/api/materials/") @@ -134,6 +145,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Handle empty filter parameter") @DisplayName("Should handle empty filter parameter") void shouldHandleEmptyFilterParameter() throws Exception { mockMvc.perform(get("/api/materials/") @@ -147,6 +159,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Handle out of bounds page number") @DisplayName("Should handle out of bounds page number") void shouldHandleOutOfBoundsPageNumber() throws Exception { mockMvc.perform(get("/api/materials/") @@ -162,6 +175,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Handle negative page number") @DisplayName("Should handle negative page number") void shouldHandleNegativePageNumber() throws Exception { mockMvc.perform(get("/api/materials/") @@ -173,6 +187,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Handle large limit parameter") @DisplayName("Should handle large limit parameter") void shouldHandleLargeLimitParameter() throws Exception { mockMvc.perform(get("/api/materials/") @@ -194,6 +209,7 @@ class MaterialControllerIntegrationTest { class GetMaterialDetailsTests { @Test + @Story("Return material details for existing material") @DisplayName("Should return material details for existing material") void shouldReturnMaterialDetailsForExistingMaterial() throws Exception { // First, get the list of materials to find a valid ID @@ -219,6 +235,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Return material details with correct data structure") @DisplayName("Should return material details with correct data structure") void shouldReturnMaterialDetailsWithCorrectDataStructure() throws Exception { @@ -244,6 +261,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Return specific material details by known part number") @DisplayName("Should return specific material details by known part number") void shouldReturnSpecificMaterialDetailsByKnownPartNumber() throws Exception { @@ -269,6 +287,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Return 400 for non-existent material ID") @DisplayName("Should return 400 for non-existent material ID") void shouldReturn404ForNonExistentMaterialId() throws Exception { mockMvc.perform(get("/api/materials/99999") @@ -278,6 +297,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Return 400 for negative material ID") @DisplayName("Should return 400 for negative material ID") void shouldReturn404ForNegativeMaterialId() throws Exception { mockMvc.perform(get("/api/materials/-1") @@ -287,6 +307,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Return 400 for invalid material ID format") @DisplayName("Should return 400 for invalid material ID format") void shouldReturn400ForInvalidMaterialIdFormat() throws Exception { mockMvc.perform(get("/api/materials/invalid") @@ -296,6 +317,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Return 400 for zero material ID") @DisplayName("Should return 400 for zero material ID") void shouldReturn400ForZeroMaterialId() throws Exception { mockMvc.perform(get("/api/materials/0") @@ -312,6 +334,7 @@ class MaterialControllerIntegrationTest { class ErrorHandlingTests { @Test + @Story("Handle missing required headers") @DisplayName("Should handle missing required headers") void shouldHandleMissingRequiredHeaders() throws Exception { mockMvc.perform(get("/api/materials/")) @@ -320,6 +343,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Handle invalid parameter types for limit") @DisplayName("Should handle invalid parameter types for limit") void shouldHandleInvalidParameterTypesForLimit() throws Exception { mockMvc.perform(get("/api/materials/") @@ -330,6 +354,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Handle invalid parameter types for page") @DisplayName("Should handle invalid parameter types for page") void shouldHandleInvalidParameterTypesForPage() throws Exception { mockMvc.perform(get("/api/materials/") @@ -340,6 +365,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Handle extremely large filter string") @DisplayName("Should handle extremely large filter string") void shouldHandleExtremelyLargeFilterString() throws Exception { String largeFilter = "x".repeat(1000); @@ -352,6 +378,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Handle special characters in filter") @DisplayName("Should handle special characters in filter") void shouldHandleSpecialCharactersInFilter() throws Exception { mockMvc.perform(get("/api/materials/") @@ -363,6 +390,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Handle SQL injection attempts in filter") @DisplayName("Should handle SQL injection attempts in filter") void shouldHandleSqlInjectionAttemptsInFilter() throws Exception { mockMvc.perform(get("/api/materials/") @@ -379,6 +407,7 @@ class MaterialControllerIntegrationTest { class PerformanceTests { @Test + @Story("Handle concurrent requests efficiently") @DisplayName("Should handle concurrent requests efficiently") @Sql(scripts = {"classpath:master_data/countries_properties.sql", "classpath:master_data/nodes.sql", "classpath:master_data/material_packaging.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/material_packaging-cleanup.sql", "classpath:master_data/nodes-cleanup.sql", "classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -395,6 +424,7 @@ class MaterialControllerIntegrationTest { } @Test + @Story("Respond within reasonable time limits") @DisplayName("Should respond within reasonable time limits") @Sql(scripts = {"classpath:master_data/countries_properties.sql", "classpath:master_data/nodes.sql", "classpath:master_data/material_packaging.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/material_packaging-cleanup.sql", "classpath:master_data/nodes-cleanup.sql", "classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -412,4 +442,4 @@ class MaterialControllerIntegrationTest { assert responseTime < 2000 : "Response time too slow: " + responseTime + "ms"; } } -} \ No newline at end of file +} diff --git a/src/test/java/de/avatic/lcc/controller/configuration/NodeControllerIntegrationTest.java b/src/test/java/de/avatic/lcc/controller/configuration/NodeControllerIntegrationTest.java index 1ccd074..0e2234a 100644 --- a/src/test/java/de/avatic/lcc/controller/configuration/NodeControllerIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/controller/configuration/NodeControllerIntegrationTest.java @@ -6,6 +6,9 @@ import de.avatic.lcc.dto.configuration.nodes.userNodes.AddUserNodeDTO; import de.avatic.lcc.dto.generic.CountryDTO; import de.avatic.lcc.dto.generic.LocationDTO; import de.avatic.lcc.dto.generic.NodeType; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -25,6 +28,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @SpringBootTest @AutoConfigureMockMvc @Transactional +@Epic("Controller") +@Feature("Configuration") class NodeControllerIntegrationTest { @Autowired @@ -38,6 +43,7 @@ class NodeControllerIntegrationTest { class ListNodesTests { @Test + @Story("Return list of nodes with default pagination") @DisplayName("Should return list of nodes with default pagination") @Sql(scripts = {"classpath:master_data/countries_properties.sql", "classpath:master_data/nodes.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/nodes-cleanup.sql", "classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -64,6 +70,7 @@ class NodeControllerIntegrationTest { } @Test + @Story("Return filtered nodes when filter parameter is provided") @DisplayName("Should return filtered nodes when filter parameter is provided") @Sql(scripts = {"classpath:master_data/countries_properties.sql", "classpath:master_data/nodes.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/nodes-cleanup.sql", "classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -77,6 +84,7 @@ class NodeControllerIntegrationTest { } @Test + @Story("Respect pagination parameters") @DisplayName("Should respect pagination parameters") @Sql(scripts = {"classpath:master_data/countries_properties.sql", "classpath:master_data/nodes.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/nodes-cleanup.sql", "classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -91,6 +99,7 @@ class NodeControllerIntegrationTest { } @Test + @Story("Return empty list when no nodes match filter") @DisplayName("Should return empty list when no nodes match filter") @Sql(scripts = {"classpath:master_data/countries_properties.sql", "classpath:master_data/nodes.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/nodes-cleanup.sql", "classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -108,6 +117,7 @@ class NodeControllerIntegrationTest { class SearchNodesTests { @Test + @Story("Search nodes without type filter") @DisplayName("Should search nodes without type filter") @Sql(scripts = {"classpath:master_data/countries_properties.sql", "classpath:master_data/nodes.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/nodes-cleanup.sql", "classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -122,6 +132,7 @@ class NodeControllerIntegrationTest { } @Test + @Story("Search nodes with specific node type") @DisplayName("Should search nodes with specific node type") @Sql(scripts = {"classpath:master_data/countries_properties.sql", "classpath:master_data/nodes.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/nodes-cleanup.sql", "classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -135,6 +146,7 @@ class NodeControllerIntegrationTest { } @Test + @Story("Include user nodes when requested") @DisplayName("Should include user nodes when requested") @Sql(scripts = {"classpath:master_data/countries_properties.sql", "classpath:master_data/nodes.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/nodes-cleanup.sql", "classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -153,6 +165,7 @@ class NodeControllerIntegrationTest { class GetNodeDetailsTests { @Test + @Story("Return node details for existing node") @DisplayName("Should return node details for existing node") @Sql(scripts = {"classpath:master_data/countries_properties.sql", "classpath:master_data/nodes.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/nodes-cleanup.sql", "classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -178,6 +191,7 @@ class NodeControllerIntegrationTest { } @Test + @Story("Return bad request for non-existing node") @DisplayName("Should return bad request for non-existing node") @Sql(scripts = {"classpath:master_data/countries_properties.sql", "classpath:master_data/nodes.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/nodes-cleanup.sql", "classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -186,6 +200,7 @@ class NodeControllerIntegrationTest { } @Test + @Story("Return node with predecessor chains") @DisplayName("Should return node with predecessor chains") @Sql(scripts = {"classpath:master_data/countries_properties.sql", "classpath:master_data/nodes.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/nodes-cleanup.sql", "classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -205,6 +220,7 @@ class NodeControllerIntegrationTest { class UpdateNodeTests { @Test + @Story("Update existing node successfully") @DisplayName("Should update existing node successfully") @Sql(scripts = {"classpath:master_data/countries_properties.sql", "classpath:master_data/nodes.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/nodes-cleanup.sql", "classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -227,6 +243,7 @@ class NodeControllerIntegrationTest { } @Test + @Story("Return 400 when ID in path doesn't match ID in body") @DisplayName("Should return 400 when ID in path doesn't match ID in body") @Sql(scripts = {"classpath:master_data/countries_properties.sql", "classpath:master_data/nodes.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/nodes-cleanup.sql", "classpath:master_data/countries_properties-cleanup.sql" @@ -243,6 +260,7 @@ class NodeControllerIntegrationTest { } @Test + @Story("Return 400 when trying to update non-existing node") @DisplayName("Should return 400 when trying to update non-existing node") @Sql(scripts = {"classpath:master_data/countries_properties.sql", "classpath:master_data/nodes.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/nodes-cleanup.sql", "classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -263,6 +281,7 @@ class NodeControllerIntegrationTest { class DeleteNodeTests { @Test + @Story("Mark node as deprecated successfully") @DisplayName("Should mark node as deprecated successfully") @Sql(scripts = {"classpath:master_data/countries_properties.sql", "classpath:master_data/nodes.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/nodes-cleanup.sql", "classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -278,6 +297,7 @@ class NodeControllerIntegrationTest { } @Test + @Story("Return 404 when trying to delete non-existing node") @DisplayName("Should return 404 when trying to delete non-existing node") @Sql(scripts = {"classpath:master_data/countries_properties.sql", "classpath:master_data/nodes.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/nodes-cleanup.sql", "classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -292,6 +312,7 @@ class NodeControllerIntegrationTest { class LocateNodeTests { @Test + @Story("Locate node by address") @DisplayName("Should locate node by address") void shouldLocateNodeByAddress() throws Exception { mockMvc.perform(get("/api/nodes/locate") @@ -304,6 +325,7 @@ class NodeControllerIntegrationTest { } @Test + @Story("Return 400 when address parameter is missing") @DisplayName("Should return 400 when address parameter is missing") void shouldReturn400WhenAddressParameterIsMissing() throws Exception { mockMvc.perform(get("/api/nodes/locate")) @@ -311,6 +333,7 @@ class NodeControllerIntegrationTest { } @Test + @Story("Handle invalid addresses gracefully") @DisplayName("Should handle invalid addresses gracefully") void shouldHandleInvalidAddressesGracefully() throws Exception { mockMvc.perform(get("/api/nodes/locate") @@ -325,6 +348,7 @@ class NodeControllerIntegrationTest { class AddUserNodeTests { @Test + @Story("Add user node successfully") @DisplayName("Should add user node successfully") @Sql(scripts = {"classpath:master_data/countries_properties.sql", "classpath:master_data/nodes.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/nodes-cleanup.sql", "classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -349,6 +373,7 @@ class NodeControllerIntegrationTest { } @Test + @Story("Return 400 for invalid user node data") @DisplayName("Should return 400 for invalid user node data") void shouldReturn400ForInvalidUserNodeData() throws Exception { AddUserNodeDTO invalidDTO = new AddUserNodeDTO(); @@ -366,6 +391,7 @@ class NodeControllerIntegrationTest { class ErrorHandlingTests { @Test + @Story("Handle malformed JSON in request body") @DisplayName("Should handle malformed JSON in request body") void shouldHandleMalformedJsonInRequestBody() throws Exception { String malformedJson = "{ \"id\": \"invalid\" malformed }"; @@ -377,6 +403,7 @@ class NodeControllerIntegrationTest { } @Test + @Story("Handle non-numeric node ID in path") @DisplayName("Should handle non-numeric node ID in path") void shouldHandleNonNumericNodeIdInPath() throws Exception { mockMvc.perform(get("/api/nodes/invalid-id")) @@ -384,6 +411,7 @@ class NodeControllerIntegrationTest { } @Test + @Story("Handle negative pagination parameters") @DisplayName("Should handle negative pagination parameters") void shouldHandleNegativePaginationParameters() throws Exception { mockMvc.perform(get("/api/nodes/") @@ -398,6 +426,7 @@ class NodeControllerIntegrationTest { class SecurityTests { @Test + @Story("Reject requests with XSS attempts in filter") @DisplayName("Should reject requests with XSS attempts in filter") void shouldRejectRequestsWithXssAttemptsInFilter() throws Exception { String xssAttempt = ""; @@ -409,6 +438,7 @@ class NodeControllerIntegrationTest { } @Test + @Story("Handle SQL injection attempts in filter") @DisplayName("Should handle SQL injection attempts in filter") void shouldHandleSqlInjectionAttemptsInFilter() throws Exception { String sqlInjection = "'; DROP TABLE node; --"; @@ -424,6 +454,7 @@ class NodeControllerIntegrationTest { class PerformanceTests { @Test + @Story("Handle large page sizes efficiently") @DisplayName("Should handle large page sizes efficiently") @Sql(scripts = { "classpath:master_data/countries_properties.sql", @@ -447,4 +478,4 @@ class NodeControllerIntegrationTest { assert executionTime < 5000; // 5 seconds max } } -} \ No newline at end of file +} diff --git a/src/test/java/de/avatic/lcc/controller/configuration/PropertyControllerIntegrationTest.java b/src/test/java/de/avatic/lcc/controller/configuration/PropertyControllerIntegrationTest.java index 45a7148..6137410 100644 --- a/src/test/java/de/avatic/lcc/controller/configuration/PropertyControllerIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/controller/configuration/PropertyControllerIntegrationTest.java @@ -1,5 +1,8 @@ package de.avatic.lcc.controller.configuration; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; @@ -18,6 +21,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @AutoConfigureMockMvc @Transactional @TestMethodOrder(MethodOrderer.OrderAnnotation.class) +@Epic("Controller") +@Feature("Configuration") class PropertyControllerIntegrationTest { @Autowired @@ -32,6 +37,7 @@ class PropertyControllerIntegrationTest { @Test @Order(1) + @Story("Return properties with default property_set parameter") @DisplayName("Should return properties with default property_set parameter") @Sql(scripts = {"classpath:master_data/countries_properties.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -52,6 +58,7 @@ class PropertyControllerIntegrationTest { @Test @Order(2) + @Story("Return properties for specific property_set") @DisplayName("Should return properties for specific property_set") @Sql(scripts = {"classpath:master_data/countries_properties.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -78,6 +85,7 @@ class PropertyControllerIntegrationTest { @Test @Order(3) + @Story("Return empty list for non-existent property_set") @DisplayName("Should return empty list for non-existent property_set") @Sql(scripts = {"classpath:master_data/countries_properties.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -95,6 +103,7 @@ class PropertyControllerIntegrationTest { @Test @Order(4) + @Story("Return all validity periods") @DisplayName("Should return all validity periods") @Sql(scripts = {"classpath:master_data/countries_properties.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -115,6 +124,7 @@ class PropertyControllerIntegrationTest { @Test @Order(5) + @Story("Invalidate validity period successfully") @DisplayName("Should invalidate validity period successfully") @Sql(scripts = {"classpath:master_data/countries_properties.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -137,6 +147,7 @@ class PropertyControllerIntegrationTest { @Test @Order(6) + @Story("Return error for non-existent validity period/ not expired validity period") @DisplayName("Should return error for non-existent validity period/ not expired validity period") @Sql(scripts = {"classpath:master_data/countries_properties.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -157,6 +168,7 @@ class PropertyControllerIntegrationTest { @Test @Order(7) + @Story("Update existing country property") @DisplayName("Should update existing country property") @Sql(scripts = {"classpath:master_data/countries_properties.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -195,6 +207,7 @@ class PropertyControllerIntegrationTest { @Test @Order(9) + @Story("Reject invalid ISO code") @DisplayName("Should reject invalid ISO code") @Sql(scripts = {"classpath:master_data/countries_properties.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -225,6 +238,7 @@ class PropertyControllerIntegrationTest { @Test @Order(10) + @Story("Set system property successfully") @DisplayName("Should set system property successfully") @Sql(scripts = {"classpath:master_data/countries_properties.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -264,6 +278,7 @@ class PropertyControllerIntegrationTest { @Test @Order(11) + @Story("Validate property data type") @DisplayName("Should validate property data type") @Sql(scripts = {"classpath:master_data/countries_properties.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -286,6 +301,7 @@ class PropertyControllerIntegrationTest { @Test @Order(14) + @Story("Approve staged changes successfully") @DisplayName("Should approve staged changes successfully") @Sql(scripts = {"classpath:master_data/countries_properties.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/countries_properties-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -357,4 +373,4 @@ class PropertyControllerIntegrationTest { } -} \ No newline at end of file +} diff --git a/src/test/java/de/avatic/lcc/controller/configuration/RateControllerAdvancedIntegrationTest.java b/src/test/java/de/avatic/lcc/controller/configuration/RateControllerAdvancedIntegrationTest.java index f4d4fcd..30ec308 100644 --- a/src/test/java/de/avatic/lcc/controller/configuration/RateControllerAdvancedIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/controller/configuration/RateControllerAdvancedIntegrationTest.java @@ -1,5 +1,9 @@ package de.avatic.lcc.controller.configuration; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; @@ -25,6 +29,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @SpringBootTest @AutoConfigureMockMvc @Transactional +@Epic("Controller") +@Feature("Configuration") class RateControllerAdvancedIntegrationTest { @Autowired @@ -35,6 +41,8 @@ class RateControllerAdvancedIntegrationTest { // Parameterized Tests @ParameterizedTest + @Story("Rate endpoints with different limits") + @DisplayName("Rate endpoints with different limits") @ValueSource(strings = {"container", "matrix"}) @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @@ -51,6 +59,8 @@ class RateControllerAdvancedIntegrationTest { } @ParameterizedTest + @Story("Container rates filter by transport type") + @DisplayName("Container rates filter by transport type") @CsvSource({ "container,RAIL", "container,SEA", @@ -69,6 +79,8 @@ class RateControllerAdvancedIntegrationTest { // Complex Date Range Tests @Test + @Story("Container rates with future date filter should return only future valid rates") + @DisplayName("Container rates with future date filter should return only future valid rates") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testContainerRates_WithFutureDateFilter_ShouldReturnOnlyFutureValidRates() throws Exception { @@ -83,6 +95,8 @@ class RateControllerAdvancedIntegrationTest { } @Test + @Story("Container rates with past date filter should return historical rates") + @DisplayName("Container rates with past date filter should return historical rates") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testContainerRates_WithPastDateFilter_ShouldReturnHistoricalRates() throws Exception { @@ -98,6 +112,8 @@ class RateControllerAdvancedIntegrationTest { // Concurrent Request Tests @Test + @Story("Container rates with multiple filters simultaneously should prioritize validAt") + @DisplayName("Container rates with multiple filters simultaneously should prioritize validAt") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testContainerRates_MultipleFiltersSimultaneously_ShouldPrioritizeValidAt() throws Exception { @@ -115,6 +131,8 @@ class RateControllerAdvancedIntegrationTest { // State Transition Tests @Test + @Story("Validity period state transitions from draft to valid") + @DisplayName("Validity period state transitions from draft to valid") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testValidityPeriod_StateTransitions_DraftToValid() throws Exception { @@ -139,6 +157,8 @@ class RateControllerAdvancedIntegrationTest { // Edge Cases for Pagination @Test + @Story("Pagination requesting page beyond available should return empty list") + @DisplayName("Pagination requesting page beyond available should return empty list") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testPagination_RequestingPageBeyondAvailable_ShouldReturnEmptyList() throws Exception { @@ -152,6 +172,8 @@ class RateControllerAdvancedIntegrationTest { } @Test + @Story("Pagination with zero limit should return bad request") + @DisplayName("Pagination with zero limit should return bad request") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testPagination_WithZeroLimit_ShouldReturnBadRequest() throws Exception { @@ -164,6 +186,8 @@ class RateControllerAdvancedIntegrationTest { // Complex Filtering Scenarios @Test + @Story("Matrix rates filter by specific country pairs") + @DisplayName("Matrix rates filter by specific country pairs") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testMatrixRates_FilterBySpecificCountryPairs() throws Exception { @@ -176,6 +200,8 @@ class RateControllerAdvancedIntegrationTest { // Business Logic Validation Tests @Test + @Story("Container rates validate rate hierarchy") + @DisplayName("Container rates validate rate hierarchy") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testContainerRates_ValidateRateHierarchy() throws Exception { @@ -199,6 +225,8 @@ class RateControllerAdvancedIntegrationTest { // Null and Empty Value Handling @Test + @Story("Validity periods with null end dates should handle gracefully") + @DisplayName("Validity periods with null end dates should handle gracefully") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testValidityPeriods_WithNullEndDates_ShouldHandleGracefully() throws Exception { @@ -211,6 +239,8 @@ class RateControllerAdvancedIntegrationTest { // Special Character Handling @Test + @Story("Invalid parameters with special characters should return 400") + @DisplayName("Invalid parameters with special characters should return 400") void testInvalidParameters_WithSpecialCharacters_ShouldReturn400() throws Exception { mockMvc.perform(get(BASE_URL + "/container") .param("limit", "20'; DROP TABLE container_rate; --") @@ -221,6 +251,8 @@ class RateControllerAdvancedIntegrationTest { // Large Dataset Performance Test @Test + @Story("Performance with large dataset should maintain response time") + @DisplayName("Performance with large dataset should maintain response time") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testPerformance_WithLargeDataset_ShouldMaintainResponseTime() throws Exception { @@ -258,4 +290,4 @@ class RateControllerAdvancedIntegrationTest { // .contentType(MediaType.APPLICATION_JSON)) // .andExpect(status().isOk()); // } -} \ No newline at end of file +} diff --git a/src/test/java/de/avatic/lcc/controller/configuration/RateControllerIntegrationTest.java b/src/test/java/de/avatic/lcc/controller/configuration/RateControllerIntegrationTest.java index 11257d5..7e0a880 100644 --- a/src/test/java/de/avatic/lcc/controller/configuration/RateControllerIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/controller/configuration/RateControllerIntegrationTest.java @@ -5,6 +5,9 @@ import de.avatic.lcc.dto.configuration.matrixrates.MatrixRateDTO; import de.avatic.lcc.dto.configuration.rates.ContainerRateDTO; import de.avatic.lcc.dto.generic.ValidityPeriodDTO; import de.avatic.lcc.model.db.rates.ValidityPeriodState; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -33,6 +36,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @SpringBootTest @AutoConfigureMockMvc @Transactional +@Epic("Controller") +@Feature("Configuration") class RateControllerIntegrationTest { private static final String BASE_URL = "/api/rates"; @@ -47,6 +52,8 @@ class RateControllerIntegrationTest { class ListContainerRatesTest { @Test + @Story("List container rates without filter should return all rates") + @DisplayName("List container rates without filter should return all rates") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testListContainerRates_WithoutFilter_ShouldReturnAllRates() throws Exception { @@ -67,6 +74,8 @@ class RateControllerIntegrationTest { } @Test + @Story("List container rates with pagination should return paged results") + @DisplayName("List container rates with pagination should return paged results") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testListContainerRates_WithPagination_ShouldReturnPagedResults() throws Exception { @@ -81,6 +90,8 @@ class RateControllerIntegrationTest { } @Test + @Story("List container rates with validity period filter should return filtered rates") + @DisplayName("List container rates with validity period filter should return filtered rates") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testListContainerRates_WithValidityPeriodFilter_ShouldReturnFilteredRates() throws Exception { @@ -93,6 +104,8 @@ class RateControllerIntegrationTest { } @Test + @Story("List container rates with validAt filter should return valid rates") + @DisplayName("List container rates with validAt filter should return valid rates") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testListContainerRates_WithValidAtFilter_ShouldReturnValidRates() throws Exception { @@ -113,6 +126,8 @@ class RateControllerIntegrationTest { class GetContainerRatesTest { @Test + @Story("Get container rate with valid ID should return rate") + @DisplayName("Get container rate with valid ID should return rate") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testGetContainerRate_WithValidId_ShouldReturnRate() throws Exception { @@ -144,6 +159,8 @@ class RateControllerIntegrationTest { } @Test + @Story("Get container rate with invalid ID should return 400") + @DisplayName("Get container rate with invalid ID should return 400") void testGetContainerRate_WithInvalidId_ShouldReturn400() throws Exception { mockMvc.perform(get(BASE_URL + "/container/{id}", 99999) .contentType(MediaType.APPLICATION_JSON)) @@ -158,6 +175,8 @@ class RateControllerIntegrationTest { @DisplayName("/api/rates/matrix/ - list matrix rates") class ListMatrixRatesTest { @Test + @Story("List matrix rates without filter should return all rates") + @DisplayName("List matrix rates without filter should return all rates") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testListMatrixRates_WithoutFilter_ShouldReturnAllRates() throws Exception { @@ -171,6 +190,8 @@ class RateControllerIntegrationTest { } @Test + @Story("List matrix rates with valid filter should return filtered rates") + @DisplayName("List matrix rates with valid filter should return filtered rates") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testListMatrixRates_WithValidFilter_ShouldReturnFilteredRates() throws Exception { @@ -185,6 +206,8 @@ class RateControllerIntegrationTest { @DisplayName("/api/rates/matrix/id - get matrix rate detail") class GetMatrixRatesTest { @Test + @Story("Get matrix rate with valid ID should return rate") + @DisplayName("Get matrix rate with valid ID should return rate") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testGetMatrixRate_WithValidId_ShouldReturnRate() throws Exception { @@ -219,6 +242,8 @@ class RateControllerIntegrationTest { @DisplayName("/api/rates/periods - List validity periods") class ListPeriodsTest { @Test + @Story("List periods should return all periods") + @DisplayName("List periods should return all periods") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testListPeriods_ShouldReturnAllPeriods() throws Exception { @@ -234,6 +259,8 @@ class RateControllerIntegrationTest { @DisplayName("/api/rates/periods/id - Invalidate validity periods") class GetPeriodsTest { @Test + @Story("Invalidate period with valid ID should return OK") + @DisplayName("Invalidate period with valid ID should return OK") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testInvalidatePeriod_WithValidId_ShouldReturnOk() throws Exception { @@ -269,6 +296,8 @@ class RateControllerIntegrationTest { } @Test + @Story("Invalidate period with invalid ID should return 404") + @DisplayName("Invalidate period with invalid ID should return 404") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testInvalidatePeriod_WithInvalidId_ShouldReturn404() throws Exception { @@ -284,6 +313,8 @@ class RateControllerIntegrationTest { @DisplayName("/api/rates/staged_changes - staged changes") class StagedChangesTest { @Test + @Story("Check rate drafts should return boolean") + @DisplayName("Check rate drafts should return boolean") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testCheckRateDrafts_ShouldReturnBoolean() throws Exception { @@ -297,6 +328,8 @@ class RateControllerIntegrationTest { } @Test + @Story("Approve rate drafts should return OK") + @DisplayName("Approve rate drafts should return OK") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testApproveRateDrafts_ShouldReturnOk() throws Exception { @@ -312,6 +345,8 @@ class RateControllerIntegrationTest { @DisplayName("/api/rates/ - Edge cases") class EdgeCasesTest { @Test + @Story("List container rates with invalid date format should return 400") + @DisplayName("List container rates with invalid date format should return 400") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testListContainerRates_WithInvalidDateFormat_ShouldReturn400() throws Exception { @@ -322,6 +357,8 @@ class RateControllerIntegrationTest { } @Test + @Story("List container rates with negative limit should return 400") + @DisplayName("List container rates with negative limit should return 400") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testListContainerRates_WithNegativeLimit_ShouldReturn400() throws Exception { @@ -332,6 +369,8 @@ class RateControllerIntegrationTest { } @Test + @Story("List matrix rates with negative page should return 400") + @DisplayName("List matrix rates with negative page should return 400") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testListMatrixRates_WithNegativePage_ShouldReturn400() throws Exception { @@ -348,6 +387,8 @@ class RateControllerIntegrationTest { @DisplayName("/api/rates/ - Performance tests") class PerformanceTests { @Test + @Story("List container rates with large limit should complete in reasonable time") + @DisplayName("List container rates with large limit should complete in reasonable time") @Sql(scripts = {"classpath:master_data/reduced_rate_setup.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"classpath:master_data/reduced_rate_setup-cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) void testListContainerRates_LargeLimit_ShouldCompleteInReasonableTime() throws Exception { @@ -367,4 +408,4 @@ class RateControllerIntegrationTest { } -} \ No newline at end of file +} diff --git a/src/test/java/de/avatic/lcc/controller/report/ReportingControllerIntegrationTest.java b/src/test/java/de/avatic/lcc/controller/report/ReportingControllerIntegrationTest.java index cca4fd2..28d8d11 100644 --- a/src/test/java/de/avatic/lcc/controller/report/ReportingControllerIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/controller/report/ReportingControllerIntegrationTest.java @@ -1,4 +1,9 @@ package de.avatic.lcc.controller.report; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; + +@Epic("Controller") +@Feature("Report") public class ReportingControllerIntegrationTest { } diff --git a/src/test/java/de/avatic/lcc/database/dialect/MSSQLDialectProviderTest.java b/src/test/java/de/avatic/lcc/database/dialect/MSSQLDialectProviderTest.java index c3d1538..4122364 100644 --- a/src/test/java/de/avatic/lcc/database/dialect/MSSQLDialectProviderTest.java +++ b/src/test/java/de/avatic/lcc/database/dialect/MSSQLDialectProviderTest.java @@ -1,5 +1,8 @@ package de.avatic.lcc.database.dialect; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -13,6 +16,8 @@ import static org.junit.jupiter.api.Assertions.*; /** * Unit tests for {@link MSSQLDialectProvider}. */ +@Epic("Database Layer") +@Feature("MSSQL Dialect") @DisplayName("MSSQLDialectProvider Tests") class MSSQLDialectProviderTest { @@ -28,12 +33,14 @@ class MSSQLDialectProviderTest { class MetadataTests { @Test + @Story("Return correct dialect name") @DisplayName("Should return correct dialect name") void shouldReturnCorrectDialectName() { assertEquals("Microsoft SQL Server", provider.getDialectName()); } @Test + @Story("Return correct driver class name") @DisplayName("Should return correct driver class name") void shouldReturnCorrectDriverClassName() { assertEquals("com.microsoft.sqlserver.jdbc.SQLServerDriver", provider.getDriverClassName()); @@ -45,6 +52,7 @@ class MSSQLDialectProviderTest { class PaginationTests { @Test + @Story("Build correct pagination clause with OFFSET/FETCH") @DisplayName("Should build correct pagination clause with OFFSET/FETCH") void shouldBuildCorrectPaginationClause() { String result = provider.buildPaginationClause(10, 20); @@ -52,6 +60,7 @@ class MSSQLDialectProviderTest { } @Test + @Story("Return pagination parameters in correct order (offset, limit)") @DisplayName("Should return pagination parameters in correct order (offset, limit)") void shouldReturnPaginationParametersInCorrectOrder() { Object[] params = provider.getPaginationParameters(10, 20); @@ -65,6 +74,7 @@ class MSSQLDialectProviderTest { class UpsertOperationTests { @Test + @Story("Build correct MERGE statement") @DisplayName("Should build correct MERGE statement") void shouldBuildCorrectMergeStatement() { List uniqueCols = Arrays.asList("id", "user_id"); @@ -83,6 +93,7 @@ class MSSQLDialectProviderTest { } @Test + @Story("Build correct conditional INSERT statement") @DisplayName("Should build correct conditional INSERT statement") void shouldBuildCorrectInsertIgnoreStatement() { List columns = Arrays.asList("user_id", "group_id"); @@ -102,6 +113,7 @@ class MSSQLDialectProviderTest { class LockingStrategyTests { @Test + @Story("Build WITH (UPDLOCK, READPAST) for SKIP LOCKED equivalent") @DisplayName("Should build WITH (UPDLOCK, READPAST) for SKIP LOCKED equivalent") void shouldBuildSelectForUpdateSkipLocked() { String baseQuery = "SELECT * FROM calculation_job WHERE state = 'CREATED'"; @@ -112,6 +124,7 @@ class MSSQLDialectProviderTest { } @Test + @Story("Build WITH (UPDLOCK, ROWLOCK) for standard locking") @DisplayName("Should build WITH (UPDLOCK, ROWLOCK) for standard locking") void shouldBuildSelectForUpdate() { String baseQuery = "SELECT * FROM calculation_job WHERE id = ?"; @@ -128,12 +141,14 @@ class MSSQLDialectProviderTest { class DateTimeFunctionTests { @Test + @Story("Return GETDATE() for current timestamp") @DisplayName("Should return GETDATE() for current timestamp") void shouldReturnGetDateForCurrentTimestamp() { assertEquals("GETDATE()", provider.getCurrentTimestamp()); } @Test + @Story("Build date subtraction with GETDATE() using DATEADD") @DisplayName("Should build date subtraction with GETDATE() using DATEADD") void shouldBuildDateSubtractionWithGetDate() { String result = provider.buildDateSubtraction(null, "3", SqlDialectProvider.DateUnit.DAY); @@ -141,6 +156,7 @@ class MSSQLDialectProviderTest { } @Test + @Story("Build date subtraction with custom base date") @DisplayName("Should build date subtraction with custom base date") void shouldBuildDateSubtractionWithCustomBaseDate() { String result = provider.buildDateSubtraction("calculation_date", "60", SqlDialectProvider.DateUnit.MINUTE); @@ -148,6 +164,7 @@ class MSSQLDialectProviderTest { } @Test + @Story("Build date addition with GETDATE() using DATEADD") @DisplayName("Should build date addition with GETDATE() using DATEADD") void shouldBuildDateAdditionWithGetDate() { String result = provider.buildDateAddition(null, "7", SqlDialectProvider.DateUnit.DAY); @@ -155,6 +172,7 @@ class MSSQLDialectProviderTest { } @Test + @Story("Build date addition with custom base date") @DisplayName("Should build date addition with custom base date") void shouldBuildDateAdditionWithCustomBaseDate() { String result = provider.buildDateAddition("start_date", "1", SqlDialectProvider.DateUnit.MONTH); @@ -162,6 +180,7 @@ class MSSQLDialectProviderTest { } @Test + @Story("Extract date from column using CAST") @DisplayName("Should extract date from column using CAST") void shouldExtractDateFromColumn() { String result = provider.extractDate("created_at"); @@ -169,6 +188,7 @@ class MSSQLDialectProviderTest { } @Test + @Story("Extract date from expression using CAST") @DisplayName("Should extract date from expression using CAST") void shouldExtractDateFromExpression() { String result = provider.extractDate("GETDATE()"); @@ -181,6 +201,7 @@ class MSSQLDialectProviderTest { class AutoIncrementResetTests { @Test + @Story("Build DBCC CHECKIDENT reset statement") @DisplayName("Should build DBCC CHECKIDENT reset statement") void shouldBuildAutoIncrementResetStatement() { String result = provider.buildAutoIncrementReset("test_table"); @@ -193,6 +214,7 @@ class MSSQLDialectProviderTest { class GeospatialDistanceTests { @Test + @Story("Build Haversine distance calculation in kilometers") @DisplayName("Should build Haversine distance calculation in kilometers") void shouldBuildHaversineDistanceCalculation() { String result = provider.buildHaversineDistance("50.1", "8.6", "node.geo_lat", "node.geo_lng"); @@ -216,6 +238,7 @@ class MSSQLDialectProviderTest { class StringTypeFunctionTests { @Test + @Story("Build CONCAT with multiple expressions") @DisplayName("Should build CONCAT with multiple expressions") void shouldBuildConcatWithMultipleExpressions() { String result = provider.buildConcat("first_name", "' '", "last_name"); @@ -223,6 +246,7 @@ class MSSQLDialectProviderTest { } @Test + @Story("Build CONCAT with single expression") @DisplayName("Should build CONCAT with single expression") void shouldBuildConcatWithSingleExpression() { String result = provider.buildConcat("column_name"); @@ -230,6 +254,7 @@ class MSSQLDialectProviderTest { } @Test + @Story("Cast to string using VARCHAR") @DisplayName("Should cast to string using VARCHAR") void shouldCastToString() { String result = provider.castToString("user_id"); @@ -242,6 +267,7 @@ class MSSQLDialectProviderTest { class BulkOperationTests { @Test + @Story("Return INT max value for MSSQL") @DisplayName("Should return INT max value for MSSQL") void shouldReturnMSSQLIntMaxValue() { // MSSQL returns INT max value (not BIGINT) @@ -249,12 +275,14 @@ class MSSQLDialectProviderTest { } @Test + @Story("Support RETURNING clause via OUTPUT") @DisplayName("Should support RETURNING clause via OUTPUT") void shouldSupportReturningClause() { assertTrue(provider.supportsReturningClause()); } @Test + @Story("Build OUTPUT clause for RETURNING") @DisplayName("Should build OUTPUT clause for RETURNING") void shouldBuildOutputClause() { String result = provider.buildReturningClause("id", "name", "created_at"); @@ -268,6 +296,7 @@ class MSSQLDialectProviderTest { class SchemaDDLTests { @Test + @Story("Return IDENTITY definition") @DisplayName("Should return IDENTITY definition") void shouldReturnIdentityDefinition() { String result = provider.getAutoIncrementDefinition(); @@ -275,6 +304,7 @@ class MSSQLDialectProviderTest { } @Test + @Story("Return DATETIME2 with default for timestamp") @DisplayName("Should return DATETIME2 with default for timestamp") void shouldReturnDateTimeWithDefaultDefinition() { String result = provider.getTimestampDefinition(); @@ -287,12 +317,14 @@ class MSSQLDialectProviderTest { class BooleanLiteralTests { @Test + @Story("Return '1' for boolean true") @DisplayName("Should return '1' for boolean true") void shouldReturnOneForBooleanTrue() { assertEquals("1", provider.getBooleanTrue()); } @Test + @Story("Return '0' for boolean false") @DisplayName("Should return '0' for boolean false") void shouldReturnZeroForBooleanFalse() { assertEquals("0", provider.getBooleanFalse()); diff --git a/src/test/java/de/avatic/lcc/database/dialect/MySQLDialectProviderTest.java b/src/test/java/de/avatic/lcc/database/dialect/MySQLDialectProviderTest.java index 109abe2..b33f88e 100644 --- a/src/test/java/de/avatic/lcc/database/dialect/MySQLDialectProviderTest.java +++ b/src/test/java/de/avatic/lcc/database/dialect/MySQLDialectProviderTest.java @@ -1,5 +1,8 @@ package de.avatic.lcc.database.dialect; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -13,6 +16,8 @@ import static org.junit.jupiter.api.Assertions.*; /** * Unit tests for {@link MySQLDialectProvider}. */ +@Epic("Database Layer") +@Feature("MySQL Dialect") @DisplayName("MySQLDialectProvider Tests") class MySQLDialectProviderTest { @@ -28,12 +33,14 @@ class MySQLDialectProviderTest { class MetadataTests { @Test + @Story("Return correct dialect name") @DisplayName("Should return correct dialect name") void shouldReturnCorrectDialectName() { assertEquals("MySQL", provider.getDialectName()); } @Test + @Story("Return correct driver class name") @DisplayName("Should return correct driver class name") void shouldReturnCorrectDriverClassName() { assertEquals("com.mysql.cj.jdbc.Driver", provider.getDriverClassName()); @@ -45,6 +52,7 @@ class MySQLDialectProviderTest { class PaginationTests { @Test + @Story("Build correct pagination clause") @DisplayName("Should build correct pagination clause") void shouldBuildCorrectPaginationClause() { String result = provider.buildPaginationClause(10, 20); @@ -52,6 +60,7 @@ class MySQLDialectProviderTest { } @Test + @Story("Return pagination parameters in correct order") @DisplayName("Should return pagination parameters in correct order") void shouldReturnPaginationParametersInCorrectOrder() { Object[] params = provider.getPaginationParameters(10, 20); @@ -64,6 +73,7 @@ class MySQLDialectProviderTest { class UpsertOperationTests { @Test + @Story("Build correct upsert statement") @DisplayName("Should build correct upsert statement") void shouldBuildCorrectUpsertStatement() { List uniqueCols = Arrays.asList("id", "user_id"); @@ -81,6 +91,7 @@ class MySQLDialectProviderTest { } @Test + @Story("Build correct insert ignore statement") @DisplayName("Should build correct insert ignore statement") void shouldBuildCorrectInsertIgnoreStatement() { List columns = Arrays.asList("user_id", "group_id"); @@ -97,6 +108,7 @@ class MySQLDialectProviderTest { class LockingStrategyTests { @Test + @Story("Build SELECT FOR UPDATE SKIP LOCKED") @DisplayName("Should build SELECT FOR UPDATE SKIP LOCKED") void shouldBuildSelectForUpdateSkipLocked() { String baseQuery = "SELECT * FROM calculation_job WHERE state = 'CREATED'"; @@ -107,6 +119,7 @@ class MySQLDialectProviderTest { } @Test + @Story("Build SELECT FOR UPDATE") @DisplayName("Should build SELECT FOR UPDATE") void shouldBuildSelectForUpdate() { String baseQuery = "SELECT * FROM calculation_job WHERE id = ?"; @@ -122,12 +135,14 @@ class MySQLDialectProviderTest { class DateTimeFunctionTests { @Test + @Story("Return NOW() for current timestamp") @DisplayName("Should return NOW() for current timestamp") void shouldReturnNowForCurrentTimestamp() { assertEquals("NOW()", provider.getCurrentTimestamp()); } @Test + @Story("Build date subtraction with NOW()") @DisplayName("Should build date subtraction with NOW()") void shouldBuildDateSubtractionWithNow() { String result = provider.buildDateSubtraction(null, "3", SqlDialectProvider.DateUnit.DAY); @@ -135,6 +150,7 @@ class MySQLDialectProviderTest { } @Test + @Story("Build date subtraction with custom base date") @DisplayName("Should build date subtraction with custom base date") void shouldBuildDateSubtractionWithCustomBaseDate() { String result = provider.buildDateSubtraction("calculation_date", "60", SqlDialectProvider.DateUnit.MINUTE); @@ -142,6 +158,7 @@ class MySQLDialectProviderTest { } @Test + @Story("Build date addition with NOW()") @DisplayName("Should build date addition with NOW()") void shouldBuildDateAdditionWithNow() { String result = provider.buildDateAddition(null, "7", SqlDialectProvider.DateUnit.DAY); @@ -149,6 +166,7 @@ class MySQLDialectProviderTest { } @Test + @Story("Build date addition with custom base date") @DisplayName("Should build date addition with custom base date") void shouldBuildDateAdditionWithCustomBaseDate() { String result = provider.buildDateAddition("start_date", "1", SqlDialectProvider.DateUnit.MONTH); @@ -156,6 +174,7 @@ class MySQLDialectProviderTest { } @Test + @Story("Extract date from column") @DisplayName("Should extract date from column") void shouldExtractDateFromColumn() { String result = provider.extractDate("created_at"); @@ -163,6 +182,7 @@ class MySQLDialectProviderTest { } @Test + @Story("Extract date from expression") @DisplayName("Should extract date from expression") void shouldExtractDateFromExpression() { String result = provider.extractDate("NOW()"); @@ -175,6 +195,7 @@ class MySQLDialectProviderTest { class AutoIncrementResetTests { @Test + @Story("Build auto-increment reset statement") @DisplayName("Should build auto-increment reset statement") void shouldBuildAutoIncrementResetStatement() { String result = provider.buildAutoIncrementReset("test_table"); @@ -187,6 +208,7 @@ class MySQLDialectProviderTest { class GeospatialDistanceTests { @Test + @Story("Build Haversine distance calculation in kilometers") @DisplayName("Should build Haversine distance calculation in kilometers") void shouldBuildHaversineDistanceCalculation() { String result = provider.buildHaversineDistance("50.1", "8.6", "node.geo_lat", "node.geo_lng"); @@ -210,6 +232,7 @@ class MySQLDialectProviderTest { class StringTypeFunctionTests { @Test + @Story("Build CONCAT with multiple expressions") @DisplayName("Should build CONCAT with multiple expressions") void shouldBuildConcatWithMultipleExpressions() { String result = provider.buildConcat("first_name", "' '", "last_name"); @@ -217,6 +240,7 @@ class MySQLDialectProviderTest { } @Test + @Story("Build CONCAT with single expression") @DisplayName("Should build CONCAT with single expression") void shouldBuildConcatWithSingleExpression() { String result = provider.buildConcat("column_name"); @@ -224,6 +248,7 @@ class MySQLDialectProviderTest { } @Test + @Story("Cast to string") @DisplayName("Should cast to string") void shouldCastToString() { String result = provider.castToString("user_id"); @@ -236,18 +261,21 @@ class MySQLDialectProviderTest { class BulkOperationTests { @Test + @Story("Return MySQL BIGINT UNSIGNED max value") @DisplayName("Should return MySQL BIGINT UNSIGNED max value") void shouldReturnMySQLBigIntUnsignedMaxValue() { assertEquals("18446744073709551615", provider.getMaxLimitValue()); } @Test + @Story("Not support RETURNING clause") @DisplayName("Should not support RETURNING clause") void shouldNotSupportReturningClause() { assertFalse(provider.supportsReturningClause()); } @Test + @Story("Throw exception when building RETURNING clause") @DisplayName("Should throw exception when building RETURNING clause") void shouldThrowExceptionWhenBuildingReturningClause() { UnsupportedOperationException exception = assertThrows( @@ -265,6 +293,7 @@ class MySQLDialectProviderTest { class SchemaDDLTests { @Test + @Story("Return AUTO_INCREMENT definition") @DisplayName("Should return AUTO_INCREMENT definition") void shouldReturnAutoIncrementDefinition() { String result = provider.getAutoIncrementDefinition(); @@ -272,10 +301,11 @@ class MySQLDialectProviderTest { } @Test + @Story("Return TIMESTAMP with ON UPDATE definition") @DisplayName("Should return TIMESTAMP with ON UPDATE definition") void shouldReturnTimestampWithOnUpdateDefinition() { String result = provider.getTimestampDefinition(); assertEquals("TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP", result); } } -} \ No newline at end of file +} diff --git a/src/test/java/de/avatic/lcc/e2e/tests/CalculationWorkflowE2ETest.java b/src/test/java/de/avatic/lcc/e2e/tests/CalculationWorkflowE2ETest.java index 758f172..32f839d 100644 --- a/src/test/java/de/avatic/lcc/e2e/tests/CalculationWorkflowE2ETest.java +++ b/src/test/java/de/avatic/lcc/e2e/tests/CalculationWorkflowE2ETest.java @@ -8,6 +8,9 @@ import de.avatic.lcc.e2e.pages.ResultsPage; import de.avatic.lcc.e2e.testdata.DestinationInput; import de.avatic.lcc.e2e.testdata.TestCase; import de.avatic.lcc.e2e.testdata.TestCases; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -25,6 +28,8 @@ import java.util.stream.Stream; *

Run with: {@code mvn test -Dtest=CalculationWorkflowE2ETest -Dgroups=e2e -Dspring.profiles.active=test,dev,mysql} */ @DisplayName("Calculation Workflow E2E Tests") +@Epic("End-to-End") +@Feature("Calculation Workflow") class CalculationWorkflowE2ETest extends AbstractE2ETest { private static final Logger logger = Logger.getLogger(CalculationWorkflowE2ETest.class.getName()); @@ -35,6 +40,7 @@ class CalculationWorkflowE2ETest extends AbstractE2ETest { @ParameterizedTest(name = "Testfall {0}: {1}") @MethodSource("provideTestCases") + @Story("Calculation workflow") @DisplayName("Calculation workflow") void testCalculationWorkflow(String id, String name, TestCase testCase) { logger.info(() -> "Starting test case: " + id + " - " + name); diff --git a/src/test/java/de/avatic/lcc/e2e/tests/DeviationAnalysisE2ETest.java b/src/test/java/de/avatic/lcc/e2e/tests/DeviationAnalysisE2ETest.java index f2bc4bc..84e68ff 100644 --- a/src/test/java/de/avatic/lcc/e2e/tests/DeviationAnalysisE2ETest.java +++ b/src/test/java/de/avatic/lcc/e2e/tests/DeviationAnalysisE2ETest.java @@ -8,6 +8,9 @@ import de.avatic.lcc.e2e.testdata.DestinationInput; import de.avatic.lcc.e2e.testdata.TestCase; import de.avatic.lcc.e2e.testdata.TestCases; import de.avatic.lcc.e2e.util.DeviationReport; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; @@ -24,6 +27,8 @@ import java.util.logging.Logger; */ @DisplayName("Deviation Analysis E2E Test") @Tag("analysis") +@Epic("End-to-End") +@Feature("Deviation Analysis") class DeviationAnalysisE2ETest extends AbstractE2ETest { private static final Logger logger = Logger.getLogger(DeviationAnalysisE2ETest.class.getName()); @@ -31,6 +36,7 @@ class DeviationAnalysisE2ETest extends AbstractE2ETest { private static final int POLL_INTERVAL_MS = 2000; @Test + @Story("Analyze deviations across all test cases") @DisplayName("Analyze deviations across all test cases") void analyzeDeviations() { DeviationReport report = new DeviationReport(); diff --git a/src/test/java/de/avatic/lcc/e2e/tests/SmokeE2ETest.java b/src/test/java/de/avatic/lcc/e2e/tests/SmokeE2ETest.java index 15a02a0..51a98f6 100644 --- a/src/test/java/de/avatic/lcc/e2e/tests/SmokeE2ETest.java +++ b/src/test/java/de/avatic/lcc/e2e/tests/SmokeE2ETest.java @@ -1,6 +1,9 @@ package de.avatic.lcc.e2e.tests; import de.avatic.lcc.e2e.pages.AssistantPage; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; @@ -19,11 +22,14 @@ import static org.junit.jupiter.api.Assertions.assertTrue; */ @Tag("smoke") @DisplayName("Smoke E2E Tests") +@Epic("End-to-End") +@Feature("Smoke Tests") class SmokeE2ETest extends AbstractE2ETest { private static final Logger logger = Logger.getLogger(SmokeE2ETest.class.getName()); @Test + @Story("Application is accessible") @DisplayName("Application is accessible") void testApplicationIsAccessible() { page.navigate(getBaseUrl()); @@ -34,6 +40,7 @@ class SmokeE2ETest extends AbstractE2ETest { } @Test + @Story("Login was successful") @DisplayName("Login was successful") void testLoginWasSuccessful() { // Login happens in @BeforeEach via AbstractE2ETest @@ -43,6 +50,7 @@ class SmokeE2ETest extends AbstractE2ETest { } @Test + @Story("Navigate to assistant page") @DisplayName("Navigate to assistant page") void testNavigateToAssistant() { // Navigate to assistant @@ -54,6 +62,7 @@ class SmokeE2ETest extends AbstractE2ETest { } @Test + @Story("Part number search is functional") @DisplayName("Part number search is functional") void testPartNumberSearchFunctional() { // Navigate to assistant @@ -76,6 +85,7 @@ class SmokeE2ETest extends AbstractE2ETest { } @Test + @Story("Test materials exist in database") @DisplayName("Test materials exist in database") void testMaterialsExistInDatabase() { // Check if our test materials are in the database diff --git a/src/test/java/de/avatic/lcc/repositories/CountryRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/CountryRepositoryIntegrationTest.java index ff6d406..53138d1 100644 --- a/src/test/java/de/avatic/lcc/repositories/CountryRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/CountryRepositoryIntegrationTest.java @@ -5,6 +5,10 @@ import de.avatic.lcc.model.db.country.IsoCode; import de.avatic.lcc.repositories.country.CountryRepository; import de.avatic.lcc.repositories.pagination.SearchQueryPagination; import de.avatic.lcc.repositories.pagination.SearchQueryResult; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -30,12 +34,16 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=CountryRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Master Data") class CountryRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired private CountryRepository countryRepository; @Test + @Story("Get by id") + @DisplayName("Get by id") void testGetById() { // Given: Country with id=1 should exist (from Flyway migrations) Integer countryId = 1; @@ -51,6 +59,8 @@ class CountryRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Get by id not found") + @DisplayName("Get by id not found") void testGetByIdNotFound() { // Given: Non-existent country ID Integer nonExistentId = 99999; @@ -63,6 +73,8 @@ class CountryRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Get by iso code") + @DisplayName("Get by iso code") void testGetByIsoCode() { // Given: Germany should exist (from Flyway migrations) IsoCode isoCode = IsoCode.DE; @@ -77,6 +89,8 @@ class CountryRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Get by iso code not found") + @DisplayName("Get by iso code not found") void testGetByIsoCodeNotFound() { // Given: Invalid ISO code that shouldn't exist // Note: This will throw IllegalArgumentException if the enum doesn't exist @@ -91,6 +105,8 @@ class CountryRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("List all countries") + @DisplayName("List all countries") void testListAllCountries() { // When: List all countries List countries = countryRepository.listAllCountries(); @@ -109,6 +125,8 @@ class CountryRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("List countries with pagination") + @DisplayName("List countries with pagination") void testListCountriesWithPagination() { // Given: Pagination settings (page 1, size 5) SearchQueryPagination pagination = new SearchQueryPagination(1, 5); @@ -126,6 +144,8 @@ class CountryRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("List countries with filter") + @DisplayName("List countries with filter") void testListCountriesWithFilter() { // Given: Filter for "German" or "Deutschland" String filter = "German"; @@ -149,6 +169,8 @@ class CountryRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("List countries with filter and pagination") + @DisplayName("List countries with filter and pagination") void testListCountriesWithFilterAndPagination() { // Given: Filter + Pagination String filter = "a"; // Should match many countries @@ -172,6 +194,8 @@ class CountryRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Boolean literal compatibility") + @DisplayName("Boolean literal compatibility") void testBooleanLiteralCompatibility() { // This test verifies that boolean literals work across MySQL (TRUE/FALSE) and MSSQL (1/0) @@ -189,6 +213,8 @@ class CountryRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Get by iso codes") + @DisplayName("Get by iso codes") void testGetByIsoCodes() { // Given: List of ISO codes List isoCodes = List.of(IsoCode.DE, IsoCode.FR, IsoCode.US); @@ -208,6 +234,8 @@ class CountryRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Get by iso codes empty list") + @DisplayName("Get by iso codes empty list") void testGetByIsoCodesEmptyList() { // Given: Empty list List emptyList = List.of(); diff --git a/src/test/java/de/avatic/lcc/repositories/DatabaseConfigurationSmokeTest.java b/src/test/java/de/avatic/lcc/repositories/DatabaseConfigurationSmokeTest.java index 1e73eda..18ece36 100644 --- a/src/test/java/de/avatic/lcc/repositories/DatabaseConfigurationSmokeTest.java +++ b/src/test/java/de/avatic/lcc/repositories/DatabaseConfigurationSmokeTest.java @@ -1,6 +1,10 @@ package de.avatic.lcc.repositories; import de.avatic.lcc.database.dialect.SqlDialectProvider; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; @@ -22,6 +26,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=DatabaseConfigurationSmokeTest * */ +@Epic("Repository") +@Feature("Infrastructure") class DatabaseConfigurationSmokeTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -31,6 +37,8 @@ class DatabaseConfigurationSmokeTest extends AbstractRepositoryIntegrationTest { private SqlDialectProvider dialectProvider; @Test + @Story("Database connection is established") + @DisplayName("Database connection is established") void testDatabaseConnectionIsEstablished() { // When: Query database Integer result = jdbcTemplate.queryForObject("SELECT 1", Integer.class); @@ -41,6 +49,8 @@ class DatabaseConfigurationSmokeTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Flyway migrations ran successfully") + @DisplayName("Flyway migrations ran successfully") void testFlywayMigrationsRanSuccessfully() { // When: Check if core tables exist Integer propertySetCount = jdbcTemplate.queryForObject( @@ -51,6 +61,8 @@ class DatabaseConfigurationSmokeTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Countries were loaded from migrations") + @DisplayName("Countries were loaded from migrations") void testCountriesWereLoadedFromMigrations() { // When: Count countries Integer countryCount = jdbcTemplate.queryForObject( @@ -63,6 +75,8 @@ class DatabaseConfigurationSmokeTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Nodes were loaded from migrations") + @DisplayName("Nodes were loaded from migrations") void testNodesWereLoadedFromMigrations() { // When: Count nodes Integer nodeCount = jdbcTemplate.queryForObject( @@ -75,6 +89,8 @@ class DatabaseConfigurationSmokeTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Correct SQL dialect provider is loaded") + @DisplayName("Correct SQL dialect provider is loaded") void testCorrectSqlDialectProviderIsLoaded() { // Debug: Print active profiles String[] activeProfiles = jdbcTemplate.getDataSource() != null ? @@ -97,6 +113,8 @@ class DatabaseConfigurationSmokeTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Boolean literal in query") + @DisplayName("Boolean literal in query") void testBooleanLiteralInQuery() { // When: Query with boolean literal from dialect provider String query = "SELECT COUNT(*) FROM node WHERE is_deprecated = " + @@ -109,6 +127,8 @@ class DatabaseConfigurationSmokeTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Pagination query") + @DisplayName("Pagination query") void testPaginationQuery() { // When: Execute query with pagination (requires ORDER BY in MSSQL) String paginationClause = dialectProvider.buildPaginationClause(5, 0); diff --git a/src/test/java/de/avatic/lcc/repositories/DistanceMatrixRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/DistanceMatrixRepositoryIntegrationTest.java index 0a0e8bc..d46e957 100644 --- a/src/test/java/de/avatic/lcc/repositories/DistanceMatrixRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/DistanceMatrixRepositoryIntegrationTest.java @@ -3,7 +3,11 @@ package de.avatic.lcc.repositories; import de.avatic.lcc.model.db.nodes.Distance; import de.avatic.lcc.model.db.nodes.DistanceMatrixState; import de.avatic.lcc.model.db.nodes.Node; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -29,6 +33,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=DistanceMatrixRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Master Data") class DistanceMatrixRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -52,6 +58,8 @@ class DistanceMatrixRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Get distance node to node") + @DisplayName("Get distance node to node") void testGetDistanceNodeToNode() { // Given: Create distance entry Distance distance = createTestDistance(testNodeId1, testNodeId2, null, null, @@ -73,6 +81,8 @@ class DistanceMatrixRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Get distance user node to user node") + @DisplayName("Get distance user node to user node") void testGetDistanceUserNodeToUserNode() { // Given: Create user node distance entry Distance distance = createTestDistance(null, null, testUserNodeId1, testUserNodeId2, @@ -93,6 +103,8 @@ class DistanceMatrixRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Get distance not found") + @DisplayName("Get distance not found") void testGetDistanceNotFound() { // When: Get non-existent distance Node from = createNodeObject(testNodeId1); @@ -104,6 +116,8 @@ class DistanceMatrixRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Save distance insert") + @DisplayName("Save distance insert") void testSaveDistanceInsert() { // Given: New distance Distance distance = createTestDistance(testNodeId1, testNodeId2, null, null, @@ -124,6 +138,8 @@ class DistanceMatrixRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Save distance update") + @DisplayName("Save distance update") void testSaveDistanceUpdate() { // Given: Existing distance Distance distance = createTestDistance(testNodeId1, testNodeId2, null, null, @@ -148,6 +164,8 @@ class DistanceMatrixRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Update retries") + @DisplayName("Update retries") void testUpdateRetries() { // Given: Insert distance Distance distance = createTestDistance(testNodeId1, testNodeId2, null, null, @@ -171,6 +189,8 @@ class DistanceMatrixRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Distance states") + @DisplayName("Distance states") void testDistanceStates() { // Test different states for (DistanceMatrixState state : new DistanceMatrixState[]{ @@ -199,6 +219,8 @@ class DistanceMatrixRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Mixed node types") + @DisplayName("Mixed node types") void testMixedNodeTypes() { // Given: Distance from regular node to user node Distance distance = createTestDistance(testNodeId1, null, null, testUserNodeId1, @@ -221,6 +243,8 @@ class DistanceMatrixRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Timestamp handling") + @DisplayName("Timestamp handling") void testTimestampHandling() { // Given: Create distance with timestamp Distance distance = createTestDistance(testNodeId1, testNodeId2, null, null, diff --git a/src/test/java/de/avatic/lcc/repositories/MaterialRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/MaterialRepositoryIntegrationTest.java index 350fdb2..e5fd750 100644 --- a/src/test/java/de/avatic/lcc/repositories/MaterialRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/MaterialRepositoryIntegrationTest.java @@ -3,6 +3,10 @@ package de.avatic.lcc.repositories; import de.avatic.lcc.model.db.materials.Material; import de.avatic.lcc.repositories.pagination.SearchQueryPagination; import de.avatic.lcc.repositories.pagination.SearchQueryResult; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -27,12 +31,16 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=MaterialRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Master Data") class MaterialRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired private MaterialRepository materialRepository; @Test + @Story("Insert and retrieve") + @DisplayName("Insert and retrieve") void testInsertAndRetrieve() { // Given: Create material Material material = createTestMaterial("TEST-001", "Test Material 1"); @@ -51,6 +59,8 @@ class MaterialRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Update") + @DisplayName("Update") void testUpdate() { // Given: Insert material Material material = createTestMaterial("TEST-002", "Original Name"); @@ -69,6 +79,8 @@ class MaterialRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Update by part number") + @DisplayName("Update by part number") void testUpdateByPartNumber() { // Given: Insert material Material material = createTestMaterial("TEST-003", "Original Name"); @@ -85,6 +97,8 @@ class MaterialRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Set deprecated by id") + @DisplayName("Set deprecated by id") void testSetDeprecatedById() { // Given: Insert material Material material = createTestMaterial("TEST-004", "Material to Deprecate"); @@ -108,6 +122,8 @@ class MaterialRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Delete by id") + @DisplayName("Delete by id") void testDeleteById() { // Given: Insert material Material material = createTestMaterial("TEST-005", "Material to Delete"); @@ -127,6 +143,8 @@ class MaterialRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("List materials with pagination") + @DisplayName("List materials with pagination") void testListMaterialsWithPagination() { // Given: Insert multiple materials for (int i = 1; i <= 5; i++) { @@ -148,6 +166,8 @@ class MaterialRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("List materials with filter") + @DisplayName("List materials with filter") void testListMaterialsWithFilter() { // Given: Insert materials with different names Material material1 = createTestMaterial("FILTER-001", "Special Widget"); @@ -177,6 +197,8 @@ class MaterialRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("List materials exclude deprecated") + @DisplayName("List materials exclude deprecated") void testListMaterialsExcludeDeprecated() { // Given: Insert deprecated and active materials Material deprecated = createTestMaterial("DEPR-001", "Deprecated Material"); @@ -200,6 +222,8 @@ class MaterialRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("List all materials") + @DisplayName("List all materials") void testListAllMaterials() { // Given: Insert materials Material material1 = createTestMaterial("ALL-001", "Material 1"); @@ -225,6 +249,8 @@ class MaterialRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Get by part number") + @DisplayName("Get by part number") void testGetByPartNumber() { // Given: Insert material Material material = createTestMaterial("BYPART-001", "Get By Part"); @@ -240,6 +266,8 @@ class MaterialRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Get by part number not found") + @DisplayName("Get by part number not found") void testGetByPartNumberNotFound() { // When: Get by non-existent part number Optional result = materialRepository.getByPartNumber("NONEXISTENT-999"); @@ -249,6 +277,8 @@ class MaterialRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Get by part numbers") + @DisplayName("Get by part numbers") void testGetByPartNumbers() { // Given: Insert multiple materials Material material1 = createTestMaterial("BULK-001", "Bulk Material 1"); @@ -276,6 +306,8 @@ class MaterialRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Get by part numbers empty list") + @DisplayName("Get by part numbers empty list") void testGetByPartNumbersEmptyList() { // When: Get by empty list List materials = materialRepository.getByPartNumbers(List.of()); @@ -286,6 +318,8 @@ class MaterialRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Delete by ids") + @DisplayName("Delete by ids") void testDeleteByIds() { // Given: Insert multiple materials Material material1 = createTestMaterial("DELETE-001", "To Delete 1"); @@ -309,6 +343,8 @@ class MaterialRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Find missing ids") + @DisplayName("Find missing ids") void testFindMissingIds() { // Given: Insert some materials Material material1 = createTestMaterial("MISSING-001", "Material 1"); @@ -328,6 +364,8 @@ class MaterialRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Find missing ids empty list") + @DisplayName("Find missing ids empty list") void testFindMissingIdsEmptyList() { // When: Check empty list List missingIds = materialRepository.findMissingIds(List.of()); diff --git a/src/test/java/de/avatic/lcc/repositories/NodeRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/NodeRepositoryIntegrationTest.java index 472b02b..b908e0b 100644 --- a/src/test/java/de/avatic/lcc/repositories/NodeRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/NodeRepositoryIntegrationTest.java @@ -4,6 +4,10 @@ import de.avatic.lcc.dto.generic.NodeType; import de.avatic.lcc.repositories.pagination.SearchQueryPagination; import de.avatic.lcc.repositories.pagination.SearchQueryResult; import de.avatic.lcc.model.db.nodes.Node; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -28,12 +32,16 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=NodeRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Master Data") class NodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired private NodeRepository nodeRepository; @Test + @Story("Insert and retrieve node") + @DisplayName("Insert and retrieve node") void testInsertAndRetrieveNode() { // Given Node node = new Node(); @@ -58,6 +66,8 @@ class NodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Update node") + @DisplayName("Update node") void testUpdateNode() { // Given: Create a node first Node node = createTestNode("Original Name", "Original Address", "50.0", "10.0"); @@ -76,6 +86,8 @@ class NodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Deprecate node") + @DisplayName("Deprecate node") void testDeprecateNode() { // Given: Create a node Node node = createTestNode("Node to Deprecate", "Address", "50.0", "10.0"); @@ -90,6 +102,8 @@ class NodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("List nodes with pagination") + @DisplayName("List nodes with pagination") void testListNodesWithPagination() { // Given: Create multiple nodes for (int i = 1; i <= 5; i++) { @@ -108,6 +122,8 @@ class NodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Search node with filter") + @DisplayName("Search node with filter") void testSearchNodeWithFilter() { // Given: Create nodes with different names Node node1 = createTestNode("Berlin Node Test", "Berlin Street 1", "52.5200", "13.4050"); @@ -127,6 +143,8 @@ class NodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Get by distance with haversine formula") + @DisplayName("Get by distance with haversine formula") void testGetByDistanceWithHaversineFormula() { // Given: Create a reference node (Berlin) Node referenceNode = createTestNode("Berlin Distance Test", "Berlin Center", "52.5200", "13.4050"); @@ -155,6 +173,8 @@ class NodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Get by distance excluding reference node") + @DisplayName("Get by distance excluding reference node") void testGetByDistanceExcludingReferenceNode() { // Given: Create reference node Node referenceNode = createTestNode("Reference Node Distance", "Ref Address", "50.0", "10.0"); @@ -175,6 +195,8 @@ class NodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Boolean literal compatibility") + @DisplayName("Boolean literal compatibility") void testBooleanLiteralCompatibility() { // Given: Create deprecated and non-deprecated nodes Node deprecatedNode = createTestNode("Deprecated Boolean Test", "Addr1", "50.0", "10.0"); diff --git a/src/test/java/de/avatic/lcc/repositories/NomenclatureRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/NomenclatureRepositoryIntegrationTest.java index ad5ac1f..9845b9f 100644 --- a/src/test/java/de/avatic/lcc/repositories/NomenclatureRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/NomenclatureRepositoryIntegrationTest.java @@ -1,6 +1,10 @@ package de.avatic.lcc.repositories; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -22,6 +26,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=NomenclatureRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Master Data") class NomenclatureRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -48,6 +54,8 @@ class NomenclatureRepositoryIntegrationTest extends AbstractRepositoryIntegratio } @Test + @Story("Search HS code with exact match") + @DisplayName("Search HS code with exact match") void testSearchHsCodeWithExactMatch() { // Given: Search for exact HS code prefix String search = "847130"; @@ -63,6 +71,8 @@ class NomenclatureRepositoryIntegrationTest extends AbstractRepositoryIntegratio } @Test + @Story("Search HS code with partial match") + @DisplayName("Search HS code with partial match") void testSearchHsCodeWithPartialMatch() { // Given: Search for partial HS code String search = "8471"; @@ -82,6 +92,8 @@ class NomenclatureRepositoryIntegrationTest extends AbstractRepositoryIntegratio } @Test + @Story("Search HS code ordering") + @DisplayName("Search HS code ordering") void testSearchHsCodeOrdering() { // Given: Search for codes String search = "8471"; @@ -101,6 +113,8 @@ class NomenclatureRepositoryIntegrationTest extends AbstractRepositoryIntegratio } @Test + @Story("Search HS code with pagination") + @DisplayName("Search HS code with pagination") void testSearchHsCodeWithPagination() { // Given: Search that returns many results String search = "8471"; @@ -114,6 +128,8 @@ class NomenclatureRepositoryIntegrationTest extends AbstractRepositoryIntegratio } @Test + @Story("Search HS code not found") + @DisplayName("Search HS code not found") void testSearchHsCodeNotFound() { // Given: Search for non-existent HS code String search = "9999"; @@ -127,6 +143,8 @@ class NomenclatureRepositoryIntegrationTest extends AbstractRepositoryIntegratio } @Test + @Story("Search HS code different prefix") + @DisplayName("Search HS code different prefix") void testSearchHsCodeDifferentPrefix() { // Given: Search for different category (furniture) String search = "9403"; @@ -142,6 +160,8 @@ class NomenclatureRepositoryIntegrationTest extends AbstractRepositoryIntegratio } @Test + @Story("Search HS code concat function") + @DisplayName("Search HS code concat function") void testSearchHsCodeConcatFunction() { // This test verifies that the CONCAT function works across both databases // MySQL: CONCAT(?, '%') diff --git a/src/test/java/de/avatic/lcc/repositories/PackagingDimensionRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/PackagingDimensionRepositoryIntegrationTest.java index 2f08e41..93902ea 100644 --- a/src/test/java/de/avatic/lcc/repositories/PackagingDimensionRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/PackagingDimensionRepositoryIntegrationTest.java @@ -5,6 +5,10 @@ import de.avatic.lcc.model.db.packaging.PackagingType; import de.avatic.lcc.model.db.utils.DimensionUnit; import de.avatic.lcc.model.db.utils.WeightUnit; import de.avatic.lcc.repositories.packaging.PackagingDimensionRepository; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -26,12 +30,16 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=PackagingDimensionRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Master Data") class PackagingDimensionRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired private PackagingDimensionRepository packagingDimensionRepository; @Test + @Story("Insert and retrieve") + @DisplayName("Insert and retrieve") void testInsertAndRetrieve() { // Given: Create packaging dimension PackagingDimension dimension = createTestDimension(1000, 500, 300, 10000, 1); @@ -60,6 +68,8 @@ class PackagingDimensionRepositoryIntegrationTest extends AbstractRepositoryInte } @Test + @Story("Update") + @DisplayName("Update") void testUpdate() { // Given: Insert dimension PackagingDimension dimension = createTestDimension(1000, 500, 300, 10000, 1); @@ -84,6 +94,8 @@ class PackagingDimensionRepositoryIntegrationTest extends AbstractRepositoryInte } @Test + @Story("Set deprecated by id") + @DisplayName("Set deprecated by id") void testSetDeprecatedById() { // Given: Insert dimension PackagingDimension dimension = createTestDimension(1000, 500, 300, 10000, 1); @@ -101,6 +113,8 @@ class PackagingDimensionRepositoryIntegrationTest extends AbstractRepositoryInte } @Test + @Story("Get by id not found") + @DisplayName("Get by id not found") void testGetByIdNotFound() { // When: Get by non-existent ID Optional result = packagingDimensionRepository.getById(99999); @@ -110,6 +124,8 @@ class PackagingDimensionRepositoryIntegrationTest extends AbstractRepositoryInte } @Test + @Story("Different packaging types") + @DisplayName("Different packaging types") void testDifferentPackagingTypes() { // Given: Insert dimensions with different types PackagingDimension hu = createTestDimension(1000, 500, 300, 10000, 1); @@ -130,6 +146,8 @@ class PackagingDimensionRepositoryIntegrationTest extends AbstractRepositoryInte } @Test + @Story("Different units") + @DisplayName("Different units") void testDifferentUnits() { // Given: Insert dimension with different units (meters and grams instead of cm and kg) PackagingDimension dimension = createTestDimension(1, 1, 1, 1000, 1); // meters and grams @@ -150,6 +168,8 @@ class PackagingDimensionRepositoryIntegrationTest extends AbstractRepositoryInte } @Test + @Story("Update with deprecation") + @DisplayName("Update with deprecation") void testUpdateWithDeprecation() { // Given: Insert dimension PackagingDimension dimension = createTestDimension(1000, 500, 300, 10000, 1); diff --git a/src/test/java/de/avatic/lcc/repositories/PackagingRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/PackagingRepositoryIntegrationTest.java index 59bca4f..0530d38 100644 --- a/src/test/java/de/avatic/lcc/repositories/PackagingRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/PackagingRepositoryIntegrationTest.java @@ -4,7 +4,11 @@ import de.avatic.lcc.model.db.packaging.Packaging; import de.avatic.lcc.repositories.packaging.PackagingRepository; import de.avatic.lcc.repositories.pagination.SearchQueryPagination; import de.avatic.lcc.repositories.pagination.SearchQueryResult; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -28,6 +32,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=PackagingRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Master Data") class PackagingRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -57,6 +63,8 @@ class PackagingRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("Insert and retrieve") + @DisplayName("Insert and retrieve") void testInsertAndRetrieve() { // Given: Create packaging Packaging packaging = new Packaging(); @@ -86,6 +94,8 @@ class PackagingRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("Update") + @DisplayName("Update") void testUpdate() { // Given: Create and insert packaging Packaging packaging = createTestPackaging(testMaterialId1, testNodeId1, testDimensionId1, testDimensionId1, false); @@ -104,6 +114,8 @@ class PackagingRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("Set deprecated by id") + @DisplayName("Set deprecated by id") void testSetDeprecatedById() { // Given: Create packaging Packaging packaging = createTestPackaging(testMaterialId1, testNodeId1, testDimensionId1, testDimensionId1, false); @@ -119,6 +131,8 @@ class PackagingRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("List packaging with pagination") + @DisplayName("List packaging with pagination") void testListPackagingWithPagination() { // Given: Create multiple packagings for (int i = 0; i < 5; i++) { @@ -139,6 +153,8 @@ class PackagingRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("List packaging filter by material id") + @DisplayName("List packaging filter by material id") void testListPackagingFilterByMaterialId() { // Given: Create packagings with different materials Packaging packaging1 = createTestPackaging(testMaterialId1, testNodeId1, testDimensionId1, testDimensionId1, false); @@ -161,6 +177,8 @@ class PackagingRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("List packaging filter by supplier id") + @DisplayName("List packaging filter by supplier id") void testListPackagingFilterBySupplierId() { // Given: Create packagings with different suppliers Packaging packaging1 = createTestPackaging(testMaterialId1, testNodeId1, testDimensionId1, testDimensionId1, false); @@ -183,6 +201,8 @@ class PackagingRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("List packaging exclude deprecated") + @DisplayName("List packaging exclude deprecated") void testListPackagingExcludeDeprecated() { // Given: Create deprecated and non-deprecated packagings Packaging deprecated = createTestPackaging(testMaterialId1, testNodeId1, testDimensionId1, testDimensionId1, true); @@ -205,6 +225,8 @@ class PackagingRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("Get by material id") + @DisplayName("Get by material id") void testGetByMaterialId() { // Given: Create packagings for specific material Packaging packaging1 = createTestPackaging(testMaterialId1, testNodeId1, testDimensionId1, testDimensionId1, false); @@ -225,6 +247,8 @@ class PackagingRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("Get by material id and supplier id") + @DisplayName("Get by material id and supplier id") void testGetByMaterialIdAndSupplierId() { // Given: Create packaging with specific material and supplier Packaging packaging = createTestPackaging(testMaterialId1, testNodeId1, testDimensionId1, testDimensionId1, false); @@ -241,6 +265,8 @@ class PackagingRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("Get by material id and supplier id not found") + @DisplayName("Get by material id and supplier id not found") void testGetByMaterialIdAndSupplierIdNotFound() { // When: Get by non-existent combination Optional result = packagingRepository.getByMaterialIdAndSupplierId(99999, 99999); @@ -250,6 +276,8 @@ class PackagingRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("List all packaging") + @DisplayName("List all packaging") void testListAllPackaging() { // Given: Create packagings Packaging packaging1 = createTestPackaging(testMaterialId1, testNodeId1, testDimensionId1, testDimensionId1, false); diff --git a/src/test/java/de/avatic/lcc/repositories/bulk/BulkOperationRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/bulk/BulkOperationRepositoryIntegrationTest.java index c1df854..465d1d9 100644 --- a/src/test/java/de/avatic/lcc/repositories/bulk/BulkOperationRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/bulk/BulkOperationRepositoryIntegrationTest.java @@ -5,7 +5,11 @@ import de.avatic.lcc.dto.bulk.BulkOperationState; import de.avatic.lcc.dto.bulk.BulkProcessingType; import de.avatic.lcc.model.bulk.BulkOperation; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -31,6 +35,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=BulkOperationRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Bulk") class BulkOperationRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -73,6 +79,8 @@ class BulkOperationRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Insert new operation") + @DisplayName("Insert new operation") void testInsertNewOperation() { // Given: New bulk operation BulkOperation newOp = new BulkOperation(); @@ -98,6 +106,8 @@ class BulkOperationRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Insert with null validity period") + @DisplayName("Insert with null validity period") void testInsertWithNullValidityPeriod() { // Given: Operation without validity period BulkOperation newOp = new BulkOperation(); @@ -118,6 +128,8 @@ class BulkOperationRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Remove old keeps newest") + @DisplayName("Remove old keeps newest") void testRemoveOldKeepsNewest() { // Given: Create 15 operations for user1 (all COMPLETED) for (int i = 0; i < 15; i++) { @@ -140,6 +152,8 @@ class BulkOperationRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Remove old preserves scheduled and processing") + @DisplayName("Remove old preserves scheduled and processing") void testRemoveOldPreservesScheduledAndProcessing() { // Given: Create 5 SCHEDULED/PROCESSING and 12 COMPLETED operations createBulkOperation(testUserId1, BulkFileType.MATERIAL, BulkOperationState.SCHEDULED, null, "sched1".getBytes()); @@ -160,6 +174,8 @@ class BulkOperationRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Update state") + @DisplayName("Update state") void testUpdateState() { // Given: Existing operation Integer opId = createBulkOperation(testUserId1, BulkFileType.MATERIAL, @@ -175,6 +191,8 @@ class BulkOperationRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("List by user id") + @DisplayName("List by user id") void testListByUserId() { // When: List operations for user1 List operations = bulkOperationRepository.listByUserId(testUserId1); @@ -186,6 +204,8 @@ class BulkOperationRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("List by user id limit") + @DisplayName("List by user id limit") void testListByUserIdLimit() { // Given: Create 15 operations for (int i = 0; i < 15; i++) { @@ -201,6 +221,8 @@ class BulkOperationRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("List by user id skips file") + @DisplayName("List by user id skips file") void testListByUserIdSkipsFile() { // When: List operations List operations = bulkOperationRepository.listByUserId(testUserId1); @@ -211,6 +233,8 @@ class BulkOperationRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Get operation by id") + @DisplayName("Get operation by id") void testGetOperationById() { // Given: Existing operation Integer opId = createBulkOperation(testUserId1, BulkFileType.MATERIAL, @@ -231,6 +255,8 @@ class BulkOperationRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Get operation by id not found") + @DisplayName("Get operation by id not found") void testGetOperationByIdNotFound() { // When: Get non-existent ID Optional operation = bulkOperationRepository.getOperationById(99999); @@ -240,6 +266,8 @@ class BulkOperationRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Update") + @DisplayName("Update") void testUpdate() { // Given: Existing operation Integer opId = createBulkOperation(testUserId1, BulkFileType.MATERIAL, @@ -267,6 +295,8 @@ class BulkOperationRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Cleanup timeouts via list by user id") + @DisplayName("Cleanup timeouts via list by user id") void testCleanupTimeoutsViaListByUserId() { // Given: Create old PROCESSING operation (simulate timeout) Integer oldOpId = createBulkOperation(testUserId1, BulkFileType.MATERIAL, @@ -288,6 +318,8 @@ class BulkOperationRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Cleanup timeouts does not affect recent") + @DisplayName("Cleanup timeouts does not affect recent") void testCleanupTimeoutsDoesNotAffectRecent() { // Given: Recent PROCESSING operation Integer recentOpId = createBulkOperation(testUserId1, BulkFileType.MATERIAL, @@ -303,6 +335,8 @@ class BulkOperationRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Remove old does not affect other users") + @DisplayName("Remove old does not affect other users") void testRemoveOldDoesNotAffectOtherUsers() { // Given: Create 15 operations for user2 for (int i = 0; i < 15; i++) { diff --git a/src/test/java/de/avatic/lcc/repositories/calculation/CalculationJobDestinationRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/calculation/CalculationJobDestinationRepositoryIntegrationTest.java index 8571a4d..ef704de 100644 --- a/src/test/java/de/avatic/lcc/repositories/calculation/CalculationJobDestinationRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/calculation/CalculationJobDestinationRepositoryIntegrationTest.java @@ -6,7 +6,11 @@ import de.avatic.lcc.model.db.calculations.CalculationJobPriority; import de.avatic.lcc.model.db.calculations.CalculationJobState; import de.avatic.lcc.model.db.premises.PremiseState; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -31,6 +35,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=CalculationJobDestinationRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Calculation") class CalculationJobDestinationRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -106,6 +112,8 @@ class CalculationJobDestinationRepositoryIntegrationTest extends AbstractReposit } @Test + @Story("Insert and get by job id") + @DisplayName("Insert and get by job id") void testInsertAndGetByJobId() { // Given: New calculation job destination CalculationJobDestination destination = createFullCalculationJobDestination(); @@ -133,6 +141,8 @@ class CalculationJobDestinationRepositoryIntegrationTest extends AbstractReposit } @Test + @Story("Get destinations by job id empty") + @DisplayName("Get destinations by job id empty") void testGetDestinationsByJobIdEmpty() { // When: Get destinations for job with no destinations List destinations = @@ -144,6 +154,8 @@ class CalculationJobDestinationRepositoryIntegrationTest extends AbstractReposit } @Test + @Story("Get destinations by job id multiple") + @DisplayName("Get destinations by job id multiple") void testGetDestinationsByJobIdMultiple() { // Given: Multiple destinations for same job CalculationJobDestination dest1 = createFullCalculationJobDestination(); @@ -168,6 +180,8 @@ class CalculationJobDestinationRepositoryIntegrationTest extends AbstractReposit } @Test + @Story("Container type enum") + @DisplayName("Container type enum") void testContainerTypeEnum() { // Given: Destinations with different container types CalculationJobDestination dest1 = createFullCalculationJobDestination(); @@ -194,6 +208,8 @@ class CalculationJobDestinationRepositoryIntegrationTest extends AbstractReposit } @Test + @Story("Boolean fields") + @DisplayName("Boolean fields") void testBooleanFields() { // Given: Destination with specific boolean values CalculationJobDestination destination = createFullCalculationJobDestination(); @@ -216,6 +232,8 @@ class CalculationJobDestinationRepositoryIntegrationTest extends AbstractReposit } @Test + @Story("Big decimal fields") + @DisplayName("Big decimal fields") void testBigDecimalFields() { // Given: Destination with specific decimal values CalculationJobDestination destination = createFullCalculationJobDestination(); @@ -241,6 +259,8 @@ class CalculationJobDestinationRepositoryIntegrationTest extends AbstractReposit } @Test + @Story("Nullable fields") + @DisplayName("Nullable fields") void testNullableFields() { // Given: Destination with some nullable fields as null CalculationJobDestination destination = createMinimalCalculationJobDestination(); diff --git a/src/test/java/de/avatic/lcc/repositories/calculation/CalculationJobRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/calculation/CalculationJobRepositoryIntegrationTest.java index adcd7d3..c6c9b97 100644 --- a/src/test/java/de/avatic/lcc/repositories/calculation/CalculationJobRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/calculation/CalculationJobRepositoryIntegrationTest.java @@ -4,7 +4,11 @@ import de.avatic.lcc.model.db.calculations.CalculationJob; import de.avatic.lcc.model.db.calculations.CalculationJobPriority; import de.avatic.lcc.model.db.calculations.CalculationJobState; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -31,6 +35,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=CalculationJobRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Calculation") class CalculationJobRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -85,6 +91,8 @@ class CalculationJobRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Insert") + @DisplayName("Insert") void testInsert() { // Given: New calculation job CalculationJob newJob = new CalculationJob(); @@ -109,6 +117,8 @@ class CalculationJobRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Fetch and lock next job priority") + @DisplayName("Fetch and lock next job priority") void testFetchAndLockNextJobPriority() { // Given: Jobs with different priorities createCalculationJob(testPremiseId, testValidityPeriodId, testPropertySetId, testUserId, @@ -126,6 +136,8 @@ class CalculationJobRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Fetch and lock next job exception") + @DisplayName("Fetch and lock next job exception") void testFetchAndLockNextJobException() { // Given: Clear existing jobs and create job in EXCEPTION state with retries < 3 jdbcTemplate.update("DELETE FROM calculation_job"); @@ -151,6 +163,8 @@ class CalculationJobRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Fetch and lock next job skips max retries") + @DisplayName("Fetch and lock next job skips max retries") void testFetchAndLockNextJobSkipsMaxRetries() { // Given: Job in EXCEPTION state with 3 retries (max reached) createCalculationJob(testPremiseId, testValidityPeriodId, testPropertySetId, testUserId, @@ -166,6 +180,8 @@ class CalculationJobRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Fetch and lock next job empty") + @DisplayName("Fetch and lock next job empty") void testFetchAndLockNextJobEmpty() { // Given: No available jobs (only VALID jobs exist) jdbcTemplate.update("DELETE FROM calculation_job WHERE job_state = 'CREATED'"); @@ -178,6 +194,8 @@ class CalculationJobRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Fetch and lock next job") + @DisplayName("Fetch and lock next job") void testFetchAndLockNextJob() { // Given: Clear existing jobs and create multiple CREATED jobs jdbcTemplate.update("DELETE FROM calculation_job"); @@ -204,6 +222,8 @@ class CalculationJobRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Mark as valid") + @DisplayName("Mark as valid") void testMarkAsValid() { // Given: Job in SCHEDULED state Integer jobId = createCalculationJob(testPremiseId, testValidityPeriodId, testPropertySetId, testUserId, @@ -219,6 +239,8 @@ class CalculationJobRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Mark as exception") + @DisplayName("Mark as exception") void testMarkAsException() { // Given: Job in SCHEDULED state Integer jobId = createCalculationJob(testPremiseId, testValidityPeriodId, testPropertySetId, testUserId, @@ -235,6 +257,8 @@ class CalculationJobRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Get calculation job") + @DisplayName("Get calculation job") void testGetCalculationJob() { // Given: Existing job Integer jobId = createCalculationJob(testPremiseId, testValidityPeriodId, testPropertySetId, testUserId, @@ -250,6 +274,8 @@ class CalculationJobRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Get calculation job not found") + @DisplayName("Get calculation job not found") void testGetCalculationJobNotFound() { // When: Get non-existent ID Optional job = calculationJobRepository.getCalculationJob(99999); @@ -259,6 +285,8 @@ class CalculationJobRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Reschedule") + @DisplayName("Reschedule") void testReschedule() { // Given: Job in EXCEPTION state Integer jobId = createCalculationJob(testPremiseId, testValidityPeriodId, testPropertySetId, testUserId, @@ -274,6 +302,8 @@ class CalculationJobRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Get calculation job with job state valid") + @DisplayName("Get calculation job with job state valid") void testGetCalculationJobWithJobStateValid() { // Given: VALID job for specific combination createCalculationJob(testPremiseId, testValidityPeriodId, testPropertySetId, testUserId, @@ -289,6 +319,8 @@ class CalculationJobRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Set state to") + @DisplayName("Set state to") void testSetStateTo() { // Given: Job in CREATED state Integer jobId = createCalculationJob(testPremiseId, testValidityPeriodId, testPropertySetId, testUserId, @@ -304,6 +336,8 @@ class CalculationJobRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Find job") + @DisplayName("Find job") void testFindJob() { // When: Find job by premise, period, and set Optional job = calculationJobRepository.findJob( @@ -320,6 +354,8 @@ class CalculationJobRepositoryIntegrationTest extends AbstractRepositoryIntegrat // due to a bug in production code: enum has INVALIDATED but DB schema only allows INVALID @Test + @Story("Get last state for") + @DisplayName("Get last state for") void testGetLastStateFor() { // Given: Multiple jobs for premise with different dates createCalculationJob(testPremiseId, testValidityPeriodId, testPropertySetId, testUserId, @@ -338,6 +374,8 @@ class CalculationJobRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Get failed job by user id") + @DisplayName("Get failed job by user id") void testGetFailedJobByUserId() { // Given: Recent EXCEPTION job (within 3 days) createCalculationJob(testPremiseId, testValidityPeriodId, testPropertySetId, testUserId, @@ -352,6 +390,8 @@ class CalculationJobRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Get self scheduled job count by user id") + @DisplayName("Get self scheduled job count by user id") void testGetSelfScheduledJobCountByUserId() { // Given: CREATED and SCHEDULED jobs createCalculationJob(testPremiseId, testValidityPeriodId, testPropertySetId, testUserId, diff --git a/src/test/java/de/avatic/lcc/repositories/calculation/CalculationJobRouteSectionRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/calculation/CalculationJobRouteSectionRepositoryIntegrationTest.java index 12e3313..ac9782f 100644 --- a/src/test/java/de/avatic/lcc/repositories/calculation/CalculationJobRouteSectionRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/calculation/CalculationJobRouteSectionRepositoryIntegrationTest.java @@ -8,7 +8,11 @@ import de.avatic.lcc.model.db.calculations.CalculationJobRouteSection; import de.avatic.lcc.model.db.calculations.CalculationJobState; import de.avatic.lcc.model.db.premises.PremiseState; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -18,6 +22,8 @@ import java.util.Map; import static org.junit.jupiter.api.Assertions.*; +@Epic("Repository") +@Feature("Calculation") public class CalculationJobRouteSectionRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -109,6 +115,8 @@ public class CalculationJobRouteSectionRepositoryIntegrationTest extends Abstrac // ========== INSERT TESTS ========== @Test + @Story("Insert with all fields") + @DisplayName("Insert with all fields") void testInsertWithAllFields() { CalculationJobRouteSection section = createFullRouteSection(); section.setCalculationJobDestinationId(testCalculationJobDestinationId1); @@ -144,6 +152,8 @@ public class CalculationJobRouteSectionRepositoryIntegrationTest extends Abstrac } @Test + @Story("Insert with null premise route section id") + @DisplayName("Insert with null premise route section id") void testInsertWithNullPremiseRouteSectionId() { CalculationJobRouteSection section = createFullRouteSection(); section.setCalculationJobDestinationId(testCalculationJobDestinationId1); @@ -160,6 +170,8 @@ public class CalculationJobRouteSectionRepositoryIntegrationTest extends Abstrac } @Test + @Story("Insert with matrix rate type") + @DisplayName("Insert with matrix rate type") void testInsertWithMatrixRateType() { CalculationJobRouteSection section = createMinimalRouteSection(); section.setCalculationJobDestinationId(testCalculationJobDestinationId1); @@ -178,6 +190,8 @@ public class CalculationJobRouteSectionRepositoryIntegrationTest extends Abstrac } @Test + @Story("Insert with D2D rate type") + @DisplayName("Insert with D2D rate type") void testInsertWithD2DRateType() { CalculationJobRouteSection section = createMinimalRouteSection(); section.setCalculationJobDestinationId(testCalculationJobDestinationId1); @@ -196,6 +210,8 @@ public class CalculationJobRouteSectionRepositoryIntegrationTest extends Abstrac } @Test + @Story("Insert with container rate type") + @DisplayName("Insert with container rate type") void testInsertWithContainerRateType() { CalculationJobRouteSection section = createMinimalRouteSection(); section.setCalculationJobDestinationId(testCalculationJobDestinationId1); @@ -214,6 +230,8 @@ public class CalculationJobRouteSectionRepositoryIntegrationTest extends Abstrac } @Test + @Story("Boolean flags") + @DisplayName("Boolean flags") void testBooleanFlags() { CalculationJobRouteSection section = createMinimalRouteSection(); section.setCalculationJobDestinationId(testCalculationJobDestinationId1); @@ -244,6 +262,8 @@ public class CalculationJobRouteSectionRepositoryIntegrationTest extends Abstrac // ========== QUERY TESTS ========== @Test + @Story("Get route sections by destination id") + @DisplayName("Get route sections by destination id") void testGetRouteSectionsByDestinationId() { CalculationJobRouteSection section1 = createFullRouteSection(); section1.setCalculationJobDestinationId(testCalculationJobDestinationId1); @@ -265,12 +285,16 @@ public class CalculationJobRouteSectionRepositoryIntegrationTest extends Abstrac } @Test + @Story("Get route sections by destination id not found") + @DisplayName("Get route sections by destination id not found") void testGetRouteSectionsByDestinationIdNotFound() { List sections = repository.getRouteSectionsByDestinationId(99999); assertTrue(sections.isEmpty()); } @Test + @Story("Get route sections by destination ids") + @DisplayName("Get route sections by destination ids") void testGetRouteSectionsByDestinationIds() { CalculationJobRouteSection section1 = createFullRouteSection(); section1.setCalculationJobDestinationId(testCalculationJobDestinationId1); @@ -296,18 +320,24 @@ public class CalculationJobRouteSectionRepositoryIntegrationTest extends Abstrac } @Test + @Story("Get route sections by destination ids empty") + @DisplayName("Get route sections by destination ids empty") void testGetRouteSectionsByDestinationIdsEmpty() { Map> grouped = repository.getRouteSectionsByDestinationIds(List.of()); assertTrue(grouped.isEmpty()); } @Test + @Story("Get route sections by destination ids null") + @DisplayName("Get route sections by destination ids null") void testGetRouteSectionsByDestinationIdsNull() { Map> grouped = repository.getRouteSectionsByDestinationIds(null); assertTrue(grouped.isEmpty()); } @Test + @Story("Get route sections by destination ids not found") + @DisplayName("Get route sections by destination ids not found") void testGetRouteSectionsByDestinationIdsNotFound() { Map> grouped = repository.getRouteSectionsByDestinationIds( List.of(99998, 99999) diff --git a/src/test/java/de/avatic/lcc/repositories/country/CountryPropertyRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/country/CountryPropertyRepositoryIntegrationTest.java index 16f92e8..38572e5 100644 --- a/src/test/java/de/avatic/lcc/repositories/country/CountryPropertyRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/country/CountryPropertyRepositoryIntegrationTest.java @@ -5,7 +5,11 @@ import de.avatic.lcc.model.db.properties.CountryPropertyMappingId; import de.avatic.lcc.model.db.rates.ValidityPeriodState; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; import de.avatic.lcc.repositories.properties.PropertySetRepository; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -31,6 +35,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=CountryPropertyRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Country") class CountryPropertyRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -70,6 +76,8 @@ class CountryPropertyRepositoryIntegrationTest extends AbstractRepositoryIntegra } @Test + @Story("Set property upsert") + @DisplayName("Set property upsert") void testSetPropertyUpsert() { // Given: Create a property in valid set first (required by setProperty logic) String validValue = "30"; @@ -96,6 +104,8 @@ class CountryPropertyRepositoryIntegrationTest extends AbstractRepositoryIntegra } @Test + @Story("Set property deletes when matches valid value") + @DisplayName("Set property deletes when matches valid value") void testSetPropertyDeletesWhenMatchesValidValue() { // Given: Create valid property with value String validValue = "30"; @@ -115,6 +125,8 @@ class CountryPropertyRepositoryIntegrationTest extends AbstractRepositoryIntegra } @Test + @Story("Get by mapping id and country id") + @DisplayName("Get by mapping id and country id") void testGetByMappingIdAndCountryId() { // Given: Create properties in draft and valid sets createTestCountryProperty(testDraftSetId, testCountryId, testPropertyTypeId, "45"); @@ -132,6 +144,8 @@ class CountryPropertyRepositoryIntegrationTest extends AbstractRepositoryIntegra } @Test + @Story("Get by mapping id and country id with set id") + @DisplayName("Get by mapping id and country id with set id") void testGetByMappingIdAndCountryIdWithSetId() { // Given: Create property in specific set createTestCountryProperty(testDraftSetId, testCountryId, testPropertyTypeId, "45"); @@ -146,6 +160,8 @@ class CountryPropertyRepositoryIntegrationTest extends AbstractRepositoryIntegra } @Test + @Story("List properties by country id") + @DisplayName("List properties by country id") void testListPropertiesByCountryId() { // Given: Create properties for country createTestCountryProperty(testDraftSetId, testCountryId, testPropertyTypeId, "45"); @@ -168,6 +184,8 @@ class CountryPropertyRepositoryIntegrationTest extends AbstractRepositoryIntegra } @Test + @Story("List properties by country id and property set id") + @DisplayName("List properties by country id and property set id") void testListPropertiesByCountryIdAndPropertySetId() { // Given: Create properties in specific set createTestCountryProperty(testDraftSetId, testCountryId, testPropertyTypeId, "45"); @@ -189,6 +207,8 @@ class CountryPropertyRepositoryIntegrationTest extends AbstractRepositoryIntegra } @Test + @Story("Fill draft") + @DisplayName("Fill draft") void testFillDraft() { // Given: Create properties in valid set for multiple property types Integer propertyType2 = getPropertyTypeId(CountryPropertyMappingId.WAGE.name()); @@ -217,6 +237,8 @@ class CountryPropertyRepositoryIntegrationTest extends AbstractRepositoryIntegra } @Test + @Story("Multiple countries") + @DisplayName("Multiple countries") void testMultipleCountries() { // Given: Create properties for different countries Integer country2 = 2; // Assuming country 2 exists from migrations diff --git a/src/test/java/de/avatic/lcc/repositories/error/SysErrorRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/error/SysErrorRepositoryIntegrationTest.java index b40edb2..1a10100 100644 --- a/src/test/java/de/avatic/lcc/repositories/error/SysErrorRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/error/SysErrorRepositoryIntegrationTest.java @@ -6,6 +6,10 @@ import de.avatic.lcc.model.db.error.SysErrorType; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; import de.avatic.lcc.repositories.pagination.SearchQueryPagination; import de.avatic.lcc.repositories.pagination.SearchQueryResult; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -31,12 +35,16 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=SysErrorRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Error") class SysErrorRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired private SysErrorRepository sysErrorRepository; @Test + @Story("Insert single") + @DisplayName("Insert single") void testInsertSingle() { // Given: Create error SysError error = createTestError("Test Error", "E001", "Test error message", @@ -51,6 +59,8 @@ class SysErrorRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Insert with trace items") + @DisplayName("Insert with trace items") void testInsertWithTraceItems() { // Given: Create error with trace items SysError error = createTestError("Test Error", "E002", "Error with trace", @@ -70,6 +80,8 @@ class SysErrorRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Insert multiple") + @DisplayName("Insert multiple") void testInsertMultiple() { // Given: Multiple errors List errors = new ArrayList<>(); @@ -84,6 +96,8 @@ class SysErrorRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("List errors with pagination") + @DisplayName("List errors with pagination") void testListErrorsWithPagination() { // Given: Insert multiple errors for (int i = 1; i <= 5; i++) { @@ -103,6 +117,8 @@ class SysErrorRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("List errors with filter") + @DisplayName("List errors with filter") void testListErrorsWithFilter() { // Given: Insert errors with different titles SysError error1 = createTestError("Database Connection Error", "F001", @@ -135,6 +151,8 @@ class SysErrorRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("List errors loads trace items") + @DisplayName("List errors loads trace items") void testListErrorsLoadsTraceItems() { // Given: Insert error with trace SysError error = createTestError("Error with Trace", "T001", @@ -170,6 +188,8 @@ class SysErrorRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes // Skipping bulk operation tests - requires complex setup with proper bulk_operation table schema @Test + @Story("Get by bulk operation id not found") + @DisplayName("Get by bulk operation id not found") void testGetByBulkOperationIdNotFound() { // When: Get by non-existent bulk operation ID Optional result = sysErrorRepository.getByBulkOperationId(99999); @@ -179,6 +199,8 @@ class SysErrorRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Error types") + @DisplayName("Error types") void testErrorTypes() { // Test different error types for (SysErrorType type : SysErrorType.values()) { @@ -195,6 +217,8 @@ class SysErrorRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Reserved keyword handling") + @DisplayName("Reserved keyword handling") void testReservedKeywordHandling() { // Test that "file" column (reserved keyword) is properly escaped // Given: Error with trace (trace has "file" column) diff --git a/src/test/java/de/avatic/lcc/repositories/packaging/PackagingPropertiesRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/packaging/PackagingPropertiesRepositoryIntegrationTest.java index e114a30..887eb9d 100644 --- a/src/test/java/de/avatic/lcc/repositories/packaging/PackagingPropertiesRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/packaging/PackagingPropertiesRepositoryIntegrationTest.java @@ -4,7 +4,11 @@ import de.avatic.lcc.model.db.properties.PackagingProperty; import de.avatic.lcc.model.db.properties.PropertyDataType; import de.avatic.lcc.model.db.properties.PropertyType; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -27,6 +31,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=PackagingPropertiesRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Packaging") class PackagingPropertiesRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -64,6 +70,8 @@ class PackagingPropertiesRepositoryIntegrationTest extends AbstractRepositoryInt } @Test + @Story("Get by packaging id") + @DisplayName("Get by packaging id") void testGetByPackagingId() { // When: Get properties by packaging ID List properties = packagingPropertiesRepository.getByPackagingId(testPackagingId); @@ -76,6 +84,8 @@ class PackagingPropertiesRepositoryIntegrationTest extends AbstractRepositoryInt } @Test + @Story("Get by packaging id empty") + @DisplayName("Get by packaging id empty") void testGetByPackagingIdEmpty() { // Given: Packaging with no properties Integer emptyPackagingId = createPackaging("Box-002", "Empty Box"); @@ -89,6 +99,8 @@ class PackagingPropertiesRepositoryIntegrationTest extends AbstractRepositoryInt } @Test + @Story("Get by packaging id and type") + @DisplayName("Get by packaging id and type") void testGetByPackagingIdAndType() { // When: Get specific property by packaging and type Optional property = packagingPropertiesRepository.getByPackagingIdAndType( @@ -102,6 +114,8 @@ class PackagingPropertiesRepositoryIntegrationTest extends AbstractRepositoryInt } @Test + @Story("Get by packaging id and type not found") + @DisplayName("Get by packaging id and type not found") void testGetByPackagingIdAndTypeNotFound() { // When: Get non-existent property Optional property = packagingPropertiesRepository.getByPackagingIdAndType( @@ -112,6 +126,8 @@ class PackagingPropertiesRepositoryIntegrationTest extends AbstractRepositoryInt } @Test + @Story("Get by packaging id and type different packaging") + @DisplayName("Get by packaging id and type different packaging") void testGetByPackagingIdAndTypeDifferentPackaging() { // Given: Different packaging Integer otherPackagingId = createPackaging("Box-003", "Other Box"); @@ -125,6 +141,8 @@ class PackagingPropertiesRepositoryIntegrationTest extends AbstractRepositoryInt } @Test + @Story("List types") + @DisplayName("List types") void testListTypes() { // When: List all property types List types = packagingPropertiesRepository.listTypes(); @@ -138,6 +156,8 @@ class PackagingPropertiesRepositoryIntegrationTest extends AbstractRepositoryInt } @Test + @Story("List types properties") + @DisplayName("List types properties") void testListTypesProperties() { // When: List types List types = packagingPropertiesRepository.listTypes(); @@ -155,6 +175,8 @@ class PackagingPropertiesRepositoryIntegrationTest extends AbstractRepositoryInt } @Test + @Story("Update insert") + @DisplayName("Update insert") void testUpdateInsert() { // Given: New property for Material // When: Update (insert) @@ -168,6 +190,8 @@ class PackagingPropertiesRepositoryIntegrationTest extends AbstractRepositoryInt } @Test + @Story("Update upsert") + @DisplayName("Update upsert") void testUpdateUpsert() { // Given: Existing Weight property with value "10.5" // When: Update with new value @@ -185,6 +209,8 @@ class PackagingPropertiesRepositoryIntegrationTest extends AbstractRepositoryInt } @Test + @Story("Update with type id") + @DisplayName("Update with type id") void testUpdateWithTypeId() { // When: Update using Integer type ID packagingPropertiesRepository.update(testPackagingId, testTypeMaterialId, "Plastic"); @@ -197,6 +223,8 @@ class PackagingPropertiesRepositoryIntegrationTest extends AbstractRepositoryInt } @Test + @Story("Update with type id string") + @DisplayName("Update with type id string") void testUpdateWithTypeIdString() { // When: Update using String type ID packagingPropertiesRepository.update(testPackagingId, String.valueOf(testTypeMaterialId), "Wood"); @@ -209,6 +237,8 @@ class PackagingPropertiesRepositoryIntegrationTest extends AbstractRepositoryInt } @Test + @Story("Get type id by mapping id") + @DisplayName("Get type id by mapping id") void testGetTypeIdByMappingId() { // When: Get type ID by mapping ID Integer typeId = packagingPropertiesRepository.getTypeIdByMappingId("WEIGHT"); @@ -219,6 +249,8 @@ class PackagingPropertiesRepositoryIntegrationTest extends AbstractRepositoryInt } @Test + @Story("Get type id by mapping id different types") + @DisplayName("Get type id by mapping id different types") void testGetTypeIdByMappingIdDifferentTypes() { // When: Get different type IDs Integer weightId = packagingPropertiesRepository.getTypeIdByMappingId("WEIGHT"); @@ -235,6 +267,8 @@ class PackagingPropertiesRepositoryIntegrationTest extends AbstractRepositoryInt } @Test + @Story("Update multiple properties") + @DisplayName("Update multiple properties") void testUpdateMultipleProperties() { // Given: Packaging with properties // When: Update multiple properties diff --git a/src/test/java/de/avatic/lcc/repositories/premise/DestinationRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/premise/DestinationRepositoryIntegrationTest.java index f2c9c3d..57f32e9 100644 --- a/src/test/java/de/avatic/lcc/repositories/premise/DestinationRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/premise/DestinationRepositoryIntegrationTest.java @@ -5,7 +5,11 @@ import de.avatic.lcc.model.db.premises.route.Destination; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; import de.avatic.lcc.util.exception.base.ForbiddenException; import de.avatic.lcc.util.exception.internalerror.DatabaseException; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -31,6 +35,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=DestinationRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Premise") class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -89,6 +95,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get by id") + @DisplayName("Get by id") void testGetById() { // Given: Create destination Integer destinationId = createDestination(testPremiseId1, testNodeId1, 500); @@ -105,6 +113,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get by id not found") + @DisplayName("Get by id not found") void testGetByIdNotFound() { // When: Get non-existent ID Optional destination = destinationRepository.getById(99999); @@ -114,6 +124,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get by premise id") + @DisplayName("Get by premise id") void testGetByPremiseId() { // When: Get destinations for premise1 List destinations = destinationRepository.getByPremiseId(testPremiseId1); @@ -125,6 +137,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get by premise id and user id") + @DisplayName("Get by premise id and user id") void testGetByPremiseIdAndUserId() { // When: Get destinations for premise1 with correct user List destinations = destinationRepository.getByPremiseIdAndUserId(testPremiseId1, testUserId1); @@ -135,6 +149,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get by premise id and user id wrong user") + @DisplayName("Get by premise id and user id wrong user") void testGetByPremiseIdAndUserIdWrongUser() { // When: Get destinations for premise1 with wrong user List destinations = destinationRepository.getByPremiseIdAndUserId(testPremiseId1, testUserId2); @@ -144,6 +160,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get by premise id and user id non existent") + @DisplayName("Get by premise id and user id non existent") void testGetByPremiseIdAndUserIdNonExistent() { // When: Get destinations for non-existent premise List destinations = destinationRepository.getByPremiseIdAndUserId(99999, testUserId1); @@ -153,6 +171,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Update") + @DisplayName("Update") void testUpdate() { // Given: Create destination Integer destinationId = createDestination(testPremiseId1, testNodeId1, 500); @@ -182,6 +202,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Update with nulls") + @DisplayName("Update with nulls") void testUpdateWithNulls() { // Given: Create destination Integer destinationId = createDestination(testPremiseId1, testNodeId1, 500); @@ -207,6 +229,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Update non existent") + @DisplayName("Update non existent") void testUpdateNonExistent() { // When/Then: Update non-existent destination should throw assertThrows(DatabaseException.class, () -> @@ -214,6 +238,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Delete by id") + @DisplayName("Delete by id") void testDeleteById() { // Given: Create destination Integer destinationId = createDestination(testPremiseId1, testNodeId1, 500); @@ -227,6 +253,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Delete by id null") + @DisplayName("Delete by id null") void testDeleteByIdNull() { // When: Delete with null (should not throw) destinationRepository.deleteById(null); @@ -236,6 +264,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get owner id by id") + @DisplayName("Get owner id by id") void testGetOwnerIdById() { // Given: Create destination for user1 Integer destinationId = createDestination(testPremiseId1, testNodeId1, 500); @@ -249,6 +279,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get owner id by id not found") + @DisplayName("Get owner id by id not found") void testGetOwnerIdByIdNotFound() { // When: Get owner ID for non-existent destination Optional ownerId = destinationRepository.getOwnerIdById(99999); @@ -258,6 +290,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get owner ids by ids") + @DisplayName("Get owner ids by ids") void testGetOwnerIdsByIds() { // Given: Create destinations for different users Integer dest1 = createDestination(testPremiseId1, testNodeId1, 500); @@ -275,6 +309,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get owner ids by ids empty") + @DisplayName("Get owner ids by ids empty") void testGetOwnerIdsByIdsEmpty() { // When: Get owner IDs for empty list Map ownerMap = destinationRepository.getOwnerIdsByIds(List.of()); @@ -284,6 +320,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get owner ids by ids null") + @DisplayName("Get owner ids by ids null") void testGetOwnerIdsByIdsNull() { // When: Get owner IDs for null Map ownerMap = destinationRepository.getOwnerIdsByIds(null); @@ -293,6 +331,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get by premise ids and node ids map") + @DisplayName("Get by premise ids and node ids map") void testGetByPremiseIdsAndNodeIdsMap() { // Given: Map of premise IDs to node IDs Map> premiseToNodes = new HashMap<>(); @@ -310,6 +350,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get by premise ids and node ids map empty") + @DisplayName("Get by premise ids and node ids map empty") void testGetByPremiseIdsAndNodeIdsMapEmpty() { // When: Get with empty map Map> result = @@ -320,6 +362,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get by premise ids and node ids lists") + @DisplayName("Get by premise ids and node ids lists") void testGetByPremiseIdsAndNodeIdsLists() { // When: Get destinations by lists Map> result = destinationRepository.getByPremiseIdsAndNodeIds( @@ -341,6 +385,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Insert") + @DisplayName("Insert") void testInsert() { // Given: New destination Destination newDest = new Destination(); @@ -373,6 +419,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Insert with nulls") + @DisplayName("Insert with nulls") void testInsertWithNulls() { // Given: New destination with nullable fields as null Destination newDest = new Destination(); @@ -406,6 +454,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Check owner success") + @DisplayName("Check owner success") void testCheckOwnerSuccess() { // Given: Destination owned by user1 Integer destId = createDestination(testPremiseId1, testNodeId1, 500); @@ -415,6 +465,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Check owner wrong user") + @DisplayName("Check owner wrong user") void testCheckOwnerWrongUser() { // Given: Destination owned by user1 Integer destId = createDestination(testPremiseId1, testNodeId1, 500); @@ -425,6 +477,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Check owner non existent") + @DisplayName("Check owner non existent") void testCheckOwnerNonExistent() { // When/Then: Check non-existent destination should throw assertThrows(ForbiddenException.class, () -> @@ -432,6 +486,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Check owner list success") + @DisplayName("Check owner list success") void testCheckOwnerListSuccess() { // Given: Destinations owned by user1 Integer dest1 = createDestination(testPremiseId1, testNodeId1, 500); @@ -442,6 +498,8 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Check owner list mixed owners") + @DisplayName("Check owner list mixed owners") void testCheckOwnerListMixedOwners() { // Given: Destinations with different owners Integer dest1 = createDestination(testPremiseId1, testNodeId1, 500); @@ -453,12 +511,16 @@ class DestinationRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Check owner list empty") + @DisplayName("Check owner list empty") void testCheckOwnerListEmpty() { // When/Then: Check with empty list should not throw assertDoesNotThrow(() -> destinationRepository.checkOwner(List.of(), testUserId1)); } @Test + @Story("Check owner list null") + @DisplayName("Check owner list null") void testCheckOwnerListNull() { // When/Then: Check with null should not throw assertDoesNotThrow(() -> destinationRepository.checkOwner((List) null, testUserId1)); diff --git a/src/test/java/de/avatic/lcc/repositories/premise/PremiseRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/premise/PremiseRepositoryIntegrationTest.java index b16b0dc..45e4f51 100644 --- a/src/test/java/de/avatic/lcc/repositories/premise/PremiseRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/premise/PremiseRepositoryIntegrationTest.java @@ -6,7 +6,11 @@ import de.avatic.lcc.model.db.premises.PremiseState; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; import de.avatic.lcc.repositories.pagination.SearchQueryPagination; import de.avatic.lcc.repositories.pagination.SearchQueryResult; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -32,6 +36,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=PremiseRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Premise") class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -78,6 +84,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("List premises") + @DisplayName("List premises") void testListPremises() { // Given: Pagination SearchQueryPagination pagination = new SearchQueryPagination(1, 10); @@ -93,6 +101,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("List premises pagination") + @DisplayName("List premises pagination") void testListPremisesPagination() { // Given: Create more premises and use pagination for (int i = 0; i < 10; i++) { @@ -112,6 +122,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("List premises with filter") + @DisplayName("List premises with filter") void testListPremisesWithFilter() { // Given: Pagination and filter SearchQueryPagination pagination = new SearchQueryPagination(1, 10); @@ -128,6 +140,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("List premises with draft filter") + @DisplayName("List premises with draft filter") void testListPremisesWithDraftFilter() { // Given: Pagination with draft filter SearchQueryPagination pagination = new SearchQueryPagination(1, 10); @@ -143,6 +157,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Insert") + @DisplayName("Insert") void testInsert() { // When: Insert new premise Integer premiseId = premiseRepository.insert( @@ -162,6 +178,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Get premise by id") + @DisplayName("Get premise by id") void testGetPremiseById() { // Given: Create premise Integer premiseId = createPremise(testUserId, testNodeId, testMaterialId, testCountryId, PremiseState.DRAFT); @@ -176,6 +194,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Get premise by id not found") + @DisplayName("Get premise by id not found") void testGetPremiseByIdNotFound() { // When: Get non-existent ID Optional premise = premiseRepository.getPremiseById(99999); @@ -185,6 +205,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Get premises by id") + @DisplayName("Get premises by id") void testGetPremisesById() { // Given: Create multiple premises Integer id1 = createPremise(testUserId, testNodeId, testMaterialId, testCountryId, PremiseState.DRAFT); @@ -201,6 +223,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Get premises by id empty") + @DisplayName("Get premises by id empty") void testGetPremisesByIdEmpty() { // When: Get with empty list List premises = premiseRepository.getPremisesById(List.of()); @@ -211,6 +235,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Reset price") + @DisplayName("Reset price") void testResetPrice() { // Given: Create premise with price Integer premiseId = createPremise(testUserId, testNodeId, testMaterialId, testCountryId, PremiseState.DRAFT); @@ -229,6 +255,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Update price") + @DisplayName("Update price") void testUpdatePrice() { // Given: Create premise Integer premiseId = createPremise(testUserId, testNodeId, testMaterialId, testCountryId, PremiseState.DRAFT); @@ -245,6 +273,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Update material") + @DisplayName("Update material") void testUpdateMaterial() { // Given: Create premise Integer premiseId = createPremise(testUserId, testNodeId, testMaterialId, testCountryId, PremiseState.DRAFT); @@ -261,6 +291,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Set material id") + @DisplayName("Set material id") void testSetMaterialId() { // Given: Create premise and new material Integer premiseId = createPremise(testUserId, testNodeId, testMaterialId, testCountryId, PremiseState.DRAFT); @@ -276,6 +308,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Delete premises by id") + @DisplayName("Delete premises by id") void testDeletePremisesById() { // Given: Create DRAFT premises Integer draftId = createPremise(testUserId, testNodeId, testMaterialId, testCountryId, PremiseState.DRAFT); @@ -290,6 +324,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Set status") + @DisplayName("Set status") void testSetStatus() { // Given: Create DRAFT premise Integer premiseId = createPremise(testUserId, testNodeId, testMaterialId, testCountryId, PremiseState.DRAFT); @@ -304,6 +340,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Find by material id and supplier id") + @DisplayName("Find by material id and supplier id") void testFindByMaterialIdAndSupplierId() { // Given: Create premise createPremise(testUserId, testNodeId, testMaterialId, testCountryId, PremiseState.DRAFT); @@ -320,6 +358,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Get premises by material ids and supplier ids") + @DisplayName("Get premises by material ids and supplier ids") void testGetPremisesByMaterialIdsAndSupplierIds() { // Given: Create premises createPremise(testUserId, testNodeId, testMaterialId, testCountryId, PremiseState.DRAFT); @@ -335,6 +375,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Find associated suppliers") + @DisplayName("Find associated suppliers") void testFindAssociatedSuppliers() { // Given: Premises with suppliers createPremise(testUserId, testNodeId, testMaterialId, testCountryId, PremiseState.DRAFT); @@ -349,6 +391,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Get ids with unlocked tariffs") + @DisplayName("Get ids with unlocked tariffs") void testGetIdsWithUnlockedTariffs() { // Given: Create premises with different tariff states Integer unlockedId = createPremise(testUserId, testNodeId, testMaterialId, testCountryId, PremiseState.DRAFT); @@ -367,6 +411,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Get premise completed count by user id") + @DisplayName("Get premise completed count by user id") void testGetPremiseCompletedCountByUserId() { // When: Get count Integer count = premiseRepository.getPremiseCompletedCountByUserId(testUserId); @@ -377,6 +423,8 @@ class PremiseRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest } @Test + @Story("Get premise draft count by user id") + @DisplayName("Get premise draft count by user id") void testGetPremiseDraftCountByUserId() { // When: Get count Integer count = premiseRepository.getPremiseDraftCountByUserId(testUserId); diff --git a/src/test/java/de/avatic/lcc/repositories/premise/RouteNodeRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/premise/RouteNodeRepositoryIntegrationTest.java index 2f57ab1..50125d5 100644 --- a/src/test/java/de/avatic/lcc/repositories/premise/RouteNodeRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/premise/RouteNodeRepositoryIntegrationTest.java @@ -3,7 +3,11 @@ package de.avatic.lcc.repositories.premise; import de.avatic.lcc.model.db.premises.PremiseState; import de.avatic.lcc.model.db.premises.route.RouteNode; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -29,6 +33,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=RouteNodeRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Premise") class RouteNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -90,6 +96,8 @@ class RouteNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("Get by id") + @DisplayName("Get by id") void testGetById() { // Given: Create route node Integer nodeId = createRouteNode("Test Node", testNodeId, testCountryId, true, true, true); @@ -107,6 +115,8 @@ class RouteNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("Get by id not found") + @DisplayName("Get by id not found") void testGetByIdNotFound() { // When: Get non-existent ID Optional node = routeNodeRepository.getById(99999); @@ -116,6 +126,8 @@ class RouteNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("Insert") + @DisplayName("Insert") void testInsert() { // Given: New route node RouteNode newNode = new RouteNode(); @@ -150,6 +162,8 @@ class RouteNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("Insert with nulls") + @DisplayName("Insert with nulls") void testInsertWithNulls() { // Given: Route node with nullable fields as null RouteNode newNode = new RouteNode(); @@ -179,6 +193,8 @@ class RouteNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("Delete all by id") + @DisplayName("Delete all by id") void testDeleteAllById() { // Given: Multiple route nodes Integer node1 = createRouteNode("Node 1", testNodeId, testCountryId, true, false, false); @@ -195,6 +211,8 @@ class RouteNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("Delete all by id empty") + @DisplayName("Delete all by id empty") void testDeleteAllByIdEmpty() { // Given: Some route nodes Integer nodeId = createRouteNode("Node", testNodeId, testCountryId, true, false, false); @@ -207,6 +225,8 @@ class RouteNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("Delete all by id null") + @DisplayName("Delete all by id null") void testDeleteAllByIdNull() { // Given: Some route nodes Integer nodeId = createRouteNode("Node", testNodeId, testCountryId, true, false, false); @@ -219,6 +239,8 @@ class RouteNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("Get from node by section id") + @DisplayName("Get from node by section id") void testGetFromNodeBySectionId() { // Given: Create route section with from and to nodes Integer fromNodeId = createRouteNode("From Node", testNodeId, testCountryId, false, false, true); @@ -235,6 +257,8 @@ class RouteNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("Get from node by section id not found") + @DisplayName("Get from node by section id not found") void testGetFromNodeBySectionIdNotFound() { // When: Get from node for non-existent section Optional fromNode = routeNodeRepository.getFromNodeBySectionId(99999); @@ -244,6 +268,8 @@ class RouteNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("Get to node by section id") + @DisplayName("Get to node by section id") void testGetToNodeBySectionId() { // Given: Create route section with from and to nodes Integer fromNodeId = createRouteNode("From Node", testNodeId, testCountryId, false, false, true); @@ -260,6 +286,8 @@ class RouteNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("Get to node by section id not found") + @DisplayName("Get to node by section id not found") void testGetToNodeBySectionIdNotFound() { // When: Get to node for non-existent section Optional toNode = routeNodeRepository.getToNodeBySectionId(99999); @@ -269,6 +297,8 @@ class RouteNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("Boolean fields") + @DisplayName("Boolean fields") void testBooleanFields() { // Given: Create nodes with different boolean combinations RouteNode node1 = new RouteNode(); @@ -316,6 +346,8 @@ class RouteNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTe } @Test + @Story("Geo coordinates") + @DisplayName("Geo coordinates") void testGeoCoordinates() { // Given: Node with specific coordinates RouteNode node = new RouteNode(); diff --git a/src/test/java/de/avatic/lcc/repositories/premise/RouteRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/premise/RouteRepositoryIntegrationTest.java index 37fd6ae..08c1618 100644 --- a/src/test/java/de/avatic/lcc/repositories/premise/RouteRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/premise/RouteRepositoryIntegrationTest.java @@ -4,7 +4,11 @@ import de.avatic.lcc.model.db.premises.PremiseState; import de.avatic.lcc.model.db.premises.route.Route; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; import de.avatic.lcc.util.exception.internalerror.DatabaseException; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -28,6 +32,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=RouteRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Premise") class RouteRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -84,6 +90,8 @@ class RouteRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Get by destination id") + @DisplayName("Get by destination id") void testGetByDestinationId() { // When: Get routes by destination List routes = routeRepository.getByDestinationId(testDestinationId); @@ -95,6 +103,8 @@ class RouteRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Get by destination id empty") + @DisplayName("Get by destination id empty") void testGetByDestinationIdEmpty() { // When: Get routes for non-existent destination List routes = routeRepository.getByDestinationId(99999); @@ -105,6 +115,8 @@ class RouteRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Get selected by destination id") + @DisplayName("Get selected by destination id") void testGetSelectedByDestinationId() { // When: Get selected route Optional selected = routeRepository.getSelectedByDestinationId(testDestinationId); @@ -118,6 +130,8 @@ class RouteRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Get selected by destination id not found") + @DisplayName("Get selected by destination id not found") void testGetSelectedByDestinationIdNotFound() { // Given: Destination with no selected routes Integer destinationId2 = createDestination(testPremiseId, testNodeId); @@ -131,6 +145,8 @@ class RouteRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Get selected by destination id multiple throws") + @DisplayName("Get selected by destination id multiple throws") void testGetSelectedByDestinationIdMultipleThrows() { // Given: Destination with multiple selected routes (invalid state) Integer destinationId2 = createDestination(testPremiseId, testNodeId); @@ -143,6 +159,8 @@ class RouteRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Insert") + @DisplayName("Insert") void testInsert() { // Given: New route Route newRoute = new Route(); @@ -164,6 +182,8 @@ class RouteRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Delete all by id") + @DisplayName("Delete all by id") void testDeleteAllById() { // Given: Multiple routes List routes = routeRepository.getByDestinationId(testDestinationId); @@ -185,6 +205,8 @@ class RouteRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Delete all by id empty") + @DisplayName("Delete all by id empty") void testDeleteAllByIdEmpty() { // When: Delete with empty list routeRepository.deleteAllById(List.of()); @@ -195,6 +217,8 @@ class RouteRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Delete all by id null") + @DisplayName("Delete all by id null") void testDeleteAllByIdNull() { // When: Delete with null routeRepository.deleteAllById(null); @@ -205,6 +229,8 @@ class RouteRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Update selected by destination id") + @DisplayName("Update selected by destination id") void testUpdateSelectedByDestinationId() { // Given: Get non-selected route List routes = routeRepository.getByDestinationId(testDestinationId); @@ -229,6 +255,8 @@ class RouteRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Update selected by destination id invalid route") + @DisplayName("Update selected by destination id invalid route") void testUpdateSelectedByDestinationIdInvalidRoute() { // When/Then: Update with non-existent route ID should throw assertThrows(DatabaseException.class, () -> @@ -236,6 +264,8 @@ class RouteRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Boolean literals") + @DisplayName("Boolean literals") void testBooleanLiterals() { // Given: Create routes with different boolean values Route route1 = new Route(); diff --git a/src/test/java/de/avatic/lcc/repositories/premise/RouteSectionRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/premise/RouteSectionRepositoryIntegrationTest.java index 1cce056..55436de 100644 --- a/src/test/java/de/avatic/lcc/repositories/premise/RouteSectionRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/premise/RouteSectionRepositoryIntegrationTest.java @@ -5,7 +5,11 @@ import de.avatic.lcc.dto.generic.TransportType; import de.avatic.lcc.model.db.premises.PremiseState; import de.avatic.lcc.model.db.premises.route.RouteSection; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -30,6 +34,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=RouteSectionRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Premise") class RouteSectionRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -97,6 +103,8 @@ class RouteSectionRepositoryIntegrationTest extends AbstractRepositoryIntegratio } @Test + @Story("Get by route id") + @DisplayName("Get by route id") void testGetByRouteId() { // When: Get sections by route ID List sections = routeSectionRepository.getByRouteId(testRouteId); @@ -108,6 +116,8 @@ class RouteSectionRepositoryIntegrationTest extends AbstractRepositoryIntegratio } @Test + @Story("Get by route id empty") + @DisplayName("Get by route id empty") void testGetByRouteIdEmpty() { // When: Get sections for non-existent route List sections = routeSectionRepository.getByRouteId(99999); @@ -118,6 +128,8 @@ class RouteSectionRepositoryIntegrationTest extends AbstractRepositoryIntegratio } @Test + @Story("Get by id") + @DisplayName("Get by id") void testGetById() { // Given: Create route section Integer sectionId = createRouteSection(testRouteId, testFromNodeId, testToNodeId, 10, @@ -139,6 +151,8 @@ class RouteSectionRepositoryIntegrationTest extends AbstractRepositoryIntegratio } @Test + @Story("Get by id not found") + @DisplayName("Get by id not found") void testGetByIdNotFound() { // When: Get non-existent ID Optional section = routeSectionRepository.getById(99999); @@ -148,6 +162,8 @@ class RouteSectionRepositoryIntegrationTest extends AbstractRepositoryIntegratio } @Test + @Story("Insert") + @DisplayName("Insert") void testInsert() { // Given: New route section RouteSection newSection = new RouteSection(); @@ -183,6 +199,8 @@ class RouteSectionRepositoryIntegrationTest extends AbstractRepositoryIntegratio } @Test + @Story("Insert with null distance") + @DisplayName("Insert with null distance") void testInsertWithNullDistance() { // Given: Route section with null distance RouteSection newSection = new RouteSection(); @@ -210,6 +228,8 @@ class RouteSectionRepositoryIntegrationTest extends AbstractRepositoryIntegratio } @Test + @Story("Delete all by id") + @DisplayName("Delete all by id") void testDeleteAllById() { // Given: Multiple route sections List sections = routeSectionRepository.getByRouteId(testRouteId); @@ -231,6 +251,8 @@ class RouteSectionRepositoryIntegrationTest extends AbstractRepositoryIntegratio } @Test + @Story("Delete all by id empty") + @DisplayName("Delete all by id empty") void testDeleteAllByIdEmpty() { // When: Delete with empty list routeSectionRepository.deleteAllById(List.of()); @@ -241,6 +263,8 @@ class RouteSectionRepositoryIntegrationTest extends AbstractRepositoryIntegratio } @Test + @Story("Delete all by id null") + @DisplayName("Delete all by id null") void testDeleteAllByIdNull() { // When: Delete with null routeSectionRepository.deleteAllById(null); @@ -251,6 +275,8 @@ class RouteSectionRepositoryIntegrationTest extends AbstractRepositoryIntegratio } @Test + @Story("Transport type enum") + @DisplayName("Transport type enum") void testTransportTypeEnum() { // Given: Sections with different transport types RouteSection section1 = new RouteSection(); @@ -294,6 +320,8 @@ class RouteSectionRepositoryIntegrationTest extends AbstractRepositoryIntegratio } @Test + @Story("Boolean flags") + @DisplayName("Boolean flags") void testBooleanFlags() { // Given: Section with different boolean flags (respecting constraint) RouteSection section = new RouteSection(); diff --git a/src/test/java/de/avatic/lcc/repositories/properties/PropertyRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/properties/PropertyRepositoryIntegrationTest.java index 0fa7e88..2f784f3 100644 --- a/src/test/java/de/avatic/lcc/repositories/properties/PropertyRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/properties/PropertyRepositoryIntegrationTest.java @@ -4,7 +4,11 @@ import de.avatic.lcc.dto.generic.PropertyDTO; import de.avatic.lcc.model.db.properties.SystemPropertyMappingId; import de.avatic.lcc.model.db.rates.ValidityPeriodState; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -31,6 +35,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=PropertyRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Properties") class PropertyRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -66,6 +72,8 @@ class PropertyRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Set property upsert") + @DisplayName("Set property upsert") void testSetPropertyUpsert() { // Given: Create a property in valid set first (required by setProperty logic) String validValue = "30"; @@ -92,6 +100,8 @@ class PropertyRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Set property deletes when matches valid value") + @DisplayName("Set property deletes when matches valid value") void testSetPropertyDeletesWhenMatchesValidValue() { // Given: Create valid property with value String validValue = "30"; @@ -111,6 +121,8 @@ class PropertyRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("List properties") + @DisplayName("List properties") void testListProperties() { // Given: Create properties in draft and valid sets createTestProperty(testDraftSetId, testPropertyTypeId, "45"); @@ -133,6 +145,8 @@ class PropertyRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("List properties by set id") + @DisplayName("List properties by set id") void testListPropertiesBySetId() { // Given: Create expired property set with properties Integer expiredSetId = createTestPropertySet(ValidityPeriodState.EXPIRED, @@ -156,6 +170,8 @@ class PropertyRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Get property by mapping id") + @DisplayName("Get property by mapping id") void testGetPropertyByMappingId() { // Given: Create valid property createTestProperty(testValidSetId, testPropertyTypeId, "30"); @@ -170,6 +186,8 @@ class PropertyRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Get property by mapping id with set id") + @DisplayName("Get property by mapping id with set id") void testGetPropertyByMappingIdWithSetId() { // Given: Create property in specific set createTestProperty(testDraftSetId, testPropertyTypeId, "45"); @@ -183,6 +201,8 @@ class PropertyRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Get property by mapping id not found") + @DisplayName("Get property by mapping id not found") void testGetPropertyByMappingIdNotFound() { // When: Get property that has no value in VALID set (WORKDAYS without creating it) Optional property = propertyRepository.getPropertyByMappingId( @@ -193,6 +213,8 @@ class PropertyRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Fill draft") + @DisplayName("Fill draft") void testFillDraft() { // Given: Create properties in valid set Integer propertyType2 = getPropertyTypeId(SystemPropertyMappingId.WORKDAYS.name()); @@ -221,6 +243,8 @@ class PropertyRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Fill draft ignores duplicates") + @DisplayName("Fill draft ignores duplicates") void testFillDraftIgnoresDuplicates() { // Given: Create property in valid set createTestProperty(testValidSetId, testPropertyTypeId, "30"); diff --git a/src/test/java/de/avatic/lcc/repositories/properties/PropertySetRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/properties/PropertySetRepositoryIntegrationTest.java index d225acb..0dca7a1 100644 --- a/src/test/java/de/avatic/lcc/repositories/properties/PropertySetRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/properties/PropertySetRepositoryIntegrationTest.java @@ -3,7 +3,11 @@ package de.avatic.lcc.repositories.properties; import de.avatic.lcc.model.db.properties.PropertySet; import de.avatic.lcc.model.db.rates.ValidityPeriodState; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -20,7 +24,7 @@ import static org.junit.jupiter.api.Assertions.*; *

* Tests critical functionality across both MySQL and MSSQL: * - Draft creation and retrieval - * - State transitions (DRAFT → VALID → EXPIRED → INVALID) + * - State transitions (DRAFT -> VALID -> EXPIRED -> INVALID) * - Date-based queries with dialect-specific date extraction * - Timestamp handling *

@@ -30,6 +34,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=PropertySetRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Properties") class PropertySetRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -44,6 +50,8 @@ class PropertySetRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get draft set") + @DisplayName("Get draft set") void testGetDraftSet() { // When: Get draft set (creates if doesn't exist) PropertySet draft = propertySetRepository.getDraftSet(); @@ -56,6 +64,8 @@ class PropertySetRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get draft set idempotent") + @DisplayName("Get draft set idempotent") void testGetDraftSetIdempotent() { // Given: Get draft first time PropertySet draft1 = propertySetRepository.getDraftSet(); @@ -68,6 +78,8 @@ class PropertySetRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get draft set id") + @DisplayName("Get draft set id") void testGetDraftSetId() { // When: Get draft set ID Integer draftId = propertySetRepository.getDraftSetId(); @@ -82,6 +94,8 @@ class PropertySetRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("List property sets") + @DisplayName("List property sets") void testListPropertySets() { // Given: Create draft propertySetRepository.getDraftSet(); @@ -100,12 +114,14 @@ class PropertySetRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Apply draft") + @DisplayName("Apply draft") void testApplyDraft() { // Given: Clean state - get draft PropertySet draft = propertySetRepository.getDraftSet(); Integer draftId = draft.getId(); - // When: Apply draft (transitions DRAFT → VALID, creates new DRAFT) + // When: Apply draft (transitions DRAFT -> VALID, creates new DRAFT) propertySetRepository.applyDraft(); // Then: Old draft should now be VALID @@ -121,6 +137,8 @@ class PropertySetRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get valid set") + @DisplayName("Get valid set") void testGetValidSet() { // Given: Apply draft to create valid set PropertySet draft = propertySetRepository.getDraftSet(); @@ -137,6 +155,8 @@ class PropertySetRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get valid set id") + @DisplayName("Get valid set id") void testGetValidSetId() { // Given: Apply draft to create valid set propertySetRepository.getDraftSet(); @@ -152,6 +172,8 @@ class PropertySetRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Apply draft expires old valid") + @DisplayName("Apply draft expires old valid") void testApplyDraftExpiresOldValid() { // Given: Manually create a VALID set (to avoid timing issues with applyDraft) LocalDateTime pastStart = LocalDateTime.now().minusDays(10); @@ -170,6 +192,8 @@ class PropertySetRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Invalidate by id") + @DisplayName("Invalidate by id") void testInvalidateById() { // Given: Create expired property set manually LocalDateTime pastStart = LocalDateTime.now().minusDays(30); @@ -187,6 +211,8 @@ class PropertySetRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Invalidate by id fails for non expired") + @DisplayName("Invalidate by id fails for non expired") void testInvalidateByIdFailsForNonExpired() { // Given: Valid property set propertySetRepository.getDraftSet(); @@ -204,6 +230,8 @@ class PropertySetRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Has properties draft when empty") + @DisplayName("Has properties draft when empty") void testHasPropertiesDraftWhenEmpty() { // Given: Draft with no properties propertySetRepository.getDraftSet(); @@ -216,6 +244,8 @@ class PropertySetRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get state") + @DisplayName("Get state") void testGetState() { // Given: Draft property set Integer draftId = propertySetRepository.getDraftSetId(); @@ -228,6 +258,8 @@ class PropertySetRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get by id") + @DisplayName("Get by id") void testGetById() { // Given: Draft property set Integer draftId = propertySetRepository.getDraftSetId(); @@ -242,6 +274,8 @@ class PropertySetRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get by id not found") + @DisplayName("Get by id not found") void testGetByIdNotFound() { // When/Then: Get non-existent ID should throw exception assertThrows(IllegalArgumentException.class, () -> @@ -250,6 +284,8 @@ class PropertySetRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get by date") + @DisplayName("Get by date") void testGetByDate() { // Given: Create valid set manually with past date (to avoid timing issues) LocalDateTime validStart = LocalDateTime.now().minusDays(5); @@ -266,6 +302,8 @@ class PropertySetRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get by date past date") + @DisplayName("Get by date past date") void testGetByDatePastDate() { // Given: Create expired property set in the past LocalDateTime pastStart = LocalDateTime.now().minusDays(30); @@ -282,6 +320,8 @@ class PropertySetRepositoryIntegrationTest extends AbstractRepositoryIntegration } @Test + @Story("Get by date ordering") + @DisplayName("Get by date ordering") void testGetByDateOrdering() { // Given: Create multiple property sets manually LocalDateTime old = LocalDateTime.now().minusDays(20); diff --git a/src/test/java/de/avatic/lcc/repositories/rates/ContainerRateRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/rates/ContainerRateRepositoryIntegrationTest.java index d23b354..1423cff 100644 --- a/src/test/java/de/avatic/lcc/repositories/rates/ContainerRateRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/rates/ContainerRateRepositoryIntegrationTest.java @@ -6,7 +6,11 @@ import de.avatic.lcc.model.db.rates.ValidityPeriodState; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; import de.avatic.lcc.repositories.pagination.SearchQueryPagination; import de.avatic.lcc.repositories.pagination.SearchQueryResult; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -34,6 +38,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=ContainerRateRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Rates") class ContainerRateRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -82,6 +88,8 @@ class ContainerRateRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("List rates by period id") + @DisplayName("List rates by period id") void testListRatesByPeriodId() { // Given: Valid period ID SearchQueryPagination pagination = new SearchQueryPagination(1, 10); @@ -97,6 +105,8 @@ class ContainerRateRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("List rates by period id with filter") + @DisplayName("List rates by period id with filter") void testListRatesByPeriodIdWithFilter() { // Given: Filter for "Hamburg" SearchQueryPagination pagination = new SearchQueryPagination(1, 10); @@ -110,6 +120,8 @@ class ContainerRateRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("List rates by period id with external mapping id filter") + @DisplayName("List rates by period id with external mapping id filter") void testListRatesByPeriodIdWithExternalMappingIdFilter() { // Given: Filter for "HAM" SearchQueryPagination pagination = new SearchQueryPagination(1, 10); @@ -123,6 +135,8 @@ class ContainerRateRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("List rates by period id pagination") + @DisplayName("List rates by period id pagination") void testListRatesByPeriodIdPagination() { // Given: Pagination with limit 2 SearchQueryPagination pagination = new SearchQueryPagination(1, 2); @@ -137,6 +151,8 @@ class ContainerRateRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Get by id") + @DisplayName("Get by id") void testGetById() { // Given: Get first rate ID SearchQueryPagination pagination = new SearchQueryPagination(1, 1); @@ -156,6 +172,8 @@ class ContainerRateRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Get by id not found") + @DisplayName("Get by id not found") void testGetByIdNotFound() { // When: Get non-existent ID Optional rate = containerRateRepository.getById(99999); @@ -165,6 +183,8 @@ class ContainerRateRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("List all rates by period id") + @DisplayName("List all rates by period id") void testListAllRatesByPeriodId() { // When: List all rates for valid period List rates = containerRateRepository.listAllRatesByPeriodId(testValidPeriodId); @@ -176,6 +196,8 @@ class ContainerRateRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Find routes by start node id and destination country id") + @DisplayName("Find routes by start node id and destination country id") void testFindRoutesByStartNodeIdAndDestinationCountryId() { // When: Find routes from Hamburg to US List routes = containerRateRepository.findRoutesByStartNodeIdAndDestinationCountryId( @@ -190,6 +212,8 @@ class ContainerRateRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Find routes by start node id and destination country id multiple") + @DisplayName("Find routes by start node id and destination country id multiple") void testFindRoutesByStartNodeIdAndDestinationCountryIdMultiple() { // When: Find routes from Hamburg to DE or US List routes = containerRateRepository.findRoutesByStartNodeIdAndDestinationCountryId( @@ -202,6 +226,8 @@ class ContainerRateRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Find routes by start node id and destination country id empty") + @DisplayName("Find routes by start node id and destination country id empty") void testFindRoutesByStartNodeIdAndDestinationCountryIdEmpty() { // When: Find routes with empty destination list List routes = containerRateRepository.findRoutesByStartNodeIdAndDestinationCountryId( @@ -213,6 +239,8 @@ class ContainerRateRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Get post runs for") + @DisplayName("Get post runs for") void testGetPostRunsFor() { // Given: Create a main run and post-run Integer testNodeWarehouseId = createTestNode("Warehouse", "WH1", testCountryUsId, false, 40.8, -74.1); @@ -233,6 +261,8 @@ class ContainerRateRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Find route with period id") + @DisplayName("Find route with period id") void testFindRouteWithPeriodId() { // When: Find route Hamburg -> New York SEA in valid period Optional route = containerRateRepository.findRoute( @@ -247,6 +277,8 @@ class ContainerRateRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Find route with period id not found") + @DisplayName("Find route with period id not found") void testFindRouteWithPeriodIdNotFound() { // When: Find route with wrong transport type Optional route = containerRateRepository.findRoute( @@ -257,6 +289,8 @@ class ContainerRateRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Find route without period id") + @DisplayName("Find route without period id") void testFindRouteWithoutPeriodId() { // When: Find route Hamburg -> New York SEA (uses VALID period) Optional route = containerRateRepository.findRoute( @@ -270,6 +304,8 @@ class ContainerRateRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Insert new rate") + @DisplayName("Insert new rate") void testInsertNewRate() { // Given: New container rate ContainerRate newRate = new ContainerRate(); @@ -293,6 +329,8 @@ class ContainerRateRepositoryIntegrationTest extends AbstractRepositoryIntegrati } @Test + @Story("Insert upsert existing") + @DisplayName("Insert upsert existing") void testInsertUpsertExisting() { // Given: Existing rate Hamburg -> New York ContainerRate updateRate = new ContainerRate(); diff --git a/src/test/java/de/avatic/lcc/repositories/rates/MatrixRateRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/rates/MatrixRateRepositoryIntegrationTest.java index c398fd2..5d45d94 100644 --- a/src/test/java/de/avatic/lcc/repositories/rates/MatrixRateRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/rates/MatrixRateRepositoryIntegrationTest.java @@ -5,7 +5,11 @@ import de.avatic.lcc.model.db.rates.ValidityPeriodState; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; import de.avatic.lcc.repositories.pagination.SearchQueryPagination; import de.avatic.lcc.repositories.pagination.SearchQueryResult; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -32,6 +36,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=MatrixRateRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Rates") class MatrixRateRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -73,6 +79,8 @@ class MatrixRateRepositoryIntegrationTest extends AbstractRepositoryIntegrationT } @Test + @Story("List rates") + @DisplayName("List rates") void testListRates() { // Given: Pagination SearchQueryPagination pagination = new SearchQueryPagination(1, 10); @@ -88,6 +96,8 @@ class MatrixRateRepositoryIntegrationTest extends AbstractRepositoryIntegrationT } @Test + @Story("List rates pagination") + @DisplayName("List rates pagination") void testListRatesPagination() { // Given: Pagination with limit 1 SearchQueryPagination pagination = new SearchQueryPagination(1, 1); @@ -102,6 +112,8 @@ class MatrixRateRepositoryIntegrationTest extends AbstractRepositoryIntegrationT } @Test + @Story("List rates by period id") + @DisplayName("List rates by period id") void testListRatesByPeriodId() { // Given: Valid period ID SearchQueryPagination pagination = new SearchQueryPagination(1, 10); @@ -117,6 +129,8 @@ class MatrixRateRepositoryIntegrationTest extends AbstractRepositoryIntegrationT } @Test + @Story("List rates by period id with filter") + @DisplayName("List rates by period id with filter") void testListRatesByPeriodIdWithFilter() { // Given: Filter for "Germany" SearchQueryPagination pagination = new SearchQueryPagination(1, 10); @@ -130,6 +144,8 @@ class MatrixRateRepositoryIntegrationTest extends AbstractRepositoryIntegrationT } @Test + @Story("List rates by period id with iso code filter") + @DisplayName("List rates by period id with iso code filter") void testListRatesByPeriodIdWithIsoCodeFilter() { // Given: Filter for "US" SearchQueryPagination pagination = new SearchQueryPagination(1, 10); @@ -143,6 +159,8 @@ class MatrixRateRepositoryIntegrationTest extends AbstractRepositoryIntegrationT } @Test + @Story("Get by id") + @DisplayName("Get by id") void testGetById() { // Given: Get first rate ID SearchQueryPagination pagination = new SearchQueryPagination(1, 1); @@ -161,6 +179,8 @@ class MatrixRateRepositoryIntegrationTest extends AbstractRepositoryIntegrationT } @Test + @Story("List all rates by period id") + @DisplayName("List all rates by period id") void testListAllRatesByPeriodId() { // When: List all rates for valid period List rates = matrixRateRepository.listAllRatesByPeriodId(testValidPeriodId); @@ -172,6 +192,8 @@ class MatrixRateRepositoryIntegrationTest extends AbstractRepositoryIntegrationT } @Test + @Story("Get by country ids") + @DisplayName("Get by country ids") void testGetByCountryIds() { // When: Get rate from DE to US Optional rate = matrixRateRepository.getByCountryIds(testCountryDeId, testCountryUsId); @@ -184,6 +206,8 @@ class MatrixRateRepositoryIntegrationTest extends AbstractRepositoryIntegrationT } @Test + @Story("Get by country ids not found") + @DisplayName("Get by country ids not found") void testGetByCountryIdsNotFound() { // Given: Non-existent country combination Integer nonExistentCountryId = 99999; @@ -196,6 +220,8 @@ class MatrixRateRepositoryIntegrationTest extends AbstractRepositoryIntegrationT } @Test + @Story("Get by country ids with period id") + @DisplayName("Get by country ids with period id") void testGetByCountryIdsWithPeriodId() { // When: Get rate from DE to US in valid period Optional rate = matrixRateRepository.getByCountryIds(testCountryDeId, testCountryUsId, testValidPeriodId); @@ -208,6 +234,8 @@ class MatrixRateRepositoryIntegrationTest extends AbstractRepositoryIntegrationT } @Test + @Story("Get by country ids with wrong period id") + @DisplayName("Get by country ids with wrong period id") void testGetByCountryIdsWithWrongPeriodId() { // When: Get rate with wrong period ID Optional rate = matrixRateRepository.getByCountryIds(testCountryDeId, testCountryUsId, testDraftPeriodId); @@ -217,6 +245,8 @@ class MatrixRateRepositoryIntegrationTest extends AbstractRepositoryIntegrationT } @Test + @Story("Insert new rate") + @DisplayName("Insert new rate") void testInsertNewRate() { // Given: New matrix rate MatrixRate newRate = new MatrixRate(); @@ -235,6 +265,8 @@ class MatrixRateRepositoryIntegrationTest extends AbstractRepositoryIntegrationT } @Test + @Story("Insert upsert existing") + @DisplayName("Insert upsert existing") void testInsertUpsertExisting() { // Given: Existing rate DE -> US MatrixRate updateRate = new MatrixRate(); @@ -257,6 +289,8 @@ class MatrixRateRepositoryIntegrationTest extends AbstractRepositoryIntegrationT } @Test + @Story("Copy current to draft") + @DisplayName("Copy current to draft") void testCopyCurrentToDraft() { // Given: Valid period has 3 rates, draft has 0 List draftRatesBefore = matrixRateRepository.listAllRatesByPeriodId(testDraftPeriodId); diff --git a/src/test/java/de/avatic/lcc/repositories/rates/ValidityPeriodRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/rates/ValidityPeriodRepositoryIntegrationTest.java index 63e37c2..e26ce51 100644 --- a/src/test/java/de/avatic/lcc/repositories/rates/ValidityPeriodRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/rates/ValidityPeriodRepositoryIntegrationTest.java @@ -3,7 +3,11 @@ package de.avatic.lcc.repositories.rates; import de.avatic.lcc.model.db.rates.ValidityPeriod; import de.avatic.lcc.model.db.rates.ValidityPeriodState; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -30,6 +34,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=ValidityPeriodRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Rates") class ValidityPeriodRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -60,6 +66,8 @@ class ValidityPeriodRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("List periods") + @DisplayName("List periods") void testListPeriods() { // When: List all periods List periods = validityPeriodRepository.listPeriods(); @@ -76,6 +84,8 @@ class ValidityPeriodRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Get by id") + @DisplayName("Get by id") void testGetById() { // When: Get by ID ValidityPeriod period = validityPeriodRepository.getById(testValidPeriodId); @@ -89,6 +99,8 @@ class ValidityPeriodRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Get valid period") + @DisplayName("Get valid period") void testGetValidPeriod() { // When: Get valid period Optional period = validityPeriodRepository.getValidPeriod(); @@ -100,6 +112,8 @@ class ValidityPeriodRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Get valid period id") + @DisplayName("Get valid period id") void testGetValidPeriodId() { // When: Get valid period ID Optional periodId = validityPeriodRepository.getValidPeriodId(); @@ -110,6 +124,8 @@ class ValidityPeriodRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Invalidate by id") + @DisplayName("Invalidate by id") void testInvalidateById() { // When: Invalidate expired period boolean invalidated = validityPeriodRepository.invalidateById(testExpiredPeriodId); @@ -122,6 +138,8 @@ class ValidityPeriodRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Invalidate by id fails for non expired") + @DisplayName("Invalidate by id fails for non expired") void testInvalidateByIdFailsForNonExpired() { // When: Try to invalidate VALID period (should only work for EXPIRED) boolean invalidated = validityPeriodRepository.invalidateById(testValidPeriodId); @@ -134,6 +152,8 @@ class ValidityPeriodRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Get period id") + @DisplayName("Get period id") void testGetPeriodId() { // Given: Time within valid period LocalDateTime now = LocalDateTime.now(); @@ -147,6 +167,8 @@ class ValidityPeriodRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Get period id for past date") + @DisplayName("Get period id for past date") void testGetPeriodIdForPastDate() { // Given: Time within expired period range LocalDateTime pastTime = LocalDateTime.now().minusDays(20); @@ -160,6 +182,8 @@ class ValidityPeriodRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Get period id not found") + @DisplayName("Get period id not found") void testGetPeriodIdNotFound() { // Given: Only expired periods (create valid period with end date so future is not covered) jdbcTemplate.update("DELETE FROM validity_period WHERE state = 'VALID'"); @@ -175,6 +199,8 @@ class ValidityPeriodRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Get by date") + @DisplayName("Get by date") void testGetByDate() { // Given: Today's date LocalDate today = LocalDate.now(); @@ -189,6 +215,8 @@ class ValidityPeriodRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Get by date past") + @DisplayName("Get by date past") void testGetByDatePast() { // Given: Date within expired period range LocalDate pastDate = LocalDate.now().minusDays(20); @@ -203,6 +231,8 @@ class ValidityPeriodRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Get by date not found") + @DisplayName("Get by date not found") void testGetByDateNotFound() { // Given: Only expired periods (create valid period with end date so future is not covered) jdbcTemplate.update("DELETE FROM validity_period WHERE state = 'VALID'"); @@ -218,6 +248,8 @@ class ValidityPeriodRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Has rate drafts") + @DisplayName("Has rate drafts") void testHasRateDrafts() { // Given: Create draft period (but no associated rates) Integer draftId = createTestValidityPeriod(ValidityPeriodState.DRAFT, @@ -231,6 +263,8 @@ class ValidityPeriodRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Has matrix rate drafts") + @DisplayName("Has matrix rate drafts") void testHasMatrixRateDrafts() { // Given: Create draft period (but no associated matrix rates) Integer draftId = createTestValidityPeriod(ValidityPeriodState.DRAFT, @@ -244,6 +278,8 @@ class ValidityPeriodRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Has container rate drafts") + @DisplayName("Has container rate drafts") void testHasContainerRateDrafts() { // Given: Create draft period (but no associated container rates) Integer draftId = createTestValidityPeriod(ValidityPeriodState.DRAFT, @@ -257,6 +293,8 @@ class ValidityPeriodRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Increase renewal") + @DisplayName("Increase renewal") void testIncreaseRenewal() { // Given: Valid period with initial renewals ValidityPeriod before = validityPeriodRepository.getById(testValidPeriodId); @@ -272,6 +310,8 @@ class ValidityPeriodRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Get by date ordering with pagination") + @DisplayName("Get by date ordering with pagination") void testGetByDateOrderingWithPagination() { // Given: Multiple periods with overlapping date ranges // testExpiredPeriodId covers: -30 to -15 days @@ -289,6 +329,8 @@ class ValidityPeriodRepositoryIntegrationTest extends AbstractRepositoryIntegrat } @Test + @Story("Multiple periods") + @DisplayName("Multiple periods") void testMultiplePeriods() { // Given: Create multiple periods Integer draft = createTestValidityPeriod(ValidityPeriodState.DRAFT, diff --git a/src/test/java/de/avatic/lcc/repositories/users/AppRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/users/AppRepositoryIntegrationTest.java index d535e99..4209902 100644 --- a/src/test/java/de/avatic/lcc/repositories/users/AppRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/users/AppRepositoryIntegrationTest.java @@ -3,7 +3,11 @@ package de.avatic.lcc.repositories.users; import de.avatic.lcc.model.db.users.App; import de.avatic.lcc.model.db.users.Group; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -28,6 +32,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=AppRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Users") class AppRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -44,6 +50,8 @@ class AppRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("List apps") + @DisplayName("List apps") void testListApps() { // Given: Insert test apps App app1 = createTestApp("Test App 1", "client1", "secret1"); @@ -65,6 +73,8 @@ class AppRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Get by id") + @DisplayName("Get by id") void testGetById() { // Given: Create app App app = createTestApp("Test App", "client123", "secret123"); @@ -81,6 +91,8 @@ class AppRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Get by id not found") + @DisplayName("Get by id not found") void testGetByIdNotFound() { // When: Get non-existent app Optional result = appRepository.getById(99999); @@ -90,6 +102,8 @@ class AppRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Get by client id") + @DisplayName("Get by client id") void testGetByClientId() { // Given: Create app with specific client ID App app = createTestApp("OAuth App", "oauth_client_id", "oauth_secret"); @@ -104,6 +118,8 @@ class AppRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Get by client id not found") + @DisplayName("Get by client id not found") void testGetByClientIdNotFound() { // When: Get non-existent client ID Optional result = appRepository.getByClientId("nonexistent"); @@ -113,6 +129,8 @@ class AppRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Insert app") + @DisplayName("Insert app") void testInsertApp() { // Given: New app App app = createTestApp("New App", "new_client", "new_secret"); @@ -131,6 +149,8 @@ class AppRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Update app") + @DisplayName("Update app") void testUpdateApp() { // Given: Existing app App app = createTestApp("Original Name", "update_client", "update_secret"); @@ -148,6 +168,8 @@ class AppRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Delete app") + @DisplayName("Delete app") void testDeleteApp() { // Given: Create app App app = createTestApp("Delete Me", "delete_client", "delete_secret"); @@ -162,6 +184,8 @@ class AppRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("App with groups") + @DisplayName("App with groups") void testAppWithGroups() { // Given: App with groups App app = createTestApp("App with Groups", "grouped_client", "grouped_secret"); @@ -187,6 +211,8 @@ class AppRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Update app groups") + @DisplayName("Update app groups") void testUpdateAppGroups() { // Given: App with one group App app = createTestApp("Group Update Test", "group_update_client", "group_update_secret"); @@ -210,6 +236,8 @@ class AppRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Delete app cascades group mappings") + @DisplayName("Delete app cascades group mappings") void testDeleteAppCascadesGroupMappings() { // Given: App with groups App app = createTestApp("Cascade Delete Test", "cascade_client", "cascade_secret"); @@ -228,6 +256,8 @@ class AppRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("App with empty groups") + @DisplayName("App with empty groups") void testAppWithEmptyGroups() { // Given: App with empty groups list App app = createTestApp("No Groups App", "no_groups_client", "no_groups_secret"); diff --git a/src/test/java/de/avatic/lcc/repositories/users/GroupRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/users/GroupRepositoryIntegrationTest.java index 1744cca..86f25ee 100644 --- a/src/test/java/de/avatic/lcc/repositories/users/GroupRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/users/GroupRepositoryIntegrationTest.java @@ -4,7 +4,11 @@ import de.avatic.lcc.model.db.users.Group; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; import de.avatic.lcc.repositories.pagination.SearchQueryPagination; import de.avatic.lcc.repositories.pagination.SearchQueryResult; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -26,6 +30,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=GroupRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Users") class GroupRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -45,6 +51,8 @@ class GroupRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("List groups") + @DisplayName("List groups") void testListGroups() { // Given: Pagination SearchQueryPagination pagination = new SearchQueryPagination(1, 10); @@ -59,6 +67,8 @@ class GroupRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("List groups pagination") + @DisplayName("List groups pagination") void testListGroupsPagination() { // Given: Pagination with limit 2 SearchQueryPagination pagination = new SearchQueryPagination(1, 2); @@ -73,6 +83,8 @@ class GroupRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("List groups ordering") + @DisplayName("List groups ordering") void testListGroupsOrdering() { // Given: Pagination SearchQueryPagination pagination = new SearchQueryPagination(1, 10); @@ -90,6 +102,8 @@ class GroupRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Find group ids") + @DisplayName("Find group ids") void testFindGroupIds() { // When: Find group IDs by names List ids = groupRepository.findGroupIds(List.of("Administrators", "Developers")); @@ -100,6 +114,8 @@ class GroupRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Find group ids single") + @DisplayName("Find group ids single") void testFindGroupIdsSingle() { // When: Find single group ID List ids = groupRepository.findGroupIds(List.of("Administrators")); @@ -110,6 +126,8 @@ class GroupRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Find group ids not found") + @DisplayName("Find group ids not found") void testFindGroupIdsNotFound() { // When: Find non-existent group List ids = groupRepository.findGroupIds(List.of("NonExistent")); @@ -120,6 +138,8 @@ class GroupRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Find group ids empty list") + @DisplayName("Find group ids empty list") void testFindGroupIdsEmptyList() { // When: Find with empty list List ids = groupRepository.findGroupIds(List.of()); @@ -130,6 +150,8 @@ class GroupRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Find group ids null") + @DisplayName("Find group ids null") void testFindGroupIdsNull() { // When: Find with null List ids = groupRepository.findGroupIds(null); @@ -140,6 +162,8 @@ class GroupRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Update group insert") + @DisplayName("Update group insert") void testUpdateGroupInsert() { // Given: New group Group newGroup = new Group(); @@ -160,6 +184,8 @@ class GroupRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Update group upsert") + @DisplayName("Update group upsert") void testUpdateGroupUpsert() { // Given: Existing group name Group updateGroup = new Group(); @@ -185,6 +211,8 @@ class GroupRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Find group ids multiple") + @DisplayName("Find group ids multiple") void testFindGroupIdsMultiple() { // When: Find multiple group IDs List ids = groupRepository.findGroupIds( @@ -196,6 +224,8 @@ class GroupRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Find group ids partial match") + @DisplayName("Find group ids partial match") void testFindGroupIdsPartialMatch() { // When: Find mix of existing and non-existing groups List ids = groupRepository.findGroupIds( diff --git a/src/test/java/de/avatic/lcc/repositories/users/UserNodeRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/users/UserNodeRepositoryIntegrationTest.java index 6f69cf2..355d200 100644 --- a/src/test/java/de/avatic/lcc/repositories/users/UserNodeRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/users/UserNodeRepositoryIntegrationTest.java @@ -2,7 +2,11 @@ package de.avatic.lcc.repositories.users; import de.avatic.lcc.model.db.nodes.Node; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -28,6 +32,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=UserNodeRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Users") class UserNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -48,6 +54,8 @@ class UserNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Add and retrieve") + @DisplayName("Add and retrieve") void testAddAndRetrieve() { // Given: Create user node Node node = createTestNode("Test Supplier Berlin", "Berlin, Germany", 52.5200, 13.4050); @@ -74,6 +82,8 @@ class UserNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Get by id not found") + @DisplayName("Get by id not found") void testGetByIdNotFound() { // When: Get by non-existent ID Optional result = userNodeRepository.getById(99999); @@ -83,6 +93,8 @@ class UserNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Search node with filter") + @DisplayName("Search node with filter") void testSearchNodeWithFilter() { // Given: Insert multiple user nodes Node node1 = createTestNode("Berlin Supplier", "Berlin", 52.5200, 13.4050); @@ -108,6 +120,8 @@ class UserNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Search node with pagination") + @DisplayName("Search node with pagination") void testSearchNodeWithPagination() { // Given: Insert multiple user nodes for (int i = 1; i <= 5; i++) { @@ -124,6 +138,8 @@ class UserNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Search node exclude deprecated") + @DisplayName("Search node exclude deprecated") void testSearchNodeExcludeDeprecated() { // Given: Insert deprecated and non-deprecated user nodes Node deprecated = createTestNode("Deprecated Supplier", "Old Address", 50.0, 10.0); @@ -144,6 +160,8 @@ class UserNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Search node by user id") + @DisplayName("Search node by user id") void testSearchNodeByUserId() { // Given: Insert nodes for different users Node user1Node = createTestNode("User 1 Supplier", "User 1 Address", 50.0, 10.0); @@ -167,6 +185,8 @@ class UserNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Get by ids") + @DisplayName("Get by ids") void testGetByIds() { // Given: Insert multiple user nodes Node node1 = createTestNode("Bulk Node 1", "Address 1", 50.0, 10.0); @@ -193,6 +213,8 @@ class UserNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Get by ids empty list") + @DisplayName("Get by ids empty list") void testGetByIdsEmptyList() { // When: Get by empty list Collection nodes = userNodeRepository.getByIds(List.of()); @@ -203,6 +225,8 @@ class UserNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Get owner by id") + @DisplayName("Get owner by id") void testGetOwnerById() { // Given: Insert user node Node node = createTestNode("Owner Test Node", "Address", 50.0, 10.0); @@ -217,6 +241,8 @@ class UserNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Get owner by id not found") + @DisplayName("Get owner by id not found") void testGetOwnerByIdNotFound() { // When: Get owner of non-existent node Optional owner = userNodeRepository.getOwnerById(99999); @@ -226,6 +252,8 @@ class UserNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Check owner valid") + @DisplayName("Check owner valid") void testCheckOwnerValid() { // Given: Insert user nodes Node node1 = createTestNode("Owner Check 1", "Address 1", 50.0, 10.0); @@ -241,6 +269,8 @@ class UserNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Check owner invalid") + @DisplayName("Check owner invalid") void testCheckOwnerInvalid() { // Given: Insert user node for user1 Node node = createTestNode("Owner Violation", "Address", 50.0, 10.0); @@ -253,6 +283,8 @@ class UserNodeRepositoryIntegrationTest extends AbstractRepositoryIntegrationTes } @Test + @Story("Check owner empty list") + @DisplayName("Check owner empty list") void testCheckOwnerEmptyList() { // When/Then: Should not throw exception for empty list assertDoesNotThrow(() -> diff --git a/src/test/java/de/avatic/lcc/repositories/users/UserRepositoryIntegrationTest.java b/src/test/java/de/avatic/lcc/repositories/users/UserRepositoryIntegrationTest.java index 297e1bd..376d5f0 100644 --- a/src/test/java/de/avatic/lcc/repositories/users/UserRepositoryIntegrationTest.java +++ b/src/test/java/de/avatic/lcc/repositories/users/UserRepositoryIntegrationTest.java @@ -5,7 +5,11 @@ import de.avatic.lcc.model.db.users.User; import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest; import de.avatic.lcc.repositories.pagination.SearchQueryPagination; import de.avatic.lcc.repositories.pagination.SearchQueryResult; +import io.qameta.allure.Epic; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -29,6 +33,8 @@ import static org.junit.jupiter.api.Assertions.*; * mvn test -Dspring.profiles.active=test,mssql -Dtest=UserRepositoryIntegrationTest * */ +@Epic("Repository") +@Feature("Users") class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { @Autowired @@ -67,6 +73,8 @@ class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("List users") + @DisplayName("List users") void testListUsers() { // Given: Pagination SearchQueryPagination pagination = new SearchQueryPagination(1, 10); @@ -81,6 +89,8 @@ class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("List users pagination") + @DisplayName("List users pagination") void testListUsersPagination() { // Given: Pagination with limit 2 SearchQueryPagination pagination = new SearchQueryPagination(1, 2); @@ -95,6 +105,8 @@ class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("List users ordering") + @DisplayName("List users ordering") void testListUsersOrdering() { // Given: Pagination SearchQueryPagination pagination = new SearchQueryPagination(1, 10); @@ -112,6 +124,8 @@ class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Update insert new user") + @DisplayName("Update insert new user") void testUpdateInsertNewUser() { // Given: New user User newUser = new User(); @@ -136,6 +150,8 @@ class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Update existing user") + @DisplayName("Update existing user") void testUpdateExistingUser() { // Given: Existing user User user = userRepository.getByWorkdayId("WD001").orElseThrow(); @@ -155,6 +171,8 @@ class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Update user with groups") + @DisplayName("Update user with groups") void testUpdateUserWithGroups() { // Given: New user with groups User newUser = new User(); @@ -180,6 +198,8 @@ class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Update user remove groups") + @DisplayName("Update user remove groups") void testUpdateUserRemoveGroups() { // Given: User with groups User user = userRepository.getByWorkdayId("WD001").orElseThrow(); @@ -195,6 +215,8 @@ class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Update user change groups") + @DisplayName("Update user change groups") void testUpdateUserChangeGroups() { // Given: User with Admin group User user = userRepository.getByWorkdayId("WD001").orElseThrow(); @@ -213,6 +235,8 @@ class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Count") + @DisplayName("Count") void testCount() { // When: Count users Integer count = userRepository.count(); @@ -222,6 +246,8 @@ class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Get user id by workday id") + @DisplayName("Get user id by workday id") void testGetUserIdByWorkdayId() { // When: Get user ID by workday ID Integer userId = userRepository.getUserIdByWorkdayId("WD001"); @@ -232,6 +258,8 @@ class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Get user id by workday id not found") + @DisplayName("Get user id by workday id not found") void testGetUserIdByWorkdayIdNotFound() { // When: Get non-existent user Integer userId = userRepository.getUserIdByWorkdayId("NONEXISTENT"); @@ -241,6 +269,8 @@ class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Get by workday id") + @DisplayName("Get by workday id") void testGetByWorkdayId() { // When: Get user by workday ID Optional user = userRepository.getByWorkdayId("WD001"); @@ -253,6 +283,8 @@ class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Get by workday id not found") + @DisplayName("Get by workday id not found") void testGetByWorkdayIdNotFound() { // When: Get non-existent user Optional user = userRepository.getByWorkdayId("NONEXISTENT"); @@ -262,6 +294,8 @@ class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Get by id") + @DisplayName("Get by id") void testGetById() { // Given: User ID Integer userId = userRepository.getUserIdByWorkdayId("WD001"); @@ -275,6 +309,8 @@ class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Get by id not found") + @DisplayName("Get by id not found") void testGetByIdNotFound() { // When: Get non-existent ID User user = userRepository.getById(99999); @@ -284,6 +320,8 @@ class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Get by email") + @DisplayName("Get by email") void testGetByEmail() { // When: Get user by email User user = userRepository.getByEmail("john.doe@example.com"); @@ -295,6 +333,8 @@ class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("Get by email not found") + @DisplayName("Get by email not found") void testGetByEmailNotFound() { // When: Get non-existent email User user = userRepository.getByEmail("nonexistent@example.com"); @@ -304,6 +344,8 @@ class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("User with group memberships") + @DisplayName("User with group memberships") void testUserWithGroupMemberships() { // When: Get user with groups User user = userRepository.getByWorkdayId("WD001").orElseThrow(); @@ -315,6 +357,8 @@ class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { } @Test + @Story("User without group memberships") + @DisplayName("User without group memberships") void testUserWithoutGroupMemberships() { // When: Get user without groups User user = userRepository.getByWorkdayId("WD003").orElseThrow(); -- 2.45.3 From 081d69577e2f0981f4aa8284e7788bc09538f83e Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 10 Feb 2026 09:38:05 +0100 Subject: [PATCH 16/18] added Maven compile step before Playwright browser installation in test.yml --- .gitea/workflows/test.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index 2a6c5d7..a350078 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -38,7 +38,9 @@ jobs: run: cd src/frontend && npm ci && BUILD_FOR_SPRING=true npm run build - name: Install Playwright Browsers - run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps chromium" + run: | + mvn compile -B --no-transfer-progress + mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps chromium" - name: Run Tests run: mvn verify -B --no-transfer-progress -- 2.45.3 From 7f6b6378f232934ba870a4a28dc8c141c46a99a3 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 10 Feb 2026 09:45:39 +0100 Subject: [PATCH 17/18] updated Maven command in test.yml to use test-compile for Playwright browser installation --- .gitea/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index a350078..fb5b730 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -39,8 +39,8 @@ jobs: - name: Install Playwright Browsers run: | - mvn compile -B --no-transfer-progress - mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps chromium" + mvn test-compile -B --no-transfer-progress + mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.classpathScope=test -D exec.args="install --with-deps chromium" - name: Run Tests run: mvn verify -B --no-transfer-progress -- 2.45.3 From 0f401ff77b1709f97856ff889b56bf59fda5af20 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 10 Feb 2026 09:58:59 +0100 Subject: [PATCH 18/18] set PLAYWRIGHT_DOWNLOAD_CONNECTION_TIMEOUT in test.yml to ensure stable browser installation --- .gitea/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index fb5b730..6d07884 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -41,6 +41,8 @@ jobs: run: | mvn test-compile -B --no-transfer-progress mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.classpathScope=test -D exec.args="install --with-deps chromium" + env: + PLAYWRIGHT_DOWNLOAD_CONNECTION_TIMEOUT: "300000" - name: Run Tests run: mvn verify -B --no-transfer-progress -- 2.45.3