Skip to content

Commit 95dee9e

Browse files
committed
test: split tap middleware tests
Signed-off-by: Gustavo Inacio <[email protected]>
1 parent 77aaa77 commit 95dee9e

File tree

5 files changed

+134
-45
lines changed

5 files changed

+134
-45
lines changed

Cargo.lock

Lines changed: 38 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,4 @@ thegraph-core = { git = "https://github.com/edgeandnode/toolshed", rev = "166353
7171
thegraph-graphql-http = "0.2.0"
7272
graphql_client = { version = "0.14.0", features = ["reqwest-rustls"] }
7373
bip39 = "2.0.0"
74+
rstest = "0.23.0"

crates/service/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ pin-project = "1.1.7"
5959
[dev-dependencies]
6060
hex-literal = "0.4.1"
6161
test-assets = { path = "../test-assets" }
62+
rstest.workspace = true
6263
tower-test = "0.4.0"
64+
tower-service = "0.3.3"
6365
tokio-test = "0.4.4"
6466

6567
[build-dependencies]

crates/service/src/middleware/auth/tap.rs

Lines changed: 93 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ where
5252
async {
5353
let execute = || async {
5454
let receipt = receipt.ok_or(IndexerServiceError::ReceiptNotFound)?;
55-
5655
// Verify the receipt and store it in the database
5756
tap_manager
5857
.verify_and_store_receipt(&ctx.unwrap_or_default(), receipt)
@@ -73,7 +72,12 @@ where
7372

7473
#[cfg(test)]
7574
mod tests {
75+
76+
use core::panic;
77+
use rstest::*;
7678
use std::{sync::Arc, time::Duration};
79+
use tokio::time::sleep;
80+
use tower::{Service, ServiceBuilder, ServiceExt};
7781

7882
use alloy::primitives::{address, Address};
7983
use axum::{
@@ -92,7 +96,6 @@ mod tests {
9296
},
9397
};
9498
use test_assets::{create_signed_receipt, TAP_EIP712_DOMAIN};
95-
use tower::{Service, ServiceBuilder, ServiceExt};
9699
use tower_http::auth::AsyncRequireAuthorizationLayer;
97100

98101
use crate::{
@@ -105,20 +108,28 @@ mod tests {
105108

106109
const ALLOCATION_ID: Address = address!("deadbeefcafebabedeadbeefcafebabedeadbeef");
107110

108-
async fn handle(_: Request<Body>) -> anyhow::Result<Response<Body>> {
109-
Ok(Response::new(Body::default()))
111+
#[fixture]
112+
fn metric() -> &'static prometheus::CounterVec {
113+
let registry = prometheus::Registry::new();
114+
let metric = Box::leak(Box::new(
115+
prometheus::register_counter_vec_with_registry!(
116+
"tap_middleware_test",
117+
"Failed queries to handler",
118+
&["deployment"],
119+
registry,
120+
)
121+
.unwrap(),
122+
));
123+
metric
110124
}
111125

112-
struct TestLabel;
113-
impl MetricLabelProvider for TestLabel {
114-
fn get_labels(&self) -> Vec<&str> {
115-
vec!["label1"]
116-
}
117-
}
126+
const FAILED_NONCE: u64 = 99;
118127

119-
#[sqlx::test(migrations = "../../migrations")]
120-
async fn test_tap_middleware(pgpool: PgPool) {
121-
let context = IndexerTapContext::new(pgpool.clone(), TAP_EIP712_DOMAIN.clone()).await;
128+
async fn service(
129+
metric: &'static prometheus::CounterVec,
130+
pgpool: PgPool,
131+
) -> impl Service<Request<Body>, Response = Response<Body>, Error = impl std::fmt::Debug> {
132+
let context = IndexerTapContext::new(pgpool, TAP_EIP712_DOMAIN.clone()).await;
122133

123134
struct MyCheck;
124135
#[async_trait::async_trait]
@@ -128,77 +139,115 @@ mod tests {
128139
_: &tap_core::receipt::Context,
129140
receipt: &ReceiptWithState<Checking>,
130141
) -> CheckResult {
131-
if receipt.signed_receipt().message.nonce == 99 {
142+
if receipt.signed_receipt().message.nonce == FAILED_NONCE {
132143
Err(CheckError::Failed(anyhow::anyhow!("Failed")))
133144
} else {
134145
Ok(())
135146
}
136147
}
137148
}
138149

139-
let tap_manager = Box::leak(Box::new(Manager::new(
150+
let manager = Box::leak(Box::new(Manager::new(
140151
TAP_EIP712_DOMAIN.clone(),
141152
context,
142153
CheckList::new(vec![Arc::new(MyCheck)]),
143154
)));
144-
let metric = Box::leak(Box::new(
145-
prometheus::register_counter_vec!(
146-
"tap_middleware_test",
147-
"Failed queries to handler",
148-
&["deployment"]
149-
)
150-
.unwrap(),
151-
));
152-
153-
let tap_auth = tap_receipt_authorize(tap_manager, metric);
154-
155+
let tap_auth = tap_receipt_authorize(manager, metric);
155156
let authorization_middleware = AsyncRequireAuthorizationLayer::new(tap_auth);
156157

157158
let mut service = ServiceBuilder::new()
158159
.layer(authorization_middleware)
159-
.service_fn(handle);
160+
.service_fn(|_: Request<Body>| async {
161+
Ok::<_, anyhow::Error>(Response::new(Body::default()))
162+
});
160163

161-
let handle = service.ready().await.unwrap();
164+
service.ready().await.unwrap();
165+
service
166+
}
167+
168+
#[rstest]
169+
#[sqlx::test(migrations = "../../migrations")]
170+
async fn test_tap_valid_receipt(
171+
metric: &'static prometheus::CounterVec,
172+
#[ignore] pgpool: PgPool,
173+
) {
174+
let mut service = service(metric, pgpool.clone()).await;
162175

163176
let receipt = create_signed_receipt(ALLOCATION_ID, 1, 1, 1).await;
164177

165178
// check with receipt
166-
let mut req = Request::new(Default::default());
179+
let mut req = Request::new(Body::default());
167180
req.extensions_mut().insert(receipt);
168-
let res = handle.call(req).await.unwrap();
181+
let res = service.call(req).await.unwrap();
169182
assert_eq!(res.status(), StatusCode::OK);
170183

171-
// todo make this sleep better
172-
tokio::time::sleep(Duration::from_millis(100)).await;
173-
174184
// verify receipts
175-
let result = sqlx::query!("SELECT * FROM scalar_tap_receipts")
176-
.fetch_all(&pgpool)
177-
.await
178-
.unwrap();
179-
assert_eq!(result.len(), 1);
185+
if tokio::time::timeout(Duration::from_secs(1), async {
186+
loop {
187+
let result = sqlx::query!("SELECT * FROM scalar_tap_receipts")
188+
.fetch_all(&pgpool)
189+
.await
190+
.unwrap();
191+
192+
if result.is_empty() {
193+
sleep(Duration::from_millis(50)).await;
194+
} else {
195+
break;
196+
}
197+
}
198+
})
199+
.await
200+
.is_err()
201+
{
202+
panic!("Timeout assertion");
203+
}
204+
}
205+
206+
#[rstest]
207+
#[sqlx::test(migrations = "../../migrations")]
208+
async fn test_invalid_receipt_with_failed_metric(
209+
metric: &'static prometheus::CounterVec,
210+
#[ignore] pgpool: PgPool,
211+
) {
212+
let mut service = service(metric, pgpool.clone()).await;
180213
// if it fails tap receipt, should return failed to process payment + tap message
181214

182215
assert_eq!(metric.collect().first().unwrap().get_metric().len(), 0);
183216

217+
struct TestLabel;
218+
impl MetricLabelProvider for TestLabel {
219+
fn get_labels(&self) -> Vec<&str> {
220+
vec!["label1"]
221+
}
222+
}
223+
184224
// default labels, all empty
185225
let labels: MetricLabels = Arc::new(TestLabel);
186226

187227
let mut receipt = create_signed_receipt(ALLOCATION_ID, 1, 1, 1).await;
188228
// change the nonce to make the receipt invalid
189-
receipt.message.nonce = 99;
190-
let mut req = Request::new(Default::default());
229+
receipt.message.nonce = FAILED_NONCE;
230+
let mut req = Request::new(Body::default());
191231
req.extensions_mut().insert(receipt);
192232
req.extensions_mut().insert(labels);
193-
let res = handle.call(req).await.unwrap();
194-
assert_eq!(res.status(), StatusCode::BAD_REQUEST);
233+
let response = service.call(req);
234+
235+
assert_eq!(response.await.unwrap().status(), StatusCode::BAD_REQUEST);
195236

196237
assert_eq!(metric.collect().first().unwrap().get_metric().len(), 1);
238+
}
197239

240+
#[rstest]
241+
#[sqlx::test(migrations = "../../migrations")]
242+
async fn test_tap_missing_signed_receipt(
243+
metric: &'static prometheus::CounterVec,
244+
#[ignore] pgpool: PgPool,
245+
) {
246+
let mut service = service(metric, pgpool.clone()).await;
198247
// if it doesnt contain the signed receipt
199248
// should return payment required
200-
let req = Request::new(Default::default());
201-
let res = handle.call(req).await.unwrap();
249+
let req = Request::new(Body::default());
250+
let res = service.call(req).await.unwrap();
202251
assert_eq!(res.status(), StatusCode::PAYMENT_REQUIRED);
203252
}
204253
}

crates/service/src/middleware/inject_context.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ mod tests {
116116
Request::builder()
117117
.uri("/")
118118
.extension(deployment)
119-
.extension(deployment)
120119
.body(body)
121120
.unwrap(),
122121
)

0 commit comments

Comments
 (0)