Class: Maze::Schemas::ValidatorBase

Inherits:
Object
  • Object
show all
Defined in:
lib/maze/schemas/validator_base.rb

Direct Known Subclasses

ConfigValidator, ErrorValidator, TraceValidator

Constant Summary collapse

HEX_STRING_16 =
'^[A-Fa-f0-9]{16}$'
HEX_STRING_32 =
'^[A-Fa-f0-9]{32}$'
HOUR_TOLERANCE =

1 hour in nanoseconds

60 * 60 * 1000 * 1000 * 1000

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(request) ⇒ ValidatorBase

Creates the validator

@param request [Hash] The trace request to validate


22
23
24
25
26
27
28
# File 'lib/maze/schemas/validator_base.rb', line 22

def initialize(request)
  @headers = request[:request].header
  @body = request[:body]
  @schema_errors = request[:schema_errors]
  @success = nil
  @errors = []
end

Instance Attribute Details

#errorsObject (readonly)

An array of error messages if the validation failed

@returns [Array] The error messages


17
18
19
# File 'lib/maze/schemas/validator_base.rb', line 17

def errors
  @errors
end

#successObject (readonly)

Whether the payloads passed the validation, one of true, false, or nil (not run)

@returns [Boolean|nil] Whether the validation was successful


13
14
15
# File 'lib/maze/schemas/validator_base.rb', line 13

def success
  @success
end

Instance Method Details

#each_element_contains(container_path, path) ⇒ Object



61
62
63
64
65
66
67
68
69
70
# File 'lib/maze/schemas/validator_base.rb', line 61

def each_element_contains(container_path, path)
  containers = Maze::Helper.read_key_path(@body, container_path)
  containers.each_with_index do |container, index|
    element = Maze::Helper.read_key_path(container, path)
    if element.nil?
      @success = false
      @errors << "Required #{container_path} element #{path} was not present at index #{index}"
    end
  end
end

#each_element_contains_each(container_path, paths) ⇒ Object



76
77
78
# File 'lib/maze/schemas/validator_base.rb', line 76

def each_element_contains_each(container_path, paths)
  paths.each { |path| each_element_contains(container_path, path) }
end

#each_element_exists(paths) ⇒ Object



51
52
53
54
55
56
57
58
59
# File 'lib/maze/schemas/validator_base.rb', line 51

def each_element_exists(paths)
  if paths.kind_of?(Array)
    paths.each {|path| element_exists(path)}
  else
    $logger.warn("each_element_exists was called with a non-array value: '#{paths}'. Use element_exists instead.")
    element_exists(paths)
  end

end

#each_event_contains(path) ⇒ Object



72
73
74
# File 'lib/maze/schemas/validator_base.rb', line 72

def each_event_contains(path)
  each_element_contains('events', path)
end

#each_event_contains_each(paths) ⇒ Object



80
81
82
# File 'lib/maze/schemas/validator_base.rb', line 80

def each_event_contains_each(paths)
  paths.each { |path| each_event_contains(path) }
end

#element_a_greater_or_equal_element_b(path_a, path_b) ⇒ Object



106
107
108
109
110
111
112
113
# File 'lib/maze/schemas/validator_base.rb', line 106

def element_a_greater_or_equal_element_b(path_a, path_b)
  element_a = Maze::Helper.read_key_path(@body, path_a)
  element_b = Maze::Helper.read_key_path(@body, path_b)
  unless element_a && element_b && element_a >= element_b
    @success = false
    @errors << "Element '#{path_a}':'#{element_a}' was expected to be greater than or equal to '#{path_b}':'#{element_b}'"
  end
end

#element_exists(path) ⇒ Object



43
44
45
46
47
48
49
# File 'lib/maze/schemas/validator_base.rb', line 43

def element_exists(path)
  element = Maze::Helper.read_key_path(@body, path)
  if element.nil?
    @success = false
    @errors << "Element '#{path}' was not found"
  end
end

#element_has_value(path, value) ⇒ Object



35
36
37
38
39
40
41
# File 'lib/maze/schemas/validator_base.rb', line 35

def element_has_value(path, value)
  element = Maze::Helper.read_key_path(@body, path)
  if element.nil? || element != value
    @success = false
    @errors << "Element '#{path}' was expected to be '#{value}', was '#{element}'"
  end
end

#element_int_in_range(path, range) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/maze/schemas/validator_base.rb', line 93

def element_int_in_range(path, range)
  element_value = Maze::Helper.read_key_path(@body, path)
  if element_value.nil? || !element_value.kind_of?(Integer)
    @success = false
    @errors << "Element '#{path}' was expected to be an integer, was '#{element_value}'"
    return
  end
  unless range.include?(element_value)
    @success = false
    @errors << "Element '#{path}':'#{element_value}' was expected to be in the range '#{range}'"
  end
end

#regex_comparison(path, regex) ⇒ Object



84
85
86
87
88
89
90
91
# File 'lib/maze/schemas/validator_base.rb', line 84

def regex_comparison(path, regex)
  element_value = Maze::Helper.read_key_path(@body, path)
  expected = Regexp.new(regex)
  unless expected.match(element_value)
    @success = false
    @errors << "Element '#{path}' was expected to match the regex '#{regex}', but was '#{element_value}'"
  end
end

#validateObject



30
31
32
33
# File 'lib/maze/schemas/validator_base.rb', line 30

def validate
  # By default the validation will pass
  @success = true
end

#validate_header(name) ⇒ Object



136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/maze/schemas/validator_base.rb', line 136

def validate_header(name)
  begin
    value = @headers[name]
    if value.nil? || value.size > 1
      @success = false
      @errors << "Expected exactly one value for header #{name}, received #{value || 'nil'}"
    else
      yield value[0]
    end
  rescue => e
    @success = false
    @errors << "Error validating header #{name} with value #{value}: #{e.message}"
  end
end

#validate_timestamp(path, tolerance) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/maze/schemas/validator_base.rb', line 115

def validate_timestamp(path, tolerance)
  return unless Maze.config.span_timestamp_validation
  timestamp = Maze::Helper.read_key_path(@body, path)
  unless timestamp.kind_of?(String)
    @success = false
    @errors << "Timestamp was expected to be a string, was '#{timestamp.class.name}'"
    return
  end
  parsed_timestamp = timestamp.to_i
  unless parsed_timestamp > 0
    @success = false
    @errors << "Timestamp was expected to be a positive integer, was '#{parsed_timestamp}'"
    return
  end
  time_in_nanos = Time.now.to_i * 1000000000
  unless (time_in_nanos - parsed_timestamp).abs < tolerance
    @success = false
    @errors << "Timestamp was expected to be within #{tolerance} nanoseconds of the current time (#{time_in_nanos}), was '#{parsed_timestamp}'"
  end
end