Beispiel #1
0
 def test_tags_none(self) -> None:
     """Test tags None."""
     obj = CfnginContext(config=CfnginConfig.parse_obj({
         "namespace": "test",
         "tags": None
     }))
     assert obj.tags == {"cfngin_namespace": obj.config.namespace}
Beispiel #2
0
 def _get_context(
     self, extra_config_args: Optional[Dict[str, Any]] = None, **kwargs: Any
 ) -> CfnginContext:
     """Get context."""
     config = {
         "namespace": "namespace",
         "stacks": [
             {"name": "vpc", "template_path": "."},
             {"name": "bastion", "requires": ["vpc"], "template_path": "."},
             {
                 "name": "instance",
                 "requires": ["vpc", "bastion"],
                 "template_path": ".",
             },
             {
                 "name": "db",
                 "requires": ["instance", "vpc", "bastion"],
                 "template_path": ".",
             },
             {"name": "other", "requires": ["db"], "template_path": "."},
         ],
     }
     if extra_config_args:
         config.update(extra_config_args)
     return CfnginContext(config=CfnginConfig.parse_obj(config), **kwargs)
Beispiel #3
0
 def test_tags_empty(self) -> None:
     """Test tags empty."""
     obj = CfnginContext(config=CfnginConfig.parse_obj({
         "namespace": "test",
         "tags": {}
     }))
     assert obj.tags == {}
Beispiel #4
0
 def test_parse_obj(self, monkeypatch: MonkeyPatch) -> None:
     """Test parse_obj."""
     monkeypatch.setattr(
         MODULE + ".CfnginConfigDefinitionModel.parse_obj",
         lambda x: CfnginConfigDefinitionModel(namespace="success"
                                               ),  # type: ignore
     )
     assert CfnginConfig.parse_obj({}).namespace == "success"
Beispiel #5
0
 def setUp(self) -> None:
     """Run before tests."""
     self.context = CfnginContext(
         config=CfnginConfig.parse_obj({
             "namespace": "test",
             "cfngin_bucket": "test"
         }))
     self.provider = mock_provider(region="us-east-1")
Beispiel #6
0
 def test_namespace_delimiter(self) -> None:
     """Test namespace_delimiter."""
     config = CfnginConfig.parse_obj({
         "namespace": "test",
         "namespace_delimiter": "."
     })
     assert (CfnginContext(
         config=config).namespace_delimiter == config.namespace_delimiter)
Beispiel #7
0
 def test_bucket_name_config(self, mocker: MockerFixture) -> None:
     """Test bucket_name from Config."""
     mocker.patch.object(CfnginContext, "upload_to_s3", True)
     assert (CfnginContext(
         config=CfnginConfig.parse_obj({
             "namespace": "test",
             "cfngin_bucket": "test-bucket"
         })).bucket_name == "test-bucket")
Beispiel #8
0
 def test_tags(self) -> None:
     """Test tags."""
     obj = CfnginContext(config=CfnginConfig.parse_obj({
         "namespace": "test",
         "tags": {
             "key": "val"
         }
     }))
     assert obj.tags == obj.config.tags
Beispiel #9
0
 def setUp(self) -> None:
     """Run before tests."""
     self.context = CfnginContext(
         config=CfnginConfig.parse_obj({"namespace": "namespace"}))
     self.provider = MockProvider()
     self.deploy_action = deploy.Action(
         self.context,
         provider_builder=MockProviderBuilder(
             provider=self.provider),  # type: ignore
     )
Beispiel #10
0
    def setUp(self) -> None:
        """Run before tests."""
        self.context = CfnginContext(
            config=CfnginConfig.parse_obj({
                "namespace": "test",
                "cfngin_bucket": "test"
            }))
        self.provider = mock_provider(region="us-east-1")

        self.mock_process = MockProcess()
        self.popen_mock = mock.patch("runway.cfngin.hooks.command.Popen",
                                     return_value=self.mock_process).start()
Beispiel #11
0
 def test_persistent_graph_location_add_json(self) -> None:
     """Test persistent_graph_location adds `.json` extension."""
     config = CfnginConfig.parse_obj({
         "namespace": "test",
         "cfngin_bucket": "test-bucket",
         "persistent_graph_key": "something",
     })
     obj = CfnginContext(config=config)
     assert obj.persistent_graph_location["Bucket"] == config.cfngin_bucket
     assert (
         obj.persistent_graph_location["Key"] ==
         f"persistent_graphs/{config.namespace}/{config.persistent_graph_key}.json"
     )
Beispiel #12
0
 def test_mappings(self) -> None:
     """Test mappings."""
     config = CfnginConfig.parse_obj({
         "namespace": "test",
         "mappings": {
             "my_map": {
                 "something": {
                     "key": "val"
                 }
             }
         }
     })
     assert CfnginContext(config=config).mappings == config.mappings
Beispiel #13
0
def mock_context(
    namespace: str = "default",
    extra_config_args: Optional[Dict[str, Any]] = None,
    **kwargs: Any,
) -> CfnginContext:
    """Mock context."""
    config_args = {"namespace": namespace}
    if extra_config_args:
        config_args.update(extra_config_args)
    config = CfnginConfig.parse_obj(config_args)
    if kwargs.get("environment"):
        return CfnginContext(config=config, **kwargs)
    return CfnginContext(config=config, environment={}, **kwargs)
Beispiel #14
0
    def setUp(self) -> None:
        """Run before tests."""
        self.count = 0
        self.config = CfnginConfig.parse_obj({"namespace": "namespace"})
        self.context = CfnginContext(config=self.config)

        class FakeLookup(LookupHandler):
            """False Lookup."""

            # pylint: disable=arguments-differ
            @classmethod
            def handle(cls, value: str, *__args: Any, **__kwargs: Any) -> str:  # type: ignore
                """Perform the lookup."""
                return "test"

        register_lookup_handler("noop", FakeLookup)
Beispiel #15
0
    def setUp(self) -> None:
        """Run before tests."""
        self.sd = {"name": "test"}  # pylint: disable=invalid-name
        self.config = CfnginConfig.parse_obj({"namespace": "namespace"})
        self.context = CfnginContext(config=self.config)
        self.stack = Stack(definition=generate_definition("vpc", 1),
                           context=self.context)

        class FakeLookup(LookupHandler):
            """False Lookup."""

            # pylint: disable=arguments-differ,unused-argument
            @classmethod
            def handle(cls, value: str, *__args: Any,
                       **__kwargs: Any) -> str:  # type: ignore
                """Perform the lookup."""
                return "test"

        register_lookup_handler("noop", FakeLookup)
Beispiel #16
0
    def test_path_relative(self) -> None:
        """Test path relative."""
        with self.temp_directory_with_files(["test/test.py"]) as temp_dir:
            results = self.run_hook(
                functions={"MyFunction": {
                    "path": "test"
                }},
                context=CfnginContext(
                    config=CfnginConfig.parse_obj({
                        "namespace": "test",
                        "cfngin_bucket": "test"
                    }),
                    config_path=Path(str(temp_dir.path)),
                ),
            )

        self.assertIsNotNone(results)

        code = results.get("MyFunction")
        self.assertIsInstance(code, Code)
        self.assert_s3_zip_file_list(code.S3Bucket, code.S3Key, ["test.py"])
Beispiel #17
0
 def _get_context(self,
                  extra_config_args: Optional[Dict[str, Any]] = None,
                  **kwargs: Any) -> CfnginContext:
     """Get context."""
     config: Dict[str, Any] = {
         "namespace":
         "namespace",
         "stacks": [
             {
                 "name": "vpc",
                 "template_path": "."
             },
             {
                 "name": "bastion",
                 "template_path": ".",
                 "variables": {
                     "test": "${output vpc::something}"
                 },
             },
             {
                 "name": "db",
                 "template_path": ".",
                 "variables": {
                     "test": "${output vpc::something}",
                     "else": "${output bastion::something}",
                 },
             },
             {
                 "name": "other",
                 "template_path": ".",
                 "variables": {}
             },
         ],
     }
     if extra_config_args:
         config.update(extra_config_args)
     return CfnginContext(config=CfnginConfig.parse_obj(config), **kwargs)
Beispiel #18
0
 def test_upload_to_s3(self, config: Dict[str, Any],
                       expected: bool) -> None:
     """Test upload_to_s3."""
     assert (CfnginContext(
         config=CfnginConfig.parse_obj(config)).upload_to_s3 is expected)
Beispiel #19
0
 def test_namespace(self) -> None:
     """Test namespace."""
     config = CfnginConfig.parse_obj({"namespace": "test"})
     assert CfnginContext(config=config).namespace == config.namespace
Beispiel #20
0
 def test_persistent_graph_location_empty(
         self, config_ext: Dict[str, str]) -> None:
     """Test persistent_graph_location."""
     config = CfnginConfig.parse_obj({"namespace": "test", **config_ext})
     assert CfnginContext(config=config).persistent_graph_location == {}
Beispiel #21
0
 def test_base_fqn(self, expected: str, namespace: str) -> None:
     """Test base_fqn."""
     obj = CfnginContext(
         config=CfnginConfig.parse_obj({"namespace": namespace}))
     assert obj.base_fqn == expected
Beispiel #22
0
class TestCFNginContext:  # pylint: disable=too-many-public-methods
    """Test runway.context._cfngin.CFNginContext."""

    config = CfnginConfig.parse_obj({
        "namespace":
        "test",
        "stacks": [
            {
                "name": "stack1",
                "template_path": "."
            },
            {
                "name": "stack2",
                "template_path": "."
            },
        ],
    })
    env = DeployEnvironment(explicit_name="test")
    persist_graph_raw_config = {
        "namespace":
        "test",
        "cfngin_bucket":
        "cfngin-test",
        "cfngin_bucket_region":
        "us-east-1",
        "persistent_graph_key":
        "test.json",
        "stacks": [
            {
                "name": "stack1",
                "template_path": "."
            },
            {
                "name": "stack2",
                "template_path": ".",
                "requires": ["stack1"]
            },
        ],
    }
    persist_graph_raw: Dict[str, Set[str]] = {
        "stack1": set(),
        "stack2": {"stack1"}
    }
    persist_graph_config = CfnginConfig.parse_obj(persist_graph_raw_config)

    @pytest.mark.parametrize(
        "namespace, expected",
        [
            ("test", "test"),
            ("test-01", "test-01"),
            ("test.01", "test-01"),
            ("Test.01", "test-01"),
        ],
    )
    def test_base_fqn(self, expected: str, namespace: str) -> None:
        """Test base_fqn."""
        obj = CfnginContext(
            config=CfnginConfig.parse_obj({"namespace": namespace}))
        assert obj.base_fqn == expected

    def test_bucket_name_config(self, mocker: MockerFixture) -> None:
        """Test bucket_name from Config."""
        mocker.patch.object(CfnginContext, "upload_to_s3", True)
        assert (CfnginContext(
            config=CfnginConfig.parse_obj({
                "namespace": "test",
                "cfngin_bucket": "test-bucket"
            })).bucket_name == "test-bucket")

    def test_bucket_name_generated(self, mocker: MockerFixture) -> None:
        """Test bucket_name generated."""
        mocker.patch.object(CfnginContext, "upload_to_s3", True)
        assert CfnginContext(
            config=self.config).bucket_name == "cfngin-test-us-east-1"

    def test_bucket_name_none(self, mocker: MockerFixture) -> None:
        """Test bucket_name is None."""
        mocker.patch.object(CfnginContext, "upload_to_s3", False)
        assert CfnginContext().bucket_name is None

    def test_copy(self) -> None:
        """Test copy."""
        obj = CfnginContext(deploy_environment=self.env)
        obj_copy = obj.copy()
        assert obj_copy != obj
        assert obj_copy.config == obj.config
        assert obj_copy.env != obj.env

    def test_get_fqn(self, mocker: MockerFixture) -> None:
        """Test get_fqn."""
        mock_get_fqn = mocker.patch(f"{MODULE}.get_fqn",
                                    return_value="success")
        obj = CfnginContext(config=self.config)
        assert obj.get_fqn("name") == "success"
        mock_get_fqn.assert_called_once_with(obj.base_fqn,
                                             self.config.namespace_delimiter,
                                             "name")

    def test_get_stack(self) -> None:
        """Test get_stack."""
        obj = CfnginContext(config=self.config)
        assert obj.get_stack("test-stack1") == obj.stacks[0]
        # namespace is added if not provided
        assert obj.get_stack("stack1") == obj.stacks[0]
        assert not obj.get_stack("dev-stack1")
        assert not obj.get_stack("stack12")

    def test_init(self, tmp_path: Path) -> None:
        """Test init."""
        obj = CfnginContext(
            config=self.config,
            config_path=tmp_path,
            deploy_environment=self.env,
            force_stacks=["stack-01"],
            parameters={"key": "val"},
            stack_names=["stack-02"],
        )
        assert obj.bucket_region == self.env.aws_region
        assert obj.config == self.config
        assert obj.config_path == tmp_path
        assert obj.env == self.env
        assert obj.force_stacks == ["stack-01"]
        assert obj.hook_data == {}
        assert obj.logger
        assert obj.parameters == {"key": "val"}
        assert obj.stack_names == ["stack-02"]

    def test_init_defaults(self) -> None:
        """Test init defaults."""
        obj = CfnginContext()
        assert obj.bucket_region == self.env.aws_region
        assert isinstance(obj.config, CfnginConfig)
        assert obj.config.namespace == "example"
        assert obj.config_path == Path.cwd()
        assert isinstance(obj.env, DeployEnvironment)
        assert obj.force_stacks == []
        assert obj.hook_data == {}
        assert obj.logger
        assert obj.parameters == {}
        assert obj.stack_names == []

    def test_lock_persistent_graph_locked(self, mocker: MockerFixture) -> None:
        """Test lock_persistent_graph no graph."""
        mocker.patch.object(CfnginContext, "persistent_graph_locked", True)
        mocker.patch.object(CfnginContext, "persistent_graph", True)
        with pytest.raises(PersistentGraphLocked):
            CfnginContext().lock_persistent_graph("123")

    def test_lock_persistent_graph_no_graph(self,
                                            mocker: MockerFixture) -> None:
        """Test lock_persistent_graph no graph."""
        mocker.patch.object(CfnginContext, "persistent_graph", None)
        assert CfnginContext().lock_persistent_graph("123") is None

    def test_lock_persistent_graph_no_such_key(self,
                                               mocker: MockerFixture) -> None:
        """Test lock_persistent_graph NoSuchKey."""
        mocker.patch.object(
            CfnginContext,
            "persistent_graph_location",
            {
                "Bucket": "test-bucket",
                "Key": "something.json"
            },
        )
        mocker.patch.object(CfnginContext, "persistent_graph_locked", False)
        mocker.patch.object(CfnginContext, "persistent_graph", True)
        obj = CfnginContext()
        stubber = Stubber(obj.s3_client)
        stubber.add_client_error("put_object_tagging", "NoSuchKey")
        with stubber, pytest.raises(PersistentGraphCannotLock):
            obj.lock_persistent_graph("123")

    def test_lock_persistent_graph(self, mocker: MockerFixture) -> None:
        """Test lock_persistent_graph."""
        mocker.patch.object(
            CfnginContext,
            "persistent_graph_location",
            {
                "Bucket": "test-bucket",
                "Key": "something.json"
            },
        )
        mocker.patch.object(CfnginContext, "persistent_graph_locked", False)
        mocker.patch.object(CfnginContext, "persistent_graph", True)
        obj = CfnginContext()
        stubber = Stubber(obj.s3_client)
        stubber.add_response(
            "put_object_tagging",
            {},
            {
                "Tagging": {
                    # pylint: disable=protected-access
                    "TagSet": [{
                        "Key": obj._persistent_graph_lock_tag,
                        "Value": "123"
                    }]
                },
                **obj.persistent_graph_location,
            },
        )
        with stubber:
            assert not obj.lock_persistent_graph("123")

    def test_mappings(self) -> None:
        """Test mappings."""
        config = CfnginConfig.parse_obj({
            "namespace": "test",
            "mappings": {
                "my_map": {
                    "something": {
                        "key": "val"
                    }
                }
            }
        })
        assert CfnginContext(config=config).mappings == config.mappings

    def test_namespace(self) -> None:
        """Test namespace."""
        config = CfnginConfig.parse_obj({"namespace": "test"})
        assert CfnginContext(config=config).namespace == config.namespace

    def test_namespace_delimiter(self) -> None:
        """Test namespace_delimiter."""
        config = CfnginConfig.parse_obj({
            "namespace": "test",
            "namespace_delimiter": "."
        })
        assert (CfnginContext(
            config=config).namespace_delimiter == config.namespace_delimiter)

    def test_persistent_graph_no_location(self, mocker: MockerFixture) -> None:
        """Test persistent_graph no persistent_graph_location."""
        mocker.patch.object(CfnginContext, "persistent_graph_location", {})
        assert CfnginContext().persistent_graph is None

    def test_persistent_graph_s3_not_verified(self,
                                              mocker: MockerFixture) -> None:
        """Test persistent_graph s3 not verified."""
        mock_graph = mocker.patch(
            f"{MODULE}.Graph",
            MagicMock(from_dict=MagicMock(return_value="success")))
        mocker.patch.object(
            CfnginContext,
            "persistent_graph_location",
            {
                "Bucket": "test-bucket",
                "key": "something.json"
            },
        )
        mocker.patch.object(CfnginContext, "s3_bucket_verified", False)
        obj = CfnginContext()
        assert obj.persistent_graph == "success"
        mock_graph.from_dict.assert_called_once_with({}, obj)

    def test_persistent_graph_no_such_key(self, mocker: MockerFixture) -> None:
        """Test persistent_graph NoSuchKey."""
        mocker.patch.object(
            CfnginContext,
            "persistent_graph_location",
            {
                "Bucket": "test-bucket",
                "Key": "something.json"
            },
        )
        mocker.patch.object(CfnginContext, "s3_bucket_verified", True)
        obj = CfnginContext()
        stubber = Stubber(obj.s3_client)

        stubber.add_client_error("get_object", "NoSuchKey")
        stubber.add_response(
            "put_object",
            {},
            {
                "Body": "{}".encode(),
                "ServerSideEncryption": "AES256",
                "ACL": "bucket-owner-full-control",
                "ContentType": "application/json",
                **obj.persistent_graph_location,
            },
        )

        with stubber:
            assert isinstance(obj.persistent_graph, Graph)
            assert obj.persistent_graph.to_dict() == {}

    def test_persistent_graph(self, mocker: MockerFixture) -> None:
        """Test persistent_graph."""
        mocker.patch.object(
            CfnginContext,
            "persistent_graph_location",
            {
                "Bucket": "test-bucket",
                "Key": "something.json"
            },
        )
        mocker.patch.object(CfnginContext, "s3_bucket_verified", True)
        obj = CfnginContext()
        stubber = Stubber(obj.s3_client)

        stubber.add_response(
            "get_object",
            {"Body": gen_s3_object_content(self.persist_graph_raw)},
            {
                "ResponseContentType": "application/json",
                **obj.persistent_graph_location,
            },
        )

        with stubber:
            assert isinstance(obj.persistent_graph, Graph)
            assert obj.persistent_graph.to_dict() == self.persist_graph_raw

    def test_persistent_graph_location_add_json(self) -> None:
        """Test persistent_graph_location adds `.json` extension."""
        config = CfnginConfig.parse_obj({
            "namespace": "test",
            "cfngin_bucket": "test-bucket",
            "persistent_graph_key": "something",
        })
        obj = CfnginContext(config=config)
        assert obj.persistent_graph_location["Bucket"] == config.cfngin_bucket
        assert (
            obj.persistent_graph_location["Key"] ==
            f"persistent_graphs/{config.namespace}/{config.persistent_graph_key}.json"
        )

    @pytest.mark.parametrize(
        "config_ext",
        [
            {
                "cfngin_bucket": "something"
            },
            {
                "cfngin_bucket": "",
                "persistent_graph_key": "something"
            },
        ],
    )
    def test_persistent_graph_location_empty(
            self, config_ext: Dict[str, str]) -> None:
        """Test persistent_graph_location."""
        config = CfnginConfig.parse_obj({"namespace": "test", **config_ext})
        assert CfnginContext(config=config).persistent_graph_location == {}

    def test_persistent_graph_location(self) -> None:
        """Test persistent_graph_location."""
        config = CfnginConfig.parse_obj({
            "namespace":
            "test",
            "cfngin_bucket":
            "test-bucket",
            "persistent_graph_key":
            "something.json",
        })
        obj = CfnginContext(config=config)
        assert obj.persistent_graph_location["Bucket"] == config.cfngin_bucket
        assert (
            obj.persistent_graph_location["Key"] ==
            f"persistent_graphs/{config.namespace}/{config.persistent_graph_key}"
        )

    def test_persistent_graph_lock_code_none(self,
                                             mocker: MockerFixture) -> None:
        """Test persistent_graph_lock_code None."""
        mocker.patch.object(CfnginContext, "persistent_graph_location", False)
        assert not CfnginContext().persistent_graph_lock_code
        mocker.patch.object(CfnginContext, "persistent_graph_location", True)
        mocker.patch.object(CfnginContext, "persistent_graph_tags",
                            {"key": "val"})
        assert not CfnginContext().persistent_graph_lock_code

    def test_persistent_graph_lock_code(self, mocker: MockerFixture) -> None:
        """Test persistent_graph_lock_code."""
        mocker.patch.object(CfnginContext, "persistent_graph_location", True)
        mocker.patch.object(CfnginContext, "persistent_graph_tags",
                            {"cfngin_lock_code": "lock code"})
        assert CfnginContext().persistent_graph_lock_code == "lock code"

    def test_persistent_graph_locked_no_code(self,
                                             mocker: MockerFixture) -> None:
        """Test persistent_graph_locked no persistent_graph_lock_code."""
        mocker.patch.object(CfnginContext, "persistent_graph", True)
        mocker.patch.object(CfnginContext, "persistent_graph_lock_code", None)
        assert CfnginContext().persistent_graph_locked is False

    def test_persistent_graph_locked_no_graph(self,
                                              mocker: MockerFixture) -> None:
        """Test persistent_graph_locked no persistent_graph."""
        mocker.patch.object(CfnginContext, "persistent_graph", {})
        assert CfnginContext().persistent_graph_locked is False

    def test_persistent_graph_locked(self, mocker: MockerFixture) -> None:
        """Test persistent_graph_locked."""
        mocker.patch.object(CfnginContext, "persistent_graph", True)
        mocker.patch.object(CfnginContext, "persistent_graph_lock_code",
                            "something")
        assert CfnginContext().persistent_graph_locked is True

    def test_persistent_graph_tags_no_such_key(self,
                                               mocker: MockerFixture) -> None:
        """Test persistent_graph_tags NoSuchKey."""
        mocker.patch.object(
            CfnginContext,
            "persistent_graph_location",
            {
                "Bucket": "test-bucket",
                "Key": "persistent_graphs/test/something.json"
            },
        )
        obj = CfnginContext()
        stubber = Stubber(obj.s3_client)
        stubber.add_client_error("get_object_tagging", "NoSuchKey")
        with stubber:
            assert obj.persistent_graph_tags == {}

    def test_persistent_graph_tags(self, mocker: MockerFixture) -> None:
        """Test persistent_graph_tags."""
        bucket = "test-bucket"
        key = "persistent_graphs/test/something.json"
        mocker.patch.object(CfnginContext, "persistent_graph_location", {
            "Bucket": bucket,
            "Key": key
        })
        obj = CfnginContext()
        stubber = Stubber(obj.s3_client)

        stubber.add_response("get_object_tagging", {"TagSet": []},
                             obj.persistent_graph_location)
        stubber.add_response(
            "get_object_tagging",
            {"TagSet": [{
                "Key": "key",
                "Value": "val"
            }]},
            obj.persistent_graph_location,
        )

        with stubber:
            assert obj.persistent_graph_tags == {}
            assert obj.persistent_graph_tags == {"key": "val"}

    def test_put_persistent_graph_empty(self, mocker: MockerFixture) -> None:
        """Test put_persistent_graph empty."""
        mocker.patch.object(
            CfnginContext,
            "persistent_graph_location",
            {
                "Bucket": "test-bucket",
                "Key": "something.json"
            },
        )
        obj = CfnginContext()
        obj.persistent_graph = Graph.from_dict({}, context=obj)
        stubber = Stubber(obj.s3_client)
        stubber.add_response("delete_object", {},
                             obj.persistent_graph_location)
        with stubber:
            assert not obj.put_persistent_graph("123")

    def test_put_persistent_graph_lock_code_mismatch(
            self, mocker: MockerFixture) -> None:
        """Test put_persistent_graph lock code mismatch."""
        mocker.patch.object(
            CfnginContext,
            "persistent_graph_location",
            {
                "Bucket": "test-bucket",
                "Key": "something.json"
            },
        )
        mocker.patch.object(CfnginContext, "persistent_graph_locked", True)
        mocker.patch.object(CfnginContext, "persistent_graph_lock_code", "0")
        obj = CfnginContext()
        obj.persistent_graph = Graph.from_dict(self.persist_graph_raw,
                                               context=obj)
        with pytest.raises(PersistentGraphLockCodeMissmatch):
            obj.put_persistent_graph("123")

    def test_put_persistent_graph_not_locked(self,
                                             mocker: MockerFixture) -> None:
        """Test put_persistent_graph not locked."""
        mocker.patch.object(
            CfnginContext,
            "persistent_graph_location",
            {
                "Bucket": "test-bucket",
                "Key": "something.json"
            },
        )
        mocker.patch.object(CfnginContext, "persistent_graph_locked", False)
        obj = CfnginContext()
        obj.persistent_graph = Graph.from_dict(self.persist_graph_raw,
                                               context=obj)
        with pytest.raises(PersistentGraphUnlocked):
            obj.put_persistent_graph("123")

    def test_put_persistent_graph_no_graph(self,
                                           mocker: MockerFixture) -> None:
        """Test put_persistent_graph n persistent_graph."""
        mocker.patch.object(CfnginContext, "persistent_graph", False)
        assert not CfnginContext().put_persistent_graph("123")

    def test_put_persistent_graph(self, mocker: MockerFixture) -> None:
        """Test put_persistent_graph."""
        mocker.patch.object(
            CfnginContext,
            "persistent_graph_location",
            {
                "Bucket": "test-bucket",
                "Key": "something.json"
            },
        )
        mocker.patch.object(CfnginContext, "persistent_graph_locked", True)
        mocker.patch.object(CfnginContext, "persistent_graph_lock_code", "123")
        obj = CfnginContext()
        obj.persistent_graph = Graph.from_dict(self.persist_graph_raw,
                                               context=obj)
        stubber = Stubber(obj.s3_client)
        stubber.add_response(
            "put_object",
            {},
            {
                "Body":
                json.dumps(self.persist_graph_raw,
                           default=json_serial,
                           indent=4).encode(),
                "ServerSideEncryption":
                "AES256",
                "ACL":
                "bucket-owner-full-control",
                "ContentType":
                "application/json",
                "Tagging":
                "cfngin_lock_code=123",
                **obj.persistent_graph_location,
            },
        )
        with stubber:
            assert not obj.put_persistent_graph("123")

    def test_s3_bucket_verified_no_bucket(self, mocker: MockerFixture) -> None:
        """Test s3_bucket_verified no bucket."""
        mocker.patch.object(CfnginContext, "bucket_name", None)
        assert CfnginContext().s3_bucket_verified is False

    def test_s3_bucket_verified(self, mocker: MockerFixture) -> None:
        """Test s3_bucket_verified."""
        mock_ensure_s3_bucket = mocker.patch(f"{MODULE}.ensure_s3_bucket")
        mocker.patch.object(CfnginContext, "bucket_name", "test-bucket")
        mocker.patch.object(CfnginContext, "persistent_graph_location", {})
        obj = CfnginContext()
        assert obj.s3_bucket_verified is True
        assert obj.s3_bucket_verified is True  # value should be cached
        mock_ensure_s3_bucket.assert_called_once_with(obj.s3_client,
                                                      obj.bucket_name,
                                                      obj.bucket_region,
                                                      persist_graph=False)

    def test_s3_client(self, mocker: MockerFixture) -> None:
        """Test s3_client."""
        mock_client = MagicMock()
        mock_session = MagicMock(client=MagicMock(return_value=mock_client))
        mock_get_session = mocker.patch.object(CfnginContext,
                                               "get_session",
                                               return_value=mock_session)
        assert CfnginContext(
            deploy_environment=self.env).s3_client == mock_client
        mock_get_session.assert_called_once_with(region=self.env.aws_region)
        mock_session.client.assert_called_once_with("s3")

    def test_set_hook_data_key_error(self) -> None:
        """Test set_hook_data KeyError."""
        obj = CfnginContext()
        obj.set_hook_data("test", {})
        with pytest.raises(KeyError):
            obj.set_hook_data("test", {"key": "val"})

    @pytest.mark.parametrize("data",
                             ["string", 1, 1.0, ["1"], {"1", "2"}, ("1", "2")])
    def test_set_hook_data_type_error(self, data: Any) -> None:
        """Test set_hook_data TypeError."""
        with pytest.raises(TypeError):
            CfnginContext().set_hook_data("test", data)  # type: ignore

    def test_set_hook_data(self) -> None:
        """Test set_hook_data."""
        obj = CfnginContext()
        obj.set_hook_data("test", {"key": "val"})
        assert obj.hook_data == {"test": {"key": "val"}}

    def test_stacks_dict(self) -> None:
        """Test stacks_dict."""
        obj = CfnginContext(config=self.config)
        assert obj.stacks_dict == {
            "test-stack1": obj.stacks[0],
            "test-stack2": obj.stacks[1],
        }

    def test_stacks(self) -> None:
        """Test stacks."""
        obj = CfnginContext(config=self.config)
        assert len(obj.stacks) == len(self.config.stacks)
        assert isinstance(obj.stacks[0], Stack)
        assert obj.stacks[0].name == self.config.stacks[0].name
        assert isinstance(obj.stacks[1], Stack)
        assert obj.stacks[1].name == self.config.stacks[1].name

    def test_tags_empty(self) -> None:
        """Test tags empty."""
        obj = CfnginContext(config=CfnginConfig.parse_obj({
            "namespace": "test",
            "tags": {}
        }))
        assert obj.tags == {}

    def test_tags_none(self) -> None:
        """Test tags None."""
        obj = CfnginContext(config=CfnginConfig.parse_obj({
            "namespace": "test",
            "tags": None
        }))
        assert obj.tags == {"cfngin_namespace": obj.config.namespace}

    def test_tags(self) -> None:
        """Test tags."""
        obj = CfnginContext(config=CfnginConfig.parse_obj({
            "namespace": "test",
            "tags": {
                "key": "val"
            }
        }))
        assert obj.tags == obj.config.tags

    def test_template_indent(self) -> None:
        """Test template_indent."""
        assert (CfnginContext(
            config=self.config).template_indent == self.config.template_indent)

    @pytest.mark.parametrize(
        "config, expected",
        [
            ({
                "namespace": "test"
            }, True),
            ({
                "namespace": ""
            }, False),
            ({
                "namespace": "test",
                "cfngin_bucket": ""
            }, False),
            ({
                "namespace": "",
                "cfngin_bucket": "something"
            }, True),
            ({
                "namespace": "test",
                "cfngin_bucket": "something"
            }, True),
        ],
    )
    def test_upload_to_s3(self, config: Dict[str, Any],
                          expected: bool) -> None:
        """Test upload_to_s3."""
        assert (CfnginContext(
            config=CfnginConfig.parse_obj(config)).upload_to_s3 is expected)

    def test_unlock_persistent_graph_empty_no_such_key(
            self, mocker: MockerFixture) -> None:
        """Test unlock_persistent_graph empty graph NoSuchKey."""
        mocker.patch.object(
            CfnginContext,
            "persistent_graph_location",
            {
                "Bucket": "test-bucket",
                "Key": "something.json"
            },
        )
        obj = CfnginContext()
        obj.persistent_graph = Graph.from_dict({}, context=obj)
        stubber = Stubber(obj.s3_client)
        stubber.add_client_error("get_object", "NoSuchKey")
        with stubber:
            assert obj.unlock_persistent_graph("123")

    def test_unlock_persistent_graph_lock_code_mismatch(
            self, mocker: MockerFixture) -> None:
        """Test unlock_persistent_graph lock code mismatch."""
        mocker.patch.object(
            CfnginContext,
            "persistent_graph_location",
            {
                "Bucket": "test-bucket",
                "Key": "something.json"
            },
        )
        mocker.patch.object(CfnginContext, "persistent_graph_locked", True)
        mocker.patch.object(CfnginContext, "persistent_graph_lock_code", "0")
        obj = CfnginContext()
        obj.persistent_graph = Graph.from_dict(self.persist_graph_raw,
                                               context=obj)
        with pytest.raises(PersistentGraphCannotUnlock):
            assert obj.unlock_persistent_graph("123")

    def test_unlock_persistent_graph_not_locked(self,
                                                mocker: MockerFixture) -> None:
        """Test unlock_persistent_graph."""
        mocker.patch.object(
            CfnginContext,
            "persistent_graph_location",
            {
                "Bucket": "test-bucket",
                "Key": "something.json"
            },
        )
        mocker.patch.object(CfnginContext, "persistent_graph_locked", False)
        mocker.patch.object(CfnginContext, "persistent_graph_lock_code", "123")
        obj = CfnginContext()
        obj.persistent_graph = Graph.from_dict(self.persist_graph_raw,
                                               context=obj)
        with pytest.raises(PersistentGraphCannotUnlock):
            obj.unlock_persistent_graph("123")

    def test_unlock_persistent_graph_no_graph(self,
                                              mocker: MockerFixture) -> None:
        """Test unlock_persistent_graph no graph."""
        mocker.patch.object(CfnginContext, "persistent_graph", False)
        assert CfnginContext().unlock_persistent_graph("123")

    def test_unlock_persistent_graph_no_such_key(
            self, mocker: MockerFixture) -> None:
        """Test unlock_persistent_graph empty graph NoSuchKey."""
        mocker.patch.object(
            CfnginContext,
            "persistent_graph_location",
            {
                "Bucket": "test-bucket",
                "Key": "something.json"
            },
        )
        mocker.patch.object(CfnginContext, "persistent_graph_locked", True)
        mocker.patch.object(CfnginContext, "persistent_graph_lock_code", "123")
        obj = CfnginContext()
        obj.persistent_graph = Graph.from_dict({}, context=obj)
        stubber = Stubber(obj.s3_client)
        stubber.add_response(
            "get_object",
            {"Body": "{}".encode()},
            {
                "ResponseContentType": "application/json",
                **obj.persistent_graph_location,
            },
        )
        stubber.add_client_error("delete_object_tagging", "NoSuchKey")
        with stubber:
            assert obj.unlock_persistent_graph("123")

    @pytest.mark.parametrize("graph_dict",
                             cast(List[Dict[str, List[str]]], [{
                                 "stack0": []
                             }, {}]))
    def test_unlock_persistent_graph(self, graph_dict: Dict[str, List[str]],
                                     mocker: MockerFixture) -> None:
        """Test unlock_persistent_graph."""
        mocker.patch.object(
            CfnginContext,
            "persistent_graph_location",
            {
                "Bucket": "test-bucket",
                "Key": "something.json"
            },
        )
        mocker.patch.object(CfnginContext, "persistent_graph_locked", True)
        mocker.patch.object(CfnginContext, "persistent_graph_lock_code", "123")
        obj = CfnginContext()
        obj.persistent_graph = Graph.from_dict(graph_dict, context=obj)
        stubber = Stubber(obj.s3_client)
        if not graph_dict:
            stubber.add_response(
                "get_object",
                {"Body": "{}".encode()},
                {
                    "ResponseContentType": "application/json",
                    **obj.persistent_graph_location,
                },
            )
        stubber.add_response("delete_object_tagging", {},
                             obj.persistent_graph_location)
        with stubber:
            assert obj.unlock_persistent_graph("123")
Beispiel #23
0
 def setUp(self) -> None:
     """Run before tests."""
     self.provider = MagicMock()
     self.context = CfnginContext(
         config=CfnginConfig.parse_obj({"namespace": "ns"}))