Skip to content

Commit 6c0eeb4

Browse files
Move InMemorySubscriber from L2 to L3 client module (#56)
* Move InMemorySubscriber from L2 to L3 client module * Updated UListener on_receive method to be asynchronous and add additional test cases * Update READMEs * Bump version to 0.2.0 for major release introducing L2 and L3. * Delete client README.html * Incorporated Reviewers comment * Fixed review comments * Fixed communication status issue * Added subscriber info in unsubscribe request * Address review comments
1 parent 7ac8b2f commit 6c0eeb4

26 files changed

Lines changed: 809 additions & 325 deletions

README.adoc

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33

44
== Overview
55

6-
This library implements the https://github.com/eclipse-uprotocol/uprotocol-spec/blob/main/languages.adoc[uProtocol Language Specific Library Requirements] for Python defined in https://github.com/eclipse-uprotocol/uprotocol-spec/tree/main[uProtocol Specifications]. The library is organized into packages that are described in <<sdk-packages>> below. Each package contains a README.adoc file that describes the purpose of the package and how to use it.
6+
This library implements the https://github.com/eclipse-uprotocol/uprotocol-spec/blob/main/languages.adoc[uProtocol Language Specific Library Requirements] for Python defined in https://github.com/eclipse-uprotocol/uprotocol-spec/tree/main[uProtocol Specifications]. The library is organized into packages that are described in <<sdk-packages>> below and organized by the layers of the protocol.
7+
8+
Each package contains a README.adoc file that describes the purpose of the package and how to use it.
79

810
The module contains the factory methods, serializers, and validators for all data types defined in the specifications, and any data models that either haven't or couldn't be defined in uprotocol-core-api yet (ex. UPayload) This library fits into the big picture of the uProtocol SDK as seen in the diagram below.
911

@@ -63,23 +65,31 @@ The Library is broken up into different packages that are described in <<sdk-pac
6365

6466

6567
.SDK Packages
66-
[#sdk-packages,width=100%,cols="20%,80%",options="header"]
68+
[#sdk-packages,width=100%,cols="1,2,5",options="header"]
6769
|===
6870

69-
| Package | Purpose
71+
| Package | Protocol Layer | Purpose
72+
73+
| link:uprotocol/client/README.adoc[`*client*`]
74+
| https://github.com/eclipse-uprotocol/up-spec/tree/main/up-l3[Application Layer (uP-L3)]
75+
| Top level client-facing interfaces to communication with USubscription, UDiscovery, and UTwin services.
76+
77+
| link:uprotocol/communication/README.adoc[`*communication*`]
78+
| https://github.com/eclipse-uprotocol/up-spec/tree/main/up-l2[communication layer (uP-L2)]
79+
| Common implementation of communication messaging patterns (publisher, subscriber, Rpcclient, RpcServer, etc..) that is build on top of the L1 transport interface (see below)
80+
81+
| link:uprotocol/transport/README.adoc[`*transport*`]
82+
| https://github.com/eclipse-uprotocol/uprotocol-spec/blob/main/up-l1/README.adoc[Transport Layer (uP-L1)]
83+
| Interface and data model for how to send() and receive() messages in a common way across various transport technologies (ex. zenoh, mqtt, http, etc...). the interface is implemented by transports (ex. up-transport-zenoh-python), and the interface is then used to build the uProtocol layer 2 communication layer implementation.
7084

7185
| link:uprotocol/uri/README.adoc[`*uri*`]
86+
|
7287
| Uniform Resource Identifier (RFC3986), how uProtocol addresses things (devices, software, methods, topics, etc...) on the network.
7388

7489
| link:uprotocol/uuid/README.adoc[`*uuid*`]
90+
|
7591
| Identifier used to uniquely identify (and timestamp) messages that are sent.
7692

77-
| link:uprotocol/communication/README.adoc[`*communication*`]
78-
| Interface to build entities that use UTransport APIs to communicate with other entities. This is described in further detail on the up-spec page about https://github.com/eclipse-uprotocol/up-spec/tree/main/up-l2[L2 APIs].
79-
80-
| link:uprotocol/transport/README.adoc[`*transport*`]
81-
| Interface and data model declaration used for bidirectional point-2-point communication between uEs. This interface is then implemented by client libraries (described https://github.com/eclipse-uprotocol/up-spec/blob/main/up-l1/README.adoc[here]) for a given underlying transport (ex. Binder, MQTT, Zenoh, SOME/IP, DDS, HTTP, etc…​)
82-
8393
|===
8494

8595
NOTE: Please visit the READMEs in <<sdk-packages>> for examples of how to use the different data types and their factories, validators, and serializers.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "up-python"
3-
version = "0.1.3-dev"
3+
version = "0.2.0-dev"
44
description = "Language specific uProtocol library for building and using UUri, UUID, UAttributes, UTransport, and more."
55
authors = ["Neelam Kushwah <neelam.kushwah@gm.com>"]
66
license = "The Apache License, Version 2.0"

tests/test_client/__init__.py

Whitespace-only changes.

tests/test_client/test_usubscription/__init__.py

Whitespace-only changes.

tests/test_client/test_usubscription/test_v3/__init__.py

Whitespace-only changes.

tests/test_communication/test_inmemorysubscriber.py renamed to tests/test_client/test_usubscription/test_v3/test_inmemoryusubcriptionclient.py

Lines changed: 317 additions & 35 deletions
Large diffs are not rendered by default.

tests/test_communication/mock_utransport.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,13 @@ async def send(self, message: UMessage) -> UStatus:
8181

8282
if message.attributes.type == UMessageType.UMESSAGE_TYPE_REQUEST:
8383
response = self.build_response(message)
84-
self._notify_listeners(response)
84+
await self._notify_listeners(response)
8585

8686
return UStatus(code=UCode.OK)
8787

88-
def _notify_listeners(self, response: UMessage):
88+
async def _notify_listeners(self, response: UMessage):
8989
for listener in self.listeners:
90-
listener.on_receive(response)
90+
await listener.on_receive(response)
9191

9292
async def register_listener(self, source: UUri, listener: UListener, sink: UUri = None) -> UStatus:
9393
self.listeners.append(listener)
@@ -130,12 +130,22 @@ def build_response(self, request):
130130
)
131131

132132

133+
class CommStatusUCodeOKTransport(MockUTransport):
134+
def build_response(self, request):
135+
status = UStatus(code=UCode.OK, message="No Communication Error")
136+
return (
137+
UMessageBuilder.response_for_request(request.attributes)
138+
.with_commstatus(status.code)
139+
.build_from_upayload(UPayload.pack(status))
140+
)
141+
142+
133143
class EchoUTransport(MockUTransport):
134144
def build_response(self, request):
135145
return request
136146

137147
async def send(self, message):
138148
response = self.build_response(message)
139-
executor = ThreadPoolExecutor(max_workers=1)
140-
executor.submit(self._notify_listeners, response)
149+
150+
await self._notify_listeners(response)
141151
return UStatus(code=UCode.OK)

tests/test_communication/test_inmemoryrpcclient.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@
1414

1515
import unittest
1616

17-
from tests.test_communication.mock_utransport import CommStatusTransport, MockUTransport, TimeoutUTransport
17+
from tests.test_communication.mock_utransport import (
18+
CommStatusTransport,
19+
CommStatusUCodeOKTransport,
20+
MockUTransport,
21+
TimeoutUTransport,
22+
)
1823
from uprotocol.communication.calloptions import CallOptions
1924
from uprotocol.communication.inmemoryrpcclient import InMemoryRpcClient
2025
from uprotocol.communication.upayload import UPayload
@@ -101,6 +106,12 @@ async def test_invoke_method_with_comm_status_transport(self):
101106
self.assertEqual(UCode.FAILED_PRECONDITION, context.exception.status.code)
102107
self.assertEqual("Communication error [FAILED_PRECONDITION]", context.exception.status.message)
103108

109+
async def test_invoke_method_with_comm_status_transport(self):
110+
rpc_client = InMemoryRpcClient(CommStatusUCodeOKTransport())
111+
payload = UPayload.pack_to_any(UUri())
112+
response = await rpc_client.invoke_method(self.create_method_uri(), payload, None)
113+
self.assertEqual(UCode.OK, UPayload.unpack(response, UStatus).code)
114+
104115
async def test_invoke_method_with_error_transport(self):
105116
class ErrorUTransport(MockUTransport):
106117
async def send(self, message):

tests/test_communication/test_inmemoryrpcserver.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
from unittest.mock import AsyncMock, MagicMock
1919

2020
from tests.test_communication.mock_utransport import EchoUTransport
21+
from uprotocol.communication.calloptions import CallOptions
22+
from uprotocol.communication.inmemoryrpcclient import InMemoryRpcClient
2123
from uprotocol.communication.inmemoryrpcserver import InMemoryRpcServer
2224
from uprotocol.communication.requesthandler import RequestHandler
2325
from uprotocol.communication.upayload import UPayload
@@ -27,6 +29,7 @@
2729
from uprotocol.transport.utransport import UTransport
2830
from uprotocol.uri.serializer.uriserializer import UriSerializer
2931
from uprotocol.v1.ucode_pb2 import UCode
32+
from uprotocol.v1.umessage_pb2 import UMessage
3033
from uprotocol.v1.uri_pb2 import UUri
3134
from uprotocol.v1.ustatus_pb2 import UStatus
3235

@@ -136,7 +139,7 @@ async def custom_register_listener_behavior(source: UUri, listener: UListener, s
136139
async def custom_send_behavior(message):
137140
serialized_uri = UriSerializer().serialize(message.attributes.sink)
138141
if serialized_uri in listeners:
139-
listeners[serialized_uri].on_receive(message)
142+
await listeners[serialized_uri].on_receive(message)
140143
return UStatus(code=UCode.OK)
141144

142145
self.mock_transport.send = AsyncMock(side_effect=custom_send_behavior)
@@ -196,6 +199,22 @@ async def test_handle_requests_exception(self):
196199
status = await transport.send(request)
197200
self.assertEqual(status.code, UCode.OK)
198201

202+
async def test_end_to_end_rpc_with_test_transport(self):
203+
class MyRequestHandler(RequestHandler):
204+
def handle_request(self, message: UMessage) -> UPayload:
205+
return UPayload.pack(UUri())
206+
207+
handler = MyRequestHandler()
208+
test_transport = EchoUTransport()
209+
server = InMemoryRpcServer(test_transport)
210+
method = self.create_method_uri()
211+
212+
self.assertEqual((await server.register_request_handler(method, handler)).code, UCode.OK)
213+
rpc_client = InMemoryRpcClient(test_transport)
214+
response = await rpc_client.invoke_method(method, None, CallOptions.DEFAULT)
215+
self.assertIsNotNone(response)
216+
self.assertEqual(response, UPayload.pack(UUri()))
217+
199218

200219
if __name__ == '__main__':
201220
unittest.main()

tests/test_communication/test_simplenotifier.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ async def test_register_listener(self):
6262
self.transport.get_source.return_value = self.source
6363

6464
class TestListener(UListener):
65-
def on_receive(self, message: UMessage):
65+
async def on_receive(self, message: UMessage):
6666
pass
6767

6868
listener = TestListener()
@@ -78,7 +78,7 @@ async def test_unregister_notification_listener(self):
7878
self.transport.unregister_listener.return_value = UStatus(code=UCode.OK)
7979

8080
class TestListener(UListener):
81-
def on_receive(self, message: UMessage):
81+
async def on_receive(self, message: UMessage):
8282
pass
8383

8484
listener = TestListener()
@@ -97,7 +97,7 @@ async def test_unregister_listener_not_registered(self):
9797
self.transport.unregister_listener.return_value = UStatus(code=UCode.NOT_FOUND)
9898

9999
class TestListener(UListener):
100-
def on_receive(self, message: UMessage):
100+
async def on_receive(self, message: UMessage):
101101
pass
102102

103103
listener = TestListener()

0 commit comments

Comments
 (0)