Skip to content
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

test: suspend() then notify() #334

Merged
merged 3 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 59 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ tempfile = "3.10"
# testing
escargot = "0.5"
pretty_assertions = "1.4"
serial_test = "3.1"
test-case = "3.3"
test_each_file = "0.3"
unindent = "0.2"
Expand Down
44 changes: 4 additions & 40 deletions crates/kernel/testsuite/moot_suite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,9 @@
//! See example.moot for a full-fledged example

mod common;
use std::{
fs::File,
io::{BufRead, BufReader},
path::Path,
sync::{Arc, Once},
};
use std::{path::Path, sync::Arc};

use common::{create_wiredtiger_db, testsuite_dir};
use eyre::Context;
use moor_db::Database;
use moor_kernel::{
config::Config,
Expand All @@ -35,7 +29,7 @@ use moor_kernel::{
sessions::{NoopClientSession, Session},
},
};
use moor_moot::{MootRunner, MootState, WIZARD};
use moor_moot::{execute_moot_test, MootRunner};
use moor_values::var::{v_none, Objid, Var};

#[cfg(feature = "relbox")]
Expand Down Expand Up @@ -95,51 +89,21 @@ fn test_wiredtiger(path: &Path) {
}
test_each_file::test_each_path! { in "./crates/kernel/testsuite/moot" as wiredtiger => test_wiredtiger }

#[allow(dead_code)]
static LOGGING_INIT: Once = Once::new();
#[allow(dead_code)]
fn init_logging() {
LOGGING_INIT.call_once(|| {
let main_subscriber = tracing_subscriber::fmt()
.compact()
.with_ansi(true)
.with_file(true)
.with_line_number(true)
.with_thread_names(true)
.with_max_level(tracing::Level::WARN)
.with_test_writer()
.finish();
tracing::subscriber::set_global_default(main_subscriber)
.expect("Unable to set configure logging");
});
}

fn test(db: Arc<dyn Database + Send + Sync>, path: &Path) {
init_logging();
if path.is_dir() {
return;
}
eprintln!("Test definition: {}", path.display());
let f = BufReader::new(File::open(path).unwrap());

let scheduler = Arc::new(Scheduler::new(db, Config::default()));
let loop_scheduler = scheduler.clone();
let scheduler_loop_jh = std::thread::Builder::new()
.name("moor-scheduler".to_string())
.spawn(move || loop_scheduler.run())
.unwrap();

let mut state = MootState::new(
execute_moot_test(
SchedulerMootRunner::new(scheduler.clone(), Arc::new(NoopClientSession::new())),
WIZARD,
path,
);
for (line_no, line) in f.lines().enumerate() {
state = state
.process_line(line_no + 1, &line.unwrap())
.context(format!("line {}", line_no + 1))
.unwrap();
}
state.finalize().unwrap();

scheduler
.submit_shutdown(0, Some("Test is done".to_string()))
Expand Down
2 changes: 2 additions & 0 deletions crates/moot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ description = "Execute MOO interaction tests described in simple text files."
[dependencies]
eyre.workspace = true
pretty_assertions.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true

moor-values = { path = "../values" }
116 changes: 113 additions & 3 deletions crates/moot/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@
//

use std::{
collections::HashMap,
fs::File,
io::{BufRead, BufReader, BufWriter, Write},
net::TcpStream,
path::PathBuf,
path::{Path, PathBuf},
process::Child,
sync::Once,
thread,
time::Duration,
time::{Duration, Instant},
};

use eyre::WrapErr;
Expand All @@ -33,6 +36,24 @@ pub const PROGRAMMER: Objid = Objid(4);
#[allow(dead_code)]
pub const NONPROGRAMMER: Objid = Objid(5);

#[allow(dead_code)]
static LOGGING_INIT: Once = Once::new();
#[allow(dead_code)]
fn init_logging() {
LOGGING_INIT.call_once(|| {
let main_subscriber = tracing_subscriber::fmt()
.compact()
.with_ansi(true)
.with_file(true)
.with_line_number(true)
.with_thread_names(true)
.with_max_level(tracing::Level::WARN)
.with_test_writer()
.finish();
tracing::subscriber::set_global_default(main_subscriber)
.expect("Unable to set configure logging");
});
}
/// Look up the path to Test.db from any crate under the `moor` workspace
pub fn test_db_path() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../moot/Test.db")
Expand Down Expand Up @@ -360,6 +381,95 @@ impl MootClient {
eprintln!("{} << {line}", self.port());
lines.push(line.to_string());
}
Ok(lines.join(""))
Ok(lines.join("\n"))
}
}

pub struct TelnetMootRunner {
port: u16,
clients: HashMap<Objid, MootClient>,
}
impl TelnetMootRunner {
pub fn new(port: u16) -> Self {
Self {
port,
clients: HashMap::new(),
}
}

fn client(&mut self, player: Objid) -> &mut MootClient {
self.clients.entry(player).or_insert_with(|| {
let start = Instant::now();
loop {
if let Ok(mut client) = MootClient::new(self.port) {
client
.send_string(std::format!("connect {}", player))
.unwrap();
return client;
} else if start.elapsed() > Duration::from_secs(5) {
panic!("Failed to connect to daemon");
} else {
std::thread::sleep(Duration::from_millis(10));
}
}
})
}

fn resolve_response(&mut self, response: String) -> Result<String, std::io::Error> {
// Resolve the response; for example, the test assertion may be `$object`; resolve it to the object's specific number.
self.client(WIZARD).command(format!(
"; return {response}; \"TelnetMootRunner::resolve_response\";"
))
}
}
impl MootRunner for TelnetMootRunner {
type Value = String;
type Error = std::io::Error;

fn eval<S: Into<String>>(
&mut self,
player: Objid,
command: S,
) -> Result<String, std::io::Error> {
let response = self
.client(player)
.command(format!("; {} \"TelnetMootRunner::eval\";", command.into()))?;
self.resolve_response(response)
}

fn command<S: AsRef<str>>(
&mut self,
player: Objid,
command: S,
) -> Result<String, std::io::Error> {
let response = self.client(player).command(command)?;
self.resolve_response(response)
}

fn none(&self) -> Self::Value {
"0".to_string()
}
}

pub fn execute_moot_test<R: MootRunner>(runner: R, path: &Path) {
init_logging();
eprintln!("Test definition: {}", path.display());

let f = BufReader::new(
File::open(path)
.wrap_err(format!("{}", path.display()))
.unwrap(),
);

let mut state = MootState::new(runner, WIZARD);
for (line_no, line) in f.lines().enumerate() {
let line = line.unwrap();
let line_no = line_no + 1;
state = state
.process_line(line_no, &line)
.wrap_err(format!("line {}", line_no))
.unwrap();
//eprintln!("[{line_no}] {line} {state:?}");
}
state.finalize().unwrap();
}
Loading
Loading