def ForMissing(cls, location): update_context = updates.Context({'expect_exit': collections.OrderedDict()}, 'expect_exit', cls.EventType().UpdateMode(), was_missing=True, location=location) return cls(update_context, 0, assertions.EqualsAssertion(None), assertions.EqualsAssertion(None))
def ForMissing(cls, location): update_context = updates.Context( {'expect_file_written': OrderedDict()}, 'expect_file_written', cls.EventType().UpdateMode(), was_missing=True, location=location) return cls(update_context, assertions.EqualsAssertion(None), assertions.EqualsAssertion(None), assertions.EqualsAssertion(None), assertions.EqualsAssertion(False))
def _ForCommon(cls, mode, http_data, uri_assertion, method_assertion, extract_references): """Builder for the attributes applicable to both requests and responses.""" header_assertion = assertions.DictAssertion() for header, value in six.iteritems(http_data.get('headers', {})): header_assertion.AddAssertion( header, assertions.Assertion.ForComplex(value)) payload_json_assertion = None payload_text_assertion = None body_present = True body_data = http_data.get('body') if 'body' not in http_data or (not body_data and body_data is not None): # The body section is missing entirely or it is present and is an empty # dictionary. In these cases, the assertions are not present and will be # updated always. body_present = False payload_json_assertion = assertions.JsonAssertion().Matches( '', assertions.MISSING_VALUE) payload_text_assertion = assertions.EqualsAssertion( assertions.MISSING_VALUE) http_data['body'] = {'text': None, 'json': {}} elif body_data is None: # The body section is present and explicitly None. This implies assertions # that the body is actual None. If it is not, the assertions will fail. body_present = False payload_json_assertion = assertions.JsonAssertion().Matches( '', None) payload_text_assertion = assertions.EqualsAssertion(None) else: # The body is present, load the assertions that were provided. if 'text' in body_data: payload_text_assertion = assertions.Assertion.ForComplex( body_data['text']) if 'json' in body_data: payload_json_assertion = assertions.JsonAssertion() json_data = body_data['json'] if not json_data or json_data == assertions.MISSING_VALUE: # If explicitly None, this asserts that the request is empty. # If explicitly the empty dictionary, the assertion checks nothing. payload_json_assertion.Matches('', json_data) else: for field, struct in six.iteritems(json_data): payload_json_assertion.Matches(field, struct) return cls(mode, uri_assertion, method_assertion, header_assertion, payload_json_assertion, payload_text_assertion, body_present, extract_references)
def FromData(cls, mode, http_data): """Creates an HttpBodyAssertion for an HTTP request or response. Args: mode: string, 'expect_request' or 'expect_response' depending on if it is a request or response. http_data: dict, api_call.expect_request or api_call.expect_response. Returns: HttpBodyAssertion """ payload_json_assertion = None payload_text_assertion = None body_present = True body_data = http_data.get('body') if 'body' not in http_data or (not body_data and body_data is not None): # The body section is missing entirely or it is present and is an empty # dictionary. In these cases, the assertions are not present and will be # updated always. body_present = False payload_json_assertion = assertions.JsonAssertion().Matches( '', assertions.MISSING_VALUE) payload_text_assertion = assertions.EqualsAssertion( assertions.MISSING_VALUE) http_data['body'] = {'text': None, 'json': {}} elif body_data is None: # The body section is present and explicitly None. This implies assertions # that the body is actual None. If it is not, the assertions will fail. body_present = False payload_json_assertion = assertions.JsonAssertion().Matches('', None) payload_text_assertion = assertions.EqualsAssertion(None) else: # The body is present, load the assertions that were provided. if 'text' in body_data: payload_text_assertion = assertions.Assertion.ForComplex( body_data['text']) if 'json' in body_data: payload_json_assertion = assertions.JsonAssertion() json_data = body_data['json'] if not json_data or json_data == assertions.MISSING_VALUE: # If explicitly None, this asserts that the request is empty. # If explicitly the empty dictionary, the assertion checks nothing. payload_json_assertion.Matches('', json_data) else: for field, struct in six.iteritems(json_data): payload_json_assertion.Matches(field, struct) return cls(mode, body_present, payload_json_assertion, payload_text_assertion)
def ForMissing(cls): """Creates a RequestAssertion for a missing api_call.""" uri_assertion = assertions.EqualsAssertion(assertions.MISSING_VALUE) method_assertion = assertions.EqualsAssertion(assertions.MISSING_VALUE) headers_assertion = assertions.DictAssertion() payload_json_assertion = (assertions.JsonAssertion() .Matches('', assertions.MISSING_VALUE)) payload_text_assertion = assertions.EqualsAssertion( assertions.MISSING_VALUE) body_assertion = HttpBodyAssertion('expect_request', False, payload_json_assertion, payload_text_assertion) return cls(uri_assertion, method_assertion, headers_assertion, body_assertion)
def _GenerateOperationsExtras(self, resource_ref_resolver, response_body): """Generates extra data if this response looks like an operation. If the body has a kind attribute that indicates an operation, this will update the scenario spec to include a default extract_references block to pull out the operation id. This should only be called if an expect_response block is not already present. If this is a polling operation it will be marked as optional. Args: resource_ref_resolver: ResourceReferenceResolver, The resolver to track the extracted references. response_body: str, The body of the response from the server. Returns: [Failure], The failures to update the spec and inject the new block or []. """ op = Operation.FromResponse(None, response_body, force_operation=self._poll_operation) if not op: # Not an operation response at all. return [] if resource_ref_resolver.IsExtractedIdCurrent('operation', op.name): # This is an op, but the id has already been extracted in a previous # event. This means that this is not the call that generated the op, but # rather the polling of the op. No need to generate the ref extraction, # but we do want to mark polling steps as optional and repeated calls. self.MarkRepeated() failures = self.CheckRepeatable() if op.status: # In order for optional to work, we need to also generate an assertion # against the status in the response. failures = assertions.EqualsAssertion(self._is_optional).Check( self._update_context.ForKey('optional'), True) failures.append( assertions.Failure.ForGeneric( self._update_context.ForKey('expect_response'), 'Adding operation response assertion for optional polling', OrderedDict([('body', { 'json': { 'status': op.status } })]))) return failures # This is a call that resulted in an operation being created. Extract its # id for future polling calls. resource_ref_resolver.SetExtractedId('operation', op.name) return [ assertions.Failure.ForGeneric( self._update_context.ForKey('expect_response'), 'Adding reference extraction for Operations response', OrderedDict([('extract_references', [ OrderedDict([('field', 'name'), ('reference', 'operation')]) ]), ('body', { 'json': {} })])) ]
def Handle(self, ux_event_data): failures = super(_PromptEvent, self).Handle(ux_event_data) if self._user_input is None: # Set the answer to 'y' if the entire assertion was missing. failures.extend( assertions.EqualsAssertion(None).Check( self._update_context.ForKey('user_input'), self.DefaultValue())) return failures
def FromData(cls, backing_data): file_data = backing_data['expect_file_written'] update_context = updates.Context(backing_data, 'expect_file_written', cls.EventType().UpdateMode()) path_assertion = assertions.EqualsAssertion(file_data.get('path')) contents_assertion = assertions.Assertion.ForComplex( file_data.get('contents')) binary_contents = file_data.get('binary_contents') if (binary_contents is not None and isinstance(binary_contents, six.text_type)): binary_contents = binary_contents.encode('utf-8') binary_contents_assertion = assertions.Assertion.ForComplex(binary_contents) is_private_assertion = assertions.EqualsAssertion( file_data.get('is_private') or False) return cls(update_context, path_assertion, contents_assertion, binary_contents_assertion, is_private_assertion)
def FromData(cls, backing_data): exit_data = backing_data['expect_exit'] code = exit_data.get('code') has_message = 'message' in exit_data message = exit_data.get('message') return cls( updates.Context(backing_data, 'expect_exit', cls.EventType().UpdateMode()), code, assertions.EqualsAssertion(code), assertions.Assertion.ForComplex(message) if has_message else None)
def FromCallData(cls, call_data): """Creates a RequestAssertion from an api_call dict.""" http_data = call_data['expect_request'] uri_assertion = assertions.Assertion.ForComplex(http_data.get('uri', '')) method_assertion = assertions.EqualsAssertion( http_data.get('method', 'GET')) headers_assertion = MakeHttpHeadersAssertion(http_data) body_assertion = HttpBodyAssertion.FromData('expect_request', http_data) return cls(uri_assertion, method_assertion, headers_assertion, body_assertion)
def Execute(self, scenario_context): if scenario_context.execution_mode == session.ExecutionMode.LOCAL: # No need to wait for anything in local mode. return rrr = scenario_context.resource_ref_resolver command = rrr.Resolve(self._command) exit_code_assertion = (None if self._exit_code is None else assertions.EqualsAssertion(self._exit_code)) stdout_assertion = (None if self._stdout is None else assertions.Assertion.ForComplex( rrr.Resolve(self._stdout))) stderr_assertion = (None if self._stderr is None else assertions.Assertion.ForComplex( rrr.Resolve(self._stderr))) def _Run(): """Executes the command for the retrier.""" try: scenario_context.command_executor(command) exit_code = 0 except Exception as e: # pylint: disable=broad-except if isinstance(e, (KeyboardInterrupt, SystemExit)): raise exit_code = getattr(e, 'exit_code', 1) stdout = scenario_context.stream_mocker.stdout_reader() stderr = scenario_context.stream_mocker.stderr_reader() result = (exit_code, stdout, stderr) if scenario_context.debug: sys.__stderr__.write('execute_command_until: Result: ' + six.text_type(result) + '\n') return result context = updates.Context.Empty() def _ShouldRetry(result, state): del state exit_code, stdout, stderr = result if exit_code_assertion and exit_code_assertion.Check( context, exit_code): return True if stdout_assertion and stdout_assertion.Check(context, stdout): return True if stderr_assertion and stderr_assertion.Check(context, stderr): return True return False retrier = retry.Retryer( max_retrials=self._retries, max_wait_ms=self._timeout * 1000, exponential_sleep_multiplier=self._exponential_sleep_multiplier, wait_ceiling_ms=self._wait_ceiling_ms) retrier.RetryOnResult(_Run, should_retry_if=_ShouldRetry, sleep_ms=1000)
def _GenerateOperationPolling(self, resource_ref_resolver, response): if not self._poll_operation and self._poll_operation is not None: # If explicitly disabled, don't treat this as an operation no matter what. return [] op = Operation.FromResponse(response, force_operation=self._poll_operation) if not op or resource_ref_resolver.IsExtractedIdCurrent( 'operation', op.name): # Not an operation response at all. if self._poll_operation is None: return [] return assertions.EqualsAssertion(self._poll_operation).Check( self._update_context.ForKey('poll_operation'), False) # We've identified the response as an operation, make sure polling is turned # on. self._ExtractOperationPollingName(resource_ref_resolver, op) failures = assertions.EqualsAssertion(self._poll_operation).Check( self._update_context.ForKey('poll_operation'), True) return failures
def ForRequest(cls, http_data): uri_assertion = assertions.Assertion.ForComplex( http_data.get('uri', '')) method_assertion = assertions.EqualsAssertion( http_data.get('method', 'GET')) extract_references = [ ReferenceExtraction.FromData(d) for d in http_data.get('extract_references', []) ] return cls._ForCommon('expect_request', http_data, uri_assertion, method_assertion, extract_references)
def HandleReturnCode(self, return_code, message=None): failures = [] failures.extend( self._code_assertion.Check(self._update_context.ForKey('code'), return_code)) if self._message_assertion or (failures and message): msg_assertion = self._message_assertion or assertions.EqualsAssertion( '') failures.extend( msg_assertion.Check(self._update_context.ForKey('message'), message)) return failures
def ForMissing(cls, location): backing_data = { 'api_call': OrderedDict([('expect_request', OrderedDict([('uri', ''), ('method', ''), ('headers', {}), ('body', { 'text': None, 'json': {} })])), ('return_response', OrderedDict([('headers', { 'status': '200' }), ('body', None)]))]) } update_context = updates.Context(backing_data, 'api_call', cls.EventType().UpdateMode(), was_missing=True, location=location) response = backing_data['api_call']['return_response'] return cls( update_context, None, None, False, HTTPAssertion( 'expect_request', assertions.EqualsAssertion(assertions.MISSING_VALUE), assertions.EqualsAssertion(assertions.MISSING_VALUE), assertions.DictAssertion(), assertions.JsonAssertion().Matches('', assertions.MISSING_VALUE), assertions.EqualsAssertion(assertions.MISSING_VALUE), False, {}), None, HTTPResponsePayload(headers=response['headers'], payload=response['body'], omit_fields=None))
def _Build(cls, backing_data, field, was_missing=False, location=None): ux_event_data = backing_data.setdefault(field, OrderedDict()) update_context = updates.Context(backing_data, field, cls.EventType().UpdateMode(), was_missing=was_missing, location=location) attr_assertions = OrderedDict() for a in cls.EventType().UXElementAttributes(): if was_missing or a in ux_event_data: # Only create assertions for things that were specified, or if the event # was missing, assert everything so it all gets filled in. attr_assertions[a] = assertions.EqualsAssertion( ux_event_data.get(a, None)) return cls(update_context, attr_assertions, ux_event_data)
def FromCallData(cls, call_data): """Creates a ResponseAssertion from an api_call dict.""" if 'expect_response' not in call_data: return None http_data = call_data['expect_response'] status = http_data.get('status') if not status: status = int(http_data.get('headers', {}).get('status', httplib.OK)) status_assertion = assertions.EqualsAssertion(status) headers_assertion = MakeHttpHeadersAssertion(http_data, for_response=True) body_assertion = HttpBodyAssertion.FromData('expect_response', http_data) extract_references = [ ReferenceExtraction.FromData(d) for d in http_data.get('extract_references', []) ] return cls(status_assertion, headers_assertion, body_assertion, extract_references)
class AssertionTests(test_case.TestCase, parameterized.TestCase): @parameterized.parameters([ (assertions.EqualsAssertion(''), '', True), (assertions.EqualsAssertion(''), 'asdf', False), (assertions.EqualsAssertion('asdf'), 'asdf', True), (assertions.EqualsAssertion('asdf'), 'qwer', False), (assertions.MatchesAssertion('asdf'), 'asdf', True), (assertions.MatchesAssertion('a.*'), 'asdf', True), (assertions.MatchesAssertion('b.*'), 'asdf', False), (assertions.MatchesAssertion(''), 'asdf', False), (assertions.MatchesAssertion('.*'), 'asdf', True), (assertions.MatchesAssertion('.*'), b'asdf', True), (assertions.IsNoneAssertion(True), None, True), (assertions.IsNoneAssertion(True), 'asdf', False), (assertions.IsNoneAssertion(True), True, False), (assertions.IsNoneAssertion(True), False, False), (assertions.IsNoneAssertion(True), 1, False), (assertions.IsNoneAssertion(False), None, False), (assertions.IsNoneAssertion(False), 'asdf', True), (assertions.IsNoneAssertion(False), True, True), (assertions.IsNoneAssertion(False), False, True), (assertions.IsNoneAssertion(False), 1, True), (assertions.InAssertion({1, 2, 3}), 1, True), (assertions.InAssertion({1, 2, 3}), 4, False), (assertions.InAssertion({1, 2, 3}), 'a', False), (assertions.InAssertion({1, 2, 3}), None, False), (assertions.InAssertion({'a', 'b', 'c'}), 'a', True), (assertions.InAssertion({'a', 'b', 'c'}), 'd', False), (assertions.InAssertion({'a', 'b', 'c'}), 1, False), (assertions.InAssertion({'a', 'b', 'c'}), None, False), (assertions.DictAssertion(), {}, True), (assertions.DictAssertion().Equals('a', 'b'), {}, False), (assertions.DictAssertion().Equals('a', 'b'), {'a': 'b'}, True), (assertions.DictAssertion().Equals('a', 'b'), {'a': 'c'}, False), (assertions.DictAssertion().Matches('a', 'b'), {}, False), (assertions.DictAssertion().Matches('a', 'b'), {'a': 'b'}, True), (assertions.DictAssertion().Matches('a', 'b'), {'a': 'c'}, False), (assertions.DictAssertion().Matches('a', '.*'), {'a': 'c'}, True), (assertions.DictAssertion().Matches( 'a', 'as.*df'), {'a': 'asqwerdf'}, True), (assertions.DictAssertion().IsNone('a'), {}, True), (assertions.DictAssertion().IsNone('a'), {'a': 'b'}, False), (assertions.DictAssertion().In('a', ['1', '2', '3']), {}, False), (assertions.DictAssertion().In('a', ['1', '2', '3']), {'a': 'b'}, False), (assertions.DictAssertion().In('a', ['1', '2', '3']), {'a': '1'}, True), ]) def testAssertion(self, assertion, actual, matches): if matches: with assertions.FailureCollector([]) as f: f.AddAll(assertion.Check(updates.Context.Empty(), actual)) else: with self.assertRaises(assertions.Error): with assertions.FailureCollector([]) as f: f.AddAll(assertion.Check(updates.Context.Empty(), actual)) @parameterized.parameters([ (assertions.JsonAssertion().Matches('', {}), True), (assertions.JsonAssertion().Matches('', {'a': {}}), True), (assertions.JsonAssertion().Matches('', {'a': {'b': 'c'}}), True), (assertions.JsonAssertion().Matches('', {'a': {'b': 'c', 'f': 1}}), True), (assertions.JsonAssertion().Matches('', {'a': {'b': 'd'}}), False), (assertions.JsonAssertion().Matches('a.f', 1), True), (assertions.JsonAssertion().Matches('a.f', 2), False), (assertions.JsonAssertion().Matches('a.g', True), True), (assertions.JsonAssertion().Matches('a.g', False), False), (assertions.JsonAssertion().Matches('h.o.p', 'q'), True), (assertions.JsonAssertion().Matches('h.o.p', 'z'), False), (assertions.JsonAssertion().Matches('h.o', {'p': 'q'}), True), (assertions.JsonAssertion().Matches('list', {}), False), (assertions.JsonAssertion().Matches('list', []), False), (assertions.JsonAssertion().Matches('list', [1, 2]), False), (assertions.JsonAssertion().Matches('list', [{}, {}]), True), (assertions.JsonAssertion().Matches('list', [{'s': 't'}, {'y': 'z'}]), True), (assertions.JsonAssertion().Matches('list', [{'s': 't'}, {'y': 'x'}]), False), (assertions.JsonAssertion().Matches('list', [{'s': 't'}, {'z': 'asdf'}]), False), (assertions.JsonAssertion().Matches('list', [{'s': 't'}, {'y': 'z'}, {'asdf', 'asdf'}]), False), (assertions.JsonAssertion().Matches('a.f', 1).Matches('a.b', 'c'), True), (assertions.JsonAssertion().Matches('a.f', 1).IsAbsent('a.x'), True), (assertions.JsonAssertion().Matches('a.f', 1).IsAbsent('a.d'), False), (assertions.JsonAssertion().Matches('n_l.l.a', [1, 3, 5]), True), (assertions.JsonAssertion().Matches('n_l.l.b', [2, 3]), False), (assertions.JsonAssertion().Matches('n_l.l.c', [0, 0]), False), (assertions.JsonAssertion().Matches('n_l.l', [{'a': 1, 'b': 2}, {'a': 3, 'b': 4}, {'a': 5, 'b': 6}]), True), ]) def testCheckJsonContent(self, assertion, matches): actual = { 'a': {'b': 'c', 'd': 'e', 'f': 1, 'g': True}, 'h': { 'i': {'j': 'k', 'l': 'm'}, 'o': {'p': 'q', 'r': 'r'}, }, 'list': [ {'s': 't', 'u': 'v'}, {'w': 'x', 'y': 'z'}, ], 'n_l': {'l': [ {'a': 1, 'b': 2}, {'a': 3, 'b': 4}, {'a': 5, 'b': 6} ]} } if matches: with assertions.FailureCollector([]) as f: f.AddAll(assertion.Check(updates.Context.Empty(), actual)) else: with self.assertRaises(assertions.Error): with assertions.FailureCollector([]) as f: f.AddAll(assertion.Check(updates.Context.Empty(), actual)) def testJsonUpdate(self): actual = { 'foo': 'bar', 'a': {'b': 'c', 'd': 'e'}, 'h': { 'i': {'j': 'k', 'l': 'm'}, }, 'scalar_list': ['s', 't', 'u'], 'dict_list': [ {'s': 't', 'u': 'v'}, {'w': 'x', 'y': 'z'}, ], 'diff_len_lists': [{'a': 'b'}, 'b', 'c'], } assertion_data = { 'foo': 'X', 'a': {'b': 'X'}, 'h': {'i': {'j': 'X'}}, 'scalar_list': ['s', 'X', 'u'], 'dict_list': [{'s': 'X', 'u': 'v'}, {'w': 'x', 'y': 'X'},], 'diff_len_lists': ['X'], } assertion = assertions.JsonAssertion() for field, struct in assertion_data.items(): assertion.Matches(field, struct) context = updates.Context( {'data': assertion_data}, 'data', updates.Mode.RESULT) failures = assertion.Check(context, actual) self.assertEqual(7, len(failures)) for f in failures: f.Update([updates.Mode.RESULT]) self.assertEqual('bar', assertion_data['foo']) self.assertEqual('c', assertion_data['a']['b']) self.assertEqual('k', assertion_data['h']['i']['j']) self.assertEqual('t', assertion_data['scalar_list'][1]) self.assertEqual('t', assertion_data['dict_list'][0]['s']) self.assertEqual('z', assertion_data['dict_list'][1]['y']) self.assertEqual([{'a': 'b'}, 'b', 'c'], assertion_data['diff_len_lists'])
def CheckRepeatable(self): return assertions.EqualsAssertion(self._is_repeatable).Check( self._update_context.ForKey('repeatable'), self._was_repeated)