Skip to content

Commit a7cca35

Browse files
author
jianggang
committed
✨ feat: support debug event
1 parent a9344fd commit a7cca35

File tree

5 files changed

+114
-35
lines changed

5 files changed

+114
-35
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
edition = "2021"
33
name = "feature-probe-server-sdk"
4-
version = "2.1.1"
4+
version = "2.2.0"
55
license = "Apache-2.0"
66
authors = ["maintain@featureprobe.com"]
77
description = "FeatureProbe Server Side SDK for Rust"
@@ -40,7 +40,7 @@ thiserror = "1.0"
4040
tracing = "0.1"
4141
url = "2"
4242

43-
feature-probe-event = { version = "1.1.3", features = [
43+
feature-probe-event = { version = "1.2.0", features = [
4444
"use_tokio",
4545
], default-features = false}
4646

src/evaluate.rs

Lines changed: 70 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,16 @@ pub struct EvalParams<'a> {
123123
variations: &'a [Value],
124124
segment_repo: &'a HashMap<String, Segment>,
125125
toggle_repo: &'a HashMap<String, Toggle>,
126+
debug_until_time: Option<u64>,
126127
}
127128

128-
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Default)]
129+
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Default, Clone)]
129130
#[serde(rename_all = "camelCase")]
130131
pub struct EvalDetail<T> {
131132
pub value: Option<T>,
132133
pub rule_index: Option<usize>,
133134
pub track_access_events: Option<bool>,
135+
pub debug_until_time: Option<u64>,
134136
pub last_modified: Option<u64>,
135137
pub variation_index: Option<usize>,
136138
pub version: Option<u64>,
@@ -168,6 +170,7 @@ impl Toggle {
168170
toggle_repo: &HashMap<String, Toggle>,
169171
is_detail: bool,
170172
deep: u8,
173+
debug_until_time: Option<u64>,
171174
) -> EvalDetail<Value> {
172175
let eval_param = EvalParams {
173176
user,
@@ -176,6 +179,7 @@ impl Toggle {
176179
key: &self.key,
177180
is_detail,
178181
variations: &self.variations,
182+
debug_until_time,
179183
};
180184

181185
match self.do_eval(&eval_param, deep) {
@@ -191,20 +195,42 @@ impl Toggle {
191195
) -> Result<EvalDetail<Value>, PrerequisiteError> {
192196
if !self.enabled {
193197
let v = self.disabled_serve.select_variation(eval_param).ok();
194-
return Ok(self.serve_variation(v, "disabled".to_owned(), None));
198+
return Ok(self.serve_variation(
199+
v,
200+
"disabled".to_owned(),
201+
None,
202+
eval_param.debug_until_time,
203+
));
195204
}
196205

197-
self.check_prerequisites(eval_param, max_deep)?;
206+
match self.check_prerequisites(eval_param, max_deep) {
207+
Ok(is_pass) => {
208+
if !is_pass {
209+
return Ok(self.default_variation(eval_param, None));
210+
}
211+
}
212+
Err(e) => return Err(e),
213+
}
198214

199215
for (i, rule) in self.rules.iter().enumerate() {
200216
match rule.serve_variation(eval_param) {
201217
Ok(v) => {
202218
if v.is_some() {
203-
return Ok(self.serve_variation(v, format!("rule {i}"), Some(i)));
219+
return Ok(self.serve_variation(
220+
v,
221+
format!("rule {i}"),
222+
Some(i),
223+
eval_param.debug_until_time,
224+
));
204225
}
205226
}
206227
Err(e) => {
207-
return Ok(self.serve_variation(None, format!("{e:?}"), Some(i)));
228+
return Ok(self.serve_variation(
229+
None,
230+
format!("{e:?}"),
231+
Some(i),
232+
eval_param.debug_until_time,
233+
));
208234
}
209235
}
210236
}
@@ -216,7 +242,7 @@ impl Toggle {
216242
&self,
217243
eval_param: &EvalParams,
218244
deep: u8,
219-
) -> Result<(), PrerequisiteError> {
245+
) -> Result<bool, PrerequisiteError> {
220246
if deep == 0 {
221247
return Err(PrerequisiteError::DeepOverflow);
222248
}
@@ -235,32 +261,35 @@ impl Toggle {
235261
user: eval_param.user,
236262
segment_repo: eval_param.segment_repo,
237263
toggle_repo: eval_param.toggle_repo,
264+
debug_until_time: eval_param.debug_until_time,
238265
},
239266
deep - 1,
240267
)?,
241268
};
242269

243270
match eval.value {
244271
Some(v) if v == pre.value => continue,
245-
_ => return Err(PrerequisiteError::NotMatch(pre.key.to_string())),
272+
_ => return Ok(false),
246273
}
247274
}
275+
return Ok(true);
248276
}
249-
250-
Ok(())
277+
Ok(true)
251278
}
252279

253280
fn serve_variation(
254281
&self,
255282
v: Option<Variation>,
256283
reason: String,
257284
rule_index: Option<usize>,
285+
debug_until_time: Option<u64>,
258286
) -> EvalDetail<Value> {
259287
EvalDetail {
260288
variation_index: v.as_ref().map(|v| v.index),
261289
value: v.map(|v| v.value),
262290
version: Some(self.version),
263291
track_access_events: self.track_access_events,
292+
debug_until_time,
264293
last_modified: self.last_modified,
265294
rule_index,
266295
reason,
@@ -273,10 +302,18 @@ impl Toggle {
273302
reason: Option<String>,
274303
) -> EvalDetail<Value> {
275304
match self.default_serve.select_variation(eval_param) {
276-
Ok(v) => {
277-
self.serve_variation(Some(v), concat_reason("default".to_owned(), reason), None)
278-
}
279-
Err(e) => self.serve_variation(None, concat_reason(format!("{e:?}"), reason), None),
305+
Ok(v) => self.serve_variation(
306+
Some(v),
307+
concat_reason("default".to_owned(), reason),
308+
None,
309+
eval_param.debug_until_time,
310+
),
311+
Err(e) => self.serve_variation(
312+
None,
313+
concat_reason(format!("{e:?}"), reason),
314+
None,
315+
eval_param.debug_until_time,
316+
),
280317
}
281318
}
282319

@@ -524,12 +561,14 @@ impl Segment {
524561
}
525562

526563
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
564+
#[serde(rename_all = "camelCase")]
527565
pub struct Repository {
528566
pub segments: HashMap<String, Segment>,
529567
pub toggles: HashMap<String, Toggle>,
530568
pub events: Option<Value>,
531569
// TODO: remove option next release
532570
pub version: Option<u128>,
571+
pub debug_until_time: Option<u64>,
533572
}
534573

535574
impl Default for Repository {
@@ -539,6 +578,7 @@ impl Default for Repository {
539578
toggles: Default::default(),
540579
events: Default::default(),
541580
version: Some(0),
581+
debug_until_time: None,
542582
}
543583
}
544584
}
@@ -612,7 +652,7 @@ mod tests {
612652

613653
let user = FPUser::new().with("city", "4");
614654
let toggle = repo.toggles.get("json_toggle").unwrap();
615-
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP);
655+
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP, None);
616656
let r = r.value.unwrap();
617657
let r = r.as_object().unwrap();
618658
assert!(r.get("variation_1").is_some());
@@ -629,7 +669,7 @@ mod tests {
629669

630670
let user = FPUser::new().with("city", "100");
631671
let toggle = repo.toggles.get("not_in_segment").unwrap();
632-
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP);
672+
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP, None);
633673
let r = r.value.unwrap();
634674
let r = r.as_object().unwrap();
635675
assert!(r.get("not_in").is_some());
@@ -646,19 +686,19 @@ mod tests {
646686

647687
let user = FPUser::new().with("city", "1").with("os", "linux");
648688
let toggle = repo.toggles.get("multi_condition_toggle").unwrap();
649-
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP);
689+
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP, None);
650690
let r = r.value.unwrap();
651691
let r = r.as_object().unwrap();
652692
assert!(r.get("variation_0").is_some());
653693

654694
let user = FPUser::new().with("os", "linux");
655695
let toggle = repo.toggles.get("multi_condition_toggle").unwrap();
656-
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP);
696+
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP, None);
657697
assert!(r.reason.starts_with("default"));
658698

659699
let user = FPUser::new().with("city", "1");
660700
let toggle = repo.toggles.get("multi_condition_toggle").unwrap();
661-
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP);
701+
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP, None);
662702
assert!(r.reason.starts_with("default"));
663703
}
664704

@@ -678,7 +718,7 @@ mod tests {
678718
let mut variation_1 = 0;
679719
let mut variation_2 = 0;
680720
for user in &users {
681-
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP);
721+
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP, None);
682722
let r = r.value.unwrap();
683723
let r = r.as_object().unwrap();
684724
if r.get("variation_0").is_some() {
@@ -709,7 +749,7 @@ mod tests {
709749

710750
let user = FPUser::new().with("city", "100");
711751
let toggle = repo.toggles.get("disabled_toggle").unwrap();
712-
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP);
752+
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP, None);
713753
assert!(r
714754
.value
715755
.unwrap()
@@ -731,7 +771,7 @@ mod tests {
731771
let user = FPUser::new().with("city", "4");
732772

733773
let toggle = repo.toggles.get("prerequisite_toggle").unwrap();
734-
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP);
774+
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP, None);
735775

736776
assert!(r.value.unwrap().as_object().unwrap().get("2").is_some());
737777
}
@@ -748,7 +788,7 @@ mod tests {
748788
let user = FPUser::new().with("city", "4");
749789

750790
let toggle = repo.toggles.get("prerequisite_toggle_not_exist").unwrap();
751-
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP);
791+
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP, None);
752792

753793
assert!(r.value.unwrap().as_object().unwrap().get("1").is_some());
754794
assert!(r.reason.contains("not exist"));
@@ -766,10 +806,10 @@ mod tests {
766806
let user = FPUser::new().with("city", "4");
767807

768808
let toggle = repo.toggles.get("prerequisite_toggle_not_match").unwrap();
769-
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP);
809+
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP, None);
770810

771811
assert!(r.value.unwrap().as_object().unwrap().get("1").is_some());
772-
assert!(r.reason.contains("not match"));
812+
assert!(r.reason.contains("default."));
773813
}
774814

775815
#[test]
@@ -784,7 +824,7 @@ mod tests {
784824
let user = FPUser::new().with("city", "4");
785825

786826
let toggle = repo.toggles.get("prerequisite_toggle").unwrap();
787-
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, 1);
827+
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, 1, None);
788828

789829
assert!(r.value.unwrap().as_object().unwrap().get("1").is_some());
790830
assert!(r.reason.contains("deep overflow"));
@@ -828,6 +868,7 @@ mod distribution_tests {
828868
variations: &[],
829869
segment_repo: &Default::default(),
830870
toggle_repo: &Default::default(),
871+
debug_until_time: None,
831872
};
832873
let result = distribution.find_index(&params);
833874

@@ -854,6 +895,7 @@ mod distribution_tests {
854895
variations: &[],
855896
segment_repo: &Default::default(),
856897
toggle_repo: &Default::default(),
898+
debug_until_time: None,
857899
};
858900
let result = distribution.find_index(&params);
859901

@@ -866,6 +908,7 @@ mod distribution_tests {
866908
variations: &[],
867909
segment_repo: &Default::default(),
868910
toggle_repo: &Default::default(),
911+
debug_until_time: None,
869912
};
870913
let result = distribution.find_index(&params_no_detail);
871914
assert!(result.is_err());
@@ -895,6 +938,7 @@ mod distribution_tests {
895938
],
896939
segment_repo: &Default::default(),
897940
toggle_repo: &Default::default(),
941+
debug_until_time: None,
898942
};
899943

900944
let result = serve.select_variation(&params).expect_err("e");
@@ -1245,7 +1289,7 @@ mod condition_tests {
12451289

12461290
let user = FPUser::new().with("city", "1");
12471291
let toggle = repo.toggles.get("json_toggle").unwrap();
1248-
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP);
1292+
let r = toggle.eval(&user, &repo.segments, &repo.toggles, false, MAX_DEEP, None);
12491293
let r = r.value.unwrap();
12501294
let r = r.as_object().unwrap();
12511295
assert!(r.get("variation_0").is_some());

0 commit comments

Comments
 (0)