Add an integration test to rink-sandbox (#128)

This commit is contained in:
Tiffany Bennett 2022-04-16 15:58:03 -07:00 committed by GitHub
parent 07bdee9eb8
commit 672c915331
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 99 additions and 2 deletions

View file

@ -20,3 +20,8 @@ serde = "1"
byteorder = "1"
color-eyre = "0.5"
async-ctrlc = { version = "1.2.0", features = ["stream"] }
[[test]]
name = "integration"
path = "integration/main.rs"
harness = false

View file

@ -0,0 +1,82 @@
use rink_sandbox::{Alloc, Sandbox, Service};
use serde_derive::{Deserialize, Serialize};
use std::{env, ffi::OsString, io::Error as IoError, time::Duration};
struct AddTwoService;
#[derive(Serialize, Deserialize)]
enum Request {
AddTwo(i64, i64),
ThrowPanic,
}
// Global allocators can't be swapped out at runtime, so your entire app
// will have to use the allocator. That said, this shouldn't have much
// overhead and the limit can be set to `usize::MAX` when not in use.
#[global_allocator]
pub(crate) static GLOBAL: Alloc = Alloc::new(usize::MAX);
// In order to keep the types the same between the parent and child
// processes, a Service trait is used. It's still possible to implement
// the trait twice and get bincode errors, but in most cases there will
// be 1 implementation of this trait.
impl Service for AddTwoService {
// All of the associated types here have to be Serialize +
// Deserialize, so that they can be sent over IPC.
// Sent from the parent to the child to evaluate.
type Req = Request;
// Sent from the child to the parent after finishing.
type Res = i64;
// Passed from the parent to the child on startup.
type Config = ();
// Args to be passed to the child process. When the child receives
// these arguments, it should call `rink_sandbox::become_child`.
fn args(_config: &Self::Config) -> Vec<OsString> {
vec!["--child".into()]
}
// The timeout to use for query execution.
fn timeout(_config: &Self::Config) -> Duration {
Duration::from_millis(100)
}
// On the child, the service will be created from the config on startup.
fn create(_config: Self::Config) -> Result<Self, IoError> {
Ok(AddTwoService)
}
// Process 1 message.
fn handle(&self, request: Self::Req) -> Self::Res {
match request {
Request::AddTwo(left, right) => left + right,
Request::ThrowPanic => {
panic!("test panic");
}
}
}
}
#[async_std::main]
async fn main() -> Result<(), IoError> {
let args = env::args().collect::<Vec<_>>();
if args.len() > 1 && args[1] == "--child" {
GLOBAL.set_limit(1_000_000);
rink_sandbox::become_child::<AddTwoService, _>(&GLOBAL);
}
let sandbox = Sandbox::<AddTwoService>::new(()).await?;
let response = sandbox.execute(Request::AddTwo(1, 2)).await.unwrap();
assert_eq!(response.result, 3);
let response = sandbox.execute(Request::AddTwo(17, 9)).await.unwrap();
assert_eq!(response.result, 26);
let response = sandbox.execute(Request::ThrowPanic).await.unwrap_err();
assert!(response.to_string().contains("test panic"));
println!("OK");
Ok(())
}

View file

@ -11,7 +11,9 @@
use serde::de::DeserializeOwned;
use serde_derive::{Deserialize, Serialize};
use std::{ffi::OsString, io::Error as IoError, panic::RefUnwindSafe, time::Duration};
use std::{
ffi::OsString, io::Error as IoError, panic::RefUnwindSafe, path::PathBuf, time::Duration,
};
use thiserror::Error;
mod alloc;
@ -85,6 +87,12 @@ pub trait Service: Sized + RefUnwindSafe + 'static {
/// The config is passed to the child on startup.
type Config: serde::Serialize + DeserializeOwned + Clone + 'static;
/// Returns the path to the executable, or None if the current
/// executable should be used.
fn program() -> Option<PathBuf> {
None
}
/// When your app is passed these CLI flags, it should call
/// [`become_child`].
fn args(config: &Self::Config) -> Vec<OsString>;

View file

@ -52,7 +52,9 @@ where
let mut ctrlc = CtrlC::new().unwrap();
loop {
let program = env::current_exe().expect("Couldn't find current executable");
let program = S::program()
.or_else(|| env::current_exe().ok())
.expect("Couldn't find executable");
let args = S::args(&config);
let mut process = Command::new(program)