-
Notifications
You must be signed in to change notification settings - Fork 123
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
tests: serialization-deserialization tests #1232
base: branch-hackathon
Are you sure you want to change the base?
Conversation
2c3e6d6
to
22071b4
Compare
|
22071b4
to
93ca668
Compare
I see there is a conflict, could you rebase on curent branch-hackathon to fix it? |
35ebefe
to
ab61b5d
Compare
Done, there should be 3 tests that are currently failing, I'm going to push a fix to handle them properly - they fail on bad values, so I will either split them into separate test or just add an error handler callback to the test function. |
6dacbfd
to
1d3719d
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.
🔧 It's difficult to follow all the changes, as they are all introduced in one commit. Could you please split them into at least the following commits:
- Rename one of
{cql_types.rs,cql_value.rs}
toserialization.rs
. - Move contents of the remaining one of
{cql_types.rs,cql_value.rs}
toserialization.rs
. - Change the existing tests, if needed.
- Add your own new tests, if any.
abce619
to
09db999
Compare
Done. |
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.
👍 Thanks for the split, commits 1, 2, 4 are now very readable.
🔧 The third commit (refactor and split old serialization tests
) is still very large and the displayed diff is complicated. Could you split it further, preferably into separate logical steps of changes, so that it's easier to follow?
async fn run_literal_and_bound_value_test_with_callback<LitVal, BoundVal, ErrHandler>( | ||
table_name: &str, | ||
type_name: &str, | ||
values: Vec<(LitVal, BoundVal)>, |
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 slice would suffice 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.
values: Vec<(LitVal, BoundVal)>, | |
values: &[(LitVal, BoundVal)], |
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.
Then, you could pass stack-allocated slices to this function and elide allocations. Not so important in tests, but useful in general.
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.
Done
async fn run_literal_input_maybe_empty_output_test<X>( | ||
table_name: &str, | ||
type_name: &str, | ||
values: Vec<(Option<&str>, Option<MaybeEmpty<X>>)>, |
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.
🔧 ditto: non-owned slice is enough.
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.
Done
.filter(|row| match row { | ||
Ok((_,)) => true, | ||
Err(e) => handle_deserialize_error(e, || false), | ||
}) | ||
.map(Result::unwrap) |
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.
filter_map
could help avoid unwrap
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.
Done
#[cfg(any( | ||
feature = "num-bigint-03", | ||
feature = "num-bigint-04", | ||
feature = "bigdecimal-04" | ||
))] | ||
fn bigint_from_str<T>(val: &str) -> T | ||
where | ||
T: FromStr, | ||
<T as FromStr>::Err: Debug, | ||
{ | ||
T::from_str(val).expect("Failed to parse BigInt") | ||
} |
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.
This function has nothing to do with bigint
- it justs calls the <T as FromStr>::from_str()
implementation. It's thus not a good generic use IMO.
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.
Removed.
feb9649
to
99817b8
Compare
I don't think further splitting is possible - I started by replacing old test functions with new ones and then went and cleaned bodies of most of the tests, alongside extracting some bits into separate tests - I guess I could separate the extraction part - I commented them out first, but other than that I think I will end up with non-compiling commits. |
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.
Just posting a few comments because I can't review the whole thing now, I have to go to sleep
use core::str; | ||
use std::{ | ||
fmt::{Debug, Display}, | ||
net::{IpAddr, Ipv4Addr, Ipv6Addr}, | ||
str::FromStr, | ||
vec, | ||
}; |
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.
Please group imports by module. There is some options in rust-analyzer to do that, or you can do that manually.
By module I mean, in this case:
use std::fmt::{Debug, Display};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::str::FromStr;
use std::vec;
Grouping more than by module makes it much more difficult to do certain refactors, and introduces a lot of unnecessary conflicts when rebasing.
Not grouping at all results in a lot of code. Grouping by module is a good compromise.
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.
Here is my config for rust-analyzer
:
"rust-analyzer.imports.merge.glob": false,
"rust-analyzer.imports.granularity.group": "module",
"rust-analyzer.imports.granularity.enforce": true,
I'm not sure if it will fix the existing imports - you probably will need to fix those manually. But all new automatic imports (ctrl + .) will be grouped properly
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.
@muzarski Thanks, added to my config.
Done
use scylla::{ | ||
client::session::Session, | ||
deserialize::{ | ||
row::BuiltinDeserializationError, | ||
value::{Emptiable, MaybeEmpty}, | ||
}, | ||
errors::DeserializationError, | ||
serialize::value::SerializeValue, | ||
value::{ | ||
Counter, CqlDate, CqlDuration, CqlTime, CqlTimestamp, CqlTimeuuid, CqlValue, CqlVarint, | ||
}, | ||
DeserializeValue, SerializeValue, | ||
}; |
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.
Ditto, don't group by more than module.
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.
Done
fn handle_deserialize_error<F, T>(error: &DeserializationError, callback: F) -> T | ||
where | ||
F: FnOnce() -> T, | ||
{ | ||
match &error.downcast_ref::<BuiltinDeserializationError>().unwrap().kind{ | ||
scylla::deserialize::row::BuiltinDeserializationErrorKind::ColumnDeserializationFailed { err, .. } => match err.downcast_ref::<scylla::deserialize::value::BuiltinDeserializationError>().unwrap().kind { | ||
scylla::deserialize::value::BuiltinDeserializationErrorKind::ExpectedNonNull => { | ||
callback() | ||
}, | ||
_ => panic!("Unexpected error: {:?}", error), | ||
} | ||
_ => panic!("Unexpected error: {:?}", error), | ||
} |
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.
It looks like you are always calling this function with callback set to || None
. In that case I don't see why the callback is useful, please remove it.
After removing it, a much better name for this function would be assert_expected_non_null_error
.
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.
Indeed, that callback was useful when I initially wrote .filter().map()
chain, so in some cases I needed T
as the return value of the callback and in others bool
, but I think this can be removed now.
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.
Done
#[cfg(any(feature = "chrono-04", feature = "time-03",))] | ||
fn handle_incorrect_dates<T>(error: &DeserializationError) -> Option<T> { | ||
match &error.downcast_ref::<BuiltinDeserializationError>().unwrap().kind { | ||
scylla::deserialize::row::BuiltinDeserializationErrorKind::ColumnDeserializationFailed { err, .. } => match err.downcast_ref::<scylla::deserialize::value::BuiltinDeserializationError>().unwrap().kind { | ||
scylla::deserialize::value::BuiltinDeserializationErrorKind::ValueOverflow => { | ||
None | ||
}, | ||
scylla::deserialize::value::BuiltinDeserializationErrorKind::ExpectedNonNull => { | ||
None | ||
}, | ||
_ => panic!("Unexpected error: {:?}", error), | ||
} | ||
_ => panic!("Unexpected error: {:?}", error), | ||
} | ||
} |
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.
This function either panics or returns None
. In that case there is no reason to return anything.
Make it just panic or not and rename it to assert_overflow_or_expected_non_null_error
- or another name if you can think of some.
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 use this function inside a filter_map
- wouldn't this break the functionality of that?
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.
This function always returns None.
So you can change it just as I suggested, and use None literal instead of its return value
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.
Oh right, I see, okay, I'll do that.
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.
Done
// Creates a new keyspace | ||
// Drops and creates table {table_name} (id int PRIMARY KEY, val {type_name}) | ||
async fn init_test(table_name: &str, type_name: &str) -> Session { | ||
init_test_maybe_without_tablets(table_name, type_name, true).await | ||
prepare_test_table(table_name, type_name, true).await | ||
} |
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 there a reason for this function to exist? Its name doesn't say anything about tablets, and the only difference between this one and prepare_test_table
is that this one always creates the ks and table with tablet support.
Maybe just remove it and call prepare_test_table
directly?
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.
This function was there previously and I initially started without it but then ported it back over when wholesale copying some of the tests - I'll just remove it, it was there to set tablets to true for pretty much every test except counter one.
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.
Done
99817b8
to
24dda73
Compare
Generalized most tests and split some of them into distinct tests to see the results easier
This commit adds additional test to test various simple types such as int and float, as well as one more uuid test and some simple string type tests
24dda73
to
8b93622
Compare
This commit refactors and adds additional tests related to serialization
inside integration tests. It adds coverage for most scalar types,
additional cases for more complex types such as Uuid and Text, Null
checking inside queries and also splits certain test cases into multiple
tests to separate expected failures from expected successes.
Pre-review checklist
./docs/source/
.Fixes:
annotations to PR description.