schemata-dea 0.0.1.beta18 → 0.0.1.beta20
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.
- 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
|