diff --git a/API/database.py b/API/database.py new file mode 100644 index 0000000..6e31cd7 --- /dev/null +++ b/API/database.py @@ -0,0 +1,23 @@ +from pymongo import MongoClient +from datetime import datetime + + +class Database: + def __init__(self, uri="mongodb://localhost:27017/", db_name="ImageDB"): + self.client = MongoClient(uri) + self.db = self.client[db_name] + + def find(self, collection, query=None): + return self.db[collection].find(query) + + def insert_one(self, collection, document): + return self.db[collection].insert_one(document) + + def find_one(self, collection,filter, projection=None): + return self.db[collection].find_one(filter=filter ,projection=projection) + + def find_one_and_delete(self, collection, query): + return self.db[collection].find_one_and_delete(query) + + def update_one(self, collection, query, update): + return self.db[collection].update_one(query, update) diff --git a/API/route.py b/API/route.py index 2fc1c54..d884cc6 100644 --- a/API/route.py +++ b/API/route.py @@ -12,6 +12,7 @@ from PIL import Image from pydantic import BaseModel from pymongo import MongoClient +from API.database import Database # Create a logger object logger = logging.getLogger(__name__) @@ -25,12 +26,14 @@ router = APIRouter() # To create connection with Mongodb -mongodb_uri = "mongodb://localhost:27017/" -port = 8000 -client = MongoClient(mongodb_uri, port) +# mongodb_uri = "mongodb://localhost:27017/" +# port = 8000 +# client = MongoClient(mongodb_uri, port) -db = client["ImageDB"] -faceEntries = db["faceEntries"] +# db = client["ImageDB"] +client = Database() + +collection="faceEntries" # Models for the data to be sent and received by the server @@ -76,8 +79,7 @@ async def create_new_faceEntry(Employee: Employee): ) os.remove(image_filename) # Store the data in the database - db.faceEntries.insert_one( - { + client.insert_one(collection, { "EmployeeCode": EmployeeCode, "Name": Name, "gender": gender, @@ -85,15 +87,17 @@ async def create_new_faceEntry(Employee: Employee): "time": time, "embeddings": embeddings, "Image": encoded_image, - } - ) + }) + # db.faceEntries.insert_one( + + # ) return {"message": "Face entry created successfully"} # To display all records @router.get("/Data/", response_model=list[Employee]) async def get_employees(): - employees_mongo = faceEntries.find() + employees_mongo = client.find(collection) employees = [ Employee( EmployeeCode=int(employee.get("EmployeeCode", 0)), @@ -112,7 +116,7 @@ async def get_employees(): async def read_employee(EmployeeCode: int): try: # logger.info(f"Start {EmployeeCode}") - items = faceEntries.find_one( + items = client.find_one(collection, filter={"EmployeeCode": EmployeeCode}, projection={ "Name": True, @@ -142,7 +146,7 @@ async def read_employee(EmployeeCode: int): async def update_employees(EmployeeCode: int, Employee: UpdateEmployee): try: # logger.warning("Updating Start") - user_id = faceEntries.find_one( + user_id = client.find_one(collection, {"EmployeeCode": EmployeeCode}, projection={"_id": True} ) print(user_id) @@ -151,7 +155,7 @@ async def update_employees(EmployeeCode: int, Employee: UpdateEmployee): Employee_data = Employee.model_dump(by_alias=True, exclude_unset=True) # logger.info(f"Employee data to update: {Employee_data}") try: - update_result = faceEntries.update_one( + update_result = client.update_one(collection, filter={"_id": ObjectId(user_id["_id"])}, update={"$set": Employee_data}, ) @@ -170,6 +174,6 @@ async def update_employees(EmployeeCode: int, Employee: UpdateEmployee): @router.delete("/delete/{EmployeeCode}") async def delete_employees(EmployeeCode: int): print(EmployeeCode) - db.faceEntries.find_one_and_delete({"EmployeeCode": EmployeeCode}) + client.find_one_and_delete(collection, {"EmployeeCode": EmployeeCode}) return {"Message": "Successfully Deleted"} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..d0f99b4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +## [Unreleased] + +### Added +- Implemented all test cases in `test_face_cycle` +- Implemented mock test cases for `test_face_cycle` to work on online runners \ No newline at end of file diff --git a/test.ipynb b/test.ipynb index f8c654d..556d392 100644 --- a/test.ipynb +++ b/test.ipynb @@ -659,10 +659,34 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "ename": "TypeError", + "evalue": "Database.find_one() missing 1 required positional argument: 'query'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[10], line 4\u001b[0m\n\u001b[1;32m 2\u001b[0m EmployeeCode \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m1\u001b[39m\n\u001b[1;32m 3\u001b[0m client \u001b[38;5;241m=\u001b[39m Database()\n\u001b[0;32m----> 4\u001b[0m \u001b[43mclient\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfind_one\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mfaceEntries\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mfilter\u001b[39;49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m{\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mEmployeeCode\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mEmployeeCode\u001b[49m\u001b[43m}\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 5\u001b[0m \u001b[43m \u001b[49m\u001b[43mprojection\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m{\u001b[49m\n\u001b[1;32m 6\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mName\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 7\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mgender\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 8\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mDepartment\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 9\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mImage\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 10\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m_id\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 11\u001b[0m \u001b[43m \u001b[49m\u001b[43m}\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[0;31mTypeError\u001b[0m: Database.find_one() missing 1 required positional argument: 'query'" + ] + } + ], + "source": [ + "from API.database import Database\n", + "EmployeeCode = 1\n", + "client = Database()\n", + "client.find_one(\"faceEntries\", filter={\"EmployeeCode\": EmployeeCode},\n", + " projection={\n", + " \"Name\": True,\n", + " \"gender\": True,\n", + " \"Department\": True,\n", + " \"Image\": True,\n", + " \"_id\": False,\n", + " })" + ] } ], "metadata": { @@ -681,7 +705,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.16" + "version": "3.10.13" } }, "nbformat": 4, diff --git a/testing/test_face_cycle.py b/testing/test_face_cycle.py index 6a209d6..102a01d 100644 --- a/testing/test_face_cycle.py +++ b/testing/test_face_cycle.py @@ -1,5 +1,6 @@ import base64 - +from unittest.mock import MagicMock, patch +from API.database import Database from fastapi.testclient import TestClient from API.route import router @@ -7,8 +8,29 @@ client = TestClient(router) -def test_face_lifecycle(): + +@patch("API.database.Database.find_one_and_delete") +@patch("API.database.Database.update_one") +@patch("API.database.Database.find_one") +@patch("API.database.Database.find") +@patch("API.database.Database.insert_one") +def test_face_lifecycle(mock_insert_one: MagicMock, mock_find: MagicMock, mock_find_one: MagicMock, mock_update_one: MagicMock, mock_find_one_and_delete: MagicMock): # Register two new faces + mock_doc = { + "_id": "65e6284d01f95cd96ea334a7", + "EmployeeCode": "1", + "Name": "Devansh", + "gender": "Male", + "Department": "IT", + "Image": "encoded_string1", + } + + # Configure the mock to return the mock document when find() is called + mock_find.return_value = [mock_doc, mock_doc] + mock_insert_one.return_value = MagicMock(inserted_id="1") + mock_find_one.return_value = mock_doc + mock_update_one.return_value = MagicMock(modified_count=1) + mock_find_one_and_delete.return_value = mock_doc with open("./test-faces/devansh.jpg", "rb") as image_file: encoded_string1 = base64.b64encode(image_file.read()).decode("utf-8") response1 = client.post( @@ -42,7 +64,7 @@ def test_face_lifecycle(): # Get all data response = client.get("/Data/") assert response.status_code == 200 - # assert len(response.json()) == 2 + assert len(response.json()) == 2 # Update a face response = client.put( @@ -60,7 +82,7 @@ def test_face_lifecycle(): # Get all data again response = client.get("/Data/") assert response.status_code == 200 - # assert len(response.json()) == 2 + assert len(response.json()) == 2 # Delete a face response = client.delete("/delete/1")