aws-sessionstore-dynamodb 0.5.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.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.yardopts +3 -0
- data/Gemfile +28 -0
- data/LICENSE.txt +12 -0
- data/README.md +171 -0
- data/Rakefile +15 -0
- data/aws-sessionstore-dynamodb.gemspec +18 -0
- data/lib/aws-sessionstore-dynamodb.rb +34 -0
- data/lib/aws/session_store/dynamo_db/configuration.rb +298 -0
- data/lib/aws/session_store/dynamo_db/errors/base_handler.rb +45 -0
- data/lib/aws/session_store/dynamo_db/errors/default_handler.rb +57 -0
- data/lib/aws/session_store/dynamo_db/garbage_collection.rb +128 -0
- data/lib/aws/session_store/dynamo_db/invalid_id_error.rb +21 -0
- data/lib/aws/session_store/dynamo_db/lock_wait_timeout_error.rb +21 -0
- data/lib/aws/session_store/dynamo_db/locking/base.rb +162 -0
- data/lib/aws/session_store/dynamo_db/locking/null.rb +40 -0
- data/lib/aws/session_store/dynamo_db/locking/pessimistic.rb +160 -0
- data/lib/aws/session_store/dynamo_db/missing_secret_key_error.rb +21 -0
- data/lib/aws/session_store/dynamo_db/rack_middleware.rb +130 -0
- data/lib/aws/session_store/dynamo_db/railtie.rb +28 -0
- data/lib/aws/session_store/dynamo_db/table.rb +98 -0
- data/lib/aws/session_store/dynamo_db/tasks/session_table.rake +21 -0
- data/lib/aws/session_store/dynamo_db/version.rb +21 -0
- data/lib/rails/generators/sessionstore/dynamodb/dynamodb_generator.rb +55 -0
- data/lib/rails/generators/sessionstore/dynamodb/templates/sessionstore/USAGE +13 -0
- data/lib/rails/generators/sessionstore/dynamodb/templates/sessionstore/dynamodb.yml +71 -0
- data/lib/rails/generators/sessionstore/dynamodb/templates/sessionstore_migration.rb +10 -0
- data/spec/aws/session_store/dynamo_db/app_config.yml +19 -0
- data/spec/aws/session_store/dynamo_db/config/dynamo_db_session.yml +24 -0
- data/spec/aws/session_store/dynamo_db/configuration_spec.rb +101 -0
- data/spec/aws/session_store/dynamo_db/error/default_error_handler_spec.rb +62 -0
- data/spec/aws/session_store/dynamo_db/garbage_collection_spec.rb +156 -0
- data/spec/aws/session_store/dynamo_db/locking/threaded_sessions_spec.rb +95 -0
- data/spec/aws/session_store/dynamo_db/rack_middleware_database_spec.rb +129 -0
- data/spec/aws/session_store/dynamo_db/rack_middleware_spec.rb +149 -0
- data/spec/aws/session_store/dynamo_db/rails_app_config.yml +24 -0
- data/spec/aws/session_store/dynamo_db/table_spec.rb +46 -0
- data/spec/spec_helper.rb +61 -0
- data/tasks/test.rake +29 -0
- metadata +123 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
5
|
+
# the License is located at
|
6
|
+
#
|
7
|
+
# http://aws.amazon.com/apache2.0/
|
8
|
+
#
|
9
|
+
# or in the "license" file accompanying this file. This file is
|
10
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
11
|
+
# ANY KIND, either express or implied. See the License for the specific
|
12
|
+
# language governing permissions and limitations under the License.
|
13
|
+
|
14
|
+
|
15
|
+
module AWS
|
16
|
+
module SessionStore
|
17
|
+
module DynamoDB
|
18
|
+
VERSION = "0.5.0"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
5
|
+
# the License is located at
|
6
|
+
#
|
7
|
+
# http://aws.amazon.com/apache2.0/
|
8
|
+
#
|
9
|
+
# or in the "license" file accompanying this file. This file is
|
10
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
11
|
+
# ANY KIND, either express or implied. See the License for the specific
|
12
|
+
# language governing permissions and limitations under the License.
|
13
|
+
|
14
|
+
require 'rails/generators/named_base'
|
15
|
+
|
16
|
+
# This class generates
|
17
|
+
# a migration file for deleting and creating
|
18
|
+
# a DynamoDB sessions table.
|
19
|
+
module Sessionstore
|
20
|
+
module Generators
|
21
|
+
class DynamodbGenerator < Rails::Generators::NamedBase
|
22
|
+
include Rails::Generators::Migration
|
23
|
+
|
24
|
+
source_root File.expand_path('templates', File.dirname(__FILE__))
|
25
|
+
|
26
|
+
# Desired name of migration class
|
27
|
+
argument :name, :type => :string, :default => "sessionstore_migration"
|
28
|
+
|
29
|
+
# @return [Rails Migration File] migration file for creation and deletion of
|
30
|
+
# session table.
|
31
|
+
def generate_migration_file
|
32
|
+
migration_template "sessionstore_migration.rb",
|
33
|
+
"#{Rails.root}/db/migrate/#{file_name}"
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def copy_sample_config_file
|
38
|
+
file = File.join("sessionstore", "dynamodb.yml")
|
39
|
+
template file, File.join(Rails.root, "config", file)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# @return [String] filename
|
45
|
+
def file_name
|
46
|
+
name.underscore
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [String] migration version using time stamp YYYYMMDDHHSS
|
50
|
+
def self.next_migration_number(dir = nil)
|
51
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Description:
|
2
|
+
Generates a migration file for deleting and a creating a DynamoDB
|
3
|
+
sessions table, and a configuration file for the session store.
|
4
|
+
|
5
|
+
Example:
|
6
|
+
rails generate sessionstore:dynamodb <MigrationName>
|
7
|
+
|
8
|
+
This will create:
|
9
|
+
db/migrate/VERSION_migration_name.rb
|
10
|
+
config/sessionstore/dynamodb.yml
|
11
|
+
|
12
|
+
The migration will be run when the command rake db:migrate is run
|
13
|
+
in the command line.
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# Uncomment and manipulate the key value pairs below
|
2
|
+
# in order to configure the DynamoDB Session Store Application.
|
3
|
+
|
4
|
+
# [String] The secret key for HMAC encryption.
|
5
|
+
# Must define secret_key here or ENV or at runtime!
|
6
|
+
# By default, a random key was generated for you!
|
7
|
+
#
|
8
|
+
secret_key: <%= require 'securerandom'; SecureRandom.hex(64) %>
|
9
|
+
|
10
|
+
# [String] Session table name.
|
11
|
+
#
|
12
|
+
# table_name: Sessions
|
13
|
+
|
14
|
+
# [String] Session table hash key name.
|
15
|
+
#
|
16
|
+
# table_key: session_id
|
17
|
+
|
18
|
+
# [Boolean] Define as true or false depending on if you want a strongly
|
19
|
+
# consistent read.
|
20
|
+
# See AWS DynamoDB documentation for table consistent_read for more
|
21
|
+
# information on this setting.
|
22
|
+
#
|
23
|
+
# consistent_read: true
|
24
|
+
|
25
|
+
# [Integer] Maximum number of reads consumed per second before
|
26
|
+
# DynamoDB returns a ThrottlingException. See AWS DynamoDB documentation
|
27
|
+
# or table read_capacity for more information on this setting.
|
28
|
+
#
|
29
|
+
# read_capacity: 10
|
30
|
+
|
31
|
+
# [Integer] Maximum number of writes consumed per second before
|
32
|
+
# DynamoDB returns a ThrottlingException. See AWS DynamoDB documentation
|
33
|
+
# or table write_capacity for more information on this setting.
|
34
|
+
#
|
35
|
+
# write_capacity: 5
|
36
|
+
|
37
|
+
# [Boolean] Define as true or false depending on whether you want all errors to be
|
38
|
+
# raised up the stack.
|
39
|
+
#
|
40
|
+
# raise_errors: false
|
41
|
+
|
42
|
+
# [Integer] Maximum number of seconds earlier
|
43
|
+
# from the current time that a session was created.
|
44
|
+
# By default this is 7 days.
|
45
|
+
#
|
46
|
+
# max_age: 604800
|
47
|
+
|
48
|
+
# [Integer] Maximum number of seconds
|
49
|
+
# before the current time that the session was last accessed.
|
50
|
+
# By default this is 5 hours.
|
51
|
+
#
|
52
|
+
# max_stale: 18000
|
53
|
+
|
54
|
+
# [Boolean] Define as true or false for whether you want to enable locking
|
55
|
+
# for all accesses to session data.
|
56
|
+
#
|
57
|
+
# enable_locking: false
|
58
|
+
|
59
|
+
# [Integer] Time in milleseconds after which lock will expire.
|
60
|
+
#
|
61
|
+
# lock_expiry_time: 500
|
62
|
+
|
63
|
+
# [Integer] Time in milleseconds to wait before retrying to obtain
|
64
|
+
# lock once an attempt to obtain lock has been made and has failed.
|
65
|
+
#
|
66
|
+
# lock_retry_delay: 500
|
67
|
+
|
68
|
+
# [Integer] Maximum time in seconds to wait to acquire lock
|
69
|
+
# before giving up.
|
70
|
+
#
|
71
|
+
# lock_max_wait_time: 1
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
5
|
+
# the License is located at
|
6
|
+
#
|
7
|
+
# http://aws.amazon.com/apache2.0/
|
8
|
+
#
|
9
|
+
# or in the "license" file accompanying this file. This file is
|
10
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
11
|
+
# ANY KIND, either express or implied. See the License for the specific
|
12
|
+
# language governing permissions and limitations under the License.
|
13
|
+
|
14
|
+
table_name: NewTable
|
15
|
+
table_key: Somekey
|
16
|
+
consistent_read: true
|
17
|
+
AWS_ACCESS_KEY_ID: FakeKey
|
18
|
+
AWS_SECRET_ACCESS_KEY: Secret
|
19
|
+
AWS_REGION: New York
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
5
|
+
# the License is located at
|
6
|
+
#
|
7
|
+
# http://aws.amazon.com/apache2.0/
|
8
|
+
#
|
9
|
+
# or in the "license" file accompanying this file. This file is
|
10
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
11
|
+
# ANY KIND, either express or implied. See the License for the specific
|
12
|
+
# language governing permissions and limitations under the License.
|
13
|
+
|
14
|
+
development:
|
15
|
+
key1: development value 1
|
16
|
+
test:
|
17
|
+
table_name: NewTable
|
18
|
+
table_key: Somekey
|
19
|
+
consistent_read: true
|
20
|
+
AWS_ACCESS_KEY_ID: FakeKey
|
21
|
+
AWS_SECRET_ACCESS_KEY: Secret
|
22
|
+
AWS_REGION: New York
|
23
|
+
production:
|
24
|
+
key1: production value 1
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
5
|
+
# the License is located at
|
6
|
+
#
|
7
|
+
# http://aws.amazon.com/apache2.0/
|
8
|
+
#
|
9
|
+
# or in the "license" file accompanying this file. This file is
|
10
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
11
|
+
# ANY KIND, either express or implied. See the License for the specific
|
12
|
+
# language governing permissions and limitations under the License.
|
13
|
+
|
14
|
+
require "spec_helper"
|
15
|
+
|
16
|
+
describe AWS::SessionStore::DynamoDB::Configuration do
|
17
|
+
|
18
|
+
let(:defaults) do
|
19
|
+
{
|
20
|
+
:table_name => "sessions",
|
21
|
+
:table_key => "session_id",
|
22
|
+
:consistent_read => true,
|
23
|
+
:read_capacity => 10,
|
24
|
+
:write_capacity => 5,
|
25
|
+
:raise_errors => false
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
let(:expected_file_opts) do
|
30
|
+
{
|
31
|
+
:consistent_read => true,
|
32
|
+
:AWS_ACCESS_KEY_ID => 'FakeKey',
|
33
|
+
:AWS_REGION => 'New York',
|
34
|
+
:table_name => 'NewTable',
|
35
|
+
:table_key => 'Somekey',
|
36
|
+
:AWS_SECRET_ACCESS_KEY => 'Secret'
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
let(:runtime_options) do
|
41
|
+
{
|
42
|
+
:table_name => "SessionTable",
|
43
|
+
:table_key => "session_id_stuff"
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def expected_options(opts)
|
48
|
+
cfg = AWS::SessionStore::DynamoDB::Configuration.new(opts)
|
49
|
+
expected_opts = defaults.merge(expected_file_opts).merge(opts)
|
50
|
+
cfg.to_hash.should include(expected_opts)
|
51
|
+
end
|
52
|
+
|
53
|
+
context "Configuration Tests" do
|
54
|
+
it "configures option with out runtime,YAML or ENV options" do
|
55
|
+
cfg = AWS::SessionStore::DynamoDB::Configuration.new
|
56
|
+
cfg.to_hash.should include(defaults)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "configures accurate option hash with runtime options, no YAML or ENV" do
|
60
|
+
cfg = AWS::SessionStore::DynamoDB::Configuration.new(runtime_options)
|
61
|
+
expected_opts = defaults.merge(runtime_options)
|
62
|
+
cfg.to_hash.should include(expected_opts)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "merge YAML and runtime options giving runtime precendence" do
|
66
|
+
config_path = File.dirname(__FILE__) + '/app_config.yml'
|
67
|
+
runtime_opts = {:config_file => config_path}.merge(runtime_options)
|
68
|
+
expected_options(runtime_opts)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "loads options from YAML file based on Rails environment" do
|
72
|
+
rails = double('Rails', {:env => 'test', :root => ''})
|
73
|
+
stub_const("Rails", rails)
|
74
|
+
config_path = File.dirname(__FILE__) + '/rails_app_config.yml'
|
75
|
+
runtime_opts = {:config_file => config_path}.merge(runtime_options)
|
76
|
+
expected_options(runtime_opts)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "has rails defiend but no file specified, no error thrown" do
|
80
|
+
rails = double('Rails', {:env => 'test', :root => ''})
|
81
|
+
stub_const("Rails", rails)
|
82
|
+
cfg = AWS::SessionStore::DynamoDB::Configuration.new(runtime_options)
|
83
|
+
expected_opts = defaults.merge(runtime_options)
|
84
|
+
cfg.to_hash.should include(expected_opts)
|
85
|
+
end
|
86
|
+
|
87
|
+
it "has rails defiend but and default rails YAML file loads" do
|
88
|
+
rails = double('Rails', {:env => 'test', :root => File.dirname(__FILE__)})
|
89
|
+
stub_const("Rails", rails)
|
90
|
+
cfg = AWS::SessionStore::DynamoDB::Configuration.new(runtime_options)
|
91
|
+
expected_opts = defaults.merge(runtime_options)
|
92
|
+
cfg.to_hash.should include(expected_opts)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "throws an exception when wrong path for file" do
|
96
|
+
config_path = 'Wrong path!'
|
97
|
+
runtime_opts = {:config_file => config_path}.merge(runtime_options)
|
98
|
+
expect{cfg = AWS::SessionStore::DynamoDB::Configuration.new(runtime_opts)}.to raise_error(Errno::ENOENT)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
5
|
+
# the License is located at
|
6
|
+
#
|
7
|
+
# http://aws.amazon.com/apache2.0/
|
8
|
+
#
|
9
|
+
# or in the "license" file accompanying this file. This file is
|
10
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
11
|
+
# ANY KIND, either express or implied. See the License for the specific
|
12
|
+
# language governing permissions and limitations under the License.
|
13
|
+
|
14
|
+
|
15
|
+
require 'spec_helper'
|
16
|
+
|
17
|
+
describe AWS::SessionStore::DynamoDB do
|
18
|
+
include Rack::Test::Methods
|
19
|
+
|
20
|
+
instance_exec(&ConstantHelpers)
|
21
|
+
|
22
|
+
before do
|
23
|
+
@options = { :dynamo_db_client => client, :secret_key => 'meltingbutter' }
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:base_app) { MultiplierApplication.new }
|
27
|
+
let(:app) { AWS::SessionStore::DynamoDB::RackMiddleware.new(base_app, @options) }
|
28
|
+
let(:client) { double('AWS::DynamoDB::Client') }
|
29
|
+
|
30
|
+
context "Error handling for Rack Middleware with default error handler" do
|
31
|
+
it "raises error for missing secret key" do
|
32
|
+
client.stub(:update_item).and_raise(missing_key_error)
|
33
|
+
lambda { get "/" }.should raise_error(missing_key_error)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "catches exception for inaccurate table name and raises error " do
|
37
|
+
client.stub(:update_item).and_raise(resource_error)
|
38
|
+
lambda { get "/" }.should raise_error(resource_error)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "catches exception for inaccurate table key" do
|
42
|
+
client.stub(:update_item).and_raise(key_error)
|
43
|
+
client.stub(:get_item).and_raise(key_error)
|
44
|
+
get "/"
|
45
|
+
last_request.env["rack.errors"].string.should include(key_error_msg)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "Test ExceptionHandler with true as return value for handle_error" do
|
50
|
+
it "raises all errors" do
|
51
|
+
@options[:raise_errors] = true
|
52
|
+
client.stub(:update_item).and_raise(client_error)
|
53
|
+
lambda { get "/" }.should raise_error(client_error)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "catches exception for inaccurate table key and raises error" do
|
57
|
+
@options[:raise_errors] = true
|
58
|
+
client.stub(:update_item).and_raise(key_error)
|
59
|
+
lambda { get "/" }.should raise_error(key_error)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
5
|
+
# the License is located at
|
6
|
+
#
|
7
|
+
# http://aws.amazon.com/apache2.0/
|
8
|
+
#
|
9
|
+
# or in the "license" file accompanying this file. This file is
|
10
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
11
|
+
# ANY KIND, either express or implied. See the License for the specific
|
12
|
+
# language governing permissions and limitations under the License.
|
13
|
+
|
14
|
+
require 'spec_helper'
|
15
|
+
|
16
|
+
describe AWS::SessionStore::DynamoDB::GarbageCollection do
|
17
|
+
def member(min,max)
|
18
|
+
member = []
|
19
|
+
for i in min..max
|
20
|
+
member << {"session_id"=>{:s=>"#{i}"}}
|
21
|
+
end
|
22
|
+
member
|
23
|
+
end
|
24
|
+
|
25
|
+
def format_scan_result
|
26
|
+
member = []
|
27
|
+
for i in 31..49
|
28
|
+
member << {"session_id"=>{:s=>"#{i}"}}
|
29
|
+
end
|
30
|
+
|
31
|
+
member.inject([]) do |rqst_array, item|
|
32
|
+
rqst_array << {:delete_request => {:key => item}}
|
33
|
+
rqst_array
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def collect_garbage
|
38
|
+
options = { :dynamo_db_client => dynamo_db_client, :max_age => 100, :max_stale => 100 }
|
39
|
+
AWS::SessionStore::DynamoDB::GarbageCollection.collect_garbage(options)
|
40
|
+
end
|
41
|
+
|
42
|
+
let(:scan_resp1){
|
43
|
+
resp = {
|
44
|
+
:member => member(0, 49),
|
45
|
+
:count => 50,
|
46
|
+
:scanned_count => 1000,
|
47
|
+
:last_evaluated_key => {}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
let(:scan_resp2){
|
52
|
+
{
|
53
|
+
:member => member(0, 31),
|
54
|
+
:last_evaluated_key => {"session_id"=>{:s=>"31"}}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
let(:scan_resp3){
|
59
|
+
{
|
60
|
+
:member => member(31,49),
|
61
|
+
:last_evaluated_key => {}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
let(:write_resp1){
|
66
|
+
{
|
67
|
+
:unprocessed_items => {}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
let(:write_resp2){
|
72
|
+
{
|
73
|
+
:unprocessed_items => {
|
74
|
+
"sessions" => [
|
75
|
+
{
|
76
|
+
:delete_request => {
|
77
|
+
:key => {
|
78
|
+
"session_id" =>
|
79
|
+
{
|
80
|
+
:s => "1"
|
81
|
+
}
|
82
|
+
}
|
83
|
+
}
|
84
|
+
},
|
85
|
+
{
|
86
|
+
:delete_request => {
|
87
|
+
:key => {
|
88
|
+
"session_id" =>
|
89
|
+
{
|
90
|
+
:s => "17"
|
91
|
+
}
|
92
|
+
}
|
93
|
+
}
|
94
|
+
}
|
95
|
+
]
|
96
|
+
}
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
let(:dynamo_db_client) {AWS::DynamoDB::Client.new}
|
101
|
+
|
102
|
+
context "Mock DynamoDB client with garbage collection" do
|
103
|
+
|
104
|
+
it "processes scan result greater than 25 and deletes in batches of 25" do
|
105
|
+
dynamo_db_client.should_receive(:scan).
|
106
|
+
exactly(1).times.and_return(scan_resp1)
|
107
|
+
dynamo_db_client.should_receive(:batch_write_item).
|
108
|
+
exactly(2).times.and_return(write_resp1)
|
109
|
+
collect_garbage
|
110
|
+
end
|
111
|
+
|
112
|
+
it "gets scan results then returns last evaluated key and resumes scanning" do
|
113
|
+
dynamo_db_client.should_receive(:scan).
|
114
|
+
exactly(2).times.and_return(scan_resp2, scan_resp3)
|
115
|
+
dynamo_db_client.should_receive(:batch_write_item).
|
116
|
+
exactly(3).times.and_return(write_resp1)
|
117
|
+
collect_garbage
|
118
|
+
end
|
119
|
+
|
120
|
+
it "it formats unprocessed_items and then batch deletes them" do
|
121
|
+
dynamo_db_client.should_receive(:scan).
|
122
|
+
exactly(1).times.and_return(scan_resp3)
|
123
|
+
dynamo_db_client.should_receive(:batch_write_item).ordered.
|
124
|
+
with(:request_items => {"sessions" => format_scan_result}).
|
125
|
+
and_return(write_resp2)
|
126
|
+
dynamo_db_client.should_receive(:batch_write_item).ordered.with(
|
127
|
+
:request_items =>
|
128
|
+
{
|
129
|
+
"sessions" => [
|
130
|
+
{
|
131
|
+
:delete_request => {
|
132
|
+
:key => {
|
133
|
+
"session_id" =>
|
134
|
+
{
|
135
|
+
:s => "1"
|
136
|
+
}
|
137
|
+
}
|
138
|
+
}
|
139
|
+
},
|
140
|
+
{
|
141
|
+
:delete_request => {
|
142
|
+
:key => {
|
143
|
+
"session_id" =>
|
144
|
+
{
|
145
|
+
:s => "17"
|
146
|
+
}
|
147
|
+
}
|
148
|
+
}
|
149
|
+
}
|
150
|
+
]
|
151
|
+
}
|
152
|
+
).and_return(write_resp1)
|
153
|
+
collect_garbage
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|