use prost::Message;
use dyn_encoding::{WireTypeId, WireValue};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
#[repr(u8)]
pub enum MessageCode {
ErrorResp = 0,
PingReq = 1,
PingResp = 2,
GetReq = 9,
GetResp = 10,
PutReq = 11,
PutResp = 12,
DelReq = 13,
DelResp = 14,
ServerInfoReq = 7,
GetServerInfoResp = 8,
ListBucketsReq = 15,
ListBucketsResp = 16,
ListKeysReq = 17,
ListKeysResp = 18,
GetBucketReq = 19,
GetBucketResp = 20,
SetBucketReq = 21,
SetBucketResp = 22,
IndexReq = 25,
IndexResp = 26,
MapRedReq = 23,
MapRedResp = 24,
DynListPeersReq = 200,
DynListPeersResp = 201,
DynClusterJoinReq = 202,
DynClusterJoinResp = 203,
DynClusterLeaveReq = 204,
DynClusterLeaveResp = 205,
DynClusterPlanReq = 206,
DynClusterPlanResp = 207,
DynClusterCommitReq = 208,
DynClusterCommitResp = 209,
DynAaeStatusReq = 220,
DynAaeStatusResp = 221,
}
impl MessageCode {
pub fn from_u8(code: u8) -> Result<Self, u8> {
Ok(match code {
0 => Self::ErrorResp,
1 => Self::PingReq,
2 => Self::PingResp,
7 => Self::ServerInfoReq,
8 => Self::GetServerInfoResp,
9 => Self::GetReq,
10 => Self::GetResp,
11 => Self::PutReq,
12 => Self::PutResp,
13 => Self::DelReq,
14 => Self::DelResp,
15 => Self::ListBucketsReq,
16 => Self::ListBucketsResp,
17 => Self::ListKeysReq,
18 => Self::ListKeysResp,
19 => Self::GetBucketReq,
20 => Self::GetBucketResp,
21 => Self::SetBucketReq,
22 => Self::SetBucketResp,
25 => Self::IndexReq,
26 => Self::IndexResp,
23 => Self::MapRedReq,
24 => Self::MapRedResp,
200 => Self::DynListPeersReq,
201 => Self::DynListPeersResp,
202 => Self::DynClusterJoinReq,
203 => Self::DynClusterJoinResp,
204 => Self::DynClusterLeaveReq,
205 => Self::DynClusterLeaveResp,
206 => Self::DynClusterPlanReq,
207 => Self::DynClusterPlanResp,
208 => Self::DynClusterCommitReq,
209 => Self::DynClusterCommitResp,
220 => Self::DynAaeStatusReq,
221 => Self::DynAaeStatusResp,
other => return Err(other),
})
}
#[must_use]
pub fn as_u8(self) -> u8 {
self as u8
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbErrorResp {
#[prost(bytes = "vec", tag = "1")]
pub errmsg: Vec<u8>,
#[prost(uint32, tag = "2")]
pub errcode: u32,
}
impl WireValue for RpbErrorResp {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbErrorResp")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbPingReq {}
impl WireValue for RpbPingReq {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbPingReq")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbPingResp {}
impl WireValue for RpbPingResp {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbPingResp")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbGetReq {
#[prost(bytes = "vec", tag = "1")]
pub bucket: Vec<u8>,
#[prost(bytes = "vec", tag = "2")]
pub key: Vec<u8>,
#[prost(uint32, optional, tag = "3")]
pub r: Option<u32>,
#[prost(uint32, optional, tag = "4")]
pub pr: Option<u32>,
#[prost(bool, optional, tag = "5")]
pub basic_quorum: Option<bool>,
#[prost(bool, optional, tag = "6")]
pub notfound_ok: Option<bool>,
#[prost(bytes = "vec", optional, tag = "7")]
pub if_modified: Option<Vec<u8>>,
#[prost(bool, optional, tag = "8")]
pub head: Option<bool>,
#[prost(bool, optional, tag = "9")]
pub deletedvclock: Option<bool>,
#[prost(uint32, optional, tag = "10")]
pub timeout: Option<u32>,
#[prost(bool, optional, tag = "11")]
pub sloppy_quorum: Option<bool>,
#[prost(uint32, optional, tag = "12")]
pub n_val: Option<u32>,
#[prost(bytes = "vec", optional, tag = "13")]
pub r#type: Option<Vec<u8>>,
}
impl WireValue for RpbGetReq {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbGetReq")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbLink {
#[prost(bytes = "vec", optional, tag = "1")]
pub bucket: Option<Vec<u8>>,
#[prost(bytes = "vec", optional, tag = "2")]
pub key: Option<Vec<u8>>,
#[prost(bytes = "vec", optional, tag = "3")]
pub tag: Option<Vec<u8>>,
}
impl WireValue for RpbLink {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbLink")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbContent {
#[prost(bytes = "vec", tag = "1")]
pub value: Vec<u8>,
#[prost(bytes = "vec", optional, tag = "2")]
pub content_type: Option<Vec<u8>>,
#[prost(bytes = "vec", optional, tag = "3")]
pub charset: Option<Vec<u8>>,
#[prost(bytes = "vec", optional, tag = "4")]
pub content_encoding: Option<Vec<u8>>,
#[prost(bytes = "vec", optional, tag = "5")]
pub vtag: Option<Vec<u8>>,
#[prost(message, repeated, tag = "6")]
pub links: Vec<RpbLink>,
#[prost(uint32, optional, tag = "7")]
pub last_mod: Option<u32>,
#[prost(uint32, optional, tag = "8")]
pub last_mod_usecs: Option<u32>,
#[prost(message, repeated, tag = "9")]
pub usermeta: Vec<RpbPair>,
#[prost(message, repeated, tag = "10")]
pub indexes: Vec<RpbPair>,
#[prost(bool, optional, tag = "11")]
pub deleted: Option<bool>,
}
impl WireValue for RpbContent {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbContent")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbGetResp {
#[prost(message, repeated, tag = "1")]
pub content: Vec<RpbContent>,
#[prost(bytes = "vec", optional, tag = "2")]
pub vclock: Option<Vec<u8>>,
#[prost(bool, optional, tag = "3")]
pub unchanged: Option<bool>,
}
impl WireValue for RpbGetResp {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbGetResp")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbPutReq {
#[prost(bytes = "vec", tag = "1")]
pub bucket: Vec<u8>,
#[prost(bytes = "vec", optional, tag = "2")]
pub key: Option<Vec<u8>>,
#[prost(bytes = "vec", optional, tag = "3")]
pub vclock: Option<Vec<u8>>,
#[prost(message, optional, tag = "4")]
pub content: Option<RpbContent>,
#[prost(uint32, optional, tag = "5")]
pub w: Option<u32>,
#[prost(uint32, optional, tag = "6")]
pub dw: Option<u32>,
#[prost(bool, optional, tag = "7")]
pub return_body: Option<bool>,
#[prost(uint32, optional, tag = "8")]
pub pw: Option<u32>,
#[prost(bool, optional, tag = "9")]
pub if_not_modified: Option<bool>,
#[prost(bool, optional, tag = "10")]
pub if_none_match: Option<bool>,
#[prost(bool, optional, tag = "11")]
pub return_head: Option<bool>,
#[prost(uint32, optional, tag = "12")]
pub timeout: Option<u32>,
#[prost(bool, optional, tag = "13")]
pub asis: Option<bool>,
#[prost(bool, optional, tag = "14")]
pub sloppy_quorum: Option<bool>,
#[prost(uint32, optional, tag = "15")]
pub n_val: Option<u32>,
#[prost(bytes = "vec", optional, tag = "16")]
pub r#type: Option<Vec<u8>>,
}
impl WireValue for RpbPutReq {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbPutReq")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbPutResp {
#[prost(message, repeated, tag = "1")]
pub content: Vec<RpbContent>,
#[prost(bytes = "vec", optional, tag = "2")]
pub vclock: Option<Vec<u8>>,
#[prost(bytes = "vec", optional, tag = "3")]
pub key: Option<Vec<u8>>,
}
impl WireValue for RpbPutResp {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbPutResp")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbDelReq {
#[prost(bytes = "vec", tag = "1")]
pub bucket: Vec<u8>,
#[prost(bytes = "vec", tag = "2")]
pub key: Vec<u8>,
#[prost(uint32, optional, tag = "3")]
pub rw: Option<u32>,
#[prost(bytes = "vec", optional, tag = "4")]
pub vclock: Option<Vec<u8>>,
#[prost(uint32, optional, tag = "5")]
pub r: Option<u32>,
#[prost(uint32, optional, tag = "6")]
pub w: Option<u32>,
#[prost(uint32, optional, tag = "7")]
pub pr: Option<u32>,
#[prost(uint32, optional, tag = "8")]
pub pw: Option<u32>,
#[prost(uint32, optional, tag = "9")]
pub dw: Option<u32>,
#[prost(uint32, optional, tag = "10")]
pub timeout: Option<u32>,
#[prost(bool, optional, tag = "11")]
pub sloppy_quorum: Option<bool>,
#[prost(uint32, optional, tag = "12")]
pub n_val: Option<u32>,
#[prost(bytes = "vec", optional, tag = "13")]
pub r#type: Option<Vec<u8>>,
}
impl WireValue for RpbDelReq {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbDelReq")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbServerInfoReq {}
impl WireValue for RpbServerInfoReq {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbServerInfoReq")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbGetServerInfoResp {
#[prost(bytes = "vec", optional, tag = "1")]
pub node: Option<Vec<u8>>,
#[prost(bytes = "vec", optional, tag = "2")]
pub server_version: Option<Vec<u8>>,
}
impl WireValue for RpbGetServerInfoResp {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbGetServerInfoResp")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbListBucketsReq {
#[prost(uint32, optional, tag = "1")]
pub timeout: Option<u32>,
#[prost(bool, optional, tag = "2")]
pub stream: Option<bool>,
#[prost(bytes = "vec", optional, tag = "3")]
pub r#type: Option<Vec<u8>>,
}
impl WireValue for RpbListBucketsReq {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbListBucketsReq")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbListBucketsResp {
#[prost(bytes = "vec", repeated, tag = "1")]
pub buckets: Vec<Vec<u8>>,
#[prost(bool, optional, tag = "2")]
pub done: Option<bool>,
}
impl WireValue for RpbListBucketsResp {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbListBucketsResp")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbListKeysReq {
#[prost(bytes = "vec", tag = "1")]
pub bucket: Vec<u8>,
#[prost(uint32, optional, tag = "2")]
pub timeout: Option<u32>,
#[prost(bytes = "vec", optional, tag = "3")]
pub r#type: Option<Vec<u8>>,
}
impl WireValue for RpbListKeysReq {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbListKeysReq")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbListKeysResp {
#[prost(bytes = "vec", repeated, tag = "1")]
pub keys: Vec<Vec<u8>>,
#[prost(bool, optional, tag = "2")]
pub done: Option<bool>,
}
impl WireValue for RpbListKeysResp {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbListKeysResp")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbBucketProps {
#[prost(uint32, optional, tag = "1")]
pub n_val: Option<u32>,
#[prost(bool, optional, tag = "2")]
pub allow_mult: Option<bool>,
#[prost(bool, optional, tag = "3")]
pub last_write_wins: Option<bool>,
#[prost(bool, optional, tag = "5")]
pub has_precommit: Option<bool>,
#[prost(bool, optional, tag = "7")]
pub has_postcommit: Option<bool>,
#[prost(uint32, optional, tag = "10")]
pub old_vclock: Option<u32>,
#[prost(uint32, optional, tag = "11")]
pub young_vclock: Option<u32>,
#[prost(uint32, optional, tag = "12")]
pub big_vclock: Option<u32>,
#[prost(uint32, optional, tag = "13")]
pub small_vclock: Option<u32>,
#[prost(uint32, optional, tag = "14")]
pub pr: Option<u32>,
#[prost(uint32, optional, tag = "15")]
pub r: Option<u32>,
#[prost(uint32, optional, tag = "16")]
pub w: Option<u32>,
#[prost(uint32, optional, tag = "17")]
pub pw: Option<u32>,
#[prost(uint32, optional, tag = "18")]
pub dw: Option<u32>,
#[prost(uint32, optional, tag = "19")]
pub rw: Option<u32>,
#[prost(bool, optional, tag = "20")]
pub basic_quorum: Option<bool>,
#[prost(bool, optional, tag = "21")]
pub notfound_ok: Option<bool>,
#[prost(bytes = "vec", optional, tag = "22")]
pub backend: Option<Vec<u8>>,
#[prost(bool, optional, tag = "23")]
pub search: Option<bool>,
#[prost(bytes = "vec", optional, tag = "25")]
pub search_index: Option<Vec<u8>>,
#[prost(bytes = "vec", optional, tag = "26")]
pub datatype: Option<Vec<u8>>,
#[prost(bool, optional, tag = "27")]
pub consistent: Option<bool>,
#[prost(bool, optional, tag = "28")]
pub write_once: Option<bool>,
#[prost(uint32, optional, tag = "29")]
pub hll_precision: Option<u32>,
#[prost(uint32, optional, tag = "30")]
pub chash_keyfun: Option<u32>,
#[prost(uint32, optional, tag = "31")]
pub replication_strategy: Option<u32>,
#[prost(bytes = "vec", optional, tag = "32")]
pub chash_keyfun_module: Option<Vec<u8>>,
}
pub const CHASH_KEYFUN_STD: u32 = 0;
pub const CHASH_KEYFUN_BUCKETONLY: u32 = 1;
pub const CHASH_KEYFUN_CUSTOM: u32 = 99;
pub const REPLICATION_STRATEGY_TOPOLOGY: u32 = 0;
pub const REPLICATION_STRATEGY_SUCCESSORS: u32 = 1;
impl WireValue for RpbBucketProps {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbBucketProps")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbGetBucketReq {
#[prost(bytes = "vec", tag = "1")]
pub bucket: Vec<u8>,
#[prost(bytes = "vec", optional, tag = "2")]
pub r#type: Option<Vec<u8>>,
}
impl WireValue for RpbGetBucketReq {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbGetBucketReq")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbGetBucketResp {
#[prost(message, optional, tag = "1")]
pub props: Option<RpbBucketProps>,
}
impl WireValue for RpbGetBucketResp {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbGetBucketResp")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbSetBucketReq {
#[prost(bytes = "vec", tag = "1")]
pub bucket: Vec<u8>,
#[prost(message, optional, tag = "2")]
pub props: Option<RpbBucketProps>,
#[prost(bytes = "vec", optional, tag = "3")]
pub r#type: Option<Vec<u8>>,
}
impl WireValue for RpbSetBucketReq {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbSetBucketReq")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbSetBucketResp {}
impl WireValue for RpbSetBucketResp {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbSetBucketResp")
}
}
pub const INDEX_QUERY_TYPE_EQ: i32 = 0;
pub const INDEX_QUERY_TYPE_RANGE: i32 = 1;
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbPair {
#[prost(bytes = "vec", tag = "1")]
pub key: Vec<u8>,
#[prost(bytes = "vec", optional, tag = "2")]
pub value: Option<Vec<u8>>,
}
impl WireValue for RpbPair {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbPair")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbIndexReq {
#[prost(bytes = "vec", tag = "1")]
pub bucket: Vec<u8>,
#[prost(bytes = "vec", tag = "2")]
pub index: Vec<u8>,
#[prost(int32, tag = "3")]
pub qtype: i32,
#[prost(bytes = "vec", optional, tag = "4")]
pub key: Option<Vec<u8>>,
#[prost(bytes = "vec", optional, tag = "5")]
pub range_min: Option<Vec<u8>>,
#[prost(bytes = "vec", optional, tag = "6")]
pub range_max: Option<Vec<u8>>,
#[prost(bool, optional, tag = "7")]
pub return_terms: Option<bool>,
#[prost(bool, optional, tag = "8")]
pub stream: Option<bool>,
#[prost(uint32, optional, tag = "9")]
pub max_results: Option<u32>,
#[prost(bytes = "vec", optional, tag = "10")]
pub continuation: Option<Vec<u8>>,
#[prost(uint32, optional, tag = "11")]
pub timeout: Option<u32>,
#[prost(bytes = "vec", optional, tag = "12")]
pub r#type: Option<Vec<u8>>,
#[prost(bytes = "vec", optional, tag = "13")]
pub term_regex: Option<Vec<u8>>,
#[prost(bool, optional, tag = "14")]
pub pagination_sort: Option<bool>,
#[prost(bytes = "vec", optional, tag = "15")]
pub cover_context: Option<Vec<u8>>,
#[prost(bool, optional, tag = "16")]
pub return_body: Option<bool>,
}
impl WireValue for RpbIndexReq {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbIndexReq")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct RpbIndexResp {
#[prost(bytes = "vec", repeated, tag = "1")]
pub keys: Vec<Vec<u8>>,
#[prost(message, repeated, tag = "2")]
pub results: Vec<RpbPair>,
#[prost(bytes = "vec", optional, tag = "3")]
pub continuation: Option<Vec<u8>>,
#[prost(bool, optional, tag = "4")]
pub done: Option<bool>,
}
impl WireValue for RpbIndexResp {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("riak.RpbIndexResp")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn message_code_round_trips() {
for code in [
MessageCode::ErrorResp,
MessageCode::PingReq,
MessageCode::PingResp,
MessageCode::ServerInfoReq,
MessageCode::GetServerInfoResp,
MessageCode::GetReq,
MessageCode::GetResp,
MessageCode::PutReq,
MessageCode::PutResp,
MessageCode::DelReq,
MessageCode::DelResp,
MessageCode::ListBucketsReq,
MessageCode::ListBucketsResp,
MessageCode::ListKeysReq,
MessageCode::ListKeysResp,
MessageCode::GetBucketReq,
MessageCode::GetBucketResp,
MessageCode::SetBucketReq,
MessageCode::SetBucketResp,
MessageCode::IndexReq,
MessageCode::IndexResp,
] {
let byte = code.as_u8();
assert_eq!(MessageCode::from_u8(byte).expect("known code"), code);
}
}
#[test]
fn message_code_rejects_unknown_byte() {
assert!(MessageCode::from_u8(3).is_err());
assert!(MessageCode::from_u8(99).is_err());
assert!(MessageCode::from_u8(255).is_err());
}
#[test]
fn message_code_round_trips_mapred() {
for code in [MessageCode::MapRedReq, MessageCode::MapRedResp] {
assert_eq!(MessageCode::from_u8(code.as_u8()).expect("known"), code);
}
}
#[test]
fn ping_req_round_trips_via_prost() {
let req = RpbPingReq::default();
let bytes = req.encode_to_vec();
assert!(bytes.is_empty(), "ping body must be empty");
let back = RpbPingReq::decode(bytes.as_slice()).expect("decode");
assert_eq!(back, req);
}
#[test]
fn ping_resp_round_trips_via_prost() {
let resp = RpbPingResp::default();
let bytes = resp.encode_to_vec();
assert!(bytes.is_empty());
let back = RpbPingResp::decode(bytes.as_slice()).expect("decode");
assert_eq!(back, resp);
}
#[test]
fn get_req_round_trips_with_optional_fields() {
let req = RpbGetReq {
bucket: b"users".to_vec(),
key: b"alice".to_vec(),
r: Some(2),
pr: Some(1),
basic_quorum: Some(true),
notfound_ok: Some(false),
if_modified: Some(b"vclock-bytes".to_vec()),
head: Some(false),
deletedvclock: None,
timeout: Some(5_000),
sloppy_quorum: None,
n_val: Some(3),
r#type: Some(b"default".to_vec()),
};
let bytes = req.encode_to_vec();
let back = RpbGetReq::decode(bytes.as_slice()).expect("decode");
assert_eq!(back, req);
}
#[test]
fn get_resp_round_trips() {
let resp = RpbGetResp {
content: vec![
RpbContent {
value: b"value-a".to_vec(),
content_type: Some(b"text/plain".to_vec()),
..RpbContent::default()
},
RpbContent {
value: b"value-b".to_vec(),
..RpbContent::default()
},
],
vclock: Some(b"vclk".to_vec()),
unchanged: Some(false),
};
let bytes = resp.encode_to_vec();
let back = RpbGetResp::decode(bytes.as_slice()).expect("decode");
assert_eq!(back, resp);
}
#[test]
fn put_req_round_trips() {
let req = RpbPutReq {
bucket: b"users".to_vec(),
key: Some(b"alice".to_vec()),
vclock: Some(b"vclk".to_vec()),
content: Some(RpbContent {
value: b"hello".to_vec(),
content_type: Some(b"application/json".to_vec()),
indexes: vec![RpbPair {
key: b"age_int".to_vec(),
value: Some(b"42".to_vec()),
}],
..RpbContent::default()
}),
w: Some(2),
dw: Some(1),
return_body: Some(true),
pw: Some(1),
if_not_modified: None,
if_none_match: None,
return_head: None,
timeout: Some(2_500),
asis: None,
sloppy_quorum: None,
n_val: Some(3),
r#type: None,
};
let bytes = req.encode_to_vec();
let back = RpbPutReq::decode(bytes.as_slice()).expect("decode");
assert_eq!(back, req);
}
#[test]
fn legacy_flat_value_put_migration() {
#[derive(Clone, PartialEq, ::prost::Message)]
struct LegacyPutReq {
#[prost(bytes = "vec", tag = "1")]
bucket: Vec<u8>,
#[prost(bytes = "vec", optional, tag = "2")]
key: Option<Vec<u8>>,
#[prost(bytes = "vec", tag = "4")]
value: Vec<u8>,
#[prost(message, repeated, tag = "100")]
indexes: Vec<RpbPair>,
}
let legacy_bad = LegacyPutReq {
bucket: b"users".to_vec(),
key: Some(b"alice".to_vec()),
value: vec![0xff, 0xff, 0xff],
indexes: Vec::new(),
};
let bytes = legacy_bad.encode_to_vec();
assert!(
RpbPutReq::decode(bytes.as_slice()).is_err(),
"legacy flat value that is not a valid submessage is rejected"
);
let new_shape = RpbPutReq {
bucket: b"users".to_vec(),
key: Some(b"alice".to_vec()),
content: Some(RpbContent {
value: b"hello".to_vec(),
indexes: vec![RpbPair {
key: b"age_int".to_vec(),
value: Some(b"42".to_vec()),
}],
..RpbContent::default()
}),
..RpbPutReq::default()
};
let back = RpbPutReq::decode(new_shape.encode_to_vec().as_slice()).expect("decode");
let content = back.content.expect("content present");
assert_eq!(content.value, b"hello");
assert_eq!(content.indexes.len(), 1);
}
#[test]
fn put_resp_round_trips() {
let resp = RpbPutResp {
content: vec![RpbContent {
value: b"echoed".to_vec(),
..RpbContent::default()
}],
vclock: Some(b"vclk2".to_vec()),
key: Some(b"alice".to_vec()),
};
let bytes = resp.encode_to_vec();
let back = RpbPutResp::decode(bytes.as_slice()).expect("decode");
assert_eq!(back, resp);
}
#[test]
fn rpb_link_round_trips() {
let link = RpbLink {
bucket: Some(b"people".to_vec()),
key: Some(b"bob".to_vec()),
tag: Some(b"friend".to_vec()),
};
let bytes = link.encode_to_vec();
let back = RpbLink::decode(bytes.as_slice()).expect("decode");
assert_eq!(back, link);
let empty = RpbLink::default();
assert!(empty.encode_to_vec().is_empty());
assert_eq!(RpbLink::decode([].as_slice()).expect("decode"), empty);
}
#[test]
fn rpb_content_round_trips_with_links_and_indexes() {
let content = RpbContent {
value: b"payload".to_vec(),
content_type: Some(b"text/plain".to_vec()),
links: vec![
RpbLink {
bucket: Some(b"people".to_vec()),
key: Some(b"bob".to_vec()),
tag: Some(b"friend".to_vec()),
},
RpbLink {
bucket: Some(b"work".to_vec()),
key: Some(b"acme".to_vec()),
tag: Some(b"employer".to_vec()),
},
],
indexes: vec![RpbPair {
key: b"age_int".to_vec(),
value: Some(b"42".to_vec()),
}],
..RpbContent::default()
};
let bytes = content.encode_to_vec();
let back = RpbContent::decode(bytes.as_slice()).expect("decode");
assert_eq!(back, content);
assert_eq!(back.links.len(), 2);
}
#[test]
fn rpb_content_round_trips_empty_links() {
let content = RpbContent {
value: b"v".to_vec(),
..RpbContent::default()
};
let bytes = content.encode_to_vec();
let back = RpbContent::decode(bytes.as_slice()).expect("decode");
assert_eq!(back, content);
assert!(back.links.is_empty());
}
#[test]
fn rpb_content_carries_full_field_set() {
let content = RpbContent {
value: b"v".to_vec(),
content_type: Some(b"text/plain".to_vec()),
charset: Some(b"utf-8".to_vec()),
content_encoding: Some(b"gzip".to_vec()),
vtag: Some(b"1a2b".to_vec()),
links: vec![RpbLink {
bucket: Some(b"b".to_vec()),
key: Some(b"k".to_vec()),
tag: Some(b"t".to_vec()),
}],
last_mod: Some(1_700_000_000),
last_mod_usecs: Some(123),
usermeta: vec![RpbPair {
key: b"meta".to_vec(),
value: Some(b"data".to_vec()),
}],
indexes: vec![RpbPair {
key: b"age_int".to_vec(),
value: Some(b"7".to_vec()),
}],
deleted: Some(false),
};
let bytes = content.encode_to_vec();
let back = RpbContent::decode(bytes.as_slice()).expect("decode");
assert_eq!(back, content);
}
#[test]
fn del_req_round_trips() {
let req = RpbDelReq {
bucket: b"users".to_vec(),
key: b"alice".to_vec(),
rw: Some(2),
vclock: Some(b"vclk".to_vec()),
r: Some(2),
w: Some(2),
pr: Some(1),
pw: Some(1),
dw: Some(1),
timeout: Some(1_000),
sloppy_quorum: Some(false),
n_val: Some(3),
r#type: None,
};
let bytes = req.encode_to_vec();
let back = RpbDelReq::decode(bytes.as_slice()).expect("decode");
assert_eq!(back, req);
}
#[test]
fn error_resp_round_trips() {
let resp = RpbErrorResp {
errmsg: b"boom".to_vec(),
errcode: 42,
};
let bytes = resp.encode_to_vec();
let back = RpbErrorResp::decode(bytes.as_slice()).expect("decode");
assert_eq!(back, resp);
}
#[test]
fn encode_is_byte_stable() {
let req = RpbGetReq {
bucket: b"b".to_vec(),
key: b"k".to_vec(),
..RpbGetReq::default()
};
let a = req.encode_to_vec();
let b = req.encode_to_vec();
assert_eq!(a, b, "prost encode is deterministic for plain fields");
}
#[test]
fn server_info_round_trips() {
let req = RpbServerInfoReq::default();
let bytes = req.encode_to_vec();
assert!(bytes.is_empty(), "server-info request body must be empty");
let back = RpbServerInfoReq::decode(bytes.as_slice()).expect("decode req");
assert_eq!(back, req);
let resp = RpbGetServerInfoResp {
node: Some(b"riak@127.0.0.1".to_vec()),
server_version: Some(b"dyniak 0.0.1".to_vec()),
};
let bytes = resp.encode_to_vec();
let back = RpbGetServerInfoResp::decode(bytes.as_slice()).expect("decode resp");
assert_eq!(back, resp);
}
#[test]
fn list_buckets_round_trips() {
let req = RpbListBucketsReq {
timeout: Some(1_000),
stream: Some(false),
r#type: Some(b"default".to_vec()),
};
let bytes = req.encode_to_vec();
let back = RpbListBucketsReq::decode(bytes.as_slice()).expect("decode req");
assert_eq!(back, req);
let resp = RpbListBucketsResp {
buckets: vec![b"users".to_vec(), b"sessions".to_vec()],
done: Some(true),
};
let bytes = resp.encode_to_vec();
let back = RpbListBucketsResp::decode(bytes.as_slice()).expect("decode resp");
assert_eq!(back, resp);
}
#[test]
fn list_keys_round_trips() {
let req = RpbListKeysReq {
bucket: b"users".to_vec(),
timeout: Some(2_500),
r#type: None,
};
let bytes = req.encode_to_vec();
let back = RpbListKeysReq::decode(bytes.as_slice()).expect("decode req");
assert_eq!(back, req);
let resp = RpbListKeysResp {
keys: vec![b"alice".to_vec(), b"bob".to_vec(), b"carol".to_vec()],
done: Some(true),
};
let bytes = resp.encode_to_vec();
let back = RpbListKeysResp::decode(bytes.as_slice()).expect("decode resp");
assert_eq!(back, resp);
}
#[test]
fn get_bucket_round_trips() {
let req = RpbGetBucketReq {
bucket: b"users".to_vec(),
r#type: Some(b"default".to_vec()),
};
let bytes = req.encode_to_vec();
let back = RpbGetBucketReq::decode(bytes.as_slice()).expect("decode req");
assert_eq!(back, req);
let resp = RpbGetBucketResp {
props: Some(RpbBucketProps {
n_val: Some(3),
allow_mult: Some(false),
last_write_wins: Some(true),
pr: Some(1),
r: Some(2),
w: Some(2),
pw: Some(1),
dw: Some(1),
rw: Some(2),
basic_quorum: Some(true),
notfound_ok: Some(false),
backend: Some(b"leveldb".to_vec()),
search_index: Some(b"users_idx".to_vec()),
datatype: None,
consistent: Some(false),
write_once: Some(false),
hll_precision: Some(14),
..RpbBucketProps::default()
}),
};
let bytes = resp.encode_to_vec();
let back = RpbGetBucketResp::decode(bytes.as_slice()).expect("decode resp");
assert_eq!(back, resp);
}
#[test]
fn set_bucket_round_trips() {
let req = RpbSetBucketReq {
bucket: b"users".to_vec(),
props: Some(RpbBucketProps {
n_val: Some(5),
allow_mult: Some(true),
..RpbBucketProps::default()
}),
r#type: Some(b"default".to_vec()),
};
let bytes = req.encode_to_vec();
let back = RpbSetBucketReq::decode(bytes.as_slice()).expect("decode req");
assert_eq!(back, req);
let resp = RpbSetBucketResp::default();
let bytes = resp.encode_to_vec();
assert!(bytes.is_empty(), "set-bucket response body must be empty");
let back = RpbSetBucketResp::decode(bytes.as_slice()).expect("decode resp");
assert_eq!(back, resp);
}
#[test]
fn bucket_props_chash_keyfun_round_trips() {
let props = RpbBucketProps {
n_val: Some(3),
chash_keyfun: Some(CHASH_KEYFUN_BUCKETONLY),
..RpbBucketProps::default()
};
let bytes = props.encode_to_vec();
let back = RpbBucketProps::decode(bytes.as_slice()).expect("decode props");
assert_eq!(back.chash_keyfun, Some(CHASH_KEYFUN_BUCKETONLY));
assert_eq!(back.n_val, Some(3));
assert_eq!(back, props);
}
#[test]
fn bucket_props_replication_strategy_round_trips() {
let props = RpbBucketProps {
replication_strategy: Some(REPLICATION_STRATEGY_SUCCESSORS),
n_val: Some(3),
..RpbBucketProps::default()
};
let bytes = props.encode_to_vec();
let back = RpbBucketProps::decode(bytes.as_slice()).expect("decode props");
assert_eq!(
back.replication_strategy,
Some(REPLICATION_STRATEGY_SUCCESSORS)
);
assert_eq!(back, props);
}
#[test]
fn bucket_props_default_omits_new_selectors() {
let props = RpbBucketProps {
n_val: Some(3),
..RpbBucketProps::default()
};
assert_eq!(props.chash_keyfun, None);
assert_eq!(props.replication_strategy, None);
let bytes = props.encode_to_vec();
let back = RpbBucketProps::decode(bytes.as_slice()).expect("decode props");
assert_eq!(back, props);
}
#[test]
fn index_round_trips() {
let req = RpbIndexReq {
bucket: b"users".to_vec(),
index: b"age_int".to_vec(),
qtype: INDEX_QUERY_TYPE_RANGE,
key: None,
range_min: Some(b"18".to_vec()),
range_max: Some(b"35".to_vec()),
return_terms: Some(true),
stream: Some(false),
max_results: Some(100),
continuation: Some(b"opaque-token".to_vec()),
timeout: Some(5_000),
r#type: Some(b"default".to_vec()),
term_regex: None,
pagination_sort: Some(true),
cover_context: None,
return_body: Some(false),
};
let bytes = req.encode_to_vec();
let back = RpbIndexReq::decode(bytes.as_slice()).expect("decode req");
assert_eq!(back, req);
let resp = RpbIndexResp {
keys: vec![b"alice".to_vec(), b"bob".to_vec()],
results: vec![
RpbPair {
key: b"21".to_vec(),
value: Some(b"alice".to_vec()),
},
RpbPair {
key: b"34".to_vec(),
value: Some(b"bob".to_vec()),
},
],
continuation: Some(b"next-page".to_vec()),
done: Some(true),
};
let bytes = resp.encode_to_vec();
let back = RpbIndexResp::decode(bytes.as_slice()).expect("decode resp");
assert_eq!(back, resp);
}
#[test]
fn index_eq_query_round_trips() {
let req = RpbIndexReq {
bucket: b"users".to_vec(),
index: b"city_bin".to_vec(),
qtype: INDEX_QUERY_TYPE_EQ,
key: Some(b"seattle".to_vec()),
..RpbIndexReq::default()
};
let bytes = req.encode_to_vec();
let back = RpbIndexReq::decode(bytes.as_slice()).expect("decode");
assert_eq!(back, req);
assert_eq!(back.qtype, 0);
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct DynRpbPeerInfo {
#[prost(uint32, tag = "1")]
pub idx: u32,
#[prost(bytes = "vec", tag = "2")]
pub dc: Vec<u8>,
#[prost(bytes = "vec", tag = "3")]
pub rack: Vec<u8>,
#[prost(bytes = "vec", tag = "4")]
pub host: Vec<u8>,
#[prost(uint32, tag = "5")]
pub port: u32,
#[prost(bytes = "vec", repeated, tag = "6")]
pub tokens: Vec<Vec<u8>>,
#[prost(bytes = "vec", tag = "7")]
pub state: Vec<u8>,
#[prost(bool, tag = "8")]
pub is_local: bool,
#[prost(bool, optional, tag = "9")]
pub is_secure: Option<bool>,
}
impl WireValue for DynRpbPeerInfo {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("dynomite.DynRpbPeerInfo")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct DynRpbStagedChange {
#[prost(uint32, tag = "1")]
pub kind: u32,
#[prost(uint32, optional, tag = "2")]
pub peer_idx: Option<u32>,
#[prost(message, optional, tag = "3")]
pub peer: Option<DynRpbPeerInfo>,
}
impl WireValue for DynRpbStagedChange {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("dynomite.DynRpbStagedChange")
}
}
pub const DYN_STAGED_CHANGE_ADD: u32 = 1;
pub const DYN_STAGED_CHANGE_REMOVE: u32 = 2;
#[derive(Clone, Eq, PartialEq, Message)]
pub struct DynRpbListPeersReq {}
impl WireValue for DynRpbListPeersReq {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("dynomite.DynRpbListPeersReq")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct DynRpbListPeersResp {
#[prost(message, repeated, tag = "1")]
pub peers: Vec<DynRpbPeerInfo>,
}
impl WireValue for DynRpbListPeersResp {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("dynomite.DynRpbListPeersResp")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct DynRpbClusterJoinReq {
#[prost(bytes = "vec", tag = "1")]
pub target: Vec<u8>,
}
impl WireValue for DynRpbClusterJoinReq {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("dynomite.DynRpbClusterJoinReq")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct DynRpbClusterJoinResp {
#[prost(message, optional, tag = "1")]
pub change: Option<DynRpbStagedChange>,
}
impl WireValue for DynRpbClusterJoinResp {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("dynomite.DynRpbClusterJoinResp")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct DynRpbClusterLeaveReq {
#[prost(uint32, tag = "1")]
pub peer_idx: u32,
}
impl WireValue for DynRpbClusterLeaveReq {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("dynomite.DynRpbClusterLeaveReq")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct DynRpbClusterLeaveResp {
#[prost(message, optional, tag = "1")]
pub change: Option<DynRpbStagedChange>,
}
impl WireValue for DynRpbClusterLeaveResp {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("dynomite.DynRpbClusterLeaveResp")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct DynRpbClusterPlanReq {}
impl WireValue for DynRpbClusterPlanReq {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("dynomite.DynRpbClusterPlanReq")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct DynRpbClusterPlanResp {
#[prost(message, repeated, tag = "1")]
pub changes: Vec<DynRpbStagedChange>,
}
impl WireValue for DynRpbClusterPlanResp {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("dynomite.DynRpbClusterPlanResp")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct DynRpbClusterCommitReq {}
impl WireValue for DynRpbClusterCommitReq {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("dynomite.DynRpbClusterCommitReq")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct DynRpbClusterCommitResp {
#[prost(uint32, tag = "1")]
pub applied: u32,
}
impl WireValue for DynRpbClusterCommitResp {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("dynomite.DynRpbClusterCommitResp")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct DynRpbAaePeerStatus {
#[prost(uint32, tag = "1")]
pub peer_idx: u32,
#[prost(bytes = "vec", tag = "2")]
pub dc: Vec<u8>,
#[prost(bytes = "vec", tag = "3")]
pub rack: Vec<u8>,
#[prost(uint64, tag = "4")]
pub last_exchange_unix: u64,
#[prost(uint64, tag = "5")]
pub divergent_keys_since_last_full_sweep: u64,
#[prost(uint64, tag = "6")]
pub repair_dispatched_total: u64,
}
impl WireValue for DynRpbAaePeerStatus {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("dynomite.DynRpbAaePeerStatus")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct DynRpbAaeStatusReq {}
impl WireValue for DynRpbAaeStatusReq {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("dynomite.DynRpbAaeStatusReq")
}
}
#[derive(Clone, Eq, PartialEq, Message)]
pub struct DynRpbAaeStatusResp {
#[prost(message, repeated, tag = "1")]
pub peers: Vec<DynRpbAaePeerStatus>,
#[prost(bytes = "vec", tag = "2")]
pub snapshot_path: Vec<u8>,
#[prost(uint64, tag = "3")]
pub snapshot_last_save_unix: u64,
#[prost(uint64, tag = "4")]
pub snapshot_last_load_unix: u64,
#[prost(uint64, tag = "5")]
pub snapshot_save_total: u64,
#[prost(uint64, tag = "6")]
pub snapshot_load_total: u64,
#[prost(uint64, tag = "7")]
pub snapshot_corruption_total: u64,
#[prost(uint32, tag = "8")]
pub tree_n_time_buckets: u32,
#[prost(uint32, tag = "9")]
pub tree_n_segments: u32,
#[prost(uint64, tag = "10")]
pub tree_time_window_seconds: u64,
#[prost(uint64, tag = "11")]
pub tree_memory_estimate_bytes: u64,
}
impl WireValue for DynRpbAaeStatusResp {
fn wire_type_id() -> WireTypeId {
WireTypeId::new("dynomite.DynRpbAaeStatusResp")
}
}
#[cfg(test)]
mod admin_tests {
use super::*;
#[test]
fn admin_message_codes_round_trip() {
for code in [
MessageCode::DynListPeersReq,
MessageCode::DynListPeersResp,
MessageCode::DynClusterJoinReq,
MessageCode::DynClusterJoinResp,
MessageCode::DynClusterLeaveReq,
MessageCode::DynClusterLeaveResp,
MessageCode::DynClusterPlanReq,
MessageCode::DynClusterPlanResp,
MessageCode::DynClusterCommitReq,
MessageCode::DynClusterCommitResp,
MessageCode::DynAaeStatusReq,
MessageCode::DynAaeStatusResp,
] {
let byte = code.as_u8();
assert_eq!(MessageCode::from_u8(byte).expect("known"), code);
}
}
#[test]
fn list_peers_req_is_empty() {
let req = DynRpbListPeersReq::default();
assert!(req.encode_to_vec().is_empty());
}
#[test]
fn peer_info_round_trips() {
let info = DynRpbPeerInfo {
idx: 1,
dc: b"dc1".to_vec(),
rack: b"r1".to_vec(),
host: b"127.0.0.1".to_vec(),
port: 8101,
tokens: vec![b"42".to_vec(), b"7777".to_vec()],
state: b"NORMAL".to_vec(),
is_local: false,
is_secure: Some(true),
};
let bytes = info.encode_to_vec();
let back = DynRpbPeerInfo::decode(bytes.as_slice()).expect("decode");
assert_eq!(back, info);
}
#[test]
fn list_peers_resp_round_trips() {
let resp = DynRpbListPeersResp {
peers: vec![
DynRpbPeerInfo {
idx: 0,
dc: b"dc1".to_vec(),
rack: b"r1".to_vec(),
host: b"10.0.0.1".to_vec(),
port: 8101,
tokens: vec![b"0".to_vec()],
state: b"NORMAL".to_vec(),
is_local: true,
is_secure: None,
},
DynRpbPeerInfo {
idx: 1,
dc: b"dc1".to_vec(),
rack: b"r1".to_vec(),
host: b"10.0.0.2".to_vec(),
port: 8101,
tokens: vec![b"2147483648".to_vec()],
state: b"DOWN".to_vec(),
is_local: false,
is_secure: None,
},
],
};
let bytes = resp.encode_to_vec();
let back = DynRpbListPeersResp::decode(bytes.as_slice()).expect("decode");
assert_eq!(back, resp);
}
#[test]
fn join_req_resp_round_trips() {
let req = DynRpbClusterJoinReq {
target: b"127.0.0.1:8103".to_vec(),
};
let back = DynRpbClusterJoinReq::decode(req.encode_to_vec().as_slice()).expect("decode");
assert_eq!(back, req);
let resp = DynRpbClusterJoinResp {
change: Some(DynRpbStagedChange {
kind: DYN_STAGED_CHANGE_ADD,
peer_idx: None,
peer: Some(DynRpbPeerInfo {
idx: 0,
dc: b"dc1".to_vec(),
rack: b"r1".to_vec(),
host: b"127.0.0.1".to_vec(),
port: 8103,
tokens: vec![b"123".to_vec()],
state: b"".to_vec(),
is_local: false,
is_secure: Some(false),
}),
}),
};
let back = DynRpbClusterJoinResp::decode(resp.encode_to_vec().as_slice()).expect("decode");
assert_eq!(back, resp);
}
#[test]
fn leave_req_resp_round_trips() {
let req = DynRpbClusterLeaveReq { peer_idx: 5 };
let back = DynRpbClusterLeaveReq::decode(req.encode_to_vec().as_slice()).expect("decode");
assert_eq!(back, req);
let resp = DynRpbClusterLeaveResp {
change: Some(DynRpbStagedChange {
kind: DYN_STAGED_CHANGE_REMOVE,
peer_idx: Some(5),
peer: None,
}),
};
let back = DynRpbClusterLeaveResp::decode(resp.encode_to_vec().as_slice()).expect("decode");
assert_eq!(back, resp);
}
#[test]
fn plan_round_trips() {
let req = DynRpbClusterPlanReq::default();
assert!(req.encode_to_vec().is_empty());
let resp = DynRpbClusterPlanResp {
changes: vec![
DynRpbStagedChange {
kind: DYN_STAGED_CHANGE_ADD,
peer_idx: None,
peer: Some(DynRpbPeerInfo {
idx: 0,
dc: b"d".to_vec(),
rack: b"r".to_vec(),
host: b"h".to_vec(),
port: 1,
tokens: vec![b"1".to_vec()],
state: b"".to_vec(),
is_local: false,
is_secure: None,
}),
},
DynRpbStagedChange {
kind: DYN_STAGED_CHANGE_REMOVE,
peer_idx: Some(2),
peer: None,
},
],
};
let back = DynRpbClusterPlanResp::decode(resp.encode_to_vec().as_slice()).expect("decode");
assert_eq!(back, resp);
}
#[test]
fn commit_round_trips() {
let req = DynRpbClusterCommitReq::default();
assert!(req.encode_to_vec().is_empty());
let resp = DynRpbClusterCommitResp { applied: 7 };
let back =
DynRpbClusterCommitResp::decode(resp.encode_to_vec().as_slice()).expect("decode");
assert_eq!(back, resp);
}
#[test]
fn aae_status_req_is_empty() {
let req = DynRpbAaeStatusReq::default();
assert!(req.encode_to_vec().is_empty());
}
#[test]
fn aae_status_resp_round_trips() {
let resp = DynRpbAaeStatusResp {
peers: vec![
DynRpbAaePeerStatus {
peer_idx: 0,
dc: b"dc1".to_vec(),
rack: b"rA".to_vec(),
last_exchange_unix: 1_700_000_000,
divergent_keys_since_last_full_sweep: 12,
repair_dispatched_total: 9,
},
DynRpbAaePeerStatus {
peer_idx: 1,
dc: b"dc1".to_vec(),
rack: b"rB".to_vec(),
last_exchange_unix: 0,
divergent_keys_since_last_full_sweep: 0,
repair_dispatched_total: 0,
},
],
snapshot_path: b"/var/lib/dynomite/aae/tree.snapshot".to_vec(),
snapshot_last_save_unix: 1_700_000_300,
snapshot_last_load_unix: 1_700_000_100,
snapshot_save_total: 5,
snapshot_load_total: 1,
snapshot_corruption_total: 0,
tree_n_time_buckets: 24,
tree_n_segments: 1024,
tree_time_window_seconds: 3600,
tree_memory_estimate_bytes: 4096,
};
let bytes = resp.encode_to_vec();
let back = DynRpbAaeStatusResp::decode(bytes.as_slice()).expect("decode");
assert_eq!(back, resp);
}
#[test]
fn every_message_reports_its_wire_type_id() {
let ids = [
RpbErrorResp::wire_type_id(),
RpbPingReq::wire_type_id(),
RpbPingResp::wire_type_id(),
RpbGetReq::wire_type_id(),
RpbLink::wire_type_id(),
RpbContent::wire_type_id(),
RpbGetResp::wire_type_id(),
RpbPutReq::wire_type_id(),
RpbPutResp::wire_type_id(),
RpbDelReq::wire_type_id(),
RpbServerInfoReq::wire_type_id(),
RpbGetServerInfoResp::wire_type_id(),
RpbListBucketsReq::wire_type_id(),
RpbListBucketsResp::wire_type_id(),
RpbListKeysReq::wire_type_id(),
RpbListKeysResp::wire_type_id(),
RpbBucketProps::wire_type_id(),
RpbGetBucketReq::wire_type_id(),
RpbGetBucketResp::wire_type_id(),
RpbSetBucketReq::wire_type_id(),
RpbSetBucketResp::wire_type_id(),
RpbPair::wire_type_id(),
RpbIndexReq::wire_type_id(),
RpbIndexResp::wire_type_id(),
DynRpbPeerInfo::wire_type_id(),
DynRpbStagedChange::wire_type_id(),
DynRpbListPeersReq::wire_type_id(),
DynRpbListPeersResp::wire_type_id(),
DynRpbClusterJoinReq::wire_type_id(),
DynRpbClusterJoinResp::wire_type_id(),
DynRpbClusterLeaveReq::wire_type_id(),
DynRpbClusterLeaveResp::wire_type_id(),
DynRpbClusterPlanReq::wire_type_id(),
DynRpbClusterPlanResp::wire_type_id(),
DynRpbClusterCommitReq::wire_type_id(),
DynRpbClusterCommitResp::wire_type_id(),
DynRpbAaePeerStatus::wire_type_id(),
DynRpbAaeStatusReq::wire_type_id(),
DynRpbAaeStatusResp::wire_type_id(),
];
assert_eq!(RpbLink::wire_type_id(), WireTypeId::new("riak.RpbLink"));
assert_eq!(
RpbContent::wire_type_id(),
WireTypeId::new("riak.RpbContent")
);
assert_eq!(
DynRpbAaeStatusResp::wire_type_id(),
WireTypeId::new("dynomite.DynRpbAaeStatusResp")
);
let mut seen = std::collections::HashSet::new();
for id in ids {
assert!(seen.insert(id), "duplicate wire type id: {id}");
}
assert_eq!(seen.len(), ids.len());
}
}