Skip to content

Commit 9881f76

Browse files
authored
add tests that run executables, particularly for --openapi (#21), fix #22
1 parent 70bc912 commit 9881f76

16 files changed

+409
-32
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ uuid = { version = "0.8", features = [ "serde", "v4" ] }
2121

2222
[dev-dependencies]
2323
libc = "0.2.71"
24+
openapiv3 = "0.3.0"
25+
subprocess = "0.2.4"
26+
newline-converter = "0.1.0"
2427

2528
[dependencies.slog]
2629
version = "2.5"

TODO.adoc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ Work queue (see also: existing GitHub issues):
1616
* decide on a code name for the whole control plane and rename the repo
1717
** oxide controller -> Oxc? Or something using the new code name?
1818
* general maintenance and cleanup
19-
** add a test that runs --openapi (to make sure it works)
2019
** scope out switching to sync
2120
** create separate exports for internal vs. external models
2221
** proper config + logging for sled agent

src/bin/oxide_controller.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,19 @@
1616
use clap::{App, Arg};
1717
use oxide_api_prototype::controller_run_openapi_external;
1818
use oxide_api_prototype::controller_run_server;
19+
use oxide_api_prototype::fatal;
20+
use oxide_api_prototype::CmdError;
1921
use oxide_api_prototype::ConfigController;
2022
use std::path::Path;
21-
use std::process::exit;
2223

2324
#[tokio::main]
2425
async fn main() {
25-
if let Err(message) = do_run().await {
26-
fatal(message);
26+
if let Err(cmd_error) = do_run().await {
27+
fatal(cmd_error);
2728
}
2829
}
2930

30-
async fn do_run() -> Result<(), String> {
31+
async fn do_run() -> Result<(), CmdError> {
3132
let matches = App::new("oxide-api-prototype")
3233
.after_help("See README.adoc for more information")
3334
.arg(
@@ -39,23 +40,21 @@ async fn do_run() -> Result<(), String> {
3940
.arg(Arg::with_name("CONFIG_FILE_PATH").required(true).index(1))
4041
.get_matches_safe()
4142
.map_err(|clap_error| {
42-
format!("parsing arguments: {}", clap_error.message)
43+
CmdError::Usage(format!(
44+
"parsing arguments: {}",
45+
clap_error.message
46+
))
4347
})?;
4448

4549
let config_file = matches.value_of("CONFIG_FILE_PATH").unwrap();
4650
let config_file_path = Path::new(config_file);
4751
let config = ConfigController::from_file(config_file_path)
48-
.map_err(|e| e.to_string())?;
52+
.map_err(|e| CmdError::Failure(e.to_string()))?;
4953

5054
if matches.is_present("openapi") {
5155
controller_run_openapi_external();
5256
Ok(())
5357
} else {
54-
controller_run_server(&config).await
58+
controller_run_server(&config).await.map_err(CmdError::Failure)
5559
}
5660
}
57-
58-
fn fatal(message: String) -> ! {
59-
eprintln!("{}: {}", std::env::args().next().unwrap(), message);
60-
exit(1);
61-
}

src/bin/sled_agent.rs

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
* TODO see the TODO for oxide-controller.
77
*/
88

9-
use std::process::exit;
10-
119
use clap::{App, Arg};
1210
use dropshot::ConfigDropshot;
1311
use dropshot::ConfigLogging;
1412
use dropshot::ConfigLoggingLevel;
13+
use oxide_api_prototype::fatal;
1514
use oxide_api_prototype::sa_run_server;
15+
use oxide_api_prototype::CmdError;
1616
use oxide_api_prototype::ConfigSledAgent;
1717
use oxide_api_prototype::SimMode;
1818
use std::net::SocketAddr;
@@ -25,7 +25,7 @@ async fn main() {
2525
}
2626
}
2727

28-
async fn do_run() -> Result<(), String> {
28+
async fn do_run() -> Result<(), CmdError> {
2929
let matches = App::new("sled_agent")
3030
.after_help("See README.adoc for more information")
3131
.arg(
@@ -42,27 +42,30 @@ async fn do_run() -> Result<(), String> {
4242
.arg(Arg::with_name("CONTROLLER_IP:PORT").required(true).index(3))
4343
.get_matches_safe()
4444
.map_err(|clap_error| {
45-
format!("parsing arguments: {}", clap_error.message)
45+
CmdError::Usage(format!(
46+
"parsing arguments: {}",
47+
clap_error.message
48+
))
4649
})?;
4750

4851
let sa_id = {
4952
let value_str = matches.value_of("SA_UUID").unwrap();
5053
Uuid::parse_str(value_str)
51-
.map_err(|e| format!("parsing SA_UUID: {}", e))?
54+
.map_err(|e| CmdError::Usage(format!("parsing SA_UUID: {}", e)))?
5255
};
5356

5457
let sa_addr = {
5558
let value_str = matches.value_of("SA_IP:PORT").unwrap();
56-
value_str
57-
.parse::<SocketAddr>()
58-
.map_err(|e| format!("parsing SA_IP:PORT: {}", e))?
59+
value_str.parse::<SocketAddr>().map_err(|e| {
60+
CmdError::Usage(format!("parsing SA_IP:PORT: {}", e))
61+
})?
5962
};
6063

6164
let controller_addr = {
6265
let value_str = matches.value_of("CONTROLLER_IP:PORT").unwrap();
63-
value_str
64-
.parse::<SocketAddr>()
65-
.map_err(|e| format!("parsing CONTROLLER_IP:PORT: {}", e))?
66+
value_str.parse::<SocketAddr>().map_err(|e| {
67+
CmdError::Usage(format!("parsing CONTROLLER_IP:PORT: {}", e))
68+
})?
6669
};
6770

6871
let sim_mode = match matches.value_of("sim-mode").unwrap() {
@@ -85,10 +88,5 @@ async fn do_run() -> Result<(), String> {
8588
},
8689
};
8790

88-
sa_run_server(&config).await
89-
}
90-
91-
fn fatal(message: String) -> ! {
92-
eprintln!("{}: {}", std::env::args().next().unwrap(), message);
93-
exit(1);
91+
sa_run_server(&config).await.map_err(CmdError::Failure)
9492
}

src/cmd.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*!
2+
* Facilities used by the command-line tools
3+
*/
4+
5+
use std::env::current_exe;
6+
use std::process::exit;
7+
8+
/** represents a fatal error in a command-line program */
9+
pub enum CmdError {
10+
/** incorrect command-line arguments */
11+
Usage(String),
12+
/** all other errors */
13+
Failure(String),
14+
}
15+
16+
/**
17+
* Exits the current process on a fatal error.
18+
*/
19+
pub fn fatal(cmd_error: CmdError) -> ! {
20+
let arg0_result = current_exe().ok();
21+
let arg0 = arg0_result
22+
.as_deref()
23+
.and_then(|pathbuf| pathbuf.file_stem())
24+
.and_then(|file_name| file_name.to_str())
25+
.unwrap_or("command");
26+
let (exit_code, message) = match cmd_error {
27+
CmdError::Usage(m) => (2, m),
28+
CmdError::Failure(m) => (1, m),
29+
};
30+
eprintln!("{}: {}", arg0, message);
31+
exit(exit_code);
32+
}

src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454

5555
mod api_error;
5656
pub mod api_model;
57+
mod cmd;
5758
mod datastore;
5859
mod http_client;
5960
mod oxide_controller;
@@ -76,5 +77,8 @@ pub use sled_agent::SledAgentClient;
7677
pub use sled_agent::SledAgentServer;
7778
pub use sled_agent::SledAgentTestInterfaces;
7879

80+
pub use cmd::fatal;
81+
pub use cmd::CmdError;
82+
7983
#[macro_use]
8084
extern crate slog;

src/oxide_controller/config.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ impl fmt::Display for LoadError {
5858
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5959
match &self.kind {
6060
LoadErrorKind::Io(e) => {
61-
write!(f, "read \"{}\": {:?}", self.path.display(), e)
61+
write!(f, "read \"{}\": {}", self.path.display(), e)
6262
}
6363
LoadErrorKind::Parse(e) => {
64-
write!(f, "parse \"{}\": {:?}", self.path.display(), e)
64+
write!(f, "parse \"{}\": {}", self.path.display(), e)
6565
}
6666
}
6767
}

0 commit comments

Comments
 (0)