Module: FakeDynamo::Validation

Included in:
DB, Filter, Item, Key, Table
Defined in:
lib/fake_dynamo/validation.rb

Instance Method Summary collapse

Instance Method Details

#add_errors(message) ⇒ Object



17
18
19
# File 'lib/fake_dynamo/validation.rb', line 17

def add_errors(message)
  @api_errors << message
end

#api_configObject



115
116
117
# File 'lib/fake_dynamo/validation.rb', line 115

def api_config
  @api_config ||= YAML.load_file(api_config_path)
end

#api_config_pathObject



119
120
121
# File 'lib/fake_dynamo/validation.rb', line 119

def api_config_path
  File.join File.expand_path(File.dirname(__FILE__)), 'api.yml'
end

#api_input_spec(operation) ⇒ Object



111
112
113
# File 'lib/fake_dynamo/validation.rb', line 111

def api_input_spec(operation)
  api_config[:operations][operation][:input]
end

#available_operationsObject



33
34
35
# File 'lib/fake_dynamo/validation.rb', line 33

def available_operations
  api_config[:operations].keys
end

#param(attribute, parents) ⇒ Object



107
108
109
# File 'lib/fake_dynamo/validation.rb', line 107

def param(attribute, parents)
  (parents + [attribute]).join('.')
end

#validate!(&block) ⇒ Object



6
7
8
9
10
11
12
13
14
# File 'lib/fake_dynamo/validation.rb', line 6

def validate!(&block)
  @api_errors = []
  yield
  unless @api_errors.empty?
    plural = @api_errors.size == 1 ? '' : 's'
    message = "#{@api_errors.size} error#{plural} detected: #{@api_errors.join('; ')}"
    raise ValidationException, message
  end
end

#validate_input(operation, data) ⇒ Object



37
38
39
40
41
# File 'lib/fake_dynamo/validation.rb', line 37

def validate_input(operation, data)
  api_input_spec(operation).each do |attribute, spec|
    validate_spec(attribute, data[attribute], spec, [])
  end
end

#validate_key_data(data, key_schema) ⇒ Object



144
145
146
147
148
149
150
151
152
153
# File 'lib/fake_dynamo/validation.rb', line 144

def validate_key_data(data, key_schema)
  validate_type(data['HashKeyElement'], key_schema.hash_key)

  if key_schema.range_key
    range_key = data['RangeKeyElement'] or raise ValidationException, "Missing the key RangeKeyElement in the Key"
    validate_type(range_key, key_schema.range_key)
  elsif data['RangeKeyElement']
    raise ValidationException, "RangeKeyElement is not present in the schema"
  end
end

#validate_key_schema(data, key_schema) ⇒ Object



134
135
136
137
138
139
140
141
142
# File 'lib/fake_dynamo/validation.rb', line 134

def validate_key_schema(data, key_schema)
  key = data[key_schema.hash_key.name] or raise ValidationException, "Missing the key #{key_schema.hash_key.name} in the item"
  validate_type(key, key_schema.hash_key)

  if key_schema.range_key
    range_key = data[key_schema.range_key.name] or raise ValidationException, "Missing the key #{key_schema.range_key.name} in the item"
    validate_type(range_key, key_schema.range_key)
  end
end

#validate_operation(operation) ⇒ Object



29
30
31
# File 'lib/fake_dynamo/validation.rb', line 29

def validate_operation(operation)
  raise UnknownOperationException, "Unknown operation: #{operation}" unless available_operations.include? operation
end

#validate_payload(operation, data) ⇒ Object



21
22
23
24
25
26
27
# File 'lib/fake_dynamo/validation.rb', line 21

def validate_payload(operation, data)
  validate! do
    validate_request_size(data)
    validate_operation(operation)
    validate_input(operation, data)
  end
end

#validate_request_size(data) ⇒ Object



155
156
157
158
159
# File 'lib/fake_dynamo/validation.rb', line 155

def validate_request_size(data)
  if data.to_s.bytesize > 1 * 1024 * 1024
    raise ValidationException, "Request size can't exceed 1 mb"
  end
end

#validate_spec(attribute, data, spec, parents) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
56
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
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/fake_dynamo/validation.rb', line 43

def validate_spec(attribute, data, spec, parents)
  if not data
    if spec.include?(:required)
      add_errors("value null at '#{param(attribute, parents)}' failed to satisfy the constraint: Member must not be null")
    end
    return
  end

  spec.each do |constrain|
    case constrain
    when :string
      add_errors("The parameter '#{param(attribute, parents)}' must be a string") unless data.kind_of? String
    when :long
      add_errors("The parameter '#{param(attribute, parents)}' must be a long") unless data.kind_of? Integer
    when :integer
      add_errors("The parameter '#{param(attribute, parents)}' must be a integer") unless data.kind_of? Integer
    when :boolean
      add_errors("The parameter '#{param(attribute, parents)}' must be a boolean") unless (data.kind_of? TrueClass or data.kind_of? FalseClass)
    when Hash
      new_parents = parents + [attribute]
      case constrain.keys.first
      when :pattern
        pattern = constrain[:pattern]
        unless data =~ pattern
          add_errors("The parameter '#{param(attribute, parents)}' should match the pattern #{pattern}")
        end
      when :within
        range = constrain[:within]
        unless range.include? data.size
          add_errors("The parameter '#{param(attribute, parents)}' value '#{data}' should be within #{range} characters")
        end
      when :enum
        enum = constrain[:enum]
        unless enum.include? data
          add_errors("Value '#{data}' at '#{param(attribute, parents)}' failed to satisfy the constraint: Member must satisfy enum values set: #{enum}")
        end
      when :structure
        structure = constrain[:structure]
        structure.each do |attribute, spec|
          validate_spec(attribute, data[attribute], spec, new_parents)
        end
      when :map
        map = constrain[:map]
        raise "#{param(attribute, parents)} must be a Hash" unless data.kind_of? Hash
        data.each do |key, value|
          validate_spec(key, key, map[:key], new_parents)
          validate_spec(key, value, map[:value], new_parents)
        end
      when :list
        raise "#{param(attribute, parents)} must be a Array" unless data.kind_of? Array
        data.each do |element|
          validate_spec(element, element, constrain[:list], new_parents)
        end
      else
        raise "Unhandled constraint #{constrain}"
      end
    when :required
      # handled earlier
    else
      raise "Unhandled constraint #{constrain}"
    end
  end
end

#validate_type(value, attribute) ⇒ Object



123
124
125
126
127
128
129
130
131
132
# File 'lib/fake_dynamo/validation.rb', line 123

def validate_type(value, attribute)
  if attribute.kind_of?(Attribute)
    expected_type = value.keys.first
    if expected_type != attribute.type
      raise ValidationException, "Type mismatch for key #{attribute.name}"
    end
  else
    raise 'Unknown attribute'
  end
end