Skip to content

Commit

Permalink
shahak/json rpc/get schema for method results (#962)
Browse files Browse the repository at this point in the history
* test(JSON-RPC): move code

* test(JSON-RPC): add function for getting a schema of a method's result
  • Loading branch information
ShahakShama authored Aug 3, 2023
1 parent 960765e commit 2d49671
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 26 deletions.
77 changes: 59 additions & 18 deletions crates/papyrus_gateway/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ pub(crate) fn get_test_rpc_server_and_storage_writer<T: JsonRpcServerImpl>()
)
}

// TODO(nevo): Schmea validates null as valid for an unknown reason.
// Investigate in the future and remove this function (use is_valid directly)
pub fn validate_schema(schema: &JSONSchema, res: Value) -> bool {
let result = &res["result"];
result != &Value::Null && schema.is_valid(result)
}

#[derive(Clone, Copy, Display)]
pub enum SpecFile {
#[display(fmt = "starknet_api_openrpc.json")]
Expand All @@ -56,9 +63,44 @@ pub enum SpecFile {
StarknetWriteApi,
}

pub async fn get_starknet_spec_api_schema(
// TODO(shahak): Make non-async.
pub async fn get_starknet_spec_api_schema_for_components(
file_to_component_names: &[(SpecFile, &[&str])],
version_id: &VersionId,
) -> JSONSchema {
get_starknet_spec_api_schema(
file_to_component_names.iter().flat_map(|(file, component_names)| {
component_names
.iter()
.map(move |component| format!("file:///api/{file}#/components/schemas/{component}"))
}),
version_id,
)
}

// TODO(shahak): Remove allow(dead_code) once we use this variant.
#[allow(dead_code)]
pub fn get_starknet_spec_api_schema_for_method_results(
file_to_methods: &[(SpecFile, &[&str])],
version_id: &VersionId,
) -> JSONSchema {
get_starknet_spec_api_schema(
file_to_methods.iter().flat_map(|(file, methods)| {
let spec_str =
std::fs::read_to_string(format!("./resources/{version_id}/{file}")).unwrap();
let spec: serde_json::Value = serde_json::from_str(&spec_str).unwrap();
methods.iter().map(move |method| {
let index = get_method_index(&spec, method);
format!("file:///api/{file}#/methods/{index}/result")
})
}),
version_id,
)
}

fn get_starknet_spec_api_schema<Refs: IntoIterator<Item = String>>(
refs: Refs,
version_id: &VersionId,
) -> JSONSchema {
let mut options = JSONSchema::options();
for entry in std::fs::read_dir(format!("./resources/{version_id}")).unwrap() {
Expand All @@ -69,27 +111,26 @@ pub async fn get_starknet_spec_api_schema(
options.with_document(format!("file:///api/{file_name}"), spec);
}

let mut components = String::from(r#"{"anyOf": ["#);
let mut refs_schema_str = String::from(r#"{"anyOf": ["#);
const SEPARATOR: &str = ", ";
for (file_name, component_names) in file_to_component_names {
for component in *component_names {
components += &format!(
r##"{{"$ref": "file:///api/{file_name}#/components/schemas/{component}"}}"##,
);
components += SEPARATOR;
}
for ref_str in refs {
refs_schema_str += &format!(r##"{{"$ref": "{ref_str}"}}"##,);
refs_schema_str += SEPARATOR;
}
// Remove the last separator.
components.truncate(components.len() - SEPARATOR.len());
components += r#"], "unevaluatedProperties": false}"#;
let schema = serde_json::from_str(&components).unwrap();
refs_schema_str.truncate(refs_schema_str.len() - SEPARATOR.len());
refs_schema_str += r#"], "unevaluatedProperties": false}"#;
let refs_schema = serde_json::from_str(&refs_schema_str).unwrap();

options.compile(&schema).unwrap()
options.compile(&refs_schema).unwrap()
}

// TODO(nevo): Schmea validates null as valid for an unknown reason.
// Investigate in the future and remove this function (use is_valid directly)
pub fn validate_schema(schema: &JSONSchema, res: Value) -> bool {
let result = &res["result"];
result != &Value::Null && schema.is_valid(result)
fn get_method_index(spec: &serde_json::Value, method: &str) -> usize {
let methods_json_arr = spec.as_object().unwrap().get("methods").unwrap().as_array().unwrap();
for (i, method_object) in methods_json_arr.iter().enumerate() {
if method_object.as_object().unwrap().get("name").unwrap() == method {
return i;
}
}
panic!("Method {method} doesn't exist");
}
6 changes: 3 additions & 3 deletions crates/papyrus_gateway/src/v0_3_0/api/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ use crate::api::{
Tag,
};
use crate::test_utils::{
get_starknet_spec_api_schema, get_test_gateway_config, get_test_rpc_server_and_storage_writer,
get_test_syncing_state, validate_schema, SpecFile,
get_starknet_spec_api_schema_for_components, get_test_gateway_config,
get_test_rpc_server_and_storage_writer, get_test_syncing_state, validate_schema, SpecFile,
};
use crate::version_config::VERSION_0_3;
use crate::{run_server, ContinuationTokenAsStruct};
Expand Down Expand Up @@ -1628,7 +1628,7 @@ async fn serialize_returns_valid_json() {
let (server_address, _handle) =
run_server(&gateway_config, get_test_syncing_state(), storage_reader).await.unwrap();

let schema = get_starknet_spec_api_schema(
let schema = get_starknet_spec_api_schema_for_components(
&[(
SpecFile::StarknetApiOpenrpc,
&[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use super::broadcasted_transaction::{
BroadcastedInvokeTransaction, BroadcastedTransaction,
};
use super::state::ContractClass;
use crate::test_utils::{get_starknet_spec_api_schema, SpecFile};
use crate::test_utils::{get_starknet_spec_api_schema_for_components, SpecFile};
use crate::version_config::VERSION_0_3;

auto_impl_get_test_instance! {
Expand Down Expand Up @@ -72,7 +72,7 @@ auto_impl_get_test_instance! {

fn validate_tx_fits_rpc(tx: BroadcastedTransaction) {
lazy_static! {
static ref SCHEMA: JSONSchema = block_on(get_starknet_spec_api_schema(
static ref SCHEMA: JSONSchema = block_on(get_starknet_spec_api_schema_for_components(
&[(SpecFile::StarknetApiOpenrpc, &["BROADCASTED_TXN"])],
&VERSION_0_3
));
Expand Down
6 changes: 3 additions & 3 deletions crates/papyrus_gateway/src/v0_4_0/api/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ use crate::api::{
Tag,
};
use crate::test_utils::{
get_starknet_spec_api_schema, get_test_gateway_config, get_test_rpc_server_and_storage_writer,
get_test_syncing_state, validate_schema, SpecFile,
get_starknet_spec_api_schema_for_components, get_test_gateway_config,
get_test_rpc_server_and_storage_writer, get_test_syncing_state, validate_schema, SpecFile,
};
use crate::version_config::VERSION_0_4;
use crate::{run_server, ContinuationTokenAsStruct};
Expand Down Expand Up @@ -1636,7 +1636,7 @@ async fn serialize_returns_valid_json() {
let (server_address, _handle) =
run_server(&gateway_config, get_test_syncing_state(), storage_reader).await.unwrap();

let schema = get_starknet_spec_api_schema(
let schema = get_starknet_spec_api_schema_for_components(
&[(
SpecFile::StarknetApiOpenrpc,
&[
Expand Down

0 comments on commit 2d49671

Please sign in to comment.