async def test_handle_pnp_commmand( self, client, event_loop, pnp_command_name, pnp_component_name, pnp_command_response_status, include_component_name, include_request_payload, include_response_payload, service_helper, device_id, module_id, ): actual_request = None if include_request_payload: request_payload = get_random_dict() else: request_payload = "" if include_response_payload: response_payload = get_random_dict() else: response_payload = None async def handle_on_command_request_received(request): nonlocal actual_request logger.info( "command request for component {}, command {} received".format( request.component_name, request.command_name)) actual_request = request logger.info("Sending response") await client.send_command_response( CommandResponse.create_from_command_request( request, pnp_command_response_status, response_payload)) client.on_command_request_received = handle_on_command_request_received await asyncio.sleep(1) # wait for subscribe, etc, to complete # invoke the command command_response = await service_helper.invoke_pnp_command( device_id, module_id, pnp_component_name, pnp_command_name, request_payload) # verify that the method request arrived correctly assert actual_request.command_name == pnp_command_name assert actual_request.component_name == pnp_component_name if request_payload: assert actual_request.payload == request_payload else: assert not actual_request.payload # and make sure the response came back successfully # Currently no way to check the command response status code because the DigitalTwinClient A # object in the service SDK does not return this to the caller. # assert command_response[Fields.COMMAND_RESPONSE_STATUS_CODE] == command_response_status assert command_response == response_payload
async def test_handle_method_call( self, client, method_name, method_response_status, include_request_payload, include_response_payload, service_helper, leak_tracker, ): leak_tracker.set_initial_object_list() actual_request = None if include_request_payload: request_payload = get_random_dict() else: request_payload = None if include_response_payload: response_payload = get_random_dict() else: response_payload = None async def handle_on_method_request_received(request): nonlocal actual_request logger.info("Method request for {} received".format(request.name)) actual_request = request logger.info("Sending response") await client.send_method_response( MethodResponse.create_from_method_request( request, method_response_status, response_payload)) client.on_method_request_received = handle_on_method_request_received await asyncio.sleep(1) # wait for subscribe, etc, to complete # invoke the method call method_response = await service_helper.invoke_method( method_name, request_payload) # verify that the method request arrived correctly assert actual_request.name == method_name if request_payload: assert actual_request.payload == request_payload else: assert not actual_request.payload # and make sure the response came back successfully assert method_response.status == method_response_status assert method_response.payload == response_payload actual_request = None # so this isn't tagged as a leak leak_tracker.check_for_leaks()
def test_handle_method_call( self, client, method_name, device_id, module_id, method_response_status, include_request_payload, include_response_payload, service_helper, ): if include_request_payload: request_payload = get_random_dict() else: request_payload = None if include_response_payload: response_payload = get_random_dict() else: response_payload = None # hack needed because there is no `nonlocal` keyword in py27. nonlocal_py27_hack = {"actual_request": None} def handle_on_method_request_received(request): logger.info("Method request for {} received".format(request.name)) nonlocal_py27_hack["actual_request"] = request logger.info("Sending response") client.send_method_response( MethodResponse.create_from_method_request( request, method_response_status, response_payload)) client.on_method_request_received = handle_on_method_request_received time.sleep(1) # wait for subscribe, etc, to complete # invoke the method call method_response = service_helper.invoke_method(device_id, module_id, method_name, request_payload) # verify that the method request arrived correctly actual_request = nonlocal_py27_hack["actual_request"] assert actual_request.name == method_name if request_payload: assert actual_request.payload == request_payload else: assert not actual_request.payload # and make sure the response came back successfully assert method_response.status == method_response_status assert method_response.payload == response_payload
async def test_get_reported_property( self, client, pnp_read_only_property_name, pnp_component_name, is_component_property, ): random_property_value = get_random_dict() assert client.connected patch = ClientPropertyCollection() if is_component_property: patch.set_component_property(pnp_component_name, pnp_read_only_property_name, random_property_value) else: patch.set_property(pnp_read_only_property_name, random_property_value) logger.info("Setting {} to {}".format(pnp_read_only_property_name, random_property_value)) await client.update_client_properties(patch) properties = await client.get_client_properties() if is_component_property: assert (properties.reported_from_device.get_component_property( pnp_component_name, pnp_read_only_property_name) == random_property_value) assert properties.reported_from_device.backing_object[ pnp_component_name]["__t"] == "c" else: assert (properties.reported_from_device.get_property( pnp_read_only_property_name) == random_property_value)
async def test_receives_simple_desired_patch(self, client, event_loop, service_helper, leak_tracker): leak_tracker.set_initial_object_list() received_patch = None received = asyncio.Event() async def handle_on_patch_received(patch): nonlocal received_patch, received print("received {}".format(patch)) received_patch = patch event_loop.call_soon_threadsafe(received.set) client.on_twin_desired_properties_patch_received = handle_on_patch_received random_dict = get_random_dict() await service_helper.set_desired_properties( {const.TEST_CONTENT: random_dict}, ) await asyncio.wait_for(received.wait(), 60) assert received.is_set() assert received_patch[const.TEST_CONTENT] == random_dict twin = await client.get_twin() assert twin[const.DESIRED][const.TEST_CONTENT] == random_dict
def test_simple_patch(self, client, service_helper, device_id, module_id): received = threading.Event() # hack needed because there is no `nonlocal` keyword in py27. nonlocal_py27_hack = {"received_patch": None, "received": received} def handle_on_patch_received(patch): print("received {}".format(patch)) nonlocal_py27_hack["received_patch"] = patch nonlocal_py27_hack["received"].set() client.on_twin_desired_properties_patch_received = handle_on_patch_received random_dict = get_random_dict() service_helper.set_desired_properties( device_id, module_id, {const.TEST_CONTENT: random_dict}, ) received.wait(timeout=10) logger.info("got it") assert nonlocal_py27_hack["received_patch"][ const.TEST_CONTENT] == random_dict twin = client.get_twin() assert twin[const.DESIRED][const.TEST_CONTENT] == random_dict
def test_sync_receives_simple_desired_patch(self, client, service_helper, leak_tracker): received_patches = queue.Queue() leak_tracker.set_initial_object_list() def handle_on_patch_received(patch): nonlocal received_patches print("received {}".format(patch)) received_patches.put(patch) client.on_twin_desired_properties_patch_received = handle_on_patch_received # erase all old desired properties. Otherwise our random dict will only # be part of the twin we get when we call `get_twin` below (because of # properties from previous tests). service_helper.set_desired_properties({const.TEST_CONTENT: None}, ) random_dict = get_random_dict() service_helper.set_desired_properties( {const.TEST_CONTENT: random_dict}, ) while True: received_patch = received_patches.get(timeout=60) if received_patch[const.TEST_CONTENT] == random_dict: twin = client.get_twin() assert twin[const.DESIRED][const.TEST_CONTENT] == random_dict break leak_tracker.check_for_leaks()
async def test_simple_patch(self, client, event_loop, service_helper, device_id, module_id): received_patch = None received = asyncio.Event() async def handle_on_patch_received(patch): nonlocal received_patch, received print("received {}".format(patch)) received_patch = patch event_loop.call_soon_threadsafe(received.set) client.on_twin_desired_properties_patch_received = handle_on_patch_received random_dict = get_random_dict() await service_helper.set_desired_properties( device_id, module_id, {const.TEST_CONTENT: random_dict}, ) await asyncio.wait_for(received.wait(), 10) logger.info("got it") assert received_patch[const.TEST_CONTENT] == random_dict twin = await client.get_twin() assert twin[const.DESIRED][const.TEST_CONTENT] == random_dict
async def test_receive_c2d(self, client, service_helper, event_loop, leak_tracker): leak_tracker.set_initial_object_list() message = json.dumps(get_random_dict()) received_message = None received = asyncio.Event() async def handle_on_message_received(message): nonlocal received_message, received logger.info("received {}".format(message)) received_message = message event_loop.call_soon_threadsafe(received.set) client.on_message_received = handle_on_message_received await service_helper.send_c2d(message, {}) await asyncio.wait_for(received.wait(), 60) assert received.is_set() assert received_message.data.decode("utf-8") == message received_message = None # so this isn't tagged as a leak leak_tracker.check_for_leaks()
def test_sync_receive_c2d(self, client, service_helper, leak_tracker): leak_tracker.set_initial_object_list() message = json.dumps(get_random_dict()) received_message = None received = threading.Event() def handle_on_message_received(message): nonlocal received_message, received logger.info("received {}".format(message)) received_message = message received.set() client.on_message_received = handle_on_message_received service_helper.send_c2d(message, {}) received.wait(timeout=60) assert received.is_set() assert received_message.data.decode("utf-8") == message received_message = None # so this isn't tagged as a leak leak_tracker.check_for_leaks()
def test_sync_sends_json_string(self, client, service_helper, leak_tracker): leak_tracker.set_initial_object_list() message = json.dumps(utils.get_random_dict()) client.send_message(message) event = service_helper.wait_for_eventhub_arrival(None) assert json.dumps(event.message_body) == message leak_tracker.check_for_leaks()
async def test_set_reported_property( self, client, pnp_read_only_property_name, pnp_component_name, is_component_property, service_helper, device_id, module_id, ): random_property_value = get_random_dict() assert client.connected patch = ClientPropertyCollection() if is_component_property: patch.set_component_property(pnp_component_name, pnp_read_only_property_name, random_property_value) else: patch.set_property(pnp_read_only_property_name, random_property_value) logger.info("Setting {} to {}".format(pnp_read_only_property_name, random_property_value)) await client.update_client_properties(patch) while True: properties = await service_helper.get_pnp_properties( device_id, module_id) if is_component_property: actual_value = properties.get(pnp_component_name, {}).get( pnp_read_only_property_name, None) else: actual_value = properties.get(pnp_read_only_property_name, None) if actual_value == random_property_value: return else: logger.warning( "property not matched yet. Expected = {}, actual = {}". format(random_property_value, actual_value)) logger.warning( "digital_twin_client.get_digital_twin returned {}".format( pprint.pformat(properties))) await asyncio.sleep(5)
async def test_desired_properties_via_get_client_properties( self, event_loop, client, pnp_component_name, pnp_writable_property_name, is_component_property, service_helper, device_id, module_id, ): random_property_value = get_random_dict() received = asyncio.Event() async def handle_on_patch_received(patch): nonlocal received logger.info("received {}".format(patch)) event_loop.call_soon_threadsafe(received.set) client.on_writable_property_update_request_received = handle_on_patch_received await asyncio.sleep(1) props = make_pnp_desired_property_patch( pnp_component_name if is_component_property else None, pnp_writable_property_name, random_property_value, ) await service_helper.update_pnp_properties(device_id, module_id, props) # wait for the desired property patch to arrive at the client # We don't actually check the contents of the patch, but the # fact that it arrived means the device registry should have # finished ingesting the patch await asyncio.wait_for(received.wait(), 10) logger.info("got it") properties = await client.get_client_properties() if is_component_property: assert ( properties.writable_properties_requests.get_component_property( pnp_component_name, pnp_writable_property_name) == random_property_value) assert (properties.writable_properties_requests. backing_object[pnp_component_name]["__t"] == "c") else: assert (properties.writable_properties_requests.get_property( pnp_writable_property_name) == random_property_value)
async def test_send_pnp_telemetry(self, client, pnp_model_id, get_next_eventhub_arrival): telemetry = get_random_dict() await client.send_telemetry(telemetry) event = await get_next_eventhub_arrival() logger.info(pprint.pformat(event)) assert event.message_body == telemetry system_props = event.system_properties assert system_props[ const.EVENTHUB_SYSPROP_DT_DATASCHEMA] == pnp_model_id assert system_props[ const.EVENTHUB_SYSPROP_CONTENT_TYPE] == const.JSON_CONTENT_TYPE assert system_props[ const. EVENTHUB_SYSPROP_CONTENT_ENCODING] == const.JSON_CONTENT_ENCODING
async def test_send_message(self, client, service_helper, device_id, module_id, event_loop): message = json.dumps(get_random_dict()) received_message = None received = asyncio.Event() async def handle_on_message_received(message): nonlocal received_message, received logger.info("received {}".format(message)) received_message = message event_loop.call_soon_threadsafe(received.set) client.on_message_received = handle_on_message_received await service_helper.send_c2d(device_id, module_id, message, {}) await asyncio.wait_for(received.wait(), 10) assert received_message.data.decode("utf-8") == message
def test_send_message(self, client, service_helper, device_id, module_id): message = json.dumps(get_random_dict()) received = threading.Event() # hack needed because there is no `nonlocal` keyword in py27. nonlocal_py27_hack = {"received_msg": None, "received": received} def handle_on_message_received(message): logger.info("received {}".format(message)) nonlocal_py27_hack["received_message"] = message nonlocal_py27_hack["received"].set() client.on_message_received = handle_on_message_received service_helper.send_c2d(device_id, module_id, message, {}) received.wait(timeout=10) assert nonlocal_py27_hack["received_message"].data.decode( "utf-8") == message
async def test_receive_desired_property_patch( self, event_loop, client, pnp_component_name, pnp_writable_property_name, is_component_property, pnp_ack_code, pnp_ack_description, service_helper, device_id, module_id, ): random_property_value = get_random_dict() received_patch = None received = asyncio.Event() async def handle_on_patch_received(patch): nonlocal received_patch, received logger.info("received {}".format(patch)) received_patch = patch event_loop.call_soon_threadsafe(received.set) client.on_writable_property_update_request_received = handle_on_patch_received await asyncio.sleep(1) # patch desired properites props = make_pnp_desired_property_patch( pnp_component_name if is_component_property else None, pnp_writable_property_name, random_property_value, ) await service_helper.update_pnp_properties(device_id, module_id, props) logger.info("patch sent. Waiting for desired proprety") # wait for the desired property patch to arrive at the client await asyncio.wait_for(received.wait(), 10) logger.info("got it") # validate the patch if is_component_property: assert (received_patch.get_component_property( pnp_component_name, pnp_writable_property_name) == random_property_value) assert received_patch.backing_object[pnp_component_name][ "__t"] == "c" else: assert received_patch.get_property( pnp_writable_property_name) == random_property_value # make a reported property patch to respond update_patch = ClientPropertyCollection() property_response = generate_writable_property_response( random_property_value, pnp_ack_code, pnp_ack_description, received_patch.version) if is_component_property: update_patch.set_component_property(pnp_component_name, pnp_writable_property_name, property_response) else: update_patch.set_property(pnp_writable_property_name, property_response) # send the reported property patch await client.update_client_properties(update_patch) # verify that the reported value via digital_twin_client.get_digital_twin() props = await service_helper.get_pnp_properties(device_id, module_id) if is_component_property: props = props[pnp_component_name] assert props[pnp_writable_property_name] == random_property_value metadata = props["$metadata"][pnp_writable_property_name] assert metadata["ackCode"] == pnp_ack_code assert metadata["ackDescription"] == pnp_ack_description assert metadata["ackVersion"] == received_patch.version assert metadata["desiredVersion"] == received_patch.version assert metadata["desiredValue"] == random_property_value
def random_reported_props(): return {const.TEST_CONTENT: get_random_dict()}