def test_dict_subset_with_array_values(self): small = {'a': ['A'], 'b': [1, 2]} big = {'a': ['A', 'B', 'C'], 'b': [1, 2, 3], 'c': ['red', 'yellow']} small_nested = {'first': small} big_nested = {'first': big, 'second': big} small_subset_pred = jp.DICT_SUBSET(small) nested_subset_pred = jp.DICT_SUBSET(small_nested) # These are matching the outer source objects because they contain # the subset we are looking for. self.assertGoodResult(PathValue('', big), small_subset_pred, small_subset_pred(big)) self.assertGoodResult(PathValue('', big_nested), nested_subset_pred, nested_subset_pred(big_nested))
def test_collect_with_dict_subset(self): # See test_dict_subset_with_array_nodes for comparision. context = ExecutionContext() letters = {'a':'A', 'b':'B', 'c':'C'} numbers = {'a':1, 'b':2} both = [letters, numbers] source = {'items': both} letter_subset_pred = jp.DICT_SUBSET({'a':'A'}) path_pred = jp.PathPredicate('items', pred=letter_subset_pred) result = path_pred(context, source) mismatch_error = jp.TypeMismatchError( expect_type=(int, long, float), got_type=str, source=source, target_path=jp.PATH_SEP.join(['items', 'a']), path_value=PathValue('items[1]', numbers)) valid_result = letter_subset_pred(context, letters).clone_with_source( source=source, base_target_path='items', base_value_path='items[0]') self.assertEqual( # pylint: disable=bad-continuation jp.PathPredicateResultBuilder(source, path_pred) .add_result_candidate(PathValue('items[0]', letters), valid_result) .add_result_candidate(PathValue('items[1]', numbers), mismatch_error) .build(True), result)
def test_dict_subset_with_array_values_bad(self): context = ExecutionContext() small = {'a':['A'], 'b':[1, 2]} big = {'a':['A', 'B', 'C'], 'b':[1, 2]} small_nested = {'first':small} big_nested = {'first':big, 'second':big} big_subset_pred = jp.DICT_SUBSET(big) nested_subset_pred = jp.DICT_SUBSET(big_nested) list_subset_pred = jp.LIST_SUBSET(big['a']) self.assertBadResult( expect_value=PathValue('a', small['a']), pred=list_subset_pred, got_result=big_subset_pred(context, small), source=small, target_path='a')
def test_dict_nested_subset(self): small = {'first': 'Apple', 'second': 'Banana'} small_subset_pred = jp.DICT_SUBSET(small) big = {'first': 'Apple', 'second': 'Banana', 'third': 'Cherry'} self.assertGoodResult(PathValue('', big), small_subset_pred, small_subset_pred(big)) small_nested = {'outer': small} small_nested_subset_pred = jp.DICT_SUBSET(small_nested) big_nested = {'outer': big, 'another': big} self.assertGoodResult(PathValue('', big_nested), small_nested_subset_pred, small_nested_subset_pred(big_nested))
def list_available_images(self): """Creates a test that confirms expected available images. Returns: st.OperationContract """ logger = logging.getLogger(__name__) # Get the list of images available (to the service account we are using). context = citest.base.ExecutionContext() gcp_agent = self.gcp_observer JournalLogger.begin_context("Collecting expected available images") relation_context = "ERROR" try: logger.debug("Looking up available images.") json_doc = gcp_agent.list_resource(context, "images") for project in GCP_STANDARD_IMAGES.keys(): logger.info("Looking for images from project=%s", project) found = gcp_agent.list_resource(context, "images", project=project) for image in found: if not image.get("deprecated", None): json_doc.append(image) # Produce the list of images that we expect to receive from spinnaker # (visible to the primary service account). spinnaker_account = self.bindings["SPINNAKER_GOOGLE_ACCOUNT"] logger.debug('Configured with Spinnaker account "%s"', spinnaker_account) expect_images = [{ "account": spinnaker_account, "imageName": image["name"] } for image in json_doc] expect_images = sorted(expect_images, key=lambda k: k["imageName"]) relation_context = "VALID" finally: JournalLogger.end_context(relation=relation_context) # pylint: disable=bad-continuation builder = HttpContractBuilder(self.agent) (builder.new_clause_builder("Has Expected Images").get_url_path( "/gce/images/find").EXPECT( ov_factory.value_list_matches( [ jp.DICT_SUBSET(image_entry) for image_entry in expect_images ], strict=True, unique=True, ))) return st.OperationContract(NoOpOperation("List Available Images"), contract=builder.build())
def list_available_images(self): """Creates a test that confirms expected available images. Returns: st.OperationContract """ logger = logging.getLogger(__name__) # Get the list of images available (to the service account we are using). context = citest.base.ExecutionContext() gcp_agent = self.gcp_observer JournalLogger.begin_context('Collecting expected available images') relation_context = 'ERROR' try: logger.debug('Looking up available images.') json_doc = gcp_agent.list_resource(context, 'images') for project in GCP_STANDARD_IMAGES.keys(): logger.info('Looking for images from project=%s', project) found = gcp_agent.list_resource(context, 'images', project=project) for image in found: if not image.get('deprecated', None): json_doc.append(image) # Produce the list of images that we expect to receive from spinnaker # (visible to the primary service account). spinnaker_account = self.agent.deployed_config.get( 'providers.google.primaryCredentials.name') logger.debug('Configured with Spinnaker account "%s"', spinnaker_account) expect_images = [{ 'account': spinnaker_account, 'imageName': image['name'] } for image in json_doc] expect_images = sorted(expect_images, key=lambda k: k['imageName']) relation_context = 'VALID' finally: JournalLogger.end_context(relation=relation_context) # pylint: disable=bad-continuation builder = HttpContractBuilder(self.agent) (builder.new_clause_builder('Has Expected Images').get_url_path( '/gce/images/find').contains_match( [jp.DICT_SUBSET(image_entry) for image_entry in expect_images], match_kwargs={ 'strict': True, 'unique': True })) return st.OperationContract(NoOpOperation('List Available Images'), contract=builder.build())
def test_dict_nested_subset_exact_keys(self): context = ExecutionContext() small_dict = {'first':'Apple', 'second':'Banana'} small_nested_dict = {'outer':small_dict} # In dictionary we want exact key matches, not subkeys. operand = {'out':{'first':'Apple'}} subset_pred = jp.DICT_SUBSET(operand) self.assertEqual( jp.MissingPathError(source=small_nested_dict, target_path='out', path_value=PathValue('', small_nested_dict)), subset_pred(context, small_nested_dict)) # In dictionary we want exact key matches, not subkeys. nested_operand = {'fir':'Apple'} operand = {'outer':nested_operand} subset_pred = jp.DICT_SUBSET(operand) self.assertEqual( jp.MissingPathError(source=small_nested_dict, target_path=jp.PATH_SEP.join(['outer', 'fir']), path_value=PathValue('outer', small_dict)), subset_pred(context, small_nested_dict))
def test_dict_simple_subset(self): context = ExecutionContext() letters = {'a':'A', 'b':'B', 'c':'C'} operand = {'a': 'A', 'b': 'B'} subset_pred = jp.DICT_SUBSET(operand) self.assertGoodResult(PathValue('', letters), subset_pred, subset_pred(context, letters)) self.assertGoodResult(PathValue('', operand), subset_pred, subset_pred(context, operand)) source = {'a':'A'} self.assertEqual( jp.MissingPathError(source=source, target_path='b', path_value=PathValue('', source)), subset_pred(context, source))
def test_dict_subset_with_array_nodes(self): # See test_collect_with_dict_subset for comparison. context = ExecutionContext() letters = {'a':'A', 'b':'B', 'c':'C'} numbers = {'a':1, 'b':2} both = [letters, numbers] source = {'items': both} # This doesnt traverse through the list because we are looking for # a dictionary subset. We were expecting a dict with an 'a' but we # found only a dict with 'items'. letter_subset_pred = jp.DICT_SUBSET({'a':'A'}) self.assertEqual( jp.MissingPathError(source=source, target_path='a', path_value=PathValue('', source)), letter_subset_pred(context, source))
def test_dict_nested_subset_exact_values(self): context = ExecutionContext() small = {'first':'Apple', 'second':'Banana'} small_nested = {'outer':small} # In dictionary we want exact matches of strings, not substrings. nested_operand = {'first':'A'} operand = {'outer':nested_operand} subset_pred = jp.DICT_SUBSET(operand) self.assertEqual( jp.PathValueResult( valid=False, pred=jp.STR_EQ('A'), path_value=PathValue(jp.PATH_SEP.join(['outer', 'first']), 'Apple'), source=small_nested, target_path=jp.PATH_SEP.join(['outer', 'first'])), subset_pred(context, small_nested))
def upsert_load_balancer(self): """Creates OperationContract for upsertLoadBalancer. Calls Spinnaker's upsertLoadBalancer with a configuration, then verifies that the expected resources and configurations are visible on GCE. See the contract builder for more info on what the expectations are. """ bindings = self.bindings target_pool_name = '{0}/targetPools/{1}-tp'.format( bindings['TEST_GCE_REGION'], self.__lb_name) spec = { 'checkIntervalSec': 9, 'healthyThreshold': 3, 'unhealthyThreshold': 5, 'timeoutSec': 2, 'port': 80 } payload = self.agent.make_json_payload_from_kwargs( job=[{ 'cloudProvider': 'gce', 'provider': 'gce', 'stack': bindings['TEST_STACK'], 'detail': self.__lb_detail, 'credentials': bindings['GCE_CREDENTIALS'], 'region': bindings['TEST_GCE_REGION'], 'ipProtocol': 'TCP', 'portRange': spec['port'], 'loadBalancerName': self.__lb_name, 'healthCheck': { 'port': spec['port'], 'timeoutSec': spec['timeoutSec'], 'checkIntervalSec': spec['checkIntervalSec'], 'healthyThreshold': spec['healthyThreshold'], 'unhealthyThreshold': spec['unhealthyThreshold'], }, 'type': 'upsertLoadBalancer', 'availabilityZones': { bindings['TEST_GCE_REGION']: [] }, 'user': '******' }], description='Create Load Balancer: ' + self.__lb_name, application=self.TEST_APP) builder = gcp.GcpContractBuilder(self.gcp_observer) (builder.new_clause_builder( 'Health Check Added', retryable_for_secs=30).list_resource( 'httpHealthChecks').contains_pred_list([ jp.PathContainsPredicate('name', '%s-hc' % self.__lb_name), jp.DICT_SUBSET(spec) ])) (builder.new_clause_builder('Target Pool Added', retryable_for_secs=30).list_resource( 'targetPools').contains_path_value( 'name', '%s-tp' % self.__lb_name)) (builder.new_clause_builder( 'Forwarding Rules Added', retryable_for_secs=30).list_resource( 'forwardingRules').contains_pred_list([ jp.PathContainsPredicate('name', self.__lb_name), jp.PathContainsPredicate('target', target_pool_name) ])) return st.OperationContract(self.new_post_operation( title='upsert_load_balancer', data=payload, path='tasks'), contract=builder.build())