Procházet zdrojové kódy

explorerd/rpc: added test coverage for invalid/missing parameters

This commit expands the test suite by adding RPC tests that cover invalid/missing parameters, unsupported data types, unparsable inputs, and invalid numeric ranges. It also includes a test case to ensure `ping_darkfid` properly handles error when invoked under a disconnected darkfid endpoint.

New test modules include:
- **rpc/mod/tests**: Tests to ensure that `ping_darkfid` correctly handles non-empty parameters and scenarios where it is invoked with a disconnected darkfid endpoint
- **rpc/blocks/tests**: Tests verifying that invalid/missing parameters for fetching blocks produce the expected error responses
- **rpc/transaction/tests**: Tests confirming that incorrect/missing parameters for retrieving transactions are properly handled
- **rpc/contracts/tests**: Tests ensuring invalid/missing parameter handling for retrieving native contracts data
- **rpc/statistics/tests**: Tests confirming that invalid/missing parameters for retrieving statistics result in correct error handling

Other updates:
- Set the default test log level to 'Off' in test_mod.rs
- Removed the `TEST_DATA_DIR` constant until the test cases are updated to run on a copy of the test `explorerdb`
- Removed the `test_data/explorerd_0` folder until the test cases are updated to use a copy of the test `explorerdb`

Running Tests:

cargo test rpc
kalm před 1 rokem
rodič
revize
04209b29e2
33 změnil soubory, kde provedl 356 přidání a 12 odebrání
  1. 0 2
      bin/explorer/explorerd/src/main.rs
  2. 152 0
      bin/explorer/explorerd/src/rpc/blocks.rs
  3. 70 0
      bin/explorer/explorerd/src/rpc/contracts.rs
  4. 57 0
      bin/explorer/explorerd/src/rpc/mod.rs
  5. 27 0
      bin/explorer/explorerd/src/rpc/statistics.rs
  6. 42 0
      bin/explorer/explorerd/src/rpc/transactions.rs
  7. 8 6
      bin/explorer/explorerd/src/test_utils/mod.rs
  8. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/1200325
  9. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/1201520
  10. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/1202173
  11. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/1490853
  12. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/1490869
  13. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/1490885
  14. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/15099
  15. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/15115
  16. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/15131
  17. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/15147
  18. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/15163
  19. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/15179
  20. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/15195
  21. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/15211
  22. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/15227
  23. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/15997
  24. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/16013
  25. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/16029
  26. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/16398
  27. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/16414
  28. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/16430
  29. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/16446
  30. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/16462
  31. 0 4
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/conf
  32. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/db
  33. binární
      bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/snap.000000000016CD3D

+ 0 - 2
bin/explorer/explorerd/src/main.rs

@@ -55,8 +55,6 @@ mod error;
 
 /// Test utilities used for unit and integration testing
 #[cfg(test)]
-#[allow(dead_code)]
-// TODO: Remove when test code that utilizes the new utility functions is checked in
 mod test_utils;
 
 const CONFIG_FILE: &str = "explorerd_config.toml";

+ 152 - 0
bin/explorer/explorerd/src/rpc/blocks.rs

@@ -156,3 +156,155 @@ impl Explorerd {
         }
     }
 }
+
+#[cfg(test)]
+/// Test module for validating the functionality of RPC methods related to explorer blocks.
+/// Focuses on ensuring proper error handling for invalid parameters across several use cases,
+/// including cases with missing values, unsupported types, invalid ranges, and unparsable inputs.
+mod tests {
+
+    use tinyjson::JsonValue;
+
+    use darkfi::rpc::{
+        jsonrpc::{ErrorCode, JsonRequest, JsonResult},
+        server::RequestHandler,
+    };
+
+    use crate::test_utils::{
+        setup, validate_invalid_rpc_header_hash, validate_invalid_rpc_parameter,
+    };
+
+    #[test]
+    /// Tests the handling of invalid parameters for the `blocks.get_last_n_blocks` JSON-RPC method.
+    /// Verifies that missing and an invalid `num_last_blocks` value results in an appropriate error.
+    fn test_blocks_get_last_n_blocks_invalid_params() {
+        smol::block_on(async {
+            // Define rpc_method and parameter names
+            let rpc_method = "blocks.get_last_n_blocks";
+            let parameter_name = "num_last_blocks";
+
+            // Set up the Explorerd instance
+            let explorerd = setup();
+
+            // Test for missing `start` parameter
+            validate_invalid_rpc_parameter(
+                &explorerd,
+                rpc_method,
+                &[],
+                ErrorCode::InvalidParams.code(),
+                &format!("Parameter '{}' at index 0 is missing", parameter_name),
+            )
+            .await;
+
+            // Test for invalid num_last_blocks parameter
+            validate_invalid_rpc_parameter(
+                &explorerd,
+                rpc_method,
+                &[JsonValue::String("invalid_number".to_string())],
+                ErrorCode::InvalidParams.code(),
+                &format!("Parameter '{}' is not a supported number type", parameter_name),
+            )
+            .await;
+        });
+    }
+
+    #[test]
+    /// Tests the handling of invalid parameters for the `blocks.get_blocks_in_heights_range`
+    /// JSON-RPC method. Verifies that invalid/missing `start` or `end` parameter values, or an
+    /// invalid range where `start` is greater than `end`, result in appropriate errors.
+    fn test_blocks_get_blocks_in_heights_range_invalid_params() {
+        smol::block_on(async {
+            // Define rpc_method and parameter names
+            let rpc_method = "blocks.get_blocks_in_heights_range";
+            let start_parameter_name = "start";
+            let end_parameter_name = "end";
+
+            // Set up the Explorerd instance
+            let explorerd = setup();
+
+            // Test for missing `start` parameter
+            validate_invalid_rpc_parameter(
+                &explorerd,
+                rpc_method,
+                &[],
+                ErrorCode::InvalidParams.code(),
+                &format!("Parameter '{}' at index 0 is missing", start_parameter_name),
+            )
+            .await;
+
+            // Test for invalid `start` parameter
+            validate_invalid_rpc_parameter(
+                &explorerd,
+                rpc_method,
+                &[JsonValue::String("invalid_number".to_string()), JsonValue::Number(10.0)],
+                ErrorCode::InvalidParams.code(),
+                &format!("Parameter '{start_parameter_name}' is not a supported number type"),
+            )
+            .await;
+
+            // Test for invalid `end` parameter
+            validate_invalid_rpc_parameter(
+                &explorerd,
+                rpc_method,
+                &[JsonValue::Number(10.0)],
+                ErrorCode::InvalidParams.code(),
+                &format!("Parameter '{}' at index 1 is missing", end_parameter_name),
+            )
+            .await;
+
+            // Test for invalid `end` parameter
+            validate_invalid_rpc_parameter(
+                &explorerd,
+                rpc_method,
+                &[JsonValue::Number(10.0), JsonValue::String("invalid_number".to_string())],
+                ErrorCode::InvalidParams.code(),
+                &format!("Parameter '{end_parameter_name}' is not a supported number type"),
+            )
+            .await;
+
+            // Test invalid range where `start` > `end`
+            let request = JsonRequest {
+                id: 1,
+                jsonrpc: "2.0",
+                method: rpc_method.to_string(),
+                params: JsonValue::Array(vec![JsonValue::Number(20.0), JsonValue::Number(10.0)]),
+            };
+
+            let response = explorerd.handle_request(request).await;
+
+            // Verify that `start > end` error is raised
+            match response {
+                JsonResult::Error(actual_error) => {
+                    let expected_error_code = ErrorCode::InvalidParams.code();
+                    assert_eq!(
+                        actual_error.error.code,
+                        expected_error_code
+                    );
+                    assert_eq!(
+                        actual_error.error.message,
+                        "Invalid range: start (20) cannot be greater than end (10)"
+                    );
+                }
+                _ => panic!(
+                    "Expected a JSON error response for method: {rpc_method}, but got something else",
+                ),
+            }
+        });
+    }
+    #[test]
+    /// Tests the handling of invalid parameters for the `blocks.get_block_by_hash` JSON-RPC method.
+    /// Verifies that an invalid `header_hash` value, either a numeric type or invalid hash string,
+    /// results in appropriate error.
+    fn test_blocks_get_block_by_hash_invalid_params() {
+        smol::block_on(async {
+            // Define the RPC method name
+            let rpc_method = "blocks.get_block_by_hash";
+
+            // Set up the explorerd
+            let explorerd = setup();
+
+            // Validate when provided with an invalid tx hash
+            validate_invalid_rpc_header_hash(&explorerd, rpc_method);
+        });
+    }
+}

+ 70 - 0
bin/explorer/explorerd/src/rpc/contracts.rs

@@ -126,3 +126,73 @@ impl Explorerd {
         }
     }
 }
+
+#[cfg(test)]
+/// Test module for validating the functionality of RPC methods related to explorer contracts.
+/// Focuses on ensuring proper error handling for invalid parameters across several use cases,
+/// including cases with missing values, unsupported types, and unparsable inputs.
+mod tests {
+
+    use tinyjson::JsonValue;
+
+    use darkfi::rpc::jsonrpc::ErrorCode;
+
+    use crate::test_utils::{
+        setup, validate_empty_rpc_parameters, validate_invalid_rpc_contract_id,
+        validate_invalid_rpc_parameter,
+    };
+
+    #[test]
+    /// Tests the `contracts.get_native_contracts` method to ensure it correctly handles cases where
+    /// empty parameters are supplied, returning an expected result or error response.
+    fn test_contracts_get_native_contracts_empty_params() {
+        smol::block_on(async {
+            validate_empty_rpc_parameters(&setup(), "contracts.get_native_contracts").await;
+        });
+    }
+
+    #[test]
+    /// Tests the `contracts.get_contract_source_code_paths` method to ensure it correctly handles cases
+    /// with invalid or missing `contract_id` parameters, returning appropriate error responses.
+    fn test_contracts_get_contract_source_code_paths_invalid_params() {
+        validate_invalid_rpc_contract_id(&setup(), "contracts.get_contract_source_code_paths");
+    }
+
+    #[test]
+    /// Tests the `contracts.get_contract_source` method to ensure it correctly handles cases
+    /// with invalid or missing parameters, returning appropriate error responses.
+    fn test_contracts_get_contract_source_invalid_params() {
+        let test_method = "contracts.get_contract_source";
+        let parameter_name = "source_path";
+
+        smol::block_on(async {
+            // Set up the explorerd instance
+            let explorerd = setup();
+
+            validate_invalid_rpc_contract_id(&explorerd, test_method);
+
+            // Test for missing `source_path` parameter
+            validate_invalid_rpc_parameter(
+                &explorerd,
+                test_method,
+                &[JsonValue::String("BZHKGQ26bzmBithTQYTJtjo2QdCqpkR9tjSBopT4yf4o".to_string())],
+                ErrorCode::InvalidParams.code(),
+                &format!("Parameter '{}' at index 1 is missing", parameter_name),
+            )
+            .await;
+
+            // Test for invalid `source_path` parameter
+            validate_invalid_rpc_parameter(
+                &explorerd,
+                test_method,
+                &[
+                    JsonValue::String("BZHKGQ26bzmBithTQYTJtjo2QdCqpkR9tjSBopT4yf4o".to_string()),
+                    JsonValue::Number(123.0), // Invalid `source_path` type
+                ],
+                ErrorCode::InvalidParams.code(),
+                &format!("Parameter '{}' is not a valid string", parameter_name),
+            )
+            .await;
+        });
+    }
+}

+ 57 - 0
bin/explorer/explorerd/src/rpc/mod.rs

@@ -339,3 +339,60 @@ fn log_request_failure(req_method: &str, params: &JsonValue, error: &JsonError)
     // Log the error
     error!(target: &log_target, "{}", error_message);
 }
+
+/// Test module for validating API functions within this `mod.rs` file. It ensures that the core API
+/// functions behave as expected and that they handle invalid parameters properly.
+#[cfg(test)]
+mod tests {
+    use tinyjson::JsonValue;
+
+    use darkfi::rpc::jsonrpc::JsonRequest;
+
+    use super::*;
+    use crate::{
+        error::ERROR_CODE_PING_DARKFID_FAILED,
+        test_utils::{setup, validate_empty_rpc_parameters},
+    };
+
+    #[test]
+    /// Validates the failure scenario of the `ping_darkfid` JSON-RPC method by sending a request
+    /// to a disconnected darkfid endpoint, ensuring the response is an error with the expected
+    /// code and message.
+    fn test_ping_darkfid_failure() {
+        smol::block_on(async {
+            // Set up the Explorerd instance
+            let explorerd = setup();
+
+            // Prepare a JSON-RPC request for `ping_darkfid`
+            let request = JsonRequest {
+                id: 1,
+                jsonrpc: "2.0",
+                method: "ping_darkfid".to_string(),
+                params: JsonValue::Array(vec![]),
+            };
+
+            // Call `handle_request` on the Explorerd instance
+            let response = explorerd.handle_request(request).await;
+
+            // Verify the response is a `JsonError` with the `PingFailed` error code
+            match response {
+                JsonResult::Error(actual_error) => {
+                    let expected_error_code = ERROR_CODE_PING_DARKFID_FAILED;
+                    let expected_error_msg = "Ping darkfid failed: Not connected, is the explorer running in no-sync mode?";
+                    assert_eq!(actual_error.error.code, expected_error_code);
+                    assert_eq!(actual_error.error.message, expected_error_msg);
+                }
+                _ => panic!("Expected a JSON object for the response, but got something else"),
+            }
+        });
+    }
+
+    /// Tests the `ping_darkfid` method to ensure it correctly handles cases where non-empty parameters
+    /// are supplied, returning an expected error response.
+    #[test]
+    fn test_ping_darkfid_empty_params() {
+        smol::block_on(async {
+            validate_empty_rpc_parameters(&setup(), "ping_darkfid").await;
+        });
+    }
+}

+ 27 - 0
bin/explorer/explorerd/src/rpc/statistics.rs

@@ -103,3 +103,30 @@ impl Explorerd {
         Ok(statistics.to_json_array())
     }
 }
+
+#[cfg(test)]
+/// Test module for validating the functionality of RPC methods related to explorer statistics.
+/// Focuses on ensuring proper error handling for invalid parameters across several use cases.
+mod tests {
+
+    use crate::test_utils::{setup, validate_empty_rpc_parameters};
+
+    /// Tests all RPC-related statistics calls when provided with empty parameters, ensuring they
+    /// handle the input correctly and return appropriate validation responses.
+    #[test]
+    fn test_statistics_rpc_calls_for_empty_parameters() {
+        smol::block_on(async {
+            let explorerd = setup();
+
+            let rpc_methods = [
+                "statistics.get_latest_metric_statistics",
+                "statistics.get_metric_statistics",
+                "statistics.get_basic_statistics",
+            ];
+
+            for rpc_method in rpc_methods.iter() {
+                validate_empty_rpc_parameters(&explorerd, rpc_method).await;
+            }
+        });
+    }
+}

+ 42 - 0
bin/explorer/explorerd/src/rpc/transactions.rs

@@ -83,3 +83,45 @@ impl Explorerd {
         }
     }
 }
+
+#[cfg(test)]
+/// Test module for validating the functionality of RPC methods related to explorer transactions.
+/// Focuses on ensuring proper error handling for invalid parameters across several use cases,
+/// including cases with missing values, unsupported types, and unparsable inputs.
+mod tests {
+
+    use crate::test_utils::{
+        setup, validate_invalid_rpc_header_hash, validate_invalid_rpc_tx_hash,
+    };
+
+    #[test]
+    /// Tests the handling of invalid parameters for the `transactions.get_transactions_by_header_hash` JSON-RPC method.
+    /// Verifies that missing and an invalid `header_hash` value results in an appropriate error.
+    fn test_transactions_get_transactions_by_header_hash() {
+        smol::block_on(async {
+            // Define the RPC method name
+            let rpc_method = "transactions.get_transactions_by_header_hash";
+
+            // Set up the explorerd
+            let explorerd = setup();
+
+            // Validate when provided with an invalid header hash
+            validate_invalid_rpc_header_hash(&explorerd, rpc_method);
+        });
+    }
+    #[test]
+    /// Tests the handling of invalid parameters for the `transactions.get_transaction_by_hash` JSON-RPC method.
+    /// Verifies that missing and an invalid `tx_hash` value results in an appropriate error.
+    fn test_transactions_get_transaction_by_hash() {
+        smol::block_on(async {
+            // Define the RPC method name
+            let rpc_method = "transactions.get_transaction_by_hash";
+
+            // Set up the explorerd
+            let explorerd = setup();
+
+            // Validate when provided with an invalid tx hash
+            validate_invalid_rpc_tx_hash(&explorerd, rpc_method);
+        });
+    }
+}

+ 8 - 6
bin/explorer/explorerd/src/test_utils/mod.rs

@@ -20,6 +20,7 @@ use std::sync::{Arc, Mutex};
 
 use lazy_static::lazy_static;
 use smol::Executor;
+use tempdir::TempDir;
 use tinyjson::JsonValue;
 use url::Url;
 
@@ -30,8 +31,6 @@ use darkfi::rpc::{
 
 use crate::Explorerd;
 
-const TEST_DATA_DIR: &str = "src/test_utils/test_data";
-
 // Defines a global `Explorerd` instance shared across all tests
 lazy_static! {
     static ref EXPLORERD_INSTANCE: Mutex<Option<Arc<Explorerd>>> = Mutex::new(None);
@@ -73,10 +72,13 @@ pub fn setup() -> Arc<Explorerd> {
 
     if instance.is_none() {
         // Initialize logger for the first time
-        init_logger(simplelog::LevelFilter::Info, vec!["sled", "runtime", "net"]);
+        init_logger(simplelog::LevelFilter::Off, vec!["sled", "runtime", "net"]);
 
         // Prepare parameters for Explorerd::new
-        let db_path = format!("{}/explorerd_0", TEST_DATA_DIR);
+        let temp_dir = TempDir::new("explorerd").expect("Failed to create temp dir");
+        let db_path_buf = temp_dir.path().join("explorerd_0");
+        let db_path =
+            db_path_buf.to_str().expect("Failed to convert db_path to string").to_string();
         let darkfid_endpoint = Url::parse("http://127.0.0.1:8240").expect("Invalid URL");
         let executor = Arc::new(Executor::new());
 
@@ -130,12 +132,12 @@ pub async fn validate_invalid_rpc_parameter(
 /// Auxiliary function that validates the handling of non-empty parameters when they are supposed
 /// to be empty for the given RPC `method`. It uses the provided [`Explorerd`] instance to ensure
 /// that unexpected non-empty parameters result in the expected error for invalid parameters.
-pub async fn validate_empty_rpc_parameters(explorerd: &Explorerd, method: String) {
+pub async fn validate_empty_rpc_parameters(explorerd: &Explorerd, method: &str) {
     // Prepare a JSON-RPC request for `ping_darkfid`
     let request = JsonRequest {
         id: 1,
         jsonrpc: "2.0",
-        method,
+        method: method.to_string(),
         params: JsonValue::Array(vec![JsonValue::String("non_empty_param".to_string())]),
     };
 

binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/1200325


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/1201520


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/1202173


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/1490853


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/1490869


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/1490885


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/15099


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/15115


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/15131


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/15147


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/15163


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/15179


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/15195


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/15211


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/15227


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/15997


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/16013


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/16029


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/16398


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/16414


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/16430


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/16446


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/blobs/16462


+ 0 - 4
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/conf

@@ -1,4 +0,0 @@
-segment_size: 524288
-use_compression: false
-version: 0.34
-vQÁ

binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/db


binární
bin/explorer/explorerd/src/test_utils/test_data/explorerd_0/snap.000000000016CD3D