示例#1
0
    def test_destroy(
        self,
        async_used: bool,
        fx_deployments: YamlLoaderDeployment,
        mocker: MockerFixture,
        runway_context: MockRunwayContext,
    ) -> None:
        """Test destroy."""
        mock_async = MagicMock()
        mocker.patch.object(Deployment, "_Deployment__async", mock_async)
        mock_sync = MagicMock()
        mocker.patch.object(Deployment, "_Deployment__sync", mock_sync)
        runway_context._use_concurrent = async_used
        obj = Deployment(
            context=runway_context,
            definition=fx_deployments.load("simple_parallel_regions"),
        )
        assert obj.destroy()

        if async_used:
            mock_async.assert_called_once_with("destroy")
            mock_sync.assert_not_called()
        else:
            mock_async.assert_not_called()
            mock_sync.assert_called_once_with("destroy")
示例#2
0
    def test_deploy_async(
        self,
        caplog: LogCaptureFixture,
        fx_deployments: YamlLoaderDeployment,
        mocker: MockerFixture,
        runway_context: MockRunwayContext,
    ) -> None:
        """Test deploy async."""
        caplog.set_level(logging.INFO, logger="runway")
        mock_futures = mocker.patch(f"{MODULE}.concurrent.futures")
        executor = MagicMock()
        executor.__enter__.return_value = executor
        mock_futures.ProcessPoolExecutor.return_value = executor
        mocker.patch.object(Deployment, "use_async", True)
        mock_mp_context = mocker.patch("multiprocessing.get_context")

        obj = Deployment(
            context=runway_context,
            definition=fx_deployments.load("simple_parallel_regions"),
        )
        assert not obj.deploy()
        assert (
            "unnamed_deployment:processing regions in parallel... (output will be interwoven)"
            in caplog.messages)
        mock_mp_context.assert_called_once_with("fork")
        mock_futures.ProcessPoolExecutor.assert_called_once_with(
            max_workers=runway_context.env.max_concurrent_regions,
            mp_context=mock_mp_context.return_value,
        )
        executor.submit.assert_has_calls([
            call(obj.run, "deploy", "us-east-1"),
            call(obj.run, "deploy", "us-west-2")
        ])
        assert executor.submit.return_value.result.call_count == 2
示例#3
0
    def test_run(
        self, mock_module, mock_aws, fx_deployments, monkeypatch, runway_context
    ):
        """Test run."""
        mock_resolve = MagicMock()
        mock_validate = MagicMock()
        definition = fx_deployments.load("min_required")
        monkeypatch.setattr(definition, "resolve", mock_resolve)
        monkeypatch.setattr(Deployment, "validate_account_credentials", mock_validate)
        obj = Deployment(context=runway_context, definition=definition)

        assert not obj.run("deploy", "us-west-2")

        assert runway_context.command == "deploy"
        assert runway_context.env.aws_region == "us-west-2"
        mock_resolve.assert_called_once_with(runway_context, obj._variables)
        mock_validate.assert_called_once_with(runway_context)
        mock_aws.AssumeRole.assert_called_once_with(runway_context)
        mock_aws.AssumeRole().__enter__.assert_called_once()
        mock_module.run_list.assert_called_once_with(
            action="deploy",
            context=runway_context,
            deployment=definition,
            future=obj._future,
            modules=definition.modules,
            variables=obj._variables,
        )
示例#4
0
    def test_init(
        self,
        async_used: bool,
        caplog: LogCaptureFixture,
        fx_deployments: YamlLoaderDeployment,
        mocker: MockerFixture,
        runway_context: MockRunwayContext,
    ) -> None:
        """Test init."""
        caplog.set_level(logging.INFO, logger="runway")
        mock_async = MagicMock()
        mocker.patch.object(Deployment, "_Deployment__async", mock_async)
        mock_sync = MagicMock()
        mocker.patch.object(Deployment, "_Deployment__sync", mock_sync)
        runway_context._use_concurrent = async_used
        obj = Deployment(
            context=runway_context,
            definition=fx_deployments.load("simple_parallel_regions"),
        )
        assert obj.init()

        if async_used:
            mock_async.assert_called_once_with("init")
            mock_sync.assert_not_called()
        else:
            mock_async.assert_not_called()
            mock_sync.assert_called_once_with("init")
示例#5
0
    def test_run(
        self,
        fx_deployments: YamlLoaderDeployment,
        mocker: MockerFixture,
        runway_context: MockRunwayContext,
    ) -> None:
        """Test run."""
        mock_aws = mocker.patch(f"{MODULE}.aws")
        mock_module = mocker.patch(f"{MODULE}.Module")
        definition = fx_deployments.load("min_required")
        mock_resolve = mocker.patch.object(definition, "resolve")
        mock_validate = mocker.patch.object(Deployment,
                                            "validate_account_credentials")
        obj = Deployment(context=runway_context, definition=definition)

        assert not obj.run("deploy", "us-west-2")

        assert runway_context.command == "deploy"
        assert runway_context.env.aws_region == "us-west-2"
        mock_resolve.assert_called_once_with(runway_context,
                                             variables=obj._variables)
        mock_validate.assert_called_once_with(runway_context)
        mock_aws.AssumeRole.assert_called_once_with(runway_context)
        mock_aws.AssumeRole().__enter__.assert_called_once()
        mock_module.run_list.assert_called_once_with(
            action="deploy",
            context=runway_context,
            deployment=definition,
            future=obj._future,
            modules=ANY,  # list of module objects change
            variables=obj._variables,
        )
示例#6
0
    def test_plan(
        self,
        async_used: bool,
        caplog: LogCaptureFixture,
        fx_deployments: YamlLoaderDeployment,
        mocker: MockerFixture,
        runway_context: MockRunwayContext,
    ) -> None:
        """Test plan."""
        caplog.set_level(logging.INFO, logger="runway")
        mock_async = MagicMock()
        mocker.patch.object(Deployment, "_Deployment__async", mock_async)
        mock_sync = MagicMock()
        mocker.patch.object(Deployment, "_Deployment__sync", mock_sync)
        runway_context._use_concurrent = async_used
        obj = Deployment(
            context=runway_context,
            definition=fx_deployments.load("simple_parallel_regions"),
        )
        assert obj.plan()

        if async_used:
            assert ("unnamed_deployment:processing of regions will be done in "
                    "parallel during deploy/destroy" in caplog.messages)
        mock_async.assert_not_called()
        mock_sync.assert_called_once_with("plan")
示例#7
0
    def test_deploy_async(
        self, mock_futures, caplog, fx_deployments, monkeypatch, runway_context
    ):
        """Test deploy async."""
        caplog.set_level(logging.INFO, logger="runway")
        executor = MagicMock()
        mock_futures.ProcessPoolExecutor.return_value = executor
        monkeypatch.setattr(Deployment, "use_async", True)

        obj = Deployment(
            context=runway_context,
            definition=fx_deployments.load("simple_parallel_regions"),
        )
        assert not obj.deploy()
        assert (
            "deployment_1:processing regions in parallel... (output will be interwoven)"
            in caplog.messages
        )
        mock_futures.ProcessPoolExecutor.assert_called_once_with(
            max_workers=runway_context.env.max_concurrent_regions
        )
        executor.submit.assert_has_calls(
            [call(obj.run, "deploy", "us-east-1"), call(obj.run, "deploy", "us-west-2")]
        )
        mock_futures.wait.assert_called_once()
        assert executor.submit.return_value.result.call_count == 2
示例#8
0
    def test_run_async(
        self,
        fx_deployments: YamlLoaderDeployment,
        mocker: MockerFixture,
        runway_context: MockRunwayContext,
    ) -> None:
        """Test run async."""
        mocker.patch(f"{MODULE}.aws")
        # ensure that mock.MagicMock is used for backported features
        mock_module = mocker.patch(f"{MODULE}.Module", MagicMock())
        definition = fx_deployments.load("simple_parallel_regions")
        runway_context._use_concurrent = True
        # ensure that mock.MagicMock is used for backported features
        mock_resolve = mocker.patch.object(definition, "resolve", MagicMock())
        mocker.patch.object(Deployment, "validate_account_credentials")
        obj = Deployment(context=runway_context, definition=definition)

        assert not obj.run("destroy", "us-west-2")

        new_ctx = mock_resolve.call_args.args[0]
        assert new_ctx != runway_context
        assert new_ctx.command == "destroy" and runway_context.command != "destroy"
        assert (new_ctx.env.aws_region == "us-west-2"
                and runway_context.env.aws_region != "us-west-2")
        assert mock_module.run_list.call_args.kwargs["context"] == new_ctx
示例#9
0
 def test_deploy(self, fx_deployments, monkeypatch, runway_context):
     """Test deploy."""
     mock_run = MagicMock()
     monkeypatch.setattr(Deployment, "run", mock_run)
     obj = Deployment(
         context=runway_context, definition=fx_deployments.load("min_required")
     )
     assert not obj.deploy()
     mock_run.assert_called_once_with("deploy", "us-east-1")
示例#10
0
 def test_deploy(
     self,
     fx_deployments: YamlLoaderDeployment,
     mocker: MockerFixture,
     runway_context: MockRunwayContext,
 ) -> None:
     """Test deploy."""
     mock_run = MagicMock()
     mocker.patch.object(Deployment, "run", mock_run)
     obj = Deployment(context=runway_context,
                      definition=fx_deployments.load("min_required"))
     assert not obj.deploy()
     mock_run.assert_called_once_with("deploy", "us-east-1")
示例#11
0
    def test_env_vars_config_unresolved(
        self, fx_deployments, monkeypatch, runway_context
    ):
        """Test env_vars_config unresolved."""
        expected = {"key": "val"}

        monkeypatch.setattr(
            MODULE + ".merge_nested_environment_dicts", MagicMock(return_value=expected)
        )
        monkeypatch.setattr(
            Deployment, "_Deployment__merge_env_vars", MagicMock(return_value=None)
        )
        monkeypatch.setattr(
            DeploymentDefinition,
            "env_vars",
            PropertyMock(
                side_effect=[UnresolvedVariable("test", MagicMock()), expected]
            ),
        )
        monkeypatch.setattr(
            DeploymentDefinition, "_env_vars", PropertyMock(), raising=False
        )

        raw_deployment = fx_deployments.get("min_required")
        deployment = DeploymentDefinition.from_list([raw_deployment])[0]
        obj = Deployment(context=runway_context, definition=deployment)

        assert obj.env_vars_config == expected
        obj.definition._env_vars.resolve.assert_called_once()
示例#12
0
    def test_env_vars_config_unresolved(
        self,
        fx_deployments: YamlLoaderDeployment,
        mocker: MockerFixture,
        runway_context: MockRunwayContext,
    ) -> None:
        """Test env_vars_config unresolved."""
        expected = {"key": "val"}
        mocker.patch.object(Deployment, "_Deployment__merge_env_vars",
                            MagicMock(return_value=None))
        mocker.patch.object(
            RunwayDeploymentDefinition,
            "env_vars",
            PropertyMock(side_effect=[
                UnresolvedVariable(
                    Variable("test", "something", variable_type="runway"),
                    MagicMock(),
                ),
                expected,
            ]),
            create=True,
        )
        mocker.patch.object(RunwayDeploymentDefinition,
                            "_env_vars",
                            PropertyMock(),
                            create=True)

        raw_deployment: Dict[str,
                             Any] = cast(Dict[str, Any],
                                         fx_deployments.get("min_required"))
        deployment = RunwayDeploymentDefinition.parse_obj(raw_deployment)
        obj = Deployment(context=runway_context, definition=deployment)

        assert obj.env_vars_config == expected
        obj.definition._env_vars.resolve.assert_called_once()
示例#13
0
    def test_run_list(self, action, monkeypatch, runway_context):
        """Test run_list."""
        dep0 = MagicMock()
        dep0.modules = ["module"]
        dep1 = MagicMock()
        dep1.modules = []
        deployments = [dep0, dep1]

        mock_action = MagicMock()
        monkeypatch.setattr(Deployment, action, mock_action)
        mock_vars = MagicMock()

        assert not Deployment.run_list(
            action=action,
            context=runway_context,
            deployments=deployments,
            future=None,
            variables=mock_vars,
        )
        dep0.resolve.assert_called_once_with(
            runway_context, variables=mock_vars, pre_process=True
        )
        dep1.resolve.assert_called_once_with(
            runway_context, variables=mock_vars, pre_process=True
        )
        mock_action.assert_called_once_with()
示例#14
0
    def test_deploy_sync(self, caplog, fx_deployments, monkeypatch, runway_context):
        """Test deploy sync."""
        caplog.set_level(logging.INFO, logger="runway")
        mock_run = MagicMock()
        monkeypatch.setattr(Deployment, "use_async", False)
        monkeypatch.setattr(Deployment, "run", mock_run)

        obj = Deployment(
            context=runway_context,
            definition=fx_deployments.load("simple_parallel_regions"),
        )
        assert not obj.deploy()
        assert "deployment_1:processing regions sequentially..." in caplog.messages
        mock_run.assert_has_calls(
            [call("deploy", "us-east-1"), call("deploy", "us-west-2")]
        )
示例#15
0
 def test_use_async(
     self, config, use_concurrent, expected, fx_deployments, runway_context
 ):
     """Test use_async."""
     runway_context._use_concurrent = use_concurrent
     obj = Deployment(context=runway_context, definition=fx_deployments.load(config))
     assert obj.use_async == expected
示例#16
0
    def test_child_modules(self, fx_deployments: YamlLoaderDeployment,
                           runway_context: MockRunwayContext) -> None:
        """Test child_modules."""
        deployment = Deployment(
            context=runway_context,
            definition=fx_deployments.load("simple_parallel_module"),
        )
        mod0 = Module(
            context=runway_context,
            definition=deployment.definition.modules[0],
            deployment=deployment.definition,
        )
        mod1 = Module(
            context=runway_context,
            definition=deployment.definition.modules[1],
            deployment=deployment.definition,
        )

        assert len(mod0.child_modules) == 2
        assert not mod1.child_modules

        for index, child in enumerate(mod0.child_modules):
            assert isinstance(child, Module)
            # basic checks to ensure the child was setup correctly
            assert child.ctx.env.name == runway_context.env.name
            assert child.definition.path == mod0.definition.child_modules[
                index].path
示例#17
0
 def test_assume_role_config(self, config, expected, fx_deployments, runway_context):
     """Test assume_role_config."""
     obj = Deployment(context=runway_context, definition=fx_deployments.load(config))
     result = obj.assume_role_config
     assert {k: result[k] for k in sorted(result)} == {
         k: expected[k] for k in sorted(expected)
     }
示例#18
0
    def test_run_list(
        self,
        action: RunwayActionTypeDef,
        mocker: MockerFixture,
        runway_context: MockRunwayContext,
    ) -> None:
        """Test run_list."""
        dep0 = MagicMock()
        dep0.modules = ["module"]
        dep1 = MagicMock()
        dep1.modules = []
        deployments = [dep0, dep1]

        mock_action = MagicMock()
        mocker.patch.object(Deployment, action, mock_action)
        mock_vars = MagicMock()

        assert not Deployment.run_list(
            action=action,
            context=runway_context,
            deployments=deployments,  # type: ignore
            future=None,  # type: ignore
            variables=mock_vars,
        )
        dep0.resolve.assert_called_once_with(runway_context,
                                             variables=mock_vars,
                                             pre_process=True)
        dep1.resolve.assert_called_once_with(runway_context,
                                             variables=mock_vars,
                                             pre_process=True)
        mock_action.assert_called_once_with()
示例#19
0
    def test_destroy(self, async_used, fx_deployments, monkeypatch, runway_context):
        """Test destroy."""
        mock_async = MagicMock()
        monkeypatch.setattr(Deployment, "_Deployment__async", mock_async)
        mock_sync = MagicMock()
        monkeypatch.setattr(Deployment, "_Deployment__sync", mock_sync)
        runway_context._use_concurrent = async_used
        obj = Deployment(
            context=runway_context,
            definition=fx_deployments.load("simple_parallel_regions"),
        )
        assert obj.destroy()

        if async_used:
            mock_async.assert_called_once_with("destroy")
            mock_sync.assert_not_called()
        else:
            mock_async.assert_not_called()
            mock_sync.assert_called_once_with("destroy")
示例#20
0
 def test_assume_role_config(
     self,
     config: str,
     expected: Dict[str, Any],
     fx_deployments: YamlLoaderDeployment,
     runway_context: MockRunwayContext,
 ) -> None:
     """Test assume_role_config."""
     obj = Deployment(context=runway_context,
                      definition=fx_deployments.load(config))
     assert obj.assume_role_config == expected
示例#21
0
 def test_regions(
     self,
     config: str,
     expected: List[str],
     fx_deployments: YamlLoaderDeployment,
     runway_context: MockRunwayContext,
 ) -> None:
     """Test regions."""
     obj = Deployment(context=runway_context,
                      definition=fx_deployments.load(config))
     assert obj.regions == expected
示例#22
0
    def test_validate_account_credentials(
        self,
        caplog: LogCaptureFixture,
        mocker: MockerFixture,
        fx_deployments: YamlLoaderDeployment,
        runway_context: MockRunwayContext,
    ) -> None:
        """Test validate_account_credentials."""
        caplog.set_level(logging.INFO, logger="runway")
        mock_aws = mocker.patch(f"{MODULE}.aws")
        obj = Deployment(context=runway_context,
                         definition=fx_deployments.load("validate_account"))

        account = MagicMock()
        account.aliases = ["no-match"]
        account.id = "111111111111"
        mock_aws.AccountDetails.return_value = account
        with pytest.raises(SystemExit) as excinfo:
            assert obj.validate_account_credentials()
        assert excinfo.value.code == 1
        assert 'does not match required account "123456789012"' in "\n".join(
            caplog.messages)
        caplog.clear()
        del excinfo

        account.id = "123456789012"
        with pytest.raises(SystemExit) as excinfo:
            assert obj.validate_account_credentials()
        assert excinfo.value.code == 1
        logs = "\n".join(caplog.messages)
        assert "verified current AWS account matches required account id" in logs
        assert 'do not match required account alias "test"' in logs
        caplog.clear()
        del logs
        del excinfo

        account.aliases = ["test"]
        assert not obj.validate_account_credentials()
        logs = "\n".join(caplog.messages)
        assert "verified current AWS account matches required account id" in logs
        assert "verified current AWS account alias matches required alias" in logs
示例#23
0
    def test_run_async(
        self, mock_module, _mock_aws, fx_deployments, monkeypatch, runway_context
    ):
        """Test run async."""
        mock_resolve = MagicMock()
        definition = fx_deployments.load("simple_parallel_regions")
        runway_context._use_concurrent = True
        monkeypatch.setattr(definition, "resolve", mock_resolve)
        monkeypatch.setattr(Deployment, "validate_account_credentials", MagicMock())
        obj = Deployment(context=runway_context, definition=definition)

        assert not obj.run("destroy", "us-west-2")

        new_ctx = mock_resolve.call_args.args[0]
        assert new_ctx != runway_context
        assert new_ctx.command == "destroy" and runway_context.command != "destroy"
        assert (
            new_ctx.env.aws_region == "us-west-2"
            and runway_context.env.aws_region != "us-west-2"
        )
        assert mock_module.run_list.call_args.kwargs["context"] == new_ctx
示例#24
0
 def test_use_async(
     self,
     config: str,
     expected: bool,
     fx_deployments: YamlLoaderDeployment,
     runway_context: MockRunwayContext,
     use_concurrent: bool,
 ) -> None:
     """Test use_async."""
     runway_context._use_concurrent = use_concurrent
     obj = Deployment(context=runway_context,
                      definition=fx_deployments.load(config))
     assert obj.use_async == expected
示例#25
0
    def test_init(self, fx_deployments, monkeypatch, runway_context):
        """Test init."""
        definition = fx_deployments.load("min_required")
        mock_merge = MagicMock()
        monkeypatch.setattr(Deployment, "_Deployment__merge_env_vars", mock_merge)

        obj = Deployment(context=runway_context, definition=definition)

        assert isinstance(obj._future, FutureDefinition)
        assert isinstance(obj._variables, VariablesDefinition)
        assert obj.definition == definition
        assert obj.ctx == runway_context
        assert obj.name == "deployment_1"
        mock_merge.assert_called_once_with()
示例#26
0
    def test_plan(
        self, async_used, caplog, fx_deployments, monkeypatch, runway_context
    ):
        """Test plan."""
        caplog.set_level(logging.INFO, logger="runway")
        mock_async = MagicMock()
        monkeypatch.setattr(Deployment, "_Deployment__async", mock_async)
        mock_sync = MagicMock()
        monkeypatch.setattr(Deployment, "_Deployment__sync", mock_sync)
        runway_context._use_concurrent = async_used
        obj = Deployment(
            context=runway_context,
            definition=fx_deployments.load("simple_parallel_regions"),
        )
        assert obj.plan()

        if async_used:
            assert (
                "deployment_1:processing of regions will be done in "
                "parallel during deploy/destroy" in caplog.messages
            )
        mock_async.assert_not_called()
        mock_sync.assert_called_once_with("plan")
示例#27
0
    def test_deploy_sync(
        self,
        caplog: LogCaptureFixture,
        fx_deployments: YamlLoaderDeployment,
        mocker: MockerFixture,
        runway_context: MockRunwayContext,
    ) -> None:
        """Test deploy sync."""
        caplog.set_level(logging.INFO, logger="runway")
        mock_run = MagicMock()
        mocker.patch.object(Deployment, "use_async", False)
        mocker.patch.object(Deployment, "run", mock_run)

        obj = Deployment(
            context=runway_context,
            definition=fx_deployments.load("simple_parallel_regions"),
        )
        assert not obj.deploy()
        assert ("unnamed_deployment:processing regions sequentially..."
                in caplog.messages)
        mock_run.assert_has_calls(
            [call("deploy", "us-east-1"),
             call("deploy", "us-west-2")])
示例#28
0
    def test_init_args(self, fx_deployments, runway_context):
        """Test init with args."""
        definition = fx_deployments.load("simple_env_vars_map")
        future = FutureDefinition(strict_environments=True)
        variables = VariablesDefinition(some_key="val")

        obj = Deployment(
            context=runway_context,
            definition=definition,
            future=future,
            variables=variables,
        )

        assert obj._future == future
        assert obj._variables == variables
        assert obj.definition == definition
        assert obj.ctx == runway_context
        assert obj.name == "deployment_1"
        assert obj.ctx.env.vars["deployment_var"] == "val"
示例#29
0
    def test___init___args(self, fx_deployments: YamlLoaderDeployment,
                           runway_context: MockRunwayContext) -> None:
        """Test __init__ with args."""
        definition = fx_deployments.load("simple_env_vars")
        future = RunwayFutureDefinitionModel()
        variables = RunwayVariablesDefinition.parse_obj({"some_key": "val"})

        obj = Deployment(
            context=runway_context,
            definition=definition,
            future=future,
            variables=variables,
        )

        assert obj._future == future
        assert obj._variables == variables
        assert obj.definition == definition
        assert obj.ctx == runway_context
        assert obj.name == "unnamed_deployment"
        assert obj.ctx.env.vars["deployment_var"] == "val"
示例#30
0
    def test___init__(
        self,
        fx_deployments: YamlLoaderDeployment,
        mocker: MockerFixture,
        runway_context: MockRunwayContext,
    ) -> None:
        """Test __init__."""
        definition = fx_deployments.load("min_required")
        mock_merge = MagicMock()
        mocker.patch.object(Deployment, "_Deployment__merge_env_vars",
                            mock_merge)

        obj = Deployment(context=runway_context, definition=definition)

        assert isinstance(obj._future, RunwayFutureDefinitionModel)
        assert isinstance(obj._variables, RunwayVariablesDefinition)
        assert obj.definition == definition
        assert obj.ctx == runway_context
        assert obj.name == "unnamed_deployment"
        mock_merge.assert_called_once_with()