Пример #1
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")
Пример #2
0
def runway_context(cd_test_dir: Path) -> RunwayContext:
    """Create Runway context."""
    return RunwayContext(deploy_environment=DeployEnvironment(
        explicit_name="test", root_dir=cd_test_dir))
Пример #3
0
def deploy_environment(tmp_path: Path) -> DeployEnvironment:
    """Create a deploy environment that can be used for testing."""
    return DeployEnvironment(explicit_name="test", root_dir=tmp_path)
Пример #4
0
class TestBaseContext:
    """Test runway.context._base.BaseContext."""

    env = DeployEnvironment(explicit_name="test")

    def test_boto3_credentials(self, mocker: MockerFixture) -> None:
        """Test boto3_credentials."""
        mocker.patch.object(self.env, "vars", TEST_ENV_CREDS)
        assert (BaseContext(
            deploy_environment=self.env).boto3_credentials == TEST_BOTO3_CREDS)

    def test_boto3_credentials_empty(self, mocker: MockerFixture) -> None:
        """Test boto3_credentials empty."""
        mocker.patch.object(self.env, "vars", TEST_BOTO3_CREDS)
        assert BaseContext(deploy_environment=self.env).boto3_credentials == {}

    def test_current_aws_creds(self, mocker: MockerFixture) -> None:
        """Test current_aws_creds."""
        mocker.patch.object(self.env, "vars", TEST_ENV_CREDS)
        assert (BaseContext(
            deploy_environment=self.env).current_aws_creds == TEST_ENV_CREDS)

    def test_current_aws_creds_empty(self, mocker: MockerFixture) -> None:
        """Test current_aws_creds empty."""
        mocker.patch.object(self.env, "vars", TEST_BOTO3_CREDS)
        assert BaseContext(deploy_environment=self.env).current_aws_creds == {}

    def test_is_interactive(self, mocker: MockerFixture) -> None:
        """Test is_interactive."""
        mocker.patch.object(self.env, "ci", False)
        ctx = BaseContext(deploy_environment=self.env)
        assert ctx.is_interactive

        mocker.patch.object(self.env, "ci", True)
        assert not ctx.is_interactive

    def test_is_noninteractive(self, mocker: MockerFixture) -> None:
        """Test is_noninteractive."""
        mocker.patch.object(self.env, "ci", False)
        ctx = BaseContext(deploy_environment=self.env)
        assert not ctx.is_noninteractive

        mocker.patch.object(self.env, "ci", True)
        assert ctx.is_noninteractive

    def test_get_session(self, mock_boto3_session: MagicMock,
                         mock_sso_botocore_session: MagicMock) -> None:
        """Test get_session."""
        ctx = BaseContext(deploy_environment=self.env)
        assert ctx.get_session() == mock_boto3_session.return_value
        mock_boto3_session.assert_called_once_with(
            aws_access_key_id=None,
            aws_secret_access_key=None,
            aws_session_token=None,
            botocore_session=mock_sso_botocore_session.return_value,
            region_name=None,
            profile_name=None,
        )
        mock_boto3_session.return_value._session.get_component.assert_called_once_with(
            "credential_provider")
        cred_provider = cast(
            MagicMock,
            mock_boto3_session.return_value._session.get_component.
            return_value,
        )
        cred_provider.get_provider.assert_called_once_with("assume-role")
        provider = cast(MagicMock, cred_provider.get_provider.return_value)
        assert provider.cache == {}

    def test_get_session_with_creds(
            self, mock_boto3_session: MagicMock,
            mock_sso_botocore_session: MagicMock) -> None:
        """Test get_session with credentials."""
        ctx = BaseContext(deploy_environment=self.env)
        assert ctx.get_session(
            **TEST_BOTO3_CREDS) == mock_boto3_session.return_value
        mock_boto3_session.assert_called_once_with(
            aws_access_key_id=TEST_BOTO3_CREDS["aws_access_key_id"],
            aws_secret_access_key=TEST_BOTO3_CREDS["aws_secret_access_key"],
            aws_session_token=TEST_BOTO3_CREDS["aws_session_token"],
            botocore_session=mock_sso_botocore_session.return_value,
            region_name=None,
            profile_name=None,
        )

    def test_get_session_with_profile(
            self, mock_boto3_session: MagicMock,
            mock_sso_botocore_session: MagicMock) -> None:
        """Test get_session with profile."""
        ctx = BaseContext(deploy_environment=self.env)
        assert ctx.get_session(
            profile="something") == mock_boto3_session.return_value
        mock_boto3_session.assert_called_once_with(
            aws_access_key_id=None,
            aws_secret_access_key=None,
            aws_session_token=None,
            botocore_session=mock_sso_botocore_session.return_value,
            region_name=None,
            profile_name="something",
        )

    def test_get_session_with_region(
            self, mock_boto3_session: MagicMock,
            mock_sso_botocore_session: MagicMock) -> None:
        """Test get_session with region."""
        ctx = BaseContext(deploy_environment=self.env)
        assert ctx.get_session(
            region="us-east-2") == mock_boto3_session.return_value
        mock_boto3_session.assert_called_once_with(
            aws_access_key_id=None,
            aws_secret_access_key=None,
            aws_session_token=None,
            botocore_session=mock_sso_botocore_session.return_value,
            region_name="us-east-2",
            profile_name=None,
        )

    def test_sys_info(self) -> None:
        """Test sys_info."""
        assert isinstance(
            BaseContext(deploy_environment=self.env).sys_info, SystemInfo)