From: Ian Jackson Date: Sun, 21 Feb 2021 22:41:13 +0000 (+0000) Subject: apitest: Code motion (tidying up) X-Git-Tag: otter-0.4.0~391 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=35d4b387756b4c29a3493863bd9218f0c51aea39;p=otter.git apitest: Code motion (tidying up) Signed-off-by: Ian Jackson --- diff --git a/apitest.rs b/apitest.rs index f3c658fb..14a112b6 100644 --- a/apitest.rs +++ b/apitest.rs @@ -2,6 +2,8 @@ // SPDX-License-Identifier: AGPL-3.0-or-later // There is NO WARRANTY. +// ==================== namespace preparation ==================== + pub mod imports { pub use otter; pub use otter::imports::*; @@ -65,13 +67,17 @@ pub use otter::ui::player_num_dasharray; pub const MS: time::Duration = time::Duration::from_millis(1); pub type AE = anyhow::Error; -pub const URL: &str = "http://localhost:8000"; +// -------------------- private imports ---------- use otter::config::DAEMON_STARTUP_REPORT; +// ==================== public constants ==================== + pub const TABLE: &str = "server::dummy"; pub const CONFIG: &str = "server-config.toml"; +pub const URL: &str = "http://localhost:8000"; + #[derive(Copy,Clone,Debug,Eq,PartialEq,Ord,PartialOrd)] #[derive(FromPrimitive,EnumIter,IntoStaticStr,EnumProperty)] #[strum(serialize_all = "snake_case")] @@ -80,35 +86,7 @@ pub enum StaticUser { #[strum(props(Token="ccg9kzoTh758QrVE1xMY7BQWB36dNJTx"))] Bob, } -pub trait AlwaysContext { - fn always_context(self, msg: &'static str) -> anyhow::Result; -} - -impl AlwaysContext for Result -where Self: anyhow::Context, -{ - fn always_context(self, msg: &'static str) -> anyhow::Result { - let x = self.context(msg); - if x.is_ok() { info!("completed {}.", msg) }; - x - } -} - -pub trait JustWarn { - fn just_warn(self) -> Option; -} - -impl JustWarn for Result { - fn just_warn(self) -> Option { - match self { - Ok(x) => Some(x), - Err(e) => { - warn!("{:#}", e); - None - }, - } - } -} +// ==================== principal public structs ==================== #[derive(Debug,Clone)] #[derive(StructOpt)] @@ -136,51 +114,6 @@ pub struct SetupCore { pub wanted_tests: TrackWantedTests, } -#[derive(Clone,Debug)] -#[derive(StructOpt)] -pub struct WantedTestsOpt { - tests: Vec, -} - -#[derive(Debug)] -pub struct TrackWantedTests { - wanted: WantedTestsOpt, - found: BTreeSet, -} - -impl WantedTestsOpt { - pub fn track(&self) -> TrackWantedTests { - TrackWantedTests { wanted: self.clone(), found: default() } - } -} - -impl TrackWantedTests { - pub fn wantp(&mut self, tname: &str) -> bool { - self.found.insert(tname.to_owned()); - let y = - self.wanted.tests.is_empty() || - self.wanted.tests.iter().any(|s| s==tname); - y - } -} - -impl Drop for TrackWantedTests { - fn drop(&mut self) { - let missing_tests = self.wanted.tests.iter().cloned() - .filter(|s| !self.found.contains(s)) - .collect::>(); - - if !missing_tests.is_empty() && !self.found.is_empty() { - for f in &self.found { - eprintln!("fyi: test that exists: {}", f); - } - for m in &missing_tests { - eprintln!("warning: unknown test requested: {}", m); - } - } - } -} - #[derive(Clone,Debug)] pub struct DirSubst { pub tmp: String, @@ -191,24 +124,9 @@ pub struct DirSubst { pub struct Instance(pub InstanceName); -#[derive(Clone,Debug)] -pub struct Subst(HashMap); - -#[derive(Clone,Debug)] -pub struct ExtendedSubst(B, X); +// ==================== Facilities for tests ==================== -impl<'i, - T: AsRef + 'i, - U: AsRef + 'i, - L: IntoIterator> - From for Subst -{ - fn from(l: L) -> Subst { - let map = l.into_iter() - .map(|(k,v)| (k.as_ref().to_owned(), v.as_ref().to_owned())).collect(); - Subst(map) - } -} +// -------------------- Substition -------------------- pub trait Substitutor { fn get(&self, kw: &str) -> Option; @@ -256,12 +174,31 @@ pub trait Substitutor { } } +#[derive(Clone,Debug)] +pub struct Subst(HashMap); + impl Substitutor for Subst { fn get(&self, kw: &str) -> Option { self.0.get(kw).map(String::clone) } } +impl<'i, + T: AsRef + 'i, + U: AsRef + 'i, + L: IntoIterator> + From for Subst +{ + fn from(l: L) -> Subst { + let map = l.into_iter() + .map(|(k,v)| (k.as_ref().to_owned(), v.as_ref().to_owned())).collect(); + Subst(map) + } +} + +#[derive(Clone,Debug)] +pub struct ExtendedSubst(B, X); + impl Substitutor for ExtendedSubst { fn get(&self, kw: &str) -> Option { self.1.get(kw).or_else(|| self.0.get(kw)) @@ -282,6 +219,100 @@ impl Substitutor for DirSubst { } } +// ---------- requested/available test tracking ---------- + +#[derive(Clone,Debug)] +#[derive(StructOpt)] +pub struct WantedTestsOpt { + tests: Vec, +} + +#[derive(Debug)] +pub struct TrackWantedTests { + wanted: WantedTestsOpt, + found: BTreeSet, +} + +impl WantedTestsOpt { + pub fn track(&self) -> TrackWantedTests { + TrackWantedTests { wanted: self.clone(), found: default() } + } +} + +impl TrackWantedTests { + pub fn wantp(&mut self, tname: &str) -> bool { + self.found.insert(tname.to_owned()); + let y = + self.wanted.tests.is_empty() || + self.wanted.tests.iter().any(|s| s==tname); + y + } +} + +impl Drop for TrackWantedTests { + fn drop(&mut self) { + let missing_tests = self.wanted.tests.iter().cloned() + .filter(|s| !self.found.contains(s)) + .collect::>(); + + if !missing_tests.is_empty() && !self.found.is_empty() { + for f in &self.found { + eprintln!("fyi: test that exists: {}", f); + } + for m in &missing_tests { + eprintln!("warning: unknown test requested: {}", m); + } + } + } +} + +#[macro_export] +macro_rules! test { + ($c:expr, $tname:expr, $s:stmt) => { + if $c.su.want_test($tname) { + debug!("-------------------- {} starting --------------------", $tname); + $s + info!("-------------------- {} completed --------------------", $tname); + } else { + trace!("- - - {} skipped - - -", $tname); + } + } +} + +// -------------------- Extra anyhow result handling -------------------- + +pub trait AlwaysContext { + fn always_context(self, msg: &'static str) -> anyhow::Result; +} + +impl AlwaysContext for Result +where Self: anyhow::Context, +{ + fn always_context(self, msg: &'static str) -> anyhow::Result { + let x = self.context(msg); + if x.is_ok() { info!("completed {}.", msg) }; + x + } +} + +pub trait JustWarn { + fn just_warn(self) -> Option; +} + +impl JustWarn for Result { + fn just_warn(self) -> Option { + match self { + Ok(x) => Some(x), + Err(e) => { + warn!("{:#}", e); + None + }, + } + } +} + +// -------------------- cleanup_notify (signaling) -------------------- + pub mod cleanup_notify { use super::imports::*; use super::AE; @@ -383,6 +414,56 @@ pub mod cleanup_notify { } } +// -------------------- generalised daemon startup -------------------- + +#[throws(AE)] +pub fn fork_something_which_prints(mut cmd: Command, + cln: &cleanup_notify::Handle, + what: &str) + -> (String, process::Child) +{ + (||{ + cmd.stdout(Stdio::piped()); + cln.arm_hook(&mut cmd)?; + let mut child = cmd.spawn().context("spawn")?; + let mut report = BufReader::new(child.stdout.take().unwrap()) + .lines().fuse(); + + let l = report.next(); + + let s = child.try_wait().context("check on spawned child")?; + if let Some(e) = s { + throw!(anyhow!("failed to start: wait status = {}", &e)); + } + + let l = match l { + Some(Ok(l)) => l, + None => throw!(anyhow!("EOF (but it's still running?")), + Some(Err(e)) => throw!(AE::from(e).context("failed to read")), + }; + + let what = what.to_owned(); + thread::spawn(move|| (||{ + for l in report { + let l: Result = l; + let l = l.context("reading further output")?; + const MAXLEN: usize = 300; + if l.len() <= MAXLEN { + println!("{} {}", what, l); + } else { + println!("{} {}...", what, &l[..MAXLEN-3]); + } + } + Ok::<_,AE>(()) + })().context(what).just_warn() + ); + + Ok::<_,AE>((l, child)) + })().with_context(|| what.to_owned())? +} + +// ==================== principal actual setup code ==================== + #[throws(AE)] pub fn reinvoke_via_bwrap(_opts: &Opts, current_exe: &str) -> Void { debug!("running bwrap"); @@ -499,52 +580,6 @@ pub fn prepare_tmpdir<'x>(opts: &'x Opts, mut current_exe: &'x str) -> DirSubst } } -#[throws(AE)] -pub fn fork_something_which_prints(mut cmd: Command, - cln: &cleanup_notify::Handle, - what: &str) - -> (String, process::Child) -{ - (||{ - cmd.stdout(Stdio::piped()); - cln.arm_hook(&mut cmd)?; - let mut child = cmd.spawn().context("spawn")?; - let mut report = BufReader::new(child.stdout.take().unwrap()) - .lines().fuse(); - - let l = report.next(); - - let s = child.try_wait().context("check on spawned child")?; - if let Some(e) = s { - throw!(anyhow!("failed to start: wait status = {}", &e)); - } - - let l = match l { - Some(Ok(l)) => l, - None => throw!(anyhow!("EOF (but it's still running?")), - Some(Err(e)) => throw!(AE::from(e).context("failed to read")), - }; - - let what = what.to_owned(); - thread::spawn(move|| (||{ - for l in report { - let l: Result = l; - let l = l.context("reading further output")?; - const MAXLEN: usize = 300; - if l.len() <= MAXLEN { - println!("{} {}", what, l); - } else { - println!("{} {}...", what, &l[..MAXLEN-3]); - } - } - Ok::<_,AE>(()) - })().context(what).just_warn() - ); - - Ok::<_,AE>((l, child)) - })().with_context(|| what.to_owned())? -} - #[throws(AE)] pub fn prepare_gameserver(cln: &cleanup_notify::Handle, ds: &DirSubst) -> (MgmtChannel, process::Child) { @@ -609,6 +644,8 @@ _ = "error" # rocket (mgmt_conn, child) } +// ---------- game spec ---------- + impl DirSubst { pub fn specs_dir(&self) -> String { format!("{}/specs" , &self.src) @@ -680,6 +717,8 @@ pub fn prepare_game(ds: &DirSubst, table: &str) -> InstanceName { instance } +// ---------- core entrypoint, for wdriver too ---------- + #[throws(AE)] pub fn setup_core(module_paths: &[&str]) -> (O, cleanup_notify::Handle, Instance, SetupCore) @@ -742,26 +781,3 @@ pub fn setup_core(module_paths: &[&str]) -> wanted_tests, }) } - -#[derive(Debug)] -pub struct Window { - pub name: String, - pub instance: InstanceName, -} - -impl Window { - pub fn table(&self) -> String { self.instance.to_string() } -} - -#[macro_export] -macro_rules! test { - ($c:expr, $tname:expr, $s:stmt) => { - if $c.su.want_test($tname) { - debug!("-------------------- {} starting --------------------", $tname); - $s - info!("-------------------- {} completed --------------------", $tname); - } else { - trace!("- - - {} skipped - - -", $tname); - } - } -} diff --git a/wdriver.rs b/wdriver.rs index 3a5ef622..4646d557 100644 --- a/wdriver.rs +++ b/wdriver.rs @@ -58,6 +58,16 @@ pub struct Setup { windows_squirreled: Vec, // see Drop impl } +#[derive(Debug)] +pub struct Window { + pub name: String, + pub instance: InstanceName, +} + +impl Window { + pub fn table(&self) -> String { self.instance.to_string() } +} + #[throws(AE)] fn prepare_xserver(cln: &cleanup_notify::Handle, ds: &DirSubst) { const DISPLAY: u16 = 12;