Skip to content

Commit 1d6f8dc

Browse files
committed
Add proptest support
Signed-off-by: Ana Hobden <[email protected]>
1 parent 90f715f commit 1d6f8dc

File tree

7 files changed

+136
-179
lines changed

7 files changed

+136
-179
lines changed

Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ edition = "2018"
1212
default = []
1313
# Enable integration tests with a running TiKV and PD instance.
1414
# Use $PD_ADDRS, comma separated, to set the addresses the tests use.
15-
integration-tests = []
15+
integration-tests = ["property-testing"]
16+
# Enable propery testing features with `proptest`.
17+
property-testing = ["proptest", "proptest-derive"]
18+
1619

1720
[lib]
1821
name = "tikv_client"
@@ -28,6 +31,8 @@ serde = "1.0"
2831
serde_derive = "1.0"
2932
tokio-core = "0.1"
3033
tokio-timer = "0.2"
34+
proptest = { version = "0.9", optional = true }
35+
proptest-derive = { version = "0.1.0", optional = true }
3136

3237
[dependencies.kvproto]
3338
git = "https://github.com/pingcap/kvproto.git"

rust-toolchain

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
nightly-2019-06-01

src/kv.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ use std::ops::{
44
Bound, Deref, DerefMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive,
55
};
66
use std::{fmt, str, u8};
7+
#[cfg(feature = "proptest-derive")]
8+
use proptest::{collection::size_range, arbitrary::any_with};
9+
#[cfg(feature = "proptest-derive")]
10+
use proptest_derive::Arbitrary;
11+
12+
#[cfg(feature = "proptest-derive")]
13+
const PROPTEST_KEY_MAX: usize = 1024 * 2; // 2 KB
14+
#[cfg(feature = "proptest-derive")]
15+
const PROPTEST_VALUE_MAX: usize = 1024 * 16; // 16 KB
716

817
use crate::{Error, Result};
918

@@ -56,7 +65,11 @@ impl<'a> fmt::Display for HexRepr<'a> {
5665
/// accept an `Into<Key>`, which means all of the above types can be passed directly to those
5766
/// functions.
5867
#[derive(Default, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
59-
pub struct Key(Vec<u8>);
68+
#[cfg_attr(feature = "proptest-derive", derive(Arbitrary))]
69+
pub struct Key(
70+
#[cfg_attr(feature = "proptest-derive", proptest(strategy = "any_with::<Vec<u8>>((size_range(PROPTEST_KEY_MAX), ()))"))]
71+
Vec<u8>
72+
);
6073

6174
impl Key {
6275
#[inline]
@@ -170,7 +183,11 @@ impl fmt::Debug for Key {
170183
/// accept an `Into<Value>`, which means all of the above types can be passed directly to those
171184
/// functions.
172185
#[derive(Default, Clone, Eq, PartialEq, Hash)]
173-
pub struct Value(Vec<u8>);
186+
#[cfg_attr(feature = "proptest-derive", derive(Arbitrary))]
187+
pub struct Value(
188+
#[cfg_attr(feature = "proptest-derive", proptest(strategy = "any_with::<Vec<u8>>((size_range(PROPTEST_VALUE_MAX), ()))"))]
189+
Vec<u8>
190+
);
174191

175192
impl Value {
176193
#[inline]
@@ -239,6 +256,7 @@ impl fmt::Debug for Value {
239256
/// Many functions which accept a `KvPair` accept an `Into<KvPair>`, which means all of the above
240257
/// types (Like a `(Key, Value)`) can be passed directly to those functions.
241258
#[derive(Default, Clone, Eq, PartialEq)]
259+
#[cfg_attr(feature = "proptest-derive", derive(Arbitrary))]
242260
pub struct KvPair(Key, Value);
243261

244262
impl KvPair {
Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.
2-
3-
mod raw;
4-
5-
use std::env::var;
6-
const ENV_PD_ADDR: &str = "PD_ADDR";
7-
8-
pub fn pd_addr() -> Vec<String> {
9-
var(ENV_PD_ADDR)
10-
.expect(&format!("Expected {}:", ENV_PD_ADDR))
11-
.split(",")
12-
.map(From::from)
13-
.collect()
14-
}
1+
// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.
2+
3+
mod raw;
4+
5+
use std::env::var;
6+
const ENV_PD_ADDR: &str = "PD_ADDR";
7+
8+
pub fn pd_addr() -> Vec<String> {
9+
var(ENV_PD_ADDR)
10+
.expect(&format!("Expected {}:", ENV_PD_ADDR))
11+
.split(",")
12+
.map(From::from)
13+
.collect()
14+
}

tests/integration/raw.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.
2+
3+
use crate::{arb_batch, integration::pd_addr};
4+
use proptest::{arbitrary::{any, any_with}, collection::size_range, proptest};
5+
use futures::executor::block_on;
6+
use tikv_client::{KvPair, raw::Client, Config, Value};
7+
8+
proptest! {
9+
#[test]
10+
fn point(
11+
pair in any::<KvPair>(),
12+
) {
13+
let client = block_on(Client::connect(Config::new(pd_addr()))).unwrap();
14+
15+
block_on(
16+
client.put(pair.key().clone(), pair.value().clone())
17+
).unwrap();
18+
19+
let out_value = block_on(
20+
client.get(pair.key().clone())
21+
).unwrap();
22+
assert_eq!(Some(Value::from(pair.value().clone())), out_value);
23+
24+
block_on(
25+
client.delete(pair.key().clone())
26+
).unwrap();
27+
}
28+
}
29+
30+
proptest! {
31+
#[test]
32+
fn batch(
33+
kvs in arb_batch(any::<KvPair>(), None),
34+
) {
35+
let client = block_on(Client::connect(Config::new(pd_addr()))).unwrap();
36+
let keys = kvs.iter().map(|kv| kv.key()).cloned().collect::<Vec<_>>();
37+
38+
block_on(
39+
client.batch_put(kvs.clone())
40+
).unwrap();
41+
42+
let out_value = block_on(
43+
client.batch_get(keys.clone())
44+
).unwrap();
45+
assert_eq!(kvs, out_value);
46+
47+
block_on(
48+
client.batch_delete(keys.clone())
49+
).unwrap();
50+
}
51+
}
52+
53+
proptest! {
54+
#[test]
55+
fn scan(
56+
kvs in arb_batch(any::<KvPair>(), None),
57+
) {
58+
let client = block_on(Client::connect(Config::new(pd_addr()))).unwrap();
59+
let mut keys = kvs.iter().map(|kv| kv.key()).cloned().collect::<Vec<_>>();
60+
keys.sort();
61+
// If we aren't getting values this is an empty vector, so use dummy values.
62+
let start_key = keys.iter().cloned().next().unwrap_or(vec![0].into());
63+
let end_key = keys.iter().cloned().last().unwrap_or(vec![0].into());
64+
65+
block_on(
66+
client.batch_put(kvs.clone())
67+
).unwrap();
68+
69+
let out_value = block_on(
70+
client.scan(start_key..=end_key, 10240) // Magic max number is TiKV intrinsic
71+
).unwrap();
72+
73+
// Since TiKV returns empty keys as tombstones in scans, we just check we can find all the items.
74+
assert!(kvs.iter().all(|kv| {
75+
out_value.iter().find(|out| kv == *out).is_some()
76+
}));
77+
78+
block_on(
79+
client.batch_delete(keys.clone())
80+
).unwrap();
81+
}
82+
}

tests/integration_tests/raw.rs

Lines changed: 0 additions & 161 deletions
This file was deleted.

tests/test.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,16 @@
33
#![feature(async_await)]
44

55
#[cfg(feature = "integration-tests")]
6-
mod integration_tests;
6+
mod integration;
7+
8+
#[cfg(feature = "proptest")]
9+
use proptest::strategy::Strategy;
10+
11+
#[cfg(feature = "proptest")]
12+
const PROPTEST_BATCH_SIZE_MAX: usize = 16;
13+
14+
#[cfg(feature = "proptest")]
15+
pub fn arb_batch<T: core::fmt::Debug>(single_strategy: impl Strategy<Value = T>, max_batch_size: impl Into<Option<usize>>) -> impl Strategy<Value = Vec<T>> {
16+
let max_batch_size = max_batch_size.into().unwrap_or(PROPTEST_BATCH_SIZE_MAX);
17+
proptest::collection::vec(single_strategy, 0..max_batch_size)
18+
}

0 commit comments

Comments
 (0)