Skip to content

Commit e3e2d77

Browse files
committed
more test util wiggling
1 parent 32426bc commit e3e2d77

File tree

5 files changed

+182
-22
lines changed

5 files changed

+182
-22
lines changed

nexus/fm/src/builder.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ impl<'a> SitrepBuilder<'a> {
4646
parent_sitrep: Option<&'a fm::Sitrep>,
4747
mut rng: SitrepBuilderRng,
4848
) -> Self {
49+
// TODO(eliza): should the RNG also be seeded with the parent sitrep
50+
// UUID and/or the Omicron zone UUID? Hmm.
4951
let sitrep_id = rng.sitrep_id();
5052
let log = log.new(slog::o!(
5153
"sitrep_id" => format!("{sitrep_id:?}"),

nexus/fm/src/diagnosis/power_shelf.rs

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -461,10 +461,11 @@ struct PmbusStatus {
461461
mod test {
462462
use super::*;
463463
use crate::ereport_analysis::test as ereport_test;
464+
use crate::test_util::FmTest;
465+
use chrono::{DateTime, Utc};
464466
use nexus_types::fm::ereport::Reporter;
465-
use omicron_test_utils::dev::test_setup_log;
466-
use omicron_uuid_kinds::EreporterRestartUuid;
467467
use omicron_uuid_kinds::OmicronZoneUuid;
468+
use std::time::Duration;
468469

469470
#[test]
470471
fn test_pwr_bad_ereport() {
@@ -483,49 +484,51 @@ mod test {
483484

484485
#[test]
485486
fn test_remove_insert_pwr_good() {
486-
const TEST_NAME: &str = "test_remove_insert_pwr_good";
487-
let logctx = test_setup_log(TEST_NAME);
488-
let mut reporter = ereport_test::SimReporter::new(
489-
Reporter::Sp { sp_type: SpType::Power, slot: 0 },
490-
EreporterRestartUuid::new_v4(),
491-
);
487+
let FmTest { logctx, mut reporters, system_builder, sitrep_rng } =
488+
FmTest::new("test_remove_insert_pwr_good");
492489

493-
let (example_system, _) =
494-
nexus_reconfigurator_planning::example::ExampleSystemBuilder::new(
495-
&logctx.log,
496-
TEST_NAME,
497-
)
498-
.nsleds(2)
499-
.build();
500-
let mut de = PowerShelfDiagnosis::new(&logctx.log);
490+
let mut reporter = reporters
491+
.reporter(Reporter::Sp { sp_type: SpType::Power, slot: 0 });
492+
let (example_system, _) = system_builder.nsleds(2).build();
501493
let mut sitrep = SitrepBuilder::new_with_rng(
502494
&logctx.log,
503495
&example_system.collection,
504496
None,
505-
crate::builder::SitrepBuilderRng::from_seed(TEST_NAME),
497+
sitrep_rng,
506498
);
499+
// It's the beginning of time!
500+
let t0 = DateTime::<Utc>::MIN_UTC;
507501

502+
let mut de = PowerShelfDiagnosis::new(&logctx.log);
508503
de.analyze_ereport(
509504
&mut sitrep,
510-
&Arc::new(reporter.parse_ereport(ereport_test::PSU_REMOVE_JSON)),
505+
&Arc::new(
506+
reporter.parse_ereport(t0, ereport_test::PSU_REMOVE_JSON),
507+
),
511508
)
512509
.expect("analyzing ereport 1 should succeed");
513510

514511
de.analyze_ereport(
515512
&mut sitrep,
516-
&Arc::new(reporter.parse_ereport(ereport_test::PSU_INSERT_JSON)),
513+
&Arc::new(reporter.parse_ereport(
514+
t0 + Duration::from_secs(1),
515+
ereport_test::PSU_INSERT_JSON,
516+
)),
517517
)
518518
.expect("analyzing ereport 2 should succeed");
519519

520520
de.analyze_ereport(
521521
&mut sitrep,
522-
&Arc::new(reporter.parse_ereport(ereport_test::PSU_PWR_GOOD_JSON)),
522+
&Arc::new(reporter.parse_ereport(
523+
t0 + Duration::from_secs(2),
524+
ereport_test::PSU_PWR_GOOD_JSON,
525+
)),
523526
)
524527
.expect("analyzing ereport 3 should succeed");
525528

526529
de.finish(&mut sitrep).expect("finish should return Ok");
527530

528-
let sitrep = sitrep.build(OmicronZoneUuid::new_v4());
531+
let sitrep = sitrep.build(OmicronZoneUuid::nil());
529532

530533
// TODO(eliza) ACTUALLY MAKE SOME ASSERTIONS ABOUT THE SITREP
531534
eprintln!("{sitrep:#?}");

nexus/fm/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,6 @@ pub mod builder;
99
pub mod diagnosis;
1010
pub mod ereport_analysis;
1111
pub use builder::{CaseBuilder, SitrepBuilder};
12+
13+
#[cfg(test)]
14+
pub mod test_util;

nexus/fm/src/test_util.rs

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
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+
use crate::builder::SitrepBuilderRng;
6+
use chrono::Utc;
7+
use nexus_reconfigurator_planning::example;
8+
use nexus_types::fm::ereport::{
9+
Ena, Ereport, EreportData, EreportId, Reporter,
10+
};
11+
use omicron_test_utils::dev;
12+
use omicron_uuid_kinds::EreporterRestartKind;
13+
use omicron_uuid_kinds::EreporterRestartUuid;
14+
use omicron_uuid_kinds::OmicronZoneKind;
15+
use omicron_uuid_kinds::OmicronZoneUuid;
16+
use rand::rngs::StdRng;
17+
use typed_rng::TypedUuidRng;
18+
19+
pub struct FmTest {
20+
pub logctx: dev::LogContext,
21+
pub reporters: SimReporters,
22+
pub sitrep_rng: SitrepBuilderRng,
23+
pub system_builder: example::ExampleSystemBuilder,
24+
}
25+
26+
impl FmTest {
27+
pub fn new(test_name: &str) -> Self {
28+
let logctx = dev::test_setup_log(test_name);
29+
let example_system_builder =
30+
example::ExampleSystemBuilder::new(&logctx.log, test_name);
31+
Self {
32+
logctx,
33+
reporters: SimReporters::new(test_name),
34+
sitrep_rng: SitrepBuilderRng::from_seed(test_name),
35+
system_builder: example_system_builder,
36+
}
37+
}
38+
}
39+
40+
pub struct SimReporters {
41+
parent: StdRng,
42+
collector_id_rng: TypedUuidRng<OmicronZoneKind>,
43+
}
44+
45+
impl SimReporters {
46+
fn new(test_name: &str) -> Self {
47+
let mut parent = typed_rng::from_seed(test_name, "sim-reporters");
48+
// TODO(eliza): would be more realistic to pick something from the
49+
// example system's omicron zones, but these UUIDs are only used for
50+
// debugging purposes...
51+
let collector_id_rng =
52+
TypedUuidRng::from_parent_rng(&mut parent, "collector-ids");
53+
Self { parent, collector_id_rng }
54+
}
55+
56+
pub fn reporter(&mut self, reporter: Reporter) -> SimReporter {
57+
let collector_id = self.collector_id_rng.next();
58+
let mut restart_id_rng = TypedUuidRng::from_parent_rng(
59+
&mut self.parent,
60+
("restart_id", reporter),
61+
);
62+
let restart_id = restart_id_rng.next();
63+
SimReporter {
64+
reporter,
65+
restart_id,
66+
ena: Ena(0x1),
67+
restart_id_rng,
68+
collector_id,
69+
}
70+
}
71+
}
72+
73+
pub struct SimReporter {
74+
reporter: Reporter,
75+
restart_id: EreporterRestartUuid,
76+
ena: Ena,
77+
restart_id_rng: TypedUuidRng<EreporterRestartKind>,
78+
79+
// TODO(eliza): this is not super realistic, as it will give a new "nexus"
80+
// to each reporter...but the DEs don't actually care who collected the
81+
// ereport, and we just need something to put in there.
82+
collector_id: OmicronZoneUuid,
83+
}
84+
85+
impl SimReporter {
86+
#[track_caller]
87+
pub fn parse_ereport(
88+
&mut self,
89+
now: chrono::DateTime<Utc>,
90+
json: &str,
91+
) -> Ereport {
92+
self.mk_ereport(
93+
now,
94+
json.parse().expect("must be called with valid ereport JSON"),
95+
)
96+
}
97+
98+
pub fn mk_ereport(
99+
&mut self,
100+
now: chrono::DateTime<Utc>,
101+
json: serde_json::Value,
102+
) -> Ereport {
103+
self.ena.0 += 1;
104+
mk_ereport(
105+
self.reporter,
106+
EreportId { ena: self.ena, restart_id: self.restart_id },
107+
self.collector_id,
108+
now,
109+
json,
110+
)
111+
}
112+
113+
pub fn restart(&mut self) {
114+
self.ena = Ena(0x1);
115+
self.restart_id = self.restart_id_rng.next();
116+
}
117+
}
118+
119+
pub fn mk_ereport(
120+
reporter: Reporter,
121+
id: EreportId,
122+
collector_id: OmicronZoneUuid,
123+
time_collected: chrono::DateTime<Utc>,
124+
json: serde_json::Value,
125+
) -> Ereport {
126+
Ereport {
127+
reporter,
128+
data: EreportData {
129+
id,
130+
collector_id,
131+
time_collected,
132+
class: json["class"]
133+
.as_str()
134+
.or_else(|| json["k"].as_str())
135+
.map(ToOwned::to_owned),
136+
serial_number: json["serial_number"]
137+
.as_str()
138+
.map(ToOwned::to_owned),
139+
part_number: json["part_number"].as_str().map(ToOwned::to_owned),
140+
report: json,
141+
},
142+
}
143+
}

nexus/types/src/fm/ereport.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,16 @@ pub struct EreportData {
5959

6060
/// Describes the source of an ereport.
6161
#[derive(
62-
Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize,
62+
Copy,
63+
Clone,
64+
Debug,
65+
Eq,
66+
PartialEq,
67+
Ord,
68+
PartialOrd,
69+
Serialize,
70+
Deserialize,
71+
Hash,
6372
)]
6473
#[serde(tag = "reporter")]
6574
pub enum Reporter {

0 commit comments

Comments
 (0)