fake_dynamo 0.1.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -1
- data/Guardfile +3 -0
- data/lib/fake_dynamo/api.yml +1 -1
- data/lib/fake_dynamo/api_2012-08-10.yml +1555 -0
- data/lib/fake_dynamo/db.rb +38 -5
- data/lib/fake_dynamo/item.rb +10 -0
- data/lib/fake_dynamo/key.rb +2 -10
- data/lib/fake_dynamo/key_schema.rb +27 -8
- data/lib/fake_dynamo/local_secondary_index.rb +27 -0
- data/lib/fake_dynamo/projection.rb +30 -0
- data/lib/fake_dynamo/table.rb +174 -76
- data/lib/fake_dynamo/validation.rb +66 -14
- data/lib/fake_dynamo/version.rb +1 -1
- data/lib/fake_dynamo.rb +2 -0
- data/spec/fake_dynamo/db_spec.rb +147 -53
- data/spec/fake_dynamo/server_spec.rb +5 -2
- data/spec/fake_dynamo/storage_spec.rb +3 -1
- data/spec/fake_dynamo/table_spec.rb +161 -39
- data/spec/fake_dynamo/validation_spec.rb +17 -18
- metadata +25 -28
- checksums.yaml +0 -7
@@ -30,10 +30,6 @@ module FakeDynamo
|
|
30
30
|
raise UnknownOperationException, "Unknown operation: #{operation}" unless available_operations.include? operation
|
31
31
|
end
|
32
32
|
|
33
|
-
def available_operations
|
34
|
-
api_config[:operations].keys
|
35
|
-
end
|
36
|
-
|
37
33
|
def validate_input(operation, data)
|
38
34
|
api_input_spec(operation).each do |attribute, spec|
|
39
35
|
validate_spec(attribute, data[attribute], spec, [])
|
@@ -71,7 +67,7 @@ module FakeDynamo
|
|
71
67
|
when :within
|
72
68
|
range = constrain[:within]
|
73
69
|
unless range.include? data.size
|
74
|
-
add_errors("The parameter '#{param(attribute, parents)}' value '#{data}' should be within #{range}
|
70
|
+
add_errors("The parameter '#{param(attribute, parents)}' value '#{data}' should be within #{range}")
|
75
71
|
end
|
76
72
|
when :enum
|
77
73
|
enum = constrain[:enum]
|
@@ -81,7 +77,7 @@ module FakeDynamo
|
|
81
77
|
when :structure
|
82
78
|
structure = constrain[:structure]
|
83
79
|
structure.each do |attribute, spec|
|
84
|
-
validate_spec(attribute, data[attribute], spec,
|
80
|
+
validate_spec(attribute, data[attribute], spec, parents + ["member"])
|
85
81
|
end
|
86
82
|
when :map
|
87
83
|
map = constrain[:map]
|
@@ -92,8 +88,8 @@ module FakeDynamo
|
|
92
88
|
end
|
93
89
|
when :list
|
94
90
|
raise "#{param(attribute, parents)} must be a Array" unless data.kind_of? Array
|
95
|
-
data.
|
96
|
-
validate_spec(element, element, constrain[:list], new_parents)
|
91
|
+
data.each_with_index do |element, i|
|
92
|
+
validate_spec(element, element, constrain[:list], new_parents + [(i+1).to_s])
|
97
93
|
end
|
98
94
|
else
|
99
95
|
raise "Unhandled constraint #{constrain}"
|
@@ -111,7 +107,11 @@ module FakeDynamo
|
|
111
107
|
end
|
112
108
|
|
113
109
|
def api_input_spec(operation)
|
114
|
-
api_config[:operations][operation
|
110
|
+
api_config[:operations].find { |spec| spec[:name] == operation }[:inputs]
|
111
|
+
end
|
112
|
+
|
113
|
+
def available_operations
|
114
|
+
@available_operations ||= api_config[:operations].map { |spec| spec[:name] }
|
115
115
|
end
|
116
116
|
|
117
117
|
def api_config
|
@@ -119,7 +119,7 @@ module FakeDynamo
|
|
119
119
|
end
|
120
120
|
|
121
121
|
def api_config_path
|
122
|
-
File.join File.expand_path(File.dirname(__FILE__)), '
|
122
|
+
File.join File.expand_path(File.dirname(__FILE__)), 'api_2012-08-10.yml'
|
123
123
|
end
|
124
124
|
|
125
125
|
def validate_type(value, attribute)
|
@@ -144,21 +144,73 @@ module FakeDynamo
|
|
144
144
|
end
|
145
145
|
|
146
146
|
def validate_key_data(data, key_schema)
|
147
|
-
|
147
|
+
hash_key = data[key_schema.hash_key.name] or key_schema_mismatch
|
148
|
+
validate_type(hash_key, key_schema.hash_key)
|
148
149
|
|
149
150
|
if key_schema.range_key
|
150
|
-
range_key = data[
|
151
|
+
range_key = data[key_schema.range_key.name] or key_schema_mismatch
|
151
152
|
validate_type(range_key, key_schema.range_key)
|
152
|
-
|
153
|
-
|
153
|
+
key_schema_mismatch if data.size != 2
|
154
|
+
else
|
155
|
+
key_schema_mismatch if data.size != 1
|
154
156
|
end
|
155
157
|
end
|
156
158
|
|
159
|
+
def key_schema_mismatch
|
160
|
+
raise ValidationException, "The provided key element does not match the schema"
|
161
|
+
end
|
162
|
+
|
157
163
|
def validate_request_size(data)
|
158
164
|
if data.to_s.bytesize > 1 * 1024 * 1024
|
159
165
|
raise ValidationException, "Request size can't exceed 1 mb"
|
160
166
|
end
|
161
167
|
end
|
162
168
|
|
169
|
+
def validate_range_key(key_schema)
|
170
|
+
unless key_schema.range_key
|
171
|
+
raise ValidationException, 'Table KeySchema does not have a range key'
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def validate_hash_key(index, table)
|
176
|
+
if index.hash_key != table.hash_key
|
177
|
+
raise ValidationException, "Index KeySchema does not have the same leading hash key as table KeySchema for index"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def validate_projection(projection)
|
182
|
+
if projection.type == 'INCLUDE'
|
183
|
+
unless projection.non_key_attributes
|
184
|
+
raise ValidationException, "ProjectionType is #{projection.type}, but NonKeyAttributes is not specified"
|
185
|
+
end
|
186
|
+
else
|
187
|
+
if projection.non_key_attributes
|
188
|
+
raise ValidationException, "ProjectionType is #{projection.type}, but NonKeyAttributes is specified"
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def validate_index_names(indexes)
|
194
|
+
names = indexes.map(&:name)
|
195
|
+
if names.uniq.size != names.size
|
196
|
+
raise ValidationException, "Duplicate index name: #{names.find { |n| names.count(n) > 1 }}"
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def validate_hash_condition(condition)
|
201
|
+
unless condition
|
202
|
+
raise ValidationException, "Query condition missed key schema element #{key_schema.hash_key.name}"
|
203
|
+
end
|
204
|
+
|
205
|
+
if condition['ComparisonOperator'] != 'EQ'
|
206
|
+
raise ValidationException, "Query key condition not supported"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def validate_range_condition(condition, schema)
|
211
|
+
unless condition.has_key?(schema.range_key.name)
|
212
|
+
raise ValidationException, "Query condition missed key schema element #{schema.range_key.name}"
|
213
|
+
end
|
214
|
+
end
|
163
215
|
end
|
164
216
|
end
|
data/lib/fake_dynamo/version.rb
CHANGED
data/lib/fake_dynamo.rb
CHANGED
@@ -6,6 +6,8 @@ require 'active_support/core_ext/class/attribute'
|
|
6
6
|
require 'fake_dynamo/exceptions'
|
7
7
|
require 'fake_dynamo/validation'
|
8
8
|
require 'fake_dynamo/filter'
|
9
|
+
require 'fake_dynamo/local_secondary_index'
|
10
|
+
require 'fake_dynamo/projection'
|
9
11
|
require 'fake_dynamo/attribute'
|
10
12
|
require 'fake_dynamo/key_schema'
|
11
13
|
require 'fake_dynamo/item'
|
data/spec/fake_dynamo/db_spec.rb
CHANGED
@@ -5,24 +5,107 @@ module FakeDynamo
|
|
5
5
|
let(:data) do
|
6
6
|
{
|
7
7
|
"TableName" => "Table1",
|
8
|
+
"AttributeDefinitions" =>
|
9
|
+
[{"AttributeName" => "AttributeName1","AttributeType" => "S"},
|
10
|
+
{"AttributeName" => "AttributeName2","AttributeType" => "N"}],
|
8
11
|
"KeySchema" =>
|
9
|
-
{"
|
10
|
-
|
12
|
+
[{"AttributeName" => "AttributeName1","KeyType" => "HASH"},
|
13
|
+
{"AttributeName" => "AttributeName2","KeyType" => "RANGE"}],
|
11
14
|
"ProvisionedThroughput" => {"ReadCapacityUnits" => 5,"WriteCapacityUnits" => 10}
|
12
15
|
}
|
13
16
|
end
|
14
17
|
|
15
18
|
let(:user_table) do
|
16
19
|
{"TableName" => "User",
|
20
|
+
"AttributeDefinitions" =>
|
21
|
+
[{"AttributeName" => "id","AttributeType" => "S"}],
|
17
22
|
"KeySchema" =>
|
18
|
-
{"
|
23
|
+
[{"AttributeName" => "id","KeyType" => "HASH"}],
|
19
24
|
"ProvisionedThroughput" => {"ReadCapacityUnits" => 5,"WriteCapacityUnits" => 10}
|
20
25
|
}
|
21
26
|
end
|
22
27
|
|
23
|
-
|
24
|
-
|
25
|
-
|
28
|
+
let(:user_table_a) do
|
29
|
+
{"TableName" => "User",
|
30
|
+
"AttributeDefinitions" =>
|
31
|
+
[{"AttributeName" => "id","AttributeType" => "S"},
|
32
|
+
{"AttributeName" => "age","AttributeType" => "S"},
|
33
|
+
{"AttributeName" => "name","AttributeType" => "S"}],
|
34
|
+
"KeySchema" =>
|
35
|
+
[{"AttributeName" => "id","KeyType" => "HASH"},
|
36
|
+
{"AttributeName" => "age", "KeyType" => "RANGE"}],
|
37
|
+
"LocalSecondaryIndexes" =>
|
38
|
+
[{"IndexName" => "age",
|
39
|
+
"KeySchema" =>
|
40
|
+
[{"AttributeName" => "id", "KeyType" => "HASH"},
|
41
|
+
{"AttributeName" => "name", "KeyType" => "RANGE"}],
|
42
|
+
"Projection" => {
|
43
|
+
"ProjectionType" => "INCLUDE",
|
44
|
+
"NonKeyAttributes" => ["name", "gender"]
|
45
|
+
}
|
46
|
+
}],
|
47
|
+
"ProvisionedThroughput" => {"ReadCapacityUnits" => 5,"WriteCapacityUnits" => 10}
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'CreateTable' do
|
52
|
+
it 'should not allow to create duplicate tables' do
|
53
|
+
subject.create_table(data)
|
54
|
+
expect { subject.create_table(data) }.to raise_error(ResourceInUseException, /duplicate/i)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should allow to create table with secondary indexes' do
|
58
|
+
subject.create_table(user_table_a)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should fail on extra attribute' do
|
62
|
+
user_table_a['AttributeDefinitions'] << {"AttributeName" => "gender","AttributeType" => "S"}
|
63
|
+
expect { subject.create_table(user_table_a) }.to raise_error(ValidationException, /some attributedefinitions.*not.*used/i)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should fail on missing attribute' do
|
67
|
+
user_table_a['AttributeDefinitions'].delete_at(1)
|
68
|
+
expect { subject.create_table(user_table_a) }.to raise_error(ValidationException, /some.*attributes.*not.*defined/i)
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'LocalSecondaryIndex' do
|
72
|
+
let(:lsi) { user_table_a['LocalSecondaryIndexes'][0] }
|
73
|
+
|
74
|
+
it 'should fail on invalid KeyType' do
|
75
|
+
lsi["KeySchema"][0]['KeyType'] = 'invalid'
|
76
|
+
expect { subject.process('CreateTable', user_table_a) }.to raise_error(ValidationException, /invalid.*enum/)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should fail if range key is missing' do
|
80
|
+
lsi['KeySchema'].delete_at(1)
|
81
|
+
expect { subject.create_table(user_table_a) }.to raise_error(ValidationException, /not.*range.*key/i)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should fail on duplicate index names' do
|
85
|
+
duplicate = lsi.clone()
|
86
|
+
user_table_a['LocalSecondaryIndexes'] << duplicate
|
87
|
+
expect { subject.create_table(user_table_a) }.to raise_error(ValidationException, /duplicate index/i)
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should fail on different hash key' do
|
91
|
+
lsi['KeySchema'][0]['AttributeName'] = 'age'
|
92
|
+
expect { subject.create_table(user_table_a) }.to raise_error(ValidationException, /not have.*same.*hash key/i)
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'projection' do
|
96
|
+
let(:projection) { user_table_a['LocalSecondaryIndexes'][0]['Projection'] }
|
97
|
+
|
98
|
+
it 'should fail if non key attributes are specified unnecessarily' do
|
99
|
+
projection['ProjectionType'] = 'KEYS_ONLY'
|
100
|
+
expect { subject.create_table(user_table_a) }.to raise_error(ValidationException, /NonKeyAttributes.*specified/i)
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should fail if non key attributes are not specified' do
|
104
|
+
projection.delete('NonKeyAttributes')
|
105
|
+
expect { subject.create_table(user_table_a) }.to raise_error(ValidationException, /NonKeyAttributes.*not.*specified/i)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
26
109
|
end
|
27
110
|
|
28
111
|
it 'should fail on unknown operation' do
|
@@ -33,7 +116,7 @@ module FakeDynamo
|
|
33
116
|
it 'should describe table' do
|
34
117
|
table = subject.create_table(data)
|
35
118
|
description = subject.describe_table({'TableName' => 'Table1'})
|
36
|
-
description.should include({
|
119
|
+
description['Table'].should include({
|
37
120
|
"ItemCount"=>0,
|
38
121
|
"TableSizeBytes"=>0})
|
39
122
|
end
|
@@ -134,22 +217,22 @@ module FakeDynamo
|
|
134
217
|
subject.process('GetItem', {
|
135
218
|
'TableName' => 'Table1',
|
136
219
|
'Key' => {
|
137
|
-
'
|
138
|
-
'
|
220
|
+
'AttributeName1' => { 'S' => 'test' },
|
221
|
+
'AttributeName2' => { 'N' => '11' }
|
139
222
|
},
|
140
223
|
'AttributesToGet' => ['AttributeName3']
|
141
224
|
})
|
142
225
|
subject.process('DeleteItem', {
|
143
226
|
'TableName' => 'Table1',
|
144
227
|
'Key' => {
|
145
|
-
'
|
146
|
-
'
|
228
|
+
'AttributeName1' => { 'S' => 'test' },
|
229
|
+
'AttributeName2' => { 'N' => '11' }
|
147
230
|
}})
|
148
231
|
subject.process('UpdateItem', {
|
149
232
|
'TableName' => 'Table1',
|
150
233
|
'Key' => {
|
151
|
-
'
|
152
|
-
'
|
234
|
+
'AttributeName1' => { 'S' => 'test' },
|
235
|
+
'AttributeName2' => { 'N' => '11' }
|
153
236
|
},
|
154
237
|
'AttributeUpdates' =>
|
155
238
|
{'AttributeName3' =>
|
@@ -163,10 +246,15 @@ module FakeDynamo
|
|
163
246
|
'TableName' => 'Table1',
|
164
247
|
'Limit' => 5,
|
165
248
|
'Count' => true,
|
166
|
-
'
|
167
|
-
|
168
|
-
|
169
|
-
|
249
|
+
'KeyConditions' => {
|
250
|
+
'AttributeName1' => {
|
251
|
+
'AttributeValueList' => [{'S' => 'att1'}],
|
252
|
+
'ComparisonOperator' => 'EQ'
|
253
|
+
},
|
254
|
+
'AttributeName2' => {
|
255
|
+
'AttributeValueList' => [{'N' => '1'}],
|
256
|
+
'ComparisonOperator' => 'GT'
|
257
|
+
}
|
170
258
|
},
|
171
259
|
'ScanIndexForward' => true
|
172
260
|
})
|
@@ -205,25 +293,22 @@ module FakeDynamo
|
|
205
293
|
response = subject.process('BatchGetItem', { 'RequestItems' =>
|
206
294
|
{
|
207
295
|
'User' => {
|
208
|
-
'Keys' => [{ '
|
209
|
-
{ '
|
296
|
+
'Keys' => [{ 'id' => { 'S' => '1' }},
|
297
|
+
{ 'id' => { 'S' => '2' }}]
|
210
298
|
},
|
211
299
|
'Table1' => {
|
212
|
-
'Keys' => [{'
|
213
|
-
'
|
300
|
+
'Keys' => [{'AttributeName1' => { 'S' => 'test' },
|
301
|
+
'AttributeName2' => { 'N' => '11' }}],
|
214
302
|
'AttributesToGet' => ['AttributeName1', 'AttributeName2']
|
215
303
|
}
|
216
304
|
}})
|
217
305
|
|
218
306
|
response.should eq({"Responses"=>
|
219
307
|
{"User"=>
|
220
|
-
{"
|
221
|
-
"Items"=>[{"id"=>{"S"=>"1"}}, {"id"=>{"S"=>"2"}}]},
|
308
|
+
[{"id"=>{"S"=>"1"}}, {"id"=>{"S"=>"2"}}],
|
222
309
|
"Table1"=>
|
223
|
-
{"
|
224
|
-
|
225
|
-
[{"AttributeName1"=>{"S"=>"test"},
|
226
|
-
"AttributeName2"=>{"N"=>"11"}}]}},
|
310
|
+
[{"AttributeName1"=>{"S"=>"test"},
|
311
|
+
"AttributeName2"=>{"N"=>"11"}}]},
|
227
312
|
"UnprocessedKeys"=>{}})
|
228
313
|
end
|
229
314
|
|
@@ -231,15 +316,15 @@ module FakeDynamo
|
|
231
316
|
response = subject.process('BatchGetItem', { 'RequestItems' =>
|
232
317
|
{
|
233
318
|
'User' => {
|
234
|
-
'Keys' => [{ '
|
235
|
-
{ '
|
319
|
+
'Keys' => [{ 'id' => { 'S' => '1' }},
|
320
|
+
{ 'id' => { 'S' => 'asd' }}]
|
236
321
|
}
|
237
|
-
}
|
322
|
+
},
|
323
|
+
'ReturnConsumedCapacity' => 'TOTAL'})
|
238
324
|
response.should eq({"Responses"=>
|
239
|
-
{"User"=>
|
240
|
-
|
241
|
-
|
242
|
-
"UnprocessedKeys"=>{}})
|
325
|
+
{"User"=> [{"id"=>{"S"=>"1"}}]},
|
326
|
+
"UnprocessedKeys"=>{},
|
327
|
+
"ConsumedCapacity" => ['CapacityUnits' => 1, 'TableName' => 'User']})
|
243
328
|
end
|
244
329
|
|
245
330
|
it 'should fail if table not found' do
|
@@ -247,8 +332,8 @@ module FakeDynamo
|
|
247
332
|
subject.process('BatchGetItem', { 'RequestItems' =>
|
248
333
|
{
|
249
334
|
'xxx' => {
|
250
|
-
'Keys' => [{ '
|
251
|
-
{ '
|
335
|
+
'Keys' => [{ 'AttributeName1' => { 'S' => '1' }},
|
336
|
+
{ 'AttributeName1' => { 'S' => 'asd' }}]}
|
252
337
|
}})
|
253
338
|
}.to raise_error(FakeDynamo::ResourceNotFoundException)
|
254
339
|
end
|
@@ -261,6 +346,8 @@ module FakeDynamo
|
|
261
346
|
db
|
262
347
|
end
|
263
348
|
|
349
|
+
let(:consumed_capacity) { {'ConsumedCapacity' => { 'CapacityUnits' => 1, 'TableName' => 'User' }} }
|
350
|
+
|
264
351
|
it 'should validate payload' do
|
265
352
|
expect {
|
266
353
|
subject.process('BatchWriteItem', {})
|
@@ -271,7 +358,7 @@ module FakeDynamo
|
|
271
358
|
expect {
|
272
359
|
subject.process('BatchWriteItem', {
|
273
360
|
'RequestItems' => {
|
274
|
-
'xxx' => ['DeleteRequest' => { 'Key' => { '
|
361
|
+
'xxx' => ['DeleteRequest' => { 'Key' => { 'AttributeName1' => { 'S' => 'ananth' }}}]
|
275
362
|
}
|
276
363
|
})
|
277
364
|
}.to raise_error(FakeDynamo::ResourceNotFoundException, /table.*not.*found/i)
|
@@ -281,8 +368,8 @@ module FakeDynamo
|
|
281
368
|
expect {
|
282
369
|
subject.process('BatchWriteItem', {
|
283
370
|
'RequestItems' => {
|
284
|
-
'User' => [{ 'DeleteRequest' => { 'Key' => { '
|
285
|
-
{ 'DeleteRequest' => { 'Key' => { '
|
371
|
+
'User' => [{ 'DeleteRequest' => { 'Key' => { 'id' => { 'S' => 'ananth' }}}},
|
372
|
+
{ 'DeleteRequest' => { 'Key' => { 'id' => { 'S' => 'ananth' }}}}]
|
286
373
|
}
|
287
374
|
})
|
288
375
|
}.to raise_error(FakeDynamo::ValidationException, /duplicate/i)
|
@@ -290,7 +377,7 @@ module FakeDynamo
|
|
290
377
|
expect {
|
291
378
|
subject.process('BatchWriteItem', {
|
292
379
|
'RequestItems' => {
|
293
|
-
'User' => [{ 'DeleteRequest' => { 'Key' => { '
|
380
|
+
'User' => [{ 'DeleteRequest' => { 'Key' => { 'id' => { 'S' => 'ananth' }}}},
|
294
381
|
{'PutRequest' => {'Item' => { 'id' => { 'S' => 'ananth'}}}}]
|
295
382
|
}
|
296
383
|
})
|
@@ -310,31 +397,38 @@ module FakeDynamo
|
|
310
397
|
response = subject.process('BatchWriteItem', {
|
311
398
|
'RequestItems' => {
|
312
399
|
'User' => [{'PutRequest' => {'Item' => { 'id' => { 'S' => 'ananth'}}}}]
|
313
|
-
}
|
400
|
+
},
|
401
|
+
'ReturnConsumedCapacity' => 'TOTAL'
|
314
402
|
})
|
315
|
-
|
316
|
-
response
|
403
|
+
response['ItemCollectionMetrics'].should be_nil
|
404
|
+
response.should eq('ConsumedCapacity' => [consumed_capacity['ConsumedCapacity']],
|
405
|
+
'UnprocessedItems' => {})
|
317
406
|
|
318
407
|
response = subject.get_item({'TableName' => 'User',
|
319
|
-
'Key' => {'
|
408
|
+
'Key' => {'id' => { 'S' => 'ananth'}}})
|
320
409
|
|
321
410
|
response['Item']['id'].should eq('S' => 'ananth')
|
322
411
|
|
323
|
-
subject.process('BatchWriteItem', {
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
412
|
+
response = subject.process('BatchWriteItem', {
|
413
|
+
'RequestItems' => {
|
414
|
+
'User' => [{ 'DeleteRequest' => { 'Key' => { 'id' => { 'S' => 'ananth' }}}}]
|
415
|
+
},
|
416
|
+
'ReturnItemCollectionMetrics' => 'SIZE'
|
417
|
+
})
|
418
|
+
|
419
|
+
response['ItemCollectionMetrics'].should_not be_nil
|
328
420
|
|
329
421
|
response = subject.get_item({'TableName' => 'User',
|
330
|
-
'Key' => {'
|
422
|
+
'Key' => {'id' => { 'S' => 'ananth'}},
|
423
|
+
'ReturnConsumedCapacity' => 'TOTAL'})
|
424
|
+
|
425
|
+
response.should eq(consumed_capacity)
|
331
426
|
|
332
|
-
response.should eq({"ConsumedCapacityUnits"=>1})
|
333
427
|
end
|
334
428
|
|
335
429
|
it 'fails it the requested operation is more than 25' do
|
336
430
|
expect {
|
337
|
-
requests = (1..26).map { |i| { 'DeleteRequest' => { 'Key' => { '
|
431
|
+
requests = (1..26).map { |i| { 'DeleteRequest' => { 'Key' => { 'id' => { 'S' => "ananth#{i}" }}}} }
|
338
432
|
|
339
433
|
subject.process('BatchWriteItem', {
|
340
434
|
'RequestItems' => {
|
@@ -342,7 +436,7 @@ module FakeDynamo
|
|
342
436
|
}
|
343
437
|
})
|
344
438
|
|
345
|
-
}.to raise_error(FakeDynamo::ValidationException, /
|
439
|
+
}.to raise_error(FakeDynamo::ValidationException, /within.*25/i)
|
346
440
|
end
|
347
441
|
|
348
442
|
it 'should fail on request size greater than 1 mb' do
|
@@ -7,9 +7,12 @@ module FakeDynamo
|
|
7
7
|
let(:data) do
|
8
8
|
{
|
9
9
|
"TableName" => "Table1",
|
10
|
+
"AttributeDefinitions" =>
|
11
|
+
[{"AttributeName" => "AttributeName1","AttributeType" => "S"},
|
12
|
+
{"AttributeName" => "AttributeName2","AttributeType" => "N"}],
|
10
13
|
"KeySchema" =>
|
11
|
-
{"
|
12
|
-
|
14
|
+
[{"AttributeName" => "AttributeName1","KeyType" => "HASH"},
|
15
|
+
{"AttributeName" => "AttributeName2","KeyType" => "RANGE"}],
|
13
16
|
"ProvisionedThroughput" => {"ReadCapacityUnits" => 5,"WriteCapacityUnits" => 10}
|
14
17
|
}
|
15
18
|
end
|
@@ -6,8 +6,10 @@ module FakeDynamo
|
|
6
6
|
|
7
7
|
let(:table) do
|
8
8
|
{"TableName" => "User",
|
9
|
+
"AttributeDefinitions" =>
|
10
|
+
[{"AttributeName" => "id","AttributeType" => "S"}],
|
9
11
|
"KeySchema" =>
|
10
|
-
{"
|
12
|
+
[{"AttributeName" => "id","KeyType" => "HASH"}],
|
11
13
|
"ProvisionedThroughput" => {"ReadCapacityUnits" => 5,"WriteCapacityUnits" => 10}
|
12
14
|
}
|
13
15
|
end
|