microsoft / microsoft/injectorppforrust
Ability to pass closure in async
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 404
- Forks
- 19
- Avg merge
- 23h 57m
- Merged PRs (30d)
- 1
Description
Hey Folks,
I was trying out the injectorpp to mock async calls. I wanted a way to map input to output. e.g
{
"hostname": "IamInLinux",
"ls": "remotefile1 remotefile2"
}
For sync functions I was able to use will_execute_raw .
Is there a way to pass async closures or fake_functions in async ?
I tried to implement the above behaviour using multiple calls to when_called_async in test_multicall, but it fails.
use tokio::process::Command;
#[tokio::main]
async fn main() {
run().await;
// run_double();
}
async fn run() {
let output = Command::new("ls")
.output()
.await
.expect("Failed to execute command");
if output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
println!("Command output:\n{}", stdout);
} else {
let stderr = String::from_utf8_lossy(&output.stderr);
eprintln!("Command failed:\n{}", stderr);
}
}
async fn run_double() {
let output = Command::new("ls")
.output()
.await
.expect("Failed to execute command");
if output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
println!("Command output:\n{}", stdout);
} else {
let stderr = String::from_utf8_lossy(&output.stderr);
eprintln!("Command failed:\n{}", stderr);
}
let output = Command::new("hostname")
.output()
.await
.expect("Failed to execute command");
if output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
println!("Command output:\n{}", stdout);
} else {
let stderr = String::from_utf8_lossy(&output.stderr);
eprintln!("Command failed:\n{}", stderr);
}
}
#[cfg(test)]
mod test {
use super::*;
use injectorpp::interface::injector::*;
use tokio::process::Command;
use std::process::{ExitStatus, Output};
#[tokio::test]
async fn test_simple() {
let mut c = Command::new("ls");
let mut injector = InjectorPP::new();
injector
.when_called_async(injectorpp::async_func!(
Command::output(&mut c),
std::io::Result<Output>
))
.will_return_async(injectorpp::async_return!(
Ok(Output {
status: ExitStatus::default(),
stdout: b"1,2".to_vec(),
stderr: b"".to_vec()
}),
std::io::Result<Output>
));
run().await;
}
async fn fake_cmd_run(cmd: &mut Command) -> std::io::Result<Output> {
if cmd.as_std().get_program() == "ls" {
Ok(Output {
status: ExitStatus::default(),
stdout: b"fakefile1,fakefile2".to_vec(),
stderr: b"".to_vec(),
})
} else if cmd.as_std().get_program() == "hostname" {
Ok(Output {
status: ExitStatus::default(),
stdout: b"IamLinux".to_vec(),
stderr: b"".to_vec(),
})
} else {
Err(std::io::Error::other("Did not work"))
}
}
#[tokio::test]
async fn test_multicall() {
let mut c = Command::new("ls");
let mut injector = InjectorPP::new();
injector
.when_called_async(injectorpp::async_func!(
Command::output(&mut c),
std::io::Result<Output>
))
.will_return_async(injectorpp::async_return!(
Ok(Output {
status: ExitStatus::default(),
stdout: b"1,2".to_vec(),
stderr: b"".to_vec()
}),
std::io::Result<Output>
));
let mut z = Command::new("hostname");
injector
.when_called_async(injectorpp::async_func!(
Command::output(&mut z),
std::io::Result<Output>
))
.will_return_async(injectorpp::async_return!(
Ok(Output {
status: ExitStatus::default(),
stdout: b"IamLinux".to_vec(),
stderr: b"".to_vec()
}),
std::io::Result<Output>
));
run_double().await;
}
}
cargo test output
---- test::test_simple stdout ----
Command output:
1,2
---- test::test_multicall stdout ----
Command output:
IamLinux
Command output:
IamLinux
Expected output:
---- test::test_multicall stdout ----
Command output:
1,2
Command output:
IamLinux
Cargo.toml
[package]
name = "injector-example"
version = "0.1.0"
edition = "2021"
[dependencies]
tokio = { version = "1", features = ["full"] }
tokio-test = "0.4"
[dev-dependencies]
injectorpp = { branch = "main", git = "https://github.com/microsoft/injectorppforrust.git", default-features = false }
I am using Mac M2 Pro to run the test and latest main branch (aa3c7f464c9f6e6f9fa1e6d4d9337c4bd9d53b89) of injectorpp repository.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the async mocking APIs used in the reported test: when_called_async, async_func!, will_return_async, and test_multicall. Reproduce the failure with the provided tokio tests, then trace how successive async calls are matched and determine how closure-based results should be supported. Done means test_multicall returns 1,2 for ls and IamLinux for hostname, with a regression test covering the behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- testing
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100