kvstore.rs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. //! Tests for KV store validation requirements
  2. #[cfg(test)]
  3. mod tests {
  4. use crate::database::mint::{
  5. validate_kvstore_params, validate_kvstore_string, KVSTORE_NAMESPACE_KEY_ALPHABET,
  6. KVSTORE_NAMESPACE_KEY_MAX_LEN,
  7. };
  8. #[test]
  9. fn test_validate_kvstore_string_valid_inputs() {
  10. // Test valid strings
  11. assert!(validate_kvstore_string("").is_ok());
  12. assert!(validate_kvstore_string("abc").is_ok());
  13. assert!(validate_kvstore_string("ABC").is_ok());
  14. assert!(validate_kvstore_string("123").is_ok());
  15. assert!(validate_kvstore_string("test_key").is_ok());
  16. assert!(validate_kvstore_string("test-key").is_ok());
  17. assert!(validate_kvstore_string("test_KEY-123").is_ok());
  18. // Test max length string
  19. let max_length_str = "a".repeat(KVSTORE_NAMESPACE_KEY_MAX_LEN);
  20. assert!(validate_kvstore_string(&max_length_str).is_ok());
  21. }
  22. #[test]
  23. fn test_validate_kvstore_string_invalid_length() {
  24. // Test string too long
  25. let too_long_str = "a".repeat(KVSTORE_NAMESPACE_KEY_MAX_LEN + 1);
  26. let result = validate_kvstore_string(&too_long_str);
  27. assert!(result.is_err());
  28. assert!(result
  29. .unwrap_err()
  30. .to_string()
  31. .contains("exceeds maximum length"));
  32. }
  33. #[test]
  34. fn test_validate_kvstore_string_invalid_characters() {
  35. // Test invalid characters
  36. let invalid_chars = vec![
  37. "test@key", // @
  38. "test key", // space
  39. "test.key", // .
  40. "test/key", // /
  41. "test\\key", // \
  42. "test+key", // +
  43. "test=key", // =
  44. "test!key", // !
  45. "test#key", // #
  46. "test$key", // $
  47. "test%key", // %
  48. "test&key", // &
  49. "test*key", // *
  50. "test(key", // (
  51. "test)key", // )
  52. "test[key", // [
  53. "test]key", // ]
  54. "test{key", // {
  55. "test}key", // }
  56. "test|key", // |
  57. "test;key", // ;
  58. "test:key", // :
  59. "test'key", // '
  60. "test\"key", // "
  61. "test<key", // <
  62. "test>key", // >
  63. "test,key", // ,
  64. "test?key", // ?
  65. "test~key", // ~
  66. "test`key", // `
  67. ];
  68. for invalid_str in invalid_chars {
  69. let result = validate_kvstore_string(invalid_str);
  70. assert!(result.is_err(), "Expected '{}' to be invalid", invalid_str);
  71. assert!(result
  72. .unwrap_err()
  73. .to_string()
  74. .contains("invalid characters"));
  75. }
  76. }
  77. #[test]
  78. fn test_validate_kvstore_params_valid() {
  79. // Test valid parameter combinations
  80. assert!(validate_kvstore_params("primary", "secondary", Some("key")).is_ok());
  81. assert!(validate_kvstore_params("primary", "", Some("key")).is_ok());
  82. assert!(validate_kvstore_params("", "", Some("key")).is_ok());
  83. assert!(validate_kvstore_params("p1", "s1", Some("different_key")).is_ok());
  84. }
  85. #[test]
  86. fn test_validate_kvstore_params_empty_namespace_rules() {
  87. // Test empty namespace rules: if primary is empty, secondary must be empty too
  88. let result = validate_kvstore_params("", "secondary", Some("key"));
  89. assert!(result.is_err());
  90. assert!(result
  91. .unwrap_err()
  92. .to_string()
  93. .contains("If primary_namespace is empty"));
  94. }
  95. #[test]
  96. fn test_validate_kvstore_params_collision_prevention() {
  97. // Test collision prevention between keys and namespaces
  98. let test_cases = vec![
  99. ("primary", "secondary", "primary"), // key matches primary namespace
  100. ("primary", "secondary", "secondary"), // key matches secondary namespace
  101. ];
  102. for (primary, secondary, key) in test_cases {
  103. let result = validate_kvstore_params(primary, secondary, Some(key));
  104. assert!(
  105. result.is_err(),
  106. "Expected collision for key '{}' with namespaces '{}'/'{}'",
  107. key,
  108. primary,
  109. secondary
  110. );
  111. let error_msg = result.unwrap_err().to_string();
  112. assert!(error_msg.contains("conflicts with namespace"));
  113. }
  114. // Test that a combined namespace string would be invalid due to the slash character
  115. let result = validate_kvstore_params("primary", "secondary", Some("primary_secondary"));
  116. assert!(result.is_ok(), "This should be valid - no actual collision");
  117. }
  118. #[test]
  119. fn test_validate_kvstore_params_invalid_strings() {
  120. // Test invalid characters in any parameter
  121. let result = validate_kvstore_params("primary@", "secondary", Some("key"));
  122. assert!(result.is_err());
  123. let result = validate_kvstore_params("primary", "secondary!", Some("key"));
  124. assert!(result.is_err());
  125. let result = validate_kvstore_params("primary", "secondary", Some("key with space"));
  126. assert!(result.is_err());
  127. }
  128. #[test]
  129. fn test_alphabet_constants() {
  130. // Verify the alphabet constant is as expected
  131. assert_eq!(
  132. KVSTORE_NAMESPACE_KEY_ALPHABET,
  133. "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-"
  134. );
  135. assert_eq!(KVSTORE_NAMESPACE_KEY_MAX_LEN, 120);
  136. }
  137. #[test]
  138. fn test_alphabet_coverage() {
  139. // Test that all valid characters are actually accepted
  140. for ch in KVSTORE_NAMESPACE_KEY_ALPHABET.chars() {
  141. let test_str = ch.to_string();
  142. assert!(
  143. validate_kvstore_string(&test_str).is_ok(),
  144. "Character '{}' should be valid",
  145. ch
  146. );
  147. }
  148. }
  149. #[test]
  150. fn test_namespace_segmentation_examples() {
  151. // Test realistic namespace segmentation scenarios
  152. // Valid segmentation examples
  153. let valid_examples = vec![
  154. ("wallets", "user123", "balance"),
  155. ("quotes", "mint", "quote_12345"),
  156. ("keysets", "", "active_keyset"),
  157. ("", "", "global_config"),
  158. ("auth", "session_456", "token"),
  159. ("mint_info", "", "version"),
  160. ];
  161. for (primary, secondary, key) in valid_examples {
  162. assert!(
  163. validate_kvstore_params(primary, secondary, Some(key)).is_ok(),
  164. "Valid example should pass: '{}'/'{}'/'{}'",
  165. primary,
  166. secondary,
  167. key
  168. );
  169. }
  170. }
  171. #[test]
  172. fn test_per_namespace_uniqueness() {
  173. // This test documents the requirement that implementations should ensure
  174. // per-namespace key uniqueness. The validation function doesn't enforce
  175. // database-level uniqueness (that's handled by the database schema),
  176. // but ensures naming conflicts don't occur between keys and namespaces.
  177. // These should be valid (different namespaces)
  178. assert!(validate_kvstore_params("ns1", "sub1", Some("key1")).is_ok());
  179. assert!(validate_kvstore_params("ns2", "sub1", Some("key1")).is_ok()); // same key, different primary namespace
  180. assert!(validate_kvstore_params("ns1", "sub2", Some("key1")).is_ok()); // same key, different secondary namespace
  181. // These should fail (collision within namespace)
  182. assert!(validate_kvstore_params("ns1", "sub1", Some("ns1")).is_err()); // key conflicts with primary namespace
  183. assert!(validate_kvstore_params("ns1", "sub1", Some("sub1")).is_err()); // key conflicts with secondary namespace
  184. }
  185. }