mirror of
https://github.com/tiffany352/rink-rs
synced 2024-11-10 05:34:14 +00:00
Add an integration test to rink-sandbox (#128)
This commit is contained in:
parent
07bdee9eb8
commit
672c915331
4 changed files with 99 additions and 2 deletions
|
@ -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
|
||||
|
|
82
sandbox/integration/main.rs
Normal file
82
sandbox/integration/main.rs
Normal 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(())
|
||||
}
|
|
@ -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>;
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue