Skip to content

Commit

Permalink
Add new api unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
paradoxxxzero committed Sep 16, 2024
1 parent 95eab64 commit 605d0ee
Show file tree
Hide file tree
Showing 7 changed files with 473 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# specific on the project
*credential.py
/roulier/tests/credentials.py
*label*.pdf # files downloaded when executed some tests

# Byte-compiled / optimized / DLL files
Expand Down
Empty file added roulier/tests/__init__.py
Empty file.
58 changes: 58 additions & 0 deletions roulier/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Copyright 2024 Akretion (http://www.akretion.com).
# @author Florian Mounier <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from datetime import date
import pytest

try:
from .credentials import CREDENTIALS
except ImportError:
from .credentials_demo import CREDENTIALS


@pytest.fixture(scope="session")
def credentials():
return {
**CREDENTIALS,
"isTest": True,
}


@pytest.fixture
def base_get_label_data():
return {
"service": {
"shippingDate": date(2024, 1, 1),
"labelFormat": "PDF",
},
"parcels": [{"weight": 1.2, "comment": "Fake comment"}],
"from_address": {
"name": "Akrétion",
"street1": "27 rue Henri Rolland",
"street2": "Batiment B",
"city": "Villeurbanne",
"zip": "69100",
"country": "FR",
"phone": "+33482538457",
},
"to_address": {
"name": "Hügǒ",
"firstName": "Victor",
"street1": "6 Place des Vôsges",
"city": "Paris",
"zip": "75004",
"country": "FR",
"email": "[email protected]",
"phone": "+33600000000",
},
}


@pytest.fixture
def base_find_pickup_site_data():
return {
"search": {
"country": "FR",
"zip": "69100",
},
}
12 changes: 12 additions & 0 deletions roulier/tests/credentials_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright 2024 Akretion (http://www.akretion.com).
# @author Florian Mounier <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

"""Copy this file to credentials.py and fill in your test credentials"""

CREDENTIALS = {
"mondialrelay_fr": { # These are public test credentials
"login": "BDTEST13",
"password": "PrivateK",
},
}
272 changes: 272 additions & 0 deletions roulier/tests/test_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
# Copyright 2024 Akretion (http://www.akretion.com).
# @author Florian Mounier <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from roulier import roulier
from roulier.carrier import Carrier, action
from roulier.exception import CarrierError, InvalidApiInput
from pydantic import BaseModel
import pytest


@pytest.fixture(autouse=True)
def reset_roulier():
roulier.factory._carrier_action = {}


def test_carrier_api():
assert "dummy" not in roulier.get_carriers_action_available()

class DummyIn(BaseModel):
name: str
id: int

class DummyOut(BaseModel):
outname: str
outid: int

@classmethod
def from_in(cls, data: DummyIn):
return cls(outname=data.name, outid=data.id)

class DummyCarrier(Carrier):
__key__ = "dummy"

@action
def get(self, input: DummyIn) -> DummyOut:
assert input.name == "test"
assert input.id == 1

return DummyOut.from_in(input)

assert "dummy" in roulier.get_carriers_action_available()
assert roulier.get_carriers_action_available()["dummy"] == ["get"]

rv = roulier.get("dummy", "get", {"name": "test", "id": 1})
assert rv == {"outname": "test", "outid": 1}


def test_carrier_api_unexposed():
class DummySubIn(BaseModel):
key: str

class DummyIn(BaseModel):
name: str | None = None
subs: list[DummySubIn]

class DummyOut(BaseModel):
len: int

@classmethod
def from_in(cls, data: DummyIn):
return cls(len=len(data.subs))

class DummyCarrier(Carrier):
__key__ = "dummy"

def unexposed(self, input: DummyIn) -> DummyOut:
"""This should not be exposed."""

@action
def acquire(self, input: DummyIn) -> DummyOut:
assert input.name == None
assert len(input.subs) == 2
return DummyOut.from_in(input)

assert "dummy" in roulier.get_carriers_action_available()
assert roulier.get_carriers_action_available()["dummy"] == ["acquire"]

rv = roulier.get("dummy", "acquire", {"subs": [{"key": "test"}, {"key": "test2"}]})
assert rv == {"len": 2}


def test_carrier_api_bad_input_signature():

class DummyOut(BaseModel):
pass

class DummyCarrier(Carrier):
__key__ = "dummy"

@action
def get(self, input) -> DummyOut:
pass

with pytest.raises(ValueError) as excinfo:
roulier.get("dummy", "get", {})
assert "Missing input argument or type hint" in str(excinfo.value)


def test_carrier_api_bad_output_signature():
class DummyIn(BaseModel):
pass

class DummyCarrier(Carrier):
__key__ = "dummy"

@action
def get(self, input: DummyIn):
pass

with pytest.raises(ValueError) as excinfo:
roulier.get("dummy", "get", {})
assert "Missing return type hint" in str(excinfo.value)


def test_carrier_api_invalid_input():
class DummyIn(BaseModel):
name: str
id: int

class DummyOut(BaseModel):
outname: str
outid: int

@classmethod
def from_in(cls, data: DummyIn):
return cls(outname=data.name, outid=data.id)

class DummyCarrier(Carrier):
__key__ = "dummy"

@action
def get(self, input: DummyIn) -> DummyOut:
return DummyOut.from_in(input)

assert "dummy" in roulier.get_carriers_action_available()
assert roulier.get_carriers_action_available()["dummy"] == ["get"]

with pytest.raises(InvalidApiInput) as excinfo:
roulier.get("dummy", "get", {"description": "test", "id": 1})

assert "Invalid input data" in str(excinfo.value)
assert "name\n Field required" in str(excinfo.value)


def test_carrier_api_invalid_output():
class DummyIn(BaseModel):
name: str
id: int

class DummyOut(BaseModel):
outname: str
outid: int

@classmethod
def from_in(cls, data: DummyIn):
return cls(out=data.name)

class DummyCarrier(Carrier):
__key__ = "dummy"

@action
def get(self, input: DummyIn) -> DummyOut:
return DummyOut.from_in(input)

assert "dummy" in roulier.get_carriers_action_available()
assert roulier.get_carriers_action_available()["dummy"] == ["get"]

with pytest.raises(CarrierError) as excinfo:
roulier.get("dummy", "get", {"name": "test", "id": 1})

assert "Action failed" in str(excinfo.value)
assert "outname\n Field required" in str(excinfo.value)


def test_carrier_api_carrier_error():
class DummyIn(BaseModel):
name: str
id: int

class DummyOut(BaseModel):
outname: str
outid: int

@classmethod
def from_in(cls, data: DummyIn):
return cls(outname=data.name, outid=data.id)

class DummyCarrier(Carrier):
__key__ = "dummy"

@action
def get(self, input: DummyIn) -> DummyOut:
raise CarrierError({"url": "http://fail"}, "This failed miserably")

assert "dummy" in roulier.get_carriers_action_available()
assert roulier.get_carriers_action_available()["dummy"] == ["get"]

with pytest.raises(CarrierError) as excinfo:
roulier.get("dummy", "get", {"name": "test", "id": 1})

assert "This failed miserably" in str(excinfo.value)
assert excinfo.value.response == {"url": "http://fail"}


def test_carrier_api_extra_input():
class DummyIn(BaseModel):
name: str
id: int

class DummyOut(BaseModel):
outname: str
outid: int

@classmethod
def from_in(cls, data: DummyIn):
return cls(outname=data.name, outid=data.id)

class DummyCarrier(Carrier):
__key__ = "dummy"

@action
def get(self, input: DummyIn) -> DummyOut:
return DummyOut.from_in(input)

assert "dummy" in roulier.get_carriers_action_available()
assert roulier.get_carriers_action_available()["dummy"] == ["get"]

rv = roulier.get("dummy", "get", {"name": "test", "description": "test", "id": 1})
assert rv == {"outname": "test", "outid": 1}


def test_carrier_api_multi_actions():
class DummyIn(BaseModel):
name: str
id: int

class DummyOut(BaseModel):
outname: str
outid: int

@classmethod
def from_in(cls, data: DummyIn):
return cls(outname=data.name, outid=data.id)

class DummyAcquireOut(BaseModel):
out: str

@classmethod
def from_in(cls, data: DummyIn):
return cls(out=f"[{data.id}] {data.name}")

class DummyCarrier(Carrier):
__key__ = "dummy"

@action
def get(self, input: DummyIn) -> DummyOut:
return DummyOut.from_in(input)

@action
def acquire(self, input: DummyIn) -> DummyAcquireOut:
return DummyAcquireOut.from_in(input)

assert "dummy" in roulier.get_carriers_action_available()
assert roulier.get_carriers_action_available()["dummy"] == ["get", "acquire"]

rv = roulier.get("dummy", "get", {"name": "test", "description": "test", "id": 1})
assert rv == {"outname": "test", "outid": 1}

rv = roulier.get(
"dummy", "acquire", {"name": "test", "description": "test", "id": 1}
)
assert rv == {"out": "[1] test"}
Loading

0 comments on commit 605d0ee

Please sign in to comment.