How do I fix the error due to Method is returning a reference to Result when I need owned Result

I have an interface as follows:

#[async_trait]
pub trait HttpClient {
    async fn send_request(&self, path: String) -> Result<Response, Error>;
}

Then in integration test, I have an implementation for it as follows:

struct MockClient {
    res_req: HashMap<String, Result<Response, Error>>
}
impl MockClient {
    pub fn mock(res_req: HashMap<String, Result<Response, Error>>) -> Self {
        Self {
            res_req,
        }
    }
}

#[async_trait]
impl HttpClient for MockClient {
    async fn send_request(&self, path: String) -> Result<Response, Error> {
        self.res_req.get(&path).unwrap()
    }
}

But his fails compilation with the following error

error[E0308]: mismatched types
  --> tests/integration_test.rs:22:9
   |
22 |         self.res_req.get(&path).unwrap()
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Result`, found reference
   |
   = note:   expected enum `Result<Response, reqwest::Error>`
           found reference `&Result<Response, reqwest::Error>`

I tried using .clone() to create a copy and returned but that did not work.

My questions are:

  1. Why is the compilation error occuring?
  2. Why did the attempt to use clone() not work?
  3. How do I get this to compile?

HashMap::get returns the reference inside hashmap. To return an owned value, it had to move it out of the map (that's what remove would do).

Result<T, E> can be cloned only if both T and E can. reqwest::Response and reqwest::Error are both not Clone.

Your best bet might be probably to generate responses in the MockClient on the fly, without pre-computing them. That is, whatever code is used to create res_req should instead run every time you call MockClient::send_request.

That becomes a bit tricky. What I was looking at doing is to seed the mock with paths and corresponding response in each tests. If I move to generating the response on the fly, it means my implementation will be a global form of all the possible paths and responses...workable but maybe not my preferred approach.

I'll tinker with it a bit and see how it turns out.

Thanks for the help.

Another way might be to store not the Responce itself, but a String, which is generated beforehand while seeding, but converted to the Responce on the fly.

doing something similar to this but now have hit another road block :sweat_smile:

The Ok(Response::from(http::response::Response::new("hi"))) works because this is just a string, but in real life, the response is a response of a custom struct! And that fails because it does not require the needed traits :sweat_smile:

error[E0277]: the trait bound `Body: From<Payload>` is not satisfied
  --> tests/integration_test.rs:30:27
   |
30 |         Ok(Response::from(http::response::Response::new(res)))
   |            -------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<Payload>` is not implemented for `Body`

I think I am going to take a step back and revisit the tests :sweat_smile: Maybe I just spin up a server in the test and mock that, instead of trying to abstract the components that makes the http requests :sweat_smile:

What's the real, non-mocked response in this case? If it's JSON, then you probably should just serialize your structs to JSON in mock, too.

Yeah. This

        let res: Payload = ...
        Ok(Response::from(http::response::Response::new(serde_json::to_string(&res).unwrap())))

Did the trick.

I just don't feel as productive with all these wrangling with the compiler :sweat_smile:

But hopefully as I use the language more, things will improve :slight_smile:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.