From f3c5bf2d790d552433a979e0ef12d4d907e5c06f Mon Sep 17 00:00:00 2001 From: wojciechwoszczek Date: Tue, 12 Dec 2023 12:33:27 +0100 Subject: [PATCH 1/9] add API test --- .github/workflows/backend.yml | 1 + tests/test_api.py | 29 +++++++++++++++++++++++++++++ tests/test_image_1.jpg | Bin 0 -> 46033 bytes 3 files changed, 30 insertions(+) create mode 100644 tests/test_api.py create mode 100644 tests/test_image_1.jpg diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml index 0c727f3..dfecf46 100644 --- a/.github/workflows/backend.yml +++ b/.github/workflows/backend.yml @@ -45,6 +45,7 @@ run: | pytest tests/test_mlflow.py pytest tests/test_train_model.py + pytest tests/test_api.py continue-on-error: false diff --git a/tests/test_api.py b/tests/test_api.py new file mode 100644 index 0000000..0c7bfb1 --- /dev/null +++ b/tests/test_api.py @@ -0,0 +1,29 @@ +import pytest +from fastapi.testclient import TestClient +import io +import sys +import os + +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) + +from src.app.api import app +from pathlib import Path + +ROOT_DIR = Path(Path(__file__).resolve().parent) + + +def test_make_prediction_endpoint(): + with TestClient(app) as client: + # Replace 'path/to/your/image.jpg' with the actual path to your test image + image_path = ROOT_DIR / 'test_image_1.jpg' + + # Open the image file in binary mode + with open(image_path, 'rb') as img_file: + # Create a file-like object from the image file + img_file_object = io.BytesIO(img_file.read()) + + files = {'beans_img': ('test_image_1.jpg', img_file_object, 'image/jpeg')} + response = client.post("/make_prediction", files=files) + + assert response.status_code == 200 + assert set(response.json().keys()) == {'prediction', 'probs'} diff --git a/tests/test_image_1.jpg b/tests/test_image_1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b65b4e1cb6627471221eb938fe9ce7033ae52c0b GIT binary patch literal 46033 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 literal 0 HcmV?d00001 From f74c86cd7558af5e8dc5d229956380456615ee7c Mon Sep 17 00:00:00 2001 From: wojciechwoszczek Date: Tue, 12 Dec 2023 12:34:18 +0100 Subject: [PATCH 2/9] get rid of testing branch in github actions --- .github/workflows/backend.yml | 1 - .github/workflows/frontend.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml index dfecf46..bb97d07 100644 --- a/.github/workflows/backend.yml +++ b/.github/workflows/backend.yml @@ -6,7 +6,6 @@ push: branches: - main - - github-actions pull_request: branches: - main diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index c57ac13..31b74c1 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -8,7 +8,6 @@ - 'src/web/**' branches: - main - - github-actions pull_request: paths: - 'src/web/**' From d112a87f83a0f795973cf48ec7fba19c2e3ec552 Mon Sep 17 00:00:00 2001 From: wojciechwoszczek Date: Tue, 12 Dec 2023 12:37:17 +0100 Subject: [PATCH 3/9] add fastapi to packages --- .github/workflows/backend.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml index bb97d07..e35e9ab 100644 --- a/.github/workflows/backend.yml +++ b/.github/workflows/backend.yml @@ -38,7 +38,7 @@ echo "MLFLOW_TRACKING_PASSWORD=${{ secrets.MLFLOW_TRACKING_PASSWORD }}" >> .env - name: Install packages # Install dependencies - run: pip install pytest mlflow python-dotenv + run: pip install pytest mlflow python-dotenv fastapi - name: Run training tests run: | From 5a73b02dfccc643c7dc291eb30f5f9d106a479bd Mon Sep 17 00:00:00 2001 From: wojciechwoszczek Date: Tue, 12 Dec 2023 12:38:59 +0100 Subject: [PATCH 4/9] one more package --- .github/workflows/backend.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml index e35e9ab..61fa1b8 100644 --- a/.github/workflows/backend.yml +++ b/.github/workflows/backend.yml @@ -38,9 +38,9 @@ echo "MLFLOW_TRACKING_PASSWORD=${{ secrets.MLFLOW_TRACKING_PASSWORD }}" >> .env - name: Install packages # Install dependencies - run: pip install pytest mlflow python-dotenv fastapi + run: pip install pytest mlflow python-dotenv fastapi httpx - - name: Run training tests + - name: Run tests run: | pytest tests/test_mlflow.py pytest tests/test_train_model.py From a6f5b54b2ae729a47f5b7dc7f7f7e6181a891add Mon Sep 17 00:00:00 2001 From: wojciechwoszczek Date: Tue, 12 Dec 2023 12:40:24 +0100 Subject: [PATCH 5/9] one more package --- .github/workflows/backend.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml index 61fa1b8..4ac0f70 100644 --- a/.github/workflows/backend.yml +++ b/.github/workflows/backend.yml @@ -37,8 +37,8 @@ echo "MLFLOW_TRACKING_USERNAME=${{ secrets.MLFLOW_TRACKING_USERNAME }}" >> .env echo "MLFLOW_TRACKING_PASSWORD=${{ secrets.MLFLOW_TRACKING_PASSWORD }}" >> .env - - name: Install packages # Install dependencies - run: pip install pytest mlflow python-dotenv fastapi httpx + - name: Install packages # Install dependencies needed for tests (not for whole project) + run: pip install pytest mlflow python-dotenv fastapi httpx uvicorn - name: Run tests run: | From aee3b1698943049833043aba703bec4a159547f9 Mon Sep 17 00:00:00 2001 From: wojciechwoszczek Date: Tue, 12 Dec 2023 12:43:03 +0100 Subject: [PATCH 6/9] One more configuration try --- .github/workflows/backend.yml | 2 +- src/app/api.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml index 4ac0f70..25b6f57 100644 --- a/.github/workflows/backend.yml +++ b/.github/workflows/backend.yml @@ -38,7 +38,7 @@ echo "MLFLOW_TRACKING_PASSWORD=${{ secrets.MLFLOW_TRACKING_PASSWORD }}" >> .env - name: Install packages # Install dependencies needed for tests (not for whole project) - run: pip install pytest mlflow python-dotenv fastapi httpx uvicorn + run: pip install pytest mlflow python-dotenv fastapi httpx torch torchvision pydantic - name: Run tests run: | diff --git a/src/app/api.py b/src/app/api.py index 724ff2d..b69ad49 100644 --- a/src/app/api.py +++ b/src/app/api.py @@ -2,7 +2,6 @@ from typing import List from PIL import Image from io import BytesIO -import uvicorn from fastapi import FastAPI, Request, File, UploadFile, HTTPException from torchvision import transforms import torch From 17e667b04437b02d71d3260b9f40097b0348dbda Mon Sep 17 00:00:00 2001 From: wojciechwoszczek Date: Tue, 12 Dec 2023 12:46:37 +0100 Subject: [PATCH 7/9] add python-multipart to dependencies --- .github/workflows/backend.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml index 25b6f57..6b66694 100644 --- a/.github/workflows/backend.yml +++ b/.github/workflows/backend.yml @@ -38,7 +38,7 @@ echo "MLFLOW_TRACKING_PASSWORD=${{ secrets.MLFLOW_TRACKING_PASSWORD }}" >> .env - name: Install packages # Install dependencies needed for tests (not for whole project) - run: pip install pytest mlflow python-dotenv fastapi httpx torch torchvision pydantic + run: pip install pytest mlflow python-dotenv fastapi httpx torch torchvision pydantic python-multipart - name: Run tests run: | From 62c9141674ca3f91186e89d8374e5c79289c1179 Mon Sep 17 00:00:00 2001 From: wojciechwoszczek Date: Tue, 12 Dec 2023 12:51:35 +0100 Subject: [PATCH 8/9] pull model needed for test --- .github/workflows/backend.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml index 6b66694..bd4b0bb 100644 --- a/.github/workflows/backend.yml +++ b/.github/workflows/backend.yml @@ -40,6 +40,13 @@ - name: Install packages # Install dependencies needed for tests (not for whole project) run: pip install pytest mlflow python-dotenv fastapi httpx torch torchvision pydantic python-multipart + - name: Pull model + run: | + dvc remote modify origin --local auth basic + dvc remote modify origin --local user ${{ secrets.DAGSHUB_USERNAME }} + dvc remote modify origin --local password ${{ secrets.DAGSHUB_TOKEN }} + dvc pull -r origin models/trained_model.pt + - name: Run tests run: | pytest tests/test_mlflow.py @@ -74,7 +81,7 @@ - name: Install packages # Install dependencies run: pip install dvc docker - - name: Pull data + - name: Pull model run: | dvc remote modify origin --local auth basic dvc remote modify origin --local user ${{ secrets.DAGSHUB_USERNAME }} From dd3cdc1b409d4e7c2bdd90d56292927c55d7d414 Mon Sep 17 00:00:00 2001 From: wojciechwoszczek Date: Tue, 12 Dec 2023 12:52:42 +0100 Subject: [PATCH 9/9] add dvc to dependencies --- .github/workflows/backend.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml index bd4b0bb..54f2d83 100644 --- a/.github/workflows/backend.yml +++ b/.github/workflows/backend.yml @@ -38,7 +38,7 @@ echo "MLFLOW_TRACKING_PASSWORD=${{ secrets.MLFLOW_TRACKING_PASSWORD }}" >> .env - name: Install packages # Install dependencies needed for tests (not for whole project) - run: pip install pytest mlflow python-dotenv fastapi httpx torch torchvision pydantic python-multipart + run: pip install pytest mlflow python-dotenv fastapi httpx torch torchvision pydantic python-multipart dvc - name: Pull model run: |