diff --git a/.idea/.gitignore b/.idea/.gitignore index ca1b149..bdf7fef 100644 --- a/.idea/.gitignore +++ b/.idea/.gitignore @@ -1,8 +1,9 @@ # IntelliJ IDEA folder-specific ignored files /shelf/ /workspace.xml +/deployment.xml /queries/ /dataSources/ /dataSources.local.xml /httpRequests/ -copilot.* \ No newline at end of file +copilot* diff --git a/examples/cameraServiceExample.py b/examples/cameraServiceExample.py index 3977b59..d3fcbae 100644 --- a/examples/cameraServiceExample.py +++ b/examples/cameraServiceExample.py @@ -4,7 +4,7 @@ from context_logger import get_logger, setup_logging from examples import setup_shutdown -from hello import ServiceInfo, Hello, Group +from hello import Service, Hello, Group setup_logging('hello') @@ -21,9 +21,12 @@ def main() -> None: group = Group.create(name='effective-range/sniper', address='239.0.1.1', port=5555, if_address=if_address) # Define the service information for the camera - info = ServiceInfo(uuid=uuid4(), name='er-sniper-camera-1', role='camera', urls={ + service = Service(uuid=uuid4(), name='er-sniper-camera-1', role='camera', address=if_address, urls={ 'api': f'grpc://{if_address}:50051', 'stream': f'http://{if_address}:8000/video_feed' + }, info={ + 'site': 'er-sniper-site-1', + 'range': 'er-sniper-range-1' }) # Use a scheduled advertizer to periodically announce the camera service @@ -32,7 +35,7 @@ def main() -> None: advertizer.start(group) # Immediately advertise the service information - advertizer.advertise(info) + advertizer.advertise(service) # Schedule periodic advertisements every 10 seconds advertizer.schedule_periodic(interval=10) diff --git a/hello/advertizer.py b/hello/advertizer.py index 5be702a..2ed632e 100644 --- a/hello/advertizer.py +++ b/hello/advertizer.py @@ -10,20 +10,20 @@ from common_utility import IReusableTimer from context_logger import get_logger -from hello import ServiceInfo, Group, Sender, Receiver, ServiceMatcher, ServiceQuery, AbstractScheduler +from hello import Service, Group, Sender, Receiver, ServiceMatcher, ServiceQuery, AbstractScheduler log = get_logger('Advertizer') class Advertizer: - def start(self, group: Group, info: ServiceInfo | None = None) -> None: + def start(self, group: Group, service: Service | None = None) -> None: raise NotImplementedError() def stop(self) -> None: raise NotImplementedError() - def advertise(self, info: ServiceInfo | None = None, log_level: int = INFO) -> None: + def advertise(self, service: Service | None = None, log_level: int = INFO) -> None: raise NotImplementedError() @@ -32,7 +32,7 @@ class DefaultAdvertizer(Advertizer): def __init__(self, sender: Sender) -> None: self._sender = sender self._group: Group | None = None - self._info: ServiceInfo | None = None + self._service: Service | None = None def __enter__(self) -> Advertizer: return self @@ -40,29 +40,29 @@ def __enter__(self) -> Advertizer: def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None: self.stop() - def start(self, group: Group, info: ServiceInfo | None = None) -> None: + def start(self, group: Group, service: Service | None = None) -> None: self._sender.start(group.hello()) self._group = group - self._info = info - log.info('Advertizer started', group=self._group, service=self._info) + self._service = service + log.info('Advertizer started', group=self._group, service=self._service) def stop(self) -> None: self._group = None - self._info = None + self._service = None self._sender.stop() log.info('Advertizer stopped') - def advertise(self, info: ServiceInfo | None = None, log_level: int = INFO) -> None: + def advertise(self, service: Service | None = None, log_level: int = INFO) -> None: if self._group: - if info: - self._info = info - if self._info: - self._sender.send(self._info) - log.log(log_level, 'Service advertised', service=self._info, group=self._group) + if service: + self._service = service + if self._service: + self._sender.send(self._service) + log.log(log_level, 'Service advertised', service=self._service, group=self._group) else: - log.warning('Cannot advertise service, no service info provided', group=self._group) + log.warning('Cannot advertise service, no service provided', group=self._group) else: - log.warning('Cannot advertise service, advertizer not started', service=info) + log.warning('Cannot advertise service, advertizer not started', service=service) class RespondingAdvertizer(DefaultAdvertizer): @@ -72,8 +72,8 @@ def __init__(self, sender: Sender, receiver: Receiver, max_response_delay: float self._receiver = receiver self._max_delay = max_response_delay - def start(self, group: Group, info: ServiceInfo | None = None) -> None: - super().start(group, info) + def start(self, group: Group, service: Service | None = None) -> None: + super().start(group, service) self._receiver.start(group.query()) self._receiver.register(self._handle_message) @@ -83,24 +83,24 @@ def stop(self) -> None: super().stop() def _handle_message(self, message: dict[str, Any]) -> None: - if self._info: + if self._service: try: query = ServiceQuery(**message) matcher = ServiceMatcher(query) log.debug('Service query received', group=self._group, query=query) - self._handle_query(matcher, self._info) + self._handle_query(matcher, self._service) except Exception as error: log.warning('Invalid service query received', group=self._group, received=message, error=error) - def _handle_query(self, matcher: ServiceMatcher, info: ServiceInfo) -> None: - if matcher.matches(info): + def _handle_query(self, matcher: ServiceMatcher, service: Service) -> None: + if matcher.matches(service): delay = round(self._max_delay * random.random(), 3) - log.info('Responding to query', group=self._group, query=matcher.query, service=info, delay=delay) + log.info('Responding to query', group=self._group, query=matcher.query, service=service, delay=delay) time.sleep(delay) - self.advertise(info) + self.advertise(service) -class ScheduledAdvertizer(AbstractScheduler[ServiceInfo], Advertizer): +class ScheduledAdvertizer(AbstractScheduler[Service], Advertizer): def __init__(self, advertizer: Advertizer, timer: IReusableTimer) -> None: super().__init__(timer) @@ -112,15 +112,15 @@ def __enter__(self) -> 'ScheduledAdvertizer': def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None: self.stop() - def start(self, group: Group, info: ServiceInfo | None = None) -> None: - self._advertizer.start(group, info) + def start(self, group: Group, service: Service | None = None) -> None: + self._advertizer.start(group, service) def stop(self) -> None: super().stop() self._advertizer.stop() - def advertise(self, info: ServiceInfo | None = None, log_level: int = INFO) -> None: - self._advertizer.advertise(info, log_level) + def advertise(self, service: Service | None = None, log_level: int = INFO) -> None: + self._advertizer.advertise(service, log_level) - def _execute(self, info: ServiceInfo | None = None) -> None: - self.advertise(info, DEBUG) + def _execute(self, service: Service | None = None) -> None: + self.advertise(service, DEBUG) diff --git a/hello/discoverer.py b/hello/discoverer.py index a463299..d79561f 100644 --- a/hello/discoverer.py +++ b/hello/discoverer.py @@ -12,13 +12,14 @@ from common_utility import IReusableTimer from context_logger import get_logger -from hello import Group, ServiceQuery, Sender, Receiver, ServiceInfo, ServiceMatcher, AbstractScheduler +from hello import Group, ServiceQuery, Sender, Receiver, Service, ServiceMatcher, AbstractScheduler log = get_logger('Discoverer') class DiscoveryEventType(Enum): DISCOVERED = 'discovered' + UNCHANGED = 'unchanged' UPDATED = 'updated' @@ -26,7 +27,7 @@ class DiscoveryEventType(Enum): class DiscoveryEvent: group: Group query: ServiceQuery - service: ServiceInfo + service: Service type: DiscoveryEventType @@ -45,13 +46,13 @@ def stop(self) -> None: def discover(self, query: ServiceQuery | None = None, log_level: int = INFO) -> None: raise NotImplementedError() - def register(self, handler: OnDiscoveryEvent) -> None: + def register(self, handler: OnDiscoveryEvent, types: set[DiscoveryEventType] | None = None) -> None: raise NotImplementedError() - def deregister(self, handler: OnDiscoveryEvent) -> None: + def deregister(self, handler: OnDiscoveryEvent, types: set[DiscoveryEventType] | None = None) -> None: raise NotImplementedError() - def get_services(self) -> dict[UUID, ServiceInfo]: + def get_services(self) -> dict[UUID, Service]: raise NotImplementedError() @@ -62,8 +63,10 @@ def __init__(self, sender: Sender, receiver: Receiver, max_workers: int = 8) -> self._receiver = receiver self._group: Group | None = None self._matcher: ServiceMatcher | None = None - self._services: dict[UUID, ServiceInfo] = {} - self._handlers: list[OnDiscoveryEvent] = [] + self._services: dict[UUID, Service] = {} + self._handlers: dict[DiscoveryEventType, list[OnDiscoveryEvent]] = { + event_type: [] for event_type in DiscoveryEventType + } self._handler_executor = ThreadPoolExecutor(max_workers=max_workers) def __enter__(self) -> Discoverer: @@ -101,48 +104,53 @@ def discover(self, query: ServiceQuery | None = None, log_level: int = INFO) -> else: log.warning('Cannot discover services, discoverer not started', query=query) - def register(self, handler: OnDiscoveryEvent) -> None: - self._handlers.append(handler) + def register(self, handler: OnDiscoveryEvent, types: set[DiscoveryEventType] | None = None) -> None: + for event_type in types if types else self._get_event_types(): + self._handlers[event_type].append(handler) - def deregister(self, handler: OnDiscoveryEvent) -> None: - self._handlers.remove(handler) + def deregister(self, handler: OnDiscoveryEvent, types: set[DiscoveryEventType] | None = None) -> None: + for event_type in types if types else self._get_event_types(): + self._handlers[event_type].remove(handler) - def get_services(self) -> dict[UUID, ServiceInfo]: + def get_services(self) -> dict[UUID, Service]: return self._services.copy() + def _get_event_types(self) -> set[DiscoveryEventType]: + return set(self._handlers.keys()) + def _handle_message(self, message: dict[str, Any]) -> None: if self._group and self._matcher: try: - service = ServiceInfo(UUID(message['uuid']), message['name'], message['role'], message.get('urls', {})) - log.debug('Service info received', service=service, group=self._group) + service = Service(UUID(message['uuid']), message['name'], message['role'], + message.get('urls', {}), message.get('info', {}), message['address']) + log.debug('Service received', service=service, group=self._group) self._handle_service(service, self._group, self._matcher) except Exception as error: - log.warn('Invalid service info received', group=self._group, data=message, error=error) + log.warn('Invalid service received', group=self._group, data=message, error=error) - def _handle_service(self, service: ServiceInfo, group: Group, matcher: ServiceMatcher) -> None: + def _handle_service(self, service: Service, group: Group, matcher: ServiceMatcher) -> None: if matcher.matches(service): stored = self._services.get(service.uuid) + event = self._create_event(group, matcher, stored, service) + self._handle_event(event) - if event := self._create_event(group, matcher, stored, service): - self._handle_event(event) - - def _create_event(self, group: Group, matcher: ServiceMatcher, - stored: ServiceInfo | None, service: ServiceInfo) -> DiscoveryEvent | None: + def _create_event(self, group: Group, matcher: ServiceMatcher, stored: Service | None, + service: Service) -> DiscoveryEvent: if stored: if stored != service: log.info('Service updated', group=group, old_service=stored, new_service=service) return DiscoveryEvent(group, matcher.query, service, DiscoveryEventType.UPDATED) else: log.debug('Service unchanged', group=group, service=service) - return None + return DiscoveryEvent(group, matcher.query, service, DiscoveryEventType.UPDATED) else: - log.info('New service discovered', group=group, service=service) + log.info('Service discovered', group=group, service=service) return DiscoveryEvent(group, matcher.query, service, DiscoveryEventType.DISCOVERED) def _handle_event(self, event: DiscoveryEvent) -> None: self._services[event.service.uuid] = event.service - for handler in self._handlers: + for handler in self._handlers[event.type]: self._handler_executor.submit(self._execute_handler, handler, event) def _execute_handler(self, handler: OnDiscoveryEvent, event: DiscoveryEvent) -> None: @@ -174,14 +182,14 @@ def stop(self) -> None: def discover(self, query: ServiceQuery | None = None, log_level: int = INFO) -> None: self._discoverer.discover(query, log_level) - def get_services(self) -> dict[UUID, ServiceInfo]: + def get_services(self) -> dict[UUID, Service]: return self._discoverer.get_services() - def register(self, handler: OnDiscoveryEvent) -> None: - self._discoverer.register(handler) + def register(self, handler: OnDiscoveryEvent, types: set[DiscoveryEventType] | None = None) -> None: + self._discoverer.register(handler, types) - def deregister(self, handler: OnDiscoveryEvent) -> None: - self._discoverer.deregister(handler) + def deregister(self, handler: OnDiscoveryEvent, types: set[DiscoveryEventType] | None = None) -> None: + self._discoverer.deregister(handler, types) def _execute(self, query: ServiceQuery | None = None) -> None: self.discover(query, DEBUG) diff --git a/hello/service.py b/hello/service.py index 153de98..3bca7be 100644 --- a/hello/service.py +++ b/hello/service.py @@ -9,21 +9,26 @@ @dataclass -class ServiceInfo: +class Service: uuid: UUID name: str role: str urls: dict[str, str] = field(default_factory=dict) + info: dict[str, Any] = field(default_factory=dict) + address: str | None = None def __repr__(self) -> str: - return f"ServiceInfo(uuid='{self.uuid}', name='{self.name}', role='{self.role}', urls='{self.urls}')" + return (f"Service(uuid='{self.uuid}', name='{self.name}', role='{self.role}', " + f"urls={self.urls}, info={self.info}), addr='{self.address}'") def to_dict(self) -> dict[str, Any]: return { 'uuid': str(self.uuid), 'name': self.name, 'role': self.role, - 'urls': self.urls + 'urls': self.urls, + 'info': self.info, + 'address': self.address, } @@ -40,7 +45,7 @@ def __init__(self, query: ServiceQuery) -> None: self._name_matcher = re.compile(self.query.name) self._role_matcher = re.compile(self.query.role) - def matches(self, info: ServiceInfo) -> bool: - name_match = self._name_matcher.match(info.name) - role_match = self._role_matcher.match(info.role) + def matches(self, service: Service) -> bool: + name_match = self._name_matcher.match(service.name) + role_match = self._role_matcher.match(service.role) return bool(name_match and role_match) diff --git a/tests/advertizerIntegrationTest.py b/tests/advertizerIntegrationTest.py index 4a6a3df..e18cf56 100644 --- a/tests/advertizerIntegrationTest.py +++ b/tests/advertizerIntegrationTest.py @@ -7,11 +7,11 @@ from test_utility import wait_for_assertion from zmq import Context -from hello import DefaultAdvertizer, ServiceInfo, Group, RadioSender, DishReceiver, RespondingAdvertizer, \ +from hello import DefaultAdvertizer, Service, Group, RadioSender, DishReceiver, RespondingAdvertizer, \ ServiceQuery, ScheduledAdvertizer GROUP = Group('test-group', 'udp://239.0.0.1:5555') -SERVICE_INFO = ServiceInfo(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:8080'}) +SERVICE = Service(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:8080'}) class AdvertizerIntegrationTest(TestCase): @@ -35,12 +35,12 @@ def test_sends_hello_when_advertises_service(self): advertizer.start(GROUP) # When - advertizer.advertise(SERVICE_INFO) + advertizer.advertise(SERVICE) wait_for_assertion(1, lambda: self.assertEqual(1, len(messages))) # Then - self.assertEqual([SERVICE_INFO.to_dict()], messages) + self.assertEqual([SERVICE.to_dict()], messages) def test_sends_hello_when_query_received(self): # Given @@ -56,7 +56,7 @@ def test_sends_hello_when_query_received(self): test_receiver.start(GROUP.hello()) test_receiver.register(lambda message: messages.append(message)) - advertizer.start(GROUP, SERVICE_INFO) + advertizer.start(GROUP, SERVICE) # When test_sender.send(ServiceQuery('test-service', 'test-role')) @@ -64,9 +64,9 @@ def test_sends_hello_when_query_received(self): wait_for_assertion(1, lambda: self.assertEqual(1, len(messages))) # Then - self.assertEqual([SERVICE_INFO.to_dict()], messages) + self.assertEqual([SERVICE.to_dict()], messages) - def test_sends_hello_when_info_changed_and_query_received(self): + def test_sends_hello_when_service_changed_and_query_received(self): # Given context = Context() sender = RadioSender(context) @@ -81,17 +81,17 @@ def test_sends_hello_when_info_changed_and_query_received(self): test_receiver.register(lambda message: messages.append(message)) advertizer.start(GROUP) - advertizer.advertise(SERVICE_INFO) + advertizer.advertise(SERVICE) query = ServiceQuery('test-service', 'test-role') test_sender.send(query) wait_for_assertion(1, lambda: self.assertEqual(2, len(messages))) - new_service_info = ServiceInfo( - SERVICE_INFO.uuid, SERVICE_INFO.name, SERVICE_INFO.role, {'test': 'http://localhost:9090'} + new_service = Service( + SERVICE.uuid, SERVICE.name, SERVICE.role, {'test': 'http://localhost:9090'} ) - advertizer.advertise(new_service_info) + advertizer.advertise(new_service) # When test_sender.send(query) @@ -100,7 +100,7 @@ def test_sends_hello_when_info_changed_and_query_received(self): # Then self.assertEqual([ - SERVICE_INFO.to_dict(), SERVICE_INFO.to_dict(), new_service_info.to_dict(), new_service_info.to_dict() + SERVICE.to_dict(), SERVICE.to_dict(), new_service.to_dict(), new_service.to_dict() ], messages) def test_sends_hello_when_schedules_advertisement_once(self): @@ -117,12 +117,12 @@ def test_sends_hello_when_schedules_advertisement_once(self): scheduled_advertizer.start(GROUP) # When - scheduled_advertizer.schedule_one_shot(SERVICE_INFO, interval=0.01) + scheduled_advertizer.schedule_one_shot(SERVICE, interval=0.01) wait_for_assertion(1, lambda: self.assertEqual(1, len(messages))) # Then - self.assertEqual([SERVICE_INFO.to_dict()], messages) + self.assertEqual([SERVICE.to_dict()], messages) def test_sends_hello_when_schedules_advertisement_periodically(self): # Given @@ -138,7 +138,7 @@ def test_sends_hello_when_schedules_advertisement_periodically(self): scheduled_advertizer.start(GROUP) # When - scheduled_advertizer.schedule_periodic(SERVICE_INFO, interval=0.01) + scheduled_advertizer.schedule_periodic(SERVICE, interval=0.01) # Then wait_for_assertion(1, lambda: self.assertTrue(len(messages) >= 10)) diff --git a/tests/apiIntegrationTest.py b/tests/apiIntegrationTest.py index ff884af..7a4c92a 100644 --- a/tests/apiIntegrationTest.py +++ b/tests/apiIntegrationTest.py @@ -6,10 +6,17 @@ from context_logger import setup_logging from test_utility import wait_for_assertion -from hello import ServiceInfo, Group, ServiceQuery, Hello, HelloConfig +from hello import Service, Group, ServiceQuery, Hello, HelloConfig GROUP = Group('test-group', 'udp://239.0.0.1:5555') -SERVICE_INFO = ServiceInfo(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:8080'}) +SERVICE = Service( + uuid4(), + 'test-service', + 'test-role', + {'test': 'http://localhost:8080'}, + {'site': 'test-site', 'range': 'test-range'}, + '192.168.1.100' +) SERVICE_QUERY = ServiceQuery('test-service', 'test-role') @@ -28,7 +35,7 @@ def test_discoverer_caches_advertised_service(self): with (Hello.builder(config).advertizer().default() as advertizer, Hello.builder(config).discoverer().default() as discoverer): - advertizer.start(GROUP, SERVICE_INFO) + advertizer.start(GROUP, SERVICE) discoverer.start(GROUP, SERVICE_QUERY) # When @@ -37,7 +44,7 @@ def test_discoverer_caches_advertised_service(self): wait_for_assertion(1, lambda: self.assertEqual(1, len(discoverer.get_services()))) # Then - self.assertEqual({SERVICE_INFO.uuid: SERVICE_INFO}, discoverer.get_services()) + self.assertEqual({SERVICE.uuid: SERVICE}, discoverer.get_services()) def test_discoverer_caches_advertised_services(self): # Given @@ -46,10 +53,24 @@ def test_discoverer_caches_advertised_services(self): with (Hello.builder(config).advertizer().default() as advertizer1, Hello.builder(config).advertizer().default() as advertizer2, Hello.builder(config).discoverer().default() as discoverer): - service_info1 = ServiceInfo(uuid4(), 'test-service1', 'test-role', {'test': 'http://localhost:8080'}) - service_info2 = ServiceInfo(uuid4(), 'test-service2', 'test-role', {'test': 'http://localhost:8080'}) - advertizer1.start(GROUP, service_info1) - advertizer2.start(GROUP, service_info2) + service1 = Service( + uuid4(), + 'test-service1', + 'test-role', + {'test': 'http://localhost:8080'}, + {'site': 'site1', 'range': 'range1'}, + '192.168.1.101' + ) + service2 = Service( + uuid4(), + 'test-service2', + 'test-role', + {'test': 'http://localhost:8080'}, + {'site': 'site2', 'range': 'range2'}, + '192.168.1.102' + ) + advertizer1.start(GROUP, service1) + advertizer2.start(GROUP, service2) discoverer.start(GROUP, ServiceQuery('test-service.+', 'test-role')) # When @@ -61,8 +82,8 @@ def test_discoverer_caches_advertised_services(self): # Then self.assertEqual({ - service_info1.uuid: service_info1, - service_info2.uuid: service_info2 + service1.uuid: service1, + service2.uuid: service2 }, discoverer.get_services()) def test_discoverer_caches_advertised_service_when_advertisement_scheduled_once(self): @@ -71,7 +92,7 @@ def test_discoverer_caches_advertised_service_when_advertisement_scheduled_once( with (Hello.builder(config).advertizer().scheduled() as advertizer, Hello.builder(config).discoverer().default() as discoverer): - advertizer.start(GROUP, SERVICE_INFO) + advertizer.start(GROUP, SERVICE) discoverer.start(GROUP, SERVICE_QUERY) # When @@ -80,7 +101,7 @@ def test_discoverer_caches_advertised_service_when_advertisement_scheduled_once( wait_for_assertion(1, lambda: self.assertEqual(1, len(discoverer.get_services()))) # Then - self.assertEqual({SERVICE_INFO.uuid: SERVICE_INFO}, discoverer.get_services()) + self.assertEqual({SERVICE.uuid: SERVICE}, discoverer.get_services()) def test_discoverer_caches_advertised_service_when_advertisement_scheduled_periodically(self): # Given @@ -88,7 +109,7 @@ def test_discoverer_caches_advertised_service_when_advertisement_scheduled_perio with (Hello.builder(config).advertizer().scheduled() as advertizer, Hello.builder(config).discoverer().default() as discoverer): - advertizer.start(GROUP, SERVICE_INFO) + advertizer.start(GROUP, SERVICE) discoverer.start(GROUP, SERVICE_QUERY) # When @@ -97,7 +118,7 @@ def test_discoverer_caches_advertised_service_when_advertisement_scheduled_perio wait_for_assertion(1, lambda: self.assertEqual(1, len(discoverer.get_services()))) # Then - self.assertEqual({SERVICE_INFO.uuid: SERVICE_INFO}, discoverer.get_services()) + self.assertEqual({SERVICE.uuid: SERVICE}, discoverer.get_services()) def test_discoverer_caches_discovery_response_service(self): # Given @@ -105,7 +126,7 @@ def test_discoverer_caches_discovery_response_service(self): with (Hello.builder(config).advertizer().default() as advertizer, Hello.builder(config).discoverer().default() as discoverer): - advertizer.start(GROUP, SERVICE_INFO) + advertizer.start(GROUP, SERVICE) discoverer.start(GROUP, SERVICE_QUERY) # When @@ -114,7 +135,7 @@ def test_discoverer_caches_discovery_response_service(self): wait_for_assertion(1, lambda: self.assertEqual(1, len(discoverer.get_services()))) # Then - self.assertEqual({SERVICE_INFO.uuid: SERVICE_INFO}, discoverer.get_services()) + self.assertEqual({SERVICE.uuid: SERVICE}, discoverer.get_services()) def test_discoverer_caches_discovery_response_services(self): # Given @@ -123,10 +144,24 @@ def test_discoverer_caches_discovery_response_services(self): with (Hello.builder(config).advertizer().default() as advertizer1, Hello.builder(config).advertizer().default() as advertizer2, Hello.builder(config).discoverer().default() as discoverer): - service_info1 = ServiceInfo(uuid4(), 'test-service1', 'test-role', {'test': 'http://localhost:8080'}) - service_info2 = ServiceInfo(uuid4(), 'test-service2', 'test-role', {'test': 'http://localhost:8080'}) - advertizer1.start(GROUP, service_info1) - advertizer2.start(GROUP, service_info2) + service1 = Service( + uuid4(), + 'test-service1', + 'test-role', + {'test': 'http://localhost:8080'}, + {'site': 'site1', 'range': 'range1'}, + '192.168.1.101' + ) + service2 = Service( + uuid4(), + 'test-service2', + 'test-role', + {'test': 'http://localhost:8080'}, + {'site': 'site2', 'range': 'range2'}, + '192.168.1.102' + ) + advertizer1.start(GROUP, service1) + advertizer2.start(GROUP, service2) discoverer.start(GROUP, ServiceQuery('test-service.+', 'test-role')) # When @@ -136,8 +171,8 @@ def test_discoverer_caches_discovery_response_services(self): # Then self.assertEqual({ - service_info1.uuid: service_info1, - service_info2.uuid: service_info2 + service1.uuid: service1, + service2.uuid: service2 }, discoverer.get_services()) def test_discoverer_caches_discovery_response_service_when_discovery_scheduled_once(self): @@ -146,7 +181,7 @@ def test_discoverer_caches_discovery_response_service_when_discovery_scheduled_o with (Hello.builder(config).advertizer().default() as advertizer, Hello.builder(config).discoverer().scheduled() as discoverer): - advertizer.start(GROUP, SERVICE_INFO) + advertizer.start(GROUP, SERVICE) discoverer.start(GROUP, SERVICE_QUERY) # When @@ -155,7 +190,7 @@ def test_discoverer_caches_discovery_response_service_when_discovery_scheduled_o wait_for_assertion(1, lambda: self.assertEqual(1, len(discoverer.get_services()))) # Then - self.assertEqual({SERVICE_INFO.uuid: SERVICE_INFO}, discoverer.get_services()) + self.assertEqual({SERVICE.uuid: SERVICE}, discoverer.get_services()) def test_discoverer_caches_discovery_response_service_when_discovery_scheduled_periodically(self): # Given @@ -163,7 +198,7 @@ def test_discoverer_caches_discovery_response_service_when_discovery_scheduled_p with (Hello.builder(config).advertizer().default() as advertizer, Hello.builder(config).discoverer().scheduled() as discoverer): - advertizer.start(GROUP, SERVICE_INFO) + advertizer.start(GROUP, SERVICE) discoverer.start(GROUP, SERVICE_QUERY) # When @@ -172,7 +207,7 @@ def test_discoverer_caches_discovery_response_service_when_discovery_scheduled_p wait_for_assertion(1, lambda: self.assertEqual(1, len(discoverer.get_services()))) # Then - self.assertEqual({SERVICE_INFO.uuid: SERVICE_INFO}, discoverer.get_services()) + self.assertEqual({SERVICE.uuid: SERVICE}, discoverer.get_services()) if __name__ == '__main__': diff --git a/tests/defaultAdvertizerTest.py b/tests/defaultAdvertizerTest.py index 4429705..3f8e583 100644 --- a/tests/defaultAdvertizerTest.py +++ b/tests/defaultAdvertizerTest.py @@ -5,10 +5,10 @@ from context_logger import setup_logging -from hello import ServiceInfo, Group, Sender, DefaultAdvertizer +from hello import Service, Group, Sender, DefaultAdvertizer GROUP = Group('test-group', 'udp://239.0.0.1:5555') -SERVICE_INFO = ServiceInfo(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:8080'}) +SERVICE = Service(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:8080'}) class DefaultAdvertizerTest(TestCase): @@ -55,43 +55,43 @@ def test_starts_sender_when_started(self): # Then sender.start.assert_called_once_with(GROUP.hello()) - def test_sends_info_when_passed_at_start(self): + def test_sends_service_when_passed_at_start(self): # Given sender = MagicMock(spec=Sender) advertizer = DefaultAdvertizer(sender) - advertizer.start(GROUP, SERVICE_INFO) + advertizer.start(GROUP, SERVICE) # When advertizer.advertise() # Then - sender.send.assert_called_once_with(SERVICE_INFO) + sender.send.assert_called_once_with(SERVICE) - def test_sends_info_when_passed_at_advertise(self): + def test_sends_service_when_passed_at_advertise(self): # Given sender = MagicMock(spec=Sender) advertizer = DefaultAdvertizer(sender) advertizer.start(GROUP) # When - advertizer.advertise(SERVICE_INFO) + advertizer.advertise(SERVICE) # Then - sender.send.assert_called_once_with(SERVICE_INFO) + sender.send.assert_called_once_with(SERVICE) - def test_sends_last_info_when_passed_at_start_and_at_advertise(self): + def test_sends_last_service_when_passed_at_start_and_at_advertise(self): # Given sender = MagicMock(spec=Sender) advertizer = DefaultAdvertizer(sender) - advertizer.start(GROUP, ServiceInfo(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:9090'})) + advertizer.start(GROUP, Service(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:9090'})) # When - advertizer.advertise(SERVICE_INFO) + advertizer.advertise(SERVICE) # Then - sender.send.assert_called_once_with(SERVICE_INFO) + sender.send.assert_called_once_with(SERVICE) - def test_does_not_send_info_when_no_info_provided(self): + def test_does_not_send_service_when_no_service_provided(self): # Given sender = MagicMock(spec=Sender) advertizer = DefaultAdvertizer(sender) @@ -103,13 +103,13 @@ def test_does_not_send_info_when_no_info_provided(self): # Then sender.send.assert_not_called() - def test_does_not_send_info_when_not_started(self): + def test_does_not_send_service_when_not_started(self): # Given sender = MagicMock(spec=Sender) advertizer = DefaultAdvertizer(sender) # When - advertizer.advertise(SERVICE_INFO) + advertizer.advertise(SERVICE) # Then sender.send.assert_not_called() diff --git a/tests/defaultDiscovererTest.py b/tests/defaultDiscovererTest.py index 4a21c34..34e1a66 100644 --- a/tests/defaultDiscovererTest.py +++ b/tests/defaultDiscovererTest.py @@ -6,12 +6,20 @@ from context_logger import setup_logging from test_utility import wait_for_assertion -from hello import ServiceInfo, Group, ServiceQuery, DefaultDiscoverer, Sender, Receiver, OnDiscoveryEvent, \ +from hello import Service, Group, ServiceQuery, DefaultDiscoverer, Sender, Receiver, OnDiscoveryEvent, \ DiscoveryEventType, DiscoveryEvent + GROUP = Group('test-group', 'udp://239.0.0.1:5555') SERVICE_QUERY = ServiceQuery('test-.*', 'test-.*') -SERVICE_INFO = ServiceInfo(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:8080'}) +SERVICE = Service( + uuid4(), + 'test-service', + 'test-role', + {'test': 'http://localhost:8080'}, + {'site': 'test-site', 'range': 'test-range'}, + '192.168.1.100' +) class DefaultDiscovererTest(TestCase): @@ -64,7 +72,7 @@ def test_starts_sender_and_receiver_when_started(self): sender.start.assert_called_once_with(GROUP.query()) receiver.start.assert_called_once_with(GROUP.hello()) - def test_registers_event_handler(self): + def test_registers_event_handler_for_all_event_types(self): # Given sender = MagicMock(spec=Sender) receiver = MagicMock(spec=Receiver) @@ -75,9 +83,26 @@ def test_registers_event_handler(self): discoverer.register(handler) # Then - self.assertIn(handler, discoverer._handlers) + self.assertIn(handler, discoverer._handlers[DiscoveryEventType.DISCOVERED]) + self.assertIn(handler, discoverer._handlers[DiscoveryEventType.UPDATED]) + self.assertIn(handler, discoverer._handlers[DiscoveryEventType.UNCHANGED]) + + def test_registers_event_handler_for_single_event_type(self): + # Given + sender = MagicMock(spec=Sender) + receiver = MagicMock(spec=Receiver) + discoverer = DefaultDiscoverer(sender, receiver) + handler = MagicMock(spec=OnDiscoveryEvent) + + # When + discoverer.register(handler, {DiscoveryEventType.DISCOVERED}) + + # Then + self.assertIn(handler, discoverer._handlers[DiscoveryEventType.DISCOVERED]) + self.assertNotIn(handler, discoverer._handlers[DiscoveryEventType.UPDATED]) + self.assertNotIn(handler, discoverer._handlers[DiscoveryEventType.UNCHANGED]) - def test_deregisters_event_handler(self): + def test_deregisters_event_handler_for_all_event_types(self): # Given sender = MagicMock(spec=Sender) receiver = MagicMock(spec=Receiver) @@ -91,25 +116,41 @@ def test_deregisters_event_handler(self): # Then self.assertNotIn(handler, discoverer._handlers) - def test_caches_service_and_calls_handler_when_receives_matching_info(self): + def test_deregisters_event_handler_for_single_event_type(self): # Given sender = MagicMock(spec=Sender) receiver = MagicMock(spec=Receiver) discoverer = DefaultDiscoverer(sender, receiver) - discoverer.start(GROUP, SERVICE_QUERY) handler = MagicMock(spec=OnDiscoveryEvent) discoverer.register(handler) # When - discoverer._handle_message(SERVICE_INFO.to_dict()) + discoverer.deregister(handler, {DiscoveryEventType.UNCHANGED}) # Then - self.assertEqual({SERVICE_INFO.uuid: SERVICE_INFO}, discoverer.get_services()) + self.assertIn(handler, discoverer._handlers[DiscoveryEventType.DISCOVERED]) + self.assertIn(handler, discoverer._handlers[DiscoveryEventType.UPDATED]) + self.assertNotIn(handler, discoverer._handlers[DiscoveryEventType.UNCHANGED]) + + def test_caches_service_and_calls_handler_when_receives_matching_service(self): + # Given + sender = MagicMock(spec=Sender) + receiver = MagicMock(spec=Receiver) + discoverer = DefaultDiscoverer(sender, receiver) + discoverer.start(GROUP, SERVICE_QUERY) + handler = MagicMock(spec=OnDiscoveryEvent) + discoverer.register(handler, {DiscoveryEventType.DISCOVERED}) + + # When + discoverer._handle_message(SERVICE.to_dict()) + + # Then + self.assertEqual({SERVICE.uuid: SERVICE}, discoverer.get_services()) wait_for_assertion(1, lambda: handler.assert_called_once_with( - DiscoveryEvent(GROUP, SERVICE_QUERY, SERVICE_INFO, DiscoveryEventType.DISCOVERED) + DiscoveryEvent(GROUP, SERVICE_QUERY, SERVICE, DiscoveryEventType.DISCOVERED) )) - def test_updates_service_and_calls_handler_when_receives_matching_info(self): + def test_updates_service_and_calls_handler_when_receives_matching_service(self): # Given sender = MagicMock(spec=Sender) receiver = MagicMock(spec=Receiver) @@ -117,22 +158,27 @@ def test_updates_service_and_calls_handler_when_receives_matching_info(self): discoverer.start(GROUP, SERVICE_QUERY) handler = MagicMock(spec=OnDiscoveryEvent) discoverer.register(handler) - discoverer._handle_message(SERVICE_INFO.to_dict()) + discoverer._handle_message(SERVICE.to_dict()) handler.reset_mock() - new_service_info = ServiceInfo( - SERVICE_INFO.uuid, SERVICE_INFO.name, SERVICE_INFO.role, {'test': 'http://localhost:9090'} + new_service = Service( + SERVICE.uuid, + SERVICE.name, + SERVICE.role, + {'test': 'http://localhost:9090'}, + {'site': 'test-site', 'range': 'test-range', 'updated': True}, + '192.168.1.101' ) # When - discoverer._handle_message(new_service_info.to_dict()) + discoverer._handle_message(new_service.to_dict()) # Then - self.assertEqual({SERVICE_INFO.uuid: new_service_info}, discoverer.get_services()) + self.assertEqual({SERVICE.uuid: new_service}, discoverer.get_services()) wait_for_assertion(1, lambda: handler.assert_called_once_with( - DiscoveryEvent(GROUP, SERVICE_QUERY, new_service_info, DiscoveryEventType.UPDATED) + DiscoveryEvent(GROUP, SERVICE_QUERY, new_service, DiscoveryEventType.UPDATED) )) - def test_does_not_call_handler_when_service_info_not_changed(self): + def test_does_not_call_handler_when_service_not_changed(self): # Given sender = MagicMock(spec=Sender) receiver = MagicMock(spec=Receiver) @@ -140,11 +186,11 @@ def test_does_not_call_handler_when_service_info_not_changed(self): discoverer.start(GROUP, SERVICE_QUERY) handler = MagicMock(spec=OnDiscoveryEvent) discoverer.register(handler) - discoverer._handle_message(SERVICE_INFO.to_dict()) + discoverer._handle_message(SERVICE.to_dict()) handler.reset_mock() # When - discoverer._handle_message(SERVICE_INFO.to_dict()) + discoverer._handle_message(SERVICE.to_dict()) # Then handler.assert_not_called() @@ -160,12 +206,12 @@ def test_handles_handler_error_gracefully(self): discoverer.register(handler) # When - discoverer._handle_message(SERVICE_INFO.to_dict()) + discoverer._handle_message(SERVICE.to_dict()) # Then - self.assertEqual({SERVICE_INFO.uuid: SERVICE_INFO}, discoverer.get_services()) + self.assertEqual({SERVICE.uuid: SERVICE}, discoverer.get_services()) wait_for_assertion(1, lambda: handler.assert_called_once_with( - DiscoveryEvent(GROUP, SERVICE_QUERY, SERVICE_INFO, DiscoveryEventType.DISCOVERED) + DiscoveryEvent(GROUP, SERVICE_QUERY, SERVICE, DiscoveryEventType.DISCOVERED) )) def test_handles_invalid_message_gracefully(self): @@ -188,7 +234,14 @@ def test_does_not_cache_service_when_info_not_matching_query(self): discoverer = DefaultDiscoverer(sender, receiver) discoverer.start(GROUP, SERVICE_QUERY) - non_matching_info = ServiceInfo(uuid4(), 'other-service', 'test-role', {'test': 'http://localhost:8080'}) + non_matching_info = Service( + uuid4(), + 'other-service', + 'test-role', + {'test': 'http://localhost:8080'}, + {'site': 'other-site'}, + '192.168.1.102' + ) # When discoverer._handle_message(non_matching_info.to_dict()) @@ -204,7 +257,7 @@ def test_does_not_cache_service_when_no_query_set(self): discoverer.start(GROUP) # When - discoverer._handle_message(SERVICE_INFO.to_dict()) + discoverer._handle_message(SERVICE.to_dict()) # Then self.assertEqual({}, discoverer.get_services()) diff --git a/tests/discovererIntegrationTest.py b/tests/discovererIntegrationTest.py index 3e3d469..e0481b5 100644 --- a/tests/discovererIntegrationTest.py +++ b/tests/discovererIntegrationTest.py @@ -7,11 +7,11 @@ from test_utility import wait_for_assertion from zmq import Context -from hello import ServiceInfo, Group, RadioSender, DishReceiver, ServiceQuery, DefaultDiscoverer, ScheduledDiscoverer +from hello import Service, Group, RadioSender, DishReceiver, ServiceQuery, DefaultDiscoverer, ScheduledDiscoverer GROUP = Group('test-group', 'udp://239.0.0.1:5555') SERVICE_QUERY = ServiceQuery('test-service', 'test-role') -SERVICE_INFO = ServiceInfo(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:8080'}) +SERVICE = Service(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:8080'}) class DiscovererIntegrationTest(TestCase): @@ -34,14 +34,14 @@ def test_discovers_service_when_hello_received(self): discoverer.start(GROUP, SERVICE_QUERY) # When - test_sender.send(SERVICE_INFO) + test_sender.send(SERVICE) wait_for_assertion(1, lambda: self.assertEqual(1, len(discoverer.get_services()))) # Then - self.assertEqual({SERVICE_INFO.uuid: SERVICE_INFO}, discoverer.get_services()) + self.assertEqual({SERVICE.uuid: SERVICE}, discoverer.get_services()) - def test_updates_service_when_info_changed(self): + def test_updates_service_when_service_changed(self): # Given context = Context() sender = RadioSender(context) @@ -51,25 +51,25 @@ def test_updates_service_when_info_changed(self): test_sender.start(GROUP.hello()) discoverer.start(GROUP, SERVICE_QUERY) - test_sender.send(SERVICE_INFO) + test_sender.send(SERVICE) wait_for_assertion(1, lambda: self.assertEqual(1, len(discoverer.get_services()))) # When - new_service_info = ServiceInfo( - SERVICE_INFO.uuid, SERVICE_INFO.name, SERVICE_INFO.role, {'test': 'http://localhost:9090'} + new_service = Service( + SERVICE.uuid, SERVICE.name, SERVICE.role, {'test': 'http://localhost:9090'} ) - test_sender.send(new_service_info) + test_sender.send(new_service) wait_for_assertion(1, lambda: self.assertEqual( 'http://localhost:9090', - discoverer.get_services()[SERVICE_INFO.uuid].urls['test'] + discoverer.get_services()[SERVICE.uuid].urls['test'] )) # Then self.assertEqual( 'http://localhost:9090', - discoverer.get_services()[SERVICE_INFO.uuid].urls['test'] + discoverer.get_services()[SERVICE.uuid].urls['test'] ) def test_sends_query(self): diff --git a/tests/dishReceiverTest.py b/tests/dishReceiverTest.py index 24579bd..7f7372e 100644 --- a/tests/dishReceiverTest.py +++ b/tests/dishReceiverTest.py @@ -8,10 +8,10 @@ from test_utility import wait_for_assertion from zmq import Context, ZMQError, Poller, POLLIN -from hello import ServiceInfo, Group, DishReceiver, OnMessage +from hello import Service, Group, DishReceiver, OnMessage GROUP = Group('test-group', 'udp://239.0.0.1:5555') -SERVICE_INFO = ServiceInfo(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:8080'}) +SERVICE = Service(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:8080'}) class DishReceiverTest(TestCase): @@ -114,7 +114,7 @@ def test_calls_registered_handler_on_message(self): # Given group = GROUP.hello() context = MagicMock(spec=Context) - context.socket.return_value.recv_json.return_value = SERVICE_INFO.to_dict() + context.socket.return_value.recv_json.return_value = SERVICE.to_dict() handler = MagicMock(spec=OnMessage) with DishReceiver(context) as receiver: @@ -126,7 +126,7 @@ def test_calls_registered_handler_on_message(self): receiver.start(group) # Then - wait_for_assertion(1, lambda: handler.assert_called_once_with(SERVICE_INFO.to_dict())) + wait_for_assertion(1, lambda: handler.assert_called_once_with(SERVICE.to_dict())) def test_handles_message_receive_error_gracefully(self): # Given @@ -150,7 +150,7 @@ def test_handles_handler_execution_error_gracefully(self): # Given group = GROUP.hello() context = MagicMock(spec=Context) - context.socket.return_value.recv_json.return_value = SERVICE_INFO.to_dict() + context.socket.return_value.recv_json.return_value = SERVICE.to_dict() handler = MagicMock(spec=OnMessage) handler.side_effect = Exception("Execution failed") @@ -163,7 +163,7 @@ def test_handles_handler_execution_error_gracefully(self): receiver.start(group) # Then - wait_for_assertion(1, lambda: handler.assert_called_once_with(SERVICE_INFO.to_dict())) + wait_for_assertion(1, lambda: handler.assert_called_once_with(SERVICE.to_dict())) if __name__ == '__main__': diff --git a/tests/radioSenderTest.py b/tests/radioSenderTest.py index af4afa2..8479fb5 100644 --- a/tests/radioSenderTest.py +++ b/tests/radioSenderTest.py @@ -7,11 +7,11 @@ from context_logger import setup_logging from zmq import Context, ZMQError -from hello import ServiceInfo, Group, ServiceQuery +from hello import Service, Group, ServiceQuery from hello.sender import RadioSender GROUP = Group('test-group', 'udp://239.0.0.1:5555') -SERVICE_INFO = ServiceInfo(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:8080'}) +SERVICE = Service(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:8080'}) SERVICE_QUERY = ServiceQuery('test-service', 'test-role') @@ -105,10 +105,10 @@ def test_sends_message_when_convertible_to_dict_with_to_dict(self): sender.start(group) # When - sender.send(SERVICE_INFO) + sender.send(SERVICE) # Then - context.socket.return_value.send_json.assert_called_with(SERVICE_INFO.to_dict(), group='hello:test-group') + context.socket.return_value.send_json.assert_called_with(SERVICE.to_dict(), group='hello:test-group') def test_sends_message_when_convertible_to_dict_with_as_dict(self): # Given @@ -120,7 +120,7 @@ def test_sends_message_when_convertible_to_dict_with_as_dict(self): class TestData: def as_dict(self) -> dict[str, Any]: - return SERVICE_INFO.to_dict() + return SERVICE.to_dict() data = TestData() @@ -138,10 +138,10 @@ def test_sends_message_when_type_is_dict(self): sender.start(group) # When - sender.send(SERVICE_INFO.to_dict()) + sender.send(SERVICE.to_dict()) # Then - context.socket.return_value.send_json.assert_called_with(SERVICE_INFO.to_dict(), group='hello:test-group') + context.socket.return_value.send_json.assert_called_with(SERVICE.to_dict(), group='hello:test-group') def test_does_not_send_message_when_not_serializable(self): # Given @@ -162,7 +162,7 @@ def test_does_not_send_message_when_not_started(self): sender = RadioSender(context) # When - sender.send(SERVICE_INFO) + sender.send(SERVICE) # Then context.socket.return_value.send_json.assert_not_called() @@ -176,10 +176,10 @@ def test_handles_send_message_error_gracefully(self): context.socket.return_value.send_json.side_effect = ZMQError(1, "Send failed") # When - sender.send(SERVICE_INFO) + sender.send(SERVICE) # Then - context.socket.return_value.send_json.assert_called_once_with(SERVICE_INFO.to_dict(), group='hello:test-group') + context.socket.return_value.send_json.assert_called_once_with(SERVICE.to_dict(), group='hello:test-group') if __name__ == '__main__': diff --git a/tests/receiverIntegrationTest.py b/tests/receiverIntegrationTest.py index 3d014fc..82eeeb4 100644 --- a/tests/receiverIntegrationTest.py +++ b/tests/receiverIntegrationTest.py @@ -6,10 +6,10 @@ from test_utility import wait_for_assertion from zmq import Context, RADIO -from hello import ServiceInfo, Group, DishReceiver +from hello import Service, Group, DishReceiver GROUP = Group('test-group', 'udp://239.0.0.1:5555') -SERVICE_INFO = ServiceInfo(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:8080'}) +SERVICE = Service(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:8080'}) class ReceiverIntegrationTest(TestCase): @@ -33,12 +33,12 @@ def test_receives_message(self): receiver.start(group) # When - radio.send_json(SERVICE_INFO.to_dict(), group=group.name) + radio.send_json(SERVICE.to_dict(), group=group.name) wait_for_assertion(1, lambda: self.assertEqual(1, len(messages))) # Then - self.assertEqual([SERVICE_INFO.to_dict()], messages) + self.assertEqual([SERVICE.to_dict()], messages) if __name__ == '__main__': diff --git a/tests/respondingAdvertizerTest.py b/tests/respondingAdvertizerTest.py index 518db3e..95b50ad 100644 --- a/tests/respondingAdvertizerTest.py +++ b/tests/respondingAdvertizerTest.py @@ -5,10 +5,10 @@ from context_logger import setup_logging -from hello import ServiceInfo, Group, Sender, Receiver, RespondingAdvertizer, ServiceQuery +from hello import Service, Group, Sender, Receiver, RespondingAdvertizer, ServiceQuery GROUP = Group('test-group', 'udp://239.0.0.1:5555') -SERVICE_INFO = ServiceInfo(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:8080'}) +SERVICE = Service(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:8080'}) class RespondingAdvertizerTest(TestCase): @@ -61,25 +61,25 @@ def test_starts_sender_and_receiver_when_started(self): sender.start.assert_called_once_with(GROUP.hello()) receiver.start.assert_called_once_with(GROUP.query()) - def test_sends_service_info_when_receives_matching_query(self): + def test_sends_service_when_receives_matching_query(self): # Given sender = MagicMock(spec=Sender) receiver = MagicMock(spec=Receiver) advertizer = RespondingAdvertizer(sender, receiver) - advertizer.start(GROUP, SERVICE_INFO) + advertizer.start(GROUP, SERVICE) # When advertizer._handle_message(ServiceQuery('test-.*', 'test-.*').__dict__) # Then - sender.send.assert_called_once_with(SERVICE_INFO) + sender.send.assert_called_once_with(SERVICE) - def test_does_not_send_service_info_when_receives_non_matching_query(self): + def test_does_not_send_service_when_receives_non_matching_query(self): # Given sender = MagicMock(spec=Sender) receiver = MagicMock(spec=Receiver) advertizer = RespondingAdvertizer(sender, receiver) - advertizer.start(GROUP, SERVICE_INFO) + advertizer.start(GROUP, SERVICE) # When advertizer._handle_message(ServiceQuery('other-.*', 'test-.*').__dict__) @@ -87,7 +87,7 @@ def test_does_not_send_service_info_when_receives_non_matching_query(self): # Then sender.send.assert_not_called() - def test_does_not_send_service_info_when_no_service_info_set(self): + def test_does_not_send_service_when_no_service_set(self): # Given sender = MagicMock(spec=Sender) receiver = MagicMock(spec=Receiver) @@ -105,7 +105,7 @@ def test_handles_invalid_message_gracefully(self): sender = MagicMock(spec=Sender) receiver = MagicMock(spec=Receiver) advertizer = RespondingAdvertizer(sender, receiver) - advertizer.start(GROUP, SERVICE_INFO) + advertizer.start(GROUP, SERVICE) # When advertizer._handle_message({'invalid': 'message'}) diff --git a/tests/scheduledAdvertizerTest.py b/tests/scheduledAdvertizerTest.py index 4083967..0e0db8e 100644 --- a/tests/scheduledAdvertizerTest.py +++ b/tests/scheduledAdvertizerTest.py @@ -7,10 +7,17 @@ from common_utility import IReusableTimer from context_logger import setup_logging -from hello import ServiceInfo, Group, ScheduledAdvertizer, Advertizer +from hello import Service, Group, ScheduledAdvertizer, Advertizer GROUP = Group('test-group', 'udp://239.0.0.1:5555') -SERVICE_INFO = ServiceInfo(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:8080'}) +SERVICE = Service( + uuid4(), + 'test-service', + 'test-role', + {'test': 'http://localhost:8080'}, + {'site': 'test-site', 'range': 'test-range'}, + '192.168.1.100' +) class ScheduledAdvertizerTest(TestCase): @@ -57,22 +64,22 @@ def test_starts_advertizer_when_started(self): scheduled_advertizer = ScheduledAdvertizer(advertizer, timer) # When - scheduled_advertizer.start(GROUP, SERVICE_INFO) + scheduled_advertizer.start(GROUP, SERVICE) # Then - advertizer.start.assert_called_once_with(GROUP, SERVICE_INFO) + advertizer.start.assert_called_once_with(GROUP, SERVICE) - def test_sends_service_info(self): + def test_sends_service(self): # Given advertizer = MagicMock(spec=Advertizer) timer = MagicMock(spec=IReusableTimer) scheduled_advertizer = ScheduledAdvertizer(advertizer, timer) # When - scheduled_advertizer.advertise(SERVICE_INFO) + scheduled_advertizer.advertise(SERVICE) # Then - advertizer.advertise.assert_called_once_with(SERVICE_INFO, INFO) + advertizer.advertise.assert_called_once_with(SERVICE, INFO) def test_schedules_advertise_once(self): # Given @@ -82,10 +89,10 @@ def test_schedules_advertise_once(self): scheduled_advertizer.start(GROUP) # When - scheduled_advertizer.schedule_one_shot(SERVICE_INFO, 60) + scheduled_advertizer.schedule_one_shot(SERVICE, 60) # Then - timer.start.assert_called_once_with(60, scheduled_advertizer._safe_execute, [SERVICE_INFO]) + timer.start.assert_called_once_with(60, scheduled_advertizer._safe_execute, [SERVICE]) def test_schedules_periodic_advertise(self): # Given @@ -95,10 +102,10 @@ def test_schedules_periodic_advertise(self): scheduled_advertizer.start(GROUP) # When - scheduled_advertizer.schedule_periodic(SERVICE_INFO, 60) + scheduled_advertizer.schedule_periodic(SERVICE, 60) # Then - timer.start.assert_called_once_with(60, scheduled_advertizer._execute_and_restart, [SERVICE_INFO]) + timer.start.assert_called_once_with(60, scheduled_advertizer._execute_and_restart, [SERVICE]) def test_execute_and_restart_calls_advertise_and_restarts_timer(self): # Given @@ -108,10 +115,10 @@ def test_execute_and_restart_calls_advertise_and_restarts_timer(self): scheduled_advertizer.start(GROUP) # When - scheduled_advertizer._execute_and_restart(SERVICE_INFO) + scheduled_advertizer._execute_and_restart(SERVICE) # Then - advertizer.advertise.assert_called_once_with(SERVICE_INFO, DEBUG) + advertizer.advertise.assert_called_once_with(SERVICE, DEBUG) timer.restart.assert_called_once() diff --git a/tests/scheduledDiscovererTest.py b/tests/scheduledDiscovererTest.py index 9632a82..e67087f 100644 --- a/tests/scheduledDiscovererTest.py +++ b/tests/scheduledDiscovererTest.py @@ -72,7 +72,7 @@ def test_registers_event_handler(self): scheduled_discoverer.register(handler) # Then - discoverer.register.assert_called_once_with(handler) + discoverer.register.assert_called_once_with(handler, None) def test_deregisters_event_handler(self): # Given @@ -86,7 +86,7 @@ def test_deregisters_event_handler(self): scheduled_discoverer.deregister(handler) # Then - discoverer.deregister.assert_called_once_with(handler) + discoverer.deregister.assert_called_once_with(handler, None) def test_sends_service_query(self): # Given diff --git a/tests/senderIntegrationTest.py b/tests/senderIntegrationTest.py index 9e473ea..bc9d738 100644 --- a/tests/senderIntegrationTest.py +++ b/tests/senderIntegrationTest.py @@ -7,11 +7,11 @@ from test_utility import wait_for_assertion from zmq import Context, DISH -from hello import ServiceInfo, Group +from hello import Service, Group from hello.sender import RadioSender GROUP = Group('test-group', 'udp://239.0.0.1:5555') -SERVICE_INFO = ServiceInfo(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:8080'}) +SERVICE = Service(uuid4(), 'test-service', 'test-role', {'test': 'http://localhost:8080'}) class SenderIntegrationTest(TestCase): @@ -36,12 +36,12 @@ def test_sends_message(self): Thread(target=lambda: messages.append(dish.recv_json())).start() # When - sender.send(SERVICE_INFO) + sender.send(SERVICE) wait_for_assertion(1, lambda: self.assertEqual(1, len(messages))) # Then - self.assertEqual([SERVICE_INFO.to_dict()], messages) + self.assertEqual([SERVICE.to_dict()], messages) if __name__ == '__main__':