aws-sessionstore-dynamodb 2.2.0 → 3.0.1
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 +22 -0
- data/LICENSE +172 -9
- data/VERSION +1 -1
- data/lib/aws/session_store/dynamo_db/configuration.rb +134 -208
- data/lib/aws/session_store/dynamo_db/errors/base_handler.rb +5 -3
- data/lib/aws/session_store/dynamo_db/errors/default_handler.rb +13 -12
- data/lib/aws/session_store/dynamo_db/errors.rb +27 -0
- data/lib/aws/session_store/dynamo_db/garbage_collection.rb +85 -93
- data/lib/aws/session_store/dynamo_db/locking/base.rb +31 -32
- data/lib/aws/session_store/dynamo_db/locking/null.rb +4 -3
- data/lib/aws/session_store/dynamo_db/locking/pessimistic.rb +32 -20
- data/lib/aws/session_store/dynamo_db/locking.rb +10 -0
- data/lib/aws/session_store/dynamo_db/rack_middleware.rb +45 -49
- data/lib/aws/session_store/dynamo_db/table.rb +64 -67
- data/lib/aws-sessionstore-dynamodb.rb +12 -14
- metadata +25 -70
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -6
- data/.github/workflows/ci.yml +0 -39
- data/.gitignore +0 -12
- data/.gitmodules +0 -3
- data/.yardopts +0 -4
- data/CODE_OF_CONDUCT.md +0 -4
- data/CONTRIBUTING.md +0 -61
- data/Gemfile +0 -24
- data/README.md +0 -125
- data/Rakefile +0 -35
- data/aws-sessionstore-dynamodb.gemspec +0 -24
- data/doc-src/templates/default/layout/html/footer.erb +0 -6
- data/doc-src/templates/default/layout/html/layout.erb +0 -31
- data/lib/aws/session_store/dynamo_db/invalid_id_error.rb +0 -7
- data/lib/aws/session_store/dynamo_db/lock_wait_timeout_error.rb +0 -7
- data/lib/aws/session_store/dynamo_db/missing_secret_key_error.rb +0 -7
- data/lib/aws/session_store/dynamo_db/version.rb +0 -7
- data/spec/aws/session_store/dynamo_db/app_config.yml +0 -16
- data/spec/aws/session_store/dynamo_db/configuration_spec.rb +0 -81
- data/spec/aws/session_store/dynamo_db/error/default_error_handler_spec.rb +0 -64
- data/spec/aws/session_store/dynamo_db/garbage_collection_spec.rb +0 -158
- data/spec/aws/session_store/dynamo_db/locking/threaded_sessions_spec.rb +0 -96
- data/spec/aws/session_store/dynamo_db/rack_middleware_database_spec.rb +0 -130
- data/spec/aws/session_store/dynamo_db/rack_middleware_spec.rb +0 -148
- data/spec/aws/session_store/dynamo_db/table_spec.rb +0 -48
- data/spec/spec_helper.rb +0 -65
data/Gemfile
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
source 'https://rubygems.org'
|
2
|
-
|
3
|
-
if ENV['RACK2']
|
4
|
-
gem 'rack', '~> 2'
|
5
|
-
end
|
6
|
-
|
7
|
-
gemspec
|
8
|
-
|
9
|
-
gem 'rake', require: false
|
10
|
-
|
11
|
-
group :docs do
|
12
|
-
gem 'yard'
|
13
|
-
gem 'yard-sitemap', '~> 1.0'
|
14
|
-
end
|
15
|
-
|
16
|
-
group :test do
|
17
|
-
gem 'rspec'
|
18
|
-
gem 'rack-test'
|
19
|
-
gem 'simplecov'
|
20
|
-
|
21
|
-
if RUBY_VERSION >= '3.0'
|
22
|
-
gem 'rexml'
|
23
|
-
end
|
24
|
-
end
|
data/README.md
DELETED
@@ -1,125 +0,0 @@
|
|
1
|
-
# Amazon DynamoDB Session Store
|
2
|
-
|
3
|
-
The **Amazon DynamoDB Session Store** handles sessions for Ruby web applications
|
4
|
-
using a DynamoDB backend. The session store is compatible with all Rack based
|
5
|
-
frameworks. For Rails applications, use the [`aws-sdk-rails`][1] gem.
|
6
|
-
|
7
|
-
## Installation
|
8
|
-
|
9
|
-
For Rack applications, you can create the Amazon DynamoDB table in a
|
10
|
-
Ruby file using the following method:
|
11
|
-
|
12
|
-
require 'aws-sessionstore-dynamodb'
|
13
|
-
|
14
|
-
Aws::SessionStore::DynamoDB::Table.create_table
|
15
|
-
|
16
|
-
Run the session store as a Rack middleware in the following way:
|
17
|
-
|
18
|
-
require 'aws-sessionstore-dynamodb'
|
19
|
-
require 'some_rack_app'
|
20
|
-
|
21
|
-
options = { :secret_key => 'SECRET_KEY' }
|
22
|
-
|
23
|
-
use Aws::SessionStore::DynamoDB::RackMiddleware.new(options)
|
24
|
-
run SomeRackApp
|
25
|
-
|
26
|
-
Note that `:secret_key` is a mandatory configuration option that must be set.
|
27
|
-
|
28
|
-
## Detailed Usage
|
29
|
-
|
30
|
-
The session store is a Rack Middleware, meaning that it will implement the Rack
|
31
|
-
interface for dealing with HTTP request/responses.
|
32
|
-
|
33
|
-
This session store uses a DynamoDB backend in order to provide scaling and
|
34
|
-
centralized data benefits for session storage with more ease than other
|
35
|
-
containers, like local servers or cookies. Once an application scales beyond
|
36
|
-
a single web server, session data will need to be shared across the servers.
|
37
|
-
DynamoDB takes care of this burden for you by scaling with your application.
|
38
|
-
Cookie storage places all session data on the client side,
|
39
|
-
discouraging sensitive data storage. It also forces strict data size
|
40
|
-
limitations. DynamoDB takes care of these concerns by allowing for a safe and
|
41
|
-
scalable storage container with a much larger data size limit for session data.
|
42
|
-
|
43
|
-
For more developer information, see the [Full API documentation][2].
|
44
|
-
|
45
|
-
### Configuration Options
|
46
|
-
|
47
|
-
A number of options are available to be set in
|
48
|
-
`Aws::SessionStore::DynamoDB::Configuration`, which is used by the
|
49
|
-
`RackMiddleware` class. These options can be set directly by Ruby code or
|
50
|
-
through environment variables.
|
51
|
-
|
52
|
-
The full set of options along with defaults can be found in the
|
53
|
-
[Configuration class documentation][3].
|
54
|
-
|
55
|
-
#### Environment Options
|
56
|
-
|
57
|
-
Certain configuration options can be loaded from the environment. These
|
58
|
-
options must be specified in the following format:
|
59
|
-
|
60
|
-
DYNAMO_DB_SESSION_NAME-OF-CONFIGURATION-OPTION
|
61
|
-
|
62
|
-
The example below would be a valid way to set the session table name:
|
63
|
-
|
64
|
-
export DYNAMO_DB_SESSION_TABLE_NAME='sessions'
|
65
|
-
|
66
|
-
### Garbage Collection
|
67
|
-
|
68
|
-
You may want to delete old sessions from your session table. You can use the
|
69
|
-
DynamoDB [Time to Live (TTL) feature][4] on the `expire_at` attribute to
|
70
|
-
automatically delete expired items.
|
71
|
-
|
72
|
-
If you want to take other attributes into consideration for deletion, you could
|
73
|
-
instead use the `GarbageCollection` class. You can create your own Rake task for
|
74
|
-
garbage collection similar to below:
|
75
|
-
|
76
|
-
require "aws-sessionstore-dynamodb"
|
77
|
-
|
78
|
-
desc 'Perform Garbage Collection'
|
79
|
-
task :garbage_collect do |t|
|
80
|
-
options = {:max_age => 3600*24, max_stale => 5*3600 }
|
81
|
-
Aws::SessionStore::DynamoDB::GarbageCollection.collect_garbage(options)
|
82
|
-
end
|
83
|
-
|
84
|
-
The above example will clear sessions older than one day or that have been
|
85
|
-
stale for longer than an hour.
|
86
|
-
|
87
|
-
### Locking Strategy
|
88
|
-
|
89
|
-
You may want the Session Store to implement the provided pessimistic locking
|
90
|
-
strategy if you are concerned about concurrency issues with session accesses.
|
91
|
-
By default, locking is not implemented for the session store. You must trigger
|
92
|
-
the locking strategy through the configuration of the session store. Pessimistic
|
93
|
-
locking, in this case, means that only one read can be made on a session at
|
94
|
-
once. While the session is being read by the process with the lock, other
|
95
|
-
processes may try to obtain a lock on the same session but will be blocked.
|
96
|
-
|
97
|
-
Locking is expensive and will drive up costs depending on how it is used.
|
98
|
-
Without locking, one read and one write are performed per request for session
|
99
|
-
data manipulation. If a locking strategy is implemented, as many as the total
|
100
|
-
maximum wait time divided by the lock retry delay writes to the database.
|
101
|
-
Keep these considerations in mind if you plan to enable locking.
|
102
|
-
|
103
|
-
#### Configuration for Locking
|
104
|
-
|
105
|
-
The following configuration options will allow you to configure the pessimistic
|
106
|
-
locking strategy according to your needs:
|
107
|
-
|
108
|
-
options = {
|
109
|
-
:enable_locking => true,
|
110
|
-
:lock_expiry_time => 500,
|
111
|
-
:lock_retry_delay => 500,
|
112
|
-
:lock_max_wait_time => 1
|
113
|
-
}
|
114
|
-
|
115
|
-
### Error Handling
|
116
|
-
|
117
|
-
You can pass in your own error handler for raised exceptions or you can allow
|
118
|
-
the default error handler to them for you. See the API documentation
|
119
|
-
on the {Aws::SessionStore::DynamoDB::Errors::BaseHandler} class for more
|
120
|
-
details.
|
121
|
-
|
122
|
-
[1]: https://github.com/aws/aws-sdk-rails/
|
123
|
-
[2]: https://docs.aws.amazon.com/sdk-for-ruby/aws-sessionstore-dynamodb/api/
|
124
|
-
[3]: https://docs.aws.amazon.com/sdk-for-ruby/aws-sessionstore-dynamodb/api/Aws/SessionStore/DynamoDB/Configuration.html
|
125
|
-
[4]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html
|
data/Rakefile
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
require 'rspec/core/rake_task'
|
2
|
-
|
3
|
-
$REPO_ROOT = File.dirname(__FILE__)
|
4
|
-
$LOAD_PATH.unshift(File.join($REPO_ROOT, 'lib'))
|
5
|
-
$VERSION = ENV['VERSION'] || File.read(File.join($REPO_ROOT, 'VERSION')).strip
|
6
|
-
|
7
|
-
|
8
|
-
Dir.glob('**/*.rake').each do |task_file|
|
9
|
-
load task_file
|
10
|
-
end
|
11
|
-
|
12
|
-
task 'test:coverage:clear' do
|
13
|
-
sh("rm -rf #{File.join($REPO_ROOT, 'coverage')}")
|
14
|
-
end
|
15
|
-
|
16
|
-
desc 'Runs unit tests'
|
17
|
-
RSpec::Core::RakeTask.new do |t|
|
18
|
-
t.rspec_opts = "-I #{$REPO_ROOT}/lib -I #{$REPO_ROOT}/spec --tag ~integration"
|
19
|
-
t.pattern = "#{$REPO_ROOT}/spec"
|
20
|
-
end
|
21
|
-
task :spec => 'test:coverage:clear'
|
22
|
-
|
23
|
-
desc 'Runs integration tests'
|
24
|
-
RSpec::Core::RakeTask.new('spec:integration') do |t|
|
25
|
-
t.rspec_opts = "-I #{$REPO_ROOT}/lib -I #{$REPO_ROOT}/spec --tag integration"
|
26
|
-
t.pattern = "#{$REPO_ROOT}/spec"
|
27
|
-
end
|
28
|
-
|
29
|
-
desc 'Runs unit and integration tests'
|
30
|
-
task 'test' => [:spec, 'spec:integration']
|
31
|
-
|
32
|
-
task :default => :spec
|
33
|
-
task 'release:test' => [:spec, 'spec:integration']
|
34
|
-
|
35
|
-
|
@@ -1,24 +0,0 @@
|
|
1
|
-
version = File.read(File.expand_path('../VERSION', __FILE__)).strip
|
2
|
-
|
3
|
-
Gem::Specification.new do |spec|
|
4
|
-
spec.name = "aws-sessionstore-dynamodb"
|
5
|
-
spec.version = version
|
6
|
-
spec.authors = ["Amazon Web Services"]
|
7
|
-
spec.email = ["aws-dr-rubygems@amazon.com"]
|
8
|
-
|
9
|
-
spec.summary = "The Amazon DynamoDB Session Store handles sessions " +
|
10
|
-
"for Ruby web applications using a DynamoDB backend."
|
11
|
-
spec.homepage = "http://github.com/aws/aws-sessionstore-dynamodb-ruby"
|
12
|
-
spec.license = "Apache License 2.0"
|
13
|
-
|
14
|
-
spec.files = `git ls-files`.split($/)
|
15
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
16
|
-
spec.require_paths = ["lib"]
|
17
|
-
|
18
|
-
# Require 1.85.0 for user_agent_frameworks config
|
19
|
-
spec.add_dependency 'aws-sdk-dynamodb', '~> 1', '>= 1.85.0'
|
20
|
-
spec.add_dependency 'rack', '>= 2', '< 4'
|
21
|
-
spec.add_dependency 'rack-session', '>= 1', '< 3'
|
22
|
-
|
23
|
-
spec.required_ruby_version = '>= 2.5'
|
24
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html>
|
3
|
-
<head>
|
4
|
-
<%= erb(:headers) %>
|
5
|
-
<!-- Docs Metrics + Cookie Consent Script -->
|
6
|
-
<meta name="guide-name" content="API Reference">
|
7
|
-
<meta name="service-name" content="AWS SDK For Ruby - AWS DynamoDB Session Store">
|
8
|
-
<script type="text/javascript" src="/assets/js/awsdocs-boot.js"></script>
|
9
|
-
</head>
|
10
|
-
<body>
|
11
|
-
<div class="nav_wrap">
|
12
|
-
<iframe id="nav" src="<%= @nav_url %>?1"></iframe>
|
13
|
-
<div id="resizer"></div>
|
14
|
-
</div>
|
15
|
-
|
16
|
-
<div id="main" tabindex="-1">
|
17
|
-
<div id="header">
|
18
|
-
<%= erb(:breadcrumb) %>
|
19
|
-
<%= erb(:search) %>
|
20
|
-
<div class="clear"></div>
|
21
|
-
</div>
|
22
|
-
|
23
|
-
<div id="content">
|
24
|
-
<!-- REGION_DISCLAIMER_DO_NOT_REMOVE -->
|
25
|
-
<%= yieldall %>
|
26
|
-
</div>
|
27
|
-
|
28
|
-
<%= erb(:footer) %>
|
29
|
-
</div>
|
30
|
-
</body>
|
31
|
-
</html>
|
@@ -1,16 +0,0 @@
|
|
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
|
@@ -1,81 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
6
|
-
# may not use this file except in compliance with the License. A copy of
|
7
|
-
# the License is located at
|
8
|
-
#
|
9
|
-
# http://aws.amazon.com/apache2.0/
|
10
|
-
#
|
11
|
-
# or in the "license" file accompanying this file. This file is
|
12
|
-
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
13
|
-
# ANY KIND, either express or implied. See the License for the specific
|
14
|
-
# language governing permissions and limitations under the License.
|
15
|
-
|
16
|
-
require 'spec_helper'
|
17
|
-
|
18
|
-
describe Aws::SessionStore::DynamoDB::Configuration do
|
19
|
-
let(:defaults) do
|
20
|
-
{
|
21
|
-
table_name: 'sessions',
|
22
|
-
table_key: 'session_id',
|
23
|
-
consistent_read: true,
|
24
|
-
read_capacity: 10,
|
25
|
-
write_capacity: 5,
|
26
|
-
raise_errors: false
|
27
|
-
}
|
28
|
-
end
|
29
|
-
|
30
|
-
let(:expected_file_opts) do
|
31
|
-
{
|
32
|
-
consistent_read: true,
|
33
|
-
table_name: 'NewTable',
|
34
|
-
table_key: 'Somekey',
|
35
|
-
}
|
36
|
-
end
|
37
|
-
|
38
|
-
let(:client) { Aws::DynamoDB::Client.new(stub_responses: true) }
|
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
|
-
expect(cfg.to_hash).to include(expected_opts)
|
51
|
-
end
|
52
|
-
|
53
|
-
before do
|
54
|
-
allow(Aws::DynamoDB::Client).to receive(:new).and_return(client)
|
55
|
-
end
|
56
|
-
|
57
|
-
context 'Configuration Tests' do
|
58
|
-
it 'configures option with out runtime,YAML or ENV options' do
|
59
|
-
cfg = Aws::SessionStore::DynamoDB::Configuration.new
|
60
|
-
expect(cfg.to_hash).to include(defaults)
|
61
|
-
end
|
62
|
-
|
63
|
-
it 'configures accurate option hash with runtime options, no YAML or ENV' do
|
64
|
-
cfg = Aws::SessionStore::DynamoDB::Configuration.new(runtime_options)
|
65
|
-
expected_opts = defaults.merge(runtime_options)
|
66
|
-
expect(cfg.to_hash).to include(expected_opts)
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'merge YAML and runtime options giving runtime precendence' do
|
70
|
-
config_path = File.dirname(__FILE__) + '/app_config.yml'
|
71
|
-
runtime_opts = { config_file: config_path }.merge(runtime_options)
|
72
|
-
expected_options(runtime_opts)
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'throws an exception when wrong path for file' do
|
76
|
-
config_path = 'Wrong path!'
|
77
|
-
runtime_opts = { config_file: config_path }.merge(runtime_options)
|
78
|
-
expect { cfg = Aws::SessionStore::DynamoDB::Configuration.new(runtime_opts) }.to raise_error(Errno::ENOENT)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
@@ -1,64 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
6
|
-
# may not use this file except in compliance with the License. A copy of
|
7
|
-
# the License is located at
|
8
|
-
#
|
9
|
-
# http://aws.amazon.com/apache2.0/
|
10
|
-
#
|
11
|
-
# or in the "license" file accompanying this file. This file is
|
12
|
-
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
13
|
-
# ANY KIND, either express or implied. See the License for the specific
|
14
|
-
# language governing permissions and limitations under the License.
|
15
|
-
|
16
|
-
require 'spec_helper'
|
17
|
-
|
18
|
-
describe Aws::SessionStore::DynamoDB do
|
19
|
-
include Rack::Test::Methods
|
20
|
-
|
21
|
-
instance_exec(&ConstantHelpers)
|
22
|
-
|
23
|
-
before do
|
24
|
-
@options = { dynamo_db_client: client, secret_key: 'meltingbutter' }
|
25
|
-
end
|
26
|
-
|
27
|
-
let(:base_app) { MultiplierApplication.new }
|
28
|
-
let(:app) { Aws::SessionStore::DynamoDB::RackMiddleware.new(base_app, @options) }
|
29
|
-
let(:client) { double('Aws::DynamoDB::Client', config: double(user_agent_frameworks: [])) }
|
30
|
-
|
31
|
-
context 'Error handling for Rack Middleware with default error handler' do
|
32
|
-
it 'raises error for missing secret key' do
|
33
|
-
allow(client).to receive(:update_item).and_raise(missing_key_error)
|
34
|
-
expect { get '/' }.to raise_error(missing_key_error)
|
35
|
-
end
|
36
|
-
|
37
|
-
it 'catches exception for inaccurate table name and raises error ' do
|
38
|
-
allow(client).to receive(:update_item).and_raise(resource_error)
|
39
|
-
expect { get '/' }.to raise_error(resource_error)
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'catches exception for inaccurate table key' do
|
43
|
-
allow(client).to receive(:update_item).and_raise(key_error)
|
44
|
-
allow(client).to receive(:get_item).and_raise(key_error)
|
45
|
-
|
46
|
-
get '/'
|
47
|
-
expect(last_request.env['rack.errors'].string).to include(key_error_msg)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
context 'Test ExceptionHandler with true as return value for handle_error' do
|
52
|
-
it 'raises all errors' do
|
53
|
-
@options[:raise_errors] = true
|
54
|
-
allow(client).to receive(:update_item).and_raise(client_error)
|
55
|
-
expect { get '/' }.to raise_error(client_error)
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'catches exception for inaccurate table key and raises error' do
|
59
|
-
@options[:raise_errors] = true
|
60
|
-
allow(client).to receive(:update_item).and_raise(key_error)
|
61
|
-
expect { get '/' }.to raise_error(key_error)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
@@ -1,158 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
6
|
-
# may not use this file except in compliance with the License. A copy of
|
7
|
-
# the License is located at
|
8
|
-
#
|
9
|
-
# http://aws.amazon.com/apache2.0/
|
10
|
-
#
|
11
|
-
# or in the "license" file accompanying this file. This file is
|
12
|
-
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
13
|
-
# ANY KIND, either express or implied. See the License for the specific
|
14
|
-
# language governing permissions and limitations under the License.
|
15
|
-
|
16
|
-
require 'spec_helper'
|
17
|
-
|
18
|
-
describe Aws::SessionStore::DynamoDB::GarbageCollection do
|
19
|
-
def items(min, max)
|
20
|
-
items = []
|
21
|
-
(min..max).each do |i|
|
22
|
-
items << { 'session_id' => { s: i.to_s } }
|
23
|
-
end
|
24
|
-
items
|
25
|
-
end
|
26
|
-
|
27
|
-
def format_scan_result
|
28
|
-
items = []
|
29
|
-
(31..49).each do |i|
|
30
|
-
items << { 'session_id' => { s: i.to_s } }
|
31
|
-
end
|
32
|
-
|
33
|
-
items.each_with_object([]) do |item, rqst_array|
|
34
|
-
rqst_array << { delete_request: { key: item } }
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def collect_garbage
|
39
|
-
options = { dynamo_db_client: dynamo_db_client, max_age: 100, max_stale: 100 }
|
40
|
-
Aws::SessionStore::DynamoDB::GarbageCollection.collect_garbage(options)
|
41
|
-
end
|
42
|
-
|
43
|
-
let(:scan_resp1) do
|
44
|
-
resp = {
|
45
|
-
items: items(0, 49),
|
46
|
-
count: 50,
|
47
|
-
scanned_count: 1000,
|
48
|
-
last_evaluated_key: {}
|
49
|
-
}
|
50
|
-
end
|
51
|
-
|
52
|
-
let(:scan_resp2) do
|
53
|
-
{
|
54
|
-
items: items(0, 31),
|
55
|
-
last_evaluated_key: { 'session_id' => { s: '31' } }
|
56
|
-
}
|
57
|
-
end
|
58
|
-
|
59
|
-
let(:scan_resp3) do
|
60
|
-
{
|
61
|
-
items: items(31, 49),
|
62
|
-
last_evaluated_key: {}
|
63
|
-
}
|
64
|
-
end
|
65
|
-
|
66
|
-
let(:write_resp1) do
|
67
|
-
{
|
68
|
-
unprocessed_items: {}
|
69
|
-
}
|
70
|
-
end
|
71
|
-
|
72
|
-
let(:write_resp2) do
|
73
|
-
{
|
74
|
-
unprocessed_items: {
|
75
|
-
'sessions' => [
|
76
|
-
{
|
77
|
-
delete_request: {
|
78
|
-
key: {
|
79
|
-
'session_id' =>
|
80
|
-
{
|
81
|
-
s: '1'
|
82
|
-
}
|
83
|
-
}
|
84
|
-
}
|
85
|
-
},
|
86
|
-
{
|
87
|
-
delete_request: {
|
88
|
-
key: {
|
89
|
-
'session_id' =>
|
90
|
-
{
|
91
|
-
s: '17'
|
92
|
-
}
|
93
|
-
}
|
94
|
-
}
|
95
|
-
}
|
96
|
-
]
|
97
|
-
}
|
98
|
-
}
|
99
|
-
end
|
100
|
-
|
101
|
-
let(:dynamo_db_client) {Aws::DynamoDB::Client.new(stub_responses: true)}
|
102
|
-
|
103
|
-
context 'Mock DynamoDB client with garbage collection' do
|
104
|
-
it 'processes scan result greater than 25 and deletes in batches of 25' do
|
105
|
-
expect(dynamo_db_client).to receive(:scan)
|
106
|
-
.exactly(1).times.and_return(scan_resp1)
|
107
|
-
expect(dynamo_db_client).to 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
|
-
expect(dynamo_db_client).to receive(:scan).
|
114
|
-
exactly(1).times.and_return(scan_resp2)
|
115
|
-
expect(dynamo_db_client).to receive(:scan).
|
116
|
-
exactly(1).times.with(hash_including(exclusive_start_key: scan_resp2[:last_evaluated_key])).
|
117
|
-
and_return(scan_resp3)
|
118
|
-
expect(dynamo_db_client).to receive(:batch_write_item).
|
119
|
-
exactly(3).times.and_return(write_resp1)
|
120
|
-
collect_garbage
|
121
|
-
end
|
122
|
-
|
123
|
-
it 'it formats unprocessed_items and then batch deletes them' do
|
124
|
-
expect(dynamo_db_client).to receive(:scan).
|
125
|
-
exactly(1).times.and_return(scan_resp3)
|
126
|
-
expect(dynamo_db_client).to receive(:batch_write_item).ordered.
|
127
|
-
with({request_items: { 'sessions' => format_scan_result }}).
|
128
|
-
and_return(write_resp2)
|
129
|
-
expect(dynamo_db_client).to receive(:batch_write_item).ordered.with({
|
130
|
-
request_items: {
|
131
|
-
'sessions' => [
|
132
|
-
{
|
133
|
-
delete_request: {
|
134
|
-
key: {
|
135
|
-
'session_id' =>
|
136
|
-
{
|
137
|
-
s: '1'
|
138
|
-
}
|
139
|
-
}
|
140
|
-
}
|
141
|
-
},
|
142
|
-
{
|
143
|
-
delete_request: {
|
144
|
-
key: {
|
145
|
-
'session_id' =>
|
146
|
-
{
|
147
|
-
s: '17'
|
148
|
-
}
|
149
|
-
}
|
150
|
-
}
|
151
|
-
}
|
152
|
-
]
|
153
|
-
}
|
154
|
-
}).and_return(write_resp1)
|
155
|
-
collect_garbage
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|