Skip to content

Ability to pass closure in async #100

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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