Skip to content

Add Integration Tests #816

New issue

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

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

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Integration Tests

on:
pull_request:
branches:
- master
- production
types:
- opened
- synchronize
- reopened

jobs:
integration-tests:
name: Run Integration Tests
runs-on: ubuntu-latest
timeout-minutes: 15

steps:
- name: Checkout code
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0

- name: Run integration tests
run: make integration-test

- name: Cleanup
if: always()
run: make integration-test-clean
21 changes: 21 additions & 0 deletions Dockerfile.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
FROM rust:1.69 AS rust_builder
RUN rustup target add x86_64-unknown-linux-musl
RUN apt-get update && apt-get install -y musl-tools
RUN git clone https://github.com/brave-intl/challenge-bypass-ristretto-ffi /src
WORKDIR /src
RUN git checkout 1.0.1
RUN CARGO_PROFILE_RELEASE_LTO=true cargo rustc --target=x86_64-unknown-linux-musl --release --crate-type staticlib

FROM golang:1.24
WORKDIR /app
COPY . .

# Copy the Rust FFI library from the rust builder stage
COPY --from=rust_builder /src/target/x86_64-unknown-linux-musl/release/libchallenge_bypass_ristretto_ffi.a /usr/lib/libchallenge_bypass_ristretto_ffi.a

RUN apt-get update && apt-get install -y postgresql-client
RUN go mod download
RUN go get github.com/stretchr/testify/assert
RUN go get github.com/segmentio/kafka-go

CMD ["go", "test", "-tags", "integration", "./integration-tests", "-v"]
55 changes: 53 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Integration test configuration
INTEGRATION_COMPOSE_FILE := docker-compose.integration.yml
INTEGRATION_COMPOSE := docker compose -f $(INTEGRATION_COMPOSE_FILE)

docker-psql:
docker compose exec postgres psql -U btokens

Expand All @@ -6,14 +10,14 @@ docker-dev:

docker-test:
docker compose -f docker-compose.yml -f docker-compose.dev.yml run --rm -p 2416:2416 challenge-bypass bash -c \
"(aws dynamodb delete-table \
"export AWS_PAGER='' && (aws dynamodb delete-table \
--table-name redemptions --endpoint-url http://dynamodb:8000 --region us-west-2 || \
aws dynamodb create-table \
--attribute-definitions AttributeName=id,AttributeType=S \
--key-schema AttributeName=id,KeyType=HASH \
--billing-mode PAY_PER_REQUEST \
--table-name redemptions --endpoint-url http://dynamodb:8000 --region us-west-2 ) \
&& go test -v ./..."
&& go test -v -tags='!integration' ./..."

docker-lint:
docker compose -f docker-compose.yml -f docker-compose.dev.yml run --rm -p 2416:2416 challenge-bypass golangci-lint run
Expand All @@ -34,3 +38,50 @@ generate-avro:

lint:
docker run --rm -v "$$(pwd):/app" --workdir /app golangci/golangci-lint:v2.1.6 golangci-lint run -v ./...

# Integration test commands
.PHONY: integration-test
integration-test: integration-test-clean
@echo "🏗️ Building services..."
@$(INTEGRATION_COMPOSE) build

@echo "🚀 Starting services..."
@$(INTEGRATION_COMPOSE) up -d

@echo "⏳ Waiting for services to be ready..."
@for i in $$(seq 1 10); do \
echo -n "$$i... "; \
sleep 1; \
done; \
echo ""

@echo "🏗️ Building test runner..."
@$(INTEGRATION_COMPOSE) --profile test build test-runner

@echo "🧪 Running integration tests..."
@TEST_NAME="$${TEST_NAME:-}" && \
if [ -n "$$TEST_NAME" ]; then \
echo "Running specific test: $$TEST_NAME"; \
$(INTEGRATION_COMPOSE) --profile test run --rm test-runner go test -v -tags=integration ./... -run=$$TEST_NAME || (echo "❌ Tests failed!"; $(MAKE) integration-test-clean; exit 1); \
else \
echo "Running all tests"; \
$(INTEGRATION_COMPOSE) --profile test run --rm test-runner || (echo "❌ Tests failed!"; $(MAKE) integration-test-clean; exit 1); \
fi

@echo "🧹 Cleaning up..."
@$(MAKE) integration-test-clean

@echo "✅ Integration tests completed successfully!"

.PHONY: integration-test-clean
integration-test-clean:
@echo "🧹 Cleaning up containers and volumes..."
@$(INTEGRATION_COMPOSE) --profile test down -v --remove-orphans 2>/dev/null || true

.PHONY: integration-test-logs
integration-test-logs:
@$(INTEGRATION_COMPOSE) logs -f

# Alias for consistency with existing naming convention
.PHONY: docker-integration-test
docker-integration-test: integration-test
69 changes: 68 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,79 @@ This project uses [golangci-lint](https://golangci-lint.run/) for linting, this
To run locally use `make lint` which runs linting using docker however if you want to run it locally using a binary release (which can be faster) follow the [installation instructions for your platform](https://golangci-lint.run/usage/install/) and then run `golangci-lint run -v ./...`

## Testing
Run the below command in order to test changes, if you have an M1 / M2 Mac (or ARM based processor) follow the steps below to setup docker to be able to run the tests

### Unit Tests

Run the below command in order to test changes, if you have an M1 / M2 Mac (or ARM based processor) follow the steps below to setup docker to be able to run the tests
```
make docker-test
```

### Integration Tests

The project includes comprehensive integration tests that verify the entire system working together with all dependencies.

#### What the Integration Tests Do

The integration tests:
- Spin up a complete environment with PostgreSQL, Kafka, Zookeeper, LocalStack (for DynamoDB), and the application
- Test end-to-end flows including:
- Token redemption flows through Kafka
- Token signing flows through Kafka
- Database persistence and retrieval
- DynamoDB operations
- Verify the application correctly processes messages between Kafka topics
- Ensure proper communication between all services

#### Running Integration Tests
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: is there a way to run a single integration test?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add documentation about the go test -run argument to help make this clear.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To run that we need to bring up the containers and test environment so we would need to run make dev then from the shell run the go test -run [args] but the make dev doesn't not include the new docker integration file so I am wondering if that would work.

It would be good to have something where we can run a single test and pick up and code changes we are making locally, similar to bat-go.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see your meaning. Good point will add.


To run the integration tests, simply use:

```bash
# run all integration tests
make integration-test
# or run a specific integration test
make integration-test TEST_NAME=TestTokenIssuanceViaKafkaAndRedeemViaHTTPFlow
```

This command will:
1. Clean up any existing test containers
2. Build all required services
3. Start the test environment (PostgreSQL, Kafka, Zookeeper, LocalStack)
4. Wait for all services to be healthy and ready (~30 seconds)
5. Build and run the test suite
6. Automatically clean up all containers and volumes after completion

#### Manual Cleanup

If the tests are interrupted or you need to manually clean up the test environment:

```bash
make integration-test-clean
```

This will remove all test containers, networks, and volumes created by the integration tests.

#### Viewing Logs

To debug issues or view what's happening during the tests:

```bash
make integration-test-logs
```

This will tail the logs from all services in the integration test environment.

#### Test Configuration

The integration tests use a separate `docker-compose.integration.yml` file which:
- Creates isolated test topics in Kafka
- Uses a dedicated test database
- Runs LocalStack for DynamoDB emulation
- Configures all services with test-specific settings

### Have an M1 / M2 (ARM) Mac?

1.) In Docker Desktop, go to: `Settings -> Docker Engine` <br />
#### Modify file to include
```
Expand Down
106 changes: 106 additions & 0 deletions docker-compose.integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
services:
cbp:
build: .
depends_on:
postgres:
condition: service_healthy
kafka:
condition: service_healthy
localstack:
condition: service_healthy
environment:
- DATABASE_URL=postgresql://testuser:testpassword@postgres:5432/testdb?sslmode=disable
- VPC_KAFKA_BROKERS=kafka:9092
- DYNAMODB_ENDPOINT=http://localstack:4566
- ENV=test
- REDEEM_CONSUMER_TOPIC=test.consumer.redeem
- REDEEM_PRODUCER_TOPIC=test.producer.redeem
- SIGN_CONSUMER_TOPIC=test.consumer.sign
- SIGN_PRODUCER_TOPIC=test.producer.sign
- CONSUMER_GROUP=integration-service
- AWS_REGION=us-east-1
- AWS_ACCESS_KEY_ID=test
- AWS_SECRET_ACCESS_KEY=test
ports:
- "2416:2416"
- "9090:9090"

postgres:
image: postgres:latest
environment:
- POSTGRES_USER=testuser
- POSTGRES_PASSWORD=testpassword
- POSTGRES_DB=testdb
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U testuser -d testdb"]
interval: 5s
timeout: 2s
retries: 10

zookeeper:
image: wurstmeister/zookeeper:latest
ports:
- "2181:2181"
healthcheck:
test: ["CMD-SHELL", "echo ruok | nc localhost 2181 | grep imok"]
interval: 5s
timeout: 2s
retries: 10

kafka:
image: wurstmeister/kafka:latest
depends_on:
zookeeper:
condition: service_healthy
ports:
- "9092:9092"
environment:
- KAFKA_ADVERTISED_HOST_NAME=kafka
- KAFKA_ADVERTISED_PORT=9092
- KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
- KAFKA_CREATE_TOPICS=test.consumer.redeem:1:1,test.producer.redeem:1:1,test.consumer.sign:1:1,test.producer.sign:1:1
- KAFKA_AUTO_CREATE_TOPICS_ENABLE=true
# Reduce memory usage for testing
- KAFKA_HEAP_OPTS=-Xmx256M -Xms128M
healthcheck:
test: ["CMD-SHELL", "kafka-topics.sh --bootstrap-server localhost:9092 --list"]
interval: 10s
timeout: 5s
retries: 10

localstack:
image: localstack/localstack:latest
ports:
- "4566:4566"
environment:
- SERVICES=dynamodb
- DEBUG=1
healthcheck:
test: ["CMD", "sh", "-c", "awslocal dynamodb list-tables --region us-east-1 || exit 1"]
interval: 5s
timeout: 5s
retries: 15

test-runner:
build:
context: .
dockerfile: Dockerfile.test
profiles:
- test
depends_on:
cbp:
condition: service_started
kafka:
condition: service_healthy
environment:
- DATABASE_URL=postgresql://testuser:testpassword@postgres:5432/testdb?sslmode=disable
- DYNAMODB_ENDPOINT=http://localstack:4566
- ENV=test
- TEST_SHOULD_WRITE_REDEEM_REQUESTS_HERE=test.consumer.redeem
- TEST_SHOULD_READ_REDEEM_REQUESTS_HERE=test.producer.redeem
- TEST_SHOULD_WRITE_SIGNING_REQUESTS_HERE=test.consumer.sign
- TEST_SHOULD_READ_SIGNING_REQUESTS_HERE=test.producer.sign
- CONSUMER_GROUP=test
command: ["go", "test", "-tags", "integration", "./integration-tests", "-v", "-count=1"]
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ require (
github.com/satori/go.uuid v1.2.0
github.com/segmentio/kafka-go v0.4.38
github.com/segmentio/kafka-go/sasl/aws_msk_iam_v2 v0.1.0
github.com/stretchr/testify v1.9.0
github.com/stretchr/testify v1.10.0
)

require (
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/throttled/throttled/v2 v2.12.0 h1:IezKE1uHlYC/0Al05oZV6Ar+uN/znw3cy9J8banxhEY=
github.com/throttled/throttled/v2 v2.12.0/go.mod h1:+EAvrG2hZAQTx8oMpBu8fq6Xmm+d1P2luKK7fIY1Esc=
github.com/xdg/scram v1.0.5 h1:TuS0RFmt5Is5qm9Tm2SoD89OPqe4IRiFtyFY4iwWXsw=
Expand Down
Loading
Loading