shapeshifter-uftp 1.1.1.dev2__tar.gz → 1.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/PKG-INFO +1 -1
  2. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/README.rst +7 -0
  3. shapeshifter-uftp-1.2.0/pyproject.toml +18 -0
  4. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/setup.py +40 -40
  5. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/client/base_client.py +7 -5
  6. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/client/dso_agr_client.py +4 -11
  7. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/client/dso_cro_client.py +1 -1
  8. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/service/base_service.py +11 -23
  9. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/uftp/cro_dso.py +8 -7
  10. shapeshifter-uftp-1.2.0/shapeshifter_uftp/uftp/parsing.py +8 -0
  11. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/uftp/validations.py +32 -29
  12. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp.egg-info/PKG-INFO +1 -1
  13. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp.egg-info/SOURCES.txt +2 -0
  14. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp.egg-info/requires.txt +5 -5
  15. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/test/test_communications.py +54 -57
  16. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/setup.cfg +0 -0
  17. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/__init__.py +0 -0
  18. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/cli.py +0 -0
  19. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/client/__init__.py +0 -0
  20. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/client/agr_cro_client.py +0 -0
  21. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/client/agr_dso_client.py +0 -0
  22. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/client/cro_agr_client.py +0 -0
  23. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/client/cro_dso_client.py +0 -0
  24. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/exceptions.py +0 -0
  25. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/logging.py +0 -0
  26. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/service/__init__.py +1 -1
  27. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/service/agr_service.py +0 -0
  28. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/service/cro_service.py +0 -0
  29. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/service/dso_service.py +0 -0
  30. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/transport.py +0 -0
  31. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/uftp/__init__.py +0 -0
  32. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/uftp/agr_cro.py +0 -0
  33. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/uftp/agr_dso.py +0 -0
  34. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/uftp/common.py +0 -0
  35. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/uftp/defaults.py +0 -0
  36. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp/uftp/metering.py +0 -0
  37. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp.egg-info/dependency_links.txt +0 -0
  38. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp.egg-info/entry_points.txt +0 -0
  39. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/shapeshifter_uftp.egg-info/top_level.txt +0 -0
  40. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/test/test_cli.py +0 -0
  41. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/test/test_client_errors.py +0 -0
  42. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/test/test_client_with_workers.py +0 -0
  43. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/test/test_clients_from_service.py +0 -0
  44. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/test/test_default_responses.py +0 -0
  45. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/test/test_message_destination.py +0 -0
  46. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/test/test_presence_of_client_methods.py +0 -0
  47. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/test/test_presence_of_service_methods.py +0 -0
  48. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/test/test_roundtrip_serialization.py +0 -0
  49. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/test/test_seal_and_unseal.py +0 -0
  50. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/test/test_service_errors.py +0 -0
  51. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/test/test_snake_case.py +0 -0
  52. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/test/test_ttl_cache.py +0 -0
  53. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/test/test_validations.py +0 -0
  54. {shapeshifter-uftp-1.1.1.dev2 → shapeshifter-uftp-1.2.0}/test/test_xml_schema_compliance.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: shapeshifter-uftp
3
- Version: 1.1.1.dev2
3
+ Version: 1.2.0
4
4
  Summary: Allows connections between DSO, AGR and CRO using the Shapeshifter (UFTP) protocol.
5
5
  Requires-Python: >=3.10
6
6
  Provides-Extra: dev
@@ -41,6 +41,13 @@ Version History
41
41
  +-------------+-------------------+----------------------------------+
42
42
  | Version | Release Date | Release Notes |
43
43
  +=============+===================+==================================+
44
+ | 1.2.0 | 2024-04-04 | Upgrade to latest FastAPI and |
45
+ | | | Pydantic. |
46
+ +-------------+-------------------+----------------------------------+
47
+ | 1.1.2 | 2024-03-12 | Pinned dependencies after a |
48
+ | | | breaking update to fastapi-xml |
49
+ | | | was released. |
50
+ +-------------+-------------------+----------------------------------+
44
51
  | 1.1.0 | 2023-08-30 | Use the published 3.0.0 spec |
45
52
  | | | for the XSD validation and |
46
53
  | | | objects. |
@@ -0,0 +1,18 @@
1
+ [tool.pytest.ini_options]
2
+ addopts = "-v --cov --cov-report html"
3
+
4
+ [tool.coverage.run]
5
+ include = [
6
+ "shapeshifter_uftp/**/*.py",
7
+ ]
8
+ omit = [
9
+ "application/asgi.py",
10
+ ]
11
+
12
+ [tool.coverage.report]
13
+ skip_empty = true
14
+
15
+ [tool.coverage.html]
16
+ directory = "test_coverage"
17
+
18
+ [tool.pylint.DESIGN]
@@ -1,40 +1,40 @@
1
- from setuptools import setup
2
-
3
- setup(
4
- name="shapeshifter-uftp",
5
- version="1.1.1.dev2",
6
- python_requires=">=3.10",
7
- description="Allows connections between DSO, AGR and CRO using the Shapeshifter (UFTP) protocol.",
8
- packages=[
9
- "shapeshifter_uftp",
10
- "shapeshifter_uftp.uftp",
11
- "shapeshifter_uftp.client",
12
- "shapeshifter_uftp.service",
13
- ],
14
- install_requires=[
15
- "xsdata[lxml]",
16
- "pynacl",
17
- "dnspython",
18
- "fastapi<0.100",
19
- "fastapi-xml",
20
- "requests",
21
- "uvicorn",
22
- "termcolor",
23
- ],
24
- extras_require={
25
- "dev": [
26
- "xmlschema",
27
- "pytest",
28
- "pytest-cov",
29
- "pylint",
30
- "sphinx",
31
- "sphinx-rtd-theme",
32
- ]
33
- },
34
- entry_points={
35
- "console_scripts": [
36
- "shapeshifter-keypair = shapeshifter_uftp.cli:generate_signing_keypair",
37
- "shapeshifter-lookup = shapeshifter_uftp.cli:perform_lookup",
38
- ]
39
- },
40
- )
1
+ from setuptools import setup
2
+
3
+ setup(
4
+ name="shapeshifter-uftp",
5
+ version="1.2.0",
6
+ python_requires=">=3.10",
7
+ description="Allows connections between DSO, AGR and CRO using the Shapeshifter (UFTP) protocol.",
8
+ packages=[
9
+ "shapeshifter_uftp",
10
+ "shapeshifter_uftp.uftp",
11
+ "shapeshifter_uftp.client",
12
+ "shapeshifter_uftp.service",
13
+ ],
14
+ install_requires=[
15
+ "xsdata[lxml]==24.4",
16
+ "pynacl==1.5.0",
17
+ "dnspython==2.6.1",
18
+ "fastapi==0.110",
19
+ "fastapi-xml==1.1.0",
20
+ "requests",
21
+ "uvicorn",
22
+ "termcolor",
23
+ ],
24
+ extras_require={
25
+ "dev": [
26
+ "xmlschema",
27
+ "pytest",
28
+ "pytest-cov",
29
+ "pylint",
30
+ "sphinx",
31
+ "sphinx-rtd-theme",
32
+ ]
33
+ },
34
+ entry_points={
35
+ "console_scripts": [
36
+ "shapeshifter-keypair = shapeshifter_uftp.cli:generate_signing_keypair",
37
+ "shapeshifter-lookup = shapeshifter_uftp.cli:perform_lookup",
38
+ ]
39
+ },
40
+ )
@@ -1,14 +1,16 @@
1
- from datetime import datetime, timezone
2
1
  import sched
3
2
  import time
3
+ from datetime import datetime, timezone
4
4
  from queue import Queue
5
- from threading import Thread, Event
5
+ from threading import Event, Thread
6
6
  from uuid import uuid4
7
+
7
8
  import requests
8
- from ..uftp import PayloadMessage, PayloadMessageResponse, SignedMessage
9
- from ..logging import logger
10
- from ..exceptions import ClientTransportException
9
+
11
10
  from .. import transport
11
+ from ..exceptions import ClientTransportException
12
+ from ..logging import logger
13
+ from ..uftp import PayloadMessage, PayloadMessageResponse, SignedMessage
12
14
 
13
15
 
14
16
  class ShapeshifterClient():
@@ -1,15 +1,8 @@
1
+ from ..uftp import (DPrognosisResponse, FlexOfferResponse,
2
+ FlexOfferRevocationResponse, FlexOrder, FlexRequest,
3
+ FlexReservationUpdate, FlexSettlement, MeteringResponse,
4
+ PayloadMessageResponse)
1
5
  from .base_client import ShapeshifterClient
2
- from ..uftp import (
3
- DPrognosisResponse,
4
- FlexRequest,
5
- FlexOfferResponse,
6
- FlexOrder,
7
- FlexReservationUpdate,
8
- FlexOfferRevocationResponse,
9
- FlexSettlement,
10
- PayloadMessageResponse,
11
- MeteringResponse,
12
- )
13
6
 
14
7
 
15
8
  class ShapeshifterDsoAgrClient(ShapeshifterClient):
@@ -1,5 +1,5 @@
1
+ from ..uftp import DsoPortfolioQuery, DsoPortfolioUpdate
1
2
  from .base_client import ShapeshifterClient
2
- from ..uftp import DsoPortfolioUpdate, DsoPortfolioQuery
3
3
 
4
4
 
5
5
  class ShapeshifterDsoCroClient(ShapeshifterClient):
@@ -1,31 +1,22 @@
1
+ import re
1
2
  from datetime import datetime, timezone
2
3
  from queue import Queue
3
- from uuid import uuid4
4
- from time import sleep
5
4
  from threading import Thread
6
- import re
7
- import traceback
5
+ from time import sleep
6
+ from uuid import uuid4
8
7
 
8
+ import uvicorn
9
9
  from fastapi import FastAPI
10
10
  from fastapi.exceptions import HTTPException
11
- from fastapi_xml import XmlAppResponse, NonJsonRoute
12
- import uvicorn
11
+ from fastapi_xml import XmlAppResponse, XmlRoute
13
12
 
13
+ from .. import transport
14
14
  from ..client import client_map
15
- from ..uftp import (
16
- SignedMessage,
17
- PayloadMessage,
18
- PayloadMessageResponse,
19
- AcceptedRejected,
20
- )
21
- from ..exceptions import (
22
- FunctionalException,
23
- TransportException,
24
- InvalidSenderException,
25
- InvalidMessageException,
26
- )
15
+ from ..exceptions import (FunctionalException, InvalidMessageException,
16
+ InvalidSenderException, TransportException)
27
17
  from ..logging import logger
28
- from .. import transport
18
+ from ..uftp import (AcceptedRejected, PayloadMessage, PayloadMessageResponse,
19
+ SignedMessage)
29
20
 
30
21
 
31
22
  class ShapeshifterService():
@@ -89,7 +80,7 @@ class ShapeshifterService():
89
80
  # (one) endpoint, and by virtue of FastAPI-XML convert the
90
81
  # python-friendly objects into XML and vice versa.
91
82
  self.app = FastAPI(default_response_class=XmlAppResponse)
92
- self.app.router.route_class = NonJsonRoute
83
+ self.app.router.route_class = XmlRoute
93
84
  self.app.router.add_api_route(
94
85
  path,
95
86
  endpoint=self._receive_message,
@@ -251,9 +242,6 @@ class ShapeshifterService():
251
242
  f"An error occurred during the post-processing of a {message.__class__.__name__} message."
252
243
  f"{err.__class__.__name__}: {err}"
253
244
  )
254
- logger.error(
255
- traceback.format_exc()
256
- )
257
245
  finally:
258
246
  self.inbound_queue.task_done()
259
247
 
@@ -265,13 +265,6 @@ class DsoPortfolioQueryResponse(PayloadMessageResponse):
265
265
  class Meta:
266
266
  name = "DSOPortfolioQueryResponse"
267
267
 
268
- congestion_point: Optional[DsoPortfolioQueryCongestionPoint] = field(
269
- default=None,
270
- metadata={
271
- "name": "CongestionPoint",
272
- "type": "Element",
273
- }
274
- )
275
268
  dso_portfolio_query_message_id: str = field(
276
269
  metadata={
277
270
  "name": "DSOPortfolioQueryMessageID",
@@ -280,6 +273,14 @@ class DsoPortfolioQueryResponse(PayloadMessageResponse):
280
273
  "pattern": r"[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}",
281
274
  }
282
275
  )
276
+
277
+ congestion_point: Optional[DsoPortfolioQueryCongestionPoint] = field(
278
+ default=None,
279
+ metadata={
280
+ "name": "CongestionPoint",
281
+ "type": "Element",
282
+ }
283
+ )
283
284
  time_zone: str = field(
284
285
  default=DEFAULT_TIME_ZONE,
285
286
  metadata={
@@ -0,0 +1,8 @@
1
+ from datetime import datetime
2
+ import re
3
+
4
+
5
+ def parse_uftp_timestamp(timestamp_str):
6
+ """
7
+ Parses a UFTP timestamp into a Python datetime.datetime object. This can take care of the
8
+ """
@@ -1,29 +1,32 @@
1
- from decimal import Decimal, InvalidOperation
2
-
3
-
4
- def validate_decimal(name: str, value: int | float | Decimal | str, digits: int):
5
- """
6
- Validates that the decimal is acceptable, and returns it with the correct number of digits.
7
- """
8
- if isinstance(value, str):
9
- try:
10
- value = Decimal(value)
11
- except InvalidOperation as exc:
12
- raise ValueError(f"{name} must be a valid numeric value, not '{value}'") from exc
13
- if not isinstance(value, (int, float, Decimal)):
14
- raise TypeError(f"'{name}' must be a numeric type, not {type(value)}")
15
- return Decimal(f"{value:.{digits}f}")
16
-
17
-
18
- def validate_list(name, value, item_type, length):
19
- """
20
- Validates that the list is of the correct type, length and content type.
21
- """
22
- if not isinstance(value, list):
23
- raise TypeError(f"'{name}' must be a list, not {type(value)}")
24
- if len(value) < length:
25
- raise ValueError(f"'Length of list '{name}' must be {length} or greater, not {len(value)}")
26
- # if not all(isinstance(item, item_type) for item in value):
27
- # raise TypeError(f"'Not all items in list were of type {item_type}")
28
- return value
29
-
1
+ from decimal import Decimal, InvalidOperation
2
+
3
+
4
+ def validate_decimal(name: str, value: int | float | Decimal | str, digits: int):
5
+ """
6
+ Validates that the decimal is acceptable, and returns it with the correct number of digits.
7
+ """
8
+ if isinstance(value, str):
9
+ try:
10
+ value = Decimal(value)
11
+ except InvalidOperation as exc:
12
+ raise ValueError(f"{name} must be a valid numeric value, not '{value}'") from exc
13
+ if not isinstance(value, (int, float, Decimal)):
14
+ raise TypeError(f"'{name}' must be a numeric type, not {type(value)}")
15
+ return Decimal(f"{value:.{digits}f}")
16
+
17
+
18
+ def validate_list(name, value, item_type, length):
19
+ """
20
+ Validates that the list is of the correct type, length and content type.
21
+ """
22
+ if not isinstance(value, list):
23
+ raise TypeError(f"'{name}' must be a list, not {type(value)}")
24
+ if len(value) < length:
25
+ raise ValueError(f"'Length of list '{name}' must be {length} or greater, not {len(value)}")
26
+ for index, item in enumerate(value):
27
+ if not isinstance(item, item_type):
28
+ raise TypeError(
29
+ f"Not all items of property {name} were of type {item_type}: "
30
+ f"item at index {index} was of type {type(item)}"
31
+ )
32
+ return value
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: shapeshifter-uftp
3
- Version: 1.1.1.dev2
3
+ Version: 1.2.0
4
4
  Summary: Allows connections between DSO, AGR and CRO using the Shapeshifter (UFTP) protocol.
5
5
  Requires-Python: >=3.10
6
6
  Provides-Extra: dev
@@ -1,4 +1,5 @@
1
1
  README.rst
2
+ pyproject.toml
2
3
  setup.py
3
4
  shapeshifter_uftp/__init__.py
4
5
  shapeshifter_uftp/cli.py
@@ -31,6 +32,7 @@ shapeshifter_uftp/uftp/common.py
31
32
  shapeshifter_uftp/uftp/cro_dso.py
32
33
  shapeshifter_uftp/uftp/defaults.py
33
34
  shapeshifter_uftp/uftp/metering.py
35
+ shapeshifter_uftp/uftp/parsing.py
34
36
  shapeshifter_uftp/uftp/validations.py
35
37
  test/test_cli.py
36
38
  test/test_client_errors.py
@@ -1,8 +1,8 @@
1
- xsdata[lxml]
2
- pynacl
3
- dnspython
4
- fastapi<0.100
5
- fastapi-xml
1
+ xsdata[lxml]==24.4
2
+ pynacl==1.5.0
3
+ dnspython==2.6.1
4
+ fastapi==0.110
5
+ fastapi-xml==1.1.0
6
6
  requests
7
7
  uvicorn
8
8
  termcolor
@@ -1,57 +1,54 @@
1
- import pytest
2
- from time import sleep
3
- from concurrent.futures import ThreadPoolExecutor
4
-
5
- from shapeshifter_uftp.uftp import routing_map, PayloadMessageResponse, AcceptedRejected
6
- from shapeshifter_uftp.service.base_service import snake_case
7
- from .helpers.messages import messages
8
- from .helpers.services import DummyAgrService, DummyCroService, DummyDsoService
9
-
10
-
11
- # These fixtures allow us to only start up the services once and use
12
- # them for all the parametrized test cases, which speeds up testing.
13
- @pytest.fixture(scope='module')
14
- def agr_service():
15
- with DummyAgrService() as service:
16
- yield service
17
-
18
- @pytest.fixture(scope='module')
19
- def cro_service():
20
- with DummyCroService() as service:
21
- yield service
22
-
23
- @pytest.fixture(scope='module')
24
- def dso_service():
25
- with DummyDsoService() as service:
26
- yield service
27
-
28
-
29
- @pytest.mark.parametrize(
30
- 'message',
31
- messages,
32
- ids=[message.__class__.__name__ for message in messages]
33
- )
34
- def test_communications(message, agr_service, cro_service, dso_service):
35
- service_map = {
36
- "AGR": agr_service,
37
- "CRO": cro_service,
38
- "DSO": dso_service,
39
- }
40
-
41
- sender_role, recipient_role = routing_map[type(message)]
42
- sender = service_map[sender_role]
43
- recipient = service_map[recipient_role]
44
- client_method = f"{recipient.sender_role.lower()}_client"
45
- with ThreadPoolExecutor() as executor:
46
- with getattr(sender, client_method)(recipient.sender_domain) as client:
47
- sending_method = f"send_{snake_case(message.__class__.__name__)}"
48
- main_future = executor.submit(getattr(client, sending_method), message)
49
-
50
- parsed_message = recipient.request_futures[f"pre_process_{snake_case(message.__class__.__name__)}"].result()
51
- breakpoint()
52
- assert parsed_message == message
53
-
54
- response_message = PayloadMessageResponse()
55
- recipient.response_futures[f"pre_process_{snake_case(message.__class__.__name__)}"].set_result(response_message)
56
- assert recipient.request_futures[f"process_{snake_case(message.__class__.__name__)}"].result() == message
57
- assert main_future.result().result == AcceptedRejected.ACCEPTED
1
+ import pytest
2
+ from time import sleep
3
+ from concurrent.futures import ThreadPoolExecutor
4
+
5
+ from shapeshifter_uftp.uftp import routing_map, PayloadMessageResponse, AcceptedRejected
6
+ from shapeshifter_uftp.service.base_service import snake_case
7
+ from .helpers.messages import messages
8
+ from .helpers.services import DummyAgrService, DummyCroService, DummyDsoService
9
+
10
+
11
+ # These fixtures allow us to only start up the services once and use
12
+ # them for all the parametrized test cases, which speeds up testing.
13
+ @pytest.fixture(scope='module')
14
+ def agr_service():
15
+ with DummyAgrService() as service:
16
+ yield service
17
+
18
+ @pytest.fixture(scope='module')
19
+ def cro_service():
20
+ with DummyCroService() as service:
21
+ yield service
22
+
23
+ @pytest.fixture(scope='module')
24
+ def dso_service():
25
+ with DummyDsoService() as service:
26
+ yield service
27
+
28
+
29
+ @pytest.mark.parametrize(
30
+ 'message',
31
+ messages,
32
+ ids=[message.__class__.__name__ for message in messages]
33
+ )
34
+ def test_communications(message, agr_service, cro_service, dso_service):
35
+ service_map = {
36
+ "AGR": agr_service,
37
+ "CRO": cro_service,
38
+ "DSO": dso_service,
39
+ }
40
+
41
+ sender_role, recipient_role = routing_map[type(message)]
42
+ sender = service_map[sender_role]
43
+ recipient = service_map[recipient_role]
44
+ client_method = f"{recipient.sender_role.lower()}_client"
45
+ with ThreadPoolExecutor() as executor:
46
+ with getattr(sender, client_method)(recipient.sender_domain) as client:
47
+ sending_method = f"send_{snake_case(message.__class__.__name__)}"
48
+ main_future = executor.submit(getattr(client, sending_method), message)
49
+
50
+ assert recipient.request_futures[f"pre_process_{snake_case(message.__class__.__name__)}"].result() == message
51
+ response_message = PayloadMessageResponse()
52
+ recipient.response_futures[f"pre_process_{snake_case(message.__class__.__name__)}"].set_result(response_message)
53
+ assert recipient.request_futures[f"process_{snake_case(message.__class__.__name__)}"].result() == message
54
+ assert main_future.result().result == AcceptedRejected.ACCEPTED
@@ -1,7 +1,7 @@
1
1
  from .agr_service import ShapeshifterAgrService
2
+ from .base_service import snake_case
2
3
  from .cro_service import ShapeshifterCroService
3
4
  from .dso_service import ShapeshifterDsoService
4
- from .base_service import snake_case
5
5
 
6
6
  __all__ = [
7
7
  "ShapeshifterAgrService",