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)
コード例 #2
0
        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="******",
コード例 #3
0
                                          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)
コード例 #5
0
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(),
コード例 #8
0
    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
コード例 #9
0

# 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()
コード例 #10
0
        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

コード例 #12
0
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
コード例 #13
0
    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")
コード例 #15
0
    @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",
コード例 #16
0

# 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()