-
Notifications
You must be signed in to change notification settings - Fork 11.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[sui CLI] Unit test Sui cli #445
Conversation
patrickkuo
commented
Feb 12, 2022
•
edited
Loading
edited
- Make cli testable by replacing println with writer
- Using PathBuf instead of String in config
- added test for Sui genesis
- Some refactoring
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sui/src/sui.rs
Outdated
NetworkConfig::read_or_create(&network_conf_path).expect("Unable to read network config."); | ||
let mut config = NetworkConfig::read_or_create(&network_conf_path)?; | ||
|
||
let mut writer = stdout(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this is certainly an improvement on the existent logging, thanks! But it's also choosing the absolute simplest form of logging, which wouldn't be so much of a problem if it wasn't a bit hard to evolve:
- the printouts you send have no level attached to them, so that you get all the prints or none at all,
- you log to a single blocking writer, with no flexibility to route your logs to several places (files, network, stdout/stderr),
If one day we want to change either one of those things, I'm afraid it may be a large refactor.
If you set it this way instead:
tracing_subscriber::fmt::init();
Which is essentially shorthand for:
use std::io;
let subscriber = tracing_subscriber::fmt::Subscriber::builder()
.with_writer(io::stdout)
.finish();
tracing::subscriber::set_global_default(subscriber)
.expect("setting tracing default failed");
Then you're not limited to writeln!
, you can do:
let span = span!(Level::INFO, "Starting network with {} authorities", config.authorities.len());
let _enter = span.enter();
and later
tracing::info!("All servers stopped");
It doesn't sound like much but:
- log-level tweaking is easy, and the calling context is preserved.
- It is thankfully straightforward to override the default subscriber for the course of one function and its descendants.
- Moreover, much later in the course of development of the CLI, we can e.g. hook up
appender
as thesubscriber
and get non-blocking rolling logs for the CLI, for free: https://crates.io/crates/tracing-appender
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is much nicer then passing in a writer! I will use tracing instead!
* make sui and wallet unit testable by passing in a writer instead of println
* added test for sui cli
* use tracing-test to validate command line output
4b86617
to
45785d6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is awesome! 🚀
let files = read_dir(working_dir.path())? | ||
.flat_map(|r| r.map(|file| file.file_name().to_str().unwrap().to_owned())) | ||
.collect::<Vec<_>>(); | ||
|
||
assert_eq!(3, files.len()); | ||
assert!(files.contains(&"wallet.conf".to_string())); | ||
assert!(files.contains(&"authorities_db".to_string())); | ||
assert!(files.contains(&"network.conf".to_string())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, I messed up by not noticing the to_str()
is a borrow-through. Sigh. This is why I prefer camino. Here's what I would write (this is a total nit by now).
let files = read_dir(working_dir.path())? | |
.flat_map(|r| r.map(|file| file.file_name().to_str().unwrap().to_owned())) | |
.collect::<Vec<_>>(); | |
assert_eq!(3, files.len()); | |
assert!(files.contains(&"wallet.conf".to_string())); | |
assert!(files.contains(&"authorities_db".to_string())); | |
assert!(files.contains(&"network.conf".to_string())); | |
let files = read_dir(working_dir.path())? | |
.flatten() | |
.flat_map(|file| file.file_name().into_string()) | |
.collect::<Vec<_>>(); | |
assert_eq!(3, files.len()); | |
assert!(files.contains(&"wallet.conf".to_owned())); | |
assert!(files.contains(&"authorities_db".to_owned())); | |
assert!(files.contains(&"network.conf".to_owned())); |
let format = tracing_subscriber::fmt::format() | ||
.with_level(false) | ||
.with_target(false) | ||
.with_thread_ids(false) | ||
.with_thread_names(false) | ||
.without_time() | ||
.compact(); | ||
tracing_subscriber::fmt().event_format(format).init(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, still a minimalist approach. Why not?
assert!(matches!(start, Err(..))); | ||
// Genesis | ||
genesis(&mut config).await?; | ||
assert!(logs_contain("Network genesis completed.")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aha! I see you've found some of the nicer features already :D