Skip to content

Commit

Permalink
test(telnet): suspend() + read() + notify()
Browse files Browse the repository at this point in the history
  • Loading branch information
abesto authored and rdaum committed Jun 24, 2024
1 parent 7e41bcf commit 17f82ef
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 20 deletions.
7 changes: 7 additions & 0 deletions crates/moot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
| <pre>% look<br>> here</pre> | Multi-line command |
| `% look` | Execute `look` as a command |
| `42`, `< 42` | Assert that we receive `42` from the server as a response to the `eval` or command |
| `=foobar` | Assert that we received a line containing exactly the string `foobar` |
| `// comment` | It's a comment! |

## Notes: `42`, `< 42`
Expand All @@ -16,6 +17,12 @@ For this style of assertion we send the read string through an extra round of `e

Consecutive lines in this style are treated as a single MOO expression; this allows for better readability if the expected output is complex.

## Notes: `=foobar`

Unlike `42` / `< 42`, there's no extra evaluation happening. We just look at raw string lines, and compare those.

This style of assertion is only supported on tests using a network connection. That is: this works on `TelnetMootRunner`, but is unimplemented on the `SchedulerMootRunner` used in the `moor-kernel` crate. _STRONGLY_ prefer using this kind of assertion in these networked tests!

## Notes: extraneous command output

Assertions are evaluated _exactly_ when the relevant line is read. This means commands may be interspersed with output assertions arbitrarily:
Expand Down
56 changes: 43 additions & 13 deletions crates/moot/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ impl<R: MootRunner> MootState<R> {
pub fn process_line(self, new_line_no: usize, line: &str) -> eyre::Result<Self> {
let line = line.trim_end_matches('\n');
match self {
MootState::Ready { runner, player } => {
MootState::Ready { mut runner, player } => {
if line.starts_with([';', '%']) {
Ok(MootState::ReadingCommand {
runner,
Expand All @@ -128,6 +128,9 @@ impl<R: MootRunner> MootState<R> {
Ok(MootState::new(runner, Self::player(new_player)?))
} else if line.is_empty() || line.starts_with("//") {
Ok(MootState::new(runner, player))
} else if let Some(expectation) = line.strip_prefix('=') {
Self::assert_raw_line(&mut runner, player, Some(expectation), new_line_no)?;
Ok(MootState::new(runner, player))
} else {
Err(eyre::eyre!(
"Expected a command (starting `;`), a comment (starting `//`), a player switch (starting `@`), a command (starting `%`), or an empty line"
Expand All @@ -153,7 +156,9 @@ impl<R: MootRunner> MootState<R> {
} else if let Some(new_player) = line.strip_prefix('@') {
Self::execute_command(&mut runner, player, &command, command_kind, line_no)?;
Ok(MootState::new(runner, Self::player(new_player)?))
} else if line.is_empty() || line.starts_with("//") || line.starts_with([';', '%'])
} else if line.is_empty()
|| line.starts_with("//")
|| line.starts_with([';', '%', '='])
{
Self::execute_command(&mut runner, player, &command, command_kind, line_no)?;
MootState::new(runner, player).process_line(new_line_no, line)
Expand All @@ -174,14 +179,14 @@ impl<R: MootRunner> MootState<R> {
line_no,
mut expectation,
} => {
if line.is_empty() || line.starts_with("//") || line.starts_with([';', '%']) {
if line.is_empty() || line.starts_with("//") || line.starts_with([';', '%', '=']) {
Self::assert_eval_result(&mut runner, player, Some(&expectation), line_no)?;
}
if line.is_empty() || line.starts_with("//") {
Ok(MootState::new(runner, player))
} else if let Some(new_player) = line.strip_prefix('@') {
Ok(MootState::new(runner, Self::player(new_player)?))
} else if line.starts_with([';', '%']) {
} else if line.starts_with([';', '%', '=']) {
MootState::new(runner, player).process_line(new_line_no, line)
} else {
expectation.push('\n');
Expand All @@ -200,7 +205,9 @@ impl<R: MootRunner> MootState<R> {

pub fn finalize(self) -> eyre::Result<()> {
match self {
MootState::Ready { .. } => Ok(()),
MootState::Ready { mut runner, player } => {
Self::assert_raw_line(&mut runner, player, None, 0)
}
MootState::ReadingCommand {
mut runner,
player,
Expand Down Expand Up @@ -269,6 +276,17 @@ impl<R: MootRunner> MootState<R> {
assert_eq!(actual, expected, "Line {line_no}");
Ok(())
}

fn assert_raw_line(
runner: &mut R,
player: Objid,
expectation: Option<&str>,
line_no: usize,
) -> eyre::Result<()> {
let actual = runner.read_line(player)?;
assert_eq!(actual.as_deref(), expectation, "Line {line_no}");
Ok(())
}
}

pub struct ManagedChild {
Expand Down Expand Up @@ -336,10 +354,16 @@ impl MootClient {

fn read_line(&self) -> Result<Option<String>, std::io::Error> {
let mut buf = String::new();
if BufReader::new(&self.stream).read_line(&mut buf)? == 0 {
return Ok(None);
match BufReader::new(&self.stream).read_line(&mut buf) {
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => Ok(None),
Err(e) => Err(e),
Ok(0) => Ok(None),
Ok(_) => {
let line = buf.trim_end_matches(['\r', '\n']).to_string();
eprintln!("{} << {}", self.port(), line);
Ok(Some(line))
}
}
Ok(Some(buf.trim_end_matches(['\r', '\n']).to_string()))
}
}

Expand Down Expand Up @@ -394,13 +418,13 @@ impl MootRunner for TelnetMootRunner {
type Value = String;
type Error = std::io::Error;

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

fn command<S: AsRef<str>>(&mut self, player: Objid, command: S) -> Result<(), std::io::Error> {
fn command<S: AsRef<str>>(&mut self, player: Objid, command: S) -> Result<(), Self::Error> {
self.client(player).write_line(command)
}

Expand All @@ -409,13 +433,19 @@ impl MootRunner for TelnetMootRunner {
}

fn read_line(&mut self, player: Objid) -> Result<Option<String>, Self::Error> {
self.client(player).read_line()
Ok(self.client(player).read_line().expect("Reading raw line"))
}

fn read_eval_result(&mut self, player: Objid) -> Result<Option<Self::Value>, Self::Error> {
let raw = self.client(player).read_line()?;
let raw = self
.client(player)
.read_line()
.expect("Reading raw eval response");
if let Some(raw) = raw {
self.resolve_response(player, raw).map(Some)
Ok(self
.resolve_response(player, raw)
.map(Some)
.expect("Reading resolved eval response"))
} else {
Ok(None)
}
Expand Down
2 changes: 1 addition & 1 deletion crates/moot/tests/moot_lmoo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,6 @@ fn test_moo(path: &Path) {
fn test_single() {
test_moo(
&PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../telnet-host/tests/moot/suspend_notify.moot"),
.join("../telnet-host/tests/moot/suspend_read_notify.moot"),
);
}
4 changes: 2 additions & 2 deletions crates/telnet-host/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,6 @@ fn test_echo() {
#[cfg(target_os = "linux")]
#[test]
#[serial(telnet_host)]
fn test_suspend_notify() {
test_moot_with_telnet_host("suspend_notify");
fn test_suspend_read_notify() {
test_moot_with_telnet_host("suspend_read_notify");
}
2 changes: 1 addition & 1 deletion crates/telnet-host/tests/moot/echo.moot
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
; return 42;
42
=42
3 changes: 0 additions & 3 deletions crates/telnet-host/tests/moot/suspend_notify.moot

This file was deleted.

20 changes: 20 additions & 0 deletions crates/telnet-host/tests/moot/suspend_read_notify.moot
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
; return 200;
=200

; return read();
%201
="201"

; notify(player, "read: " + read()); return "retval";
%hi
=read: hi
="retval"

// TODO disabled for now: this consistently fails
// ; suspend(0.1); notify(player, "read 2: " + read()); return "retval 2";
// %hello
// =read2: hello
// ="retval2"

; suspend(0.1); return 42;
=42

0 comments on commit 17f82ef

Please sign in to comment.