diff --git a/.gitignore b/.gitignore index b1397e6..f8ee497 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,5 @@ Cargo.lock /target /rhai_test_download -/rhai_test_fs \ No newline at end of file +/rhai_test_fs +run_rhai_tests.log \ No newline at end of file diff --git a/docs/rhai/index.md b/docs/rhai/index.md index 56ddc04..4172a58 100644 --- a/docs/rhai/index.md +++ b/docs/rhai/index.md @@ -33,6 +33,7 @@ SAL includes test scripts for verifying the functionality of its Rhai integratio - [OS Module Tests](os_module_tests.md): Tests for file system, download, and package management operations - [Git Module Tests](git_module_tests.md): Tests for Git repository management and operations - [Process Module Tests](process_module_tests.md): Tests for command execution and process management +- [Redis Client Module Tests](redisclient_module_tests.md): Tests for Redis connection and operations - [Running Tests](running_tests.md): Instructions for running all Rhai tests - [CI Workflow](ci_workflow.md): Continuous integration workflow for Rhai tests diff --git a/docs/rhai/redisclient_module_tests.md b/docs/rhai/redisclient_module_tests.md new file mode 100644 index 0000000..42d241b --- /dev/null +++ b/docs/rhai/redisclient_module_tests.md @@ -0,0 +1,97 @@ +# Redis Client Module Tests + +This document describes the test scripts for the Redis client module in the SAL library. These tests verify the functionality of the Redis client module's connection management and Redis operations. + +## Test Structure + +The tests are organized into two main scripts: + +1. **Redis Connection** (`01_redis_connection.rhai`): Tests basic Redis connection and simple operations like PING, SET, GET, and DEL. +2. **Redis Operations** (`02_redis_operations.rhai`): Tests more advanced Redis operations like hash operations (HSET, HGET, HGETALL, HDEL) and list operations (RPUSH, LLEN, LRANGE). + +Additionally, there's a runner script (`run_all_tests.rhai`) that executes all tests and reports results. The runner script contains simplified versions of the individual tests to avoid dependency issues. + +## Running the Tests + +To run all tests, execute the following command from the project root: + +```bash +herodo --path src/rhai_tests/redisclient/run_all_tests.rhai +``` + +To run individual test scripts: + +```bash +herodo --path src/rhai_tests/redisclient/01_redis_connection.rhai +``` + +## Test Details + +### Redis Connection Test + +The Redis connection test (`01_redis_connection.rhai`) verifies the following functions: + +- `redis_ping`: Checking if the Redis server is available +- `redis_set`: Setting a key-value pair +- `redis_get`: Getting a value by key +- `redis_del`: Deleting a key + +The test creates a temporary key, performs operations on it, and then cleans up after itself. + +### Redis Operations Test + +The Redis operations test (`02_redis_operations.rhai`) verifies the following functions: + +- Hash operations: + - `redis_hset`: Setting a field in a hash + - `redis_hget`: Getting a field from a hash + - `redis_hgetall`: Getting all fields and values from a hash + - `redis_hdel`: Deleting a field from a hash + +- List operations: + - `redis_rpush`: Adding elements to a list + - `redis_llen`: Getting the length of a list + - `redis_lrange`: Getting a range of elements from a list + +The test creates temporary keys with a unique prefix, performs operations on them, and then cleans up after itself. + +## Test Runner + +The test runner script (`run_all_tests.rhai`) provides a framework for executing all tests and reporting results. It: + +1. Checks if Redis is available before running tests +2. Skips tests if Redis is not available +3. Contains simplified versions of each test +4. Runs each test in a try/catch block to handle errors +5. Catches and reports any errors +6. Provides a summary of passed, failed, and skipped tests + +## Redis Server Requirements + +These tests require a Redis server to be running and accessible. The tests will attempt to connect to Redis using the following strategy: + +1. First, try to connect via Unix socket at `$HOME/hero/var/myredis.sock` +2. If that fails, try to connect via TCP to `127.0.0.1` on the default Redis port (6379) + +If no Redis server is available, the tests will be skipped rather than failing. + +## Adding New Tests + +To add a new test: + +1. Create a new Rhai script in the `src/rhai_tests/redisclient` directory +2. Add a new test section to the `run_all_tests.rhai` script +3. Update this documentation to include information about the new test + +## Best Practices for Writing Tests + +When writing tests for the Redis client module: + +1. Always check if Redis is available before running tests +2. Use a unique prefix for test keys to avoid conflicts +3. Clean up any keys created during testing +4. Use assertions to verify expected behavior +5. Print clear messages about what's being tested +6. Handle errors gracefully +7. Make tests independent of each other +8. Keep tests focused on specific functionality diff --git a/run_rhai_tests.log b/run_rhai_tests.log deleted file mode 100644 index 7159db6..0000000 --- a/run_rhai_tests.log +++ /dev/null @@ -1,131 +0,0 @@ -======================================= - Running All Rhai Tests  -======================================= - -Running tests for module: git -------------------------------------- -Found 1 Rhai script to execute: - -Executing: src/rhai_tests/git/run_all_tests.rhai -=== Running Git Module Tests === - ---- Running Basic Git Operations Tests --- -Created test directory: rhai_test_git -Testing GitTree constructor... -✓ GitTree created successfully -Testing GitTree.list() with empty directory... -✓ GitTree.list(): Found 0 repositories (expected 0) -Testing GitTree.find() with empty directory... -✓ GitTree.find(): Found 0 repositories (expected 0) -Cleaning up... -✓ Cleanup: Directory rhai_test_git removed ---- Basic Git Operations Tests completed successfully --- - ---- Running Git Repository Operations Tests --- -Created test directory: rhai_test_git_ops -Creating GitTree... -✓ GitTree created successfully -Cleaning up... -✓ Cleanup: Directory rhai_test_git_ops removed ---- Git Repository Operations Tests completed successfully --- - -=== Test Summary === -Passed: 2 -Failed: 0 -Total: 2 - -✅ All tests passed! -Script executed successfully -Result: 0 - -All scripts executed -✓ Module git tests passed - -Running tests for module: os -------------------------------------- -Found 1 Rhai script to execute: - -Executing: src/rhai_tests/os/run_all_tests.rhai -=== Running OS Module Tests === - ---- Running File Operations Tests --- -Testing mkdir... -✓ mkdir: Successfully created directory 'rhai_test_fs' -✓ mkdir (nested): Successfully created directory 'rhai_test_fs/subdir' -✓ file_write: Successfully wrote to file 'rhai_test_fs/test.txt' -✓ file_read: Content matches -✓ file_size: 48 bytes -✓ delete: Directory cleaned up ---- File Operations Tests completed successfully --- - ---- Running Download Operations Tests --- -Created test directory: rhai_test_download -✓ which: curl found at /usr/bin/curl -✓ cmd_ensure_exists: Command 'curl' exists -Downloading https://raw.githubusercontent.com/rust-lang/rust/master/LICENSE-MIT... -Downloading https://raw.githubusercontent.com/rust-lang/rust/master/LICENSE-MIT to rhai_test_download/license.txt -Download complete! File size: 1.04 KB -✓ download_file: rhai_test_download/license.txt -✓ Downloaded file content verified -✓ Cleanup: Directory rhai_test_download removed ---- Download Operations Tests completed successfully --- - ---- Running Package Operations Tests --- -Current platform: Ubuntu -✓ package_set_debug: Debug mode enabled ---- Package Operations Tests completed successfully --- - -=== Test Summary === -Passed: 3 -Failed: 0 -Total: 3 - -✅ All tests passed! -Script executed successfully -Result: 0 - -All scripts executed -✓ Module os tests passed - -Running tests for module: process -------------------------------------- -Found 1 Rhai script to execute: - -Executing: src/rhai_tests/process/run_all_tests.rhai -=== Running Process Module Tests === - ---- Running Command Execution Tests --- -Testing run() with a simple command... -Hello, World! -✓ run().execute(): Command executed successfully -Testing which() function... -✓ which(): Found bash at /usr/bin/bash ---- Command Execution Tests completed successfully --- - ---- Running Process Management Tests --- -Testing process_list() function... -✓ process_list(): Found 344 processes -Testing process properties... -✓ Process properties: PID=1, Name=systemd ---- Process Management Tests completed successfully --- - -=== Test Summary === -Passed: 2 -Failed: 0 -Total: 2 - -✅ All tests passed! -Script executed successfully -Result: 0 - -All scripts executed -✓ Module process tests passed - -======================================= - Test Summary  -======================================= -Total modules tested: 3 -Passed: 3 -Failed: 0 - -All tests passed! diff --git a/src/rhai/mod.rs b/src/rhai/mod.rs index 9d38a42..1ee81eb 100644 --- a/src/rhai/mod.rs +++ b/src/rhai/mod.rs @@ -9,6 +9,7 @@ mod git; mod nerdctl; mod os; mod process; +mod redisclient; mod rfs; mod text; @@ -39,6 +40,9 @@ pub use os::{ rsync, }; +// Re-export Redis client module registration function +pub use redisclient::register_redisclient_module; + pub use process::{ kill, process_get, @@ -140,6 +144,9 @@ pub fn register(engine: &mut Engine) -> Result<(), Box> { // Register RFS module functions rfs::register(engine)?; + // Register Redis client module functions + redisclient::register_redisclient_module(engine)?; + // Future modules can be registered here Ok(()) diff --git a/src/rhai/redisclient.rs b/src/rhai/redisclient.rs new file mode 100644 index 0000000..89f8d9d --- /dev/null +++ b/src/rhai/redisclient.rs @@ -0,0 +1,323 @@ +//! Rhai wrappers for Redis client module functions +//! +//! This module provides Rhai wrappers for the functions in the Redis client module. + +use crate::redisclient; +use rhai::{Engine, EvalAltResult, Map}; +use std::collections::HashMap; + +/// Register Redis client module functions with the Rhai engine +/// +/// # Arguments +/// +/// * `engine` - The Rhai engine to register the functions with +/// +/// # Returns +/// +/// * `Result<(), Box>` - Ok if registration was successful, Err otherwise +pub fn register_redisclient_module(engine: &mut Engine) -> Result<(), Box> { + // Register basic Redis operations + engine.register_fn("redis_ping", redis_ping); + engine.register_fn("redis_set", redis_set); + engine.register_fn("redis_get", redis_get); + engine.register_fn("redis_del", redis_del); + + // Register hash operations + engine.register_fn("redis_hset", redis_hset); + engine.register_fn("redis_hget", redis_hget); + engine.register_fn("redis_hgetall", redis_hgetall); + engine.register_fn("redis_hdel", redis_hdel); + + // Register list operations + engine.register_fn("redis_rpush", redis_rpush); + engine.register_fn("redis_lpush", redis_lpush); + engine.register_fn("redis_llen", redis_llen); + engine.register_fn("redis_lrange", redis_lrange); + + // Register other operations + engine.register_fn("redis_reset", redis_reset); + + Ok(()) +} + +/// Ping the Redis server +/// +/// # Returns +/// +/// * `Result>` - "PONG" if successful, error otherwise +pub fn redis_ping() -> Result> { + let mut cmd = redis::cmd("PING"); + redisclient::execute(&mut cmd).map_err(|e| { + Box::new(EvalAltResult::ErrorRuntime( + format!("Redis error: {}", e).into(), + rhai::Position::NONE, + )) + }) +} + +/// Set a key-value pair in Redis +/// +/// # Arguments +/// +/// * `key` - The key to set +/// * `value` - The value to set +/// +/// # Returns +/// +/// * `Result>` - true if successful, error otherwise +pub fn redis_set(key: &str, value: &str) -> Result> { + let mut cmd = redis::cmd("SET"); + cmd.arg(key).arg(value); + let result: redis::RedisResult = redisclient::execute(&mut cmd); + match result { + Ok(s) if s == "OK" => Ok(true), + Ok(_) => Ok(false), + Err(e) => Err(Box::new(EvalAltResult::ErrorRuntime( + format!("Redis error: {}", e).into(), + rhai::Position::NONE, + ))), + } +} + +/// Get a value from Redis by key +/// +/// # Arguments +/// +/// * `key` - The key to get +/// +/// # Returns +/// +/// * `Result>` - The value if found, empty string if not found, error otherwise +pub fn redis_get(key: &str) -> Result> { + let mut cmd = redis::cmd("GET"); + cmd.arg(key); + let result: redis::RedisResult> = redisclient::execute(&mut cmd); + match result { + Ok(Some(value)) => Ok(value), + Ok(None) => Ok(String::new()), + Err(e) => Err(Box::new(EvalAltResult::ErrorRuntime( + format!("Redis error: {}", e).into(), + rhai::Position::NONE, + ))), + } +} + +/// Delete a key from Redis +/// +/// # Arguments +/// +/// * `key` - The key to delete +/// +/// # Returns +/// +/// * `Result>` - true if successful, error otherwise +pub fn redis_del(key: &str) -> Result> { + let mut cmd = redis::cmd("DEL"); + cmd.arg(key); + let result: redis::RedisResult = redisclient::execute(&mut cmd); + match result { + Ok(n) => Ok(n > 0), + Err(e) => Err(Box::new(EvalAltResult::ErrorRuntime( + format!("Redis error: {}", e).into(), + rhai::Position::NONE, + ))), + } +} + +/// Set a field in a hash +/// +/// # Arguments +/// +/// * `key` - The hash key +/// * `field` - The field to set +/// * `value` - The value to set +/// +/// # Returns +/// +/// * `Result>` - true if successful, error otherwise +pub fn redis_hset(key: &str, field: &str, value: &str) -> Result> { + let mut cmd = redis::cmd("HSET"); + cmd.arg(key).arg(field).arg(value); + let result: redis::RedisResult = redisclient::execute(&mut cmd); + match result { + Ok(_) => Ok(true), + Err(e) => Err(Box::new(EvalAltResult::ErrorRuntime( + format!("Redis error: {}", e).into(), + rhai::Position::NONE, + ))), + } +} + +/// Get a field from a hash +/// +/// # Arguments +/// +/// * `key` - The hash key +/// * `field` - The field to get +/// +/// # Returns +/// +/// * `Result>` - The value if found, empty string if not found, error otherwise +pub fn redis_hget(key: &str, field: &str) -> Result> { + let mut cmd = redis::cmd("HGET"); + cmd.arg(key).arg(field); + let result: redis::RedisResult> = redisclient::execute(&mut cmd); + match result { + Ok(Some(value)) => Ok(value), + Ok(None) => Ok(String::new()), + Err(e) => Err(Box::new(EvalAltResult::ErrorRuntime( + format!("Redis error: {}", e).into(), + rhai::Position::NONE, + ))), + } +} + +/// Get all fields and values from a hash +/// +/// # Arguments +/// +/// * `key` - The hash key +/// +/// # Returns +/// +/// * `Result>` - A map of field-value pairs, error otherwise +pub fn redis_hgetall(key: &str) -> Result> { + let mut cmd = redis::cmd("HGETALL"); + cmd.arg(key); + let result: redis::RedisResult> = redisclient::execute(&mut cmd); + match result { + Ok(hash_map) => { + let mut map = Map::new(); + for (k, v) in hash_map { + map.insert(k.into(), v.into()); + } + Ok(map) + } + Err(e) => Err(Box::new(EvalAltResult::ErrorRuntime( + format!("Redis error: {}", e).into(), + rhai::Position::NONE, + ))), + } +} + +/// Delete a field from a hash +/// +/// # Arguments +/// +/// * `key` - The hash key +/// * `field` - The field to delete +/// +/// # Returns +/// +/// * `Result>` - true if successful, error otherwise +pub fn redis_hdel(key: &str, field: &str) -> Result> { + let mut cmd = redis::cmd("HDEL"); + cmd.arg(key).arg(field); + let result: redis::RedisResult = redisclient::execute(&mut cmd); + match result { + Ok(n) => Ok(n > 0), + Err(e) => Err(Box::new(EvalAltResult::ErrorRuntime( + format!("Redis error: {}", e).into(), + rhai::Position::NONE, + ))), + } +} + +/// Push an element to the end of a list +/// +/// # Arguments +/// +/// * `key` - The list key +/// * `value` - The value to push +/// +/// # Returns +/// +/// * `Result>` - The new length of the list, error otherwise +pub fn redis_rpush(key: &str, value: &str) -> Result> { + let mut cmd = redis::cmd("RPUSH"); + cmd.arg(key).arg(value); + redisclient::execute(&mut cmd).map_err(|e| { + Box::new(EvalAltResult::ErrorRuntime( + format!("Redis error: {}", e).into(), + rhai::Position::NONE, + )) + }) +} + +/// Push an element to the beginning of a list +/// +/// # Arguments +/// +/// * `key` - The list key +/// * `value` - The value to push +/// +/// # Returns +/// +/// * `Result>` - The new length of the list, error otherwise +pub fn redis_lpush(key: &str, value: &str) -> Result> { + let mut cmd = redis::cmd("LPUSH"); + cmd.arg(key).arg(value); + redisclient::execute(&mut cmd).map_err(|e| { + Box::new(EvalAltResult::ErrorRuntime( + format!("Redis error: {}", e).into(), + rhai::Position::NONE, + )) + }) +} + +/// Get the length of a list +/// +/// # Arguments +/// +/// * `key` - The list key +/// +/// # Returns +/// +/// * `Result>` - The length of the list, error otherwise +pub fn redis_llen(key: &str) -> Result> { + let mut cmd = redis::cmd("LLEN"); + cmd.arg(key); + redisclient::execute(&mut cmd).map_err(|e| { + Box::new(EvalAltResult::ErrorRuntime( + format!("Redis error: {}", e).into(), + rhai::Position::NONE, + )) + }) +} + +/// Get a range of elements from a list +/// +/// # Arguments +/// +/// * `key` - The list key +/// * `start` - The start index +/// * `stop` - The stop index +/// +/// # Returns +/// +/// * `Result, Box>` - The elements in the range, error otherwise +pub fn redis_lrange(key: &str, start: i64, stop: i64) -> Result, Box> { + let mut cmd = redis::cmd("LRANGE"); + cmd.arg(key).arg(start).arg(stop); + redisclient::execute(&mut cmd).map_err(|e| { + Box::new(EvalAltResult::ErrorRuntime( + format!("Redis error: {}", e).into(), + rhai::Position::NONE, + )) + }) +} + +/// Reset the Redis client connection +/// +/// # Returns +/// +/// * `Result>` - true if successful, error otherwise +pub fn redis_reset() -> Result> { + match redisclient::reset() { + Ok(_) => Ok(true), + Err(e) => Err(Box::new(EvalAltResult::ErrorRuntime( + format!("Redis error: {}", e).into(), + rhai::Position::NONE, + ))), + } +} diff --git a/src/rhai_tests/redisclient/01_redis_connection.rhai b/src/rhai_tests/redisclient/01_redis_connection.rhai new file mode 100644 index 0000000..6ab8aef --- /dev/null +++ b/src/rhai_tests/redisclient/01_redis_connection.rhai @@ -0,0 +1,68 @@ +// 01_redis_connection.rhai +// Tests for Redis client connection and basic operations + +// Custom assert function +fn assert_true(condition, message) { + if !condition { + print(`ASSERTION FAILED: ${message}`); + throw message; + } +} + +// Helper function to check if Redis is available +fn is_redis_available() { + try { + // Try to execute a simple PING command + let ping_result = redis_ping(); + return ping_result == "PONG"; + } catch(err) { + print(`Redis connection error: ${err}`); + return false; + } +} + +print("=== Testing Redis Client Connection ==="); + +// Check if Redis is available +let redis_available = is_redis_available(); +if !redis_available { + print("Redis server is not available. Skipping Redis tests."); + // Exit gracefully without error + return; +} + +print("✓ Redis server is available"); + +// Test redis_ping function +print("Testing redis_ping()..."); +let ping_result = redis_ping(); +assert_true(ping_result == "PONG", "PING should return PONG"); +print(`✓ redis_ping(): Returned ${ping_result}`); + +// Test redis_set and redis_get functions +print("Testing redis_set() and redis_get()..."); +let test_key = "rhai_test_key"; +let test_value = "Hello from Rhai test"; + +// Set a value +let set_result = redis_set(test_key, test_value); +assert_true(set_result, "SET operation should succeed"); +print(`✓ redis_set(): Successfully set key ${test_key}`); + +// Get the value back +let get_result = redis_get(test_key); +assert_true(get_result == test_value, "GET should return the value we set"); +print(`✓ redis_get(): Successfully retrieved value for key ${test_key}`); + +// Test redis_del function +print("Testing redis_del()..."); +let del_result = redis_del(test_key); +assert_true(del_result, "DEL operation should succeed"); +print(`✓ redis_del(): Successfully deleted key ${test_key}`); + +// Verify the key was deleted +let get_after_del = redis_get(test_key); +assert_true(get_after_del == "", "Key should not exist after deletion"); +print("✓ Key was successfully deleted"); + +print("All Redis connection tests completed successfully!"); diff --git a/src/rhai_tests/redisclient/02_redis_operations.rhai b/src/rhai_tests/redisclient/02_redis_operations.rhai new file mode 100644 index 0000000..ad23dac --- /dev/null +++ b/src/rhai_tests/redisclient/02_redis_operations.rhai @@ -0,0 +1,109 @@ +// 02_redis_operations.rhai +// Tests for advanced Redis operations + +// Custom assert function +fn assert_true(condition, message) { + if !condition { + print(`ASSERTION FAILED: ${message}`); + throw message; + } +} + +// Helper function to check if Redis is available +fn is_redis_available() { + try { + // Try to execute a simple PING command + let ping_result = redis_ping(); + return ping_result == "PONG"; + } catch(err) { + print(`Redis connection error: ${err}`); + return false; + } +} + +print("=== Testing Advanced Redis Operations ==="); + +// Check if Redis is available +let redis_available = is_redis_available(); +if !redis_available { + print("Redis server is not available. Skipping Redis tests."); + // Exit gracefully without error + return; +} + +print("✓ Redis server is available"); + +// Test prefix for all keys to avoid conflicts +let prefix = "rhai_test_"; + +// Test redis_hset and redis_hget functions +print("Testing redis_hset() and redis_hget()..."); +let hash_key = prefix + "hash"; +let field1 = "field1"; +let value1 = "value1"; +let field2 = "field2"; +let value2 = "value2"; + +// Set hash fields +let hset_result1 = redis_hset(hash_key, field1, value1); +assert_true(hset_result1, "HSET operation should succeed for field1"); +let hset_result2 = redis_hset(hash_key, field2, value2); +assert_true(hset_result2, "HSET operation should succeed for field2"); +print(`✓ redis_hset(): Successfully set fields in hash ${hash_key}`); + +// Get hash fields +let hget_result1 = redis_hget(hash_key, field1); +assert_true(hget_result1 == value1, "HGET should return the value we set for field1"); +let hget_result2 = redis_hget(hash_key, field2); +assert_true(hget_result2 == value2, "HGET should return the value we set for field2"); +print(`✓ redis_hget(): Successfully retrieved values from hash ${hash_key}`); + +// Test redis_hgetall function +print("Testing redis_hgetall()..."); +let hgetall_result = redis_hgetall(hash_key); +assert_true(hgetall_result.len() == 2, "HGETALL should return 2 fields"); +assert_true(hgetall_result[field1] == value1, "HGETALL should include field1 with correct value"); +assert_true(hgetall_result[field2] == value2, "HGETALL should include field2 with correct value"); +print(`✓ redis_hgetall(): Successfully retrieved all fields from hash ${hash_key}`); + +// Test redis_hdel function +print("Testing redis_hdel()..."); +let hdel_result = redis_hdel(hash_key, field1); +assert_true(hdel_result, "HDEL operation should succeed"); +print(`✓ redis_hdel(): Successfully deleted field from hash ${hash_key}`); + +// Verify the field was deleted +let hget_after_del = redis_hget(hash_key, field1); +assert_true(hget_after_del == "", "Field should not exist after deletion"); +print("✓ Field was successfully deleted from hash"); + +// Test redis_list operations +print("Testing redis list operations..."); +let list_key = prefix + "list"; + +// Push items to list +let rpush_result = redis_rpush(list_key, "item1"); +assert_true(rpush_result > 0, "RPUSH operation should succeed"); +redis_rpush(list_key, "item2"); +redis_rpush(list_key, "item3"); +print(`✓ redis_rpush(): Successfully pushed items to list ${list_key}`); + +// Get list length +let llen_result = redis_llen(list_key); +assert_true(llen_result == 3, "List should have 3 items"); +print(`✓ redis_llen(): List has ${llen_result} items`); + +// Get list range +let lrange_result = redis_lrange(list_key, 0, -1); +assert_true(lrange_result.len() == 3, "LRANGE should return 3 items"); +assert_true(lrange_result[0] == "item1", "First item should be 'item1'"); +assert_true(lrange_result[2] == "item3", "Last item should be 'item3'"); +print(`✓ redis_lrange(): Successfully retrieved all items from list ${list_key}`); + +// Clean up +print("Cleaning up..."); +redis_del(hash_key); +redis_del(list_key); +print("✓ Cleanup: All test keys removed"); + +print("All Redis operations tests completed successfully!"); diff --git a/src/rhai_tests/redisclient/run_all_tests.rhai b/src/rhai_tests/redisclient/run_all_tests.rhai new file mode 100644 index 0000000..d19e98d --- /dev/null +++ b/src/rhai_tests/redisclient/run_all_tests.rhai @@ -0,0 +1,121 @@ +// run_all_tests.rhai +// Runs all Redis client module tests + +print("=== Running Redis Client Module Tests ==="); + +// Custom assert function +fn assert_true(condition, message) { + if !condition { + print(`ASSERTION FAILED: ${message}`); + throw message; + } +} + +// Helper function to check if Redis is available +fn is_redis_available() { + try { + // Try to execute a simple PING command + let ping_result = redis_ping(); + return ping_result == "PONG"; + } catch(err) { + print(`Redis connection error: ${err}`); + return false; + } +} + +// Run each test directly +let passed = 0; +let failed = 0; +let skipped = 0; + +// Check if Redis is available +let redis_available = is_redis_available(); +if !redis_available { + print("Redis server is not available. Skipping all Redis tests."); + skipped = 2; // Skip both tests +} else { + // Test 1: Redis Connection + print("\n--- Running Redis Connection Tests ---"); + try { + // Test redis_ping function + print("Testing redis_ping()..."); + let ping_result = redis_ping(); + assert_true(ping_result == "PONG", "PING should return PONG"); + print(`✓ redis_ping(): Returned ${ping_result}`); + + // Test redis_set and redis_get functions + print("Testing redis_set() and redis_get()..."); + let test_key = "rhai_test_key"; + let test_value = "Hello from Rhai test"; + + // Set a value + let set_result = redis_set(test_key, test_value); + assert_true(set_result, "SET operation should succeed"); + print(`✓ redis_set(): Successfully set key ${test_key}`); + + // Get the value back + let get_result = redis_get(test_key); + assert_true(get_result == test_value, "GET should return the value we set"); + print(`✓ redis_get(): Successfully retrieved value for key ${test_key}`); + + // Clean up + redis_del(test_key); + + print("--- Redis Connection Tests completed successfully ---"); + passed += 1; + } catch(err) { + print(`!!! Error in Redis Connection Tests: ${err}`); + failed += 1; + } + + // Test 2: Redis Operations + print("\n--- Running Redis Operations Tests ---"); + try { + // Test prefix for all keys to avoid conflicts + let prefix = "rhai_test_"; + + // Test redis_hset and redis_hget functions + print("Testing redis_hset() and redis_hget()..."); + let hash_key = prefix + "hash"; + let field = "field1"; + let value = "value1"; + + // Set hash field + let hset_result = redis_hset(hash_key, field, value); + assert_true(hset_result, "HSET operation should succeed"); + print(`✓ redis_hset(): Successfully set field in hash ${hash_key}`); + + // Get hash field + let hget_result = redis_hget(hash_key, field); + assert_true(hget_result == value, "HGET should return the value we set"); + print(`✓ redis_hget(): Successfully retrieved value from hash ${hash_key}`); + + // Clean up + redis_del(hash_key); + + print("--- Redis Operations Tests completed successfully ---"); + passed += 1; + } catch(err) { + print(`!!! Error in Redis Operations Tests: ${err}`); + failed += 1; + } +} + +print("\n=== Test Summary ==="); +print(`Passed: ${passed}`); +print(`Failed: ${failed}`); +print(`Skipped: ${skipped}`); +print(`Total: ${passed + failed + skipped}`); + +if failed == 0 { + if skipped > 0 { + print("\n⚠️ All tests skipped or passed!"); + } else { + print("\n✅ All tests passed!"); + } +} else { + print("\n❌ Some tests failed!"); +} + +// Return the number of failed tests (0 means success) +failed;