-
Notifications
You must be signed in to change notification settings - Fork 91
Expand file tree
/
Copy pathlib.rs
More file actions
177 lines (159 loc) · 6.63 KB
/
Copy pathlib.rs
File metadata and controls
177 lines (159 loc) · 6.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//! Integration testing facilities for Nexus
use nexus_test_interface::NexusServer;
use omicron_common::api::external::IdentityMetadata;
use omicron_sled_agent::sim;
use omicron_test_utils::dev::poll::{CondCheckError, wait_for_condition};
use omicron_uuid_kinds::GenericUuid;
use omicron_uuid_kinds::RackUuid;
use std::fmt::Debug;
use std::net::Ipv6Addr;
use std::time::Duration;
use uuid::Uuid;
pub use sim::TEST_HARDWARE_THREADS;
pub use sim::TEST_RESERVOIR_RAM;
pub mod background;
pub mod db;
pub mod http_testing;
mod nexus_test;
pub mod resource_helpers;
pub mod sql;
mod starter;
pub use nexus_test::ControlPlaneBuilder;
pub use nexus_test::ControlPlaneTestContext;
pub use nexus_test::load_test_config;
#[cfg(feature = "omicron-dev")]
pub use nexus_test::omicron_dev_setup_with_config;
pub use starter::ControlPlaneStarter;
pub use starter::ControlPlaneTestContextSledAgent;
pub use starter::register_test_producer;
pub use starter::start_oximeter;
pub use starter::start_producer_server;
pub use starter::start_sled_agent;
pub use starter::start_sled_agent_with_config;
// TODO: Convert all the UUIDs here to be (typed) constants, similar to
// RACK_UUID, and using the pattern
// RackUuid::from_u128(0xc19a698f_c6f9_4a17_ae30_20d711b8f7dc).
pub const SLED_AGENT_UUID: &str = "b6d65341-167c-41df-9b5c-41cded99c229";
pub const SLED_AGENT2_UUID: &str = "039be560-54cc-49e3-88df-1a29dadbf913";
pub const RACK_UUID: RackUuid = nexus_db_queries::db::pub_test_utils::RACK_UUID;
pub const SWITCH_UUID: &str = "dae4e1f1-410e-4314-bff1-fec0504be07e";
pub const PHYSICAL_DISK_UUID: &str = "fbf4e1f1-410e-4314-bff1-fec0504be07e";
pub const OXIMETER_UUID: &str = "39e6175b-4df2-4730-b11d-cbc1e60a2e78";
pub const PRODUCER_UUID: &str = "a6458b7d-87c3-4483-be96-854d814c20de";
pub const RACK_SUBNET: &str = "fd00:1122:3344:0100::/56";
pub const PHYSICAL_DISK_ADOPTION_REQ_UUID: &str =
"f6944257-9799-4e3e-89b1-c2297b67c16f";
/// Password for the user created by the test suite
///
/// This is only used by the test suite and `omicron-dev run-all` (the latter of
/// which uses the test suite setup code for most of its operation). These are
/// both transient deployments with no sensitive data.
pub const TEST_SUITE_PASSWORD: &str = "oxide";
/// Hash for [`TEST_SUITE_PASSWORD`]
///
/// This is hardcoded because it's used in many integration tests and
/// recomputing it a ton of times wastes a lot of time.
// You can recompute this with: `cargo run --example=argon2 -- --input oxide`
// (where `oxide` here is TEST_SUITE_PASSWORD (above)). The tool will output
// the password hash before proceeding to measure how long it takes to hash.
pub const TEST_SUITE_PASSWORD_HASH: &str = "$argon2id$v=19$m=98304,t=23,p=1$\
R/bEz3yhItskrgbhagyJvg$n3Df2hJDW29A66y//h4LBRrKXC2jfrn2wUsf0k6O10g";
/// Returns whether the two identity metadata objects are identical.
pub fn identity_eq(ident1: &IdentityMetadata, ident2: &IdentityMetadata) {
assert_eq!(ident1.id, ident2.id);
assert_eq!(ident1.name, ident2.name);
assert_eq!(ident1.description, ident2.description);
assert_eq!(ident1.time_created, ident2.time_created);
assert_eq!(ident1.time_modified, ident2.time_modified);
}
/// Order-agnostic vec equality
pub fn assert_same_items<T: PartialEq + Debug>(v1: Vec<T>, v2: Vec<T>) {
assert_eq!(v1.len(), v2.len(), "{:?} and {:?} don't match", v1, v2);
for item in v1.iter() {
assert!(v2.contains(item), "{:?} and {:?} don't match", v1, v2);
}
}
/// Wait until a producer is registered with Oximeter.
///
/// This blocks until the producer is registered, for up to 60s. It panics if
/// the retry loop hits a permanent error.
pub async fn wait_for_producer<G: GenericUuid>(
oximeter: &oximeter_collector::Oximeter,
producer_id: G,
) {
wait_for_producer_impl(oximeter, producer_id.into_untyped_uuid()).await;
}
// This function is outlined from wait_for_producer to avoid unnecessary
// monomorphization.
async fn wait_for_producer_impl(
oximeter: &oximeter_collector::Oximeter,
producer_id: Uuid,
) {
wait_for_condition(
|| async {
if oximeter
.list_producers(None, usize::MAX)
.iter()
.any(|p| p.id == producer_id)
{
Ok(())
} else {
Err(CondCheckError::<()>::NotYet { status: None })
}
},
&Duration::from_secs(1),
&Duration::from_secs(60),
)
.await
.expect("Failed to find producer within time limit");
}
/// Build a DPD client for test validation using the first running dendrite instance
pub fn dpd_client<N: NexusServer>(
cptestctx: &ControlPlaneTestContext<N>,
) -> dpd_client::Client {
// Get the first available dendrite instance and extract the values we need
let dendrite_guard = cptestctx.dendrite.read().unwrap();
let (switch_slot, dendrite_instance) = dendrite_guard
.iter()
.find(|(_, instance)| instance.is_dpd_running())
.expect("No dendrite instances running for test");
// Copy the values we need while the guard is still alive
let switch_slot = *switch_slot;
let port = dendrite_instance.port();
drop(dendrite_guard);
let client_state = dpd_client::ClientState {
tag: String::from("nexus-test"),
log: cptestctx.logctx.log.new(slog::o!(
"component" => "DpdClient",
"switch_slot" => format!("{switch_slot:?}"),
)),
};
let addr = Ipv6Addr::LOCALHOST;
dpd_client::Client::new(&format!("http://[{addr}]:{port}"), client_state)
}
#[cfg(test)]
mod test {
use crate::TEST_SUITE_PASSWORD;
use crate::TEST_SUITE_PASSWORD_HASH;
use omicron_passwords::Password;
use omicron_passwords::PasswordHashString;
// Verify that the hardcoded test suite password hash matches the hardcoded
// test suite password. Obviously it would be less brittle to just compute
// the hash each time we needed it, but that uses a lot of CPU time (by
// design) and has to be done for every single test. That adds up.
#[test]
fn test_suite_password_matches_hash() {
let hasher = omicron_passwords::Hasher::default();
let password: Password = Password::new(TEST_SUITE_PASSWORD).unwrap();
let hash: PasswordHashString =
TEST_SUITE_PASSWORD_HASH.parse().unwrap();
let okay = hasher.verify_password(&password, &hash).unwrap();
assert!(
okay,
"TEST_SUITE_PASSWORD does not match TEST_SUITE_PASSWORD_HASH"
);
}
}