-
Notifications
You must be signed in to change notification settings - Fork 13
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
Add test coverage to xk6-redis #5
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't looked at the majority of the test code but would like to ask:
Have we considered not using a full blown redis in golang as this seems to pull a bunch of dependancies (even just for tests) that would then end up in the core k6 repo.
Arguably we don't really care about the "correct" behaviuour of any of the commands once they are called. So I wonder if we can just have some stubs that just check that it gets what seems like an okay redis command.
This arguably will require some amount of redis wire format parsing and returning of somethign that looks at least somewhat like what redis client should expect.
Running a full blown redis and having the integration tests behind a flag might also be preferable if it will mean that we will not suddenly depend on a lua interpreter for some tests :(
e607083
to
6fc8197
Compare
Changelog since the last review round:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From a fairly quick over the top look - haven't looked at each test case separately through and through - it LGTM! 👏
I would prefer to get the golangci.yaml update now and remove all the nolint
that are possible to be removed. Especially file wide ones.
As general note on tests - it might be better to check the error - like just to be certain it doesn''t actually error with something we are not expecting.
It will be nice if we have the example from the Readme as a test 🤔 Or at least something like it - that does something more.
The stub looks a bit big and I did not have time to look it over all that much, sorry - maybe if this stays open longer I might go through it more.
You have a general 👍 from me, if you have something specific you want my opinion on - I can try to look into it more, but otherwise I don't see any reason to block merging this. We can always fix something that turned out to not be as a great down the line.
p.s. I thought about the fact that a lot of the tests almost look at the same and can be made into table ones ... but that likely will not make them any easier to read so ... I am kind of against that idea.
dae41d5
to
efaa6ef
Compare
Alright, I've addressed the feedback I received, most notably:
|
efaa6ef
to
b1da722
Compare
b1da722
to
230eec1
Compare
In the context of tests, using the `RunT` method will spawn up a new instance of a stub server speaking redis protocol. The server's behavior can be observed and controlled using the `RegisterCommandHandler` method for instance. The redis stub server has zero dependencies. It is essentially a stripped down version of miniredis. Most exsting alternatives as of writing this commit were either pure mocking librarry (not actually listening on a tcp port), or feature-full servers importing external dependencies to support things such as Lua that we did not need.
Those tests use the previously introduced redis stub server to send request to a fac simile server, and ensure that the exposed JS API behaves as intended. We are less intrested in actual redis behavior correctness than in verifying that the module sends proper commands to redis, and reacts as expected to somewhat expected responses.
230eec1
to
1303ac9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👏 🎉
What
This PR adds integration tests covering the xk6-redis API with the goal to improve its stability and test coverage in preparation of merging it to k6's core. It attempts to test the extension in the context of a script interacting with a Redis instance, and focuses on testing the k6/goja/promises/event loop behavior of the
Client
, rather than interactions with Redis itself (considering we use a pre-established Redis library under the hood). In certain scenarios, we relied on a more extensive testing strategy in order to explicit the promise-based specific behavior of certain operations that might derive from Redis' behavior itself (rejecting a promise under certain conditions rather than returning zero, for instance).Things that were left out of the scope of this PR: this PR doesn't test Redis in sentinel mode, nor in cluster mode. The feature should be supported out of the box, but I didn't get to address testing it, yet (if ever).
How
This PR is quite massive. Writing tests for an API as big as Redis' involves, well, lots of code. That was to be expected. However, the test file is organized as follows:
Client
command has its ownTestClient{Command}(
test function. They all follow the same convention, and the same approach, and should be somewhat similar. It's probably not worth reviewing ALL of them, but by reviewing a few of them, the pattern should become explicit, and you will likely be able to spot systemic mistakes and cases I might have missed.TestClientCommandsAgainstUnreachableServer
andTestClientCommandInInitContext
verify that, based on the fact that every command will ensure a connection is established under the hood, those should fail when ran against an unreachable host, or when executed in the init context.Client.Connect
,Client.Close
and private methods have been tested separately, and follow a bit of a different testing convention, and it might be reviewing those.Open questions and Feedback needed
Connect and Close methods
Although the underlying library we used to implement the interactions with Redis does not require to explicitly establish a connection, we need to emulate that in the context of k6. The main reason for is that we want to avoid IO to happen in the init context of our users scripts. Besides, as we want our Redis client to reuse our VUs
Dialer
andTLSConfig
, we need to wait for the VUState
to be available before any connection to a Redis instance/cluster is attempted. As a result, I tackled this constraint by implementing explicitConnect
andClose
methods, as we seem to already have in other extensions/modules such as gRPC's.Our main design question is: as of today, every client's methods call connect under the hood, to make sure that the Redis client has an underlying client's instance, that is properly configured with the VU's
Dialer
andTLSConfig
. I would like to hear your views on what design you'd prefer: the user must explicitly call the.connect
method in the init context, or we keep connecting under the hood automatically?.Testing approach
We've used an integration testing approach. To avoid importing extra-dependencies, we have developed a dedicated and externally controllable redis mock/stub server (in the spirit of
httptest
). Running this stub server, we run scripts directly into a test runtime, and assert the outcome directly in the script. Once the script is successfully run, we assert that our redis stub server received the commands we expected in the order we anticipated.I probably have missed some failure scenarios, some edge cases, or dark corners of the script I'm not yet aware of, or have forgotten 🤷🏻 Please, check out some tests, and let me know if you can think of ways to break them, so I can improve the whole suite.
Finally
Thank you for your time and attention! Please let me know what you think 🙇🏻
Edits
26th of July 2022: Removed mentions of miniredis in favor of the stub server. Explicated testing design strategy.