fake_dynamo 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|