Class: Familia::Validation::Validator

Inherits:
Object
  • Object
show all
Defined in:
lib/familia/validation/validator.rb

Overview

Main validation engine that orchestrates command recording and validation. Provides high-level interface for validating Redis operations against expectations with detailed reporting and atomicity verification.

Examples:

Basic validation

validator = Validator.new

result = validator.validate do |expect|
  # Define expectations
  expect.hset("user:123", "name", "John")
        .incr("counter")

  # Execute code under test
  user = User.new(id: "123", name: "John")
  user.save
  Counter.increment
end

puts result.valid? ? "PASS" : "FAIL"
puts result.detailed_report

Transaction validation

validator = Validator.new

result = validator.validate do |expect|
  expect.transaction do |tx|
    tx.hset("user:123", "name", "John")
      .incr("counter")
  end

  # Code should execute atomically
  Familia.transaction do |conn|
    conn.hset("user:123", "name", "John")
    conn.incr("counter")
  end
end

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Validator

Returns a new instance of Validator.



45
46
47
48
49
50
51
52
53
54
# File 'lib/familia/validation/validator.rb', line 45

def initialize(options = {})
  @options = {
    auto_register_middleware: true,
    strict_atomicity: true,
    performance_tracking: true,
    command_filtering: :all # :all, :familia_only, :custom
  }.merge(options)

  register_middleware if @options[:auto_register_middleware]
end

Instance Attribute Details

#optionsObject (readonly)

Returns the value of attribute options.



43
44
45
# File 'lib/familia/validation/validator.rb', line 43

def options
  @options
end

Instance Method Details

#analyze_performance(command_sequence) ⇒ Object

Performance analysis of recorded commands



157
158
159
# File 'lib/familia/validation/validator.rb', line 157

def analyze_performance(command_sequence)
  PerformanceAnalyzer.new(command_sequence).analyze
end

#assert_commands_executed(expected_commands, actual_commands = nil) ⇒ Object

Assert that specific commands were executed



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/familia/validation/validator.rb', line 136

def assert_commands_executed(expected_commands, actual_commands = nil)
  actual_commands ||= get_last_recorded_sequence

  expectations = CommandExpectations.new
  expected_commands.each do |cmd_spec|
    case cmd_spec
    when Array
      expectations.command(cmd_spec[0], *cmd_spec[1..-1])
    when Hash
      cmd_spec.each do |cmd, args|
        expectations.command(cmd, *Array(args))
      end
    when String
      expectations.match_pattern(cmd_spec)
    end
  end

  expectations.validate(actual_commands)
end

#capture_redis_commands(&block) ⇒ Object

Capture and return Redis commands without validation



162
163
164
165
166
167
# File 'lib/familia/validation/validator.rb', line 162

def capture_redis_commands(&block)
  CommandRecorder.start_recording
  register_middleware_if_needed
  block.call if block_given?
  CommandRecorder.stop_recording
end

#validate(&block) ⇒ Object

Main validation method - records commands and validates against expectations

Raises:

  • (ArgumentError)


57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/familia/validation/validator.rb', line 57

def validate(&block)
  raise ArgumentError, "Block required for validation" unless block_given?

  expectations = nil
  command_sequence = nil

  begin
    # Start recording commands
    CommandRecorder.start_recording
    register_middleware_if_needed

    # Execute the validation block
    expectations = CommandExpectations.new
    block.call(expectations)

    # Get recorded commands
    command_sequence = CommandRecorder.stop_recording

  rescue => e
    CommandRecorder.stop_recording
    raise ValidationError, "Validation failed with error: #{e.message}"
  end

  # Validate and return result
  result = expectations.validate(command_sequence)

  if @options[:performance_tracking]
    add_performance_metrics(result, command_sequence)
  end

  if @options[:strict_atomicity]
    apply_atomicity_validation(result, command_sequence)
  end

  result
end

#validate_atomicity(&block) ⇒ Object

Validate that code executes atomically (within transactions)



120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/familia/validation/validator.rb', line 120

def validate_atomicity(&block)
  CommandRecorder.start_recording
  register_middleware_if_needed

  begin
    block.call
    command_sequence = CommandRecorder.stop_recording
  rescue => e
    CommandRecorder.stop_recording
    raise ValidationError, "Atomicity validation failed: #{e.message}"
  end

  AtomicityValidator.new(command_sequence, @options).validate
end

#validate_execution(expectations_block, execution_block) ⇒ Object

Validate that specific code executes expected Redis commands



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/familia/validation/validator.rb', line 95

def validate_execution(expectations_block, execution_block)
  expectations = CommandExpectations.new
  expectations_block.call(expectations)

  CommandRecorder.start_recording
  register_middleware_if_needed

  begin
    execution_block.call
    command_sequence = CommandRecorder.stop_recording
  rescue => e
    CommandRecorder.stop_recording
    raise ValidationError, "Execution failed: #{e.message}"
  end

  result = expectations.validate(command_sequence)

  if @options[:performance_tracking]
    add_performance_metrics(result, command_sequence)
  end

  result
end