fake_dynamo 0.1.4 → 0.2.0
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/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
|