diff --git a/.env b/.env
index b9fe4ea..7c2fa16 100644
--- a/.env
+++ b/.env
@@ -1,2 +1,4 @@
PROXY_ADDRESS="http://localhost:3000"
TARGET_URL="https://gist.githubusercontent.com/mattes/23e64faadb5fd4b5112f379903d2572e/raw/ddbf0a56001367467f71bda64347aa881d83533c/example.json"
+PROXY_PORT="3000"
+RUST_LOG="debug"
diff --git a/Cargo.toml b/Cargo.toml
index 1f917e5..3cfc38f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,35 @@
+[package]
+name = "web-proof-tee"
+version = "0.1.0"
+edition = "2021"
+
+[dev-dependencies]
+tokio = { version = "1.0", features = ["full", "test-util"] }
+anyhow = "1.0"
+reqwest = { version = "0.11", features = ["json"] }
+serde_json = "1.0"
+once_cell = "1.19"
+rstest = "0.18"
+tracing = "0.1"
+tracing-subscriber = { version = "0.3", features = ["env-filter"] }
+
[workspace]
resolver = "2"
members = [
"client",
"proxy"
]
+
+# Define workspace-wide dependency versions
+[workspace.dependencies]
+tokio = { version = "1.0", features = ["full"] }
+anyhow = "1.0"
+reqwest = { version = "0.11", features = ["json"] }
+serde_json = "1.0"
+once_cell = "1.19"
+tracing = "0.1"
+tracing-subscriber = { version = "0.3", features = ["env-filter"] }
+
+[[test]]
+name = "integration_tests"
+path = "tests/tests.rs"
diff --git a/README.md b/README.md
index 8761250..a49367a 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,10 @@
web proofs by TEE
+## demo of client-proxy tee flow
+Runs a proxied GET to an [arbitrary](https://gist.githubusercontent.com/mattes/23e64faadb5fd4b5112f379903d2572e/raw/ddbf0a56001367467f71bda64347aa881d83533c/example.json) gist json file.
+
+See `.justfile` for commands, e.g. `just test`.
## License
Licensed under your option of either:
diff --git a/client/Cargo.toml b/client/Cargo.toml
index 8276576..dbdfd07 100644
--- a/client/Cargo.toml
+++ b/client/Cargo.toml
@@ -3,7 +3,7 @@ authors = ["Pluto developers "]
description = """TEE client"""
edition = "2021"
license = "Apache2.0 OR MIT"
-name = "web-proof-tee-client"
+name = "client"
repository = "https://github.com/pluto/web-proof-tee"
version = "0.1.0"
diff --git a/client/src/main.rs b/client/src/main.rs
index 1c0e444..75fbf13 100644
--- a/client/src/main.rs
+++ b/client/src/main.rs
@@ -10,14 +10,9 @@ use std::env;
use anyhow::{Context, Result};
use dotenv::dotenv;
-use serde::Deserialize;
+use serde_json::Value;
use tracing::{debug, error, info, warn};
-#[derive(Clone, Debug, Deserialize)]
-struct Response {
- _hello: String,
-}
-
#[tokio::main]
async fn main() -> Result<()> {
dotenv().ok();
@@ -64,7 +59,7 @@ async fn main() -> Result<()> {
anyhow::bail!("Request failed with status {}: {}", status, text);
}
- let data: Response = response.json().await.context("Failed to parse response as JSON")?;
+ let data: Value = response.json().await.context("Failed to parse response as JSON")?;
info!(
response = ?data,
"Successfully received and parsed response"
diff --git a/proxy/src/main.rs b/proxy/src/main.rs
index 73a6c43..ec6b3e2 100644
--- a/proxy/src/main.rs
+++ b/proxy/src/main.rs
@@ -109,8 +109,7 @@ async fn forward_request(target_url: &str) -> Result {
let status = StatusCode::from_u16(response.status().as_u16())?;
let body: Value = response.json().await?;
-
- debug!(status = ?status, "Received response from target");
+ debug!("Parsed response body: {:?}", body);
Ok((status, Json(body)))
}
diff --git a/proxy/src/xclip b/proxy/src/xclip
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/tests.rs b/tests/tests.rs
index a1accc0..be8067d 100644
--- a/tests/tests.rs
+++ b/tests/tests.rs
@@ -1,66 +1,119 @@
+//! Integration tests
#![allow(unused_imports)]
#![allow(unused_variables)]
#![allow(dead_code)]
#![allow(unreachable_code)]
#![allow(non_snake_case)]
#![allow(clippy::clone_on_copy)]
-//! Integration tests
-use tracing::Level;
-use tracing_subscriber::FmtSubscriber;
-
-static INIT: std::sync::Once = std::sync::Once::new();
-fn setup_test_tracing() {
- INIT.call_once(|| {
- let subscriber =
- FmtSubscriber::builder().with_max_level(Level::INFO).with_test_writer().finish();
- tracing::subscriber::set_global_default(subscriber)
- .expect("setting default subscriber failed");
- });
+use std::time::Duration;
+
+use anyhow::Result;
+use once_cell::sync::Lazy;
+use rstest::*;
+use tokio::time::sleep;
+use tracing::{debug, error, info, instrument, warn};
+use tracing_subscriber::fmt::format::FmtSpan;
+
+static TEST_PORT: Lazy = Lazy::new(|| "3333".to_string());
+static TEST_SERVER: Lazy = Lazy::new(|| format!("http://localhost:{}", *TEST_PORT));
+
+/// Helper struct to manage server lifecycle
+#[derive(Debug)]
+struct TestServer {
+ handle: tokio::process::Child,
}
-use arbitrary::Arbitrary;
-use rstest::{fixture, rstest};
-// rstest provides features to take common context into tests, and set up small cases testing
-#[derive(Clone, Debug, Eq, PartialEq, Arbitrary)]
-struct Wb {
- b: bool,
- count: usize,
+
+impl Drop for TestServer {
+ fn drop(&mut self) { let _ = self.handle.start_kill(); }
}
-// context setup function to be implicitly called by `wb`
-#[fixture]
-fn count() -> usize { return 0usize; }
-// context setup function to be implicitly called by `test_wb`
-#[fixture]
-fn wb(#[default(false)] b: bool, count: usize) -> Wb {
- setup_test_tracing();
- Wb { b, count }
+
+impl TestServer {
+ async fn start() -> Result {
+ info!("Starting test server on port {}", *TEST_PORT);
+ let handle = tokio::process::Command::new("cargo")
+ .args(["run", "-p", "proxy", "--"])
+ .env("PROXY_PORT", &*TEST_PORT) // Changed from PORT to PROXY_PORT
+ .env("RUST_LOG", "debug")
+ .kill_on_drop(true)
+ .spawn()?;
+
+ // Wait longer for server startup
+ info!("Waiting for server to start up");
+ sleep(Duration::from_secs(2)).await; // Increased from 5ms to 2s
+
+ // Verify server is running by attempting to connect
+ let client = reqwest::Client::new();
+ let max_retries = 5;
+ for i in 0..max_retries {
+ match client.get(&*TEST_SERVER).send().await {
+ Ok(_) => {
+ info!("Server is ready!");
+ break;
+ },
+ Err(e) => {
+ if i == max_retries - 1 {
+ error!("Server failed to start after {} retries: {}", max_retries, e);
+ return Err(anyhow::anyhow!("Server failed to start"));
+ }
+ warn!("Server not ready, retrying in 1s...");
+ sleep(Duration::from_secs(1)).await;
+ },
+ }
+ }
+
+ Ok(Self { handle })
+ }
+
+ #[instrument]
+ async fn stop(mut self) -> Result<()> {
+ info!("Stopping test server");
+ self.handle.kill().await?;
+ Ok(())
+ }
}
-// small-cases fuzzing
-// argument wb will inherit the above function if names match; will generate 3x3 case-tests
-#[rstest]
-#[case(0, true, true)]
-#[case(1, true, false)]
-fn test_wb(wb: Wb, #[case] n: usize, #[case] b: bool, #[case] expected: bool) {
- tracing::info!("wb: {wb:?}");
- let wb_ = Wb { count: n, b };
- assert_eq!(wb == wb_, expected); // this will fail for case_1 cases
+/// Test fixture for managing server and client setup
+#[derive(Debug)]
+struct TestContext {
+ server: TestServer,
+ client: reqwest::Client,
}
-// ex 2 - baby fuzz; will generate 2x2 test cases
-#[rstest]
-fn test_enumerative(#[values(0, 4)] n: usize, #[values(7, 8)] m: usize) {
- assert!(n < m);
+/// Initialize tracing for tests
+fn init_tracing() {
+ let _ = tracing_subscriber::fmt()
+ .with_env_filter("debug")
+ .with_span_events(FmtSpan::CLOSE)
+ .with_test_writer()
+ .try_init();
}
-// fuzz test
-fn reverse(xs: &[T]) -> Vec {
- let mut rev = vec![];
- for x in xs.iter() {
- rev.insert(0, x.clone())
- }
- rev
+/// Fixture setup function
+#[fixture]
+async fn test_context() -> TestContext {
+ init_tracing();
+ info!("Setting up test context");
+ let server = TestServer::start().await.expect("Failed to start test server");
+ let client = reqwest::Client::new();
+ TestContext { server, client }
}
-// fuzz, declare quickcheck on any argument implementing Arbitrary
-#[quickcheck_macros::quickcheck]
-fn prop(xs: Vec) -> bool { xs == reverse(&reverse(&xs)) }
+#[rstest]
+#[tokio::test]
+async fn test_proxy_forwarding(#[future] test_context: TestContext) -> Result<()> {
+ let ctx = test_context.await;
+ let test_url = "https://gist.githubusercontent.com/mattes/23e64faadb5fd4b5112f379903d2572e/raw/ddbf0a56001367467f71bda64347aa881d83533c/example.json";
+
+ info!("Sending request through proxy to {}", test_url);
+ let response = ctx.client.get(&*TEST_SERVER).header("X-Target-URL", test_url).send().await?;
+
+ debug!(status = ?response.status(), "Received response");
+ assert!(response.status().is_success());
+
+ let body: serde_json::Value = response.json().await?;
+ debug!(body = ?body, "Parsed response body");
+ assert_eq!(body["hello"], "world");
+
+ ctx.server.stop().await?;
+ Ok(())
+}