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_unlock_persistent_graph(self): """Return 'True' when delete tag is successful.""" code = '0000' context = Context(config=self.persist_graph_config) context._s3_bucket_verified = True context._persistent_graph = Graph.from_dict({'stack1': []}, context) stubber = Stubber(context.s3_conn) stubber.add_response( 'get_object_tagging', {'TagSet': gen_tagset({context._persistent_graph_lock_tag: code})}, context.persistent_graph_location) stubber.add_response('delete_object_tagging', {}, context.persistent_graph_location) with stubber: self.assertTrue(context.unlock_persistent_graph(code)) stubber.assert_no_pending_responses()
def test_run_persist( self, mock_execute: MagicMock, mock_unlock: MagicMock, mock_lock: MagicMock, mock_graph_tags: PropertyMock, ) -> None: """Test run persist.""" mock_graph_tags.return_value = {} context = self._get_context( extra_config_args={"persistent_graph_key": "test.json"}) context._persistent_graph = Graph.from_steps( [Step.from_stack_name("removed", context)]) deploy_action = deploy.Action(context=context) deploy_action.run() mock_graph_tags.assert_called_once() mock_lock.assert_called_once() mock_execute.assert_called_once() mock_unlock.assert_called_once()
def test_unlock_persistent_graph_no_object(self): """Return 'None' when object does not exist. This can occur if the object is deleted by 'put_persistent_graph'. """ code = "0000" context = Context(config=self.persist_graph_config) context._s3_bucket_verified = True context._persistent_graph = Graph() stubber = Stubber(context.s3_conn) expected_params = context.persistent_graph_location.copy() expected_params.update({"ResponseContentType": "application/json"}) stubber.add_client_error("get_object", "NoSuchKey", expected_params=expected_params) with stubber: assert context.unlock_persistent_graph(code) stubber.assert_no_pending_responses()
def test_unlock_persistent_graph_code_missmatch(self): """Error raised when local code does not match object.""" code = "0000" context = Context(config=self.persist_graph_config) context._s3_bucket_verified = True context._persistent_graph = Graph.from_dict({"stack1": []}, context) stubber = Stubber(context.s3_conn) stubber.add_response( "get_object_tagging", { "TagSet": gen_tagset( {context._persistent_graph_lock_tag: "1111"}) }, context.persistent_graph_location, ) with stubber: with self.assertRaises(PersistentGraphCannotUnlock): context.unlock_persistent_graph(code) stubber.assert_no_pending_responses()
def test_lock_persistent_graph(self): """Return 'None' when lock is successful.""" code = "0000" context = Context(config=self.persist_graph_config) context._s3_bucket_verified = True context._persistent_graph = Graph() stubber = Stubber(context.s3_conn) expected_params = { "Tagging": { "TagSet": gen_tagset({context._persistent_graph_lock_tag: code}) } } expected_params.update(context.persistent_graph_location) stubber.add_response("get_object_tagging", {"TagSet": []}, context.persistent_graph_location) stubber.add_response("put_object_tagging", {}, expected_params) with stubber: self.assertIsNone(context.lock_persistent_graph(code)) stubber.assert_no_pending_responses()
def test_dump(self) -> None: """Test dump.""" requires: List[str] = [] steps: List[Step] = [] for i in range(5): overrides = { "variables": { "PublicSubnets": "1", "SshKeyName": "1", "PrivateSubnets": "1", "Random": "${noop something}", }, "requires": requires, } stack = Stack( definition=generate_definition("vpc", i, **overrides), context=self.context, ) requires = [stack.name] steps += [Step(stack)] graph = Graph.from_steps(steps) plan = Plan(description="Test", graph=graph) tmp_dir = tempfile.mkdtemp() try: plan.dump(directory=tmp_dir, context=self.context) for step in plan.steps: template_path = os.path.join( tmp_dir, stack_template_key_name(step.stack.blueprint) # type: ignore ) self.assertTrue(os.path.isfile(template_path)) finally: shutil.rmtree(tmp_dir)
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_generate_plan_with_persist_exclude(self, mock_stack_action, mock_tags): """Test generate plan with persist exclude.""" mock_stack_action.return_value = MagicMock() mock_tags.return_value = {} context = mock_context(namespace='test', extra_config_args=self.config_persist, region=self.region) persist_step = Step.from_stack_name('removed', context) context._persistent_graph = Graph.from_steps([persist_step]) action = BaseAction(context=context, provider_builder=MockProviderBuilder( self.provider, region=self.region)) plan = action._generate_plan(include_persistent_graph=False) self.assertIsInstance(plan, Plan) # order is different between python2/3 so can't compare dicts result_graph_dict = plan.graph.to_dict() self.assertEqual(2, len(result_graph_dict)) self.assertEqual(set(), result_graph_dict['stack1']) self.assertEqual(set(['stack1']), result_graph_dict['stack2']) self.assertEqual(BaseAction.DESCRIPTION, plan.description) self.assertTrue(plan.require_unlocked)
def test_execute_plan_cancelled(self) -> None: """Test execute plan cancelled.""" vpc = Stack(definition=generate_definition("vpc", 1), context=self.context) bastion = Stack( definition=generate_definition("bastion", 1, requires=[vpc.name]), context=self.context, ) calls: List[str] = [] def fn(stack: Stack, status: Optional[Status] = None) -> Status: calls.append(stack.fqn) if stack.fqn == vpc_step.name: raise CancelExecution return COMPLETE vpc_step = Step(vpc, fn=fn) bastion_step = Step(bastion, fn=fn) graph = Graph.from_steps([vpc_step, bastion_step]) plan = Plan(description="Test", graph=graph) plan.execute(walk) self.assertEqual(calls, ["namespace-vpc.1", "namespace-bastion.1"])
def test_lock_persistent_graph_locked(self): """Error raised when when object is locked.""" code = '0000' context = Context(config=self.persist_graph_config) context._s3_bucket_verified = True context._persistent_graph = Graph() stubber = Stubber(context.s3_conn) expected_params = { 'Tagging': { 'TagSet': gen_tagset({context._persistent_graph_lock_tag: code}) } } expected_params.update(context.persistent_graph_location) stubber.add_response('get_object_tagging', { 'TagSet': gen_tagset({context._persistent_graph_lock_tag: '1111'}) }, context.persistent_graph_location) with stubber: with self.assertRaises(PersistentGraphLocked): context.lock_persistent_graph(code) stubber.assert_no_pending_responses()
def test_dumps(self): """Test dumps.""" graph = Graph() graph.add_steps(self.steps) self.assertEqual(json.dumps(self.graph_dict), graph.dumps())