Skip to content
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
286 changes: 286 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,286 @@
name: Test All Services

on:
push:
branches: [ master, feature/** ]
pull_request:
branches: [ master ]

jobs:
test-fraud-detection:
name: Test Fraud Detection Service
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install dependencies
working-directory: ./services/fraud_detection
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt

- name: Generate gRPC stubs
working-directory: ./utils/pb
run: |
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. fraud_detection/fraud_detection.proto
sed -i 's/^import fraud_detection_pb2/from . import fraud_detection_pb2/' fraud_detection/fraud_detection_pb2_grpc.py

- name: Run tests with pytest
working-directory: ./services/fraud_detection
run: |
python -m pytest tests/ -v --cov=src --cov-report=term-missing --cov-report=xml

- name: Upload coverage
uses: codecov/codecov-action@v4
continue-on-error: true
with:
files: ./services/fraud_detection/coverage.xml
flags: fraud-detection
name: fraud-detection-coverage

test-transaction-verification:
name: Test Transaction Verification Service
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install dependencies
working-directory: ./services/transaction_verification
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt

- name: Generate gRPC stubs
working-directory: ./utils/pb
run: |
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. transaction_verification/transaction_verification.proto
sed -i 's/^import transaction_verification_pb2/from . import transaction_verification_pb2/' transaction_verification/transaction_verification_pb2_grpc.py

- name: Run tests with pytest
working-directory: ./services/transaction_verification
run: |
python -m pytest tests/ -v --cov=src --cov-report=term-missing --cov-report=xml

- name: Upload coverage
uses: codecov/codecov-action@v4
continue-on-error: true
with:
files: ./services/transaction_verification/coverage.xml
flags: transaction-verification
name: transaction-verification-coverage

test-suggestions:
name: Test Suggestions Service
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install dependencies
working-directory: ./services/suggestions
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt

- name: Generate gRPC stubs
working-directory: ./utils/pb
run: |
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. suggestions/suggestions.proto
sed -i 's/^import suggestions_pb2/from . import suggestions_pb2/' suggestions/suggestions_pb2_grpc.py

- name: Run tests with pytest
working-directory: ./services/suggestions
run: |
python -m pytest tests/ -v --cov=src --cov-report=term-missing --cov-report=xml

- name: Upload coverage
uses: codecov/codecov-action@v4
continue-on-error: true
with:
files: ./services/suggestions/coverage.xml
flags: suggestions
name: suggestions-coverage

test-orchestrator:
name: Test Orchestrator Service
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install dependencies
working-directory: ./services/orchestrator
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt

- name: Generate all gRPC stubs
working-directory: ./utils/pb
run: |
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. fraud_detection/fraud_detection.proto
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. transaction_verification/transaction_verification.proto
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. suggestions/suggestions.proto
sed -i 's/^import fraud_detection_pb2/from . import fraud_detection_pb2/' fraud_detection/fraud_detection_pb2_grpc.py
sed -i 's/^import transaction_verification_pb2/from . import transaction_verification_pb2/' transaction_verification/transaction_verification_pb2_grpc.py
sed -i 's/^import suggestions_pb2/from . import suggestions_pb2/' suggestions/suggestions_pb2_grpc.py

- name: Run tests with pytest
working-directory: ./services/orchestrator
run: |
python -m pytest tests/ -v --cov=src --cov-report=term-missing --cov-report=xml

- name: Upload coverage
uses: codecov/codecov-action@v4
continue-on-error: true
with:
files: ./services/orchestrator/coverage.xml
flags: orchestrator
name: orchestrator-coverage

integration-test:
name: Integration Test with Docker Compose
runs-on: ubuntu-latest
needs: [test-fraud-detection, test-transaction-verification, test-suggestions, test-orchestrator]

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Build and start services
run: |
docker compose up -d --build

- name: Wait for services to be ready
run: |
echo "Waiting for services to start..."
sleep 15

- name: Check services are running
run: |
docker compose ps
docker compose logs

- name: Test orchestrator health endpoint
run: |
response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8081/)
if [ "$response" != "200" ]; then
echo "Health check failed with status code: $response"
exit 1
fi
echo "Health check passed"

- name: Test valid checkout request
run: |
response=$(curl -s -X POST http://localhost:8081/checkout \
-H "Content-Type: application/json" \
-d '{
"user": {"name": "Test User", "contact": "test@example.com"},
"creditCard": {"number": "4532015112830366", "expirationDate": "12/25", "cvv": "123"},
"items": [{"name": "Test Book", "quantity": 2}]
}')
echo "Response: $response"

status=$(echo $response | jq -r '.status')
if [ "$status" != "Order Approved" ]; then
echo "Expected 'Order Approved', got: $status"
exit 1
fi
echo "Valid checkout test passed"

- name: Test fraud detection (high quantity)
run: |
response=$(curl -s -X POST http://localhost:8081/checkout \
-H "Content-Type: application/json" \
-d '{
"user": {"name": "Test User", "contact": "test@example.com"},
"creditCard": {"number": "4532015112830366", "expirationDate": "12/25", "cvv": "123"},
"items": [{"name": "Test Book", "quantity": 60}]
}')
echo "Response: $response"

status=$(echo $response | jq -r '.status')
if [ "$status" != "Order Rejected" ]; then
echo "Expected 'Order Rejected', got: $status"
exit 1
fi
echo "Fraud detection test passed"

- name: Test validation (missing user)
run: |
response=$(curl -s -X POST http://localhost:8081/checkout \
-H "Content-Type: application/json" \
-d '{
"creditCard": {"number": "4532015112830366", "expirationDate": "12/25", "cvv": "123"},
"items": [{"name": "Test Book", "quantity": 2}]
}')
echo "Response: $response"

error_code=$(echo $response | jq -r '.error.code')
if [ "$error_code" != "MISSING_USER" ]; then
echo "Expected error code 'MISSING_USER', got: $error_code"
exit 1
fi
echo "Validation test passed"

- name: Show service logs on failure
if: failure()
run: |
echo "=== Orchestrator logs ==="
docker compose logs orchestrator
echo "=== Fraud Detection logs ==="
docker compose logs fraud_detection
echo "=== Transaction Verification logs ==="
docker compose logs transaction_verification
echo "=== Suggestions logs ==="
docker compose logs suggestions

- name: Stop services
if: always()
run: |
docker compose down -v

test-summary:
name: Test Summary
runs-on: ubuntu-latest
needs: [test-fraud-detection, test-transaction-verification, test-suggestions, test-orchestrator, integration-test]
if: always()

steps:
- name: Check test results
run: |
if [ "${{ needs.test-fraud-detection.result }}" != "success" ] || \
[ "${{ needs.test-transaction-verification.result }}" != "success" ] || \
[ "${{ needs.test-suggestions.result }}" != "success" ] || \
[ "${{ needs.test-orchestrator.result }}" != "success" ] || \
[ "${{ needs.integration-test.result }}" != "success" ]; then
echo "❌ Some tests failed!"
exit 1
else
echo "✅ All tests passed!"
fi
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
__pycache__
__pycache__
.pytest_cache
.vscode/
vscode/
70 changes: 36 additions & 34 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -1,59 +1,61 @@
version: '3'
services:
frontend:
build:
# Use the current directory as the build context
# This allows us to access the files in the current directory inside the Dockerfile
context: ./
dockerfile: ./frontend/Dockerfile
dockerfile: ./services/frontend/Dockerfile
ports:
# Expose port 8080 on the host, and map port 80 of the container to port 8080 on the host
# Access the application at http://localhost:8080
- "8080:80"
volumes:
# Mount the frontend directory
- ./frontend/src:/usr/share/nginx/html
- ./services/frontend/src:/usr/share/nginx/html
orchestrator:
build:
# Use the current directory as the build context
# This allows us to access the files in the current directory inside the Dockerfile
context: ./
# Use the Dockerfile in the orchestrator directory
dockerfile: ./orchestrator/Dockerfile
dockerfile: ./services/orchestrator/Dockerfile
ports:
# Expose port 8081 on the host, and map port 5000 of the container to port 8081 on the host
- 8081:5000
environment:
# Pass the environment variables to the container
# The PYTHONUNBUFFERED environment variable ensures that the output from the application is logged to the console
- PYTHONUNBUFFERED=TRUE
# The PYTHONFILE environment variable specifies the absolute entry point of the application
# Check app.py in the orchestrator directory to see how this is used
- PYTHONFILE=/app/orchestrator/src/app.py
- PYTHONFILE=/app/services/orchestrator/src/app.py
volumes:
# Mount the utils directory in the current directory to the /app/utils directory in the container
- ./utils:/app/utils
# Mount the orchestrator/src directory in the current directory to the /app/orchestrator/src directory in the container
- ./orchestrator/src:/app/orchestrator/src
- ./services/orchestrator/src:/app/services/orchestrator/src
- ./services/orchestrator/tests:/app/services/orchestrator/tests
fraud_detection:
build:
# Use the current directory as the build context
# This allows us to access the files in the current directory inside the Dockerfile
context: ./
# Use the Dockerfile in the fraud_detection directorys
dockerfile: ./fraud_detection/Dockerfile
dockerfile: ./services/fraud_detection/Dockerfile
ports:
# Expose port 50051 on the host, and map port 50051 of the container to port 50051 on the host
- 50051:50051
environment:
# Pass the environment variables to the container
# The PYTHONUNBUFFERED environment variable ensures that the output from the application is logged to the console
- PYTHONUNBUFFERED=TRUE
# The PYTHONFILE environment variable specifies the absolute entry point of the application
# Check app.py in the fraud_detection directory to see how this is used
- PYTHONFILE=/app/fraud_detection/src/app.py
- PYTHONFILE=/app/services/fraud_detection/src/app.py
volumes:
# Mount the utils directory in the current directory to the /app/utils directory in the container
- ./utils:/app/utils
# Mount the fraud_detection/src directory in the current directory to the /app/fraud_detection/src directory in the container
- ./fraud_detection/src:/app/fraud_detection/src
- ./services/fraud_detection/src:/app/services/fraud_detection/src
- ./services/fraud_detection/tests:/app/services/fraud_detection/tests
transaction_verification:
build:
context: ./
dockerfile: ./services/transaction_verification/Dockerfile
ports:
- 50052:50052
environment:
- PYTHONUNBUFFERED=TRUE
- PYTHONFILE=/app/services/transaction_verification/src/app.py
volumes:
- ./utils:/app/utils
- ./services/transaction_verification/src:/app/services/transaction_verification/src
- ./services/transaction_verification/tests:/app/services/transaction_verification/tests
suggestions:
build:
context: ./
dockerfile: ./services/suggestions/Dockerfile
ports:
- 50053:50053
environment:
- PYTHONUNBUFFERED=TRUE
- PYTHONFILE=/app/services/suggestions/src/app.py
volumes:
- ./utils:/app/utils
- ./services/suggestions/src:/app/services/suggestions/src
- ./services/suggestions/tests:/app/services/suggestions/tests
4 changes: 0 additions & 4 deletions fraud_detection/requirements.txt

This file was deleted.

Loading