def test_lock_persistent_graph_no_object(self): """Error raised when when there is no object to lock.""" 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_client_error( "get_object_tagging", "NoSuchKey", expected_params=context.persistent_graph_location, ) stubber.add_client_error("put_object_tagging", "NoSuchKey", expected_params=expected_params) with stubber: with self.assertRaises(PersistentGraphCannotLock): context.lock_persistent_graph(code) stubber.assert_no_pending_responses()
def test_put_persistent_graph(self): """Return 'None' when put is successful.""" code = "0000" context = Context(config=self.persist_graph_config) context._s3_bucket_verified = True graph_dict = {"stack1": [], "stack2": ["stack1"]} context._persistent_graph = Graph.from_dict(graph_dict, context) stubber = Stubber(context.s3_conn) expected_params = { "Body": json.dumps(graph_dict, indent=4), "ServerSideEncryption": "AES256", "ACL": "bucket-owner-full-control", "ContentType": "application/json", "Tagging": "{}={}".format(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: code})}, context.persistent_graph_location, ) stubber.add_response("put_object", {}, expected_params) with stubber: self.assertIsNone(context.put_persistent_graph(code)) stubber.assert_no_pending_responses()
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_put_persistent_graph(self): """Return 'None' when put is successful.""" code = '0000' context = Context(config=self.persist_graph_config) context._s3_bucket_verified = True graph_dict = {'stack1': [], 'stack2': ['stack1']} context._persistent_graph = Graph.from_dict(graph_dict, context) stubber = Stubber(context.s3_conn) expected_params = { 'Body': json.dumps(graph_dict, indent=4), 'ServerSideEncryption': 'AES256', 'ACL': 'bucket-owner-full-control', 'ContentType': 'application/json', 'Tagging': '{}={}'.format(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: code})}, context.persistent_graph_location) stubber.add_response('put_object', {}, expected_params) with stubber: self.assertIsNone(context.put_persistent_graph(code)) stubber.assert_no_pending_responses()
def test_execute_plan_graph_locked(self): """Test execute plan with locked persistent graph.""" context = Context(config=self.config) context._persistent_graph = Graph.from_dict({"stack1": []}, context) context._persistent_graph_lock_code = "1111" plan = Plan(description="Test", graph=Graph(), context=context) print(plan.locked) with self.assertRaises(PersistentGraphLocked): plan.execute()
def test_persistent_graph_locked(self, mock_prop): """Return 'True' or 'False' based on code property.""" mock_prop.return_value = {} context = Context(config=self.persist_graph_config) context._persistent_graph = True context._persistent_graph_lock_code = True self.assertTrue(context.persistent_graph_locked) context._persistent_graph_lock_code = None self.assertFalse(context.persistent_graph_locked) mock_prop.assert_called_once()
def test_put_persistent_graph_unlocked(self): """Error raised when trying to update an unlocked object.""" 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": []}, context.persistent_graph_location) with stubber: with self.assertRaises(PersistentGraphUnlocked): context.put_persistent_graph("") stubber.assert_no_pending_responses()
def test_unlock_persistent_graph_not_locked(self): """Error raised when object is not locked.""" 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": []}, context.persistent_graph_location) with stubber: with self.assertRaises(PersistentGraphCannotUnlock): context.unlock_persistent_graph(code) stubber.assert_no_pending_responses()
def test_put_persistent_graph_empty(self): """Object deleted when persistent graph is empty.""" code = "0000" context = Context(config=self.persist_graph_config) context._s3_bucket_verified = True context._persistent_graph = Graph() stubber = Stubber(context.s3_conn) stubber.add_response("delete_object", {}, context.persistent_graph_location) with stubber: self.assertFalse(context.persistent_graph.to_dict()) self.assertIsNone(context.put_persistent_graph(code)) stubber.assert_no_pending_responses()
def test_execute_plan(self): """Test execute plan.""" context = Context(config=self.config) context.put_persistent_graph = mock.MagicMock() vpc = Stack(definition=generate_definition("vpc", 1), context=context) bastion = Stack( definition=generate_definition("bastion", 1, requires=[vpc.name]), context=context, ) removed = Stack(definition=generate_definition("removed", 1, requires=[]), context=context) context._persistent_graph = Graph.from_steps([removed]) calls = [] def _launch_stack(stack, status=None): calls.append(stack.fqn) return COMPLETE def _destroy_stack(stack, status=None): calls.append(stack.fqn) return COMPLETE graph = Graph.from_steps([ Step(removed, _destroy_stack), Step(vpc, _launch_stack), Step(bastion, _launch_stack), ]) plan = Plan(description="Test", graph=graph, context=context) plan.context._persistent_graph_lock_code = plan.lock_code plan.execute(walk) # the order these are appended changes between python2/3 self.assertIn("namespace-vpc.1", calls) self.assertIn("namespace-bastion.1", calls) self.assertIn("namespace-removed.1", calls) context.put_persistent_graph.assert_called() # order is different between python2/3 so can't compare dicts result_graph_dict = context.persistent_graph.to_dict() self.assertEqual(2, len(result_graph_dict)) self.assertEqual(set(), result_graph_dict.get("vpc.1")) self.assertEqual(set(["vpc.1"]), result_graph_dict.get("bastion.1")) self.assertIsNone(result_graph_dict.get("namespace-removed.1"))
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_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_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_put_persistent_graph_code_missmatch(self): """Error raised when provided lock 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(PersistentGraphLockCodeMissmatch): context.put_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()