ops_handled_by_this_stage = [ pipeline_ops_iothub.SetAuthProviderArgsOperation, pipeline_ops_iothub.SendD2CMessageOperation, pipeline_ops_iothub.SendOutputEventOperation, pipeline_ops_iothub.SendMethodResponseOperation, pipeline_ops_base.SendIotRequestOperation, pipeline_ops_base.EnableFeatureOperation, pipeline_ops_base.DisableFeatureOperation, ] events_handled_by_this_stage = [pipeline_events_mqtt.IncomingMQTTMessageEvent] pipeline_stage_test.add_base_pipeline_stage_tests( cls=pipeline_stages_iothub_mqtt.IoTHubMQTTConverterStage, module=this_module, all_ops=all_common_ops + all_iothub_ops, handled_ops=ops_handled_by_this_stage, all_events=all_common_events + all_iothub_events, handled_events=events_handled_by_this_stage, ) @pytest.fixture def stage(mocker): return make_mock_stage( mocker, pipeline_stages_iothub_mqtt.IoTHubMQTTConverterStage) @pytest.fixture def set_auth_provider_args(callback): return pipeline_ops_iothub.SetAuthProviderArgsOperation( device_id=fake_device_id, hostname=fake_hostname, callback=callback)
assert stage.sas_token is None @pytest.mark.it("Initializes 'transport' attribute as None") def test_transport(self, cls_type, init_kwargs): stage = cls_type(**init_kwargs) assert stage.transport is None @pytest.mark.it("Initializes with no pending connection operation") def test_pending_op(self, cls_type, init_kwargs): stage = cls_type(**init_kwargs) assert stage._pending_connection_op is None pipeline_stage_test.add_base_pipeline_stage_tests( test_module=this_module, stage_class_under_test=pipeline_stages_mqtt.MQTTTransportStage, stage_test_config_class=MQTTTransportStageTestConfig, extended_stage_instantiation_test_class=MQTTTransportInstantiationTests, ) @pytest.mark.describe( "MQTTTransportStage - .run_op() -- Called with SetMQTTConnectionArgsOperation" ) class TestMQTTTransportStageRunOpCalledWithSetMQTTConnectionArgsOperation( MQTTTransportStageTestConfig, StageRunOpTestBase): @pytest.fixture def op(self, mocker): return pipeline_ops_mqtt.SetMQTTConnectionArgsOperation( client_id="fake_client_id", hostname="fake_hostname", username="******",
sastoken=mocker.MagicMock()) return cfg @pytest.fixture def stage(self, mocker, cls_type, init_kwargs, pipeline_config): stage = cls_type(**init_kwargs) stage.pipeline_root = stage.pipeline_root = pipeline_stages_base.PipelineRootStage( pipeline_config) stage.send_op_down = mocker.MagicMock() stage.send_event_up = mocker.MagicMock() return stage pipeline_stage_test.add_base_pipeline_stage_tests( test_module=this_module, stage_class_under_test=pipeline_stages_iothub_http. IoTHubHTTPTranslationStage, stage_test_config_class=IoTHubHTTPTranslationStageTestConfig, ) @pytest.mark.describe( "IoTHubHTTPTranslationStage - .run_op() -- Called with MethodInvokeOperation op" ) class TestIoTHubHTTPTranslationStageRunOpCalledWithMethodInvokeOperation( IoTHubHTTPTranslationStageTestConfig, StageRunOpTestBase): @pytest.fixture def pipeline_config(self, mocker): # Because Method related functionality is limited to Module, configure the stage for a module # auth type shouldn't matter for this stage, so just give it a fake sastoken for now. cfg = config.IoTHubPipelineConfig( hostname="http://my.hostname",
api_version = "2019-03-31" ops_handled_by_this_stage = [ pipeline_ops_provisioning.SetSecurityClientArgsOperation, pipeline_ops_provisioning.SendRegistrationRequestOperation, pipeline_ops_provisioning.SendQueryRequestOperation, pipeline_ops_base.EnableFeatureOperation, pipeline_ops_base.DisableFeatureOperation, ] events_handled_by_this_stage = [pipeline_events_mqtt.IncomingMQTTMessageEvent] pipeline_stage_test.add_base_pipeline_stage_tests( cls=pipeline_stages_provisioning_mqtt.ProvisioningMQTTConverterStage, module=this_module, all_ops=all_common_ops + all_provisioning_ops, handled_ops=ops_handled_by_this_stage, all_events=all_common_events + all_provisioning_events, handled_events=events_handled_by_this_stage, ) @pytest.fixture(scope="function") def some_exception(): return Exception("Alohomora") @pytest.fixture def mock_stage(mocker): return make_mock_stage( mocker, pipeline_stages_provisioning_mqtt.ProvisioningMQTTConverterStage)
class EnsureDesiredPropertiesStageInstantiationTests(EnsureDesiredPropertiesStageTestConfig): @pytest.mark.it("Initializes 'last_version_seen' None") def test_last_version_seen(self, init_kwargs): stage = pipeline_stages_iothub.EnsureDesiredPropertiesStage(**init_kwargs) assert stage.last_version_seen is None @pytest.mark.it("Initializes 'pending_get_request' None") def test_pending_get_request(self, init_kwargs): stage = pipeline_stages_iothub.EnsureDesiredPropertiesStage(**init_kwargs) assert stage.pending_get_request is None pipeline_stage_test.add_base_pipeline_stage_tests( test_module=this_module, stage_class_under_test=pipeline_stages_iothub.EnsureDesiredPropertiesStage, stage_test_config_class=EnsureDesiredPropertiesStageTestConfig, extended_stage_instantiation_test_class=EnsureDesiredPropertiesStageInstantiationTests, ) @pytest.mark.describe( "EnsureDesiredPropertiesStage - .run_op() -- Called with EnableFeatureOperation" ) class TestEnsureDesiredPropertiesStageRunOpWithEnableFeatureOperation( StageRunOpTestBase, EnsureDesiredPropertiesStageTestConfig ): @pytest.fixture def op(self, mocker): return pipeline_ops_base.EnableFeatureOperation( feature_name="fake_feature_name", callback=mocker.MagicMock() )
@pytest.fixture def init_kwargs(self): return {} @pytest.fixture def stage(self, mocker, cls_type, init_kwargs): stage = cls_type(**init_kwargs) stage.send_op_down = mocker.MagicMock() stage.send_event_up = mocker.MagicMock() return stage pipeline_stage_test.add_base_pipeline_stage_tests( test_module=this_module, stage_class_under_test=pipeline_stages_provisioning.UseSecurityClientStage, stage_test_config_class=UseSecurityClientStageTestConfig, ) @pytest.mark.describe( "UseSecurityClientStage - .run_op() -- Called with SetSymmetricKeySecurityClientOperation" ) class TestUseSecurityClientStageRunOpWithSetSymmetricKeySecurityClientOperation( StageRunOpTestBase, UseSecurityClientStageTestConfig): @pytest.fixture def op(self, mocker): security_client = SymmetricKeySecurityClient( provisioning_host="hogwarts.com", registration_id="registered_remembrall", id_scope="weasley_wizard_wheezes",
ops_handled_by_this_stage = [ pipeline_ops_provisioning.SetProvisioningClientConnectionArgsOperation, pipeline_ops_provisioning.SendRegistrationRequestOperation, pipeline_ops_provisioning.SendQueryRequestOperation, pipeline_ops_base.EnableFeatureOperation, pipeline_ops_base.DisableFeatureOperation, ] events_handled_by_this_stage = [pipeline_events_mqtt.IncomingMQTTMessageEvent] pipeline_stage_test.add_base_pipeline_stage_tests( cls=pipeline_stages_provisioning_mqtt.ProvisioningMQTTConverterStage, module=this_module, all_ops=all_common_ops + all_provisioning_ops, handled_ops=ops_handled_by_this_stage, all_events=all_common_events + all_provisioning_events, handled_events=events_handled_by_this_stage, extra_initializer_defaults={"action_to_topic": dict}, ) @pytest.fixture def set_security_client_args(mocker): op = pipeline_ops_provisioning.SetProvisioningClientConnectionArgsOperation( provisioning_host=fake_provisioning_host, registration_id=fake_registration_id, id_scope=fake_id_scope, sas_token=fake_sas_token, client_cert=fake_client_cert, callback=mocker.MagicMock(),
pipeline_ops_mqtt.SetMQTTConnectionArgsOperation, pipeline_ops_mqtt.MQTTPublishOperation, pipeline_ops_mqtt.MQTTSubscribeOperation, pipeline_ops_mqtt.MQTTUnsubscribeOperation, ] events_handled_by_this_stage = [] # TODO: Potentially refactor this out to package level class that can be inherited pipeline_stage_test.add_base_pipeline_stage_tests( cls=pipeline_stages_mqtt.MQTTTransportStage, module=this_module, all_ops=all_common_ops, handled_ops=ops_handled_by_this_stage, all_events=all_common_events, handled_events=events_handled_by_this_stage, methods_that_enter_pipeline_thread=[ "_on_mqtt_message_received", "_on_mqtt_connected", "_on_mqtt_connection_failure", "_on_mqtt_disconnected", ], ) @pytest.fixture def stage(mocker): stage = pipeline_stages_mqtt.MQTTTransportStage() root = pipeline_stages_base.PipelineRootStage() stage.previous = root root.next = stage
# Workaround for flake8. A class with this name is actually created inside # add_base_pipeline_stage_test, but flake8 doesn't know that class TestPipelineRootStagePipelineThreading: pass pipeline_stage_test.add_base_pipeline_stage_tests( cls=pipeline_stages_base.PipelineRootStage, module=this_module, all_ops=all_common_ops, handled_ops=[], all_events=all_common_events, handled_events=all_common_events, methods_that_can_run_in_any_thread=["append_stage", "run_op"], extra_initializer_defaults={ "on_pipeline_event_handler": None, "on_connected_handler": None, "on_disconnected_handler": None, "connected": False, }, positional_arguments=["pipeline_configuration"], ) @pytest.mark.it("Calls operation callback in callback thread") def _test_pipeline_root_runs_callback_in_callback_thread(self, stage, mocker): # the stage fixture comes from the TestPipelineRootStagePipelineThreading object that # this test method gets added to, so it's a PipelineRootStage object stage.pipeline_root = stage callback_called = threading.Event()
stage = cls_type(**init_kwargs) stage.send_op_down = mocker.MagicMock() stage.send_event_up = mocker.MagicMock() return stage class UseAuthProviderStageInstantiationTests(UseAuthProviderStageTestConfig): @pytest.mark.it("Initializes 'auth_provider' as None") def test_auth_provider(self, init_kwargs): stage = pipeline_stages_iothub.UseAuthProviderStage(**init_kwargs) assert stage.auth_provider is None pipeline_stage_test.add_base_pipeline_stage_tests( test_module=this_module, stage_class_under_test=pipeline_stages_iothub.UseAuthProviderStage, stage_test_config_class=UseAuthProviderStageTestConfig, extended_stage_instantiation_test_class=UseAuthProviderStageInstantiationTests, ) @pytest.mark.describe( "UseAuthProviderStage - .run_op() -- Called with SetAuthProviderOperation (SAS Authentication)" ) class TestUseAuthProviderStageRunOpWithSetAuthProviderOperation( StageRunOpTestBase, UseAuthProviderStageTestConfig ): # Auth Providers are configured with different values depending on if the higher level client # is a Device or Module. Parametrize with both possibilities. # TODO: Eventually would be ideal to test using real auth provider instead of the fake one # This probably should just wait until auth provider refactor for ease though. @pytest.fixture(params=["Device", "Module"])
# manually add it to the individual test.py files that need it. If, # instead, we had added it to some conftest.py, it would be applied to # every tests in every file and we don't want that. @pytest.fixture(autouse=True) def apply_fake_pipeline_thread(fake_pipeline_thread): pass pipeline_stage_test.add_base_pipeline_stage_tests( cls=pipeline_stages_base.EnsureConnectionStage, module=this_module, all_ops=all_common_ops, handled_ops=[ pipeline_ops_base.ConnectOperation, pipeline_ops_base.DisconnectOperation, pipeline_ops_base.EnableFeatureOperation, pipeline_ops_base.DisableFeatureOperation, pipeline_ops_base.SendIotRequestAndWaitForResponseOperation, pipeline_ops_base.SendIotRequestOperation, ], all_events=all_common_events, handled_events=[], ) # Workaround for flake8. A class with this name is actually created inside # add_base_pipeline_stage_test, but flake8 doesn't know that class TestPipelineRootStagePipelineThreading: pass
fake_hostname = "__fake_hostname__" fake_gateway_hostname = "__fake_gateway_hostname__" fake_ca_cert = "__fake_ca_cert__" fake_sas_token = "__fake_sas_token__" fake_symmetric_key = "Zm9vYmFy" fake_x509_cert_file = "fantastic_beasts" fake_x509_cert_key_file = "where_to_find_them" fake_pass_phrase = "alohomora" pipeline_stage_test.add_base_pipeline_stage_tests( cls=pipeline_stages_iothub.UseAuthProviderStage, module=this_module, all_ops=all_common_ops + all_iothub_ops, handled_ops=[ pipeline_ops_iothub.SetAuthProviderOperation, pipeline_ops_iothub.SetX509AuthProviderOperation, ], all_events=all_common_events + all_iothub_events, handled_events=[], methods_that_enter_pipeline_thread=["on_sas_token_updated"], ) def make_mock_sas_token_auth_provider(): class MockAuthProvider(object): def get_current_sas_token(self): return fake_sas_token auth_provider = MockAuthProvider() auth_provider.device_id = fake_device_id auth_provider.hostname = fake_hostname
pass fake_device_id = "elder_wand" fake_registration_id = "registered_remembrall" fake_provisioning_host = "hogwarts.com" fake_id_scope = "weasley_wizard_wheezes" fake_ca_cert = "fake_ca_cert" fake_sas_token = "horcrux_token" pipeline_stage_test.add_base_pipeline_stage_tests( cls=pipeline_stages_provisioning.UseSecurityClientStage, module=this_module, all_ops=all_common_ops + all_provisioning_ops, handled_ops=[ pipeline_ops_provisioning.SetSymmetricKeySecurityClientOperation, pipeline_ops_provisioning.SetX509SecurityClientOperation, ], all_events=all_common_events + all_provisioning_events, handled_events=[], ) fake_symmetric_key = "Zm9vYmFy" fake_x509_cert_file = "fantastic_beasts" fake_x509_cert_key_file = "where_to_find_them" fake_pass_phrase = "alohomora" def create_x509_security_client(): mock_x509 = X509(fake_x509_cert_file, fake_x509_cert_key_file, fake_pass_phrase)
) return cfg @pytest.fixture def stage(self, mocker, cls_type, init_kwargs, pipeline_config): stage = cls_type(**init_kwargs) stage.pipeline_root = pipeline_stages_base.PipelineRootStage( pipeline_config) stage.send_op_down = mocker.MagicMock() stage.send_event_up = mocker.MagicMock() return stage pipeline_stage_test.add_base_pipeline_stage_tests( test_module=this_module, stage_class_under_test=pipeline_stages_provisioning_mqtt. ProvisioningMQTTTranslationStage, stage_test_config_class=ProvisioningMQTTTranslationStageTestConfig, ) @pytest.mark.describe( "ProvisioningMQTTTranslationStage - .run_op() -- Called with InitializePipelineOperation" ) class TestProvisioningMQTTTranslationStageRunOpWithInitializePipelineOperation( StageRunOpTestBase, ProvisioningMQTTTranslationStageTestConfig): @pytest.fixture def op(self, mocker): return pipeline_ops_base.InitializePipelineOperation( callback=mocker.MagicMock()) @pytest.mark.it("Derives the MQTT client id, and sets it on the op")
@pytest.fixture def init_kwargs(self): return {} @pytest.fixture def stage(self, mocker, cls_type, init_kwargs): stage = cls_type(**init_kwargs) stage.send_op_down = mocker.MagicMock() stage.send_event_up = mocker.MagicMock() return stage pipeline_stage_test.add_base_pipeline_stage_tests( test_module=this_module, stage_class_under_test=pipeline_stages_provisioning.UseSecurityClientStage, stage_test_config_class=UseSecurityClientStageTestConfig, ) @pytest.mark.describe( "UseSecurityClientStage - .run_op() -- Called with SetSymmetricKeySecurityClientOperation" ) class TestUseSecurityClientStageRunOpWithSetSymmetricKeySecurityClientOperation( StageRunOpTestBase, UseSecurityClientStageTestConfig): @pytest.fixture def op(self, mocker): security_client = SymmetricKeySecurityClient( provisioning_host="hogwarts.com", registration_id="registered_remembrall", id_scope="weasley_wizard_wheezes",
# Workaround for flake8. A class with this name is actually created inside # add_base_pipeline_stage_test, but flake8 doesn't know that class TestPipelineRootStagePipelineThreading: pass pipeline_stage_test.add_base_pipeline_stage_tests( cls=pipeline_stages_base.PipelineRootStage, module=this_module, all_ops=all_common_ops, handled_ops=[], all_events=all_common_events, handled_events=all_common_events, methods_that_can_run_in_any_thread=["append_stage", "run_op"], extra_initializer_defaults={ "on_pipeline_event_handler": None, "on_connected_handler": None, "on_disconnected_handler": None, "connected": False, }, positional_arguments=["pipeline_configuration"], ) @pytest.mark.it("Calls operation callback in callback thread") def _test_pipeline_root_runs_callback_in_callback_thread(self, stage, mocker): # the stage fixture comes from the TestPipelineRootStagePipelineThreading object that # this test method gets added to, so it's a PipelineRootStage object stage.pipeline_root = stage callback_called = threading.Event()