chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

171
vendor/tower/tests/balance/main.rs vendored Normal file
View File

@@ -0,0 +1,171 @@
#![cfg(feature = "balance")]
#[path = "../support.rs"]
mod support;
use std::future::Future;
use std::task::{Context, Poll};
use tokio_stream::wrappers::UnboundedReceiverStream;
use tokio_test::{assert_pending, assert_ready, task};
use tower::balance::p2c::Balance;
use tower::discover::Change;
use tower_service::Service;
use tower_test::mock;
type Req = &'static str;
struct Mock(mock::Mock<Req, Req>);
impl Service<Req> for Mock {
type Response = <mock::Mock<Req, Req> as Service<Req>>::Response;
type Error = <mock::Mock<Req, Req> as Service<Req>>::Error;
type Future = <mock::Mock<Req, Req> as Service<Req>>::Future;
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.0.poll_ready(cx)
}
fn call(&mut self, req: Req) -> Self::Future {
self.0.call(req)
}
}
impl tower::load::Load for Mock {
type Metric = usize;
fn load(&self) -> Self::Metric {
rand::random_range(usize::MIN..=usize::MAX)
}
}
#[test]
fn stress() {
let _t = support::trace_init();
let mut task = task::spawn(());
let (tx, rx) = tokio::sync::mpsc::unbounded_channel::<Result<_, &'static str>>();
let mut cache = Balance::<_, Req>::new(UnboundedReceiverStream::new(rx));
let mut nready = 0;
let mut services = slab::Slab::<(mock::Handle<Req, Req>, bool)>::new();
let mut retired = Vec::<mock::Handle<Req, Req>>::new();
for _ in 0..100_000 {
for _ in 0..rand::random_range(0u8..8) {
if !services.is_empty() && rand::random() {
if nready == 0 || rand::random::<u8>() > u8::MAX / 4 {
// ready a service
// TODO: sometimes ready a removed service?
for (_, (handle, ready)) in &mut services {
if !*ready {
handle.allow(1);
*ready = true;
nready += 1;
break;
}
}
} else {
// use a service
use std::task::Poll;
match task.enter(|cx, _| cache.poll_ready(cx)) {
Poll::Ready(Ok(())) => {
assert_ne!(nready, 0, "got ready when no service is ready");
let mut fut = cache.call("hello");
let mut fut = std::pin::Pin::new(&mut fut);
assert_pending!(task.enter(|cx, _| fut.as_mut().poll(cx)));
let mut found = false;
for (_, (handle, ready)) in &mut services {
if *ready {
if let Poll::Ready(Some((req, res))) = handle.poll_request() {
assert_eq!(req, "hello");
res.send_response("world");
*ready = false;
nready -= 1;
found = true;
break;
}
}
}
if !found {
// we must have been given a retired service
let mut at = None;
for (i, handle) in retired.iter_mut().enumerate() {
if let Poll::Ready(Some((req, res))) = handle.poll_request() {
assert_eq!(req, "hello");
res.send_response("world");
at = Some(i);
break;
}
}
let _ = retired.swap_remove(
at.expect("request was not sent to a ready service"),
);
nready -= 1;
}
assert_ready!(task.enter(|cx, _| fut.as_mut().poll(cx))).unwrap();
}
Poll::Ready(_) => unreachable!("discover stream has not failed"),
Poll::Pending => {
// assert_eq!(nready, 0, "got pending when a service is ready");
}
}
}
} else if services.is_empty() || rand::random() {
if services.is_empty() || nready == 0 || rand::random() {
// add
let (svc, mut handle) = mock::pair::<Req, Req>();
let svc = Mock(svc);
handle.allow(0);
let k = services.insert((handle, false));
let ok = tx.send(Ok(Change::Insert(k, svc)));
assert!(ok.is_ok());
} else {
// remove
while !services.is_empty() {
let k = rand::random_range(0..=services.iter().next_back().unwrap().0);
if services.contains(k) {
let (handle, ready) = services.remove(k);
if ready {
retired.push(handle);
}
let ok = tx.send(Ok(Change::Remove(k)));
assert!(ok.is_ok());
break;
}
}
}
} else {
// fail a service
while !services.is_empty() {
let k = rand::random_range(0..=services.iter().next_back().unwrap().0);
if services.contains(k) {
let (mut handle, ready) = services.remove(k);
if ready {
nready -= 1;
}
handle.send_error("doom");
break;
}
}
}
}
let r = task.enter(|cx, _| cache.poll_ready(cx));
// drop any retired services that the p2c has gotten rid of
let mut removed = Vec::new();
for (i, handle) in retired.iter_mut().enumerate() {
if let Poll::Ready(None) = handle.poll_request() {
removed.push(i);
}
}
for i in removed.into_iter().rev() {
retired.swap_remove(i);
nready -= 1;
}
use std::task::Poll;
match r {
Poll::Ready(Ok(())) => {
assert_ne!(nready, 0, "got ready when no service is ready");
}
Poll::Ready(_) => unreachable!("discover stream has not failed"),
Poll::Pending => {
assert_eq!(nready, 0, "got pending when a service is ready");
}
}
}
}

459
vendor/tower/tests/buffer/main.rs vendored Normal file
View File

@@ -0,0 +1,459 @@
#![cfg(feature = "buffer")]
#[path = "../support.rs"]
mod support;
use std::thread;
use tokio_test::{assert_pending, assert_ready, assert_ready_err, assert_ready_ok, task};
use tower::buffer::{error, Buffer};
use tower::{util::ServiceExt, Service};
use tower_test::{assert_request_eq, mock};
fn let_worker_work() {
// Allow the Buffer's executor to do work
thread::sleep(::std::time::Duration::from_millis(100));
}
#[tokio::test(flavor = "current_thread")]
async fn req_and_res() {
let _t = support::trace_init();
let (mut service, mut handle) = new_service();
assert_ready_ok!(service.poll_ready());
let mut response = task::spawn(service.call("hello"));
assert_request_eq!(handle, "hello").send_response("world");
let_worker_work();
assert_eq!(assert_ready_ok!(response.poll()), "world");
}
#[tokio::test(flavor = "current_thread")]
async fn clears_canceled_requests() {
let _t = support::trace_init();
let (mut service, mut handle) = new_service();
handle.allow(1);
assert_ready_ok!(service.poll_ready());
let mut res1 = task::spawn(service.call("hello"));
let send_response1 = assert_request_eq!(handle, "hello");
// don't respond yet, new requests will get buffered
assert_ready_ok!(service.poll_ready());
let res2 = task::spawn(service.call("hello2"));
assert_pending!(handle.poll_request());
assert_ready_ok!(service.poll_ready());
let mut res3 = task::spawn(service.call("hello3"));
drop(res2);
send_response1.send_response("world");
let_worker_work();
assert_eq!(assert_ready_ok!(res1.poll()), "world");
// res2 was dropped, so it should have been canceled in the buffer
handle.allow(1);
assert_request_eq!(handle, "hello3").send_response("world3");
let_worker_work();
assert_eq!(assert_ready_ok!(res3.poll()), "world3");
}
#[tokio::test(flavor = "current_thread")]
async fn when_inner_is_not_ready() {
let _t = support::trace_init();
let (mut service, mut handle) = new_service();
// Make the service NotReady
handle.allow(0);
assert_ready_ok!(service.poll_ready());
let mut res1 = task::spawn(service.call("hello"));
let_worker_work();
assert_pending!(res1.poll());
assert_pending!(handle.poll_request());
handle.allow(1);
assert_request_eq!(handle, "hello").send_response("world");
let_worker_work();
assert_eq!(assert_ready_ok!(res1.poll()), "world");
}
#[tokio::test(flavor = "current_thread")]
async fn when_inner_fails() {
use std::error::Error as StdError;
let _t = support::trace_init();
let (mut service, mut handle) = new_service();
// Make the service NotReady
handle.allow(0);
handle.send_error("foobar");
assert_ready_ok!(service.poll_ready());
let mut res1 = task::spawn(service.call("hello"));
let_worker_work();
let e = assert_ready_err!(res1.poll());
if let Some(e) = e.downcast_ref::<error::ServiceError>() {
let e = e.source().unwrap();
assert_eq!(e.to_string(), "foobar");
} else {
panic!("unexpected error type: {:?}", e);
}
}
#[tokio::test(flavor = "current_thread")]
async fn poll_ready_when_worker_is_dropped_early() {
let _t = support::trace_init();
let (service, _handle) = mock::pair::<(), ()>();
let (service, worker) = Buffer::pair(service, 1);
let mut service = mock::Spawn::new(service);
drop(worker);
let err = assert_ready_err!(service.poll_ready());
assert!(err.is::<error::Closed>(), "should be a Closed: {:?}", err);
}
#[tokio::test(flavor = "current_thread")]
async fn response_future_when_worker_is_dropped_early() {
let _t = support::trace_init();
let (service, mut handle) = mock::pair::<_, ()>();
let (service, worker) = Buffer::pair(service, 1);
let mut service = mock::Spawn::new(service);
// keep the request in the worker
handle.allow(0);
assert_ready_ok!(service.poll_ready());
let mut response = task::spawn(service.call("hello"));
drop(worker);
let_worker_work();
let err = assert_ready_err!(response.poll());
assert!(err.is::<error::Closed>(), "should be a Closed: {:?}", err);
}
#[tokio::test(flavor = "current_thread")]
async fn waits_for_channel_capacity() {
let _t = support::trace_init();
let (service, mut handle) = mock::pair::<&'static str, &'static str>();
let (service, worker) = Buffer::pair(service, 2);
let mut service = mock::Spawn::new(service);
let mut worker = task::spawn(worker);
// keep requests in the worker
handle.allow(0);
assert_ready_ok!(service.poll_ready());
let mut response1 = task::spawn(service.call("hello"));
assert_pending!(worker.poll());
assert_ready_ok!(service.poll_ready());
let mut response2 = task::spawn(service.call("hello"));
assert_pending!(worker.poll());
assert_ready_ok!(service.poll_ready());
let mut response3 = task::spawn(service.call("hello"));
assert_pending!(service.poll_ready());
assert_pending!(worker.poll());
handle.allow(1);
assert_pending!(worker.poll());
handle
.next_request()
.await
.unwrap()
.1
.send_response("world");
assert_pending!(worker.poll());
assert_ready_ok!(response1.poll());
assert_ready_ok!(service.poll_ready());
let mut response4 = task::spawn(service.call("hello"));
assert_pending!(worker.poll());
handle.allow(3);
assert_pending!(worker.poll());
handle
.next_request()
.await
.unwrap()
.1
.send_response("world");
assert_pending!(worker.poll());
assert_ready_ok!(response2.poll());
assert_pending!(worker.poll());
handle
.next_request()
.await
.unwrap()
.1
.send_response("world");
assert_pending!(worker.poll());
assert_ready_ok!(response3.poll());
assert_pending!(worker.poll());
handle
.next_request()
.await
.unwrap()
.1
.send_response("world");
assert_pending!(worker.poll());
assert_ready_ok!(response4.poll());
}
#[tokio::test(flavor = "current_thread")]
async fn wakes_pending_waiters_on_close() {
let _t = support::trace_init();
let (service, mut handle) = mock::pair::<_, ()>();
let (mut service, worker) = Buffer::pair(service, 1);
let mut worker = task::spawn(worker);
// keep the request in the worker
handle.allow(0);
let service1 = service.ready().await.unwrap();
assert_pending!(worker.poll());
let mut response = task::spawn(service1.call("hello"));
assert!(worker.is_woken(), "worker task should be woken by request");
assert_pending!(worker.poll());
// fill the channel so all subsequent requests will wait for capacity
let service1 = assert_ready_ok!(task::spawn(service.ready()).poll());
assert_pending!(worker.poll());
let mut response2 = task::spawn(service1.call("world"));
let mut service1 = service.clone();
let mut ready1 = task::spawn(service1.ready());
assert_pending!(worker.poll());
assert_pending!(ready1.poll(), "no capacity");
let mut service1 = service.clone();
let mut ready2 = task::spawn(service1.ready());
assert_pending!(worker.poll());
assert_pending!(ready2.poll(), "no capacity");
// kill the worker task
drop(worker);
let err = assert_ready_err!(response.poll());
assert!(
err.is::<error::Closed>(),
"response should fail with a Closed, got: {:?}",
err
);
let err = assert_ready_err!(response2.poll());
assert!(
err.is::<error::Closed>(),
"response should fail with a Closed, got: {:?}",
err
);
assert!(
ready1.is_woken(),
"dropping worker should wake ready task 1"
);
let err = assert_ready_err!(ready1.poll());
assert!(
err.is::<error::Closed>(),
"ready 1 should fail with a Closed, got: {:?}",
err
);
assert!(
ready2.is_woken(),
"dropping worker should wake ready task 2"
);
let err = assert_ready_err!(ready1.poll());
assert!(
err.is::<error::Closed>(),
"ready 2 should fail with a Closed, got: {:?}",
err
);
}
#[tokio::test(flavor = "current_thread")]
async fn wakes_pending_waiters_on_failure() {
let _t = support::trace_init();
let (service, mut handle) = mock::pair::<_, ()>();
let (mut service, worker) = Buffer::pair(service, 1);
let mut worker = task::spawn(worker);
// keep the request in the worker
handle.allow(0);
let service1 = service.ready().await.unwrap();
assert_pending!(worker.poll());
let mut response = task::spawn(service1.call("hello"));
assert!(worker.is_woken(), "worker task should be woken by request");
assert_pending!(worker.poll());
// fill the channel so all subsequent requests will wait for capacity
let service1 = assert_ready_ok!(task::spawn(service.ready()).poll());
assert_pending!(worker.poll());
let mut response2 = task::spawn(service1.call("world"));
let mut service1 = service.clone();
let mut ready1 = task::spawn(service1.ready());
assert_pending!(worker.poll());
assert_pending!(ready1.poll(), "no capacity");
let mut service1 = service.clone();
let mut ready2 = task::spawn(service1.ready());
assert_pending!(worker.poll());
assert_pending!(ready2.poll(), "no capacity");
// fail the inner service
handle.send_error("foobar");
// worker task terminates
assert_ready!(worker.poll());
let err = assert_ready_err!(response.poll());
assert!(
err.is::<error::ServiceError>(),
"response should fail with a ServiceError, got: {:?}",
err
);
let err = assert_ready_err!(response2.poll());
assert!(
err.is::<error::ServiceError>(),
"response should fail with a ServiceError, got: {:?}",
err
);
assert!(
ready1.is_woken(),
"dropping worker should wake ready task 1"
);
let err = assert_ready_err!(ready1.poll());
assert!(
err.is::<error::ServiceError>(),
"ready 1 should fail with a ServiceError, got: {:?}",
err
);
assert!(
ready2.is_woken(),
"dropping worker should wake ready task 2"
);
let err = assert_ready_err!(ready1.poll());
assert!(
err.is::<error::ServiceError>(),
"ready 2 should fail with a ServiceError, got: {:?}",
err
);
}
#[tokio::test(flavor = "current_thread")]
async fn propagates_trace_spans() {
use tower::util::ServiceExt;
use tracing::Instrument;
let _t = support::trace_init();
let span = tracing::info_span!("my_span");
let service = support::AssertSpanSvc::new(span.clone());
let (service, worker) = Buffer::pair(service, 5);
let worker = tokio::spawn(worker);
let result = tokio::spawn(service.oneshot(()).instrument(span));
result.await.expect("service panicked").expect("failed");
worker.await.expect("worker panicked");
}
#[tokio::test(flavor = "current_thread")]
async fn doesnt_leak_permits() {
let _t = support::trace_init();
let (service, mut handle) = mock::pair::<_, ()>();
let (mut service1, worker) = Buffer::pair(service, 2);
let mut worker = task::spawn(worker);
let mut service2 = service1.clone();
let mut service3 = service1.clone();
// Attempt to poll the first clone of the buffer to readiness multiple
// times. These should all succeed, because the readiness is never
// *consumed* --- no request is sent.
assert_ready_ok!(task::spawn(service1.ready()).poll());
assert_ready_ok!(task::spawn(service1.ready()).poll());
assert_ready_ok!(task::spawn(service1.ready()).poll());
// It should also be possible to drive the second clone of the service to
// readiness --- it should only acquire one permit, as well.
assert_ready_ok!(task::spawn(service2.ready()).poll());
assert_ready_ok!(task::spawn(service2.ready()).poll());
assert_ready_ok!(task::spawn(service2.ready()).poll());
// The third clone *doesn't* poll ready, because the first two clones have
// each acquired one permit.
let mut ready3 = task::spawn(service3.ready());
assert_pending!(ready3.poll());
// Consume the first service's readiness.
let mut response = task::spawn(service1.call(()));
handle.allow(1);
assert_pending!(worker.poll());
handle.next_request().await.unwrap().1.send_response(());
assert_pending!(worker.poll());
assert_ready_ok!(response.poll());
// Now, the third service should acquire a permit...
assert!(ready3.is_woken());
assert_ready_ok!(ready3.poll());
}
type Handle = mock::Handle<&'static str, &'static str>;
type MockBuffer = Buffer<&'static str, mock::future::ResponseFuture<&'static str>>;
fn new_service() -> (mock::Spawn<MockBuffer>, Handle) {
// bound is >0 here because clears_canceled_requests needs multiple outstanding requests
new_service_with_bound(10)
}
fn new_service_with_bound(bound: usize) -> (mock::Spawn<MockBuffer>, Handle) {
mock::spawn_with(|s| {
let (svc, worker) = Buffer::pair(s, bound);
thread::spawn(move || {
let mut fut = tokio_test::task::spawn(worker);
while fut.poll().is_pending() {}
});
svc
})
}

55
vendor/tower/tests/builder.rs vendored Normal file
View File

@@ -0,0 +1,55 @@
#![cfg(all(feature = "buffer", feature = "limit", feature = "retry"))]
mod support;
use futures_util::pin_mut;
use std::{future::Ready, time::Duration};
use tower::builder::ServiceBuilder;
use tower::retry::Policy;
use tower::util::ServiceExt;
use tower_service::*;
use tower_test::{assert_request_eq, mock};
#[tokio::test(flavor = "current_thread")]
async fn builder_service() {
let _t = support::trace_init();
let (service, handle) = mock::pair();
pin_mut!(handle);
let policy = MockPolicy::<&'static str, bool>::default();
let mut client = ServiceBuilder::new()
.buffer(5)
.concurrency_limit(5)
.rate_limit(5, Duration::from_secs(5))
.retry(policy)
.map_response(|r: &'static str| r == "world")
.map_request(|r: &'static str| r == "hello")
.service(service);
// allow a request through
handle.allow(1);
let fut = client.ready().await.unwrap().call("hello");
assert_request_eq!(handle, true).send_response("world");
assert!(fut.await.unwrap());
}
#[derive(Debug, Clone, Default)]
struct MockPolicy<Req, Res> {
_pd: std::marker::PhantomData<(Req, Res)>,
}
impl<Req, Res, E> Policy<Req, Res, E> for MockPolicy<Req, Res>
where
Req: Clone,
E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
{
type Future = Ready<()>;
fn retry(&mut self, _req: &mut Req, _result: &mut Result<Res, E>) -> Option<Self::Future> {
None
}
fn clone_request(&mut self, req: &Req) -> Option<Req> {
Some(req.clone())
}
}

View File

@@ -0,0 +1,63 @@
#![cfg(feature = "filter")]
#[path = "../support.rs"]
mod support;
use futures_util::future::pin_mut;
use std::future::{poll_fn, Future};
use tower::filter::{error::Error, AsyncFilter};
use tower_service::Service;
use tower_test::{assert_request_eq, mock};
#[tokio::test(flavor = "current_thread")]
async fn passthrough_sync() {
let _t = support::trace_init();
let (mut service, handle) = new_service(|_| async { Ok(()) });
let th = tokio::spawn(async move {
// Receive the requests and respond
pin_mut!(handle);
for i in 0..10usize {
assert_request_eq!(handle, format!("ping-{}", i)).send_response(format!("pong-{}", i));
}
});
let mut responses = vec![];
for i in 0usize..10 {
let request = format!("ping-{}", i);
poll_fn(|cx| service.poll_ready(cx)).await.unwrap();
let exchange = service.call(request);
let exchange = async move {
let response = exchange.await.unwrap();
let expect = format!("pong-{}", i);
assert_eq!(response.as_str(), expect.as_str());
};
responses.push(exchange);
}
futures_util::future::join_all(responses).await;
th.await.unwrap();
}
#[tokio::test(flavor = "current_thread")]
async fn rejected_sync() {
let _t = support::trace_init();
let (mut service, _handle) = new_service(|_| async { Err(Error::rejected()) });
service.call("hello".into()).await.unwrap_err();
}
type Mock = mock::Mock<String, String>;
type Handle = mock::Handle<String, String>;
fn new_service<F, U>(f: F) -> (AsyncFilter<Mock, F>, Handle)
where
F: Fn(&String) -> U,
U: Future<Output = Result<(), Error>>,
{
let (service, handle) = mock::pair();
let service = AsyncFilter::new(service, f);
(service, handle)
}

184
vendor/tower/tests/hedge/main.rs vendored Normal file
View File

@@ -0,0 +1,184 @@
#![cfg(feature = "hedge")]
#[path = "../support.rs"]
mod support;
use std::time::Duration;
use tokio::time;
use tokio_test::{assert_pending, assert_ready, assert_ready_ok, task};
use tower::hedge::{Hedge, Policy};
use tower_test::{assert_request_eq, mock};
#[tokio::test(flavor = "current_thread")]
async fn hedge_orig_completes_first() {
let _t = support::trace_init();
time::pause();
let (mut service, mut handle) = new_service(TestPolicy);
assert_ready_ok!(service.poll_ready());
let mut fut = task::spawn(service.call("orig"));
// Check that orig request has been issued.
let req = assert_request_eq!(handle, "orig");
// Check fut is not ready.
assert_pending!(fut.poll());
// Check hedge has not been issued.
assert_pending!(handle.poll_request());
time::advance(Duration::from_millis(11)).await;
// Check fut is not ready.
assert_pending!(fut.poll());
// Check that the hedge has been issued.
let _hedge_req = assert_request_eq!(handle, "orig");
req.send_response("orig-done");
// Check that fut gets orig response.
assert_eq!(assert_ready_ok!(fut.poll()), "orig-done");
}
#[tokio::test(flavor = "current_thread")]
async fn hedge_hedge_completes_first() {
let _t = support::trace_init();
time::pause();
let (mut service, mut handle) = new_service(TestPolicy);
assert_ready_ok!(service.poll_ready());
let mut fut = task::spawn(service.call("orig"));
// Check that orig request has been issued.
let _req = assert_request_eq!(handle, "orig");
// Check fut is not ready.
assert_pending!(fut.poll());
// Check hedge has not been issued.
assert_pending!(handle.poll_request());
time::advance(Duration::from_millis(11)).await;
// Check fut is not ready.
assert_pending!(fut.poll());
// Check that the hedge has been issued.
let hedge_req = assert_request_eq!(handle, "orig");
hedge_req.send_response("hedge-done");
// Check that fut gets hedge response.
assert_eq!(assert_ready_ok!(fut.poll()), "hedge-done");
}
#[tokio::test(flavor = "current_thread")]
async fn completes_before_hedge() {
let _t = support::trace_init();
let (mut service, mut handle) = new_service(TestPolicy);
assert_ready_ok!(service.poll_ready());
let mut fut = task::spawn(service.call("orig"));
// Check that orig request has been issued.
let req = assert_request_eq!(handle, "orig");
// Check fut is not ready.
assert_pending!(fut.poll());
req.send_response("orig-done");
// Check hedge has not been issued.
assert_pending!(handle.poll_request());
// Check that fut gets orig response.
assert_eq!(assert_ready_ok!(fut.poll()), "orig-done");
}
#[tokio::test(flavor = "current_thread")]
async fn request_not_retyable() {
let _t = support::trace_init();
time::pause();
let (mut service, mut handle) = new_service(TestPolicy);
assert_ready_ok!(service.poll_ready());
let mut fut = task::spawn(service.call(NOT_RETRYABLE));
// Check that orig request has been issued.
let req = assert_request_eq!(handle, NOT_RETRYABLE);
// Check fut is not ready.
assert_pending!(fut.poll());
// Check hedge has not been issued.
assert_pending!(handle.poll_request());
time::advance(Duration::from_millis(10)).await;
// Check fut is not ready.
assert_pending!(fut.poll());
// Check hedge has not been issued.
assert_pending!(handle.poll_request());
req.send_response("orig-done");
// Check that fut gets orig response.
assert_eq!(assert_ready_ok!(fut.poll()), "orig-done");
}
#[tokio::test(flavor = "current_thread")]
async fn request_not_clonable() {
let _t = support::trace_init();
time::pause();
let (mut service, mut handle) = new_service(TestPolicy);
assert_ready_ok!(service.poll_ready());
let mut fut = task::spawn(service.call(NOT_CLONABLE));
// Check that orig request has been issued.
let req = assert_request_eq!(handle, NOT_CLONABLE);
// Check fut is not ready.
assert_pending!(fut.poll());
// Check hedge has not been issued.
assert_pending!(handle.poll_request());
time::advance(Duration::from_millis(10)).await;
// Check fut is not ready.
assert_pending!(fut.poll());
// Check hedge has not been issued.
assert_pending!(handle.poll_request());
req.send_response("orig-done");
// Check that fut gets orig response.
assert_eq!(assert_ready_ok!(fut.poll()), "orig-done");
}
type Req = &'static str;
type Res = &'static str;
type Mock = tower_test::mock::Mock<Req, Res>;
type Handle = tower_test::mock::Handle<Req, Res>;
static NOT_RETRYABLE: &str = "NOT_RETRYABLE";
static NOT_CLONABLE: &str = "NOT_CLONABLE";
#[derive(Clone)]
struct TestPolicy;
impl tower::hedge::Policy<Req> for TestPolicy {
fn can_retry(&self, req: &Req) -> bool {
*req != NOT_RETRYABLE
}
fn clone_request(&self, req: &Req) -> Option<Req> {
if *req == NOT_CLONABLE {
None
} else {
Some(req)
}
}
}
fn new_service<P: Policy<Req> + Clone>(policy: P) -> (mock::Spawn<Hedge<Mock, P>>, Handle) {
let (service, handle) = tower_test::mock::pair();
let mock_latencies: [u64; 10] = [1, 1, 1, 1, 1, 1, 1, 1, 10, 10];
let service = Hedge::new_with_mock_latencies(
service,
policy,
10,
0.9,
Duration::from_secs(60),
&mock_latencies,
);
(mock::Spawn::new(service), handle)
}

216
vendor/tower/tests/limit/concurrency.rs vendored Normal file
View File

@@ -0,0 +1,216 @@
use crate::support;
use tokio_test::{assert_pending, assert_ready, assert_ready_ok};
use tower::limit::concurrency::ConcurrencyLimitLayer;
use tower_test::{assert_request_eq, mock};
#[tokio::test(flavor = "current_thread")]
async fn basic_service_limit_functionality_with_poll_ready() {
let _t = support::trace_init();
let limit = ConcurrencyLimitLayer::new(2);
let (mut service, mut handle) = mock::spawn_layer(limit);
assert_ready_ok!(service.poll_ready());
let r1 = service.call("hello 1");
assert_ready_ok!(service.poll_ready());
let r2 = service.call("hello 2");
assert_pending!(service.poll_ready());
assert!(!service.is_woken());
// The request gets passed through
assert_request_eq!(handle, "hello 1").send_response("world 1");
// The next request gets passed through
assert_request_eq!(handle, "hello 2").send_response("world 2");
// There are no more requests
assert_pending!(handle.poll_request());
assert_eq!(r1.await.unwrap(), "world 1");
assert!(service.is_woken());
// Another request can be sent
assert_ready_ok!(service.poll_ready());
let r3 = service.call("hello 3");
assert_pending!(service.poll_ready());
assert_eq!(r2.await.unwrap(), "world 2");
// The request gets passed through
assert_request_eq!(handle, "hello 3").send_response("world 3");
assert_eq!(r3.await.unwrap(), "world 3");
}
#[tokio::test(flavor = "current_thread")]
async fn basic_service_limit_functionality_without_poll_ready() {
let _t = support::trace_init();
let limit = ConcurrencyLimitLayer::new(2);
let (mut service, mut handle) = mock::spawn_layer(limit);
assert_ready_ok!(service.poll_ready());
let r1 = service.call("hello 1");
assert_ready_ok!(service.poll_ready());
let r2 = service.call("hello 2");
assert_pending!(service.poll_ready());
// The request gets passed through
assert_request_eq!(handle, "hello 1").send_response("world 1");
assert!(!service.is_woken());
// The next request gets passed through
assert_request_eq!(handle, "hello 2").send_response("world 2");
assert!(!service.is_woken());
// There are no more requests
assert_pending!(handle.poll_request());
assert_eq!(r1.await.unwrap(), "world 1");
assert!(service.is_woken());
// One more request can be sent
assert_ready_ok!(service.poll_ready());
let r4 = service.call("hello 4");
assert_pending!(service.poll_ready());
assert_eq!(r2.await.unwrap(), "world 2");
assert!(service.is_woken());
// The request gets passed through
assert_request_eq!(handle, "hello 4").send_response("world 4");
assert_eq!(r4.await.unwrap(), "world 4");
}
#[tokio::test(flavor = "current_thread")]
async fn request_without_capacity() {
let _t = support::trace_init();
let limit = ConcurrencyLimitLayer::new(0);
let (mut service, _) = mock::spawn_layer::<(), (), _>(limit);
assert_pending!(service.poll_ready());
}
#[tokio::test(flavor = "current_thread")]
async fn reserve_capacity_without_sending_request() {
let _t = support::trace_init();
let limit = ConcurrencyLimitLayer::new(1);
let (mut s1, mut handle) = mock::spawn_layer(limit);
let mut s2 = s1.clone();
// Reserve capacity in s1
assert_ready_ok!(s1.poll_ready());
// Service 2 cannot get capacity
assert_pending!(s2.poll_ready());
// s1 sends the request, then s2 is able to get capacity
let r1 = s1.call("hello");
assert_request_eq!(handle, "hello").send_response("world");
assert_pending!(s2.poll_ready());
r1.await.unwrap();
assert_ready_ok!(s2.poll_ready());
}
#[tokio::test(flavor = "current_thread")]
async fn service_drop_frees_capacity() {
let _t = support::trace_init();
let limit = ConcurrencyLimitLayer::new(1);
let (mut s1, _handle) = mock::spawn_layer::<(), (), _>(limit);
let mut s2 = s1.clone();
// Reserve capacity in s1
assert_ready_ok!(s1.poll_ready());
// Service 2 cannot get capacity
assert_pending!(s2.poll_ready());
drop(s1);
assert!(s2.is_woken());
assert_ready_ok!(s2.poll_ready());
}
#[tokio::test(flavor = "current_thread")]
async fn response_error_releases_capacity() {
let _t = support::trace_init();
let limit = ConcurrencyLimitLayer::new(1);
let (mut s1, mut handle) = mock::spawn_layer::<_, (), _>(limit);
let mut s2 = s1.clone();
// Reserve capacity in s1
assert_ready_ok!(s1.poll_ready());
// s1 sends the request, then s2 is able to get capacity
let r1 = s1.call("hello");
assert_request_eq!(handle, "hello").send_error("boom");
r1.await.unwrap_err();
assert_ready_ok!(s2.poll_ready());
}
#[tokio::test(flavor = "current_thread")]
async fn response_future_drop_releases_capacity() {
let _t = support::trace_init();
let limit = ConcurrencyLimitLayer::new(1);
let (mut s1, _handle) = mock::spawn_layer::<_, (), _>(limit);
let mut s2 = s1.clone();
// Reserve capacity in s1
assert_ready_ok!(s1.poll_ready());
// s1 sends the request, then s2 is able to get capacity
let r1 = s1.call("hello");
assert_pending!(s2.poll_ready());
drop(r1);
assert_ready_ok!(s2.poll_ready());
}
#[tokio::test(flavor = "current_thread")]
async fn multi_waiters() {
let _t = support::trace_init();
let limit = ConcurrencyLimitLayer::new(1);
let (mut s1, _handle) = mock::spawn_layer::<(), (), _>(limit);
let mut s2 = s1.clone();
let mut s3 = s1.clone();
// Reserve capacity in s1
assert_ready_ok!(s1.poll_ready());
// s2 and s3 are not ready
assert_pending!(s2.poll_ready());
assert_pending!(s3.poll_ready());
drop(s1);
assert!(s2.is_woken());
assert!(!s3.is_woken());
drop(s2);
assert!(s3.is_woken());
}

5
vendor/tower/tests/limit/main.rs vendored Normal file
View File

@@ -0,0 +1,5 @@
#![cfg(feature = "limit")]
mod concurrency;
mod rate;
#[path = "../support.rs"]
pub(crate) mod support;

71
vendor/tower/tests/limit/rate.rs vendored Normal file
View File

@@ -0,0 +1,71 @@
use super::support;
use std::time::Duration;
use tokio::time;
use tokio_test::{assert_pending, assert_ready, assert_ready_ok};
use tower::limit::rate::RateLimitLayer;
use tower_test::{assert_request_eq, mock};
#[tokio::test(flavor = "current_thread")]
async fn reaching_capacity() {
let _t = support::trace_init();
time::pause();
let rate_limit = RateLimitLayer::new(1, Duration::from_millis(100));
let (mut service, mut handle) = mock::spawn_layer(rate_limit);
assert_ready_ok!(service.poll_ready());
let response = service.call("hello");
assert_request_eq!(handle, "hello").send_response("world");
assert_eq!(response.await.unwrap(), "world");
assert_pending!(service.poll_ready());
assert_pending!(handle.poll_request());
time::advance(Duration::from_millis(101)).await;
assert_ready_ok!(service.poll_ready());
let response = service.call("two");
assert_request_eq!(handle, "two").send_response("done");
assert_eq!(response.await.unwrap(), "done");
}
#[tokio::test(flavor = "current_thread")]
async fn remaining_gets_reset() {
// This test checks for the case where the `until` state gets reset
// but the `rem` does not. This was a bug found `cd7dd12315706fc0860a35646b1eb7b60c50a5c1`.
//
// The main premise here is that we can make one request which should initialize the state
// as ready. Then we can advance the clock to put us beyond the current period. When we make
// subsequent requests the `rem` for the next window is continued from the previous when
// it should be totally reset.
let _t = support::trace_init();
time::pause();
let rate_limit = RateLimitLayer::new(3, Duration::from_millis(100));
let (mut service, mut handle) = mock::spawn_layer(rate_limit);
assert_ready_ok!(service.poll_ready());
let response = service.call("hello");
assert_request_eq!(handle, "hello").send_response("world");
assert_eq!(response.await.unwrap(), "world");
time::advance(Duration::from_millis(100)).await;
assert_ready_ok!(service.poll_ready());
let response = service.call("hello");
assert_request_eq!(handle, "hello").send_response("world");
assert_eq!(response.await.unwrap(), "world");
assert_ready_ok!(service.poll_ready());
let response = service.call("hello");
assert_request_eq!(handle, "hello").send_response("world");
assert_eq!(response.await.unwrap(), "world");
assert_ready_ok!(service.poll_ready());
}

39
vendor/tower/tests/load_shed/main.rs vendored Normal file
View File

@@ -0,0 +1,39 @@
#![cfg(feature = "load-shed")]
#[path = "../support.rs"]
mod support;
use tokio_test::{assert_ready_err, assert_ready_ok, task};
use tower::load_shed::LoadShedLayer;
use tower_test::{assert_request_eq, mock};
#[tokio::test(flavor = "current_thread")]
async fn when_ready() {
let _t = support::trace_init();
let layer = LoadShedLayer::new();
let (mut service, mut handle) = mock::spawn_layer(layer);
assert_ready_ok!(service.poll_ready(), "overload always reports ready");
let mut response = task::spawn(service.call("hello"));
assert_request_eq!(handle, "hello").send_response("world");
assert_eq!(assert_ready_ok!(response.poll()), "world");
}
#[tokio::test(flavor = "current_thread")]
async fn when_not_ready() {
let _t = support::trace_init();
let layer = LoadShedLayer::new();
let (mut service, mut handle) = mock::spawn_layer::<_, (), _>(layer);
handle.allow(0);
assert_ready_ok!(service.poll_ready(), "overload always reports ready");
let mut fut = task::spawn(service.call("hello"));
let err = assert_ready_err!(fut.poll());
assert!(err.is::<tower::load_shed::error::Overloaded>());
}

223
vendor/tower/tests/ready_cache/main.rs vendored Normal file
View File

@@ -0,0 +1,223 @@
#![cfg(feature = "ready-cache")]
#[path = "../support.rs"]
mod support;
use std::pin::Pin;
use tokio_test::{assert_pending, assert_ready, task};
use tower::ready_cache::{error, ReadyCache};
use tower_test::mock;
type Req = &'static str;
type Mock = mock::Mock<Req, Req>;
#[test]
fn poll_ready_inner_failure() {
let _t = support::trace_init();
let mut task = task::spawn(());
let mut cache = ReadyCache::<usize, Mock, Req>::default();
let (service0, mut handle0) = mock::pair::<Req, Req>();
handle0.send_error("doom");
cache.push(0, service0);
let (service1, mut handle1) = mock::pair::<Req, Req>();
handle1.allow(1);
cache.push(1, service1);
let failed = assert_ready!(task.enter(|cx, _| cache.poll_pending(cx))).unwrap_err();
assert_eq!(failed.0, 0);
assert_eq!(format!("{}", failed.1), "doom");
assert_eq!(cache.len(), 1);
}
#[test]
fn poll_ready_not_ready() {
let _t = support::trace_init();
let mut task = task::spawn(());
let mut cache = ReadyCache::<usize, Mock, Req>::default();
let (service0, mut handle0) = mock::pair::<Req, Req>();
handle0.allow(0);
cache.push(0, service0);
let (service1, mut handle1) = mock::pair::<Req, Req>();
handle1.allow(0);
cache.push(1, service1);
assert_pending!(task.enter(|cx, _| cache.poll_pending(cx)));
assert_eq!(cache.ready_len(), 0);
assert_eq!(cache.pending_len(), 2);
assert_eq!(cache.len(), 2);
}
#[test]
fn poll_ready_promotes_inner() {
let _t = support::trace_init();
let mut task = task::spawn(());
let mut cache = ReadyCache::<usize, Mock, Req>::default();
let (service0, mut handle0) = mock::pair::<Req, Req>();
handle0.allow(1);
cache.push(0, service0);
let (service1, mut handle1) = mock::pair::<Req, Req>();
handle1.allow(1);
cache.push(1, service1);
assert_eq!(cache.ready_len(), 0);
assert_eq!(cache.pending_len(), 2);
assert_eq!(cache.len(), 2);
assert_ready!(task.enter(|cx, _| cache.poll_pending(cx))).unwrap();
assert_eq!(cache.ready_len(), 2);
assert_eq!(cache.pending_len(), 0);
assert_eq!(cache.len(), 2);
}
#[test]
fn evict_ready_then_error() {
let _t = support::trace_init();
let mut task = task::spawn(());
let mut cache = ReadyCache::<usize, Mock, Req>::default();
let (service, mut handle) = mock::pair::<Req, Req>();
handle.allow(0);
cache.push(0, service);
assert_pending!(task.enter(|cx, _| cache.poll_pending(cx)));
handle.allow(1);
assert_ready!(task.enter(|cx, _| cache.poll_pending(cx))).unwrap();
handle.send_error("doom");
assert!(cache.evict(&0));
assert_ready!(task.enter(|cx, _| cache.poll_pending(cx))).unwrap();
}
#[test]
fn evict_pending_then_error() {
let _t = support::trace_init();
let mut task = task::spawn(());
let mut cache = ReadyCache::<usize, Mock, Req>::default();
let (service, mut handle) = mock::pair::<Req, Req>();
handle.allow(0);
cache.push(0, service);
assert_pending!(task.enter(|cx, _| cache.poll_pending(cx)));
handle.send_error("doom");
assert!(cache.evict(&0));
assert_ready!(task.enter(|cx, _| cache.poll_pending(cx))).unwrap();
}
#[test]
fn push_then_evict() {
let _t = support::trace_init();
let mut task = task::spawn(());
let mut cache = ReadyCache::<usize, Mock, Req>::default();
let (service, mut handle) = mock::pair::<Req, Req>();
handle.allow(0);
cache.push(0, service);
handle.send_error("doom");
assert!(cache.evict(&0));
assert_ready!(task.enter(|cx, _| cache.poll_pending(cx))).unwrap();
}
#[test]
fn error_after_promote() {
let _t = support::trace_init();
let mut task = task::spawn(());
let mut cache = ReadyCache::<usize, Mock, Req>::default();
let (service, mut handle) = mock::pair::<Req, Req>();
handle.allow(0);
cache.push(0, service);
assert_pending!(task.enter(|cx, _| cache.poll_pending(cx)));
handle.allow(1);
assert_ready!(task.enter(|cx, _| cache.poll_pending(cx))).unwrap();
handle.send_error("doom");
assert_ready!(task.enter(|cx, _| cache.poll_pending(cx))).unwrap();
}
#[test]
fn duplicate_key_by_index() {
let _t = support::trace_init();
let mut task = task::spawn(());
let mut cache = ReadyCache::<usize, Mock, Req>::default();
let (service0, mut handle0) = mock::pair::<Req, Req>();
handle0.allow(1);
cache.push(0, service0);
let (service1, mut handle1) = mock::pair::<Req, Req>();
handle1.allow(1);
// this push should replace the old service (service0)
cache.push(0, service1);
// this evict should evict service1
cache.evict(&0);
// poll_pending should complete (there are no remaining pending services)
assert_ready!(task.enter(|cx, _| cache.poll_pending(cx))).unwrap();
// but service 0 should not be ready (1 replaced, 1 evicted)
assert!(!task.enter(|cx, _| cache.check_ready(cx, &0)).unwrap());
let (service2, mut handle2) = mock::pair::<Req, Req>();
handle2.allow(1);
// this push should ensure replace the evicted service1
cache.push(0, service2);
// there should be no more pending
assert_ready!(task.enter(|cx, _| cache.poll_pending(cx))).unwrap();
// _and_ service 0 should now be callable
assert!(task.enter(|cx, _| cache.check_ready(cx, &0)).unwrap());
}
// Tests https://github.com/tower-rs/tower/issues/415
#[tokio::test(flavor = "current_thread")]
async fn cancelation_observed() {
let mut cache = ReadyCache::default();
let mut handles = vec![];
// NOTE This test passes at 129 items, but fails at 130 items (if coop
// scheduling interferes with cancelation).
for _ in 0..130 {
let (svc, mut handle) = tower_test::mock::pair::<(), ()>();
handle.allow(1);
cache.push("ep0", svc);
handles.push(handle);
}
struct Ready(ReadyCache<&'static str, tower_test::mock::Mock<(), ()>, ()>);
impl Unpin for Ready {}
impl std::future::Future for Ready {
type Output = Result<(), error::Failed<&'static str>>;
fn poll(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> {
self.get_mut().0.poll_pending(cx)
}
}
Ready(cache).await.unwrap();
}

227
vendor/tower/tests/retry/main.rs vendored Normal file
View File

@@ -0,0 +1,227 @@
#![cfg(feature = "retry")]
#[path = "../support.rs"]
mod support;
use std::future;
use tokio_test::{assert_pending, assert_ready_err, assert_ready_ok, task};
use tower::retry::Policy;
use tower_test::{assert_request_eq, mock};
#[tokio::test(flavor = "current_thread")]
async fn retry_errors() {
let _t = support::trace_init();
let (mut service, mut handle) = new_service(RetryErrors);
assert_ready_ok!(service.poll_ready());
let mut fut = task::spawn(service.call("hello"));
assert_request_eq!(handle, "hello").send_error("retry me");
assert_pending!(fut.poll());
assert_request_eq!(handle, "hello").send_response("world");
assert_eq!(fut.into_inner().await.unwrap(), "world");
}
#[tokio::test(flavor = "current_thread")]
async fn retry_limit() {
let _t = support::trace_init();
let (mut service, mut handle) = new_service(Limit(2));
assert_ready_ok!(service.poll_ready());
let mut fut = task::spawn(service.call("hello"));
assert_request_eq!(handle, "hello").send_error("retry 1");
assert_pending!(fut.poll());
assert_request_eq!(handle, "hello").send_error("retry 2");
assert_pending!(fut.poll());
assert_request_eq!(handle, "hello").send_error("retry 3");
assert_eq!(assert_ready_err!(fut.poll()).to_string(), "retry 3");
}
#[tokio::test(flavor = "current_thread")]
async fn retry_error_inspection() {
let _t = support::trace_init();
let (mut service, mut handle) = new_service(UnlessErr("reject"));
assert_ready_ok!(service.poll_ready());
let mut fut = task::spawn(service.call("hello"));
assert_request_eq!(handle, "hello").send_error("retry 1");
assert_pending!(fut.poll());
assert_request_eq!(handle, "hello").send_error("reject");
assert_eq!(assert_ready_err!(fut.poll()).to_string(), "reject");
}
#[tokio::test(flavor = "current_thread")]
async fn retry_cannot_clone_request() {
let _t = support::trace_init();
let (mut service, mut handle) = new_service(CannotClone);
assert_ready_ok!(service.poll_ready());
let mut fut = task::spawn(service.call("hello"));
assert_request_eq!(handle, "hello").send_error("retry 1");
assert_eq!(assert_ready_err!(fut.poll()).to_string(), "retry 1");
}
#[tokio::test(flavor = "current_thread")]
async fn success_with_cannot_clone() {
let _t = support::trace_init();
// Even though the request couldn't be cloned, if the first request succeeds,
// it should succeed overall.
let (mut service, mut handle) = new_service(CannotClone);
assert_ready_ok!(service.poll_ready());
let mut fut = task::spawn(service.call("hello"));
assert_request_eq!(handle, "hello").send_response("world");
assert_ready_ok!(fut.poll(), "world");
}
#[tokio::test(flavor = "current_thread")]
async fn retry_mutating_policy() {
let _t = support::trace_init();
let (mut service, mut handle) = new_service(MutatingPolicy { remaining: 2 });
assert_ready_ok!(service.poll_ready());
let mut fut = task::spawn(service.call("hello"));
assert_request_eq!(handle, "hello").send_response("world");
assert_pending!(fut.poll());
// the policy alters the request. in real life, this might be setting a header
assert_request_eq!(handle, "retrying").send_response("world");
assert_pending!(fut.poll());
assert_request_eq!(handle, "retrying").send_response("world");
assert_ready_err!(fut.poll(), "out of retries");
}
type Req = &'static str;
type Res = &'static str;
type InnerError = &'static str;
type Error = Box<dyn std::error::Error + Send + Sync>;
type Mock = mock::Mock<Req, Res>;
type Handle = mock::Handle<Req, Res>;
#[derive(Clone)]
struct RetryErrors;
impl Policy<Req, Res, Error> for RetryErrors {
type Future = future::Ready<()>;
fn retry(&mut self, _: &mut Req, result: &mut Result<Res, Error>) -> Option<Self::Future> {
if result.is_err() {
Some(future::ready(()))
} else {
None
}
}
fn clone_request(&mut self, req: &Req) -> Option<Req> {
Some(*req)
}
}
#[derive(Clone)]
struct Limit(usize);
impl Policy<Req, Res, Error> for Limit {
type Future = future::Ready<()>;
fn retry(&mut self, _: &mut Req, result: &mut Result<Res, Error>) -> Option<Self::Future> {
if result.is_err() && self.0 > 0 {
self.0 -= 1;
Some(future::ready(()))
} else {
None
}
}
fn clone_request(&mut self, req: &Req) -> Option<Req> {
Some(*req)
}
}
#[derive(Clone)]
struct UnlessErr(InnerError);
impl Policy<Req, Res, Error> for UnlessErr {
type Future = future::Ready<()>;
fn retry(&mut self, _: &mut Req, result: &mut Result<Res, Error>) -> Option<Self::Future> {
result.as_ref().err().and_then(|err| {
if err.to_string() != self.0 {
Some(future::ready(()))
} else {
None
}
})
}
fn clone_request(&mut self, req: &Req) -> Option<Req> {
Some(*req)
}
}
#[derive(Clone)]
struct CannotClone;
impl Policy<Req, Res, Error> for CannotClone {
type Future = future::Ready<()>;
fn retry(&mut self, _: &mut Req, _: &mut Result<Res, Error>) -> Option<Self::Future> {
unreachable!("retry cannot be called since request isn't cloned");
}
fn clone_request(&mut self, _req: &Req) -> Option<Req> {
None
}
}
/// Test policy that changes the request to `retrying` during retries and the result to `"out of retries"`
/// when retries are exhausted.
#[derive(Clone)]
struct MutatingPolicy {
remaining: usize,
}
impl Policy<Req, Res, Error> for MutatingPolicy
where
Error: From<&'static str>,
{
type Future = future::Ready<()>;
fn retry(&mut self, req: &mut Req, result: &mut Result<Res, Error>) -> Option<Self::Future> {
if self.remaining == 0 {
*result = Err("out of retries".into());
None
} else {
*req = "retrying";
self.remaining -= 1;
Some(future::ready(()))
}
}
fn clone_request(&mut self, req: &Req) -> Option<Req> {
Some(*req)
}
}
fn new_service<P: Policy<Req, Res, Error> + Clone>(
policy: P,
) -> (mock::Spawn<tower::retry::Retry<P, Mock>>, Handle) {
let retry = tower::retry::RetryLayer::new(policy);
mock::spawn_layer(retry)
}

86
vendor/tower/tests/spawn_ready/main.rs vendored Normal file
View File

@@ -0,0 +1,86 @@
#![cfg(feature = "spawn-ready")]
#[path = "../support.rs"]
mod support;
use tokio::time;
use tokio_test::{assert_pending, assert_ready, assert_ready_err, assert_ready_ok};
use tower::spawn_ready::{SpawnReady, SpawnReadyLayer};
use tower::util::ServiceExt;
use tower_test::mock;
#[tokio::test(flavor = "current_thread")]
async fn when_inner_is_not_ready() {
time::pause();
let _t = support::trace_init();
let layer = SpawnReadyLayer::new();
let (mut service, mut handle) = mock::spawn_layer::<(), (), _>(layer);
// Make the service NotReady
handle.allow(0);
assert_pending!(service.poll_ready());
// Make the service is Ready
handle.allow(1);
time::sleep(time::Duration::from_millis(100)).await;
assert_ready_ok!(service.poll_ready());
}
#[tokio::test(flavor = "current_thread")]
async fn when_inner_fails() {
let _t = support::trace_init();
let layer = SpawnReadyLayer::new();
let (mut service, mut handle) = mock::spawn_layer::<(), (), _>(layer);
// Make the service NotReady
handle.allow(0);
handle.send_error("foobar");
assert_eq!(
assert_ready_err!(service.poll_ready()).to_string(),
"foobar"
);
}
#[tokio::test(flavor = "current_thread")]
async fn propagates_trace_spans() {
use tracing::Instrument;
let _t = support::trace_init();
let span = tracing::info_span!("my_span");
let service = support::AssertSpanSvc::new(span.clone());
let service = SpawnReady::new(service);
let result = tokio::spawn(service.oneshot(()).instrument(span));
result.await.expect("service panicked").expect("failed");
}
#[cfg(test)]
#[tokio::test(flavor = "current_thread")]
async fn abort_on_drop() {
let (mock, mut handle) = mock::pair::<(), ()>();
let mut svc = SpawnReady::new(mock);
handle.allow(0);
// Drive the service to readiness until we signal a drop.
let (drop_tx, drop_rx) = tokio::sync::oneshot::channel();
let mut task = tokio_test::task::spawn(async move {
tokio::select! {
_ = drop_rx => {}
_ = svc.ready() => unreachable!("Service must not become ready"),
}
});
assert_pending!(task.poll());
assert_pending!(handle.poll_request());
// End the task and ensure that the inner service has been dropped.
assert!(drop_tx.send(()).is_ok());
tokio_test::assert_ready!(task.poll());
tokio::task::yield_now().await;
assert!(tokio_test::assert_ready!(handle.poll_request()).is_none());
}

59
vendor/tower/tests/steer/main.rs vendored Normal file
View File

@@ -0,0 +1,59 @@
#![cfg(feature = "steer")]
#[path = "../support.rs"]
mod support;
use std::{
future::{ready, Ready},
task::{Context, Poll},
};
use tower::steer::Steer;
use tower_service::Service;
type StdError = Box<dyn std::error::Error + Send + Sync + 'static>;
struct MyService(u8, bool);
impl Service<String> for MyService {
type Response = u8;
type Error = StdError;
type Future = Ready<Result<u8, Self::Error>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
if !self.1 {
Poll::Pending
} else {
Poll::Ready(Ok(()))
}
}
fn call(&mut self, _req: String) -> Self::Future {
ready(Ok(self.0))
}
}
#[tokio::test(flavor = "current_thread")]
async fn pick_correctly() {
let _t = support::trace_init();
let srvs = vec![MyService(42, true), MyService(57, true)];
let mut st = Steer::new(srvs, |_: &_, _: &[_]| 1);
std::future::poll_fn(|cx| st.poll_ready(cx)).await.unwrap();
let r = st.call(String::from("foo")).await.unwrap();
assert_eq!(r, 57);
}
#[tokio::test(flavor = "current_thread")]
async fn pending_all_ready() {
let _t = support::trace_init();
let srvs = vec![MyService(42, true), MyService(57, false)];
let mut st = Steer::new(srvs, |_: &_, _: &[_]| 0);
let p = futures_util::poll!(std::future::poll_fn(|cx| st.poll_ready(cx)));
match p {
Poll::Pending => (),
_ => panic!(
"Steer should not return poll_ready if at least one component service is not ready"
),
}
}

79
vendor/tower/tests/support.rs vendored Normal file
View File

@@ -0,0 +1,79 @@
#![allow(dead_code)]
use std::fmt;
use std::future;
use std::task::{Context, Poll};
use tower::Service;
pub(crate) fn trace_init() -> tracing::subscriber::DefaultGuard {
let subscriber = tracing_subscriber::fmt()
.with_test_writer()
.with_max_level(tracing::Level::TRACE)
.with_thread_names(true)
.finish();
tracing::subscriber::set_default(subscriber)
}
#[derive(Clone, Debug)]
pub struct AssertSpanSvc {
span: tracing::Span,
polled: bool,
}
pub struct AssertSpanError(String);
impl fmt::Debug for AssertSpanError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl fmt::Display for AssertSpanError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl std::error::Error for AssertSpanError {}
impl AssertSpanSvc {
pub fn new(span: tracing::Span) -> Self {
Self {
span,
polled: false,
}
}
fn check(&self, func: &str) -> Result<(), AssertSpanError> {
let current_span = tracing::Span::current();
tracing::debug!(?current_span, ?self.span, %func);
if current_span == self.span {
return Ok(());
}
Err(AssertSpanError(format!(
"{} called outside expected span\n expected: {:?}\n current: {:?}",
func, self.span, current_span
)))
}
}
impl Service<()> for AssertSpanSvc {
type Response = ();
type Error = AssertSpanError;
type Future = future::Ready<Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
if self.polled {
return Poll::Ready(self.check("poll_ready"));
}
cx.waker().wake_by_ref();
self.polled = true;
Poll::Pending
}
fn call(&mut self, _: ()) -> Self::Future {
future::ready(self.check("call"))
}
}

251
vendor/tower/tests/util/call_all.rs vendored Normal file
View File

@@ -0,0 +1,251 @@
use super::support;
use futures_core::Stream;
use futures_util::pin_mut;
use std::fmt;
use std::future::{ready, Future, Ready};
use std::task::{Context, Poll};
use std::{cell::Cell, rc::Rc};
use tokio_stream::wrappers::UnboundedReceiverStream;
use tokio_test::{assert_pending, assert_ready, task};
use tower::util::ServiceExt;
use tower_service::*;
use tower_test::{assert_request_eq, mock, mock::Mock};
type Error = Box<dyn std::error::Error + Send + Sync + 'static>;
#[derive(Debug, Eq, PartialEq)]
struct Srv {
admit: Rc<Cell<bool>>,
count: Rc<Cell<usize>>,
}
impl Service<&'static str> for Srv {
type Response = &'static str;
type Error = Error;
type Future = Ready<Result<Self::Response, Error>>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
if !self.admit.get() {
return Poll::Pending;
}
self.admit.set(false);
Poll::Ready(Ok(()))
}
fn call(&mut self, req: &'static str) -> Self::Future {
self.count.set(self.count.get() + 1);
ready(Ok(req))
}
}
#[test]
fn ordered() {
let _t = support::trace_init();
let mut mock = task::spawn(());
let admit = Rc::new(Cell::new(false));
let count = Rc::new(Cell::new(0));
let srv = Srv {
count: count.clone(),
admit: admit.clone(),
};
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
let ca = srv.call_all(UnboundedReceiverStream::new(rx));
pin_mut!(ca);
assert_pending!(mock.enter(|cx, _| ca.as_mut().poll_next(cx)));
tx.send("one").unwrap();
mock.is_woken();
assert_pending!(mock.enter(|cx, _| ca.as_mut().poll_next(cx)));
admit.set(true);
let v = assert_ready!(mock.enter(|cx, _| ca.as_mut().poll_next(cx)))
.transpose()
.unwrap();
assert_eq!(v, Some("one"));
assert_pending!(mock.enter(|cx, _| ca.as_mut().poll_next(cx)));
admit.set(true);
tx.send("two").unwrap();
mock.is_woken();
tx.send("three").unwrap();
let v = assert_ready!(mock.enter(|cx, _| ca.as_mut().poll_next(cx)))
.transpose()
.unwrap();
assert_eq!(v, Some("two"));
assert_pending!(mock.enter(|cx, _| ca.as_mut().poll_next(cx)));
admit.set(true);
let v = assert_ready!(mock.enter(|cx, _| ca.as_mut().poll_next(cx)))
.transpose()
.unwrap();
assert_eq!(v, Some("three"));
admit.set(true);
assert_pending!(mock.enter(|cx, _| ca.as_mut().poll_next(cx)));
admit.set(true);
tx.send("four").unwrap();
mock.is_woken();
let v = assert_ready!(mock.enter(|cx, _| ca.as_mut().poll_next(cx)))
.transpose()
.unwrap();
assert_eq!(v, Some("four"));
assert_pending!(mock.enter(|cx, _| ca.as_mut().poll_next(cx)));
// need to be ready since impl doesn't know it'll get EOF
admit.set(true);
// When we drop the request stream, CallAll should return None.
drop(tx);
mock.is_woken();
let v = assert_ready!(mock.enter(|cx, _| ca.as_mut().poll_next(cx)))
.transpose()
.unwrap();
assert!(v.is_none());
assert_eq!(count.get(), 4);
// We should also be able to recover the wrapped Service.
assert_eq!(ca.take_service(), Srv { count, admit });
}
#[tokio::test(flavor = "current_thread")]
async fn unordered() {
let _t = support::trace_init();
let (mock, handle) = mock::pair::<_, &'static str>();
pin_mut!(handle);
let mut task = task::spawn(());
let requests = futures_util::stream::iter(&["one", "two"]);
let svc = mock.call_all(requests).unordered();
pin_mut!(svc);
assert_pending!(task.enter(|cx, _| svc.as_mut().poll_next(cx)));
let resp1 = assert_request_eq!(handle, &"one");
let resp2 = assert_request_eq!(handle, &"two");
resp2.send_response("resp 1");
let v = assert_ready!(task.enter(|cx, _| svc.as_mut().poll_next(cx)))
.transpose()
.unwrap();
assert_eq!(v, Some("resp 1"));
assert_pending!(task.enter(|cx, _| svc.as_mut().poll_next(cx)));
resp1.send_response("resp 2");
let v = assert_ready!(task.enter(|cx, _| svc.as_mut().poll_next(cx)))
.transpose()
.unwrap();
assert_eq!(v, Some("resp 2"));
let v = assert_ready!(task.enter(|cx, _| svc.as_mut().poll_next(cx)))
.transpose()
.unwrap();
assert!(v.is_none());
}
#[tokio::test]
async fn pending() {
let _t = support::trace_init();
let (mock, mut handle) = mock::pair::<_, &'static str>();
let mut task = task::spawn(());
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
let ca = mock.call_all(UnboundedReceiverStream::new(rx));
pin_mut!(ca);
assert_pending!(task.enter(|cx, _| ca.as_mut().poll_next(cx)));
tx.send("req").unwrap();
assert_pending!(task.enter(|cx, _| ca.as_mut().poll_next(cx)));
assert_request_eq!(handle, "req").send_response("res");
let res = assert_ready!(task.enter(|cx, _| ca.as_mut().poll_next(cx)));
assert_eq!(res.transpose().unwrap(), Some("res"));
assert_pending!(task.enter(|cx, _| ca.as_mut().poll_next(cx)));
}
#[tokio::test]
async fn poll_ready_error() {
struct ReadyOnceThenErr {
polled: bool,
inner: Mock<&'static str, &'static str>,
}
#[derive(Debug)]
pub struct StringErr(String);
impl fmt::Display for StringErr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl std::error::Error for StringErr {}
impl Service<&'static str> for ReadyOnceThenErr {
type Response = &'static str;
type Error = Error;
type Future = <Mock<&'static str, &'static str> as Service<&'static str>>::Future;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
match self.polled {
false => {
self.polled = true;
self.inner.poll_ready(cx)
}
true => Poll::Ready(Err(Box::new(StringErr("poll_ready error".to_string())))),
}
}
fn call(&mut self, req: &'static str) -> Self::Future {
self.inner.call(req)
}
}
let _t = support::trace_init();
let (mock, mut handle) = mock::pair::<_, &'static str>();
let svc = ReadyOnceThenErr {
polled: false,
inner: mock,
};
let mut task = task::spawn(());
// "req0" is called, then "req1" receives a poll_ready error so "req2" will never be called.
// Still the response from "req0" is waited on before ending the `call_all` stream.
let requests = futures_util::stream::iter(vec!["req0", "req1", "req2"]);
let ca = svc.call_all(requests);
pin_mut!(ca);
let err = assert_ready!(task.enter(|cx, _| ca.as_mut().poll_next(cx)));
assert_eq!(err.unwrap().unwrap_err().to_string(), "poll_ready error");
assert_request_eq!(handle, "req0").send_response("res0");
let res = assert_ready!(task.enter(|cx, _| ca.as_mut().poll_next(cx)));
assert_eq!(res.transpose().unwrap(), Some("res0"));
let res = assert_ready!(task.enter(|cx, _| ca.as_mut().poll_next(cx)));
assert_eq!(res.transpose().unwrap(), None);
}
#[tokio::test]
async fn stream_does_not_block_service() {
use tower::buffer::Buffer;
use tower::limit::ConcurrencyLimit;
let _t = support::trace_init();
let (mock, mut handle) = mock::pair::<_, &'static str>();
let mut task = task::spawn(());
let svc = Buffer::new(ConcurrencyLimit::new(mock, 1), 1);
// Always pending, but should not occupy a concurrency slot.
let pending = svc.clone().call_all(futures_util::stream::pending());
pin_mut!(pending);
assert_pending!(task.enter(|cx, _| pending.as_mut().poll_next(cx)));
let call = svc.oneshot("req");
pin_mut!(call);
assert_pending!(task.enter(|cx, _| call.as_mut().poll(cx)));
assert_request_eq!(handle, "req").send_response("res");
let res = assert_ready!(task.enter(|cx, _| call.as_mut().poll(cx)));
assert_eq!(res.unwrap(), "res");
}

8
vendor/tower/tests/util/main.rs vendored Normal file
View File

@@ -0,0 +1,8 @@
#![cfg(feature = "util")]
#![allow(clippy::type_complexity)]
mod call_all;
mod oneshot;
mod service_fn;
#[path = "../support.rs"]
pub(crate) mod support;

40
vendor/tower/tests/util/oneshot.rs vendored Normal file
View File

@@ -0,0 +1,40 @@
use std::task::{Context, Poll};
use std::{future::Future, pin::Pin};
use tower::util::ServiceExt;
use tower_service::Service;
#[tokio::test(flavor = "current_thread")]
async fn service_driven_to_readiness() {
// This test ensures that `oneshot` will repeatedly call `poll_ready` until
// the service is ready.
let _t = super::support::trace_init();
struct PollMeTwice {
ready: bool,
}
impl Service<()> for PollMeTwice {
type Error = ();
type Response = ();
type Future = Pin<
Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + Sync + 'static>,
>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), ()>> {
if self.ready {
Poll::Ready(Ok(()))
} else {
self.ready = true;
cx.waker().wake_by_ref();
Poll::Pending
}
}
fn call(&mut self, _: ()) -> Self::Future {
assert!(self.ready, "service not driven to readiness!");
Box::pin(async { Ok(()) })
}
}
let svc = PollMeTwice { ready: false };
svc.oneshot(()).await.unwrap();
}

12
vendor/tower/tests/util/service_fn.rs vendored Normal file
View File

@@ -0,0 +1,12 @@
use std::future::ready;
use tower::util::service_fn;
use tower_service::Service;
#[tokio::test(flavor = "current_thread")]
async fn simple() {
let _t = super::support::trace_init();
let mut add_one = service_fn(|req| ready(Ok::<_, ()>(req + 1)));
let answer = add_one.call(1).await.unwrap();
assert_eq!(answer, 2);
}