Skip to content

Commit

Permalink
Merge pull request #103 from sigmavirus24/feature/add-allow_playback_…
Browse files Browse the repository at this point in the history
…repeats-option

Add allow_playback_repeats option
  • Loading branch information
sigmavirus24 committed Apr 7, 2016
2 parents 48d677c + fa2b947 commit f08afda
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 9 deletions.
21 changes: 17 additions & 4 deletions betamax/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from datetime import datetime, timedelta
from requests.adapters import BaseAdapter, HTTPAdapter

_SENTINEL = object()


class BetamaxAdapter(BaseAdapter):
"""This object is an implementation detail of the library.
Expand Down Expand Up @@ -61,26 +63,37 @@ def load_cassette(self, cassette_name, serialize, options):
self.serialize = serialize
self.options.update(options.items())
placeholders = self.options.get('placeholders', [])
cassette_options = {}

default_options = Cassette.default_cassette_options

match_requests_on = self.options.get(
'match_requests_on', default_options['match_requests_on']
)

preserve_exact_body_bytes = self.options.get(
cassette_options['preserve_exact_body_bytes'] = self.options.get(
'preserve_exact_body_bytes',
)

cassette_options['allow_playback_repeats'] = self.options.get(
'allow_playback_repeats'
)

cassette_options['record_mode'] = self.options.get('record')

for option, value in list(cassette_options.items()):
if value is None:
cassette_options.pop(option)

self.cassette = Cassette(
cassette_name, serialize, placeholders=placeholders,
record_mode=self.options.get('record'),
preserve_exact_body_bytes=preserve_exact_body_bytes,
cassette_library_dir=self.options.get('cassette_library_dir')
cassette_library_dir=self.options.get('cassette_library_dir'),
**cassette_options
)

if 'record' in self.options:
self.cassette.record_mode = self.options['record']

self.cassette.match_options = match_requests_on

re_record_interval = timedelta.max
Expand Down
10 changes: 8 additions & 2 deletions betamax/cassette/cassette.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ class Cassette(object):
'match_requests_on': ['method', 'uri'],
're_record_interval': None,
'placeholders': [],
'preserve_exact_body_bytes': False
'preserve_exact_body_bytes': False,
'allow_playback_repeats': False,
}

def __init__(self, cassette_name, serialization_format, **kwargs):
Expand Down Expand Up @@ -49,6 +50,10 @@ def __init__(self, cassette_name, serialization_format, **kwargs):
'preserve_exact_body_bytes', kwargs, defaults
)

self.allow_playback_repeats = _option_from(
'allow_playback_repeats', kwargs, defaults
)

# Initialize the interactions
self.interactions = []

Expand Down Expand Up @@ -130,7 +135,8 @@ def find_match(self, request):
break

# set interaction as used before returning
i.used = True
if not self.allow_playback_repeats:
i.used = True
return i

# No matches. So sad.
Expand Down
8 changes: 7 additions & 1 deletion betamax/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,20 @@ def translate_cassette_options():
yield (k, v) if k != 'record_mode' else ('record', v)


def isboolean(value):
return value in [True, False]


class Options(object):
valid_options = {
'match_requests_on': validate_matchers,
're_record_interval': lambda x: x is None or x > 0,
'record': validate_record,
'serialize': validate_serializer, # TODO: Remove this
'serialize_with': validate_serializer,
'preserve_exact_body_bytes': lambda x: x in [True, False],
'preserve_exact_body_bytes': isboolean,
'placeholders': validate_placeholders,
'allow_playback_repeats': isboolean,
}

defaults = {
Expand All @@ -47,6 +52,7 @@ class Options(object):
'serialize_with': 'json',
'preserve_exact_body_bytes': False,
'placeholders': [],
'allow_playback_repeats': False,
}

def __init__(self, data=None):
Expand Down
7 changes: 5 additions & 2 deletions betamax/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,11 @@ def timestamp():
return stamp[:i]


_SENTINEL = object()


def _option_from(option, kwargs, defaults):
value = kwargs.get(option)
if value is None:
value = kwargs.get(option, _SENTINEL)
if value is _SENTINEL:
value = defaults.get(option)
return value
1 change: 1 addition & 0 deletions tests/cassettes/replay_interactions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"http_interactions": [{"response": {"url": "http://httpbin.org/get", "status": {"message": "OK", "code": 200}, "body": {"string": "{\n \"args\": {}, \n \"headers\": {\n \"Accept\": \"*/*\", \n \"Accept-Encoding\": \"gzip, deflate\", \n \"Host\": \"httpbin.org\", \n \"User-Agent\": \"python-requests/2.9.1\"\n }, \n \"origin\": \"96.37.91.79\", \n \"url\": \"http://httpbin.org/get\"\n}\n", "encoding": null}, "headers": {"Access-Control-Allow-Origin": ["*"], "Access-Control-Allow-Credentials": ["true"], "Connection": ["keep-alive"], "Content-Type": ["application/json"], "Date": ["Thu, 07 Apr 2016 13:22:08 GMT"], "Server": ["nginx"], "Content-Length": ["235"]}}, "recorded_at": "2016-04-07T13:22:13", "request": {"uri": "http://httpbin.org/get", "method": "GET", "body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept": ["*/*"], "Connection": ["keep-alive"], "User-Agent": ["python-requests/2.9.1"], "Accept-Encoding": ["gzip, deflate"]}}}], "recorded_with": "betamax/0.5.1"}
27 changes: 27 additions & 0 deletions tests/integration/test_allow_playback_repeats.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import betamax

from tests.integration import helper


class TestPlaybackRepeatInteractions(helper.IntegrationHelper):
def test_will_replay_the_same_interaction(self):
self.cassette_created = False
s = self.session
recorder = betamax.Betamax(s)
# NOTE(sigmavirus24): Ensure the cassette is recorded
with recorder.use_cassette('replay_interactions'):
cassette = recorder.current_cassette
r = s.get('http://httpbin.org/get')
assert r.status_code == 200
assert len(cassette.interactions) == 1

with recorder.use_cassette('replay_interactions',
allow_playback_repeats=True):
cassette = recorder.current_cassette
r = s.get('http://httpbin.org/get')
assert r.status_code == 200
assert len(cassette.interactions) == 1
r = s.get('http://httpbin.org/get')
assert r.status_code == 200
assert len(cassette.interactions) == 1
assert cassette.interactions[0].used is False

0 comments on commit f08afda

Please sign in to comment.