Rob, thanks for betamax! We've been using it to enable component testing. Along the way, we've found that one of our preferred usage patterns relies upon a sequence of HTTP interactions. For example, one of our common scenarios is business logic that manipulates a data object. Part of that logic includes simple interactions to a backend system, such as:
betamax doesn't distinguish interactions 1 and 3, so we added sequential read/write tape modes:
WRITE_SEQUENTIAL records each HTTP interaction in order.
READ_SEQUENTIAL replays the HTTP interactions in order; if the HTTP request doesn't match the next recorded request, then we throw an IllegalStateException. Thus READ_SEQUENTIAL asserts that each request matches the recorded request.
This pull request contains themodifications to support sequential read/write tape modes. I offer this for your consideration as a new feature for betamax.
Thanks again for this project!
Fixed snakeyaml version for maven download.
Added support for sequential read/write tapes.
Merge remote-tracking branch 'upstream/master'
Add qualifier to version string.
Remove unused logger.
Wow, that looks great. There's been an issue for implementing this for a while (#7) but I haven't got round to even looking at it.
I'm going to add some test coverage around this & roll it into a release. For the time being I have released version 1.2-SNAPSHOT on http://oss.sonatype.org/content/groups/public/ with your changes.
Thanks again for a really useful feature.
@steveims can I ask if there's a reason you didn't support 'looping', i.e. that in READ_SEQUENTIAL mode the sequence gets repeated if more requests are made than there are recordings? Would that be a problem for you if I added it? It's kind of an edge case as one would expect the same number of requests to happen but right now an ArrayIndexOutOfBoundsException is thrown & I'd like to handle things in a cleaner way.
@robfletcher Depends how you want to interpret "sequential mode." We built it as a means to manage very controlled tests. Sequential reads enable us to build unit tests to confirm our HTTP interactions. That includes confirming that the request matches the expected (asserted within Betamax); our client code receives the corresponding response and our unit code asserts our handling of that response.
So controlled order and number of records is important. Reading after end of tape (in sequential mode) means the flow has changed, so we expect an error. Likely a new tape needs to be recorded.
I'm not sure of the use case for looping? Concurrent requests sounds non-deterministic, which seems outside the scope of a sequential tape?
I guess the problem is there are 3 different ways to approach this:
These would all make sense in different scenarios. That said Betamax should probably keep it simple. If someone needs to integration test against a REST endpoint they should do so. I think I'll go with what you originally committed and just ensure a reasonable error is returned to the client.
I'm going to merge this into master.
There is a small thread safety issue where you might get a HTTP 500 instead of a 403 if you send too many requests or out of sequence requests to a sequential tape using multiple threads. If all the requests on the tape match and you don't send too many requests it is thread safe and guarantees that no two threads will get sent the same recorded response.
I want to rethink the HTTP status codes anyway so I'll roll handling that problem into #71.
@steveims I've updated 1.2-SNAPSHOT with the final version of this code. Let me know if you see any issues.
@robfletcher Looks good. Thanks!
Hi, as this issue is closed, I would like to ask if the modes are now integrated into the code that you can download on your site? I can see them in the documentation, on your main page, but not in downloaded code (1.1.2). Thanks!
It's in 2.0-SNAPSHOT which is available from oss.jfrog.org.
Thanks for the quick response :)
No problem. Let me know how it's working for you. There are some differences between 1.2 and 2.0 and I'm still ironing out a number of compatibility issues with various frameworks – Grails in particular but I don't anticipate any further major API changes before 2.0