fake_dynamo 0.2.4 → 0.2.5
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.
- 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
|