From 2d49671f55368779f55698e97fa5ad98627420c8 Mon Sep 17 00:00:00 2001 From: ShahakShama <70578257+ShahakShama@users.noreply.github.com> Date: Thu, 3 Aug 2023 17:15:33 +0300 Subject: [PATCH] shahak/json rpc/get schema for method results (#962) * test(JSON-RPC): move code * test(JSON-RPC): add function for getting a schema of a method's result --- crates/papyrus_gateway/src/test_utils.rs | 77 ++++++++++++++----- crates/papyrus_gateway/src/v0_3_0/api/test.rs | 6 +- .../v0_3_0/broadcasted_transaction_test.rs | 4 +- crates/papyrus_gateway/src/v0_4_0/api/test.rs | 6 +- 4 files changed, 67 insertions(+), 26 deletions(-) diff --git a/crates/papyrus_gateway/src/test_utils.rs b/crates/papyrus_gateway/src/test_utils.rs index 3670a99db3..3da5a273f1 100644 --- a/crates/papyrus_gateway/src/test_utils.rs +++ b/crates/papyrus_gateway/src/test_utils.rs @@ -46,6 +46,13 @@ pub(crate) fn get_test_rpc_server_and_storage_writer() ) } +// 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")] @@ -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: Refs, + version_id: &VersionId, ) -> JSONSchema { let mut options = JSONSchema::options(); for entry in std::fs::read_dir(format!("./resources/{version_id}")).unwrap() { @@ -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"); } diff --git a/crates/papyrus_gateway/src/v0_3_0/api/test.rs b/crates/papyrus_gateway/src/v0_3_0/api/test.rs index 023304841f..14359d6ee2 100644 --- a/crates/papyrus_gateway/src/v0_3_0/api/test.rs +++ b/crates/papyrus_gateway/src/v0_3_0/api/test.rs @@ -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}; @@ -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, &[ diff --git a/crates/papyrus_gateway/src/v0_3_0/broadcasted_transaction_test.rs b/crates/papyrus_gateway/src/v0_3_0/broadcasted_transaction_test.rs index 96dc34f4fa..a3c2f74534 100644 --- a/crates/papyrus_gateway/src/v0_3_0/broadcasted_transaction_test.rs +++ b/crates/papyrus_gateway/src/v0_3_0/broadcasted_transaction_test.rs @@ -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! { @@ -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 )); diff --git a/crates/papyrus_gateway/src/v0_4_0/api/test.rs b/crates/papyrus_gateway/src/v0_4_0/api/test.rs index 14447ebe47..4f700dad20 100644 --- a/crates/papyrus_gateway/src/v0_4_0/api/test.rs +++ b/crates/papyrus_gateway/src/v0_4_0/api/test.rs @@ -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}; @@ -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, &[