Skip to content

Commit

Permalink
Merge pull request #69 from ral-facilities/view-all-manufacturers-#66
Browse files Browse the repository at this point in the history
View all manufacturers #66
  • Loading branch information
VKTB authored Oct 23, 2023
2 parents 7352d52 + 8d40072 commit c5bb224
Show file tree
Hide file tree
Showing 8 changed files with 233 additions and 10 deletions.
14 changes: 13 additions & 1 deletion inventory_management_system_api/repositories/manufacturer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Module for providing a repository for managing manufacturers in a MongoDB database.
"""
import logging
from typing import Optional
from typing import Optional, List

from fastapi import Depends
from pymongo.collection import Collection
Expand Down Expand Up @@ -64,6 +64,18 @@ def get(self, manufacturer_id: str) -> Optional[ManufacturerOut]:
return ManufacturerOut(**manufacturer)
return None

def list(self) -> List[ManufacturerOut]:
"""Get all manufacturers from database
:return: List of manufacturers, or empty list if no manufacturers
"""

logger.info("Getting all manufacturers from database")

manufacturers = self._collection.find()

return [ManufacturerOut(**manufacturer) for manufacturer in manufacturers]

def _is_duplicate_manufacturer(self, code: str) -> bool:
"""
Check if manufacturer with the same url already exists in the manufacturer collection
Expand Down
15 changes: 14 additions & 1 deletion inventory_management_system_api/routers/v1/manufacturer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
`Manufacturer` service.
"""
import logging

from typing import List
from fastapi import APIRouter, status, Depends, HTTPException
from inventory_management_system_api.core.exceptions import DuplicateRecordError

Expand Down Expand Up @@ -38,3 +38,16 @@ def create_manufacturer(
message = "A manufacturer with the same name has been found"
logger.exception(message)
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=message) from exc


@router.get(
path="/",
summary="Get all manufacturers",
response_description="List of manufacturers",
)
def get_all_manufacturers(manufacturer_service: ManufacturerService = Depends()) -> List[ManufacturerSchema]:
# pylint: disable=missing-function-docstring
logger.info("Getting manufacturers")

manufacturers = manufacturer_service.list()
return [ManufacturerSchema(**manufacturer.dict()) for manufacturer in manufacturers]
4 changes: 2 additions & 2 deletions inventory_management_system_api/schemas/manufacturer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
Module for defining the API schema models for representing manufacturers.
"""

from pydantic import BaseModel, Field
from pydantic import BaseModel, Field, HttpUrl


class ManufacturerPostRequestSchema(BaseModel):
"""Schema model for manufactuer creation request"""

name: str = Field(description="Name of manufacturer")
url: str = Field(description="URL of manufacturer")
url: HttpUrl = Field(description="URL of manufacturer")
address: str = Field(description="Address of manufacturer")


Expand Down
8 changes: 8 additions & 0 deletions inventory_management_system_api/services/manufacturer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import logging
import re

from typing import List
from fastapi import Depends
from inventory_management_system_api.models.manufacturer import ManufacturerIn, ManufacturerOut

Expand Down Expand Up @@ -48,3 +49,10 @@ def _generate_code(self, name: str) -> str:
"""
name = name.lower().strip()
return re.sub(r"\s", "-", name)

def list(self) -> List[ManufacturerOut]:
"""Get all manufactuers
:return: list of all manufacturers
"""
return self._manufacturer_repository.list()
51 changes: 47 additions & 4 deletions test/e2e/test_manufacturer.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def test_create_manufacturer(test_client):
"""Test creating a manufacturer"""
manufacturer_post = {
"name": "Manufacturer A",
"url": "example.com",
"url": "http://example.com",
"address": "Street A",
}

Expand All @@ -36,23 +36,66 @@ def test_create_manufacturer(test_client):
assert manufacturer["address"] == manufacturer_post["address"]


def test_check_duplicate_url_within_manufacturer(test_client):
def test_check_duplicate_name_within_manufacturer(test_client):
"""Test creating a manufactuer with a duplicate name"""

manufacturer_post = {
"name": "Manufacturer A",
"url": "example.com",
"url": "http://example.com",
"address": "Street A",
}
test_client.post("/v1/manufacturer", json=manufacturer_post)

manufacturer_post = {
"name": "Manufacturer A",
"url": "test.com",
"url": "http://test.com",
"address": "Street B",
}

response = test_client.post("/v1/manufacturer", json=manufacturer_post)

assert response.status_code == 409
assert response.json()["detail"] == "A manufacturer with the same name has been found"


def test_list(test_client):
"""Test getting all manufacturers"""
manufacturer_post = {
"name": "Manufacturer A",
"url": "http://example.com",
"address": "Street A",
}
test_client.post("/v1/manufacturer", json=manufacturer_post)
manufacturer_post = {
"name": "Manufacturer B",
"url": "http://2ndExample.com",
"address": "Street B",
}
test_client.post("/v1/manufacturer", json=manufacturer_post)

response = test_client.get("/v1/manufacturer")

assert response.status_code == 200

manufacturers = list(response.json())

assert len(manufacturers) == 2
assert manufacturers[0]["name"] == "Manufacturer A"
assert manufacturers[0]["url"] == "http://example.com"
assert manufacturers[0]["address"] == "Street A"
assert manufacturers[0]["code"] == "manufacturer-a"

assert manufacturers[1]["name"] == "Manufacturer B"
assert manufacturers[1]["url"] == "http://2ndExample.com"
assert manufacturers[1]["address"] == "Street B"
assert manufacturers[1]["code"] == "manufacturer-b"


def test_list_when_no_manufacturers(test_client):
"""Test trying to get all manufacturers when there are none in the databse"""

response = test_client.get("/v1/manufacturer")

assert response.status_code == 200
manufacturers = list(response.json())
assert not manufacturers
63 changes: 61 additions & 2 deletions test/unit/repositories/test_manufacturer.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def test_create_manufacturer(test_helpers, database_mock, manufacturer_repositor
"address": manufacturer.address,
},
)
# pylint: disable=duplicate-code
created_manufacturer = manufacturer_repository.create(
ManufacturerIn(
name=manufacturer.name,
Expand All @@ -57,6 +58,7 @@ def test_create_manufacturer(test_helpers, database_mock, manufacturer_repositor
"address": manufacturer.address,
}
)
# pylint: enable=duplicate-code
database_mock.manufacturer.find_one.assert_called_once_with({"_id": CustomObjectId(manufacturer.id)})
assert created_manufacturer == manufacturer

Expand All @@ -69,20 +71,77 @@ def test_create_manufacturer_duplicate(test_helpers, database_mock, manufacturer
duplicate manufacturer, and does not create the manufacturer.
"""
manufacturer = ManufacturerOut(
_id=str(ObjectId()), name="Manufacturer B", code="manufacturer-b", url="duplicate.co.uk", address="street B"
_id=str(ObjectId()),
name="Manufacturer B",
code="manufacturer-b",
url="http://duplicate.co.uk",
address="street B",
)

# Mock count_documents to return 1 (duplicat manufacturer found)
test_helpers.mock_count_documents(database_mock.manufacturer, 1)

with pytest.raises(DuplicateRecordError) as exc:
manufacturer_repository.create(
# pylint: disable=duplicate-code
ManufacturerIn(
name=manufacturer.name,
code=manufacturer.code,
url=manufacturer.url,
address=manufacturer.address,
)
)

# pylint: enable=duplicate-code
assert str(exc.value) == "Duplicate manufacturer found"


def test_list(test_helpers, database_mock, manufacturer_repository):
"""Test getting all manufacturers"""
manufacturer_1 = ManufacturerOut(
_id=str(ObjectId()),
code="manufacturer-a",
name="Manufacturer A",
url="http://testUrl.co.uk",
address="1 Example street",
)

manufacturer_2 = ManufacturerOut(
_id=str(ObjectId()),
code="manufacturer-b",
name="Manufacturer B",
url="http://2ndTestUrl.co.uk",
address="2 Example street",
)

test_helpers.mock_find(
database_mock.manufacturer,
[
{
"_id": CustomObjectId(manufacturer_1.id),
"code": manufacturer_1.code,
"name": manufacturer_1.name,
"url": manufacturer_1.url,
"address": manufacturer_1.address,
},
{
"_id": CustomObjectId(manufacturer_2.id),
"code": manufacturer_2.code,
"name": manufacturer_2.name,
"url": manufacturer_2.url,
"address": manufacturer_2.address,
},
],
)

retrieved_manufacturers = manufacturer_repository.list()

database_mock.manufacturer.find.assert_called_once_with()
assert retrieved_manufacturers == [manufacturer_1, manufacturer_2]


def test_list_when_no_manufacturers(test_helpers, database_mock, manufacturer_repository):
"""Test trying to get all manufacturers when there are none in the databse"""
test_helpers.mock_find(database_mock.manufacturer, [])
retrieved_manufacturers = manufacturer_repository.list()

assert retrieved_manufacturers == []
10 changes: 10 additions & 0 deletions test/unit/services/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from inventory_management_system_api.models.catalogue_category import CatalogueCategoryOut
from inventory_management_system_api.models.catalogue_item import CatalogueItemOut
from inventory_management_system_api.repositories.catalogue_category import CatalogueCategoryRepo
from inventory_management_system_api.repositories.manufacturer import ManufacturerRepo
from inventory_management_system_api.repositories.catalogue_item import CatalogueItemRepo
from inventory_management_system_api.repositories.system import SystemRepo
from inventory_management_system_api.services.catalogue_category import CatalogueCategoryService
Expand Down Expand Up @@ -36,6 +37,15 @@ def fixture_catalogue_item_repository_mock() -> Mock:
return Mock(CatalogueItemRepo)


@pytest.fixture(name="manufacturer_repository_mock")
def fixture_manufacturer_repository_mock() -> Mock:
"""
Fixture to create a mock of the `ManufacturerRepo dependency
:return: Mocked ManufacturerRepo instance
"""
return Mock(ManufacturerRepo)

@pytest.fixture(name="system_repository_mock")
def fixture_system_repository_mock() -> Mock:
"""
Expand Down
78 changes: 78 additions & 0 deletions test/unit/services/test_manufacturer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
"""
Unit tests for the `ManufacturerService` service.
"""

from unittest.mock import Mock
import pytest
from bson import ObjectId

from inventory_management_system_api.models.manufacturer import ManufacturerIn, ManufacturerOut
from inventory_management_system_api.schemas.manufacturer import ManufacturerPostRequestSchema
from inventory_management_system_api.services.manufacturer import ManufacturerService


@pytest.fixture(name="manufacturer_service")
def fixture_manufacturer_service(manufacturer_repository_mock: Mock) -> ManufacturerService:
"""
Fixture to create a `ManufacturerService` instance with a mocked `ManufacturerRepo`
:param: manufacturer_repository_mock: Mocked `ManufacturerRepo` instance.
:return: `ManufacturerService` instance with mocked dependency
"""
return ManufacturerService(manufacturer_repository_mock)


def test_create(manufacturer_repository_mock, manufacturer_service):
"""
Testing creating a manufacturer
"""
manufacturer = ManufacturerOut(
_id=str(ObjectId()),
name="Manufacturer A",
code="manufacturer-a",
url="http://testUrl.co.uk",
address="1 Example street",
)
manufacturer_repository_mock.create.return_value = manufacturer

created_manufacturer = manufacturer_service.create(
ManufacturerPostRequestSchema(
name=manufacturer.name,
url=manufacturer.url,
address=manufacturer.address,
)
)
manufacturer_repository_mock.create.assert_called_once_with(
ManufacturerIn(
name=manufacturer.name,
code=manufacturer.code,
url=manufacturer.url,
address=manufacturer.address,
)
)
assert created_manufacturer == manufacturer


def test_list(manufacturer_repository_mock, manufacturer_service):
"""Test getting all manufacturers"""
# pylint: disable=duplicate-code
manufacturer_1 = ManufacturerOut(
_id=str(ObjectId()),
code="manufacturer-a",
name="Manufacturer A",
url="http://testUrl.co.uk",
address="1 Example street",
)

manufacturer_2 = ManufacturerOut(
_id=str(ObjectId()),
code="manufacturer-b",
name="Manufacturer B",
url="http://2ndTestUrl.co.uk",
address="2 Example street",
)
# pylint: enable=duplicate-code
manufacturer_repository_mock.list.return_value = [manufacturer_1, manufacturer_2]
retrieved_manufacturer = manufacturer_service.list()
manufacturer_repository_mock.list.assert_called_once_with()
assert retrieved_manufacturer == [manufacturer_1, manufacturer_2]

0 comments on commit c5bb224

Please sign in to comment.