ci_engine/result_cache/
spot_check.rs1use super::key::{CacheKey, entry_id_bytes};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum SpotCheck {
13 Never,
15 Always,
17 Fraction {
19 numerator: u32,
21 denominator: u32,
23 },
24}
25
26impl Default for SpotCheck {
27 fn default() -> Self {
28 Self::Fraction {
29 numerator: 1,
30 denominator: 32,
31 }
32 }
33}
34
35impl SpotCheck {
36 #[must_use]
38 pub fn should_sample(&self, key: &CacheKey, check_name: &str) -> bool {
39 match *self {
40 Self::Never => false,
41 Self::Always => true,
42 Self::Fraction {
43 numerator,
44 denominator,
45 } => {
46 if denominator == 0 || numerator == 0 {
47 return false;
48 }
49 if numerator >= denominator {
50 return true;
51 }
52 let bytes = entry_id_bytes(key, check_name);
53 let bucket = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
54 bucket % denominator < numerator
55 }
56 }
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use crypto::{Basis, BasisKind, StateRef};
63
64 use super::*;
65 use crate::model::ExecutionContext;
66
67 fn key() -> CacheKey {
68 let mut check = ci_config::Check::new("build", vec!["true".to_string()]);
69 check.timeout_secs = 1;
70 check.supersede = false;
71 CacheKey::derive(
72 &std::collections::BTreeMap::new(),
73 &ExecutionContext {
74 repo: "test/repo".to_string(),
75 state: StateRef {
76 content_hash: "state".to_string(),
77 change_id: "change".to_string(),
78 logical_change_id: None,
79 },
80 basis: Basis {
81 kind: BasisKind::Branch,
82 evaluated_tree_digest: "tree".to_string(),
83 },
84 definition_digest: "definition".to_string(),
85 toolchain: None,
86 pick_id: None,
87 attempt: 1,
88 runner: None,
89 image_digest: None,
90 },
91 &check,
92 )
93 }
94
95 #[test]
96 fn fraction_is_deterministic_for_a_key() {
97 let key = key();
98 let policy = SpotCheck::Fraction {
99 numerator: 1,
100 denominator: 2,
101 };
102 let first = policy.should_sample(&key, "build");
103 assert_eq!(first, policy.should_sample(&key, "build"));
104 assert!(SpotCheck::Always.should_sample(&key, "build"));
105 assert!(!SpotCheck::Never.should_sample(&key, "build"));
106 }
107}