fake_dynamo 0.2.4 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -1
- data/README.md +10 -2
- data/bin/fake_dynamo +1 -1
- data/lib/fake_dynamo/api_2012-08-10.yml +1 -0
- data/lib/fake_dynamo/item.rb +11 -1
- data/lib/fake_dynamo/storage.rb +9 -12
- data/lib/fake_dynamo/table.rb +6 -4
- data/lib/fake_dynamo/version.rb +1 -1
- data/spec/fake_dynamo/table_spec.rb +39 -15
- data/spec/spec_helper.rb +1 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00648c19b3f1c992a04883bf4d11c9f20dbcb0fc
|
4
|
+
data.tar.gz: 682d63c6cdd1d7cfb71b5cb6e49015e2511e78cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 451e3ecb17977f41920ecc97c5a83f609914665be57d567624704b6b4b6ede06a5423e1208b7b811eebc44323610ab2141b8c2dc1ab1aad9866fd228e77b3401
|
7
|
+
data.tar.gz: ea9338856d85b0550e44fe69090a33872470fe2bf861f09985f4a4707d42f03c6656ce91be213999c4a58ee698a9f1191b60d34717f882f458e410d1b4264cb9
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -6,7 +6,7 @@ local hosted, inmemory Amazon DynamoDB emulator.
|
|
6
6
|
|
7
7
|
| Amazon DynamoDB API version | FakeDynamo gem version|
|
8
8
|
| --------------------------- | ----------------------|
|
9
|
-
| [2012-08-10][v2] | 0.2.
|
9
|
+
| [2012-08-10][v2] | 0.2.5 |
|
10
10
|
| [2011-12-05][v1] | 0.1.3 |
|
11
11
|
|
12
12
|
|
@@ -19,7 +19,7 @@ local hosted, inmemory Amazon DynamoDB emulator.
|
|
19
19
|
__requires ruby >= 1.9__
|
20
20
|
|
21
21
|
````
|
22
|
-
gem install fake_dynamo --version 0.2.
|
22
|
+
gem install fake_dynamo --version 0.2.5
|
23
23
|
|
24
24
|
fake_dynamo --port 4567
|
25
25
|
````
|
@@ -53,6 +53,14 @@ AWS.config(:use_ssl => false,
|
|
53
53
|
region: "xxx"});
|
54
54
|
````
|
55
55
|
|
56
|
+
* [aws-sdk-java](https://github.com/aws/aws-sdk-java) (AWS SDK for Java)
|
57
|
+
|
58
|
+
````java
|
59
|
+
AWSCredentials credentials = new BasicAWSCredentials("xxx", "xxx");
|
60
|
+
AmazonDynamoDB client = new AmazonDynamoDBClient(credentials);
|
61
|
+
client.setEndpoint("http://localhost:4567");
|
62
|
+
````
|
63
|
+
|
56
64
|
__please open a pull request with your configuration if you are using
|
57
65
|
fake_dynamo with clients other than the ones mentioned above__.
|
58
66
|
|
data/bin/fake_dynamo
CHANGED
@@ -57,7 +57,7 @@ if (pid = options[:pid])
|
|
57
57
|
File.open(pid, 'w') { |f| f.write(Process.pid) }
|
58
58
|
end
|
59
59
|
|
60
|
-
FakeDynamo::Storage.
|
60
|
+
FakeDynamo::Storage.instance.init_db(options[:db])
|
61
61
|
FakeDynamo::Logger.setup(options[:log_level])
|
62
62
|
|
63
63
|
if options[:compact]
|
data/lib/fake_dynamo/item.rb
CHANGED
@@ -4,7 +4,7 @@ module FakeDynamo
|
|
4
4
|
attr_accessor :key, :attributes
|
5
5
|
|
6
6
|
class << self
|
7
|
-
def from_data(data, key_schema)
|
7
|
+
def from_data(data, key_schema, attribute_definitions)
|
8
8
|
item = Item.new
|
9
9
|
item.key = Key.from_schema(data, key_schema)
|
10
10
|
|
@@ -14,6 +14,8 @@ module FakeDynamo
|
|
14
14
|
item.attributes[name] = Attribute.from_hash(name, value)
|
15
15
|
end
|
16
16
|
end
|
17
|
+
|
18
|
+
item.validate_attribute_types(attribute_definitions)
|
17
19
|
item
|
18
20
|
end
|
19
21
|
|
@@ -116,5 +118,13 @@ module FakeDynamo
|
|
116
118
|
{}
|
117
119
|
end
|
118
120
|
end
|
121
|
+
|
122
|
+
def validate_attribute_types(definitions)
|
123
|
+
definitions.each do |definition|
|
124
|
+
if attr = self[definition.name]
|
125
|
+
validate_type(attr.as_hash[definition.name], definition)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
119
129
|
end
|
120
130
|
end
|
data/lib/fake_dynamo/storage.rb
CHANGED
@@ -4,11 +4,9 @@ require 'tempfile'
|
|
4
4
|
module FakeDynamo
|
5
5
|
class Storage
|
6
6
|
|
7
|
-
attr_accessor :compacted, :loaded
|
7
|
+
attr_accessor :compacted, :loaded, :db_path
|
8
8
|
|
9
9
|
class << self
|
10
|
-
attr_accessor :db_path
|
11
|
-
|
12
10
|
def instance
|
13
11
|
@storage ||= Storage.new
|
14
12
|
end
|
@@ -18,10 +16,6 @@ module FakeDynamo
|
|
18
16
|
Logger.log
|
19
17
|
end
|
20
18
|
|
21
|
-
def initialize
|
22
|
-
init_db
|
23
|
-
end
|
24
|
-
|
25
19
|
def write_commands
|
26
20
|
%w[CreateTable DeleteItem DeleteTable PutItem UpdateItem UpdateTable BatchWriteItem]
|
27
21
|
end
|
@@ -30,14 +24,17 @@ module FakeDynamo
|
|
30
24
|
write_commands.include?(command)
|
31
25
|
end
|
32
26
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
27
|
+
def init_db(path)
|
28
|
+
@db_path = path
|
29
|
+
|
30
|
+
return if File.exists?(db_path) && File.writable?(db_path)
|
36
31
|
|
37
|
-
def init_db
|
38
|
-
return if File.exists? db_path
|
39
32
|
FileUtils.mkdir_p(File.dirname(db_path))
|
40
33
|
FileUtils.touch(db_path)
|
34
|
+
rescue Errno::EACCES
|
35
|
+
puts "Cannot create or access db file at #{db_path}"
|
36
|
+
puts "Make sure you have write access to #{db_path}"
|
37
|
+
exit(1)
|
41
38
|
end
|
42
39
|
|
43
40
|
def delete_db
|
data/lib/fake_dynamo/table.rb
CHANGED
@@ -106,7 +106,7 @@ module FakeDynamo
|
|
106
106
|
end
|
107
107
|
|
108
108
|
def put_item(data)
|
109
|
-
item = Item.from_data(data['Item'], key_schema)
|
109
|
+
item = Item.from_data(data['Item'], key_schema, attribute_definitions)
|
110
110
|
old_item = @items[item.key]
|
111
111
|
check_conditions(old_item, data['Expected'])
|
112
112
|
@items[item.key] = item
|
@@ -115,7 +115,7 @@ module FakeDynamo
|
|
115
115
|
end
|
116
116
|
|
117
117
|
def batch_put_request(data)
|
118
|
-
Item.from_data(data['Item'], key_schema)
|
118
|
+
Item.from_data(data['Item'], key_schema, attribute_definitions)
|
119
119
|
end
|
120
120
|
|
121
121
|
def batch_put(item)
|
@@ -193,6 +193,8 @@ module FakeDynamo
|
|
193
193
|
attribute_updates.each do |name, update_data|
|
194
194
|
item.update(name, update_data)
|
195
195
|
end
|
196
|
+
|
197
|
+
item.validate_attribute_types(attribute_definitions)
|
196
198
|
end
|
197
199
|
rescue => e
|
198
200
|
if item_created
|
@@ -318,14 +320,14 @@ module FakeDynamo
|
|
318
320
|
end
|
319
321
|
|
320
322
|
def sack_attributes(data, index)
|
321
|
-
return
|
323
|
+
return if !index || index.projection.type == 'ALL'
|
322
324
|
|
323
325
|
if data['Select'] == 'COUNT'
|
324
326
|
return projected_attributes(index)
|
325
327
|
end
|
326
328
|
|
327
329
|
if attrs = attributes_to_get(data, index)
|
328
|
-
if (attrs - projected_attributes(index)).empty?
|
330
|
+
if (attrs - (projected_attributes(index))).empty?
|
329
331
|
return projected_attributes(index)
|
330
332
|
end
|
331
333
|
end
|
data/lib/fake_dynamo/version.rb
CHANGED
@@ -30,7 +30,7 @@ module FakeDynamo
|
|
30
30
|
'Item' => {
|
31
31
|
'AttributeName1' => { 'S' => "test" },
|
32
32
|
'AttributeName2' => { 'N' => '11' },
|
33
|
-
'AttributeName3' => { '
|
33
|
+
'AttributeName3' => { 'N' => "14" },
|
34
34
|
'binary' => { 'B' => Base64.strict_encode64("binary") },
|
35
35
|
'binary_set' => { 'BS' => [Base64.strict_encode64("binary")] }
|
36
36
|
},
|
@@ -146,6 +146,17 @@ module FakeDynamo
|
|
146
146
|
end.to raise_error(ValidationException, /mismatch/i)
|
147
147
|
end
|
148
148
|
|
149
|
+
it 'should fail on index type mismatch' do
|
150
|
+
expect do
|
151
|
+
subject.put_item({ 'TableName' => 'Table1',
|
152
|
+
'Item' => {
|
153
|
+
'AttributeName1' => { 'S' => "test" },
|
154
|
+
'AttributeName2' => { 'N' => '11' },
|
155
|
+
'AttributeName3' => { 'S' => 'another' },
|
156
|
+
}})
|
157
|
+
end.to raise_error(ValidationException, /mismatch/i)
|
158
|
+
end
|
159
|
+
|
149
160
|
it 'should fail if the attribute value contains empty string' do
|
150
161
|
expect do
|
151
162
|
subject.put_item({ 'TableName' => 'Table1',
|
@@ -204,9 +215,9 @@ module FakeDynamo
|
|
204
215
|
[[{}, /set to null/],
|
205
216
|
[{'Exists' => true}, /set to true/],
|
206
217
|
[{'Exists' => false}],
|
207
|
-
[{'Value' => { '
|
208
|
-
[{'Value' => { '
|
209
|
-
[{'Value' => { '
|
218
|
+
[{'Value' => { 'N' => '15' } }],
|
219
|
+
[{'Value' => { 'N' => '15' }, 'Exists' => true}],
|
220
|
+
[{'Value' => { 'N' => '15' }, 'Exists' => false}, /cannot expect/i]].each do |value, message|
|
210
221
|
|
211
222
|
op = lambda {
|
212
223
|
subject.put_item(item.merge({'Expected' => { 'AttributeName3' => value }}))
|
@@ -221,14 +232,14 @@ module FakeDynamo
|
|
221
232
|
end
|
222
233
|
|
223
234
|
it 'should give default response' do
|
224
|
-
item['Item']['AttributeName3'] = { '
|
235
|
+
item['Item']['AttributeName3'] = { 'N' => "17" }
|
225
236
|
subject.put_item(item).should include(consumed_capacity)
|
226
237
|
end
|
227
238
|
|
228
239
|
it 'should send old item' do
|
229
240
|
old_item = Utils.deep_copy(item)
|
230
241
|
new_item = Utils.deep_copy(item)
|
231
|
-
new_item['Item']['AttributeName3'] = { '
|
242
|
+
new_item['Item']['AttributeName3'] = { 'N' => "17" }
|
232
243
|
new_item.merge!({'ReturnValues' => 'ALL_OLD'})
|
233
244
|
subject.put_item(new_item)['Attributes'].should == old_item['Item']
|
234
245
|
end
|
@@ -261,7 +272,7 @@ module FakeDynamo
|
|
261
272
|
'AttributesToGet' => ['AttributeName3', 'xxx'],
|
262
273
|
'ReturnConsumedCapacity' => 'TOTAL'
|
263
274
|
})
|
264
|
-
response.should eq({ 'Item' => { 'AttributeName3' => { '
|
275
|
+
response.should eq({ 'Item' => { 'AttributeName3' => { 'N' => '14'}}}
|
265
276
|
.merge(consumed_capacity))
|
266
277
|
end
|
267
278
|
end
|
@@ -293,13 +304,13 @@ module FakeDynamo
|
|
293
304
|
|
294
305
|
response = subject.delete_item(key.merge({'Expected' =>
|
295
306
|
{'AttributeName3' =>
|
296
|
-
{'Value' => { '
|
307
|
+
{'Value' => { 'N' => '14'}}}}))
|
297
308
|
response.should eq(consumed_capacity)
|
298
309
|
|
299
310
|
expect do
|
300
311
|
subject.delete_item(key.merge({'Expected' =>
|
301
312
|
{'AttributeName3' =>
|
302
|
-
{'Value' => { '
|
313
|
+
{'Value' => { 'N' => '14'}}}}))
|
303
314
|
end.to raise_error(ConditionalCheckFailedException)
|
304
315
|
end
|
305
316
|
|
@@ -317,7 +328,7 @@ module FakeDynamo
|
|
317
328
|
end
|
318
329
|
|
319
330
|
let(:put) do
|
320
|
-
{'AttributeUpdates' => {'AttributeName3' => { 'Value' => { '
|
331
|
+
{'AttributeUpdates' => {'AttributeName3' => { 'Value' => { 'N' => '18' },
|
321
332
|
'Action' => 'PUT'}}}
|
322
333
|
end
|
323
334
|
|
@@ -348,13 +359,20 @@ module FakeDynamo
|
|
348
359
|
end.to raise_error(ConditionalCheckFailedException)
|
349
360
|
end
|
350
361
|
|
362
|
+
it "should check index types" do
|
363
|
+
expect do
|
364
|
+
put['AttributeUpdates']['AttributeName3']['Value'] = {'S' => 'another'}
|
365
|
+
subject.update_item(key.merge(put))
|
366
|
+
end.to raise_error(ValidationException, /mismatch/i)
|
367
|
+
end
|
368
|
+
|
351
369
|
it "should create new item if the key doesn't exist" do
|
352
370
|
key['Key']['AttributeName1']['S'] = 'new'
|
353
371
|
subject.update_item(key.merge(put))
|
354
372
|
subject.get_item(key).should include( "Item"=>
|
355
373
|
{"AttributeName1"=>{"S"=>"new"},
|
356
374
|
"AttributeName2"=>{"N"=>"11"},
|
357
|
-
"AttributeName3"=>{"
|
375
|
+
"AttributeName3"=>{"N"=>"18"}})
|
358
376
|
end
|
359
377
|
|
360
378
|
it "shouldn't create a new item if key doesn't exist and action is delete" do
|
@@ -365,13 +383,13 @@ module FakeDynamo
|
|
365
383
|
|
366
384
|
it "should handle return values" do
|
367
385
|
data = key.merge(put).merge({'ReturnValues' => 'UPDATED_NEW'})
|
368
|
-
subject.update_item(data).should include({'Attributes' => { 'AttributeName3' => { '
|
386
|
+
subject.update_item(data).should include({'Attributes' => { 'AttributeName3' => { 'N' => '18'}}})
|
369
387
|
end
|
370
388
|
end
|
371
389
|
|
372
390
|
context '#return_values' do
|
373
391
|
let(:put) do
|
374
|
-
{'AttributeUpdates' => {'AttributeName3' => { 'Value' => { '
|
392
|
+
{'AttributeUpdates' => {'AttributeName3' => { 'Value' => { 'N' => '19' },
|
375
393
|
'Action' => 'PUT'}}}
|
376
394
|
end
|
377
395
|
|
@@ -388,13 +406,13 @@ module FakeDynamo
|
|
388
406
|
it "should return update old value" do
|
389
407
|
subject.put_item(item)
|
390
408
|
data = key.merge(put).merge({'ReturnValues' => 'UPDATED_OLD'})
|
391
|
-
subject.update_item(data).should include({'Attributes' => { 'AttributeName3' => { '
|
409
|
+
subject.update_item(data).should include({'Attributes' => { 'AttributeName3' => { 'N' => '14'}}})
|
392
410
|
end
|
393
411
|
|
394
412
|
it "should return update new value" do
|
395
413
|
subject.put_item(item)
|
396
414
|
data = key.merge(put).merge({'ReturnValues' => 'UPDATED_NEW'})
|
397
|
-
subject.update_item(data).should include({'Attributes' => { 'AttributeName3' => { '
|
415
|
+
subject.update_item(data).should include({'Attributes' => { 'AttributeName3' => { 'N' => '19'}}})
|
398
416
|
end
|
399
417
|
end
|
400
418
|
|
@@ -636,6 +654,12 @@ module FakeDynamo
|
|
636
654
|
result['Items'].first.should eq('AttributeName1' => { 'S' => 'att1'},
|
637
655
|
'AttributeName2' => { 'N' => '3' })
|
638
656
|
end
|
657
|
+
|
658
|
+
it 'should handle attributes_to_get within index' do
|
659
|
+
index_query['AttributesToGet'] = ['AttributeName1']
|
660
|
+
result = subject.query(index_query)
|
661
|
+
result['Items'].first.should eq('AttributeName1' => { 'S' => 'att1'})
|
662
|
+
end
|
639
663
|
end
|
640
664
|
|
641
665
|
context '#scan' do
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fake_dynamo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anantha Kumaran
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-09-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sinatra
|