Rust 实现hyper::client::Connect以进行测试

Rust 实现hyper::client::Connect以进行测试,rust,Rust,我试图通过使用静态响应实现自己的hyper::Client::Connect来测试一些使用hyper::Client的代码。我已经弄清楚了类型,但无法弄清楚运行时的问题,tokio proto抱怨说请求/响应不匹配。下面是我的代码的简化版本,演示了失败: extern crate futures; extern crate hyper; extern crate tokio_core; extern crate tokio_io; use futures::{future, Future, S

我试图通过使用静态响应实现自己的
hyper::Client::Connect
来测试一些使用
hyper::Client
的代码。我已经弄清楚了类型,但无法弄清楚运行时的问题,
tokio proto
抱怨说
请求/响应不匹配
。下面是我的代码的简化版本,演示了失败:

extern crate futures;
extern crate hyper;
extern crate tokio_core;
extern crate tokio_io;

use futures::{future, Future, Stream};
use std::str::from_utf8;
use std::io::Cursor;

struct Client<'a, C: 'a> {
    client: &'a hyper::Client<C>,
    url: &'a str,
}

impl<'a, C: hyper::client::Connect> Client<'a, C> {
    fn get(&self) -> Box<Future<Item = String, Error = hyper::Error>> {
        Box::new(self.client.get(self.url.parse().unwrap()).and_then(|res| {
            let body = Vec::new();
            res.body()
                .fold(body, |mut acc, chunk| {
                    acc.extend_from_slice(chunk.as_ref());
                    Ok::<_, hyper::Error>(acc)
                })
                .and_then(move |value| Ok(String::from(from_utf8(&value).unwrap())))
        }))
    }
}

struct StaticConnector<'a> {
    body: &'a [u8],
}

impl<'a> StaticConnector<'a> {
    fn new(body: &'a [u8]) -> StaticConnector {
        StaticConnector { body: body }
    }
}

impl<'a> hyper::server::Service for StaticConnector<'a> {
    type Request = hyper::Uri;
    type Response = Cursor<Vec<u8>>;
    type Error = std::io::Error;
    type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;

    fn call(&self, _: Self::Request) -> Self::Future {
        Box::new(future::ok(Cursor::new(self.body.to_vec())))
    }
}

fn main() {
    let mut core = tokio_core::reactor::Core::new().unwrap();
    let handle = core.handle();

    // My StaticConnector for testing
    let hyper_client = hyper::Client::configure()
        .connector(StaticConnector::new(
            b"\
                 HTTP/1.1 200 OK\r\n\
                 Content-Length: 8\r\n\
                 \r\n\
                 Maldives\
                 ",
        ))
        .build(&handle);

    // Real Connector
    /*
    let hyper_client = hyper::Client::configure().build(&handle);
    */

    let client = Client {
        client: &hyper_client,
        url: "http://ifconfig.co/country",
    };
    let result = core.run(client.get()).unwrap();
    println!("{}", result);
}
extern板条箱期货;
外部板条箱;
外部板条箱东京大学核心;
外部板条箱东京;
使用未来:{future,future,Stream};
使用std::str::from_utf8;
使用std::io::Cursor;
结构客户端{
客户端:&'a hyper::client,
url:&'a str,
}
恳求{
fn获取(&self)->框{
Box::new(self.client.get(self.url.parse().unwrap())。然后(| res |{
让body=Vec::new();
决议草案主体()
.折叠(身体、身体、身体、身体){
acc.extend_from_slice(chunk.as_ref());
好的:(acc)
})
.和|然后(移动|值|确定(字符串::from(from _utf8(&value).unwrap()))
}))
}
}
结构静态连接器{
fn新(主体:&'a[u8])->静态连接器{
静态连接器{body:body}
}
}
恳求{
类型请求=hyper::Uri;
类型响应=游标;
类型错误=std::io::Error;
输入Future=Box;
fn调用(&self,quo:self::Request)->self::Future{
Box::new(future::ok(Cursor::new(self.body.to_vec()))
}
}
fn main(){
让mut core=tokio_core::reactor::core::new().unwrap();
让handle=core.handle();
//用于测试的静态连接器
让hyper_client=hyper::client::configure()
.connector(静态连接器::新建(
b“\
HTTP/1.1 200正常\r\n\
内容长度:8\r\n\
\r\n\
马尔代夫\
",
))
.构建和处理;
//实连接器
/*
让hyper_client=hyper::client::configure().生成(&handle);
*/
让客户端=客户端{
客户端:&超级客户端,
url:“http://ifconfig.co/country",
};
让result=core.run(client.get()).unwrap();
println!(“{}”,结果);
}


我猜是我对
Io
使用了
光标
,这在某种程度上是不完整的,但我无法调试并取得进展。一种想法是,对
光标的写入
hyper::Client
可能无法按预期工作。也许我需要一个用于写入的
接收器和用于读取的静态内容的组合?所有的想法,我都没能取得进展使用

原始代码不起作用的原因是,在客户端发送请求之前,读卡器端提供了响应,因此
tokio proto
出现了
请求/响应不匹配的错误。在我们首先需要安排读者阻止,或者更具体地说,错误是用<代码> STD::IO::ErrOrtho::WordBoads向事件循环指示没有任何东西,但是不要认为它是<代码> EOF。此外,一旦我们得到表明请求已发送且tokio原型机正在等待响应的写入,我们将使用
futures::task::current.notify
解除对读取的阻止。以下是一个按预期运行的更新实施:

extern crate futures;
extern crate hyper;
extern crate tokio_core;
extern crate tokio_io;

use futures::{future, Future, Stream, task, Poll};
use std::str::from_utf8;
use std::io::{self, Cursor, Read, Write};
use tokio_io::{AsyncRead, AsyncWrite};

struct Client<'a, C: 'a> {
    client: &'a hyper::Client<C>,
    url: &'a str,
}

impl<'a, C: hyper::client::Connect> Client<'a, C> {
    fn get(&self) -> Box<Future<Item = String, Error = hyper::Error>> {
        Box::new(self.client.get(self.url.parse().unwrap()).and_then(|res| {
            let body = Vec::new();
            res.body()
                .fold(body, |mut acc, chunk| {
                    acc.extend_from_slice(chunk.as_ref());
                    Ok::<_, hyper::Error>(acc)
                })
                .and_then(move |value| Ok(String::from(from_utf8(&value).unwrap())))
        }))
    }
}

struct StaticStream {
    wrote: bool,
    body: Cursor<Vec<u8>>,
}

impl Read for StaticStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if self.wrote {
            self.body.read(buf)
        } else {
            Err(io::ErrorKind::WouldBlock.into())
        }
    }
}

impl Write for StaticStream {
    fn write<'a>(&mut self, buf: &'a [u8]) -> io::Result<usize> {
        self.wrote = true;
        task::current().notify();
        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl AsyncRead for StaticStream {}

impl AsyncWrite for StaticStream {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        Ok(().into())
    }
}

struct StaticConnector<'a> {
    body: &'a [u8],
}

impl<'a> StaticConnector<'a> {
    fn new(body: &'a [u8]) -> StaticConnector {
        StaticConnector { body: body }
    }
}

impl<'a> hyper::server::Service for StaticConnector<'a> {
    type Request = hyper::Uri;
    type Response = StaticStream;
    type Error = std::io::Error;
    type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;

    fn call(&self, _: Self::Request) -> Self::Future {
        Box::new(future::ok(StaticStream {
            wrote: false,
            body: Cursor::new(self.body.to_vec()),
        }))
    }
}

fn main() {
    let mut core = tokio_core::reactor::Core::new().unwrap();
    let handle = core.handle();

    // My StaticConnector for testing
    let hyper_client = hyper::Client::configure()
        .connector(StaticConnector::new(
            b"\
                 HTTP/1.1 200 OK\r\n\
                 Content-Length: 8\r\n\
                 \r\n\
                 Maldives\
                 ",
        ))
        .build(&handle);

    // Real Connector
    /*
    let hyper_client = hyper::Client::configure().build(&handle);
    */

    let client = Client {
        client: &hyper_client,
        url: "http://ifconfig.co/country",
    };
    let result = core.run(client.get()).unwrap();
    println!("{}", result);
}
extern板条箱期货;
外部板条箱;
外部板条箱东京大学核心;
外部板条箱东京;
使用未来:{future,future,Stream,task,Poll};
使用std::str::from_utf8;
使用std::io::{self,Cursor,Read,Write};
使用tokio_io::{AsyncRead,AsyncWrite};
结构客户端{
客户端:&'a hyper::client,
url:&'a str,
}
恳求{
fn获取(&self)->框{
Box::new(self.client.get(self.url.parse().unwrap())。然后(| res |{
让body=Vec::new();
决议草案主体()
.折叠(身体、身体、身体、身体){
acc.extend_from_slice(chunk.as_ref());
好的:(acc)
})
.和|然后(移动|值|确定(字符串::from(from _utf8(&value).unwrap()))
}))
}
}
结构静态流{
作者:布尔,
正文:游标,
}
静态流的impl读取{
fn read(&mut self,buf:&mut[u8])->io::Result{
如果是我自己写的{
self.body.read(buf)
}否则{
错误(io::ErrorKind::WouldBlock.into())
}
}
}
静态流的impl写入{
fn写入io::结果{
self.writed=true;
任务::当前().notify();
Ok(buf.len())
}
fn刷新(&mut self)->io::结果{
好(())
}
}
静态流{}的impl AsyncRead
StaticStream的impl异步写入{
fn关闭(&mut self)->轮询{
好(().into())
}
}
结构静态连接器{
fn新(主体:&'a[u8])->静态连接器{
静态连接器{body:body}
}
}
恳求{
类型请求=hyper::Uri;
类型响应=静态流;
类型错误=std::io::Error;
输入Future=Box;
fn调用(&self,quo:self::Request)->self::Future{
框::新建(未来::确定(静态流){
写道:错,
body:Cursor::new(self.body.to_vec()),
}))
}
}
fn main(){
让mut core=tokio_core::reactor::core::new().unwrap();
让handle=core.handle();
//用于测试的静态连接器
让hyper_client=hyper::client::configure()
.connector(静态连接器::新建(
b“\
HTTP/1.1 200正常\r\n\
内容长度:8\r\n\
\r\n\
马尔代夫\
",
))
.构建和处理;
//实连接器
/*
让hyper_client=hyper::client::configure().生成(&handle);
*/
让客户端=客户端{
客户端:&超级客户端,
url:“http://ifconfig.co/country",
};
让result=core.run(client.get()).unwrap();
println!(“{}”,结果);
}

注:这意味着