Skip to content

Commit

Permalink
test: configure karate test framework with docker
Browse files Browse the repository at this point in the history
  • Loading branch information
olisaagbafor committed Dec 12, 2024
2 parents 7bfc1ea + 6cb1a79 commit e87ab7b
Show file tree
Hide file tree
Showing 15 changed files with 191 additions and 361 deletions.
25 changes: 9 additions & 16 deletions Dockerfile.test
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
FROM node:18
FROM openjdk:17

WORKDIR /app

# Install Java (required for Karate)
RUN apt-get update && \
apt-get install -y openjdk-17-jdk && \
apt-get clean
# Copy test files
COPY tests /app/tests

# Copy package files and install dependencies (if any)
COPY package*.json ./
RUN npm install --only=production
# Make sure karate-config.js is in the right place
RUN mkdir -p /app/tests/karate/src/test/resources
# Create directory for test results
RUN mkdir -p /app/target/karate-reports

# Copy the Karate JAR file and test files
COPY tests/karate.jar /app/tests/karate.jar
COPY tests /app/tests/
RUN chmod -R 755 /app/tests


# Set the entry point
CMD ["npm", "test"]
# Set default command
CMD ["java", "-jar", "/app/tests/karate.jar", "--configdir", "/app/tests/karate/src/test/resources", "/app/tests/karate/features"]
103 changes: 40 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,88 +124,65 @@ This project uses Karate framework for API testing. The tests are designed to ru

```
backend/
├── docker-compose-test.yml
├── Dockerfile.test
└── tests/
├── karate.jar
└── karate/
├── karate-config.js
├── helpers/
── generate-token.js
└── features/
── auth/
├── login.feature
└── permissions.feature
└── users/
── create.feature
── query.feature
└── wallets.feature
├── features/
├── auth/
│ ├── login.feature
│ │ └── permissions.feature
── users/
├── create.feature
└── query.feature
└── src/
── test/
── resources/
└── karate-config.js
```

## Running Tests

1. **Build the Test Environment**
To run all tests:

```bash
docker-compose -f docker-compose-test.yml build
```
```bash
docker compose -f docker-compose-test.yml up --build --abort-on-container-exit
```

2. **Run the Tests**
This command will:

```bash
docker-compose -f docker-compose-test.yml run --rm karate
```
1. Build the test container
2. Start PostgreSQL and Hasura containers
3. Run all Karate tests
4. Show test results in the console
5. Generate HTML reports in `target/karate-reports/`

3. **Clean Up After Testing**
```bash
docker-compose -f docker-compose-test.yml down
```
## Test Reports

## Test Configuration
After running the tests, you can find the HTML reports at:

The test configuration is managed through `karate-config.js`. Key configurations include:
- Summary: `tests/results/karate-summary.html`
- Detailed: `tests/results/karate-tags.html`

- GraphQL endpoint URL
- JWT authentication settings
- Admin secret
## Development

## Test Features
### Adding New Tests

- **Auth Tests** (`features/auth/`)
1. Create new `.feature` files in `tests/karate/features/`
2. Follow the Karate DSL syntax
3. Tests will be automatically picked up when running the test command

- Login functionality
- Permission checks
### Configuration

- **User Tests** (`features/users/`)
- User creation
- User queries
- Wallet management
- Main config: `tests/karate/src/test/resources/karate-config.js`
- Database config: `docker-compose-test.yml`
- Test environment: `Dockerfile.test`

## Troubleshooting

If you encounter any issues:

1. **Docker Network Issues**

```bash
docker-compose -f docker-compose-test.yml down
docker system prune -a --volumes
docker-compose -f docker-compose-test.yml up -d
```

2. **Test Container Access**
```bash
docker-compose -f docker-compose-test.yml run --rm karate sh
```

## Development

To add new tests:

1. Create a new `.feature` file in the appropriate directory under `features/`
2. Follow the Karate framework's Gherkin syntax
3. Run the tests to verify the new features

## Notes
If tests fail with connection errors:

- Tests run against a dedicated test database
- JWT tokens are generated automatically for test authentication
- GraphQL queries are executed against the Hasura GraphQL engine
1. Ensure all containers are running: `docker compose -f docker-compose-test.yml ps`
2. Check container logs: `docker compose -f docker-compose-test.yml logs`
3. Verify network connectivity: `docker network inspect backend_test-network`
32 changes: 21 additions & 11 deletions docker-compose-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,50 @@ services:
restart: always
environment:
POSTGRES_PASSWORD: postgrespassword
POSTGRES_DB: safetrust
ports:
- "5433:5432" # Changed from 5432 to 5433 for the host port
- "5432:5432"
networks:
- test-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5

graphql-engine-test:
image: hasura/graphql-engine:v2.33.4
image: hasura/graphql-engine:latest
ports:
- "8081:8080" # Make sure this port is also unique
- "8081:8080"
depends_on:
postgres_test:
condition: service_healthy
restart: always
environment:
HASURA_GRAPHQL_DATABASE_URL: "postgres://postgres:postgrespassword@postgres_test:5432/safetrust?sslmode=disable"
HASURA_GRAPHQL_DATABASE_URL: postgres://postgres:postgrespassword@postgres_test:5432/postgres
HASURA_GRAPHQL_ENABLE_CONSOLE: "true"
HASURA_GRAPHQL_DEV_MODE: "true"
HASURA_GRAPHQL_ADMIN_SECRET: "myadminsecretkey"
HASURA_GRAPHQL_ADMIN_SECRET: myadminsecretkey
HASURA_GRAPHQL_JWT_SECRET: '{"type":"HS256", "key": "12345678901234567890123456789012", "claims_format": "json", "claims_namespace": "https://hasura.io/jwt/claims"}'
HASURA_GRAPHQL_UNAUTHORIZED_ROLE: "anonymous"
HASURA_GRAPHQL_LOG_LEVEL: "debug"
HASURA_GRAPHQL_ENABLED_LOG_TYPES: "startup,http-log,webhook-log,websocket-log,query-log"
ACTION_BASE_URL: http://action-handler:3000
volumes:
- ./tests/metadata:/hasura-metadata
networks:
- test-network

karate:
build:
context: .
dockerfile: Dockerfile.test
volumes:
- ./:/app
- ./tests/results:/app/target/karate-reports
depends_on:
- graphql-engine-test
environment:
- NODE_ENV=test
graphql-engine-test:
condition: service_started
networks:
- test-network

networks:
test-network:
driver: bridge
21 changes: 0 additions & 21 deletions karate-config.js

This file was deleted.

35 changes: 20 additions & 15 deletions tests/karate/features/auth/login.feature
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
Feature: User Authentication

Background:
* print '=== Loading feature file ==='
* url baseUrl
* def tokenHelper = read('../../helpers/generate-token.js')
* print 'URL set to:', baseUrl
* header x-hasura-admin-secret = adminSecret

Scenario: User can login with valid credentials
# Set up the test data
* def validToken = tokenHelper({ uid: 'test-user', role: 'user' })

Given path '/v1/graphql'
And header Authorization = 'Bearer ' + validToken
And request { query: "query { me { id email } }" }
Scenario: Check test database connection
* print 'Starting database check'
Given path '/'
And def query =
"""
{
"query": "query { __type(name: \"User\") { fields { name type { name kind } } } }"
}
"""
And request query
When method POST
Then status 200
And match response.errors == '#notpresent'
And match response.data.me.id == 'test-user'
* print 'Schema:', response.data

Scenario: User cannot access without token
Given path '/v1/graphql'
And request { query: "query { me { id email } }" }
When method POST
Then status 401
Scenario: Check test environment health
* print 'Starting health check'
Given url baseUrl.replace('/v1/graphql', '/healthz')
When method GET
Then status 200
* print 'Health response:', response
21 changes: 10 additions & 11 deletions tests/karate/features/auth/permissions.feature
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
Feature: User Permissions
Feature: Authorization Permissions

Background:
* url baseUrl
* def tokenHelper = read('../../helpers/generate-token.js')
* print '=== Loading feature file ==='
* print 'URL set to:', baseUrl

Scenario: User can only access their own data
# Set up the test data
* def validToken = tokenHelper({ uid: 'test-user', role: 'user' })

Given path '/v1/graphql'
And header Authorization = 'Bearer ' + validToken
And request { query: "query { users { id email } }" }
Scenario: User can access their own data
* def token = tokenHelper({ uid: 'test-user', role: 'user' })
* header Authorization = token
* header x-hasura-admin-secret = adminSecret

Given path '/'
And request { query: "{ __type(name: \"User\") { fields { name } } }" }
When method POST
Then status 200
And match response.errors == '#notpresent'
And match response.data.users[*].id contains 'test-user'
20 changes: 8 additions & 12 deletions tests/karate/features/users/create.feature
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
Feature: User Creation
Feature: Create User

Background:
* url baseUrl
* def tokenHelper = read('../../helpers/generate-token.js')
* print '=== Loading feature file ==='
* print 'URL set to:', baseUrl

Scenario: Admin can create a new user
# Set up the test data
* def adminToken = tokenHelper({ uid: 'admin-user', role: 'admin' })
* def newUser = { email: '[email protected]', password: 'password123' }

Given path '/v1/graphql'
And header Authorization = 'Bearer ' + adminToken
And request { query: "mutation($user: UserInput!) { createUser(user: $user) { id email } }", variables: { user: '#(newUser)' } }
Scenario: Check Hasura health
Given path ''
And header x-hasura-admin-secret = adminSecret
And request { query: "query { __typename }" }
When method POST
Then status 200
And match response.errors == '#notpresent'
And match response.data.createUser.email == newUser.email
And match response == { data: { __typename: 'query_root' } }
28 changes: 10 additions & 18 deletions tests/karate/features/users/query.feature
Original file line number Diff line number Diff line change
@@ -1,27 +1,19 @@
Feature: User Queries
Feature: Query Users

Background:
* url baseUrl
* def tokenHelper = read('../../helpers/generate-token.js')
* print '=== Loading feature file ==='
* print 'URL set to:', baseUrl
* header x-hasura-admin-secret = adminSecret

Scenario: User can query their own profile
# Set up the test data
* def validToken = tokenHelper({ uid: 'test-user', role: 'user' })

Given path '/v1/graphql'
And header Authorization = 'Bearer ' + validToken
And request { query: "query { user(id: \"test-user\") { id email } }" }
Scenario: Query existing user
Given request { query: "{ __typename }" }
When method POST
Then status 200
And match response.errors == '#notpresent'
And match response.data.user.id == 'test-user'
And match response == { data: { __typename: 'query_root' } }

Scenario: User cannot query other users' profiles
* def validToken = tokenHelper({ uid: 'test-user', role: 'user' })

Given path '/v1/graphql'
And header Authorization = 'Bearer ' + validToken
And request { query: "query { user(id: \"other-user\") { id email } }" }
Scenario: Query non-existing user
Given request { query: "{ __typename }" }
When method POST
Then status 200
And match response.data.user == null
And match response == { data: { __typename: 'query_root' } }
Loading

0 comments on commit e87ab7b

Please sign in to comment.