Skip to content

Commit 32426bc

Browse files
committed
consistent test rng thingy
1 parent 3c6c4d6 commit 32426bc

File tree

6 files changed

+125
-13
lines changed

6 files changed

+125
-13
lines changed

Cargo.lock

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

nexus/fm/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ chrono.workspace = true
1212
iddqd.workspace = true
1313
nexus-types.workspace = true
1414
omicron-uuid-kinds.workspace = true
15+
rand.workspace = true
1516
schemars.workspace = true
1617
serde.workspace = true
1718
serde_json.workspace = true
1819
slog.workspace = true
20+
typed-rng.workspace = true
1921

2022
omicron-workspace-hack.workspace = true
2123

nexus/fm/src/builder.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use slog::Logger;
1212

1313
mod case;
1414
pub use case::{AllCases, CaseBuilder};
15+
pub(crate) mod rng;
16+
pub use rng::SitrepBuilderRng;
1517

1618
#[derive(Debug)]
1719
pub struct SitrepBuilder<'a> {
@@ -30,15 +32,29 @@ impl<'a> SitrepBuilder<'a> {
3032
inventory: &'a inventory::Collection,
3133
parent_sitrep: Option<&'a fm::Sitrep>,
3234
) -> Self {
33-
let sitrep_id = SitrepUuid::new_v4();
35+
Self::new_with_rng(
36+
log,
37+
inventory,
38+
parent_sitrep,
39+
SitrepBuilderRng::from_entropy(),
40+
)
41+
}
42+
43+
pub fn new_with_rng(
44+
log: &Logger,
45+
inventory: &'a inventory::Collection,
46+
parent_sitrep: Option<&'a fm::Sitrep>,
47+
mut rng: SitrepBuilderRng,
48+
) -> Self {
49+
let sitrep_id = rng.sitrep_id();
3450
let log = log.new(slog::o!(
3551
"sitrep_id" => format!("{sitrep_id:?}"),
3652
"parent_sitrep_id" => format!("{:?}", parent_sitrep.as_ref().map(|s| s.id())),
3753
"inv_collection_id" => format!("{:?}", inventory.id),
3854
));
3955

4056
let (cases, impact_lists) =
41-
case::AllCases::new(log.clone(), sitrep_id, parent_sitrep);
57+
case::AllCases::new(log.clone(), sitrep_id, parent_sitrep, rng);
4258

4359
slog::info!(
4460
&log,

nexus/fm/src/builder/case.rs

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
// License, v. 2.0. If a copy of the MPL was not distributed with this
33
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44

5+
use super::rng;
56
use crate::alert;
67
use anyhow::Context;
78
use chrono::Utc;
89
use iddqd::id_ord_map::{self, IdOrdMap};
910
use nexus_types::fm;
1011
use nexus_types::inventory::SpType;
11-
use omicron_uuid_kinds::AlertUuid;
1212
use omicron_uuid_kinds::CaseUuid;
1313
use omicron_uuid_kinds::SitrepUuid;
1414
use std::collections::{HashMap, HashSet};
@@ -19,20 +19,23 @@ pub struct CaseBuilder {
1919
pub log: slog::Logger,
2020
pub case: fm::Case,
2121
pub sitrep_id: SitrepUuid,
22+
rng: rng::CaseBuilderRng,
2223
}
2324

2425
#[derive(Debug)]
2526
pub struct AllCases {
2627
log: slog::Logger,
2728
sitrep_id: SitrepUuid,
2829
pub cases: IdOrdMap<CaseBuilder>,
30+
rng: rng::SitrepBuilderRng,
2931
}
3032

3133
impl AllCases {
32-
pub fn new(
34+
pub(super) fn new(
3335
log: slog::Logger,
3436
sitrep_id: SitrepUuid,
3537
parent_sitrep: Option<&fm::Sitrep>,
38+
mut rng: rng::SitrepBuilderRng,
3639
) -> (Self, ImpactLists) {
3740
// Copy forward any open cases from the parent sitrep.
3841
// If a case was closed in the parent sitrep, skip it.
@@ -48,11 +51,12 @@ impl AllCases {
4851
.or_default()
4952
.insert(case.id);
5053
}
51-
CaseBuilder::new(&log, sitrep_id, case.clone())
54+
let rng = rng::CaseBuilderRng::new(case.id, &mut rng);
55+
CaseBuilder::new(&log, sitrep_id, case.clone(), rng)
5256
})
5357
.collect();
5458

55-
let cases = Self { log, sitrep_id, cases };
59+
let cases = Self { log, sitrep_id, cases, rng };
5660
let impact_lists = ImpactLists { cases_by_sp: cases_by_location };
5761
(cases, impact_lists)
5862
}
@@ -61,7 +65,7 @@ impl AllCases {
6165
&mut self,
6266
de: fm::DiagnosisEngineKind,
6367
) -> anyhow::Result<iddqd::id_ord_map::RefMut<'_, CaseBuilder>> {
64-
let id = CaseUuid::new_v4();
68+
let (id, case_rng) = self.rng.next_case();
6569
let sitrep_id = self.sitrep_id;
6670
let case = match self.cases.entry(&id) {
6771
iddqd::id_ord_map::Entry::Occupied(_) => {
@@ -80,7 +84,9 @@ impl AllCases {
8084
alerts_requested: Default::default(),
8185
impacted_locations: Default::default(),
8286
};
83-
entry.insert(CaseBuilder::new(&self.log, sitrep_id, case))
87+
entry.insert(CaseBuilder::new(
88+
&self.log, sitrep_id, case, case_rng,
89+
))
8490
}
8591
};
8692

@@ -107,20 +113,25 @@ impl AllCases {
107113
}
108114

109115
impl CaseBuilder {
110-
fn new(log: &slog::Logger, sitrep_id: SitrepUuid, case: fm::Case) -> Self {
116+
fn new(
117+
log: &slog::Logger,
118+
sitrep_id: SitrepUuid,
119+
case: fm::Case,
120+
rng: rng::CaseBuilderRng,
121+
) -> Self {
111122
let log = log.new(slog::o!(
112123
"case_id" => format!("{:?}", case.id),
113124
"de" => case.de.to_string(),
114125
"created_sitrep_id" => format!("{:?}", case.created_sitrep_id),
115126
));
116-
Self { log, case, sitrep_id }
127+
Self { log, case, sitrep_id, rng }
117128
}
118129

119130
pub fn request_alert<A: alert::Alert>(
120131
&mut self,
121132
alert: &A,
122133
) -> anyhow::Result<()> {
123-
let id = AlertUuid::new_v4();
134+
let id = self.rng.next_alert();
124135
let class = A::CLASS;
125136
let req = fm::AlertRequest {
126137
id,

nexus/fm/src/builder/rng.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
//! RNGs for sitrep generation to allow reproduceable UUID generation
6+
//! (particularly for tests).
7+
//!
8+
//! This is similar to the `nexus_reconfigurator_planning::planner::rng`
9+
//! module.
10+
11+
use omicron_uuid_kinds::AlertKind;
12+
use omicron_uuid_kinds::AlertUuid;
13+
use omicron_uuid_kinds::CaseKind;
14+
use omicron_uuid_kinds::CaseUuid;
15+
use omicron_uuid_kinds::SitrepUuid;
16+
use rand::SeedableRng as _;
17+
use rand::rngs::StdRng;
18+
use std::hash::Hash;
19+
use typed_rng::TypedUuidRng;
20+
21+
#[derive(Clone, Debug)]
22+
pub struct SitrepBuilderRng {
23+
parent: StdRng,
24+
case_rng: TypedUuidRng<CaseKind>,
25+
}
26+
27+
impl SitrepBuilderRng {
28+
pub fn from_entropy() -> Self {
29+
Self::new_from_parent(StdRng::from_os_rng())
30+
}
31+
32+
pub fn from_seed<H: Hash>(seed: H) -> Self {
33+
// Important to add some more bytes here, so that builders with the
34+
// same seed but different purposes don't end up with the same UUIDs.
35+
const SEED_EXTRA: &str = "sitrep-builder";
36+
Self::new_from_parent(typed_rng::from_seed(seed, SEED_EXTRA))
37+
}
38+
39+
pub fn new_from_parent(mut parent: StdRng) -> Self {
40+
let case_rng = TypedUuidRng::from_parent_rng(&mut parent, "case");
41+
42+
Self { parent, case_rng }
43+
}
44+
45+
pub(super) fn sitrep_id(&mut self) -> SitrepUuid {
46+
// we only need a single sitrep UUID, so no sense storing a whole RNG
47+
// for it in the builder RNGs...
48+
TypedUuidRng::from_parent_rng(&mut self.parent, "sitrep").next()
49+
}
50+
51+
pub(super) fn next_case(&mut self) -> (CaseUuid, CaseBuilderRng) {
52+
let case_id = self.case_rng.next();
53+
let rng = CaseBuilderRng::new(case_id, self);
54+
(case_id, rng)
55+
}
56+
}
57+
58+
#[derive(Clone, Debug)]
59+
pub(super) struct CaseBuilderRng {
60+
alert_rng: TypedUuidRng<AlertKind>,
61+
}
62+
63+
impl CaseBuilderRng {
64+
pub(super) fn new(
65+
case_id: CaseUuid,
66+
sitrep: &mut SitrepBuilderRng,
67+
) -> Self {
68+
let alert_rng = TypedUuidRng::from_parent_rng(
69+
&mut sitrep.parent,
70+
(case_id, "alert"),
71+
);
72+
Self { alert_rng }
73+
}
74+
75+
pub(super) fn next_alert(&mut self) -> AlertUuid {
76+
self.alert_rng.next()
77+
}
78+
}

nexus/fm/src/diagnosis/power_shelf.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -498,8 +498,12 @@ mod test {
498498
.nsleds(2)
499499
.build();
500500
let mut de = PowerShelfDiagnosis::new(&logctx.log);
501-
let mut sitrep =
502-
SitrepBuilder::new(&logctx.log, &example_system.collection, None);
501+
let mut sitrep = SitrepBuilder::new_with_rng(
502+
&logctx.log,
503+
&example_system.collection,
504+
None,
505+
crate::builder::SitrepBuilderRng::from_seed(TEST_NAME),
506+
);
503507

504508
de.analyze_ereport(
505509
&mut sitrep,

0 commit comments

Comments
 (0)