Skip to content

Commit 2454048

Browse files
authored
Merge pull request #15 from Shopify/reformat-move-main-logic
refactor: move engine function outside of the main
2 parents f17e995 + 2b7edbc commit 2454048

File tree

7 files changed

+156
-226
lines changed

7 files changed

+156
-226
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "script-runner"
3-
version = "0.2.1"
3+
version = "0.2.2"
44
edition = "2021"
55

66
[profile.test]

src/engine.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
use anyhow::{anyhow, Result};
2+
use std::{
3+
path::PathBuf,
4+
time::{Duration, Instant},
5+
};
6+
use wasmtime::{Engine, Linker, Module, Store};
7+
8+
use wasmtime_wasi::sync::WasiCtxBuilder;
9+
10+
use crate::function_run_result::FunctionRunResult;
11+
12+
pub fn run(script_path: PathBuf, input_path: PathBuf) -> Result<FunctionRunResult> {
13+
let engine = Engine::default();
14+
let module = Module::from_file(&engine, &script_path)
15+
.map_err(|e| anyhow!("Couldn't load script {:?}: {}", &script_path, e))?;
16+
17+
let input: serde_json::Value = serde_json::from_reader(
18+
std::fs::File::open(&input_path)
19+
.map_err(|e| anyhow!("Couldn't load input {:?}: {}", &input_path, e))?,
20+
)
21+
.map_err(|e| anyhow!("Couldn't load input {:?}: {}", &input_path, e))?;
22+
let input = serde_json::to_vec(&input)?;
23+
24+
let input_stream = wasi_common::pipe::ReadPipe::new(std::io::Cursor::new(input));
25+
let output_stream = wasi_common::pipe::WritePipe::new_in_memory();
26+
let error_stream = wasi_common::pipe::WritePipe::new_in_memory();
27+
28+
let runtime: Duration;
29+
30+
{
31+
let mut linker = Linker::new(&engine);
32+
wasmtime_wasi::add_to_linker(&mut linker, |s| s)?;
33+
let wasi = WasiCtxBuilder::new()
34+
.stdin(Box::new(input_stream))
35+
.stdout(Box::new(output_stream.clone()))
36+
.stderr(Box::new(error_stream.clone()))
37+
.inherit_args()?
38+
.build();
39+
let mut store = Store::new(&engine, wasi);
40+
41+
linker.module(&mut store, "", &module)?;
42+
43+
let start = Instant::now();
44+
45+
let instance = linker.instantiate(&mut store, &module)?;
46+
let module_result = instance
47+
.get_typed_func::<(), (), _>(&mut store, "_start")?
48+
.call(&mut store, ());
49+
50+
runtime = start.elapsed();
51+
52+
match module_result {
53+
Ok(_) => {}
54+
Err(e) => {
55+
eprintln!("Error:\n{}", e);
56+
}
57+
}
58+
};
59+
60+
let logs = error_stream
61+
.try_into_inner()
62+
.expect("Error stream reference still exists")
63+
.into_inner();
64+
let logs =
65+
std::str::from_utf8(&logs).map_err(|e| anyhow!("Couldn't print Script Logs: {}", e))?;
66+
67+
let output = output_stream
68+
.try_into_inner()
69+
.expect("Output stream reference still exists")
70+
.into_inner();
71+
let output: serde_json::Value = serde_json::from_slice(output.as_slice())
72+
.map_err(|e| anyhow!("Couldn't decode Script Output: {}", e))?;
73+
74+
let function_run_result = FunctionRunResult::new(runtime, output, logs.to_string());
75+
76+
Ok(function_run_result)
77+
}
78+
79+
#[cfg(test)]
80+
mod tests {
81+
use super::*;
82+
use std::path::Path;
83+
84+
#[test]
85+
fn test_runtime_under_threshold() {
86+
let function_run_result = run(
87+
Path::new("tests/benchmarks/hello_world.wasm").to_path_buf(),
88+
Path::new("tests/benchmarks/hello_world.json").to_path_buf(),
89+
)
90+
.unwrap();
91+
92+
assert!(function_run_result.runtime <= Duration::from_millis(5));
93+
}
94+
95+
#[test]
96+
fn test_runtime_over_threshold() {
97+
let function_run_result = run(
98+
Path::new("tests/benchmarks/sleeps.wasm").to_path_buf(),
99+
Path::new("tests/benchmarks/sleeps.json").to_path_buf(),
100+
)
101+
.unwrap();
102+
103+
assert!(function_run_result.runtime > Duration::from_millis(5));
104+
}
105+
}

src/function_run_result.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use colored::Colorize;
2+
use std::{fmt, time::Duration};
3+
4+
pub struct FunctionRunResult {
5+
pub runtime: Duration,
6+
pub logs: String,
7+
pub output: serde_json::Value,
8+
}
9+
10+
impl FunctionRunResult {
11+
pub fn new(runtime: Duration, output: serde_json::Value, logs: String) -> Self {
12+
FunctionRunResult {
13+
runtime,
14+
output,
15+
logs,
16+
}
17+
}
18+
}
19+
20+
impl fmt::Display for FunctionRunResult {
21+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
22+
let title = " Benchmark Results ".black().on_bright_green();
23+
write!(f, "{}\n\n", title)?;
24+
25+
writeln!(f, "Runtime: {:?}\n", self.runtime)?;
26+
27+
writeln!(
28+
f,
29+
"{}\n\n{}",
30+
" Logs ".black().on_bright_blue(),
31+
self.logs
32+
)?;
33+
34+
writeln!(
35+
f,
36+
"Output:\n{}",
37+
serde_json::to_string_pretty(&self.output).unwrap_or_else(|error| error.to_string())
38+
)?;
39+
40+
Ok(())
41+
}
42+
}

src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
pub mod run_statistics;
1+
pub mod engine;
2+
pub mod function_run_result;

src/main.rs

Lines changed: 5 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
1-
use std::{
2-
path::PathBuf,
3-
time::{Duration, Instant},
4-
};
1+
use std::path::PathBuf;
52

6-
use anyhow::{anyhow, Result};
3+
use anyhow::Result;
74
use clap::Parser;
8-
use colored::Colorize;
9-
use script_runner::run_statistics::RunStatistics;
10-
use wasmtime::*;
11-
use wasmtime_wasi::sync::WasiCtxBuilder;
5+
use script_runner::engine::run;
126

137
/// Simple script runner which takes JSON as a convenience.
148
#[derive(Parser)]
@@ -25,77 +19,9 @@ struct Opts {
2519
fn main() -> Result<()> {
2620
let opts: Opts = Opts::parse();
2721

28-
let engine = Engine::default();
29-
let module = Module::from_file(&engine, &opts.script)
30-
.map_err(|e| anyhow!("Couldn't load script {:?}: {}", &opts.script, e))?;
22+
let function_run_result = run(opts.script, opts.input)?;
3123

32-
let input: serde_json::Value = serde_json::from_reader(
33-
std::fs::File::open(&opts.input)
34-
.map_err(|e| anyhow!("Couldn't load input {:?}: {}", &opts.input, e))?,
35-
)
36-
.map_err(|e| anyhow!("Couldn't load input {:?}: {}", &opts.input, e))?;
37-
let input = serde_json::to_vec(&input)?;
38-
39-
let input_stream = wasi_common::pipe::ReadPipe::new(std::io::Cursor::new(input));
40-
let output_stream = wasi_common::pipe::WritePipe::new_in_memory();
41-
let error_stream = wasi_common::pipe::WritePipe::new_in_memory();
42-
43-
{
44-
// Link WASI and construct the store.
45-
let mut linker = Linker::new(&engine);
46-
wasmtime_wasi::add_to_linker(&mut linker, |s| s)?;
47-
let wasi = WasiCtxBuilder::new()
48-
.stdin(Box::new(input_stream))
49-
.stdout(Box::new(output_stream.clone()))
50-
.stderr(Box::new(error_stream.clone()))
51-
.inherit_args()?
52-
.build();
53-
let mut store = Store::new(&engine, wasi);
54-
55-
linker.module(&mut store, "", &module)?;
56-
57-
let start = Instant::now();
58-
59-
// Execute the module
60-
let result = linker
61-
.get_default(&mut store, "")?
62-
.typed::<(), (), _>(&store)?
63-
.call(&mut store, ());
64-
65-
let runtime = start.elapsed();
66-
67-
let benchmark = RunStatistics::new(runtime, Duration::from_millis(5));
68-
69-
println!("{}", benchmark);
70-
71-
match result {
72-
Ok(_) => {}
73-
Err(e) => {
74-
eprintln!("Error:\n{}", e);
75-
}
76-
}
77-
};
78-
79-
let logs = error_stream
80-
.try_into_inner()
81-
.expect("Error stream reference still exists")
82-
.into_inner();
83-
let logs =
84-
std::str::from_utf8(&logs).map_err(|e| anyhow!("Couldn't print Script Logs: {}", e))?;
85-
86-
println!(
87-
"{}\n\n{}",
88-
" Logs ".black().on_bright_blue(),
89-
logs
90-
);
91-
92-
let output = output_stream
93-
.try_into_inner()
94-
.expect("Output stream reference still exists")
95-
.into_inner();
96-
let output: serde_json::Value = serde_json::from_slice(output.as_slice())
97-
.map_err(|e| anyhow!("Couldn't decode Script Output: {}", e))?;
98-
println!("Output:\n{}", serde_json::to_string_pretty(&output)?);
24+
println!("{}", function_run_result);
9925

10026
Ok(())
10127
}

0 commit comments

Comments
 (0)