mirror of
https://github.com/kevin1024/vcrpy.git
synced 2025-12-08 16:53:23 +00:00
313 lines
10 KiB
Python
313 lines
10 KiB
Python
import copy
|
|
import inspect
|
|
import os
|
|
|
|
from six.moves import http_client as httplib
|
|
import pytest
|
|
import yaml
|
|
|
|
from vcr.compat import mock, contextlib
|
|
from vcr.cassette import Cassette
|
|
from vcr.errors import UnhandledHTTPRequestError
|
|
from vcr.patch import force_reset
|
|
from vcr.matchers import path, method, query, host
|
|
from vcr.stubs import VCRHTTPSConnection
|
|
|
|
|
|
def test_cassette_load(tmpdir):
|
|
a_file = tmpdir.join('test_cassette.yml')
|
|
a_file.write(yaml.dump({'interactions': [
|
|
{'request': {'body': '', 'uri': 'foo', 'method': 'GET', 'headers': {}},
|
|
'response': 'bar'}
|
|
]}))
|
|
a_cassette = Cassette.load(path=str(a_file))
|
|
assert len(a_cassette) == 1
|
|
|
|
|
|
def test_cassette_not_played():
|
|
a = Cassette('test')
|
|
assert not a.play_count
|
|
|
|
|
|
def test_cassette_append():
|
|
a = Cassette('test')
|
|
a.append('foo', 'bar')
|
|
assert a.requests == ['foo']
|
|
assert a.responses == ['bar']
|
|
|
|
|
|
def test_cassette_len():
|
|
a = Cassette('test')
|
|
a.append('foo', 'bar')
|
|
a.append('foo2', 'bar2')
|
|
assert len(a) == 2
|
|
|
|
|
|
def _mock_requests_match(request1, request2, matchers):
|
|
return request1 == request2
|
|
|
|
|
|
@mock.patch('vcr.cassette.requests_match', _mock_requests_match)
|
|
def test_cassette_contains():
|
|
a = Cassette('test')
|
|
a.append('foo', 'bar')
|
|
assert 'foo' in a
|
|
|
|
|
|
@mock.patch('vcr.cassette.requests_match', _mock_requests_match)
|
|
def test_cassette_responses_of():
|
|
a = Cassette('test')
|
|
a.append('foo', 'bar')
|
|
assert a.responses_of('foo') == ['bar']
|
|
|
|
|
|
@mock.patch('vcr.cassette.requests_match', _mock_requests_match)
|
|
def test_cassette_get_missing_response():
|
|
a = Cassette('test')
|
|
with pytest.raises(UnhandledHTTPRequestError):
|
|
a.responses_of('foo')
|
|
|
|
|
|
@mock.patch('vcr.cassette.requests_match', _mock_requests_match)
|
|
def test_cassette_cant_read_same_request_twice():
|
|
a = Cassette('test')
|
|
a.append('foo', 'bar')
|
|
a.play_response('foo')
|
|
with pytest.raises(UnhandledHTTPRequestError):
|
|
a.play_response('foo')
|
|
|
|
|
|
def make_get_request():
|
|
conn = httplib.HTTPConnection("www.python.org")
|
|
conn.request("GET", "/index.html")
|
|
return conn.getresponse()
|
|
|
|
|
|
@mock.patch('vcr.cassette.requests_match', return_value=True)
|
|
@mock.patch('vcr.cassette.load_cassette', lambda *args, **kwargs: (('foo',), (mock.MagicMock(),)))
|
|
@mock.patch('vcr.cassette.Cassette.can_play_response_for', return_value=True)
|
|
@mock.patch('vcr.stubs.VCRHTTPResponse')
|
|
def test_function_decorated_with_use_cassette_can_be_invoked_multiple_times(*args):
|
|
decorated_function = Cassette.use(path='test')(make_get_request)
|
|
for i in range(4):
|
|
decorated_function()
|
|
|
|
|
|
def test_arg_getter_functionality():
|
|
arg_getter = mock.Mock(return_value={'path': 'test'})
|
|
context_decorator = Cassette.use_arg_getter(arg_getter)
|
|
|
|
with context_decorator as cassette:
|
|
assert cassette._path == 'test'
|
|
|
|
arg_getter.return_value = {'path': 'other'}
|
|
|
|
with context_decorator as cassette:
|
|
assert cassette._path == 'other'
|
|
|
|
arg_getter.return_value = {'path': 'other', 'filter_headers': ('header_name',)}
|
|
|
|
@context_decorator
|
|
def function():
|
|
pass
|
|
|
|
with mock.patch.object(
|
|
Cassette, 'load',
|
|
return_value=mock.MagicMock(inject=False)
|
|
) as cassette_load:
|
|
function()
|
|
cassette_load.assert_called_once_with(**arg_getter.return_value)
|
|
|
|
|
|
def test_cassette_not_all_played():
|
|
a = Cassette('test')
|
|
a.append('foo', 'bar')
|
|
assert not a.all_played
|
|
|
|
|
|
@mock.patch('vcr.cassette.requests_match', _mock_requests_match)
|
|
def test_cassette_all_played():
|
|
a = Cassette('test')
|
|
a.append('foo', 'bar')
|
|
a.play_response('foo')
|
|
assert a.all_played
|
|
|
|
|
|
def test_before_record_response():
|
|
before_record_response = mock.Mock(return_value='mutated')
|
|
cassette = Cassette('test', before_record_response=before_record_response)
|
|
cassette.append('req', 'res')
|
|
|
|
before_record_response.assert_called_once_with('res')
|
|
assert cassette.responses[0] == 'mutated'
|
|
|
|
|
|
def assert_get_response_body_is(value):
|
|
conn = httplib.HTTPConnection("www.python.org")
|
|
conn.request("GET", "/index.html")
|
|
assert conn.getresponse().read().decode('utf8') == value
|
|
|
|
|
|
@mock.patch('vcr.cassette.requests_match', _mock_requests_match)
|
|
@mock.patch('vcr.cassette.Cassette.can_play_response_for', return_value=True)
|
|
@mock.patch('vcr.cassette.Cassette._save', return_value=True)
|
|
def test_nesting_cassette_context_managers(*args):
|
|
first_response = {'body': {'string': b'first_response'}, 'headers': {},
|
|
'status': {'message': 'm', 'code': 200}}
|
|
|
|
second_response = copy.deepcopy(first_response)
|
|
second_response['body']['string'] = b'second_response'
|
|
|
|
with contextlib.ExitStack() as exit_stack:
|
|
first_cassette = exit_stack.enter_context(Cassette.use(path='test'))
|
|
exit_stack.enter_context(mock.patch.object(first_cassette, 'play_response',
|
|
return_value=first_response))
|
|
assert_get_response_body_is('first_response')
|
|
|
|
# Make sure a second cassette can supercede the first
|
|
with Cassette.use(path='test') as second_cassette:
|
|
with mock.patch.object(second_cassette, 'play_response', return_value=second_response):
|
|
assert_get_response_body_is('second_response')
|
|
|
|
# Now the first cassette should be back in effect
|
|
assert_get_response_body_is('first_response')
|
|
|
|
|
|
def test_nesting_context_managers_by_checking_references_of_http_connection():
|
|
original = httplib.HTTPConnection
|
|
with Cassette.use(path='test'):
|
|
first_cassette_HTTPConnection = httplib.HTTPConnection
|
|
with Cassette.use(path='test'):
|
|
second_cassette_HTTPConnection = httplib.HTTPConnection
|
|
assert second_cassette_HTTPConnection is not first_cassette_HTTPConnection
|
|
with Cassette.use(path='test'):
|
|
assert httplib.HTTPConnection is not second_cassette_HTTPConnection
|
|
with force_reset():
|
|
assert httplib.HTTPConnection is original
|
|
assert httplib.HTTPConnection is second_cassette_HTTPConnection
|
|
assert httplib.HTTPConnection is first_cassette_HTTPConnection
|
|
|
|
|
|
def test_custom_patchers():
|
|
class Test(object):
|
|
attribute = None
|
|
with Cassette.use(path='custom_patches',
|
|
custom_patches=((Test, 'attribute', VCRHTTPSConnection),)):
|
|
assert issubclass(Test.attribute, VCRHTTPSConnection)
|
|
assert VCRHTTPSConnection is not Test.attribute
|
|
old_attribute = Test.attribute
|
|
|
|
with Cassette.use(path='custom_patches',
|
|
custom_patches=((Test, 'attribute', VCRHTTPSConnection),)):
|
|
assert issubclass(Test.attribute, VCRHTTPSConnection)
|
|
assert VCRHTTPSConnection is not Test.attribute
|
|
assert Test.attribute is not old_attribute
|
|
|
|
assert issubclass(Test.attribute, VCRHTTPSConnection)
|
|
assert VCRHTTPSConnection is not Test.attribute
|
|
assert Test.attribute is old_attribute
|
|
|
|
|
|
def test_decorated_functions_are_reentrant():
|
|
info = {"second": False}
|
|
original_conn = httplib.HTTPConnection
|
|
@Cassette.use(path='whatever', inject=True)
|
|
def test_function(cassette):
|
|
if info['second']:
|
|
assert httplib.HTTPConnection is not info['first_conn']
|
|
else:
|
|
info['first_conn'] = httplib.HTTPConnection
|
|
info['second'] = True
|
|
test_function()
|
|
assert httplib.HTTPConnection is info['first_conn']
|
|
test_function()
|
|
assert httplib.HTTPConnection is original_conn
|
|
|
|
|
|
def test_cassette_use_called_without_path_uses_function_to_generate_path():
|
|
@Cassette.use(inject=True)
|
|
def function_name(cassette):
|
|
assert cassette._path == 'function_name'
|
|
function_name()
|
|
|
|
|
|
def test_path_transformer_with_function_path():
|
|
path_transformer = lambda path: os.path.join('a', path)
|
|
@Cassette.use(inject=True, path_transformer=path_transformer)
|
|
def function_name(cassette):
|
|
assert cassette._path == os.path.join('a', 'function_name')
|
|
function_name()
|
|
|
|
|
|
def test_path_transformer_with_context_manager():
|
|
with Cassette.use(
|
|
path='b', path_transformer=lambda *args: 'a'
|
|
) as cassette:
|
|
assert cassette._path == 'a'
|
|
|
|
|
|
def test_path_transformer_None():
|
|
with Cassette.use(
|
|
path='a', path_transformer=None,
|
|
) as cassette:
|
|
assert cassette._path == 'a'
|
|
|
|
|
|
def test_func_path_generator():
|
|
def generator(function):
|
|
return os.path.join(os.path.dirname(inspect.getfile(function)),
|
|
function.__name__)
|
|
@Cassette.use(inject=True, func_path_generator=generator)
|
|
def function_name(cassette):
|
|
assert cassette._path == os.path.join(os.path.dirname(__file__), 'function_name')
|
|
function_name()
|
|
|
|
|
|
def test_use_as_decorator_on_coroutine():
|
|
original_http_connetion = httplib.HTTPConnection
|
|
@Cassette.use(inject=True)
|
|
def test_function(cassette):
|
|
assert httplib.HTTPConnection.cassette is cassette
|
|
assert httplib.HTTPConnection is not original_http_connetion
|
|
value = yield 1
|
|
assert value == 1
|
|
assert httplib.HTTPConnection.cassette is cassette
|
|
assert httplib.HTTPConnection is not original_http_connetion
|
|
value = yield 2
|
|
assert value == 2
|
|
coroutine = test_function()
|
|
value = next(coroutine)
|
|
while True:
|
|
try:
|
|
value = coroutine.send(value)
|
|
except StopIteration:
|
|
break
|
|
|
|
|
|
def test_use_as_decorator_on_generator():
|
|
original_http_connetion = httplib.HTTPConnection
|
|
@Cassette.use(inject=True)
|
|
def test_function(cassette):
|
|
assert httplib.HTTPConnection.cassette is cassette
|
|
assert httplib.HTTPConnection is not original_http_connetion
|
|
yield 1
|
|
assert httplib.HTTPConnection.cassette is cassette
|
|
assert httplib.HTTPConnection is not original_http_connetion
|
|
yield 2
|
|
assert list(test_function()) == [1, 2]
|
|
|
|
|
|
def test_similar_requests(tmpdir):
|
|
# WIP needs to be finished
|
|
@Cassette.use(inject=True, match_on=(path, query, host, method))
|
|
def test_function(cassette):
|
|
conn = httplib.HTTPConnection("www.python.org")
|
|
conn.request("GET", "/index.html?test=1")
|
|
|
|
conn = httplib.HTTPConnection("www.python.org")
|
|
conn.request("GET", "/index.html?test=0")
|
|
|
|
conn = httplib.HTTPConnection("www.cool.org")
|
|
conn.request("GET", "/index.html?test=0")
|
|
cassette.similar_requests()
|