aws-sessionstore-dynamodb 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|