Skip to content

Ability to pass closure in async #100

@palash3

Description

@palash3

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 (aa3c7f4) of injectorpp repository.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions