schemata-dea 0.0.1.beta18 → 0.0.1.beta20
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/schemata/common/error.rb +34 -9
- data/lib/schemata/common/msgbase.rb +119 -126
- data/lib/schemata/common/msgtypebase.rb +11 -10
- data/lib/schemata/common/parsed_msg.rb +4 -4
- data/lib/schemata/dea/version.rb +1 -1
- data/lib/schemata/helpers.rb +1 -0
- data/lib/schemata/helpers/stringify.rb +7 -10
- data/spec/common/error_spec.rb +90 -0
- data/spec/common/helpers_spec.rb +0 -25
- data/spec/common/msgbase_spec.rb +162 -0
- data/spec/common/parsed_msg_spec.rb +3 -3
- data/spec/component/component_foo_spec.rb +9 -9
- data/spec/helpers/stringify_spec.rb +72 -0
- metadata +8 -1
@@ -1,18 +1,43 @@
|
|
1
1
|
module Schemata
|
2
|
-
class
|
3
|
-
class EncodeError < StandardError; end
|
4
|
-
class SchemaDefinitionError < StandardError; end
|
2
|
+
class Error < StandardError
|
5
3
|
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
attr_reader :source_exception, :source_backtrace
|
5
|
+
|
6
|
+
def initialize(source_exception = $!, message = nil)
|
7
|
+
message = source_exception.message if message.nil? && source_exception
|
8
|
+
super(message)
|
9
|
+
if source_exception
|
10
|
+
@source_exception = source_exception
|
11
|
+
@source_backtrace = source_exception.backtrace || []
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def backtrace
|
16
|
+
self_backtrace = super
|
17
|
+
self_backtrace && source_backtrace ? self_backtrace + source_backtrace : self_backtrace
|
9
18
|
end
|
10
19
|
end
|
11
20
|
|
12
|
-
class
|
21
|
+
class DecodeError < Error; end
|
22
|
+
class EncodeError < Error; end
|
23
|
+
class SchemaDefinitionError < Error; end
|
24
|
+
|
25
|
+
class UpdateAttributeError < Error
|
26
|
+
attr_reader :key
|
27
|
+
|
28
|
+
def initialize(key, exception = $!)
|
29
|
+
super(exception, "#{key}: #{exception.message}")
|
30
|
+
@key = key
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class IncompatibleVersionError < Error
|
35
|
+
attr_reader :msg_version, :component_version
|
36
|
+
|
13
37
|
def initialize(msg_version, component_version)
|
14
|
-
super("min message version #{msg_version} too high for component
|
15
|
-
|
38
|
+
super(self, "min message version #{msg_version} too high for component version #{component_version}")
|
39
|
+
@msg_version = msg_version
|
40
|
+
@component_version = component_version
|
16
41
|
end
|
17
42
|
end
|
18
43
|
end
|
@@ -10,31 +10,18 @@ module Schemata
|
|
10
10
|
class ValidatingContainer
|
11
11
|
def initialize(data = {})
|
12
12
|
data ||= {}
|
13
|
-
@schema = self.class.const_get(:SCHEMA)
|
14
13
|
@contents = {}
|
15
14
|
|
16
15
|
data.each do |key, field_value|
|
17
|
-
key = Schemata::Helpers.
|
18
|
-
field_schema =
|
16
|
+
key = Schemata::Helpers.stringify_symbols(key) # TODO see test
|
17
|
+
field_schema = schema.schemas[key]
|
19
18
|
next unless field_schema
|
20
19
|
|
21
|
-
# TODO This call to stringify should be removed when cc/dea stop using
|
22
|
-
# Symbols.
|
23
|
-
#
|
24
|
-
# Currently, some fields (for example, 'states' in requests sent
|
25
|
-
# on dea.find.droplet), are are symbols, During Yajl decoding, however,
|
26
|
-
# they become strings. Thus, on the encoding side, Schemata should expect
|
27
|
-
# symbols, but on the decoding side, it should expect strings. To allow
|
28
|
-
# for this in the schema definition, Schemata stringifies all symbols during
|
29
|
-
# construction of Schemata objects.
|
30
|
-
field_value = Schemata::Helpers.stringify(field_value)
|
31
|
-
|
32
20
|
begin
|
33
|
-
field_schema
|
21
|
+
field_value = validate_field(field_schema, key, field_value)
|
34
22
|
rescue Membrane::SchemaValidationError => e
|
35
|
-
raise Schemata::UpdateAttributeError.new(key, e
|
23
|
+
raise Schemata::UpdateAttributeError.new(key, e)
|
36
24
|
end
|
37
|
-
|
38
25
|
@contents[key] = Schemata::Helpers.deep_copy(field_value)
|
39
26
|
end
|
40
27
|
end
|
@@ -50,17 +37,9 @@ module Schemata
|
|
50
37
|
nil
|
51
38
|
end
|
52
39
|
|
53
|
-
|
54
|
-
# symbols. See comment above for a better description.
|
40
|
+
|
55
41
|
vc_klass.send(:define_method, "#{key}=") do |field_value|
|
56
|
-
field_value =
|
57
|
-
unless schema.optional_keys.include?(key) && field_value == nil
|
58
|
-
begin
|
59
|
-
field_schema.validate(field_value)
|
60
|
-
rescue Membrane::SchemaValidationError => e
|
61
|
-
raise Schemata::UpdateAttributeError.new(key, e.message)
|
62
|
-
end
|
63
|
-
end
|
42
|
+
field_value = validate_field(field_schema, key, field_value)
|
64
43
|
@contents[key] = Schemata::Helpers.deep_copy(field_value)
|
65
44
|
field_value
|
66
45
|
end
|
@@ -77,7 +56,23 @@ module Schemata
|
|
77
56
|
end
|
78
57
|
|
79
58
|
def validate
|
80
|
-
|
59
|
+
schema.schemas.each do |key, field_schema|
|
60
|
+
validate_field(field_schema, key, @contents[key])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def validate_field(field_schema, key, field_value)
|
67
|
+
field_value = Schemata::Helpers.stringify_symbols(field_value) # TODO see test
|
68
|
+
unless schema.optional_keys.include?(key) && field_value == nil
|
69
|
+
field_schema.validate(field_value)
|
70
|
+
end
|
71
|
+
field_value
|
72
|
+
end
|
73
|
+
|
74
|
+
def schema
|
75
|
+
self.class.const_get(:SCHEMA)
|
81
76
|
end
|
82
77
|
end
|
83
78
|
|
@@ -86,7 +81,7 @@ module Schemata
|
|
86
81
|
end
|
87
82
|
|
88
83
|
def aux_vc_klass
|
89
|
-
|
84
|
+
self.class.const_get(:AUX_VC_KLASS) if self.class.aux_schema
|
90
85
|
end
|
91
86
|
|
92
87
|
def initialize(msg_data_hash = nil, aux_data_hash = nil)
|
@@ -101,10 +96,10 @@ module Schemata
|
|
101
96
|
validate_contents
|
102
97
|
validate_aux_data
|
103
98
|
rescue Membrane::SchemaValidationError => e
|
104
|
-
raise Schemata::EncodeError.new(e
|
99
|
+
raise Schemata::EncodeError.new(e)
|
105
100
|
end
|
106
101
|
|
107
|
-
|
102
|
+
message_type
|
108
103
|
curr_version = self.class.version
|
109
104
|
min_version = self.class::MIN_VERSION_ALLOWED
|
110
105
|
|
@@ -146,140 +141,138 @@ module Schemata
|
|
146
141
|
end
|
147
142
|
|
148
143
|
def message_type
|
149
|
-
_, component, msg_type,
|
144
|
+
_, component, msg_type, _ = self.class.name.split("::")
|
150
145
|
Schemata::const_get(component)::const_get(msg_type)
|
151
146
|
end
|
152
147
|
|
153
148
|
def component
|
154
|
-
|
149
|
+
component = self.class.name.split("::")[1]
|
155
150
|
Schemata::const_get(component)
|
156
151
|
end
|
157
152
|
|
158
153
|
def self.included(klass)
|
159
|
-
klass.extend(Schemata::ClassMethods)
|
160
|
-
klass.extend(Dsl)
|
154
|
+
klass.extend(Schemata::MessageBase::ClassMethods)
|
155
|
+
klass.extend(Schemata::MessageBase::Dsl)
|
161
156
|
end
|
162
|
-
end
|
163
157
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
158
|
+
module ClassMethods
|
159
|
+
def mock
|
160
|
+
mock = {}
|
161
|
+
mock_values.keys.each do |k|
|
162
|
+
value = mock_values[k]
|
163
|
+
mock[k] = value.respond_to?("call") ? value.call : value
|
164
|
+
end
|
165
|
+
self.new(mock)
|
170
166
|
end
|
171
|
-
self.new(mock)
|
172
|
-
end
|
173
|
-
|
174
|
-
def schema
|
175
|
-
self::SCHEMA
|
176
|
-
end
|
177
|
-
|
178
|
-
def aux_schema
|
179
|
-
return self::AUX_SCHEMA if defined?(self::AUX_SCHEMA)
|
180
|
-
end
|
181
|
-
|
182
|
-
def mock_values
|
183
|
-
self::MOCK_VALUES
|
184
|
-
end
|
185
167
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
end
|
168
|
+
def schema
|
169
|
+
self::SCHEMA
|
170
|
+
end
|
190
171
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
Schemata::const_get(component)::const_get(msg_type)::
|
195
|
-
const_get("V#{version}")
|
196
|
-
end
|
197
|
-
end
|
172
|
+
def aux_schema
|
173
|
+
return self::AUX_SCHEMA if defined?(self::AUX_SCHEMA)
|
174
|
+
end
|
198
175
|
|
199
|
-
|
200
|
-
|
201
|
-
schema = Membrane::SchemaParser.parse(&blk)
|
202
|
-
unless schema.kind_of? Membrane::Schema::Record
|
203
|
-
Schemata::SchemaDefinitionError.new("Schema must be a hash")
|
176
|
+
def mock_values
|
177
|
+
self::MOCK_VALUES
|
204
178
|
end
|
205
|
-
self::const_set(:SCHEMA, schema)
|
206
|
-
end
|
207
179
|
|
208
|
-
|
209
|
-
|
210
|
-
unless aux_schema.kind_of? Membrane::Schema::Record
|
211
|
-
Schemata::SchemaDefinitionError.new("Schema must be a hash")
|
180
|
+
def version
|
181
|
+
self.name.split("::")[-1][1..-1].to_i
|
212
182
|
end
|
213
183
|
|
214
|
-
|
184
|
+
def previous_version
|
185
|
+
_, component, msg_type, version = self.name.split("::")
|
186
|
+
version = version[1..-1].to_i - 1
|
187
|
+
Schemata::const_get(component)::const_get(msg_type)::const_get("V#{version}")
|
188
|
+
end
|
215
189
|
end
|
216
190
|
|
217
|
-
|
218
|
-
|
219
|
-
|
191
|
+
module Dsl
|
192
|
+
def define_schema(&blk)
|
193
|
+
schema = Membrane::SchemaParser.parse(&blk)
|
194
|
+
unless schema.kind_of? Membrane::Schema::Record
|
195
|
+
raise Schemata::SchemaDefinitionError.new(nil, "Schema must be a hash")
|
196
|
+
end
|
197
|
+
self::const_set(:SCHEMA, schema)
|
220
198
|
end
|
221
|
-
const_set(:MIN_VERSION_ALLOWED, min_version)
|
222
|
-
end
|
223
199
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
begin
|
229
|
-
previous_version::SCHEMA.validate(old_data)
|
230
|
-
rescue Membrane::SchemaValidationError => e
|
231
|
-
raise Schemata::DecodeError.new(e.message)
|
200
|
+
def define_aux_schema(&blk)
|
201
|
+
aux_schema = Membrane::SchemaParser.parse(&blk)
|
202
|
+
unless aux_schema.kind_of? Membrane::Schema::Record
|
203
|
+
raise Schemata::SchemaDefinitionError.new(nil, "Schema must be a hash")
|
232
204
|
end
|
233
205
|
|
234
|
-
|
206
|
+
self::const_set(:AUX_SCHEMA, aux_schema)
|
235
207
|
end
|
236
|
-
end
|
237
208
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
raise Schemata::DecodeError.new("Necessary aux_data missing")
|
209
|
+
def define_min_version(min_version)
|
210
|
+
unless min_version.is_a? Integer
|
211
|
+
raise SchemaDefinitionError.new(nil, "Min version must be an integer")
|
242
212
|
end
|
243
|
-
|
213
|
+
const_set(:MIN_VERSION_ALLOWED, min_version)
|
214
|
+
end
|
244
215
|
|
245
|
-
|
246
|
-
|
247
|
-
|
216
|
+
def define_upvert(&blk)
|
217
|
+
eigenclass.send(:define_method, :upvert) do |old_data|
|
218
|
+
# No need to validate aux_data because upvert is only called during
|
219
|
+
# decode, when aux_data is irrelevant
|
220
|
+
begin
|
221
|
+
previous_version::SCHEMA.validate(old_data)
|
222
|
+
rescue Membrane::SchemaValidationError => e
|
223
|
+
raise Schemata::DecodeError.new(e)
|
224
|
+
end
|
248
225
|
|
249
|
-
|
250
|
-
|
226
|
+
blk.call(old_data)
|
227
|
+
end
|
251
228
|
end
|
252
|
-
end
|
253
229
|
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
230
|
+
def define_generate_old_fields(&blk)
|
231
|
+
self.send(:define_method, :generate_old_fields) do
|
232
|
+
if self.class.aux_schema && aux_data.empty?
|
233
|
+
raise Schemata::DecodeError.new(nil, "Necessary aux_data missing")
|
234
|
+
end
|
235
|
+
old_fields = blk.call(self)
|
236
|
+
|
237
|
+
msg_contents = contents
|
238
|
+
msg_contents.update(old_fields)
|
239
|
+
msg_obj = self.class.previous_version.new(msg_contents)
|
240
|
+
|
241
|
+
msg_obj.validate_contents
|
242
|
+
return msg_obj, old_fields
|
243
|
+
end
|
258
244
|
end
|
259
245
|
|
260
|
-
hash
|
246
|
+
def define_mock_values(hash=nil, &blk)
|
247
|
+
if (hash && blk) || (!hash && !blk)
|
248
|
+
# value defined twice or not at all
|
249
|
+
raise SchemaDefinitionError.new(nil, "Mock values incorrectly defined")
|
250
|
+
end
|
251
|
+
|
252
|
+
hash = blk.call if blk
|
261
253
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
254
|
+
# Validate a sample of the mock values.
|
255
|
+
mock = {}
|
256
|
+
hash.each do |key, value|
|
257
|
+
mock[key] = value.respond_to?("call") ? value.call : value
|
258
|
+
end
|
259
|
+
|
260
|
+
begin
|
261
|
+
self.schema.validate(mock)
|
262
|
+
define_constant(:MOCK_VALUES, hash)
|
263
|
+
rescue Membrane::SchemaValidationError => e
|
264
|
+
raise SchemaDefinitionError.new(nil, "Sample mock values do not match schema: #{e}")
|
265
|
+
end
|
266
266
|
end
|
267
267
|
|
268
|
-
|
269
|
-
self.
|
270
|
-
define_constant(:MOCK_VALUES, hash)
|
271
|
-
rescue Membrane::SchemaValidationError => e
|
272
|
-
raise SchemaDefinitionError.new("Sample mock values do not match schema: #{e}")
|
268
|
+
def define_constant(constant_name, constant_value)
|
269
|
+
self.const_set(constant_name, constant_value)
|
273
270
|
end
|
274
|
-
end
|
275
271
|
|
276
|
-
|
277
|
-
|
278
|
-
|
272
|
+
def include_preschemata
|
273
|
+
define_constant(:INCLUDE_PRESCHEMATA, true)
|
274
|
+
end
|
279
275
|
|
280
|
-
def include_preschemata
|
281
|
-
define_constant(:INCLUDE_PRESCHEMATA, true)
|
282
276
|
end
|
283
|
-
|
284
277
|
end
|
285
278
|
end
|
@@ -60,9 +60,9 @@ module Schemata
|
|
60
60
|
# We don't validate aux data in decode.
|
61
61
|
return msg_obj
|
62
62
|
rescue Schemata::UpdateAttributeError => e
|
63
|
-
raise Schemata::DecodeError.new(e
|
63
|
+
raise Schemata::DecodeError.new(e)
|
64
64
|
rescue Membrane::SchemaValidationError => e
|
65
|
-
raise Schemata::DecodeError.new(e
|
65
|
+
raise Schemata::DecodeError.new(e)
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
@@ -124,12 +124,14 @@ module Schemata
|
|
124
124
|
end
|
125
125
|
|
126
126
|
# Define attribute accessors for the message class
|
127
|
-
klass.schema.schemas.each do |key,
|
128
|
-
klass.send(:define_method, key)
|
129
|
-
@contents.send(key)
|
130
|
-
end
|
127
|
+
klass.schema.schemas.each do |key, _|
|
128
|
+
klass.send(:define_method, key) { @contents.send(key) }
|
131
129
|
klass.send(:define_method, "#{key}=") do |field_value|
|
132
|
-
|
130
|
+
begin
|
131
|
+
@contents.send("#{key}=", field_value)
|
132
|
+
rescue Membrane::SchemaValidationError => e
|
133
|
+
raise Schemata::UpdateAttributeError.new(key, e)
|
134
|
+
end
|
133
135
|
end
|
134
136
|
end
|
135
137
|
self::const_set("V#{v}", klass)
|
@@ -144,9 +146,8 @@ module Schemata
|
|
144
146
|
msg_obj = current_class.new(msg_contents)
|
145
147
|
msg_obj.validate_contents
|
146
148
|
return msg_obj
|
147
|
-
rescue Schemata::UpdateAttributeError,
|
148
|
-
|
149
|
-
raise Schemata::DecodeError.new(e.message)
|
149
|
+
rescue Schemata::UpdateAttributeError, Membrane::SchemaValidationError => e
|
150
|
+
raise Schemata::DecodeError.new(e)
|
150
151
|
end
|
151
152
|
end
|
152
153
|
|
@@ -12,24 +12,24 @@ module Schemata
|
|
12
12
|
|
13
13
|
@min_version = @contents['min_version']
|
14
14
|
if !@min_version
|
15
|
-
raise DecodeError.new("Field 'min_version' abset from message")
|
15
|
+
raise DecodeError.new(nil, "Field 'min_version' abset from message")
|
16
16
|
end
|
17
17
|
|
18
18
|
versions = []
|
19
19
|
@contents.keys.each do |k|
|
20
20
|
next if k == 'min_version'
|
21
21
|
unless k =~ /^V[0-9]+$/
|
22
|
-
raise DecodeError.new("Invalid key: #{k}")
|
22
|
+
raise DecodeError.new(nil, "Invalid key: #{k}")
|
23
23
|
end
|
24
24
|
versions << k[1..-1].to_i
|
25
25
|
end
|
26
26
|
|
27
27
|
if versions.empty?
|
28
|
-
raise DecodeError.new("Message contains no versioned hashes")
|
28
|
+
raise DecodeError.new(nil, "Message contains no versioned hashes")
|
29
29
|
end
|
30
30
|
|
31
31
|
if Set.new(versions.min..versions.max) != Set.new(versions)
|
32
|
-
raise DecodeError.new("There are versions missing between\
|
32
|
+
raise DecodeError.new(nil, "There are versions missing between\
|
33
33
|
#{versions.min} and #{versions.max}")
|
34
34
|
end
|
35
35
|
|
data/lib/schemata/dea/version.rb
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
Dir[File.expand_path("../helpers/*.rb", __FILE__)].each { |file| require file }
|
@@ -1,24 +1,21 @@
|
|
1
1
|
module Schemata
|
2
2
|
module Helpers
|
3
|
+
class StringifyError < StandardError; end
|
3
4
|
|
4
|
-
def self.
|
5
|
+
def self.stringify_symbols(node)
|
5
6
|
case node
|
6
|
-
when String
|
7
|
-
return node
|
8
|
-
when Numeric, TrueClass, FalseClass
|
9
|
-
return node
|
10
7
|
when Hash
|
11
8
|
copy = {}
|
12
|
-
node.each { |k, v| copy[k.to_s] =
|
9
|
+
node.each { |k, v| copy[k.to_s] = stringify_symbols(v) }
|
13
10
|
return copy
|
14
11
|
when Array
|
15
|
-
return node.map { |v|
|
16
|
-
when NilClass
|
17
|
-
return nil
|
12
|
+
return node.map { |v| stringify_symbols(v) }
|
18
13
|
when Symbol
|
19
14
|
return node.to_s
|
15
|
+
when String, Numeric, TrueClass, FalseClass, NilClass
|
16
|
+
return node
|
20
17
|
else
|
21
|
-
raise
|
18
|
+
raise StringifyError.new("Unexpected class: #{node.class}")
|
22
19
|
end
|
23
20
|
end
|
24
21
|
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'schemata/common/error'
|
3
|
+
|
4
|
+
describe Schemata do
|
5
|
+
let(:backtrace) { %w(foo bar) }
|
6
|
+
let(:message) { "message" }
|
7
|
+
let(:exception) do
|
8
|
+
error = StandardError.new(message)
|
9
|
+
error.set_backtrace backtrace
|
10
|
+
error
|
11
|
+
end
|
12
|
+
|
13
|
+
describe Schemata::Error do
|
14
|
+
context 'when an exception is explicitly passed in' do
|
15
|
+
context 'and a message is not passed in' do
|
16
|
+
subject { Schemata::Error.new(exception) }
|
17
|
+
|
18
|
+
its(:message) { should eq message }
|
19
|
+
its(:backtrace) { should be_nil }
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'and a message is passed in' do
|
23
|
+
subject { Schemata::Error.new(exception, "other message") }
|
24
|
+
|
25
|
+
its(:message) { should eq "other message" }
|
26
|
+
its(:backtrace) { should be_nil }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when no exception is passed in' do
|
31
|
+
context 'and it is a reraise' do
|
32
|
+
subject do
|
33
|
+
error = nil
|
34
|
+
begin
|
35
|
+
begin
|
36
|
+
raise exception
|
37
|
+
rescue
|
38
|
+
raise Schemata::Error.new
|
39
|
+
end
|
40
|
+
rescue => e
|
41
|
+
error = e
|
42
|
+
end
|
43
|
+
error
|
44
|
+
end
|
45
|
+
|
46
|
+
its(:message) { should eq message }
|
47
|
+
its(:source_backtrace) { should eq backtrace }
|
48
|
+
|
49
|
+
it 'includes the re raised exception' do
|
50
|
+
expect(subject.backtrace.first).to match /error_spec\.rb/
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'includes the chained exception' do
|
54
|
+
expect(subject.backtrace.last).to eq "bar"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'and it is a standlone exception' do
|
59
|
+
subject { Schemata::Error.new(nil, message) }
|
60
|
+
|
61
|
+
its(:message) { should eq message }
|
62
|
+
its(:backtrace) { should be_nil }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe Schemata::UpdateAttributeError do
|
68
|
+
let(:key) { "key" }
|
69
|
+
subject { Schemata::UpdateAttributeError.new(key, exception) }
|
70
|
+
|
71
|
+
its(:message) { should eq "#{key}: #{message}" }
|
72
|
+
its(:to_s) { should eq "#{key}: #{message}" }
|
73
|
+
its(:key) { should eq key }
|
74
|
+
its(:backtrace) { should be_nil }
|
75
|
+
end
|
76
|
+
|
77
|
+
describe Schemata::IncompatibleVersionError do
|
78
|
+
let(:msg_version) { 1 }
|
79
|
+
let(:component_version) { 2 }
|
80
|
+
|
81
|
+
subject { Schemata::IncompatibleVersionError.new(msg_version, component_version) }
|
82
|
+
|
83
|
+
its(:message) { should eq "min message version #{msg_version} too high for component version #{component_version}" }
|
84
|
+
its(:to_s) { should eq "min message version #{msg_version} too high for component version #{component_version}" }
|
85
|
+
its(:msg_version) { should eq msg_version }
|
86
|
+
its(:component_version) { should eq component_version }
|
87
|
+
its(:backtrace) { should be_nil }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
data/spec/common/helpers_spec.rb
CHANGED
@@ -87,29 +87,4 @@ describe Schemata::Helpers do
|
|
87
87
|
end.to raise_error(described_class::CopyError, /Unexpected class: /)
|
88
88
|
end
|
89
89
|
end
|
90
|
-
|
91
|
-
describe "#stringify" do
|
92
|
-
it "should stringify nil" do
|
93
|
-
str = Schemata::Helpers.stringify(nil)
|
94
|
-
str.should == nil
|
95
|
-
end
|
96
|
-
|
97
|
-
it "should stringify a string" do
|
98
|
-
original = "foo"
|
99
|
-
str = Schemata::Helpers.stringify(original)
|
100
|
-
str.should == "foo"
|
101
|
-
end
|
102
|
-
|
103
|
-
it "should stringify a symbol" do
|
104
|
-
original = :foo
|
105
|
-
str = Schemata::Helpers.stringify(original)
|
106
|
-
str.should == "foo"
|
107
|
-
end
|
108
|
-
|
109
|
-
it "should stringify a hash" do
|
110
|
-
original = { "foo" => :foo }
|
111
|
-
str = Schemata::Helpers.stringify(original)
|
112
|
-
str.should == { "foo" => "foo" }
|
113
|
-
end
|
114
|
-
end
|
115
90
|
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'membrane'
|
3
|
+
require 'schemata/helpers'
|
4
|
+
require 'schemata/common/msgbase'
|
5
|
+
|
6
|
+
describe Schemata::MessageBase do
|
7
|
+
describe Schemata::MessageBase::ValidatingContainer do
|
8
|
+
let(:data) { {"required" => "value"} }
|
9
|
+
let(:validating_container) { Schemata::MessageBase::ValidatingContainer.define(schema) }
|
10
|
+
let(:instance_validating_container) { validating_container.new(data) }
|
11
|
+
let(:schema) do
|
12
|
+
Membrane::SchemaParser.parse do
|
13
|
+
{
|
14
|
+
"required" => String,
|
15
|
+
optional("optional") => String
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe ".new" do
|
21
|
+
context 'when the field is an optional attribute' do
|
22
|
+
let(:data) { {:optional => nil} }
|
23
|
+
it 'allows it to be set to nil' do
|
24
|
+
expect(instance_validating_container.optional).to be_nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when the keys are string in the data" do
|
29
|
+
it { expect(instance_validating_container.required).to eq "value" }
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when keys are symbols in the data due to DEA inconsistencies" do
|
33
|
+
let(:data) { {:required => "value"} }
|
34
|
+
|
35
|
+
it 'stringifies them temporarily' do
|
36
|
+
# TODO Yajl decodes keys become strings. Thus, on the encoding side, Schemata should allow symbols,
|
37
|
+
# but on the decoding side, it should expect strings. E.g. states in dea.find.droplet
|
38
|
+
expect(instance_validating_container.required).to eq "value"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe ".define" do
|
44
|
+
context 'when the field is required' do
|
45
|
+
it "doesn't it to be set to nil" do
|
46
|
+
expect { instance_validating_container.required = nil }.to raise_error Membrane::SchemaValidationError
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'when the field is an optional attribute' do
|
51
|
+
it 'allows it to be set to nil' do
|
52
|
+
expect { instance_validating_container.optional = nil }.not_to raise_error
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '#validate' do
|
58
|
+
let(:required) { "foo" }
|
59
|
+
let(:optional) { "bar" }
|
60
|
+
|
61
|
+
subject do
|
62
|
+
instance_validating_container.required = required
|
63
|
+
instance_validating_container.optional = optional
|
64
|
+
instance_validating_container.validate
|
65
|
+
end
|
66
|
+
|
67
|
+
it { expect { subject }.not_to raise_error }
|
68
|
+
|
69
|
+
context 'when the schema an optional nil value' do
|
70
|
+
let(:optional) { nil }
|
71
|
+
it { expect { subject }.not_to raise_error }
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'when the schema an optional wrong type value' do
|
75
|
+
let(:optional) { 123 }
|
76
|
+
it { expect { subject }.to raise_error Membrane::SchemaValidationError }
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'when the schema a required nil value' do
|
80
|
+
let(:required) { nil }
|
81
|
+
it { expect { subject }.to raise_error Membrane::SchemaValidationError }
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'when the schema a required wrong type value' do
|
85
|
+
let(:required) { 123 }
|
86
|
+
it { expect { subject }.to raise_error Membrane::SchemaValidationError }
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe Schemata::MessageBase::Dsl do
|
92
|
+
describe '#define_aux_schema' do
|
93
|
+
let(:dsl) do
|
94
|
+
class TestDsl
|
95
|
+
extend Schemata::MessageBase::Dsl
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
after do
|
100
|
+
dsl::AUX_SCHEMA
|
101
|
+
end
|
102
|
+
|
103
|
+
subject do
|
104
|
+
dsl.define_aux_schema &schema
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'when the aux schema is a Record' do
|
108
|
+
let(:schema) { ->(_) { {"key" => String} } }
|
109
|
+
|
110
|
+
it 'sets the AUX_SCHEMA constant to the parse schema' do
|
111
|
+
subject
|
112
|
+
expect(dsl::AUX_SCHEMA).to be_a Membrane::Schema::Record
|
113
|
+
end
|
114
|
+
|
115
|
+
it "correctly parses the schema" do
|
116
|
+
subject
|
117
|
+
expect(dsl::AUX_SCHEMA.schemas["key"].klass).to eq String
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'when the aux schema is not a Record' do
|
122
|
+
let(:schema) { ->(_) { [String] } }
|
123
|
+
it { expect { subject }.to raise_error Schemata::SchemaDefinitionError, "Schema must be a hash" }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe '#define_schema' do
|
128
|
+
let(:dsl) do
|
129
|
+
class TestDsl
|
130
|
+
extend Schemata::MessageBase::Dsl
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
after do
|
135
|
+
dsl::SCHEMA
|
136
|
+
end
|
137
|
+
|
138
|
+
subject do
|
139
|
+
dsl.define_schema &schema
|
140
|
+
end
|
141
|
+
|
142
|
+
context 'when the aux schema is a Record' do
|
143
|
+
let(:schema) { ->(_) { {"key" => String} } }
|
144
|
+
|
145
|
+
it 'sets the SCHEMA constant to the parse schema' do
|
146
|
+
subject
|
147
|
+
expect(dsl::SCHEMA).to be_a Membrane::Schema::Record
|
148
|
+
end
|
149
|
+
|
150
|
+
it "correctly parses the schema" do
|
151
|
+
subject
|
152
|
+
expect(dsl::SCHEMA.schemas["key"].klass).to eq String
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
context 'when the aux schema is not a Record' do
|
157
|
+
let(:schema) { ->(_) { [String] } }
|
158
|
+
it { expect { subject }.to raise_error Schemata::SchemaDefinitionError, "Schema must be a hash" }
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -7,7 +7,7 @@ describe Schemata::ParsedMessage do
|
|
7
7
|
"V10" : { "foo" : "bar" }
|
8
8
|
}'
|
9
9
|
expect {
|
10
|
-
|
10
|
+
Schemata::ParsedMessage.new(json)
|
11
11
|
}.to raise_error(Schemata::DecodeError)
|
12
12
|
end
|
13
13
|
|
@@ -17,7 +17,7 @@ describe Schemata::ParsedMessage do
|
|
17
17
|
"foo" : "bar"
|
18
18
|
}'
|
19
19
|
expect {
|
20
|
-
|
20
|
+
Schemata::ParsedMessage.new(json)
|
21
21
|
}.to raise_error(Schemata::DecodeError)
|
22
22
|
end
|
23
23
|
|
@@ -26,7 +26,7 @@ describe Schemata::ParsedMessage do
|
|
26
26
|
"min_version" : 10
|
27
27
|
}'
|
28
28
|
expect {
|
29
|
-
|
29
|
+
Schemata::ParsedMessage.new(json)
|
30
30
|
}.to raise_error(Schemata::DecodeError)
|
31
31
|
end
|
32
32
|
|
@@ -94,7 +94,7 @@ describe Schemata::Component do
|
|
94
94
|
}
|
95
95
|
json_msg = Yajl::Encoder.encode msg_hash
|
96
96
|
expect {
|
97
|
-
|
97
|
+
Schemata::Component::Foo.decode(json_msg)
|
98
98
|
}.to raise_error(Schemata::DecodeError)
|
99
99
|
end
|
100
100
|
|
@@ -104,7 +104,7 @@ describe Schemata::Component do
|
|
104
104
|
}
|
105
105
|
json_msg = Yajl::Encoder.encode msg_hash
|
106
106
|
expect {
|
107
|
-
|
107
|
+
Schemata::Component::Foo.decode(json_msg)
|
108
108
|
}.to raise_error(Schemata::DecodeError)
|
109
109
|
end
|
110
110
|
|
@@ -147,7 +147,7 @@ describe Schemata::Component do
|
|
147
147
|
}
|
148
148
|
json_msg = Yajl::Encoder.encode(msg_hash)
|
149
149
|
expect {
|
150
|
-
|
150
|
+
Schemata::Component::Foo.decode(json_msg)
|
151
151
|
}.to raise_error(Schemata::DecodeError)
|
152
152
|
end
|
153
153
|
|
@@ -164,7 +164,7 @@ of V11 and V10 hashes" do
|
|
164
164
|
}
|
165
165
|
json_msg = Yajl::Encoder.encode(msg_hash)
|
166
166
|
expect {
|
167
|
-
|
167
|
+
Schemata::Component::Foo.decode(
|
168
168
|
json_msg)
|
169
169
|
}.to raise_error(Schemata::DecodeError)
|
170
170
|
end
|
@@ -183,20 +183,20 @@ of V10, V11, and V12 hashes" do
|
|
183
183
|
}
|
184
184
|
json_msg = Yajl::Encoder.encode msg_hash
|
185
185
|
expect {
|
186
|
-
|
186
|
+
Schemata::Component::Foo.decode(json_msg)
|
187
187
|
}.to raise_error(Schemata::DecodeError)
|
188
188
|
|
189
189
|
msg_hash["V11"]["foo2"] = "bar"
|
190
190
|
msg_hash["V12"]["foo2"] = 1
|
191
191
|
json_msg = Yajl::Encoder.encode msg_hash
|
192
192
|
expect {
|
193
|
-
|
193
|
+
Schemata::Component::Foo.decode(json_msg)
|
194
194
|
}.to raise_error(Schemata::DecodeError)
|
195
195
|
end
|
196
196
|
|
197
197
|
it "should raise an IncompatibleVersionError when it gets a v13 msg" do
|
198
198
|
expect {
|
199
|
-
|
199
|
+
Schemata::Component::Foo.decode(@v13_msg)
|
200
200
|
}.to raise_error(Schemata::IncompatibleVersionError)
|
201
201
|
end
|
202
202
|
end
|
@@ -465,7 +465,7 @@ of V10, V11, and V12 hashes" do
|
|
465
465
|
it "should raise an error if the msg_obj is incomplete" do
|
466
466
|
msg_obj = Schemata::Component::Foo::V10.new({"foo1" => "foo"})
|
467
467
|
expect {
|
468
|
-
|
468
|
+
msg_obj.encode
|
469
469
|
}.to raise_error(Schemata::EncodeError)
|
470
470
|
end
|
471
471
|
end
|
@@ -475,7 +475,7 @@ of V10, V11, and V12 hashes" do
|
|
475
475
|
set_current_version(Schemata::Component::Foo, 11)
|
476
476
|
end
|
477
477
|
|
478
|
-
after:each do
|
478
|
+
after :each do
|
479
479
|
reset_version(Schemata::Component::Foo)
|
480
480
|
end
|
481
481
|
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'schemata/helpers'
|
3
|
+
|
4
|
+
describe Schemata::Helpers do
|
5
|
+
describe ".stringify" do
|
6
|
+
subject { Schemata::Helpers.stringify_symbols(obj) }
|
7
|
+
|
8
|
+
context 'when the object is a String' do
|
9
|
+
let(:obj) { "foo" }
|
10
|
+
it { should eq obj }
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'when the object is a symbol' do
|
14
|
+
let(:obj) { :foo }
|
15
|
+
it { should eq "foo" }
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when the object is a numeric' do
|
19
|
+
let(:obj) { 123.03 }
|
20
|
+
it { should eq obj }
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'when the object is a nil' do
|
24
|
+
let(:obj) { nil }
|
25
|
+
it { should be_nil }
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when the object is a nil' do
|
29
|
+
let(:obj) { true }
|
30
|
+
it { should be_true }
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when the object is a nil' do
|
34
|
+
let(:obj) { false }
|
35
|
+
it { should be_false }
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'when the object is an array' do
|
39
|
+
context 'and one of the values is a symobl' do
|
40
|
+
let(:obj) { [:foo, "bar", :baz] }
|
41
|
+
it { should eq %w(foo bar baz) }
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'and their is a nested array' do
|
45
|
+
let(:obj) { [:foo, ["bar", :bar], :baz] }
|
46
|
+
it { should eq ["foo", ["bar", "bar"], "baz"] }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when the object is a hash" do
|
51
|
+
context 'and the value is a symbol' do
|
52
|
+
let(:obj) { { "foo" => :foo } }
|
53
|
+
it { should eq("foo" => "foo") }
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'and the key is a symbol' do
|
57
|
+
let(:obj) { { :foo => 'foo'} }
|
58
|
+
it { should eq("foo" => "foo") }
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'and their is a nested hash' do
|
62
|
+
let(:obj) { { :foo => {:foo => 'bar'}} }
|
63
|
+
it { should eq("foo" => {"foo" => "bar"}) }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'when the object is a nil' do
|
68
|
+
let(:obj) { Object.new }
|
69
|
+
it { expect { subject }.to raise_error Schemata::Helpers::StringifyError }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: schemata-dea
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.1.
|
4
|
+
version: 0.0.1.beta20
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -149,9 +149,12 @@ files:
|
|
149
149
|
- lib/schemata/helpers/decamelize.rb
|
150
150
|
- lib/schemata/helpers/hash_copy.rb
|
151
151
|
- lib/schemata/helpers/stringify.rb
|
152
|
+
- lib/schemata/helpers.rb
|
152
153
|
- spec/cloud_controller_spec.rb
|
153
154
|
- spec/common/componentbase_spec.rb
|
155
|
+
- spec/common/error_spec.rb
|
154
156
|
- spec/common/helpers_spec.rb
|
157
|
+
- spec/common/msgbase_spec.rb
|
155
158
|
- spec/common/msgtypebase_spec.rb
|
156
159
|
- spec/common/parsed_msg_spec.rb
|
157
160
|
- spec/component/aux_data_spec.rb
|
@@ -161,6 +164,7 @@ files:
|
|
161
164
|
- spec/component2/component2_bar_spec.rb
|
162
165
|
- spec/dea_spec.rb
|
163
166
|
- spec/health_manager_spec.rb
|
167
|
+
- spec/helpers/stringify_spec.rb
|
164
168
|
- spec/router_spec.rb
|
165
169
|
- spec/spec_helper.rb
|
166
170
|
- spec/staging_spec.rb
|
@@ -195,7 +199,9 @@ summary: validation for cloundfoundry DEA messages
|
|
195
199
|
test_files:
|
196
200
|
- spec/cloud_controller_spec.rb
|
197
201
|
- spec/common/componentbase_spec.rb
|
202
|
+
- spec/common/error_spec.rb
|
198
203
|
- spec/common/helpers_spec.rb
|
204
|
+
- spec/common/msgbase_spec.rb
|
199
205
|
- spec/common/msgtypebase_spec.rb
|
200
206
|
- spec/common/parsed_msg_spec.rb
|
201
207
|
- spec/component/aux_data_spec.rb
|
@@ -205,6 +211,7 @@ test_files:
|
|
205
211
|
- spec/component2/component2_bar_spec.rb
|
206
212
|
- spec/dea_spec.rb
|
207
213
|
- spec/health_manager_spec.rb
|
214
|
+
- spec/helpers/stringify_spec.rb
|
208
215
|
- spec/router_spec.rb
|
209
216
|
- spec/spec_helper.rb
|
210
217
|
- spec/staging_spec.rb
|