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!(“{}”,结果);
}
注:这意味着