familia 2.0.0.pre17 → 2.0.0.pre18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.rst +60 -0
- data/CLAUDE.md +9 -2
- data/Gemfile.lock +1 -1
- data/README.md +13 -0
- data/bin/irb +1 -1
- data/docs/guides/core-field-system.md +48 -26
- data/docs/migrating/v2.0.0-pre18.md +58 -0
- data/docs/qodo-merge-compliance.md +96 -0
- data/lib/familia/base.rb +0 -2
- data/lib/familia/connection/middleware.rb +58 -4
- data/lib/familia/connection.rb +1 -1
- data/lib/familia/data_type/{commands.rb → database_commands.rb} +2 -2
- data/lib/familia/data_type/serialization.rb +5 -5
- data/lib/familia/data_type.rb +2 -2
- data/lib/familia/encryption/encrypted_data.rb +12 -2
- data/lib/familia/encryption/manager.rb +11 -4
- data/lib/familia/features/autoloader.rb +3 -1
- data/lib/familia/features/encrypted_fields/encrypted_field_type.rb +11 -3
- data/lib/familia/features/relationships/indexing/multi_index_generators.rb +9 -9
- data/lib/familia/features/relationships/indexing/unique_index_generators.rb +41 -27
- data/lib/familia/features/safe_dump.rb +2 -3
- data/lib/familia/horreum/database_commands.rb +1 -1
- data/lib/familia/horreum/definition.rb +6 -37
- data/lib/familia/horreum/management.rb +17 -12
- data/lib/familia/horreum/persistence.rb +1 -1
- data/lib/familia/horreum/serialization.rb +91 -73
- data/lib/familia/horreum.rb +10 -6
- data/lib/familia/identifier_extractor.rb +60 -0
- data/lib/familia/logging.rb +271 -112
- data/lib/familia/refinements.rb +0 -1
- data/lib/familia/version.rb +1 -1
- data/lib/familia.rb +2 -2
- data/lib/middleware/{database_middleware.rb → database_logger.rb} +47 -14
- data/pr_agent.toml +31 -0
- data/pr_compliance_checklist.yaml +45 -0
- data/try/edge_cases/empty_identifiers_try.rb +1 -1
- data/try/edge_cases/hash_symbolization_try.rb +31 -31
- data/try/edge_cases/json_serialization_try.rb +2 -2
- data/try/edge_cases/legacy_data_detection/deserialization_edge_cases_try.rb +170 -0
- data/try/edge_cases/race_conditions_try.rb +1 -1
- data/try/edge_cases/reserved_keywords_try.rb +1 -1
- data/try/edge_cases/string_coercion_try.rb +1 -1
- data/try/edge_cases/ttl_side_effects_try.rb +1 -1
- data/try/features/encrypted_fields/aad_protection_try.rb +1 -1
- data/try/features/encrypted_fields/concealed_string_core_try.rb +1 -1
- data/try/features/encrypted_fields/context_isolation_try.rb +1 -1
- data/try/features/encrypted_fields/encrypted_fields_core_try.rb +1 -1
- data/try/features/encrypted_fields/encrypted_fields_integration_try.rb +1 -1
- data/try/features/encrypted_fields/encrypted_fields_no_cache_security_try.rb +1 -1
- data/try/features/encrypted_fields/encrypted_fields_security_try.rb +1 -1
- data/try/features/encrypted_fields/error_conditions_try.rb +1 -1
- data/try/features/encrypted_fields/fresh_key_derivation_try.rb +1 -1
- data/try/features/encrypted_fields/fresh_key_try.rb +1 -1
- data/try/features/encrypted_fields/key_rotation_try.rb +1 -1
- data/try/features/encrypted_fields/memory_security_try.rb +1 -1
- data/try/features/encrypted_fields/missing_current_key_version_try.rb +1 -1
- data/try/features/encrypted_fields/nonce_uniqueness_try.rb +1 -1
- data/try/features/encrypted_fields/secure_by_default_behavior_try.rb +1 -1
- data/try/features/encrypted_fields/thread_safety_try.rb +1 -1
- data/try/features/encrypted_fields/universal_serialization_safety_try.rb +1 -1
- data/try/{encryption → features/encryption}/config_persistence_try.rb +1 -1
- data/try/{encryption/encryption_core_try.rb → features/encryption/core_try.rb} +2 -2
- data/try/{encryption → features/encryption}/instance_variable_scope_try.rb +1 -1
- data/try/{encryption → features/encryption}/module_loading_try.rb +1 -1
- data/try/{encryption → features/encryption}/providers/aes_gcm_provider_try.rb +1 -1
- data/try/{encryption → features/encryption}/providers/xchacha20_poly1305_provider_try.rb +1 -1
- data/try/{encryption → features/encryption}/roundtrip_validation_try.rb +1 -1
- data/try/{encryption → features/encryption}/secure_memory_handling_try.rb +2 -2
- data/try/features/expiration/expiration_try.rb +1 -1
- data/try/features/external_identifier/external_identifier_try.rb +1 -1
- data/try/features/feature_dependencies_try.rb +1 -1
- data/try/features/feature_improvements_try.rb +1 -1
- data/try/features/object_identifier/object_identifier_integration_try.rb +1 -1
- data/try/features/object_identifier/object_identifier_try.rb +1 -1
- data/try/features/quantization/quantization_try.rb +1 -1
- data/try/features/real_feature_integration_try.rb +17 -14
- data/try/features/relationships/indexing_commands_verification_try.rb +8 -3
- data/try/features/relationships/indexing_try.rb +6 -1
- data/try/features/relationships/participation_commands_verification_spec.rb +1 -1
- data/try/features/relationships/participation_commands_verification_try.rb +4 -4
- data/try/features/relationships/participation_performance_improvements_try.rb +1 -1
- data/try/features/relationships/participation_reverse_index_try.rb +1 -1
- data/try/features/relationships/relationships_api_changes_try.rb +1 -1
- data/try/features/relationships/relationships_edge_cases_try.rb +3 -3
- data/try/features/relationships/relationships_performance_minimal_try.rb +1 -1
- data/try/features/relationships/relationships_performance_simple_try.rb +1 -1
- data/try/features/relationships/relationships_performance_try.rb +1 -1
- data/try/features/relationships/relationships_performance_working_try.rb +1 -1
- data/try/features/relationships/relationships_try.rb +1 -1
- data/try/features/safe_dump/safe_dump_advanced_try.rb +1 -1
- data/try/features/safe_dump/safe_dump_try.rb +1 -1
- data/try/features/transient_fields/redacted_string_try.rb +1 -1
- data/try/features/transient_fields/refresh_reset_try.rb +1 -1
- data/try/features/transient_fields/single_use_redacted_string_try.rb +1 -1
- data/try/features/transient_fields/transient_fields_core_try.rb +1 -1
- data/try/features/transient_fields/transient_fields_integration_try.rb +1 -1
- data/try/{connection → integration/connection}/fiber_context_preservation_try.rb +1 -1
- data/try/{connection → integration/connection}/handler_constraints_try.rb +1 -1
- data/try/{core → integration/connection}/isolated_dbclient_try.rb +1 -1
- data/try/integration/connection/middleware_reconnect_try.rb +87 -0
- data/try/{connection → integration/connection}/operation_mode_guards_try.rb +1 -1
- data/try/{connection → integration/connection}/pipeline_fallback_integration_try.rb +1 -1
- data/try/{core → integration/connection}/pools_try.rb +1 -1
- data/try/{connection → integration/connection}/responsibility_chain_tracking_try.rb +1 -1
- data/try/{connection → integration/connection}/transaction_fallback_integration_try.rb +1 -1
- data/try/{connection → integration/connection}/transaction_mode_permissive_try.rb +1 -1
- data/try/{connection → integration/connection}/transaction_mode_strict_try.rb +1 -1
- data/try/{connection → integration/connection}/transaction_mode_warn_try.rb +1 -1
- data/try/{connection → integration/connection}/transaction_modes_try.rb +1 -1
- data/try/{core → integration}/conventional_inheritance_try.rb +1 -1
- data/try/{core → integration}/create_method_try.rb +1 -1
- data/try/integration/cross_component_try.rb +1 -1
- data/try/{core → integration}/database_consistency_try.rb +11 -8
- data/try/{core → integration}/familia_extended_try.rb +1 -1
- data/try/{core → integration}/familia_members_methods_try.rb +1 -1
- data/try/{models → integration/models}/customer_safe_dump_try.rb +1 -1
- data/try/{models → integration/models}/customer_try.rb +1 -1
- data/try/{models → integration/models}/datatype_base_try.rb +1 -1
- data/try/{models → integration/models}/familia_object_try.rb +1 -1
- data/try/{core → integration}/persistence_operations_try.rb +1 -1
- data/try/integration/relationships_persistence_round_trip_try.rb +441 -0
- data/try/{configuration → integration}/scenarios_try.rb +1 -1
- data/try/{core → integration}/secure_identifier_try.rb +1 -1
- data/try/{core → integration}/verifiable_identifier_try.rb +1 -1
- data/try/performance/benchmarks_try.rb +2 -2
- data/try/support/benchmarks/deserialization_benchmark.rb +180 -0
- data/try/support/benchmarks/deserialization_correctness_test.rb +237 -0
- data/try/{helpers → support/helpers}/test_helpers.rb +12 -3
- data/try/{core → unit/core}/autoloader_try.rb +1 -1
- data/try/{core → unit/core}/base_enhancements_try.rb +1 -9
- data/try/{core → unit/core}/connection_try.rb +1 -1
- data/try/{core → unit/core}/errors_try.rb +1 -1
- data/try/{core → unit/core}/extensions_try.rb +1 -1
- data/try/unit/core/familia_logger_try.rb +110 -0
- data/try/{core → unit/core}/familia_try.rb +1 -1
- data/try/{core → unit/core}/middleware_try.rb +41 -1
- data/try/{core → unit/core}/settings_try.rb +1 -1
- data/try/{core → unit/core}/time_utils_try.rb +1 -1
- data/try/{core → unit/core}/tools_try.rb +1 -1
- data/try/{core → unit/core}/utils_try.rb +17 -14
- data/try/{data_types → unit/data_types}/boolean_try.rb +1 -1
- data/try/{data_types → unit/data_types}/counter_try.rb +1 -1
- data/try/{data_types → unit/data_types}/datatype_base_try.rb +1 -1
- data/try/{data_types → unit/data_types}/hash_try.rb +1 -1
- data/try/{data_types → unit/data_types}/list_try.rb +1 -1
- data/try/{data_types → unit/data_types}/lock_try.rb +1 -1
- data/try/{data_types → unit/data_types}/sorted_set_try.rb +1 -1
- data/try/{data_types → unit/data_types}/sorted_set_zadd_options_try.rb +1 -1
- data/try/{data_types → unit/data_types}/string_try.rb +1 -1
- data/try/{data_types → unit/data_types}/unsortedset_try.rb +1 -1
- data/try/{horreum → unit/horreum}/auto_indexing_on_save_try.rb +1 -1
- data/try/{horreum → unit/horreum}/base_try.rb +3 -3
- data/try/{horreum → unit/horreum}/class_methods_try.rb +1 -1
- data/try/{horreum → unit/horreum}/commands_try.rb +1 -1
- data/try/{horreum → unit/horreum}/defensive_initialization_try.rb +1 -1
- data/try/{horreum → unit/horreum}/destroy_related_fields_cleanup_try.rb +1 -1
- data/try/{horreum → unit/horreum}/enhanced_conflict_handling_try.rb +1 -1
- data/try/{horreum → unit/horreum}/field_categories_try.rb +27 -18
- data/try/{horreum → unit/horreum}/field_definition_try.rb +1 -1
- data/try/{horreum → unit/horreum}/initialization_try.rb +2 -2
- data/try/unit/horreum/json_type_preservation_try.rb +248 -0
- data/try/{horreum → unit/horreum}/relations_try.rb +1 -1
- data/try/{horreum → unit/horreum}/serialization_persistent_fields_try.rb +24 -18
- data/try/{horreum → unit/horreum}/serialization_try.rb +4 -4
- data/try/{horreum → unit/horreum}/settings_try.rb +1 -1
- data/try/{refinements → unit/refinements}/dear_json_array_methods_try.rb +1 -1
- data/try/{refinements → unit/refinements}/dear_json_hash_methods_try.rb +1 -1
- data/try/{refinements → unit/refinements}/time_literals_numeric_methods_try.rb +1 -1
- data/try/{refinements → unit/refinements}/time_literals_string_methods_try.rb +1 -1
- metadata +134 -125
- data/lib/familia/distinguisher.rb +0 -85
- data/lib/familia/refinements/logger_trace.rb +0 -60
- data/try/refinements/logger_trace_methods_try.rb +0 -44
- /data/try/{debugging → support/debugging}/README.md +0 -0
- /data/try/{debugging → support/debugging}/cache_behavior_tracer.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_aad_process.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_concealed_internal.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_concealed_reveal.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_context_aad.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_context_simple.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_cross_context.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_database_load.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_encrypted_json_check.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_encrypted_json_step_by_step.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_exists_lifecycle.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_field_decrypt.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_fresh_cross_context.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_load_path.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_method_definition.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_method_resolution.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_minimal.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_provider.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_secure_behavior.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_string_class.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_test.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_test_design.rb +0 -0
- /data/try/{debugging → support/debugging}/encryption_method_tracer.rb +0 -0
- /data/try/{debugging → support/debugging}/provider_diagnostics.rb +0 -0
- /data/try/{helpers → support/helpers}/test_cleanup.rb +0 -0
- /data/try/{memory → support/memory}/memory_basic_test.rb +0 -0
- /data/try/{memory → support/memory}/memory_detailed_test.rb +0 -0
- /data/try/{memory → support/memory}/memory_docker_ruby_dump.sh +0 -0
- /data/try/{memory → support/memory}/memory_search_for_string.rb +0 -0
- /data/try/{memory → support/memory}/test_actual_redactedstring_protection.rb +0 -0
- /data/try/{prototypes → support/prototypes}/atomic_saves_v1_context_proxy.rb +0 -0
- /data/try/{prototypes → support/prototypes}/atomic_saves_v2_connection_switching.rb +0 -0
- /data/try/{prototypes → support/prototypes}/atomic_saves_v3_connection_pool.rb +0 -0
- /data/try/{prototypes → support/prototypes}/atomic_saves_v4.rb +0 -0
- /data/try/{prototypes → support/prototypes}/lib/atomic_saves_v2_connection_switching_helpers.rb +0 -0
- /data/try/{prototypes → support/prototypes}/lib/atomic_saves_v3_connection_pool_helpers.rb +0 -0
- /data/try/{prototypes → support/prototypes}/pooling/README.md +0 -0
- /data/try/{prototypes → support/prototypes}/pooling/configurable_stress_test.rb +0 -0
- /data/try/{prototypes → support/prototypes}/pooling/lib/atomic_saves_v3_connection_pool_helpers.rb +0 -0
- /data/try/{prototypes → support/prototypes}/pooling/lib/connection_pool_metrics.rb +0 -0
- /data/try/{prototypes → support/prototypes}/pooling/lib/connection_pool_stress_test.rb +0 -0
- /data/try/{prototypes → support/prototypes}/pooling/lib/connection_pool_threading_models.rb +0 -0
- /data/try/{prototypes → support/prototypes}/pooling/lib/visualize_stress_results.rb +0 -0
- /data/try/{prototypes → support/prototypes}/pooling/pool_siege.rb +0 -0
- /data/try/{prototypes → support/prototypes}/pooling/run_stress_tests.rb +0 -0
@@ -4,7 +4,7 @@
|
|
4
4
|
# bug in Tryouts 3.1 that prevents the setup instance vars from
|
5
5
|
# being available to the testcases.
|
6
6
|
|
7
|
-
require_relative '../helpers/test_helpers'
|
7
|
+
require_relative '../support/helpers/test_helpers'
|
8
8
|
|
9
9
|
Familia.debug = false
|
10
10
|
|
@@ -25,22 +25,31 @@ end
|
|
25
25
|
@test_hash.keys
|
26
26
|
#=> ["name", "age", "nested"]
|
27
27
|
|
28
|
-
## After save and refresh, default behavior uses
|
28
|
+
## After save and refresh, default behavior uses string keys
|
29
29
|
@test_obj.refresh!
|
30
30
|
@test_obj.config.keys
|
31
|
-
#=> [
|
31
|
+
#=> ["name", "age", "nested"]
|
32
32
|
|
33
|
-
## Nested hash also has
|
34
|
-
@test_obj.config[
|
35
|
-
#=> [
|
33
|
+
## Nested hash also has string keys
|
34
|
+
@test_obj.config["nested"].keys
|
35
|
+
#=> ["theme"]
|
36
36
|
|
37
37
|
## Get raw JSON from Valkey/Redis
|
38
38
|
@raw_json = @test_obj.hget('config')
|
39
39
|
@raw_json.class
|
40
40
|
#=> String
|
41
41
|
|
42
|
-
## deserialize_value with default symbolize:
|
43
|
-
@
|
42
|
+
## deserialize_value with default symbolize: false returns string keys
|
43
|
+
@string_result_default = @test_obj.deserialize_value(@raw_json)
|
44
|
+
@string_result_default.keys
|
45
|
+
#=> ["name", "age", "nested"]
|
46
|
+
|
47
|
+
## Nested hash in default result also has string keys
|
48
|
+
@string_result_default["nested"].keys
|
49
|
+
#=> ["theme"]
|
50
|
+
|
51
|
+
## deserialize_value with symbolize: true returns symbol keys
|
52
|
+
@symbol_result = @test_obj.deserialize_value(@raw_json, symbolize: true)
|
44
53
|
@symbol_result.keys
|
45
54
|
#=> [:name, :age, :nested]
|
46
55
|
|
@@ -48,21 +57,12 @@ end
|
|
48
57
|
@symbol_result[:nested].keys
|
49
58
|
#=> [:theme]
|
50
59
|
|
51
|
-
##
|
52
|
-
@string_result = @test_obj.deserialize_value(@raw_json, symbolize: false)
|
53
|
-
@string_result.keys
|
54
|
-
#=> ["name", "age", "nested"]
|
55
|
-
|
56
|
-
## Nested hash in string result also has string keys
|
57
|
-
@string_result['nested'].keys
|
58
|
-
#=> ["theme"]
|
59
|
-
|
60
|
-
## Values are preserved correctly in both cases
|
60
|
+
## Values are preserved correctly with symbol keys
|
61
61
|
@symbol_result[:name]
|
62
62
|
#=> "John"
|
63
63
|
|
64
|
-
##
|
65
|
-
@
|
64
|
+
## Values are preserved correctly with string keys
|
65
|
+
@string_result_default['name']
|
66
66
|
#=> "John"
|
67
67
|
|
68
68
|
## Arrays are handled correctly too
|
@@ -71,27 +71,27 @@ end
|
|
71
71
|
@array_json = @test_obj.hget('config')
|
72
72
|
#=> "[{\"item\":\"value\"},\"string\",123]"
|
73
73
|
|
74
|
+
## Array with default (symbolize: false) keeps hash keys as strings
|
75
|
+
@string_array_default = @test_obj.deserialize_value(@array_json)
|
76
|
+
@string_array_default[0].keys
|
77
|
+
#=> ["item"]
|
78
|
+
|
74
79
|
## Array with symbolize: true converts hash keys to symbols
|
75
|
-
@symbol_array = @test_obj.deserialize_value(@array_json)
|
80
|
+
@symbol_array = @test_obj.deserialize_value(@array_json, symbolize: true)
|
76
81
|
@symbol_array[0].keys
|
77
82
|
#=> [:item]
|
78
83
|
|
79
|
-
##
|
80
|
-
@string_array = @test_obj.deserialize_value(@array_json, symbolize: false)
|
81
|
-
@string_array[0].keys
|
82
|
-
#=> ["item"]
|
83
|
-
|
84
|
-
## Non-hash/array values are returned as-is
|
84
|
+
## JSON-encoded string is parsed correctly
|
85
85
|
@test_obj.deserialize_value('"just a string"')
|
86
|
-
#=> "
|
86
|
+
#=> "just a string"
|
87
87
|
|
88
|
-
## Non-
|
88
|
+
## Non-JSON string returns as-is
|
89
89
|
@test_obj.deserialize_value('just a string')
|
90
90
|
#=> "just a string"
|
91
91
|
|
92
|
-
##
|
92
|
+
## JSON number is parsed to Integer
|
93
93
|
@test_obj.deserialize_value('42')
|
94
|
-
#=>
|
94
|
+
#=> 42
|
95
95
|
|
96
96
|
## Invalid JSON returns original string
|
97
97
|
@test_obj.deserialize_value('invalid json')
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# try/edge_cases/json_serialization_try.rb
|
2
2
|
|
3
|
-
require_relative '../helpers/test_helpers'
|
3
|
+
require_relative '../support/helpers/test_helpers'
|
4
4
|
|
5
5
|
Familia.debug = false
|
6
6
|
|
@@ -44,7 +44,7 @@ test_obj.simple = 'just a string'
|
|
44
44
|
test_obj.tags = %w[ruby valkey json familia]
|
45
45
|
test_obj.save
|
46
46
|
test_obj.hgetall
|
47
|
-
#=> {"id"=>"json_test_1", "config"=>"{\"theme\":\"dark\",\"notifications\":true,\"settings\":{\"volume\":80}}", "tags"=>"[\"ruby\",\"valkey\",\"json\",\"familia\"]", "simple"=>"just a string"}
|
47
|
+
#=> {"id"=>"\"json_test_1\"", "config"=>"{\"theme\":\"dark\",\"notifications\":true,\"settings\":{\"volume\":80}}", "tags"=>"[\"ruby\",\"valkey\",\"json\",\"familia\"]", "simple"=>"\"just a string\""}
|
48
48
|
|
49
49
|
## Test 4: Hash should be deserialized back to Hash
|
50
50
|
test_obj = JsonTest.new 'any_id_will_do'
|
@@ -0,0 +1,170 @@
|
|
1
|
+
# Edge case tests for deserialize_value with legacy data detection
|
2
|
+
#
|
3
|
+
# Tests the nuanced deserialization that distinguishes between:
|
4
|
+
# - Corrupted JSON (data that looks like JSON but fails to parse)
|
5
|
+
# - Legacy plain strings (data that was never JSON)
|
6
|
+
# - Valid JSON data
|
7
|
+
|
8
|
+
require_relative '../../../lib/familia'
|
9
|
+
require 'logger'
|
10
|
+
require 'stringio'
|
11
|
+
|
12
|
+
# Capture log output for verification
|
13
|
+
@log_output = StringIO.new
|
14
|
+
@original_logger = Familia.instance_variable_get(:@logger)
|
15
|
+
Familia.instance_variable_set(:@logger, Logger.new(@log_output))
|
16
|
+
Familia.instance_variable_get(:@logger).level = Logger::DEBUG
|
17
|
+
|
18
|
+
class TestModel < Familia::Horreum
|
19
|
+
identifier_field :test_id
|
20
|
+
field :test_id
|
21
|
+
field :data
|
22
|
+
end
|
23
|
+
|
24
|
+
@model = TestModel.new(test_id: "test1")
|
25
|
+
|
26
|
+
## Valid JSON number deserializes correctly
|
27
|
+
@result = @model.deserialize_value("123", field_name: :data)
|
28
|
+
@result
|
29
|
+
#=> 123
|
30
|
+
|
31
|
+
## Valid JSON boolean deserializes correctly
|
32
|
+
@result = @model.deserialize_value("true", field_name: :data)
|
33
|
+
@result
|
34
|
+
#=> true
|
35
|
+
|
36
|
+
## Valid JSON string deserializes correctly
|
37
|
+
@result = @model.deserialize_value('"hello"', field_name: :data)
|
38
|
+
@result
|
39
|
+
#=> "hello"
|
40
|
+
|
41
|
+
## Valid JSON array deserializes correctly
|
42
|
+
@result = @model.deserialize_value('[1,2,3]', field_name: :data)
|
43
|
+
@result
|
44
|
+
#=> [1, 2, 3]
|
45
|
+
|
46
|
+
## Valid JSON object deserializes correctly
|
47
|
+
@result = @model.deserialize_value('{"key":"value"}', field_name: :data)
|
48
|
+
@result
|
49
|
+
#=> {"key"=>"value"}
|
50
|
+
|
51
|
+
## Plain string (legacy data) returns as-is
|
52
|
+
@log_output = StringIO.new
|
53
|
+
Familia.instance_variable_set(:@logger, Logger.new(@log_output))
|
54
|
+
Familia.instance_variable_get(:@logger).level = Logger::DEBUG
|
55
|
+
@result = @model.deserialize_value("plain text", field_name: :data)
|
56
|
+
@result
|
57
|
+
#=> "plain text"
|
58
|
+
|
59
|
+
## Legacy data logs at debug level
|
60
|
+
@log_output.rewind
|
61
|
+
@log_content = @log_output.read
|
62
|
+
puts "LOG CONTENT: #{@log_content.inspect}" if ENV['DEBUG']
|
63
|
+
@log_content
|
64
|
+
#=~> /Legacy plain string/
|
65
|
+
|
66
|
+
## Corrupted JSON starting with { logs error
|
67
|
+
@log_output = StringIO.new
|
68
|
+
Familia.instance_variable_set(:@logger, Logger.new(@log_output))
|
69
|
+
Familia.instance_variable_get(:@logger).level = Logger::DEBUG
|
70
|
+
@result = @model.deserialize_value("{broken", field_name: :data)
|
71
|
+
@result
|
72
|
+
#=> "{broken"
|
73
|
+
|
74
|
+
## Corrupted JSON logs at error level
|
75
|
+
@log_output.rewind
|
76
|
+
@log_content = @log_output.read
|
77
|
+
puts "LOG CONTENT: #{@log_content.inspect}" if ENV['DEBUG']
|
78
|
+
@log_content.match?(/Corrupted JSON/)
|
79
|
+
#=> true
|
80
|
+
|
81
|
+
## Corrupted JSON starting with [ logs error
|
82
|
+
@log_output = StringIO.new
|
83
|
+
Familia.instance_variable_set(:@logger, Logger.new(@log_output))
|
84
|
+
Familia.instance_variable_get(:@logger).level = Logger::DEBUG
|
85
|
+
@result = @model.deserialize_value("[1,2,", field_name: :data)
|
86
|
+
@result
|
87
|
+
#=> "[1,2,"
|
88
|
+
|
89
|
+
## Corrupted array logs at error level
|
90
|
+
@log_output.rewind
|
91
|
+
@log_content = @log_output.read
|
92
|
+
@log_content.match?(/Corrupted JSON/)
|
93
|
+
#=> true
|
94
|
+
|
95
|
+
## Corrupted JSON starting with quote logs error
|
96
|
+
@log_output = StringIO.new
|
97
|
+
Familia.instance_variable_set(:@logger, Logger.new(@log_output))
|
98
|
+
Familia.instance_variable_get(:@logger).level = Logger::DEBUG
|
99
|
+
@result = @model.deserialize_value('"unterminated', field_name: :data)
|
100
|
+
@result
|
101
|
+
#=> '"unterminated'
|
102
|
+
|
103
|
+
## Unterminated string logs at error level
|
104
|
+
@log_output.rewind
|
105
|
+
@log_content = @log_output.read
|
106
|
+
@log_content.match?(/Corrupted JSON/)
|
107
|
+
#=> true
|
108
|
+
|
109
|
+
## Corrupted boolean-like value logs error
|
110
|
+
@log_output = StringIO.new
|
111
|
+
Familia.instance_variable_set(:@logger, Logger.new(@log_output))
|
112
|
+
Familia.instance_variable_get(:@logger).level = Logger::DEBUG
|
113
|
+
@result = @model.deserialize_value("true123", field_name: :data)
|
114
|
+
@result
|
115
|
+
#=> "true123"
|
116
|
+
|
117
|
+
## Plain text starting with 'true' is legacy data
|
118
|
+
@log_output.rewind
|
119
|
+
@log_content = @log_output.read
|
120
|
+
@log_content
|
121
|
+
#=~> /Legacy plain string/
|
122
|
+
|
123
|
+
## Field name context appears in error messages
|
124
|
+
@log_output = StringIO.new
|
125
|
+
Familia.instance_variable_set(:@logger, Logger.new(@log_output))
|
126
|
+
Familia.instance_variable_get(:@logger).level = Logger::DEBUG
|
127
|
+
@result = @model.deserialize_value("{broken", field_name: :important_field)
|
128
|
+
@log_output.rewind
|
129
|
+
@log_content = @log_output.read
|
130
|
+
@log_content.match?(/TestModel#important_field/)
|
131
|
+
#=> true
|
132
|
+
|
133
|
+
## dbkey context appears in error messages when available
|
134
|
+
@model.save
|
135
|
+
@log_output = StringIO.new
|
136
|
+
Familia.instance_variable_set(:@logger, Logger.new(@log_output))
|
137
|
+
Familia.instance_variable_get(:@logger).level = Logger::DEBUG
|
138
|
+
@result = @model.deserialize_value("{broken", field_name: :data)
|
139
|
+
@log_output.rewind
|
140
|
+
@log_content = @log_output.read
|
141
|
+
@log_content.match?(/#{Regexp.escape(@model.dbkey)}/)
|
142
|
+
#=> true
|
143
|
+
|
144
|
+
## Empty string returns nil
|
145
|
+
@result = @model.deserialize_value("", field_name: :data)
|
146
|
+
@result
|
147
|
+
#=> nil
|
148
|
+
|
149
|
+
## nil returns nil
|
150
|
+
@result = @model.deserialize_value(nil, field_name: :data)
|
151
|
+
@result
|
152
|
+
#=> nil
|
153
|
+
|
154
|
+
## JSON null deserializes to nil
|
155
|
+
@result = @model.deserialize_value("null", field_name: :data)
|
156
|
+
@result
|
157
|
+
#=> nil
|
158
|
+
|
159
|
+
## Symbolize option works with hash keys
|
160
|
+
@result = @model.deserialize_value('{"name":"test"}', symbolize: true, field_name: :data)
|
161
|
+
@result.keys.first.class
|
162
|
+
#=> Symbol
|
163
|
+
|
164
|
+
## Default keeps string keys
|
165
|
+
@result = @model.deserialize_value('{"name":"test"}', field_name: :data)
|
166
|
+
@result.keys.first.class
|
167
|
+
#=> String
|
168
|
+
|
169
|
+
# Teardown
|
170
|
+
Familia.instance_variable_set(:@logger, @original_logger)
|
@@ -3,7 +3,7 @@
|
|
3
3
|
# Security tests for the no-cache encryption strategy
|
4
4
|
# These tests verify that we maintain security properties by NOT caching derived keys
|
5
5
|
|
6
|
-
require_relative '../../helpers/test_helpers'
|
6
|
+
require_relative '../../support/helpers/test_helpers'
|
7
7
|
|
8
8
|
test_keys = {
|
9
9
|
v1: Base64.strict_encode64('a' * 32),
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'base64'
|
4
4
|
|
5
|
-
require_relative '../../helpers/test_helpers'
|
5
|
+
require_relative '../../support/helpers/test_helpers'
|
6
6
|
|
7
7
|
# This tryouts file is based on the premise that there is no current key
|
8
8
|
# version set. This is a global setting so if other tryouts rely on
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# try/encryption/encryption_core_try.rb
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
3
|
+
require_relative '../../support/helpers/test_helpers'
|
4
|
+
require_relative '../../../lib/familia/encryption'
|
5
5
|
require 'base64'
|
6
6
|
|
7
7
|
# Test constants will be redefined in each test since variables don't persist
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# try/encryption/secure_memory_handling_try.rb
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
3
|
+
require_relative '../../support/helpers/test_helpers'
|
4
|
+
require_relative '../../../lib/familia/encryption/providers/secure_xchacha20_poly1305_provider'
|
5
5
|
require 'base64'
|
6
6
|
|
7
7
|
# SETUP
|