async def record_responses(cassette, vcr_request, response): """Because aiohttp follows redirects by default, we must support them by default. This method is used to write individual request-response chains that were implicitly followed to get to the final destination. """ for past_response in response.history: aiohttp_request = past_response.request_info # No data because it's following a redirect. past_request = Request( aiohttp_request.method, str(aiohttp_request.url), None, _serialize_headers(aiohttp_request.headers), ) await record_response(cassette, past_request, past_response) # If we're following redirects, then the last request-response # we record is the one attached to the `response`. if response.history: aiohttp_request = response.request_info vcr_request = Request( aiohttp_request.method, str(aiohttp_request.url), None, _serialize_headers(aiohttp_request.headers), ) await record_response(cassette, vcr_request, response)
def test_replace_dict_post_data_parameters(): # This tests all of: # 1. keeping a parameter # 2. removing a parameter # 3. replacing a parameter # 4. replacing a parameter using a callable # 5. removing a parameter using a callable # 6. replacing a parameter that doesn't exist body = { "one": "keep", "two": "lose", "three": "change", "four": "shout", "five": "whisper" } request = Request("POST", "http://google.com", body, {}) request.headers["Content-Type"] = "application/x-www-form-urlencoded" replace_post_data_parameters( request, [ ("two", None), ("three", "tada"), ("four", lambda key, value, request: value.upper()), ("five", lambda key, value, request: None), ("six", "doesntexist"), ], ) expected_data = {"one": "keep", "three": "tada", "four": "SHOUT"} assert request.body == expected_data
def request(self, method, url, body=None, headers=None): '''Persist the request metadata in self._vcr_request''' self._vcr_request = Request(method=method, uri=self._uri(url), body=body, headers=headers or {}) log.debug('Got {0}'.format(self._vcr_request))
def test_replace_headers(): # This tests all of: # 1. keeping a header # 2. removing a header # 3. replacing a header # 4. replacing a header using a callable # 5. removing a header using a callable # 6. replacing a header that doesn't exist headers = { "one": ["keep"], "two": ["lose"], "three": ["change"], "four": ["shout"], "five": ["whisper"] } request = Request("GET", "http://google.com", "", headers) replace_headers( request, [ ("two", None), ("three", "tada"), ("four", lambda key, value, request: value.upper()), ("five", lambda key, value, request: None), ("six", "doesntexist"), ], ) assert request.headers == {"one": "keep", "three": "tada", "four": "SHOUT"}
def test_replace_headers(): # This tests all of: # 1. keeping a header # 2. removing a header # 3. replacing a header # 4. replacing a header using a callable # 5. removing a header using a callable # 6. replacing a header that doesn't exist headers = { 'one': ['keep'], 'two': ['lose'], 'three': ['change'], 'four': ['shout'], 'five': ['whisper'], } request = Request('GET', 'http://google.com', '', headers) replace_headers(request, [ ('two', None), ('three', 'tada'), ('four', lambda key, value, request: value.upper()), ('five', lambda key, value, request: None), ('six', 'doesntexist'), ]) assert request.headers == { 'one': 'keep', 'three': 'tada', 'four': 'SHOUT', }
def test_serialize_empty_request(): request = Request(method="POST", uri="http://localhost/", body="", headers={}) serialize({"requests": [request], "responses": [{}]}, jsonserializer)
def test_serialize_json_request(): request = Request(method="POST", uri="http://localhost/", body="{'hello': 'world'}", headers={}) serialize({"requests": [request], "responses": [{}]}, jsonserializer)
def play_responses(cassette, vcr_request, kwargs): history = [] allow_redirects = kwargs.get("allow_redirects", True) vcr_response = cassette.play_response(vcr_request) response = build_response(vcr_request, vcr_response, history) # If we're following redirects, continue playing until we reach # our final destination. while allow_redirects and 300 <= response.status <= 399: if "location" not in response.headers: break next_url = URL(response.url).join(URL(response.headers["location"])) # Make a stub VCR request that we can then use to look up the recorded # VCR request saved to the cassette. This feels a little hacky and # may have edge cases based on the headers we're providing (e.g. if # there's a matcher that is used to filter by headers). vcr_request = Request("GET", str(next_url), None, _serialize_headers(response.request_info.headers)) vcr_requests = cassette.find_requests_with_most_matches(vcr_request) for vcr_request, *_ in vcr_requests: if cassette.can_play_response_for(vcr_request): break # Tack on the response we saw from the redirect into the history # list that is added on to the final response. history.append(response) vcr_response = cassette.play_response(vcr_request) response = build_response(vcr_request, vcr_response, history) return response
def test_headers(): headers = {'X-Header1': ['h1'], 'X-Header2': 'h2'} req = Request('GET', 'http://go.com/', '', headers) assert req.headers == {'X-Header1': 'h1', 'X-Header2': 'h2'} req.add_header('X-Header1', 'h11') assert req.headers == {'X-Header1': 'h11', 'X-Header2': 'h2'}
def play_responses(cassette, vcr_request): history = [] vcr_response = cassette.play_response(vcr_request) response = build_response(vcr_request, vcr_response, history) # If we're following redirects, continue playing until we reach # our final destination. while 300 <= response.status <= 399: new_location = response.headers["location"] potential_next_url = URL(new_location) next_url = (potential_next_url if potential_next_url.is_absolute() else URL(response.url).with_path(new_location)) # Make a stub VCR request that we can then use to look up the recorded # VCR request saved to the cassette. This feels a little hacky and # may have edge cases based on the headers we're providing (e.g. if # there's a matcher that is used to filter by headers). vcr_request = Request( "GET", str(next_url), None, _serialize_headers(response.request_info.headers)) vcr_request = cassette.find_requests_with_most_matches( vcr_request)[0][0] # Tack on the response we saw from the redirect into the history # list that is added on to the final response. history.append(response) vcr_response = cassette.play_response(vcr_request) response = build_response(vcr_request, vcr_response, history) return response
def putrequest(self, method, url, *args, **kwargs): """ httplib gives you more than one way to do it. This is a way to start building up a request. Usually followed by a bunch of putheader() calls. """ self._vcr_request = Request(method=method, uri=self._uri(url), body="", headers={}) log.debug("Got {}".format(self._vcr_request))
def test_remove_json_post_data_parameters(): body = b'{"id": "secret", "foo": "bar", "baz": "qux"}' request = Request('POST', 'http://google.com', body, {}) request.add_header('Content-Type', 'application/json') remove_post_data_parameters(request, ['id']) request_body_json = json.loads(request.body.decode('utf-8')) expected_json = json.loads(b'{"foo": "bar", "baz": "qux"}'.decode('utf-8')) assert request_body_json == expected_json
def test_remove_dict_post_data_parameters(): # Test the backward-compatible API wrapper. body = {"id": "secret", "foo": "bar", "baz": "qux"} request = Request("POST", "http://google.com", body, {}) request.headers["Content-Type"] = "application/x-www-form-urlencoded" remove_post_data_parameters(request, ["id"]) expected_data = {"foo": "bar", "baz": "qux"} assert request.body == expected_data
def test_vcr_before_record_request_params(): base_path = 'http://httpbin.org/' def before_record_cb(request): if request.path != '/get': return request test_vcr = VCR(filter_headers=('cookie',), before_record_request=before_record_cb, ignore_hosts=('www.test.com',), ignore_localhost=True, filter_query_parameters=('foo',)) with test_vcr.use_cassette('test') as cassette: assert cassette.filter_request(Request('GET', base_path + 'get', '', {})) is None assert cassette.filter_request(Request('GET', base_path + 'get2', '', {})) is not None assert cassette.filter_request(Request('GET', base_path + '?foo=bar', '', {})).query == [] assert cassette.filter_request( Request('GET', base_path + '?foo=bar', '', {'cookie': 'test', 'other': 'fun'})).headers == {'other': 'fun'} assert cassette.filter_request(Request('GET', base_path + '?foo=bar', '', {'cookie': 'test', 'other': 'fun'})).headers == {'other': 'fun'} assert cassette.filter_request(Request('GET', 'http://www.test.com' + '?foo=bar', '', {'cookie': 'test', 'other': 'fun'})) is None with test_vcr.use_cassette('test', before_record_request=None) as cassette: # Test that before_record can be overwritten with assert cassette.filter_request(Request('GET', base_path + 'get', '', {})) is not None
def test_serialize_json_request(): request = Request( method='POST', uri='http://localhost/', body="{'hello': 'world'}", headers={}, ) serialize({'requests': [request], 'responses': [{}]}, jsonserializer)
def test_remove_json_post_data_parameters(): # Test the backward-compatible API wrapper. body = b'{"id": "secret", "foo": "bar", "baz": "qux"}' request = Request('POST', 'http://google.com', body, {}) request.headers['Content-Type'] = 'application/json' remove_post_data_parameters(request, ['id']) request_body_json = json.loads(request.body.decode('utf-8')) expected_json = json.loads(b'{"foo": "bar", "baz": "qux"}'.decode('utf-8')) assert request_body_json == expected_json
def test_remove_json_post_data_parameters(): # Test the backward-compatible API wrapper. body = b'{"id": "secret", "foo": "bar", "baz": "qux"}' request = Request("POST", "http://google.com", body, {}) request.headers["Content-Type"] = "application/json" remove_post_data_parameters(request, ["id"]) request_body_json = json.loads(request.body.decode("utf-8")) expected_json = json.loads(b'{"foo": "bar", "baz": "qux"}'.decode("utf-8")) assert request_body_json == expected_json
def test_serialize_empty_request(): request = Request( method='POST', uri='http://localhost/', body='', headers={}, ) serialize({'requests': [request], 'responses': [{}]}, jsonserializer)
def test_serialize_binary_request(): msg = "Does this HTTP interaction contain binary data?" request = Request(method="POST", uri="http://localhost/", body=b"\x8c", headers={}) try: serialize({"requests": [request], "responses": [{}]}, jsonserializer) except (UnicodeDecodeError, TypeError) as exc: assert msg in str(exc)
def request_has_matches(cassette_path, flask_request): cassette_requests = Request(method=flask_request.method, uri=request.url, body=flask_request.data, headers=flask_request.headers) with set_underlying_vcr_logging_level(): cassette = Cassette.load(path=cassette_path, match_on=(extended_vcr_body_matcher, extended_query_matcher, method, extended_vcr_body_matcher)) for matches in cassette.find_requests_with_most_matches(cassette_requests): *_, failure = matches if not failure: return True return False
def test_vcr_before_record_request_params(): base_path = "http://httpbin.org/" def before_record_cb(request): if request.path != "/get": return request test_vcr = VCR( filter_headers=("cookie", ("bert", "ernie")), before_record_request=before_record_cb, ignore_hosts=("www.test.com", ), ignore_localhost=True, filter_query_parameters=("foo", ("tom", "jerry")), filter_post_data_parameters=("posted", ("no", "trespassing")), ) with test_vcr.use_cassette("test") as cassette: # Test explicit before_record_cb request_get = Request("GET", base_path + "get", "", {}) assert cassette.filter_request(request_get) is None request = Request("GET", base_path + "get2", "", {}) assert cassette.filter_request(request) is not None # Test filter_query_parameters request = Request("GET", base_path + "?foo=bar", "", {}) assert cassette.filter_request(request).query == [] request = Request("GET", base_path + "?tom=nobody", "", {}) assert cassette.filter_request(request).query == [("tom", "jerry")] # Test filter_headers request = Request("GET", base_path + "?foo=bar", "", { "cookie": "test", "other": "fun", "bert": "nobody" }) assert cassette.filter_request(request).headers == { "other": "fun", "bert": "ernie" } # Test ignore_hosts request = Request("GET", "http://www.test.com" + "?foo=bar", "", { "cookie": "test", "other": "fun" }) assert cassette.filter_request(request) is None # Test ignore_localhost request = Request("GET", "http://localhost:8000" + "?foo=bar", "", { "cookie": "test", "other": "fun" }) assert cassette.filter_request(request) is None with test_vcr.use_cassette("test", before_record_request=None) as cassette: # Test that before_record can be overwritten in context manager. assert cassette.filter_request(request_get) is not None
def request(self, method, url, body=None, headers=None): '''Persist the request metadata in self._vcr_request''' self._vcr_request = Request( protocol=self._protocol, host=self.host, port=self.port, method=method, path=url, body=body, headers=headers or {} )
def request(self, method, url, body=None, headers=None, *args, **kwargs): """Persist the request metadata in self._vcr_request""" self._vcr_request = Request(method=method, uri=self._uri(url), body=body, headers=headers or {}) log.debug("Got {}".format(self._vcr_request)) # Note: The request may not actually be finished at this point, so # I'm not sending the actual request until getresponse(). This # allows me to compare the entire length of the response to see if it # exists in the cassette. self._sock = VCRFakeSocket()
def test_replace_query_parameters_callable(): # This goes beyond test_replace_query_parameters() to ensure that the # callable receives the expected arguments. uri = 'http://g.com/?hey=there' request = Request('GET', uri, '', {}) callme = mock.Mock(return_value='ho') replace_query_parameters(request, [('hey', callme)]) assert request.uri == 'http://g.com/?hey=ho' assert callme.call_args == ((), {'request': request, 'key': 'hey', 'value': 'there'})
def test_replace_headers_callable(): # This goes beyond test_replace_headers() to ensure that the callable # receives the expected arguments. headers = {'hey': 'there'} request = Request('GET', 'http://google.com', '', headers) callme = mock.Mock(return_value='ho') replace_headers(request, [('hey', callme)]) assert request.headers == {'hey': 'ho'} assert callme.call_args == ((), {'request': request, 'key': 'hey', 'value': 'there'})
def test_vcr_before_record_request_params(): base_path = 'http://httpbin.org/' def before_record_cb(request): if request.path != '/get': return request test_vcr = VCR(filter_headers=('cookie', ('bert', 'ernie')), before_record_request=before_record_cb, ignore_hosts=('www.test.com', ), ignore_localhost=True, filter_query_parameters=('foo', ('tom', 'jerry')), filter_post_data_parameters=('posted', ('no', 'trespassing'))) with test_vcr.use_cassette('test') as cassette: # Test explicit before_record_cb request_get = Request('GET', base_path + 'get', '', {}) assert cassette.filter_request(request_get) is None request = Request('GET', base_path + 'get2', '', {}) assert cassette.filter_request(request) is not None # Test filter_query_parameters request = Request('GET', base_path + '?foo=bar', '', {}) assert cassette.filter_request(request).query == [] request = Request('GET', base_path + '?tom=nobody', '', {}) assert cassette.filter_request(request).query == [('tom', 'jerry')] # Test filter_headers request = Request('GET', base_path + '?foo=bar', '', { 'cookie': 'test', 'other': 'fun', 'bert': 'nobody' }) assert (cassette.filter_request(request).headers == { 'other': 'fun', 'bert': 'ernie' }) # Test ignore_hosts request = Request('GET', 'http://www.test.com' + '?foo=bar', '', { 'cookie': 'test', 'other': 'fun' }) assert cassette.filter_request(request) is None # Test ignore_localhost request = Request('GET', 'http://localhost:8000' + '?foo=bar', '', { 'cookie': 'test', 'other': 'fun' }) assert cassette.filter_request(request) is None with test_vcr.use_cassette('test', before_record_request=None) as cassette: # Test that before_record can be overwritten in context manager. assert cassette.filter_request(request_get) is not None
def test_serialize_binary(): request = Request(method="GET", uri="http://localhost/", body="", headers={}) cassette = {"requests": [request], "responses": [{"body": b"\x8c"}]} with pytest.raises(Exception) as e: serialize(cassette) assert (e.message == "Error serializing cassette to JSON. Does this \ HTTP interaction contain binary data? If so, use a different \ serializer (like the yaml serializer) for this request")
async def new_request(self, method, url, **kwargs): headers = kwargs.get('headers') headers = self._prepare_headers(headers) data = kwargs.get('data') params = kwargs.get('params') request_url = URL(url) if params: for k, v in params.items(): params[k] = str(v) request_url = URL(url).with_query(params) vcr_request = Request(method, str(request_url), data, headers) if cassette.can_play_response_for(vcr_request): vcr_response = cassette.play_response(vcr_request) response = MockClientResponse(method, URL(vcr_response.get('url'))) response.status = vcr_response['status']['code'] response._body = vcr_response['body']['string'] response.reason = vcr_response['status']['message'] response._headers = vcr_response['headers'] response.close() return response if cassette.write_protected and cassette.filter_request(vcr_request): response = MockClientResponse(method, URL(url)) response.status = 599 msg = ("No match for the request {!r} was found. Can't overwrite " "existing cassette {!r} in your current record mode {!r}.") msg = msg.format(vcr_request, cassette._path, cassette.record_mode) response._body = msg.encode() response.close() return response response = await real_request(self, method, url, **kwargs) # NOQA: E999 vcr_response = { 'status': { 'code': response.status, 'message': response.reason, }, 'headers': dict(response.headers), 'body': { 'string': (await response.read()) }, # NOQA: E999 'url': response.url, } cassette.append(vcr_request, vcr_response) return response
def test_serialize_binary(): request = Request( method='GET', uri='http://localhost/', body='', headers={}, ) cassette = {'requests': [request], 'responses': [{'body': b'\x8c'}]} with pytest.raises(Exception) as e: serialize(cassette) assert e.message == "Error serializing cassette to JSON. Does this \
def test_before_record_response_as_filter(): request = Request("GET", "/", "", {}) response = object() # just can't be None # Prevent actually saving the cassette with mock.patch("vcr.cassette.FilesystemPersister.save_cassette"): filter_all = mock.Mock(return_value=None) vcr = VCR(before_record_response=filter_all) with vcr.use_cassette("test") as cassette: cassette.append(request, response) assert cassette.data == [] assert not cassette.dirty