harness/payload/dogstatsd/
common.rs1use antithesis_sdk::random::random_choice;
4use rand::distr::Distribution;
5use rand::Rng;
6
7use crate::rand::Boundary;
8
9#[derive(Clone, Copy, Debug)]
11pub enum Vibe {
12 Clean,
14 Feral,
16}
17
18#[must_use]
20pub fn sample_vibe() -> Vibe {
21 match random_choice(&[Vibe::Clean, Vibe::Feral]) {
22 Some(Vibe::Feral) => Vibe::Feral,
23 _ => Vibe::Clean,
24 }
25}
26
27pub(crate) const NAME_SEPARATORS: &[u8] = b"._- ";
29
30pub(crate) const COMPLIANT_WORD: &[&[u8]] = &[
32 b"adp",
33 b"dogstatsd",
34 b"requests",
35 b"latency",
36 b"errors",
37 b"count",
38 b"total",
39 b"bytes",
40 b"queue",
41 b"workers",
42];
43
44pub(crate) const ABERRANT_WORD: &[&[u8]] = &[
47 b"",
48 b" ",
49 b"\t",
50 b"\0",
51 b"a:b",
52 b"a|b",
53 b"a,b",
54 b"#hash",
55 b"@at",
56 b"_sc",
57 b"_e{1,1}",
58 b"\x80",
59 b"\xc3",
60 b"\xed\xa0\x80",
61 b"\xc0\x80",
62 b"\xff\xfe",
63 b"emoji\xf0\x9f\x92\xa9",
64];
65
66pub(crate) const ABERRANT_VALUES: &[&[u8]] = &[
69 b"0",
70 b"-0",
71 b"inf",
72 b"-inf",
73 b"+inf",
74 b"nan",
75 b"infinity",
76 b"1e999999",
77 b"-1e999999",
78 b"0x1p4",
79 b"1_000",
80 b".",
81 b"+",
82 b"-",
83 b"1.",
84 b".5",
85 b"1:2:3:4:5",
86 b"00000000000000000000000000000000000000000000000000000001.5",
87 b"3.141592653589793115997963468544185161590576171875000000000000000000000000",
88 "\u{221e}".as_bytes(),
89 "-\u{221e}".as_bytes(),
90 "\u{ff11}\u{ff12}\u{ff13}".as_bytes(),
91 "\u{0664}\u{0662}".as_bytes(),
92];
93
94pub(crate) const COMPLIANT_TS: &[&[u8]] = &[b"1700000000", b"1", b"1609459200"];
96
97const COMPLIANT_TAG_KEYS: &[&[u8]] = &[b"env", b"service", b"region", b"version", b"team", b"host", b"shard"];
98const ABERRANT_TAG_KEYS: &[&[u8]] = &[b"", b" ", b":", b",", b"#", b"\0", b"\x80"];
99const COMPLIANT_TAG_VALUES: &[&[u8]] = &[
100 b"prod",
101 b"staging",
102 b"adp",
103 b"us-east-1",
104 b"eu-west-1",
105 b"1.2.3",
106 b"web01",
107 b"0",
108];
109const ABERRANT_TAG_VALUES: &[&[u8]] = &[b"", b",", b"|", b":", b"\xff", b"\xed\xa0\x80", b"a,b"];
110
111#[derive(Clone, Copy)]
113enum Form {
114 Compact,
115 Expanded,
116}
117
118pub(crate) fn extend_choice(buf: &mut Vec<u8>, vibe: Vibe, compliant: &[&[u8]], aberrant: &[&[u8]]) {
121 let pools: &[&[&[u8]]] = match vibe {
122 Vibe::Clean => &[compliant],
123 Vibe::Feral => &[compliant, aberrant],
124 };
125 if let Some(&pool) = random_choice(pools) {
126 if let Some(&item) = random_choice(pool) {
127 buf.extend_from_slice(item);
128 }
129 }
130}
131
132pub(crate) fn write_segments<R: Rng + ?Sized>(
135 rng: &mut R, buf: &mut Vec<u8>, vibe: Vibe, compliant: &[&[u8]], aberrant: &[&[u8]], separators: &[u8],
136) {
137 let count = Boundary::<u8>::new().sample(rng);
138 for i in 0..count {
139 if i > 0 {
140 if let Some(&sep) = random_choice(separators) {
141 buf.push(sep);
142 }
143 }
144 extend_choice(buf, vibe, compliant, aberrant);
145 }
146}
147
148pub(crate) fn write_words<R: Rng + ?Sized>(rng: &mut R, buf: &mut Vec<u8>, vibe: Vibe) {
150 write_segments(rng, buf, vibe, COMPLIANT_WORD, ABERRANT_WORD, NAME_SEPARATORS);
151}
152
153pub(crate) fn write_field(buf: &mut Vec<u8>, vibe: Vibe, prefix: &[u8], compliant: &[&[u8]], aberrant: &[&[u8]]) {
155 buf.push(b'|');
156 buf.extend_from_slice(prefix);
157 extend_choice(buf, vibe, compliant, aberrant);
158}
159
160pub(crate) fn write_tags<R: Rng + ?Sized>(rng: &mut R, buf: &mut Vec<u8>, vibe: Vibe) {
164 let count = Boundary::<u8>::new().sample(rng);
165 for t in 0..count {
166 if t == 0 {
167 buf.extend_from_slice(b"|#");
168 } else {
169 buf.push(b',');
170 }
171 write_segments(rng, buf, vibe, COMPLIANT_TAG_KEYS, ABERRANT_TAG_KEYS, NAME_SEPARATORS);
172 buf.push(b':');
173 write_segments(
174 rng,
175 buf,
176 vibe,
177 COMPLIANT_TAG_VALUES,
178 ABERRANT_TAG_VALUES,
179 NAME_SEPARATORS,
180 );
181 }
182}
183
184pub(crate) fn write_number<R: Rng + ?Sized>(rng: &mut R, buf: &mut Vec<u8>, digits: &[u8]) {
187 match random_choice(&[Form::Compact, Form::Expanded]) {
188 Some(Form::Expanded) => {
189 let (sign, rest) = match digits.first() {
190 Some(&(b'-' | b'+')) => (&digits[..1], &digits[1..]),
191 _ => (&digits[..0], digits),
192 };
193 buf.extend_from_slice(sign);
194 pad_zeros(rng, buf);
195 buf.extend_from_slice(rest);
196 let fractional = rest.contains(&b'.') && !rest.iter().any(|&c| c == b'e' || c == b'E');
197 if fractional {
198 pad_zeros(rng, buf);
199 }
200 }
201 _ => buf.extend_from_slice(digits),
202 }
203}
204
205fn pad_zeros<R: Rng + ?Sized>(rng: &mut R, buf: &mut Vec<u8>) {
207 let zeros = usize::from(Boundary::<u8>::new().sample(rng));
208 buf.resize(buf.len() + zeros, b'0');
209}