Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CORE BUG][Verified Can Replicate] Wrong number of requests recorded under new_episodes mode #753

Open
vickyliin opened this issue Aug 2, 2023 · 3 comments · May be fixed by #755
Open

Comments

@vickyliin
Copy link

vickyliin commented Aug 2, 2023

AFAIK, when allow_playback_repeats is False, the number of requests should be equal to the length of cassette data.
But when we use new_episodes mode with same/matched requests called several times, the number of cassette data is smaller than the number of requests.

This is the same problem as mentioned here: #245
I changed the reproduce script to httpx so it's easier to count the number of requests:
https://colab.research.google.com/gist/vickyliin/cf06ea0dc0f7f2f8a1b5c30bb8f3909d/vcrpy-bug.ipynb

In the new_episodes context, the number of reuqests is 7, while the length of cassette.data is only 4

The cause is cassette.append doesn't set play_counts just like #245 mentioned. When a new and matched request calls, it uses the previously appended cassette data. So the total number of cassette.data for the above script is 1 (old) + 6/2 (new episodes) = 4

For now I use the following code as a hotfix:

class FixedCassette(Cassette):
    def append_and_play(self, request, response) -> None:
        prev_len_data = len(self.data)
        super().append(request, response)
        is_appended = len(self.data) == prev_len_data + 1
        if is_appended:
            self.play_counts[prev_len_data] += 1

    def _load(self) -> None:
        super()._load()
        self.append = self.append_and_play
        self._load = None


context = vcr.use_cassette(...)
context.cls = FixedCassette
wich context:
    run_requests()

Related code:

Records are only used when no play_count

vcrpy/vcr/cassette.py

Lines 266 to 274 in 69de388

def play_response(self, request):
"""
Get the response corresponding to a request, but only if it
hasn't been played back before, and mark it as played
"""
for index, response in self._responses(request):
if self.play_counts[index] == 0 or self.allow_playback_repeats:
self.play_counts[index] += 1
return response

append does not set play_count

vcrpy/vcr/cassette.py

Lines 234 to 247 in 69de388

def append(self, request, response):
"""Add a request, response pair to this cassette"""
log.info("Appending request %s and response %s", request, response)
request = self._before_record_request(request)
if not request:
return
# Deepcopy is here because mutation of `response` will corrupt the
# real response.
response = copy.deepcopy(response)
response = self._before_record_response(response)
if response is None:
return
self.data.append((request, response))
self.dirty = True

append is also used when loading cassette so we can't set play_count in append directly

vcrpy/vcr/cassette.py

Lines 342 to 348 in 69de388

def _load(self):
try:
requests, responses = self._persister.load_cassette(self._path, serializer=self._serializer)
for request, response in zip(requests, responses):
self.append(request, response)
self.dirty = False
self.rewound = True

For other modes, we can't see this problem because rewound is False (or it's ALL mode)

vcrpy/vcr/cassette.py

Lines 262 to 264 in 69de388

def can_play_response_for(self, request):
request = self._before_record_request(request)
return request and request in self and self.record_mode != RecordMode.ALL and self.rewound

@vickyliin
Copy link
Author

vickyliin commented Aug 3, 2023

I'm trying to make a PR to fix this issue, but found play_count is heavily relied on in the tests to check if a record is newly added or being played.

I'm wondering if

  • I should modify the logic of play_count to be added whenever a record has been played no matter from loaded cassettes or from a real request and change all the related tests
  • or I should find a work around

@vickyliin vickyliin linked a pull request Aug 3, 2023 that will close this issue
@vickyliin vickyliin changed the title Wrong number of requests recorded under new_episodes mode [Bug] Wrong number of requests recorded under new_episodes mode Aug 7, 2023
@vickyliin vickyliin changed the title [Bug] Wrong number of requests recorded under new_episodes mode [CORE BUG] Wrong number of requests recorded under new_episodes mode Aug 7, 2023
@vickyliin vickyliin changed the title [CORE BUG] Wrong number of requests recorded under new_episodes mode [CORE BUG][Verified Can Replicate] Wrong number of requests recorded under new_episodes mode Aug 7, 2023
@vickyliin
Copy link
Author

vickyliin commented Aug 7, 2023

This bug is pretty annoying because the cassette keeps growing after each time we run the code, until no new repeated requests is making. It takes log(n) runs to make the cassette stable

@vickyliin
Copy link
Author

I'm willing to help. Anyone can make a decision? Anything else can I do now?

cfm added a commit to freedomofpress/securedrop-client that referenced this issue Feb 6, 2024
…h different responses

Thanks to @vickyliin for suggesting this workaround for
kevin1024/vcrpy#753.
cfm added a commit to freedomofpress/securedrop-client that referenced this issue Feb 6, 2024
…h different responses

Thanks to @vickyliin for suggesting this workaround for
kevin1024/vcrpy#753.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue Feb 12, 2024
…h different responses

Thanks to @vickyliin for suggesting this workaround for
kevin1024/vcrpy#753.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue Feb 12, 2024
…h different responses

Thanks to @vickyliin for suggesting this workaround for
kevin1024/vcrpy#753.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue Feb 12, 2024
…h different responses

Thanks to @vickyliin for suggesting this workaround for
kevin1024/vcrpy#753.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue Feb 14, 2024
…h different responses

Thanks to @vickyliin for suggesting this workaround for
kevin1024/vcrpy#753.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue Feb 14, 2024
…h different responses

Thanks to @vickyliin for suggesting this workaround for
kevin1024/vcrpy#753.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue Feb 20, 2024
…h different responses

Thanks to @vickyliin for suggesting this workaround for
kevin1024/vcrpy#753.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue Feb 20, 2024
…h different responses

Thanks to @vickyliin for suggesting this workaround for
kevin1024/vcrpy#753.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue Feb 20, 2024
…h different responses

Thanks to @vickyliin for suggesting this workaround for
kevin1024/vcrpy#753.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue Feb 21, 2024
…h different responses

Thanks to @vickyliin for suggesting this workaround for
kevin1024/vcrpy#753.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue Feb 29, 2024
…h different responses

Thanks to @vickyliin for suggesting this workaround for
kevin1024/vcrpy#753.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue Mar 1, 2024
We can't use VCR.py's "custom_patches" parameter because our
API._send_json_request() is RPC- rather than connection-oriented.  But
we can just instrument _send_json_request() directly, which is what we
do here.

We subclass vcr.cassette.Cassette to handle identical requests with
different responses, which was suggestd by @vickyliin as a workaround
for kevin1024/vcrpy#753.

Now that the SDK‒proxy connection is itself instrumented, there's only
one path to test, with no special error-handling logic required, so
merge TestAPIProxy into TestAPI.

I considered merging TestAPI and TestShared as well, now that (without
TestAPIProxy) TestAPI is the only subclass of TestShared.  But
reorganizing the alphabetized helpers in TestShared versus the
strictly-sequenced TestAPI methods can wait.

The tests are also now more patient with slow deletion operations.
I'd want to DRY up this logic if this pattern shows up in more places,
but it would require adding another level of indirection.  A @Retry
decorator isn't appropriate at the level of the test method, and a
context manager can't loop over its closure.

And re-apply the hack from 880635d by renaming test_logout to start with
a "z" so it runs last.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue Mar 5, 2024
We can't use VCR.py's "custom_patches" parameter because our
API._send_json_request() is RPC- rather than connection-oriented.  But
we can just instrument _send_json_request() directly, which is what we
do here.

We subclass vcr.cassette.Cassette to handle identical requests with
different responses, which was suggestd by @vickyliin as a workaround
for kevin1024/vcrpy#753.

Now that the SDK‒proxy connection is itself instrumented, there's only
one path to test, with no special error-handling logic required, so
merge TestAPIProxy into TestAPI.

I considered merging TestAPI and TestShared as well, now that (without
TestAPIProxy) TestAPI is the only subclass of TestShared.  But
reorganizing the alphabetized helpers in TestShared versus the
strictly-sequenced TestAPI methods can wait.

The tests are also now more patient with slow deletion operations.
I'd want to DRY up this logic if this pattern shows up in more places,
but it would require adding another level of indirection.  A @Retry
decorator isn't appropriate at the level of the test method, and a
context manager can't loop over its closure.

And re-apply the hack from 880635d by renaming test_logout to start with
a "z" so it runs last.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue Mar 7, 2024
We can't use VCR.py's "custom_patches" parameter because our
API._send_json_request() is RPC- rather than connection-oriented.  But
we can just instrument _send_json_request() directly, which is what we
do here.

We subclass vcr.cassette.Cassette to handle identical requests with
different responses, which was suggestd by @vickyliin as a workaround
for kevin1024/vcrpy#753.

Now that the SDK‒proxy connection is itself instrumented, there's only
one path to test, with no special error-handling logic required, so
merge TestAPIProxy into TestAPI.

I considered merging TestAPI and TestShared as well, now that (without
TestAPIProxy) TestAPI is the only subclass of TestShared.  But
reorganizing the alphabetized helpers in TestShared versus the
strictly-sequenced TestAPI methods can wait.

The tests are also now more patient with slow deletion operations.
I'd want to DRY up this logic if this pattern shows up in more places,
but it would require adding another level of indirection.  A @Retry
decorator isn't appropriate at the level of the test method, and a
context manager can't loop over its closure.

And re-apply the hack from 880635d by renaming test_logout to start with
a "z" so it runs last.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue May 1, 2024
We can't use VCR.py's "custom_patches" parameter because our
API._send_json_request() is RPC- rather than connection-oriented.  But
we can just instrument _send_json_request() directly, which is what we
do here.

We subclass vcr.cassette.Cassette to handle identical requests with
different responses, which was suggestd by @vickyliin as a workaround
for kevin1024/vcrpy#753.

Now that the SDK‒proxy connection is itself instrumented, there's only
one path to test, with no special error-handling logic required, so
merge TestAPIProxy into TestAPI.

I considered merging TestAPI and TestShared as well, now that (without
TestAPIProxy) TestAPI is the only subclass of TestShared.  But
reorganizing the alphabetized helpers in TestShared versus the
strictly-sequenced TestAPI methods can wait.

The tests are also now more patient with slow deletion operations.
I'd want to DRY up this logic if this pattern shows up in more places,
but it would require adding another level of indirection.  A @Retry
decorator isn't appropriate at the level of the test method, and a
context manager can't loop over its closure.

And re-apply the hack from 880635d by renaming test_logout to start with
a "z" so it runs last.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue May 1, 2024
We can't use VCR.py's "custom_patches" parameter because our
API._send_json_request() is RPC- rather than connection-oriented.  But
we can just instrument _send_json_request() directly, which is what we
do here.

We subclass vcr.cassette.Cassette to handle identical requests with
different responses, which was suggestd by @vickyliin as a workaround
for kevin1024/vcrpy#753.

Now that the SDK‒proxy connection is itself instrumented, there's only
one path to test, with no special error-handling logic required, so
merge TestAPIProxy into TestAPI.

I considered merging TestAPI and TestShared as well, now that (without
TestAPIProxy) TestAPI is the only subclass of TestShared.  But
reorganizing the alphabetized helpers in TestShared versus the
strictly-sequenced TestAPI methods can wait.

The tests are also now more patient with slow deletion operations.
I'd want to DRY up this logic if this pattern shows up in more places,
but it would require adding another level of indirection.  A @Retry
decorator isn't appropriate at the level of the test method, and a
context manager can't loop over its closure.

And re-apply the hack from 880635d by renaming test_logout to start with
a "z" so it runs last.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue May 2, 2024
We can't use VCR.py's "custom_patches" parameter because our
API._send_json_request() is RPC- rather than connection-oriented.  But
we can just instrument _send_json_request() directly, which is what we
do here.

We subclass vcr.cassette.Cassette to handle identical requests with
different responses, which was suggestd by @vickyliin as a workaround
for kevin1024/vcrpy#753.

Now that the SDK‒proxy connection is itself instrumented, there's only
one path to test, with no special error-handling logic required, so
merge TestAPIProxy into TestAPI.

I considered merging TestAPI and TestShared as well, now that (without
TestAPIProxy) TestAPI is the only subclass of TestShared.  But
reorganizing the alphabetized helpers in TestShared versus the
strictly-sequenced TestAPI methods can wait.

The tests are also now more patient with slow deletion operations.
I'd want to DRY up this logic if this pattern shows up in more places,
but it would require adding another level of indirection.  A @Retry
decorator isn't appropriate at the level of the test method, and a
context manager can't loop over its closure.

And re-apply the hack from 880635d by renaming test_logout to start with
a "z" so it runs last.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue May 2, 2024
We can't use VCR.py's "custom_patches" parameter because our
API._send_json_request() is RPC- rather than connection-oriented.  But
we can just instrument _send_json_request() directly, which is what we
do here.

We subclass vcr.cassette.Cassette to handle identical requests with
different responses, which was suggestd by @vickyliin as a workaround
for kevin1024/vcrpy#753.

Now that the SDK‒proxy connection is itself instrumented, there's only
one path to test, with no special error-handling logic required, so
merge TestAPIProxy into TestAPI.

I considered merging TestAPI and TestShared as well, now that (without
TestAPIProxy) TestAPI is the only subclass of TestShared.  But
reorganizing the alphabetized helpers in TestShared versus the
strictly-sequenced TestAPI methods can wait.

The tests are also now more patient with slow deletion operations.
I'd want to DRY up this logic if this pattern shows up in more places,
but it would require adding another level of indirection.  A @Retry
decorator isn't appropriate at the level of the test method, and a
context manager can't loop over its closure.

And re-apply the hack from 880635d by renaming test_logout to start with
a "z" so it runs last.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue May 2, 2024
We can't use VCR.py's "custom_patches" parameter because our
API._send_json_request() is RPC- rather than connection-oriented.  But
we can just instrument _send_json_request() directly, which is what we
do here.

We subclass vcr.cassette.Cassette to handle identical requests with
different responses, which was suggestd by @vickyliin as a workaround
for kevin1024/vcrpy#753.

Now that the SDK‒proxy connection is itself instrumented, there's only
one path to test, with no special error-handling logic required, so
merge TestAPIProxy into TestAPI.

I considered merging TestAPI and TestShared as well, now that (without
TestAPIProxy) TestAPI is the only subclass of TestShared.  But
reorganizing the alphabetized helpers in TestShared versus the
strictly-sequenced TestAPI methods can wait.

The tests are also now more patient with slow deletion operations.
I'd want to DRY up this logic if this pattern shows up in more places,
but it would require adding another level of indirection.  A @Retry
decorator isn't appropriate at the level of the test method, and a
context manager can't loop over its closure.

And re-apply the hack from 880635d by renaming test_logout to start with
a "z" so it runs last.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue May 2, 2024
We can't use VCR.py's "custom_patches" parameter because our
API._send_json_request() is RPC- rather than connection-oriented.  But
we can just instrument _send_json_request() directly, which is what we
do here.

We subclass vcr.cassette.Cassette to handle identical requests with
different responses, which was suggestd by @vickyliin as a workaround
for kevin1024/vcrpy#753.

Now that the SDK‒proxy connection is itself instrumented, there's only
one path to test, with no special error-handling logic required, so
merge TestAPIProxy into TestAPI.

I considered merging TestAPI and TestShared as well, now that (without
TestAPIProxy) TestAPI is the only subclass of TestShared.  But
reorganizing the alphabetized helpers in TestShared versus the
strictly-sequenced TestAPI methods can wait.

The tests are also now more patient with slow deletion operations.
I'd want to DRY up this logic if this pattern shows up in more places,
but it would require adding another level of indirection.  A @Retry
decorator isn't appropriate at the level of the test method, and a
context manager can't loop over its closure.

And re-apply the hack from 880635d by renaming test_logout to start with
a "z" so it runs last.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue May 2, 2024
We can't use VCR.py's "custom_patches" parameter because our
API._send_json_request() is RPC- rather than connection-oriented.  But
we can just instrument _send_json_request() directly, which is what we
do here.

We subclass vcr.cassette.Cassette to handle identical requests with
different responses, which was suggestd by @vickyliin as a workaround
for kevin1024/vcrpy#753.

Now that the SDK‒proxy connection is itself instrumented, there's only
one path to test, with no special error-handling logic required, so
merge TestAPIProxy into TestAPI.

I considered merging TestAPI and TestShared as well, now that (without
TestAPIProxy) TestAPI is the only subclass of TestShared.  But
reorganizing the alphabetized helpers in TestShared versus the
strictly-sequenced TestAPI methods can wait.

The tests are also now more patient with slow deletion operations.
I'd want to DRY up this logic if this pattern shows up in more places,
but it would require adding another level of indirection.  A @Retry
decorator isn't appropriate at the level of the test method, and a
context manager can't loop over its closure.

And re-apply the hack from 880635d by renaming test_logout to start with
a "z" so it runs last.
cfm added a commit to freedomofpress/securedrop-client that referenced this issue May 8, 2024
We can't use VCR.py's "custom_patches" parameter because our
API._send_json_request() is RPC- rather than connection-oriented.  But
we can just instrument _send_json_request() directly, which is what we
do here.

We subclass vcr.cassette.Cassette to handle identical requests with
different responses, which was suggestd by @vickyliin as a workaround
for kevin1024/vcrpy#753.

Now that the SDK‒proxy connection is itself instrumented, there's only
one path to test, with no special error-handling logic required, so
merge TestAPIProxy into TestAPI.

I considered merging TestAPI and TestShared as well, now that (without
TestAPIProxy) TestAPI is the only subclass of TestShared.  But
reorganizing the alphabetized helpers in TestShared versus the
strictly-sequenced TestAPI methods can wait.

The tests are also now more patient with slow deletion operations.
I'd want to DRY up this logic if this pattern shows up in more places,
but it would require adding another level of indirection.  A @Retry
decorator isn't appropriate at the level of the test method, and a
context manager can't loop over its closure.

And re-apply the hack from 880635d by renaming test_logout to start with
a "z" so it runs last.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue May 15, 2024
We can't use VCR.py's "custom_patches" parameter because our
API._send_json_request() is RPC- rather than connection-oriented.  But
we can just instrument _send_json_request() directly, which is what we
do here.

We subclass vcr.cassette.Cassette to handle identical requests with
different responses, which was suggestd by @vickyliin as a workaround
for kevin1024/vcrpy#753.

Now that the SDK‒proxy connection is itself instrumented, there's only
one path to test, with no special error-handling logic required, so
merge TestAPIProxy into TestAPI.

I considered merging TestAPI and TestShared as well, now that (without
TestAPIProxy) TestAPI is the only subclass of TestShared.  But
reorganizing the alphabetized helpers in TestShared versus the
strictly-sequenced TestAPI methods can wait.

The tests are also now more patient with slow deletion operations.
I'd want to DRY up this logic if this pattern shows up in more places,
but it would require adding another level of indirection.  A @Retry
decorator isn't appropriate at the level of the test method, and a
context manager can't loop over its closure.

And re-apply the hack from 880635d by renaming test_logout to start with
a "z" so it runs last.
micahflee added a commit to freedomofpress/securedrop-client that referenced this issue May 16, 2024
We can't use VCR.py's "custom_patches" parameter because our
API._send_json_request() is RPC- rather than connection-oriented.  But
we can just instrument _send_json_request() directly, which is what we
do here.

We subclass vcr.cassette.Cassette to handle identical requests with
different responses, which was suggestd by @vickyliin as a workaround
for kevin1024/vcrpy#753.

Now that the SDK‒proxy connection is itself instrumented, there's only
one path to test, with no special error-handling logic required, so
merge TestAPIProxy into TestAPI.

I considered merging TestAPI and TestShared as well, now that (without
TestAPIProxy) TestAPI is the only subclass of TestShared.  But
reorganizing the alphabetized helpers in TestShared versus the
strictly-sequenced TestAPI methods can wait.

The tests are also now more patient with slow deletion operations.
I'd want to DRY up this logic if this pattern shows up in more places,
but it would require adding another level of indirection.  A @Retry
decorator isn't appropriate at the level of the test method, and a
context manager can't loop over its closure.

And re-apply the hack from 880635d by renaming test_logout to start with
a "z" so it runs last.
legoktm pushed a commit to freedomofpress/securedrop-client that referenced this issue May 17, 2024
We can't use VCR.py's "custom_patches" parameter because our
API._send_json_request() is RPC- rather than connection-oriented.  But
we can just instrument _send_json_request() directly, which is what we
do here.

We subclass vcr.cassette.Cassette to handle identical requests with
different responses, which was suggestd by @vickyliin as a workaround
for kevin1024/vcrpy#753.

Now that the SDK‒proxy connection is itself instrumented, there's only
one path to test, with no special error-handling logic required, so
merge TestAPIProxy into TestAPI.

I considered merging TestAPI and TestShared as well, now that (without
TestAPIProxy) TestAPI is the only subclass of TestShared.  But
reorganizing the alphabetized helpers in TestShared versus the
strictly-sequenced TestAPI methods can wait.

The tests are also now more patient with slow deletion operations.
I'd want to DRY up this logic if this pattern shows up in more places,
but it would require adding another level of indirection.  A @Retry
decorator isn't appropriate at the level of the test method, and a
context manager can't loop over its closure.

And re-apply the hack from 880635d by renaming test_logout to start with
a "z" so it runs last.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant