Skip to content

Commit

Permalink
feat(inspect-server): support POST requests
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelstanley committed Aug 29, 2023
1 parent 4197eaf commit 1da90a4
Show file tree
Hide file tree
Showing 6 changed files with 335 additions and 42 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## Added
### Added

- Added authority claimer service to support reader mode
- Added support to `POST` *inspect state* requests

## [1.0.0] 2023-08-22

Expand Down
24 changes: 21 additions & 3 deletions offchain/inspect-server/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,37 @@ use crate::inspect::{
CompletionStatus, InspectClient, InspectStateResponse, Report,
};

// (2^20 - 64) bytes, which is the length of the RX buffer minus metadata
pub const CARTESI_MACHINE_RX_BUFFER_LIMIT: usize = 1_048_512;

pub fn create(
config: &InspectServerConfig,
inspect_client: InspectClient,
) -> std::io::Result<Server> {
let inspect_path = config.inspect_path_prefix.clone() + "/{payload:.*}";
let inspect_path = config.inspect_path_prefix.clone();
let inspect_get_path = inspect_path.clone() + "/{payload:.*}";
let server = HttpServer::new(move || {
let cors = Cors::permissive();
App::new()
.app_data(web::Data::new(inspect_client.clone()))
.app_data(web::PayloadConfig::new(CARTESI_MACHINE_RX_BUFFER_LIMIT))
.wrap(middleware::Logger::default())
.wrap(cors)
.service(
web::resource(inspect_get_path.clone())
.route(web::get().to(inspect_get)),
)
.service(
web::resource(inspect_path.clone())
.route(web::get().to(inspect)),
.route(web::post().to(inspect_post)),
)
})
.bind(config.inspect_server_address.clone())?
.run();
Ok(server)
}

async fn inspect(
async fn inspect_get(
request: HttpRequest,
payload: web::Path<String>,
inspect_client: web::Data<InspectClient>,
Expand All @@ -50,6 +59,15 @@ async fn inspect(
Ok(HttpResponse::Ok().json(http_response))
}

async fn inspect_post(
payload: web::Bytes,
inspect_client: web::Data<InspectClient>,
) -> actix_web::error::Result<impl Responder> {
let response = inspect_client.inspect(payload.to_vec()).await?;
let http_response = HttpInspectResponse::from(response);
Ok(HttpResponse::Ok().json(http_response))
}

#[derive(Debug, Deserialize, Serialize)]
pub struct HttpInspectResponse {
pub status: String,
Expand Down
38 changes: 35 additions & 3 deletions offchain/inspect-server/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,14 +251,46 @@ impl<T: MockInspect> ServerManager for MockServerManager<T> {
}
}

/// Send an inspect-state request to the inspect server.
/// Send an inspect-state request to the inspect server via GET.
/// If the status code is 200, return the HttpInspectResponse.
/// Else, return the status code and the error message.
pub async fn send_request(
pub async fn send_get_request(
payload: &str,
) -> Result<HttpInspectResponse, (StatusCode, String)> {
let url = format!("http://{}/inspect/{}", INSPECT_SERVER_ADDRESS, payload);
let response = reqwest::get(url).await.expect("failed to send inspect");
let response = reqwest::get(url)
.await
.expect("failed to send inspect via GET");
let status = response.status();
if status == 200 {
let response = response
.json::<HttpInspectResponse>()
.await
.expect("failed to decode json response");
Ok(response)
} else {
let message = response
.text()
.await
.expect("failed to obtain response body");
Err((status, message))
}
}

/// Send an inspect-state request to the inspect server via POST.
/// If the status code is 200, return the HttpInspectResponse.
/// Else, return the status code and the error message.
pub async fn send_post_request(
payload: &str,
) -> Result<HttpInspectResponse, (StatusCode, String)> {
let url = format!("http://{}/inspect", INSPECT_SERVER_ADDRESS);
let client = reqwest::Client::new();
let response = client
.post(url)
.body(String::from(payload))
.send()
.await
.expect("failed to send inspect via POST");
let status = response.status();
if status == 200 {
let response = response
Expand Down
86 changes: 70 additions & 16 deletions offchain/inspect-server/tests/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

mod common;
use crate::common::*;
use inspect_server::server::CARTESI_MACHINE_RX_BUFFER_LIMIT;

struct EchoInspect {}

Expand All @@ -17,9 +18,9 @@ impl MockInspect for EchoInspect {
}
}

async fn test_payload(sent_payload: &str, expected_payload: &str) {
async fn test_get_payload(sent_payload: &str, expected_payload: &str) {
let test_state = TestState::setup(EchoInspect {}).await;
let response = send_request(sent_payload)
let response = send_get_request(sent_payload)
.await
.expect("failed to obtain response");
assert_eq!(response.status, "Accepted");
Expand All @@ -32,32 +33,32 @@ async fn test_payload(sent_payload: &str, expected_payload: &str) {

#[tokio::test]
#[serial_test::serial]
async fn test_simple_payload() {
test_payload("hello", "hello").await;
async fn test_get_simple_payload() {
test_get_payload("hello", "hello").await;
}

#[tokio::test]
#[serial_test::serial]
async fn test_payload_with_spaces() {
test_payload("hello world", "hello world").await;
async fn test_get_payload_with_spaces() {
test_get_payload("hello world", "hello world").await;
}

#[tokio::test]
#[serial_test::serial]
async fn test_url_encoded_payload() {
test_payload("hello%20world", "hello world").await;
async fn test_get_url_encoded_payload() {
test_get_payload("hello%20world", "hello world").await;
}

#[tokio::test]
#[serial_test::serial]
async fn test_payload_with_slashes() {
test_payload("user/123/name", "user/123/name").await;
async fn test_get_payload_with_slashes() {
test_get_payload("user/123/name", "user/123/name").await;
}

#[tokio::test]
#[serial_test::serial]
async fn test_payload_with_path_and_query() {
test_payload(
async fn test_get_payload_with_path_and_query() {
test_get_payload(
"user/data?key=value&key2=value2",
"user/data?key=value&key2=value2",
)
Expand All @@ -66,8 +67,8 @@ async fn test_payload_with_path_and_query() {

#[tokio::test]
#[serial_test::serial]
async fn test_raw_json_payload() {
test_payload(
async fn test_get_raw_json_payload() {
test_get_payload(
r#"{"key": ["value1", "value2"]}"#,
r#"{"key": ["value1", "value2"]}"#,
)
Expand All @@ -76,6 +77,59 @@ async fn test_raw_json_payload() {

#[tokio::test]
#[serial_test::serial]
async fn test_payload_with_empty_payload() {
test_payload("", "").await;
async fn test_get_empty_payload() {
test_get_payload("", "").await;
}

async fn test_post_payload(sent_payload: &str, expected_payload: &str) {
let test_state = TestState::setup(EchoInspect {}).await;
let response = send_post_request(sent_payload)
.await
.expect("failed to obtain response");
assert_eq!(response.status, "Accepted");
assert_eq!(response.exception_payload, None);
assert_eq!(response.reports.len(), 1);
let expected_payload = String::from("0x") + &hex::encode(expected_payload);
assert_eq!(response.reports[0].payload, expected_payload);
test_state.teardown().await;
}

#[tokio::test]
#[serial_test::serial]
async fn test_post_empty_payload() {
test_post_payload("", "").await;
}

#[tokio::test]
#[serial_test::serial]
async fn test_post_simple_payload() {
test_post_payload("hello", "hello").await;
}

#[tokio::test]
#[serial_test::serial]
async fn test_post_raw_json_payload() {
test_post_payload(
r#"{"key": ["value1", "value2"]}"#,
r#"{"key": ["value1", "value2"]}"#,
)
.await;
}

#[tokio::test]
#[serial_test::serial]
async fn test_post_payload_on_limit() {
let payload = "0".repeat(CARTESI_MACHINE_RX_BUFFER_LIMIT);
test_post_payload(&payload.clone(), &payload.clone()).await;
}

#[tokio::test]
#[serial_test::serial]
async fn test_post_fails_when_payload_over_limit() {
let payload = "0".repeat(CARTESI_MACHINE_RX_BUFFER_LIMIT + 1);
let test_state = TestState::setup(EchoInspect {}).await;
send_post_request(&payload)
.await
.expect_err("Payload reached size limit");
test_state.teardown().await;
}
Loading

0 comments on commit 1da90a4

Please sign in to comment.