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
testing: MockConnection
helper for testing clients without a server
#465
Conversation
|
I cleaned up the PR, added module docs with example, and made sure to test by enabling the |
cc @Marwes -- It was unclear to me how to flag a PR for attention so decided to cc you here. Is there a better way to go about getting attention for a PR? Are you the right person? |
Rebased on latest |
Cargo.toml
Outdated
@@ -68,6 +68,7 @@ script = ["sha1_smol"] | |||
tls = ["native-tls"] | |||
async-std-comp = ["aio", "async-std"] | |||
async-std-tls-comp = ["async-std-comp", "async-native-tls", "tls"] | |||
testing = ["futures"] |
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.
Is this intended to be part of the public API? What's the use case for doing this?
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.
Yes, it is intended to be part of the public API so that users (like me) can incorporate these test helpers into the unit tests in our codebases. I have made it be a feature here (which would be enabled as a dev dependency), but it could also be put into a separate crate, much like Tokio has done with the tokio-test
crate. Thoughts?
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.
A separate crate would allow evolving the API separately from the rest of the crate's API. I suppose we could keep the feature unstable for now (as in, we don't guarantee the public API to be compatible across semver-compatible versions of the crate).
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 will restructure this PR to create a redis-test
crate. Is that acceptable?
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.
@jaymell what do you think? I'm just worried the API might be unstable, but maybe it's not so bad?
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.
Hmm, I would say that a separate crate certainly does sound like an ideal solution, though the additional maintenance costs there do temper my enthusiasm somewhat 😅
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'll switch to separate crate then (but the code will still live in this repo).
src/testing.rs
Outdated
#[cfg(feature = "aio")] | ||
use crate::aio::ConnectionLike as AioConnectionLike; | ||
|
||
/// Helper trait for converting test values into a `redis::Value` returned from a |
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.
How/why is ToRedisArgs
/FromRedisValue
different from what we need here?
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.
Neither ToRedisArgs
nor FromRedisValue
produces redis::Value
instances from non-Redis values as required by the test helper:
ToRedisArgs
cannot be used because it is designed to convert a value into an array of bytes and not convert toredis::Value
. (ToRedisArgs.to_redis_args
returnsVec<Vec<u8>>
andToRedisArgs.write_redis_args
wants aRedisWrite
impl which has methods likewrite_arg
which takes a&[u8]
).FromRedisValue
is irrelevant because it converts in the opposite direction than what is needed by the test helper. The test helper needs to convert from a non-Redis type toredis::Value
.FromRedisValue
converts fromredis::Value
to a non-Redis type.
873fa5b
to
d108f46
Compare
@@ -10,6 +10,9 @@ documentation = "https://docs.rs/redis" | |||
license = "BSD-3-Clause" | |||
edition = "2018" | |||
|
|||
[workspace] |
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 tend to find nested crate workspaces confusing to navigate. Would you mind changing this so that the top-level Cargo.toml
only contains the workspace, and move the redis crate into a redis
directory?
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.
Should that be done in a separate PR?
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.
(to avoid confusing commit history)
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.
In my mind the ideal way to submit it would be a single PR with clean commits: one commit that moves the code around and one commit that adds the new crate. Each commit should ideally pass CI, though I usually don't test that explicitly (but it sucks if formatting changes for one commit make it into another).
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.
So it sounds like that PRs are not squashed before merge then. Will do as separate commits in this PR then. (Context: My company merges via squash-and-merge generally for PRs so a separate PR would be the only way to accomplish having separate commit history in that case.)
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'm also okay with separate PRs if you prefer. For my own changes I usually submit clean commits "manually" (squashing with interactive rebase). If a PR only contains one logical change, I'll also squash via merge in the Git UI, but I don't like doing that for changes that contain multiple logical changes.
redis-test/Cargo.toml
Outdated
@@ -0,0 +1,18 @@ | |||
[package] | |||
name = "redis-test" | |||
version = "0.21.5" |
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.
Let's just call this 0.1.0.
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.
Will do.
redis-test/Cargo.toml
Outdated
license = "BSD-3-Clause" | ||
|
||
[dependencies] | ||
redis = { path = ".." } |
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.
If we're going to publish this it should also have a specific version.
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 added a version
, but kept the path
so it continues to work with in-repo builds. Tokio does something similar.
I rebased the PR and turned it into two commits: the first moves the existing |
aa0e40f
to
340debd
Compare
The CI tests with Rust 1.51.0 fails due to |
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.
If you rebase this, I'd be okay with merging this.
Style nit: I think we could just git mv mock_conn.rs lib.rs
, it doesn't make much sense to me to have the indirection in this case since everything lives in one module anyway.
Rebased and also moved the contents of |
Repushed after making sure subsequent updates to Cargo.toml were taken into account. |
Note: The lint job in CI is failing on existing code, and not the new |
@jaymell any thoughts before we merge this? I'll take care of the new clippy issues separately. |
This PR adds
MockConnection
which implementscrate::connection::ConnectionLike
andcrate::aio::ConnectionLike
to appear like a client without the need to make any network requests. It is initialized with a list ofMockCmd
instances which wrap the expected commands and responses. This allows users to test their clients without much overhead.The
testing
module is behind thetesting
feature which is non-default. Users should activate it in thedev-dependencies
of their crate'sCargo.toml
.