Skip to content

Commit 17aa123

Browse files
authored
Merge pull request #22 from hmcts/chore/amp-187-api_tests
AMP-187 Add api test as a separate module in project which can be inv…
2 parents b5bbb79 + 484c583 commit 17aa123

File tree

14 files changed

+327
-60
lines changed

14 files changed

+327
-60
lines changed

.github/workflows/codeql.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ jobs:
9696

9797
- name: DAST - Build and run containerised app
9898
run: |
99+
cd apiTest
99100
docker compose -f docker-compose.yml up -d
100101
101102
echo "Waiting for health endpoint..."

apiTest/apiTest_README.md

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
# API Test Module
2+
3+
This module contains api tests that run against a Docker containerized version of the application.
4+
The tests make HTTP calls to verify the API endpoints are working correctly.
5+
6+
## Overview
7+
8+
The `apiTest` module is a standalone Gradle project that:
9+
- Runs api tests against the application running in Docker containers
10+
- Automatically manages Docker containers (starts before tests, stops after)
11+
- Generates HTML and XML test reports
12+
13+
## Prerequisites
14+
15+
Before running the tests, ensure you have the following installed and configured:
16+
17+
### Required Software
18+
19+
1. **Java 21** (or higher)
20+
- Verify installation: `java -version`
21+
- Should show version 21 or higher
22+
23+
2. **Docker Desktop** (or Docker Engine)
24+
- Verify installation: `docker --version`
25+
- Docker must be running (check with `docker ps`)
26+
- Docker Compose V2 must be available: `docker compose version`
27+
28+
### System Requirements
29+
30+
- At least 4GB of free RAM (Docker containers need memory)
31+
- Ports available: `8082` (application), `5432` (PostgreSQL), `9999` (WireMock)
32+
- Sufficient disk space for Docker images
33+
34+
## Running Tests
35+
36+
### From the Root Directory
37+
38+
```bash
39+
# Navigate to the apiTest directory
40+
cd apiTest
41+
42+
# Run all tests
43+
../gradlew test
44+
45+
# Run tests with more verbose output
46+
../gradlew test --info
47+
48+
# Run tests with debug output
49+
../gradlew test --debug
50+
```
51+
52+
### From the apiTest Directory
53+
54+
```bash
55+
# If you're already in the apiTest directory
56+
../gradlew test
57+
```
58+
59+
### What Happens When You Run Tests
60+
61+
1. **Builds the root project's bootJar** - The application JAR is built first
62+
2. **Builds Docker images** - Creates the application Docker image
63+
3. **Starts Docker containers**:
64+
- PostgreSQL database (port 5432)
65+
- Application server (port 8082)
66+
- WireMock server (port 9999)
67+
4. **Runs tests** - Executes all test classes
68+
5. **Stops and removes containers** - Cleanup after tests complete
69+
70+
### Running Specific Tests
71+
72+
```bash
73+
# Run a specific test class
74+
../gradlew test --tests "RootApiTest"
75+
76+
# Run a specific test method
77+
../gradlew test --tests "RootApiTest.root_endpoint_should_be_ok"
78+
```
79+
80+
## Test Reports
81+
82+
After running tests, you can view the results in several formats:
83+
84+
### HTML Test Report (Recommended)
85+
86+
**Location:** `apiTest/build/reports/tests/test/index.html`
87+
88+
The HTML report includes:
89+
- Test summary (total, passed, failed, skipped)
90+
- Individual test results with execution times
91+
- Stack traces for failed tests
92+
- Package and class-level summaries
93+
94+
### JUnit XML Reports
95+
96+
**Location:** `apiTest/build/test-results/test/`
97+
98+
These XML reports are useful for CI/CD integration.
99+
100+
## Troubleshooting
101+
102+
### Issue: "Could not start Gradle Test Executor 1: Failed to load JUnit Platform"
103+
104+
**Solution:** This should be resolved with the current configuration. If you see this error:
105+
1. Clean the build: `../gradlew clean`
106+
2. Rebuild: `../gradlew build`
107+
108+
### Issue: "no main manifest attribute, in /app/apiTest-0.0.999.jar"
109+
110+
**Solution:** This means the Docker build context is wrong. Ensure:
111+
1. The `docker-compose.yml` has `context: ..` (builds from root directory)
112+
2. The root project's `bootJar` is built before Docker build
113+
3. Run: `../gradlew buildRootBootJar` manually if needed
114+
115+
### Issue: Container exits with code 1
116+
117+
**Check application logs:**
118+
```bash
119+
# View app container logs
120+
docker logs apitest-app-1
121+
122+
# Or using docker-compose
123+
docker-compose -f docker-compose.yml logs app
124+
125+
# View all container logs
126+
docker-compose -f docker-compose.yml logs
127+
```
128+
129+
**Common causes:**
130+
- Application configuration errors
131+
- Database connection issues
132+
- Missing environment variables
133+
- Port conflicts
134+
135+
### Issue: Port already in use
136+
137+
**Solution:** Stop any services using the required ports:
138+
```bash
139+
# Check what's using port 8082
140+
lsof -i :8082
141+
142+
# Check what's using port 5432
143+
lsof -i :5432
144+
145+
# Stop conflicting services or change ports in docker-compose.yml
146+
```
147+
148+
### Issue: Cannot connect to database
149+
150+
**Solution:**
151+
- Ensure the database container is healthy: `docker ps` should show "Healthy"
152+
- Check database logs: `docker-compose -f docker-compose.yml logs db`
153+
- Verify connection string in `docker-compose.yml` matches database configuration
154+
155+
## Manual Container Management
156+
157+
If you need to manually manage containers:
158+
159+
```bash
160+
# Start containers without running tests
161+
docker-compose -f docker-compose.yml up -d
162+
163+
# Stop containers
164+
docker-compose -f docker-compose.yml down
165+
166+
# View container logs
167+
docker-compose -f docker-compose.yml logs -f app
168+
169+
# Check container status
170+
docker-compose -f docker-compose.yml ps
171+
172+
# Rebuild containers
173+
docker-compose -f docker-compose.yml build --no-cache
174+
```
175+
176+
## Test Configuration
177+
178+
### Environment Variables
179+
180+
Tests use the following default configuration:
181+
- Application base URL: `http://localhost:8082` (can be overridden with `app.baseUrl` system property)
182+
- Database: PostgreSQL on port 5432
183+
- WireMock: Port 9999
184+
185+
### Customizing Test Execution
186+
187+
You can override the application URL:
188+
```bash
189+
gradle test -Dapp.baseUrl=http://localhost:8080
190+
```
191+

apiTest/build.gradle

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// TODO need to delete duplicate code
2+
plugins {
3+
id 'java'
4+
id 'com.avast.gradle.docker-compose' version '0.17.20'
5+
id 'io.spring.dependency-management' version '1.1.7'
6+
}
7+
8+
group = 'uk.gov.hmcts.cp'
9+
version = System.getProperty('ARTEFACT_VERSION') ?: '0.0.999'
10+
11+
// Disable main source set since this module only has tests
12+
sourceSets {
13+
main {
14+
java.srcDirs = []
15+
resources.srcDirs = []
16+
}
17+
}
18+
19+
// Disable unnecessary tasks for test-only module
20+
tasks.named('jar') {
21+
enabled = false
22+
}
23+
24+
tasks.named('compileJava') {
25+
enabled = false
26+
}
27+
28+
tasks.named('processResources') {
29+
enabled = false
30+
}
31+
32+
dependencyManagement {
33+
imports {
34+
mavenBom "org.springframework.boot:spring-boot-dependencies:4.0.1"
35+
}
36+
}
37+
38+
tasks.named('test') {
39+
description = "Runs api tests against docker-compose stack"
40+
group = "Verification"
41+
useJUnitPlatform()
42+
dependsOn tasks.composeUp
43+
finalizedBy tasks.composeDown
44+
45+
testLogging {
46+
events "passed", "skipped", "failed"
47+
exceptionFormat = 'full'
48+
showStandardStreams = true
49+
}
50+
51+
reports {
52+
junitXml.required.set(true)
53+
html.required.set(true)
54+
}
55+
}
56+
57+
tasks.named('build') {
58+
dependsOn tasks.named('test')
59+
}
60+
61+
dockerCompose {
62+
useComposeFiles = ['docker-compose.yml']
63+
startedServices = ['db', 'app']
64+
65+
buildBeforeUp = true
66+
waitForTcpPorts = true
67+
upAdditionalArgs = ['--wait', '--wait-timeout', '120']
68+
69+
captureContainersOutput = true
70+
removeOrphans = true
71+
stopContainers = true
72+
removeContainers = true
73+
74+
useDockerComposeV2 = true
75+
dockerExecutable = 'docker'
76+
}
77+
78+
// Build the root project's bootJar before building Docker image
79+
tasks.register('buildRootBootJar', Exec) {
80+
description = "Builds the root project's bootJar"
81+
workingDir = projectDir.parent
82+
executable = "${projectDir.parent}/gradlew"
83+
args = ['bootJar']
84+
}
85+
86+
tasks.named('composeBuild') {
87+
dependsOn tasks.named('buildRootBootJar')
88+
}
89+
90+
dependencies {
91+
testImplementation "org.springframework:spring-web"
92+
testImplementation "org.springframework.boot:spring-boot-starter-test"
93+
testRuntimeOnly "org.junit.platform:junit-platform-launcher"
94+
}
95+
96+
repositories {
97+
mavenLocal()
98+
mavenCentral()
99+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ services:
1010

1111
app:
1212
build:
13+
context: ..
1314
dockerfile: Dockerfile
1415
environment:
1516
SERVER_PORT: 8082

src/apiTest/java/uk/gov/hmcts/cp/subscription/http/ActuatorApiTest.java renamed to apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/ActuatorApiTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
class ActuatorApiTest {
1414

1515
private final String baseUrl = System.getProperty("app.baseUrl", "http://localhost:8082");
16+
// TODO remove this client and use FeignClient/RestClient
1617
private final RestTemplate http = new RestTemplate();
1718

1819
@Test

src/apiTest/java/uk/gov/hmcts/cp/subscription/http/RootApiTest.java renamed to apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/RootApiTest.java

File renamed without changes.

src/apiTest/java/uk/gov/hmcts/cp/subscription/http/SubscriptionApiTest.java renamed to apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/SubscriptionApiTest.java

File renamed without changes.
8.48 KB
Binary file not shown.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"materialId": "6c198796-08bb-4803-b456-fa0c29ca6021",
3+
"alfrescoAssetId": "82257b1b-571d-432e-8871-b0c5b4bd18b1",
4+
"fileName": "PrisonCourtRegister_20251219083322.pdf",
5+
"mimeType": "application/pdf",
6+
"materialAddedDate": "2025-12-19T08:33:29.866Z"
7+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"request": {
3+
"method": "GET",
4+
"url": "/material-query-api/query/api/rest/material/material/7c198796-08bb-4803-b456-fa0c29ca6021/content"
5+
},
6+
"response": {
7+
"status": 200,
8+
"headers": {
9+
"Content-Type": "application/pdf",
10+
"Content-Disposition": "inline; filename=\"material-content.pdf\""
11+
},
12+
"bodyFileName": "material-content.pdf"
13+
}
14+
}

0 commit comments

Comments
 (0)