Skip to content
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

fix: ✅ Updating API tests that uses authentification #588

Merged
merged 2 commits into from
Oct 15, 2024
Merged
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
38 changes: 13 additions & 25 deletions .github/workflows/main-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,31 +41,17 @@ jobs:
name: Test Backend
needs: build-backend
runs-on: ubuntu-latest
container:
image: ${{ needs.build-backend.outputs.image_tag }}
env:
AWS_REGION: gra
AWS_DEFAULT_REGION: gra
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
S3_URL_ENDPOINT: https://s3.gra.io.cloud.ovh.net/
S3_BUCKET_NAME: basegun-s3
EMAIL_HOST: mailpit
EMAIL_PORT: 1025
OIDC_CONFIG_URL: https://token.actions.githubusercontent.com/.well-known/openid-configuration
OIDC_JWKS_URL: https://token.actions.githubusercontent.com/.well-known/jwks
OIDC_JWKS_KID: cc413527-173f-5a05-976e-9c52b1d7b431
OIDC_CLIENT_ID: basegun
steps:
- run: cd /app && pytest
services:
mailpit:
image: axllent/mailpit
ports:
- 1025:1025
env:
MP_SMTP_AUTH_ACCEPT_ANY: 1
MP_SMTP_AUTH_ALLOW_INSECURE: 1
- uses: actions/checkout@v4
- name: Start stack using docker compose
run: IMAGE_TAG=${{ needs.build-backend.outputs.image_tag }} docker compose -f docker-compose.yml -f docker-compose.ci.yml up -d
- run: docker compose exec backend coverage run -m pytest
- run: docker compose exec backend coverage xml
- name: Produce the coverage report
uses: insightsengineering/coverage-action@v2
with:
path: ./backend/coverage.xml
publish: true

test-frontend-format:
name: Test Frontend Formatting
Expand All @@ -85,11 +71,13 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Start stack using docker compose
run: docker compose -f docker-compose.yml -f docker-compose.override.ci.yml up -d
run: IMAGE_TAG=${{ needs.build-backend.outputs.image_tag }} docker compose -f docker-compose.yml -f docker-compose.ci.yml up -d
- name: Cypress run
uses: cypress-io/github-action@v6
with:
working-directory: ./frontend
build: npm run build
start: npm run start
command: npm run test:e2e-ci
- name: Send artifacts
uses: actions/upload-artifact@v3
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ temp/
version.txt
*.crt
*.pem
.ruff_cache
.ruff_cache
.coverage
coverage.xml
2 changes: 1 addition & 1 deletion backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.11-slim as base
FROM python:3.11-slim AS base
WORKDIR /app

# librairies necessary for image processing
Expand Down
9 changes: 8 additions & 1 deletion backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,19 @@
docker compose up -d
```

## Run tests
## How to run tests ?

```shell
docker compose exec backend pytest
```

## Run tests with coverage report ?

```shell
docker compose exec backend coverage -m pytest
docker compose exec backend coverage report
```

## How to stop ?

```shell
Expand Down
8 changes: 7 additions & 1 deletion backend/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
[tool.ruff]
exclude = ["frontend"]
exclude = ["frontend"]

[tool.coverage.report]
omit = [
"/app/config-3.py",
"/app/config.py",
]
4 changes: 2 additions & 2 deletions backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ cryptography==43.0.1
# ML
basegun-ml==1.0.1
# Dev
pytest==7.4.3
coverage==7.6.1
pytest==8.3.3
coverage==7.6.3
Faker==30.1.0
25 changes: 25 additions & 0 deletions backend/src/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from typing import Annotated

import jwt
import requests
from fastapi import Depends, HTTPException, status

from src.config import OIDC_CLIENT_ID
Expand Down Expand Up @@ -71,3 +72,27 @@ async def get_current_user(token: Annotated[str, Depends(OAUTH2_SCHEME)]):
except jwt.InvalidTokenError as exception:
logging.error(exception)
raise credentials_exception


def get_access_token(username, password, client_id):
url = "http://keycloak:8080/realms/basegun/protocol/openid-connect/token"

response = requests.post(
url,
data={
"client_id": client_id,
"username": username,
"password": password,
"grant_type": "password",
},
headers={"Content-Type": "application/x-www-form-urlencoded"},
)

if response.status_code != 200:
raise Exception(f"Expected status 200, got {response.status_code}")

access_token = response.json().get("access_token")
if access_token is None:
raise Exception("Access token not found")

return access_token
20 changes: 20 additions & 0 deletions backend/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import pytest
from fastapi.testclient import TestClient

from src.config import OIDC_CLIENT_ID
from src.main import app
from src.utils import get_access_token


class AuthenticableTestClient(TestClient):
def __init__(self, app):
super().__init__(app)

def authenticate(self, username="gendarmerie", password="password"):
token = get_access_token(username, password, OIDC_CLIENT_ID)
self.headers["Authorization"] = f"Bearer {token}"


@pytest.fixture
def client():
return AuthenticableTestClient(app)
25 changes: 11 additions & 14 deletions backend/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,8 @@
import boto3
import pytest
import requests
from fastapi.testclient import TestClient

from src.config import S3_BUCKET_NAME, S3_URL_ENDPOINT
from src.main import app

client = TestClient(app)

BUCKET_POLICY = {
"Version": "2012-10-17",
Expand All @@ -35,12 +31,12 @@ def create_bucket():


class TestApi:
def test_home(self):
def test_home(self, client):
"""Checks that the route / is alive"""
response = client.get("/api/")
assert response.text == "Basegun backend"

def test_version(self):
def test_version(self, client):
"""Checks that the route /version sends a version"""
response = client.get("/api/version")
assert response.status_code == 200
Expand All @@ -64,7 +60,7 @@ def check_log_base(self, log):
assert log["level"] == 6
assert log["_bg_model"].startswith("EffB")

def test_upload(self):
def test_upload(self, client):
"""Checks that the file upload works properly"""
create_bucket()
path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "revolver.jpg")
Expand All @@ -85,7 +81,7 @@ def test_upload(self):
assert "gun_length" in res
assert "gun_barrel_length" in res

def test_feedback_and_logs(self):
def test_feedback_and_logs(self, client):
"""Checks that the feedback works properly"""
confidence = 90
label = "revolver"
Expand All @@ -104,7 +100,7 @@ def test_feedback_and_logs(self):

assert r.status_code == 200

def test_headers(self):
def test_headers(self, client):
HEADERS_TO_ADD = requests.get(
"https://owasp.org/www-project-secure-headers/ci/headers_add.json"
).json()["headers"]
Expand All @@ -121,7 +117,7 @@ def test_headers(self):


class TestUpload:
def test_revolver_without_card(self):
def test_revolver_without_card(self, client):
with open("./tests/revolver.jpg", "rb") as f:
response = client.post(
"/api/upload",
Expand All @@ -137,7 +133,7 @@ def test_revolver_without_card(self):
assert response.data["gun_barrel_length"] is None
assert response.data["conf_card"] is None

def test_semi_auto_without_card(self):
def test_semi_auto_without_card(self, client):
with open("./tests/epaule_a_levier_sous_garde.jpg", "rb") as f:
response = client.post(
"/api/upload",
Expand All @@ -155,8 +151,8 @@ def test_semi_auto_without_card(self):


class TestExpertContact:
@pytest.mark.skip("Need to authenticate to run that test.")
def test_success(self, faker):
def test_success(self, faker, client):
client.authenticate()
with open("./tests/revolver.jpg", "rb") as f:
response = client.post(
"/api/expert-contact",
Expand All @@ -180,10 +176,11 @@ def test_success(self, faker):
"markings_description": faker.pystr(),
},
)

response.data = response.json()
assert response.status_code == 200

def test_403(self):
def test_403(self, client):
response = client.post("/api/expert-contact")
response.data = response.json()
assert response.status_code == 403
23 changes: 0 additions & 23 deletions backend/tests/test_auth.py

This file was deleted.

5 changes: 0 additions & 5 deletions backend/tests/test_email.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
from fastapi.testclient import TestClient

from src.main import app
from src.utils import send_mail

client = TestClient(app)


class TestEmail:
def test_email(self):
Expand Down
3 changes: 3 additions & 0 deletions docker-compose.ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
services:
backend:
image: ${IMAGE_TAG}
7 changes: 0 additions & 7 deletions docker-compose.override.ci.yml

This file was deleted.

15 changes: 1 addition & 14 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,11 @@ services:
ports:
- 5000:5000
volumes:
- ./backend/src:/app/src
- ./backend/tests:/app/tests
- ./backend/logs:/tmp/logs
- ./backend/.:/app/.
depends_on:
keycloak:
condition: service_healthy

frontend:
build:
context: ./frontend
target: ${BUILD_TARGET:-dev}
container_name: basegun-frontend
ports:
- 3000:5173
volumes:
- ./frontend/src:/app/src
- /app/node_modules

# Mock Cloud Pi S3
minio:
image: minio/minio
Expand Down
10 changes: 3 additions & 7 deletions frontend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:20-slim as base
FROM node:20-slim AS base

WORKDIR /app

Expand All @@ -7,15 +7,11 @@ RUN npm ci

COPY . .

FROM base as dev

CMD ["npm", "run", "dev"]

FROM base as build
FROM base AS build

RUN npm run build

FROM nginxinc/nginx-unprivileged:1.24-alpine as prod
FROM nginxinc/nginx-unprivileged:1.24-alpine AS prod

COPY nginx.conf /etc/nginx/nginx.conf

Expand Down
Loading
Loading