fake_dynamo 0.0.1
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/.gitignore +17 -0
- data/.rspec +1 -0
- data/Gemfile +11 -0
- data/Guardfile +19 -0
- data/LICENSE +22 -0
- data/README.md +4 -0
- data/Rakefile +2 -0
- data/bin/fake_dynamo +17 -0
- data/fake_dynamo.gemspec +18 -0
- data/lib/fake_dynamo.rb +20 -0
- data/lib/fake_dynamo/api.yml +734 -0
- data/lib/fake_dynamo/attribute.rb +54 -0
- data/lib/fake_dynamo/db.rb +113 -0
- data/lib/fake_dynamo/exceptions.rb +57 -0
- data/lib/fake_dynamo/filter.rb +110 -0
- data/lib/fake_dynamo/item.rb +102 -0
- data/lib/fake_dynamo/key.rb +71 -0
- data/lib/fake_dynamo/key_schema.rb +26 -0
- data/lib/fake_dynamo/server.rb +43 -0
- data/lib/fake_dynamo/storage.rb +71 -0
- data/lib/fake_dynamo/table.rb +362 -0
- data/lib/fake_dynamo/validation.rb +155 -0
- data/lib/fake_dynamo/version.rb +3 -0
- data/spec/fake_dynamo/db_spec.rb +257 -0
- data/spec/fake_dynamo/filter_spec.rb +122 -0
- data/spec/fake_dynamo/item_spec.rb +97 -0
- data/spec/fake_dynamo/server_spec.rb +47 -0
- data/spec/fake_dynamo/table_spec.rb +435 -0
- data/spec/fake_dynamo/validation_spec.rb +63 -0
- data/spec/spec_helper.rb +28 -0
- metadata +105 -0
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module FakeDynamo
|
4
|
+
module Validation
|
5
|
+
|
6
|
+
def validate!(&block)
|
7
|
+
@api_errors = []
|
8
|
+
yield
|
9
|
+
unless @api_errors.empty?
|
10
|
+
plural = @api_errors.size == 1 ? '' : 's'
|
11
|
+
message = "#{@api_errors.size} error#{plural} detected: #{@api_errors.join('; ')}"
|
12
|
+
raise ValidationException, message
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def add_errors(message)
|
18
|
+
@api_errors << message
|
19
|
+
end
|
20
|
+
|
21
|
+
def validate_payload(operation, data)
|
22
|
+
validate! do
|
23
|
+
validate_operation(operation)
|
24
|
+
validate_input(operation, data)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def validate_operation(operation)
|
29
|
+
raise UnknownOperationException, "Unknown operation: #{operation}" unless available_operations.include? operation
|
30
|
+
end
|
31
|
+
|
32
|
+
def available_operations
|
33
|
+
api_config[:operations].keys
|
34
|
+
end
|
35
|
+
|
36
|
+
def validate_input(operation, data)
|
37
|
+
api_input_spec(operation).each do |attribute, spec|
|
38
|
+
validate_spec(attribute, data[attribute], spec, [])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def validate_spec(attribute, data, spec, parents)
|
43
|
+
if not data
|
44
|
+
if spec.include?(:required)
|
45
|
+
add_errors("value null at '#{param(attribute, parents)}' failed to satisfy the constraint: Member must not be null")
|
46
|
+
end
|
47
|
+
return
|
48
|
+
end
|
49
|
+
|
50
|
+
spec.each do |constrain|
|
51
|
+
case constrain
|
52
|
+
when :string
|
53
|
+
add_errors("The parameter '#{param(attribute, parents)}' must be a string") unless data.kind_of? String
|
54
|
+
when :long
|
55
|
+
add_errors("The parameter '#{param(attribute, parents)}' must be a long") unless data.kind_of? Fixnum
|
56
|
+
when :integer
|
57
|
+
add_errors("The parameter '#{param(attribute, parents)}' must be a integer") unless data.kind_of? Fixnum
|
58
|
+
when :boolean
|
59
|
+
add_errors("The parameter '#{param(attribute, parents)}' must be a boolean") unless (data.kind_of? TrueClass or data.kind_of? FalseClass)
|
60
|
+
when Hash
|
61
|
+
new_parents = parents + [attribute]
|
62
|
+
case constrain.keys.first
|
63
|
+
when :pattern
|
64
|
+
pattern = constrain[:pattern]
|
65
|
+
unless data =~ pattern
|
66
|
+
add_errors("The parameter '#{param(attribute, parents)}' should match the pattern #{pattern}")
|
67
|
+
end
|
68
|
+
when :within
|
69
|
+
range = constrain[:within]
|
70
|
+
unless range.include? data.size
|
71
|
+
add_errors("The parameter '#{param(attribute, parents)}' value '#{data}' should be within #{range} characters")
|
72
|
+
end
|
73
|
+
when :enum
|
74
|
+
enum = constrain[:enum]
|
75
|
+
unless enum.include? data
|
76
|
+
add_errors("Value '#{data}' at '#{param(attribute, parents)}' failed to satisfy the constraint: Member must satisfy enum values set: #{enum}")
|
77
|
+
end
|
78
|
+
when :structure
|
79
|
+
structure = constrain[:structure]
|
80
|
+
structure.each do |attribute, spec|
|
81
|
+
validate_spec(attribute, data[attribute], spec, new_parents)
|
82
|
+
end
|
83
|
+
when :map
|
84
|
+
map = constrain[:map]
|
85
|
+
raise "#{param(attribute, parents)} must be a Hash" unless data.kind_of? Hash
|
86
|
+
data.each do |key, value|
|
87
|
+
validate_spec(key, key, map[:key], new_parents)
|
88
|
+
validate_spec(key, value, map[:value], new_parents)
|
89
|
+
end
|
90
|
+
when :list
|
91
|
+
raise "#{param(attribute, parents)} must be a Array" unless data.kind_of? Array
|
92
|
+
data.each do |element|
|
93
|
+
validate_spec(element, element, constrain[:list], new_parents)
|
94
|
+
end
|
95
|
+
else
|
96
|
+
raise "Unhandled constraint #{constrain}"
|
97
|
+
end
|
98
|
+
when :required
|
99
|
+
# handled earlier
|
100
|
+
else
|
101
|
+
raise "Unhandled constraint #{constrain}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def param(attribute, parents)
|
107
|
+
(parents + [attribute]).join('.')
|
108
|
+
end
|
109
|
+
|
110
|
+
def api_input_spec(operation)
|
111
|
+
api_config[:operations][operation][:input]
|
112
|
+
end
|
113
|
+
|
114
|
+
def api_config
|
115
|
+
@api_config ||= YAML.load_file(api_config_path)
|
116
|
+
end
|
117
|
+
|
118
|
+
def api_config_path
|
119
|
+
File.join File.expand_path(File.dirname(__FILE__)), 'api.yml'
|
120
|
+
end
|
121
|
+
|
122
|
+
def validate_type(value, attribute)
|
123
|
+
if attribute.kind_of?(Attribute)
|
124
|
+
expected_type = value.keys.first
|
125
|
+
if expected_type != attribute.type
|
126
|
+
raise ValidationException, "Type mismatch for key #{attribute.name}"
|
127
|
+
end
|
128
|
+
else
|
129
|
+
raise 'Unknown attribute'
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def validate_key_schema(data, key_schema)
|
134
|
+
key = data[key_schema.hash_key.name] or raise ValidationException, "Missing the key #{key_schema.hash_key.name} in the item"
|
135
|
+
validate_type(key, key_schema.hash_key)
|
136
|
+
|
137
|
+
if key_schema.range_key
|
138
|
+
range_key = data[key_schema.range_key.name] or raise ValidationException, "Missing the key #{key_schema.range_key.name} in the item"
|
139
|
+
validate_type(range_key, key_schema.range_key)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def validate_key_data(data, key_schema)
|
144
|
+
validate_type(data['HashKeyElement'], key_schema.hash_key)
|
145
|
+
|
146
|
+
if key_schema.range_key
|
147
|
+
range_key = data['RangeKeyElement'] or raise ValidationException, "Missing the key RangeKeyElement in the Key"
|
148
|
+
validate_type(range_key, key_schema.range_key)
|
149
|
+
elsif data['RangeKeyElement']
|
150
|
+
raise ValidationException, "RangeKeyElement is not present in the schema"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,257 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module FakeDynamo
|
4
|
+
describe DB do
|
5
|
+
let(:data) do
|
6
|
+
{
|
7
|
+
"TableName" => "Table1",
|
8
|
+
"KeySchema" =>
|
9
|
+
{"HashKeyElement" => {"AttributeName" => "AttributeName1","AttributeType" => "S"},
|
10
|
+
"RangeKeyElement" => {"AttributeName" => "AttributeName2","AttributeType" => "N"}},
|
11
|
+
"ProvisionedThroughput" => {"ReadCapacityUnits" => 5,"WriteCapacityUnits" => 10}
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:user_table) do
|
16
|
+
{"TableName" => "User",
|
17
|
+
"KeySchema" =>
|
18
|
+
{"HashKeyElement" => {"AttributeName" => "id","AttributeType" => "S"}},
|
19
|
+
"ProvisionedThroughput" => {"ReadCapacityUnits" => 5,"WriteCapacityUnits" => 10}
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should not allow to create duplicate tables' do
|
24
|
+
subject.create_table(data)
|
25
|
+
expect { subject.create_table(data) }.to raise_error(ResourceInUseException, /duplicate/i)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should fail on unknown operation' do
|
29
|
+
expect { subject.process('unknown', data) }.to raise_error(UnknownOperationException, /unknown/i)
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'DescribeTable' do
|
33
|
+
it 'should describe table' do
|
34
|
+
table = subject.create_table(data)
|
35
|
+
description = subject.describe_table({'TableName' => 'Table1'})
|
36
|
+
description.should include({
|
37
|
+
"ItemCount"=>0,
|
38
|
+
"TableSizeBytes"=>0})
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should fail on unavailable table' do
|
42
|
+
expect { subject.describe_table({'TableName' => 'Table1'}) }.to raise_error(ResourceNotFoundException, /table1 not found/i)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should fail on invalid payload' do
|
46
|
+
expect { subject.process('DescribeTable', {}) }.to raise_error(ValidationException, /null/)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'DeleteTable' do
|
51
|
+
it "should delete table" do
|
52
|
+
subject.create_table(data)
|
53
|
+
response = subject.delete_table(data)
|
54
|
+
subject.tables.should be_empty
|
55
|
+
response['TableDescription']['TableStatus'].should == 'DELETING'
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should not allow to delete the same table twice" do
|
59
|
+
subject.create_table(data)
|
60
|
+
subject.delete_table(data)
|
61
|
+
expect { subject.delete_table(data) }.to raise_error(ResourceNotFoundException, /table1 not found/i)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'ListTable' do
|
66
|
+
before :each do
|
67
|
+
(1..5).each do |i|
|
68
|
+
data['TableName'] = "Table#{i}"
|
69
|
+
subject.create_table(data)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should list all table" do
|
74
|
+
result = subject.list_tables({})
|
75
|
+
result.should eq({"TableNames"=>["Table1", "Table2", "Table3", "Table4", "Table5"]})
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should handle limit and exclusive_start_table_name' do
|
79
|
+
result = subject.list_tables({'Limit' => 3,
|
80
|
+
'ExclusiveStartTableName' => 'Table1'})
|
81
|
+
result.should eq({'TableNames'=>["Table2", "Table3", "Table4"],
|
82
|
+
'LastEvaluatedTableName' => "Table4"})
|
83
|
+
|
84
|
+
result = subject.list_tables({'Limit' => 3,
|
85
|
+
'ExclusiveStartTableName' => 'Table2'})
|
86
|
+
result.should eq({'TableNames' => ['Table3', 'Table4', 'Table5']})
|
87
|
+
|
88
|
+
result = subject.list_tables({'ExclusiveStartTableName' => 'blah'})
|
89
|
+
result.should eq({"TableNames"=>["Table1", "Table2", "Table3", "Table4", "Table5"]})
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should validate payload' do
|
93
|
+
expect { subject.process('ListTables', {'Limit' => 's'}) }.to raise_error(ValidationException)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'UpdateTable' do
|
98
|
+
|
99
|
+
it 'should update throughput' do
|
100
|
+
subject.create_table(data)
|
101
|
+
response = subject.update_table({'TableName' => 'Table1',
|
102
|
+
'ProvisionedThroughput' => {
|
103
|
+
'ReadCapacityUnits' => 7,
|
104
|
+
'WriteCapacityUnits' => 15
|
105
|
+
}})
|
106
|
+
|
107
|
+
response['TableDescription'].should include({'TableStatus' => 'UPDATING'})
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should handle validation' do
|
111
|
+
subject.create_table(data)
|
112
|
+
expect { subject.process('UpdateTable', {'TableName' => 'Table1'}) }.to raise_error(ValidationException, /null/)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'delegate to table' do
|
117
|
+
subject do
|
118
|
+
db = DB.new
|
119
|
+
db.create_table(data)
|
120
|
+
db
|
121
|
+
end
|
122
|
+
|
123
|
+
let(:item) do
|
124
|
+
{ 'TableName' => 'Table1',
|
125
|
+
'Item' => {
|
126
|
+
'AttributeName1' => { 'S' => "test" },
|
127
|
+
'AttributeName2' => { 'N' => '11' },
|
128
|
+
'AttributeName3' => { 'S' => "another" }
|
129
|
+
}}
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'should delegate to table' do
|
133
|
+
subject.process('PutItem', item)
|
134
|
+
subject.process('GetItem', {
|
135
|
+
'TableName' => 'Table1',
|
136
|
+
'Key' => {
|
137
|
+
'HashKeyElement' => { 'S' => 'test' },
|
138
|
+
'RangeKeyElement' => { 'N' => '11' }
|
139
|
+
},
|
140
|
+
'AttributesToGet' => ['AttributeName3']
|
141
|
+
})
|
142
|
+
subject.process('DeleteItem', {
|
143
|
+
'TableName' => 'Table1',
|
144
|
+
'Key' => {
|
145
|
+
'HashKeyElement' => { 'S' => 'test' },
|
146
|
+
'RangeKeyElement' => { 'N' => '11' }
|
147
|
+
}})
|
148
|
+
subject.process('UpdateItem', {
|
149
|
+
'TableName' => 'Table1',
|
150
|
+
'Key' => {
|
151
|
+
'HashKeyElement' => { 'S' => 'test' },
|
152
|
+
'RangeKeyElement' => { 'N' => '11' }
|
153
|
+
},
|
154
|
+
'AttributeUpdates' =>
|
155
|
+
{'AttributeName3' =>
|
156
|
+
{'Value' => {'S' => 'AttributeValue3_New'},
|
157
|
+
'Action' => 'PUT'}
|
158
|
+
},
|
159
|
+
'ReturnValues' => 'ALL_NEW'
|
160
|
+
})
|
161
|
+
|
162
|
+
subject.process('Query', {
|
163
|
+
'TableName' => 'Table1',
|
164
|
+
'Limit' => 5,
|
165
|
+
'Count' => true,
|
166
|
+
'HashKeyValue' => {'S' => 'att1'},
|
167
|
+
'RangeKeyCondition' => {
|
168
|
+
'AttributeValueList' => [{'N' => '1'}],
|
169
|
+
'ComparisonOperator' => 'GT'
|
170
|
+
},
|
171
|
+
'ScanIndexForward' => true
|
172
|
+
})
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
context 'batch get item' do
|
177
|
+
subject do
|
178
|
+
db = DB.new
|
179
|
+
db.create_table(data)
|
180
|
+
db.create_table(user_table)
|
181
|
+
|
182
|
+
db.put_item({ 'TableName' => 'Table1',
|
183
|
+
'Item' => {
|
184
|
+
'AttributeName1' => { 'S' => "test" },
|
185
|
+
'AttributeName2' => { 'N' => '11' },
|
186
|
+
'AttributeName3' => { 'S' => "another" }
|
187
|
+
}})
|
188
|
+
|
189
|
+
db.put_item({'TableName' => 'User',
|
190
|
+
'Item' => { 'id' => { 'S' => '1' }}
|
191
|
+
})
|
192
|
+
db.put_item({'TableName' => 'User',
|
193
|
+
'Item' => { 'id' => { 'S' => '2' }}
|
194
|
+
})
|
195
|
+
db
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'should validate payload' do
|
199
|
+
expect {
|
200
|
+
subject.process('BatchGetItem', {})
|
201
|
+
}.to raise_error(FakeDynamo::ValidationException)
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'should return items' do
|
205
|
+
response = subject.process('BatchGetItem', { 'RequestItems' =>
|
206
|
+
{
|
207
|
+
'User' => {
|
208
|
+
'Keys' => [{ 'HashKeyElement' => { 'S' => '1' }},
|
209
|
+
{ 'HashKeyElement' => { 'S' => '2' }}]
|
210
|
+
},
|
211
|
+
'Table1' => {
|
212
|
+
'Keys' => [{'HashKeyElement' => { 'S' => 'test' },
|
213
|
+
'RangeKeyElement' => { 'N' => '11' }}],
|
214
|
+
'AttributesToGet' => ['AttributeName1', 'AttributeName2']
|
215
|
+
}
|
216
|
+
}})
|
217
|
+
|
218
|
+
response.should eq({"Responses"=>
|
219
|
+
{"User"=>
|
220
|
+
{"ConsumedCapacityUnits"=>1,
|
221
|
+
"Items"=>[{"id"=>{"S"=>"1"}}, {"id"=>{"S"=>"2"}}]},
|
222
|
+
"Table1"=>
|
223
|
+
{"ConsumedCapacityUnits"=>1,
|
224
|
+
"Items"=>
|
225
|
+
[{"AttributeName1"=>{"S"=>"test"},
|
226
|
+
"AttributeName2"=>{"N"=>"11"}}]}},
|
227
|
+
"UnprocessedKeys"=>{}})
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'should handle missing items' do
|
231
|
+
response = subject.process('BatchGetItem', { 'RequestItems' =>
|
232
|
+
{
|
233
|
+
'User' => {
|
234
|
+
'Keys' => [{ 'HashKeyElement' => { 'S' => '1' }},
|
235
|
+
{ 'HashKeyElement' => { 'S' => 'asd' }}]
|
236
|
+
}
|
237
|
+
}})
|
238
|
+
response.should eq({"Responses"=>
|
239
|
+
{"User"=>
|
240
|
+
{"ConsumedCapacityUnits"=>1,
|
241
|
+
"Items"=>[{"id"=>{"S"=>"1"}}]}},
|
242
|
+
"UnprocessedKeys"=>{}})
|
243
|
+
end
|
244
|
+
|
245
|
+
it 'should fail if table not found' do
|
246
|
+
expect {
|
247
|
+
subject.process('BatchGetItem', { 'RequestItems' =>
|
248
|
+
{
|
249
|
+
'xxx' => {
|
250
|
+
'Keys' => [{ 'HashKeyElement' => { 'S' => '1' }},
|
251
|
+
{ 'HashKeyElement' => { 'S' => 'asd' }}]}
|
252
|
+
}})
|
253
|
+
}.to raise_error(FakeDynamo::ResourceNotFoundException)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module FakeDynamo
|
4
|
+
|
5
|
+
class FilterTest
|
6
|
+
include Filter
|
7
|
+
end
|
8
|
+
|
9
|
+
describe Filter do
|
10
|
+
subject { FilterTest.new }
|
11
|
+
|
12
|
+
let(:s_attr) { Attribute.new('test', 'bcd', 'S')}
|
13
|
+
let(:ss_attr) { Attribute.new('test', ['ab', 'cd'], 'SS') }
|
14
|
+
let(:n_attr) { Attribute.new('test', '10', 'N')}
|
15
|
+
let(:ns_attr) { Attribute.new('test', ['1', '2', '3', '4'], 'NS')}
|
16
|
+
|
17
|
+
|
18
|
+
it 'tests eq' do
|
19
|
+
subject.eq_filter([{'S' => 'bcd'}], s_attr, false).should be_true
|
20
|
+
subject.eq_filter([{'S' => '10'}], n_attr, false).should be_false
|
21
|
+
expect { subject.eq_filter([{'S' => '10'}], n_attr, true) }.to raise_error(ValidationException, /mismatch/)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'tests le' do
|
25
|
+
subject.le_filter([{'S' => 'c'}], s_attr, false).should be_true
|
26
|
+
subject.le_filter([{'S' => 'bcd'}], s_attr, false).should be_true
|
27
|
+
subject.le_filter([{'N' => 'bcd'}], s_attr, false).should be_false
|
28
|
+
subject.le_filter([{'S' => 'a'}], s_attr, false).should be_false
|
29
|
+
subject.le_filter([{'N' => '10'}], n_attr, false).should be_true
|
30
|
+
subject.le_filter([{'N' => '11'}], n_attr, false).should be_true
|
31
|
+
subject.le_filter([{'N' => '1'}], n_attr, false).should be_false
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'tests lt' do
|
35
|
+
subject.lt_filter([{'S' => 'c'}], s_attr, false).should be_true
|
36
|
+
subject.lt_filter([{'S' => 'bcd'}], s_attr, false).should be_false
|
37
|
+
subject.lt_filter([{'N' => 'bcd'}], s_attr, false).should be_false
|
38
|
+
subject.lt_filter([{'S' => 'a'}], s_attr, false).should be_false
|
39
|
+
subject.lt_filter([{'N' => '10'}], n_attr, false).should be_false
|
40
|
+
subject.lt_filter([{'N' => '11'}], n_attr, false).should be_true
|
41
|
+
subject.lt_filter([{'N' => '1'}], n_attr, false).should be_false
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'test ge' do
|
45
|
+
subject.ge_filter([{'S' => 'c'}], s_attr, false).should be_false
|
46
|
+
subject.ge_filter([{'S' => 'bcd'}], s_attr, false).should be_true
|
47
|
+
subject.ge_filter([{'N' => 'bcd'}], s_attr, false).should be_false
|
48
|
+
subject.ge_filter([{'S' => 'a'}], s_attr, false).should be_true
|
49
|
+
subject.ge_filter([{'N' => '10'}], n_attr, false).should be_true
|
50
|
+
subject.ge_filter([{'N' => '11'}], n_attr, false).should be_false
|
51
|
+
subject.ge_filter([{'N' => '1'}], n_attr, false).should be_true
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'test gt' do
|
55
|
+
subject.gt_filter([{'S' => 'c'}], s_attr, false).should be_false
|
56
|
+
subject.gt_filter([{'S' => 'bcd'}], s_attr, false).should be_false
|
57
|
+
subject.gt_filter([{'N' => 'bcd'}], s_attr, false).should be_false
|
58
|
+
subject.gt_filter([{'S' => 'a'}], s_attr, false).should be_true
|
59
|
+
subject.gt_filter([{'N' => '10'}], n_attr, false).should be_false
|
60
|
+
subject.gt_filter([{'N' => '11'}], n_attr, false).should be_false
|
61
|
+
subject.gt_filter([{'N' => '1'}], n_attr, false).should be_true
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'test begins_with' do
|
65
|
+
subject.begins_with_filter([{'S' => 'bc'}], s_attr, false).should be_true
|
66
|
+
subject.begins_with_filter([{'S' => 'cd'}], s_attr, false).should be_false
|
67
|
+
expect {
|
68
|
+
subject.begins_with_filter([{'N' => '10'}], n_attr, false)
|
69
|
+
}.to raise_error(ValidationException, /not supported/)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'test between' do
|
73
|
+
expect {
|
74
|
+
subject.between_filter([{'S' => 'bc'}], s_attr, false)
|
75
|
+
}.to raise_error(ValidationException, /argument count/)
|
76
|
+
subject.between_filter([{'S' => 'a'},{'S' => 'c'}], s_attr, false).should be_true
|
77
|
+
subject.between_filter([{'S' => 'bcd'},{'S' => 'bcd'}], s_attr, false).should be_true
|
78
|
+
subject.between_filter([{'N' => '9'},{'N' => '11'}], n_attr, false).should be_true
|
79
|
+
subject.between_filter([{'S' => '9'},{'S' => '11'}], n_attr, false).should be_false
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'test ne' do
|
83
|
+
subject.ne_filter([{'S' => 'bcd'}], s_attr, false).should be_false
|
84
|
+
subject.ne_filter([{'S' => '10'}], n_attr, false).should be_false
|
85
|
+
subject.ne_filter([{'S' => 'xx'}], s_attr, false).should be_true
|
86
|
+
subject.ne_filter([{'S' => '10'}], n_attr, false).should be_false
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'test not null' do
|
90
|
+
subject.not_null_filter(nil, nil, false).should be_false
|
91
|
+
subject.not_null_filter(nil, s_attr, false).should be_true
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'test null' do
|
95
|
+
subject.null_filter(nil, nil, false).should be_true
|
96
|
+
subject.null_filter(nil, s_attr, false).should be_false
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'test contains' do
|
100
|
+
subject.contains_filter([{'S' => 'cd'}], s_attr, false).should be_true
|
101
|
+
subject.contains_filter([{'S' => 'cd'}], ss_attr, false).should be_true
|
102
|
+
subject.contains_filter([{'N' => '2'}], ns_attr, false).should be_true
|
103
|
+
subject.contains_filter([{'N' => '10'}], n_attr, false).should be_false
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'test not contains' do
|
107
|
+
subject.not_contains_filter([{'S' => 'xx'}], s_attr, false).should be_true
|
108
|
+
subject.not_contains_filter([{'S' => 'cd'}], s_attr, false).should be_false
|
109
|
+
subject.not_contains_filter([{'S' => 'cd'}], ss_attr, false).should be_false
|
110
|
+
subject.not_contains_filter([{'N' => '2'}], ns_attr, false).should be_false
|
111
|
+
subject.not_contains_filter([{'N' => '12'}], ns_attr, false).should be_true
|
112
|
+
subject.not_contains_filter([{'N' => '10'}], n_attr, false).should be_false
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'test in' do
|
116
|
+
subject.in_filter([{'S' => 'bcd'}], s_attr, false).should be_true
|
117
|
+
subject.in_filter([{'S' => 'bcd'}, {'N' => '10'}], n_attr, true).should be_true
|
118
|
+
subject.in_filter([{'N' => '1'}], ns_attr, true).should be_false
|
119
|
+
subject.in_filter([{'S' => 'xx'}], s_attr, false).should be_false
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|