diff --git a/.travis.yml b/.travis.yml index 1a4e024..d327a09 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,7 @@ +branches: + only: + - master + language: ruby rvm: @@ -17,6 +21,6 @@ sudo: false env: - AWS_REGION=us-west-2 -script: bundle exec rake test +script: bundle exec rake test:unit bundler_args: --without docs release repl diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9d98158 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,24 @@ +Unreleased Changes +------------------ + +* Remove Rails support (moved to the `aws-sdk-rails` gem). + +* Use V3 of Ruby SDK + +* Fix a `dynamo_db.scan()` incompatibility from the V1 -> V2 upgrade in the garbage collector. + +1.0.0 (2017-08-14) +------------------ + +* Use V2 of Ruby SDK (no history) + + +0.5.1 (2015-08-26) +------------------ + +* Bug Fix (no history) + +0.5.0 (2013-08-27) +------------------ + +* Initial Release (no history) diff --git a/LICENSE.txt b/LICENSE similarity index 100% rename from LICENSE.txt rename to LICENSE diff --git a/README.md b/README.md index fe73f8e..b09703d 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,12 @@ # Amazon DynamoDB Session Store The **Amazon DynamoDB Session Store** handles sessions for Ruby web applications -using a DynamoDB backend. The session store is compatible with Rails (3.x or 4.x) -and other Rack based frameworks. +using a DynamoDB backend. The session store is compatible with all Rack based +frameworks. For Rails applications, use the [`aws-sdk-rails`][1] gem. ## Installation -#### Rails Installation - -Install the session store gem by placing the following command into your -Gemfile: - - gem 'aws-sessionstore-dynamodb' - -You will need to have an existing Amazon DynamoDB session table in order for the -application to work. You can generate a migration file for the session table -with the following command: - - rails generate sessionstore:dynamodb - -To create the table, run migrations as normal with: - - rake db:migrate - -Change the session store to `:dynamodb_store` by editing -`config/initializers/session_store.rb` to contain the following: - - YourAppName::Application.config.session_store :dynamodb_store - -You can now start your Rails application with session support. - -#### Basic Rack Application Installation - -For non-Rails applications, you can create the Amazon DynamoDB table in a +For Rack applications, you can create the Amazon DynamoDB table in a Ruby file using the following method: require 'aws-sessionstore-dynamodb' @@ -66,18 +40,17 @@ discouraging sensitive data storage. It also forces strict data size limitations. DynamoDB takes care of these concerns by allowing for a safe and scalable storage container with a much larger data size limit for session data. -Full API documentation of the library can be found on [RubyDoc.info][1]. +For more developer information, see the [Full API documentation][2]. ### Configuration Options A number of options are available to be set in `Aws::SessionStore::DynamoDB::Configuration`, which is used by the -`RackMiddleware` class. These options can be set in the YAML configuration -file in a Rails application (located in `config/sessionstore/dynamodb.yml`), -directly by Ruby code, or through environment variables. +`RackMiddleware` class. These options can be set directly by Ruby code or +through environment variables. The full set of options along with defaults can be found in the -[Configuration class documentation][2]. +[Configuration class documentation][3]. #### Environment Options @@ -90,36 +63,15 @@ The example below would be a valid way to set the session table name: export DYNAMO_DB_SESSION_TABLE_NAME='sessions' -### Rails Generator Details - -The generator command specified in the installation section will generate two -files: a migration file, `db/migration/VERSION_migration_name.rb`, and a -configuration YAML file, `config/sessionstore/dynamodb.yml`. - -You can run the command with an argument that will define the name of the -migration file. Once the YAML file is created, you can uncomment any of the -lines to set configuration options to your liking. The session store will pull -options from `config/sessionstore/dynamodb.yml` by default if the file exists. -If you do not wish to place the configuration YAML file in that location, -you can also pass in a different file path to pull options from. - ### Garbage Collection -You may want to delete old sessions from your session table. The -following examples show how to clear old sessions from your table. - -#### Rails - -A Rake task for garbage collection is provided for Rails applications. -By default sessions do not expire. See `config/sessionstore/dynamodb.yml` to -configure the max age or stale period of a session. Once you have configured -those values you can clear the old sessions with: - - rake dynamo_db:collect_garbage - -#### Outside of Rails +You may want to delete old sessions from your session table. You can use the +DynamoDB [Time to Live (TTL) feature][4] on the `expire_at` attribute to +automatically delete expired items. -You can create your own Rake task for garbage collection similar to below: +If you want to take other attributes into consideration for deletion, you could +instead use the `GarbageCollection` class. You can create your own Rake task for +garbage collection similar to below: require "aws-sessionstore-dynamodb" @@ -167,5 +119,7 @@ the default error handler to them for you. See the API documentation on the {Aws::SessionStore::DynamoDB::Errors::BaseHandler} class for more details. -[1]: http://rubydoc.org/gems/aws-sessionstore-dynamodb/frames -[2]: http://rubydoc.org/gems/aws-sessionstore-dynamodb/AWS/SessionStore/DynamoDB/Configuration#initialize-instance_method +[1]: https://github.com/aws/aws-sdk-rails/ +[2]: https://docs.aws.amazon.com/sdk-for-ruby/aws-sessionstore-dynamodb/api/ +[3]: https://docs.aws.amazon.com/sdk-for-ruby/aws-sessionstore-dynamodb/api/Aws/SessionStore/DynamoDB/Configuration.html +[4]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html diff --git a/Rakefile b/Rakefile index c684f43..03902bc 100644 --- a/Rakefile +++ b/Rakefile @@ -2,21 +2,37 @@ $REPO_ROOT = File.dirname(__FILE__) $LOAD_PATH.unshift(File.join($REPO_ROOT, 'lib')) $VERSION = ENV['VERSION'] || File.read(File.join($REPO_ROOT, 'VERSION')).strip +require 'rspec/core/rake_task' + +Dir.glob('**/*.rake').each do |task_file| + load task_file +end + task 'test:coverage:clear' do sh("rm -rf #{File.join($REPO_ROOT, 'coverage')}") end +# Override the test task definitions +# this package uses rspec tags to define integration tests +Rake::Task["test:unit"].clear desc 'Runs unit tests' +RSpec::Core::RakeTask.new('test:unit') do |t| + t.rspec_opts = "-I #{$REPO_ROOT}/lib -I #{$REPO_ROOT}/spec --tag ~integration" + t.pattern = "#{$REPO_ROOT}/spec" +end task 'test:unit' => 'test:coverage:clear' +Rake::Task["test:integration"].clear desc 'Runs integration tests' +RSpec::Core::RakeTask.new('test:integration') do |t| + t.rspec_opts = "-I #{$REPO_ROOT}/lib -I #{$REPO_ROOT}/spec --tag integration" + t.pattern = "#{$REPO_ROOT}/spec" +end task 'test:integration' => 'test:coverage:clear' desc 'Runs unit and integration tests' task 'test' => ['test:unit', 'test:integration'] -task :default => :test +task :default => 'test:unit' + -Dir.glob('**/*.rake').each do |task_file| - load task_file -end diff --git a/VERSION b/VERSION index 3eefcb9..227cea2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0 +2.0.0 diff --git a/lib/aws-sessionstore-dynamodb.rb b/lib/aws-sessionstore-dynamodb.rb index 1d4a5cb..4fa603b 100644 --- a/lib/aws-sessionstore-dynamodb.rb +++ b/lib/aws-sessionstore-dynamodb.rb @@ -1,17 +1,3 @@ -# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. - - module Aws module SessionStore module DynamoDB; end @@ -31,4 +17,3 @@ module DynamoDB; end require 'aws/session_store/dynamo_db/rack_middleware' require 'aws/session_store/dynamo_db/table' require 'aws/session_store/dynamo_db/version' -require 'aws/session_store/dynamo_db/railtie' if defined?(Rails) diff --git a/lib/aws/session_store/dynamo_db/configuration.rb b/lib/aws/session_store/dynamo_db/configuration.rb index c23561b..5cd2ba4 100644 --- a/lib/aws/session_store/dynamo_db/configuration.rb +++ b/lib/aws/session_store/dynamo_db/configuration.rb @@ -1,16 +1,3 @@ -# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. - require 'yaml' require 'aws-sdk-dynamodb' @@ -240,24 +227,15 @@ def file_options(options = {}) file_path = config_file_path(options) if file_path load_from_file(file_path) - elsif rails_defined && File.exists?(rails_config_file_path) - load_from_file(rails_config_file_path) else {} end end - # @return [Boolean] Necessary Rails variables defined. - def rails_defined - defined?(Rails) && defined?(Rails.root) && defined?(Rails.env) - end - - # Load options from YAML file depending on existence of Rails - # and possible development stage defined. + # Load options from YAML file def load_from_file(file_path) require "erb" opts = YAML.load(ERB.new(File.read(file_path)).result) || {} - opts = opts[Rails.env] if rails_defined && opts.key?(Rails.env) symbolize_keys(opts) end @@ -266,11 +244,6 @@ def config_file_path(options) options[:config_file] || ENV["DYNAMO_DB_SESSION_CONFIG_FILE"] end - # @return [String] Rails configuraton path to YAML file default. - def rails_config_file_path - File.join(Rails.root, "config", "sessionstore/dynamodb.yml") - end - # Set accessible attributes after merged options. def set_attributes(options) @options.keys.each do |opt_name| diff --git a/lib/aws/session_store/dynamo_db/errors/base_handler.rb b/lib/aws/session_store/dynamo_db/errors/base_handler.rb index 5abff83..9291213 100644 --- a/lib/aws/session_store/dynamo_db/errors/base_handler.rb +++ b/lib/aws/session_store/dynamo_db/errors/base_handler.rb @@ -1,17 +1,3 @@ -# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. - - module Aws::SessionStore::DynamoDB::Errors # BaseErrorHandler provides an interface for error handlers # that can be passed in to {Aws::SessionStore::DynamoDB::RackMiddleware}. diff --git a/lib/aws/session_store/dynamo_db/errors/default_handler.rb b/lib/aws/session_store/dynamo_db/errors/default_handler.rb index 79615a3..53e70a2 100644 --- a/lib/aws/session_store/dynamo_db/errors/default_handler.rb +++ b/lib/aws/session_store/dynamo_db/errors/default_handler.rb @@ -1,17 +1,3 @@ -# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. - - module Aws::SessionStore::DynamoDB::Errors # This class handles errors raised from DynamoDB. class DefaultHandler < Aws::SessionStore::DynamoDB::Errors::BaseHandler diff --git a/lib/aws/session_store/dynamo_db/garbage_collection.rb b/lib/aws/session_store/dynamo_db/garbage_collection.rb index 871c010..e1f8845 100644 --- a/lib/aws/session_store/dynamo_db/garbage_collection.rb +++ b/lib/aws/session_store/dynamo_db/garbage_collection.rb @@ -1,16 +1,3 @@ -# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. - require 'aws-sdk-dynamodb' module Aws::SessionStore::DynamoDB @@ -50,7 +37,7 @@ def scan_filter(config) # @api private def eliminate_unwanted_sessions(config, last_key = nil) scan_result = scan(config, last_key) - batch_delete(config, scan_result[:member]) + batch_delete(config, scan_result[:items]) scan_result[:last_evaluated_key] || {} end diff --git a/lib/aws/session_store/dynamo_db/invalid_id_error.rb b/lib/aws/session_store/dynamo_db/invalid_id_error.rb index f6a3a1f..b7de751 100644 --- a/lib/aws/session_store/dynamo_db/invalid_id_error.rb +++ b/lib/aws/session_store/dynamo_db/invalid_id_error.rb @@ -1,17 +1,3 @@ -# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. - - module Aws::SessionStore::DynamoDB class InvalidIDError < RuntimeError def initialize(msg = "Corrupt Session ID!") diff --git a/lib/aws/session_store/dynamo_db/lock_wait_timeout_error.rb b/lib/aws/session_store/dynamo_db/lock_wait_timeout_error.rb index 550b1d0..15ca039 100644 --- a/lib/aws/session_store/dynamo_db/lock_wait_timeout_error.rb +++ b/lib/aws/session_store/dynamo_db/lock_wait_timeout_error.rb @@ -1,17 +1,3 @@ -# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. - - module Aws::SessionStore::DynamoDB class LockWaitTimeoutError < RuntimeError def initialize(msg = 'Maximum time spent to acquire lock has been exceeded!') diff --git a/lib/aws/session_store/dynamo_db/locking/base.rb b/lib/aws/session_store/dynamo_db/locking/base.rb index 85148d9..4b351f6 100644 --- a/lib/aws/session_store/dynamo_db/locking/base.rb +++ b/lib/aws/session_store/dynamo_db/locking/base.rb @@ -1,17 +1,3 @@ -# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. - - module Aws::SessionStore::DynamoDB::Locking # This class provides a framework for implementing # locking strategies. diff --git a/lib/aws/session_store/dynamo_db/locking/null.rb b/lib/aws/session_store/dynamo_db/locking/null.rb index 869284e..5bb04c1 100644 --- a/lib/aws/session_store/dynamo_db/locking/null.rb +++ b/lib/aws/session_store/dynamo_db/locking/null.rb @@ -1,17 +1,3 @@ -# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. - - module Aws::SessionStore::DynamoDB::Locking # This class gets and sets sessions # without a locking strategy. diff --git a/lib/aws/session_store/dynamo_db/locking/pessimistic.rb b/lib/aws/session_store/dynamo_db/locking/pessimistic.rb index 72831eb..c61e5c8 100644 --- a/lib/aws/session_store/dynamo_db/locking/pessimistic.rb +++ b/lib/aws/session_store/dynamo_db/locking/pessimistic.rb @@ -1,24 +1,8 @@ -# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. - - module Aws::SessionStore::DynamoDB::Locking # This class implements a pessimistic locking strategy for the # DynamoDB session handler. Sessions obtain an exclusive lock # for reads that is only released when the session is saved. class Pessimistic < Aws::SessionStore::DynamoDB::Locking::Base - WAIT_ERROR = - # Saves the session. def set_session_data(env, sid, session, options = {}) super(env, sid, session, set_lock_options(env, options)) diff --git a/lib/aws/session_store/dynamo_db/missing_secret_key_error.rb b/lib/aws/session_store/dynamo_db/missing_secret_key_error.rb index e0af423..ed13be0 100644 --- a/lib/aws/session_store/dynamo_db/missing_secret_key_error.rb +++ b/lib/aws/session_store/dynamo_db/missing_secret_key_error.rb @@ -1,17 +1,3 @@ -# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. - - module Aws::SessionStore::DynamoDB class MissingSecretKeyError < RuntimeError def initialize(msg = "No secret key provided!") diff --git a/lib/aws/session_store/dynamo_db/rack_middleware.rb b/lib/aws/session_store/dynamo_db/rack_middleware.rb index 40e6c1f..92d77c7 100644 --- a/lib/aws/session_store/dynamo_db/rack_middleware.rb +++ b/lib/aws/session_store/dynamo_db/rack_middleware.rb @@ -1,16 +1,3 @@ -# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. - require 'rack/session/abstract/id' require 'openssl' require 'aws-sdk-dynamodb' @@ -18,7 +5,7 @@ module Aws::SessionStore::DynamoDB # This class is an ID based Session Store Rack Middleware # that uses a DynamoDB backend for session storage. - class RackMiddleware < Rack::Session::Abstract::ID + class RackMiddleware < Rack::Session::Abstract::Persisted # Initializes SessionStore middleware. # @@ -58,16 +45,16 @@ def validate_config end # Gets session data. - def get_session(env, sid) + def find_session(req, sid) validate_config case verify_hmac(sid) when nil - set_new_session_properties(env) + set_new_session_properties(req.env) when false - handle_error {raise InvalidIDError} - set_new_session_properties(env) + handle_error { raise InvalidIDError } + set_new_session_properties(req.env) else - data = @lock.get_session_data(env, sid) + data = @lock.get_session_data(req.env, sid) [sid, data || {}] end end @@ -81,15 +68,15 @@ def set_new_session_properties(env) # # @return [Hash] If session has been saved. # @return [false] If session has could not be saved. - def set_session(env, sid, session, options) - @lock.set_session_data(env, sid, session, options) + def write_session(req, sid, session, options) + @lock.set_session_data(req.env, sid, session, options) end # Destroys session and removes session from database. # # @return [String] return a new session id or nil if options[:drop] - def destroy_session(env, sid, options) - @lock.delete_session(env, sid) + def delete_session(req, sid, options) + @lock.delete_session(req.env, sid) generate_sid unless options[:drop] end diff --git a/lib/aws/session_store/dynamo_db/railtie.rb b/lib/aws/session_store/dynamo_db/railtie.rb deleted file mode 100644 index bb76006..0000000 --- a/lib/aws/session_store/dynamo_db/railtie.rb +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. - - -module Aws::SessionStore::DynamoDB - class Railtie < Rails::Railtie - initializer 'aws-sessionstore-dynamodb-rack-middleware' do - ActionDispatch::Session::DynamodbStore = Aws::SessionStore::DynamoDB::RackMiddleware - end - - # Load all rake tasks - rake_tasks do - Dir[File.expand_path("../tasks/*.rake", __FILE__)].each do |rake_task| - load rake_task - end - end - end -end diff --git a/lib/aws/session_store/dynamo_db/table.rb b/lib/aws/session_store/dynamo_db/table.rb index f87bafd..1754227 100644 --- a/lib/aws/session_store/dynamo_db/table.rb +++ b/lib/aws/session_store/dynamo_db/table.rb @@ -1,16 +1,3 @@ -# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. - require 'aws-sdk-dynamodb' require 'logger' diff --git a/lib/aws/session_store/dynamo_db/tasks/session_table.rake b/lib/aws/session_store/dynamo_db/tasks/session_table.rake deleted file mode 100644 index a659c02..0000000 --- a/lib/aws/session_store/dynamo_db/tasks/session_table.rake +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. - -namespace "db" do - namespace "sessions" do - desc 'Clean up old sessions in Amazon DynamoDB session store' - task :cleanup => :environment do |t| - Aws::SessionStore::DynamoDB::GarbageCollection.collect_garbage - end - end -end diff --git a/lib/aws/session_store/dynamo_db/version.rb b/lib/aws/session_store/dynamo_db/version.rb index 2fdf8a6..d905596 100644 --- a/lib/aws/session_store/dynamo_db/version.rb +++ b/lib/aws/session_store/dynamo_db/version.rb @@ -1,21 +1,7 @@ -# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. - - module Aws module SessionStore module DynamoDB - VERSION = "1.0.0" + VERSION = "2.0.0" end end end diff --git a/lib/rails/generators/sessionstore/dynamodb/dynamodb_generator.rb b/lib/rails/generators/sessionstore/dynamodb/dynamodb_generator.rb deleted file mode 100644 index 9bd0605..0000000 --- a/lib/rails/generators/sessionstore/dynamodb/dynamodb_generator.rb +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. - -require 'rails/generators/named_base' - -# This class generates -# a migration file for deleting and creating -# a DynamoDB sessions table. -module Sessionstore - module Generators - class DynamodbGenerator < Rails::Generators::NamedBase - include Rails::Generators::Migration - - source_root File.expand_path('templates', File.dirname(__FILE__)) - - # Desired name of migration class - argument :name, :type => :string, :default => "sessionstore_migration" - - # @return [Rails Migration File] migration file for creation and deletion of - # session table. - def generate_migration_file - migration_template "sessionstore_migration.rb", - "#{Rails.root}/db/migrate/#{file_name}" - end - - - def copy_sample_config_file - file = File.join("sessionstore", "dynamodb.yml") - template file, File.join(Rails.root, "config", file) - end - - private - - # @return [String] filename - def file_name - name.underscore - end - - # @return [String] migration version using time stamp YYYYMMDDHHSS - def self.next_migration_number(dir = nil) - Time.now.utc.strftime("%Y%m%d%H%M%S") - end - end - end -end diff --git a/lib/rails/generators/sessionstore/dynamodb/templates/sessionstore/USAGE b/lib/rails/generators/sessionstore/dynamodb/templates/sessionstore/USAGE deleted file mode 100644 index c1d0b14..0000000 --- a/lib/rails/generators/sessionstore/dynamodb/templates/sessionstore/USAGE +++ /dev/null @@ -1,13 +0,0 @@ -Description: - Generates a migration file for deleting and a creating a DynamoDB - sessions table, and a configuration file for the session store. - -Example: - rails generate sessionstore:dynamodb - - This will create: - db/migrate/VERSION_migration_name.rb - config/sessionstore/dynamodb.yml - - The migration will be run when the command rake db:migrate is run - in the command line. diff --git a/lib/rails/generators/sessionstore/dynamodb/templates/sessionstore/dynamodb.yml b/lib/rails/generators/sessionstore/dynamodb/templates/sessionstore/dynamodb.yml deleted file mode 100644 index 449f743..0000000 --- a/lib/rails/generators/sessionstore/dynamodb/templates/sessionstore/dynamodb.yml +++ /dev/null @@ -1,71 +0,0 @@ -# Uncomment and manipulate the key value pairs below -# in order to configure the DynamoDB Session Store Application. - -# [String] The secret key for HMAC encryption. -# Must define secret_key here or ENV or at runtime! -# By default, a random key was generated for you! -# -secret_key: <%= require 'securerandom'; SecureRandom.hex(64) %> - -# [String] Session table name. -# -# table_name: Sessions - -# [String] Session table hash key name. -# -# table_key: session_id - -# [Boolean] Define as true or false depending on if you want a strongly -# consistent read. -# See AWS DynamoDB documentation for table consistent_read for more -# information on this setting. -# -# consistent_read: true - -# [Integer] Maximum number of reads consumed per second before -# DynamoDB returns a ThrottlingException. See AWS DynamoDB documentation -# or table read_capacity for more information on this setting. -# -# read_capacity: 10 - -# [Integer] Maximum number of writes consumed per second before -# DynamoDB returns a ThrottlingException. See AWS DynamoDB documentation -# or table write_capacity for more information on this setting. -# -# write_capacity: 5 - -# [Boolean] Define as true or false depending on whether you want all errors to be -# raised up the stack. -# -# raise_errors: false - -# [Integer] Maximum number of seconds earlier -# from the current time that a session was created. -# By default this is 7 days. -# -# max_age: 604800 - -# [Integer] Maximum number of seconds -# before the current time that the session was last accessed. -# By default this is 5 hours. -# -# max_stale: 18000 - -# [Boolean] Define as true or false for whether you want to enable locking -# for all accesses to session data. -# -# enable_locking: false - -# [Integer] Time in milleseconds after which lock will expire. -# -# lock_expiry_time: 500 - -# [Integer] Time in milleseconds to wait before retrying to obtain -# lock once an attempt to obtain lock has been made and has failed. -# -# lock_retry_delay: 500 - -# [Integer] Maximum time in seconds to wait to acquire lock -# before giving up. -# -# lock_max_wait_time: 1 diff --git a/lib/rails/generators/sessionstore/dynamodb/templates/sessionstore_migration.rb b/lib/rails/generators/sessionstore/dynamodb/templates/sessionstore_migration.rb deleted file mode 100644 index 5cb51fe..0000000 --- a/lib/rails/generators/sessionstore/dynamodb/templates/sessionstore_migration.rb +++ /dev/null @@ -1,10 +0,0 @@ -class <%= name.camelize %> < ActiveRecord::Migration - def up - Aws::SessionStore::DynamoDB::Table.create_table - end - - def down - Aws::SessionStore::DynamoDB::Table.delete_table - end -end - diff --git a/spec/aws/session_store/dynamo_db/app_config.yml b/spec/aws/session_store/dynamo_db/app_config.yml index 614f606..836edd8 100644 --- a/spec/aws/session_store/dynamo_db/app_config.yml +++ b/spec/aws/session_store/dynamo_db/app_config.yml @@ -11,9 +11,9 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. - table_name: NewTable - table_key: Somekey - consistent_read: true - AWS_ACCESS_KEY_ID: FakeKey - AWS_SECRET_ACCESS_KEY: Secret - AWS_REGION: New York +table_name: NewTable +table_key: Somekey +consistent_read: true +AWS_ACCESS_KEY_ID: FakeKey +AWS_SECRET_ACCESS_KEY: Secret +AWS_REGION: New York diff --git a/spec/aws/session_store/dynamo_db/config/dynamo_db_session.yml b/spec/aws/session_store/dynamo_db/config/dynamo_db_session.yml deleted file mode 100644 index 6013d5d..0000000 --- a/spec/aws/session_store/dynamo_db/config/dynamo_db_session.yml +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. - -development: - key1: development value 1 -test: - table_name: NewTable - table_key: Somekey - consistent_read: true - AWS_ACCESS_KEY_ID: FakeKey - AWS_SECRET_ACCESS_KEY: Secret - AWS_REGION: New York -production: - key1: production value 1 diff --git a/spec/aws/session_store/dynamo_db/configuration_spec.rb b/spec/aws/session_store/dynamo_db/configuration_spec.rb index 1164136..292e1a6 100644 --- a/spec/aws/session_store/dynamo_db/configuration_spec.rb +++ b/spec/aws/session_store/dynamo_db/configuration_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"). You @@ -11,91 +13,66 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. -require "spec_helper" +require 'spec_helper' describe Aws::SessionStore::DynamoDB::Configuration do - let(:defaults) do { - :table_name => "sessions", - :table_key => "session_id", - :consistent_read => true, - :read_capacity => 10, - :write_capacity => 5, - :raise_errors => false + table_name: 'sessions', + table_key: 'session_id', + consistent_read: true, + read_capacity: 10, + write_capacity: 5, + raise_errors: false } end let(:expected_file_opts) do { - :consistent_read => true, - :AWS_ACCESS_KEY_ID => 'FakeKey', - :AWS_REGION => 'New York', - :table_name => 'NewTable', - :table_key => 'Somekey', - :AWS_SECRET_ACCESS_KEY => 'Secret' + consistent_read: true, + AWS_ACCESS_KEY_ID: 'FakeKey', + AWS_REGION: 'New York', + table_name: 'NewTable', + table_key: 'Somekey', + AWS_SECRET_ACCESS_KEY: 'Secret' } end let(:runtime_options) do { - :table_name => "SessionTable", - :table_key => "session_id_stuff" + table_name: 'SessionTable', + table_key: 'session_id_stuff' } end def expected_options(opts) cfg = Aws::SessionStore::DynamoDB::Configuration.new(opts) expected_opts = defaults.merge(expected_file_opts).merge(opts) - cfg.to_hash.should include(expected_opts) + expect(cfg.to_hash).to include(expected_opts) end - context "Configuration Tests" do - it "configures option with out runtime,YAML or ENV options" do + context 'Configuration Tests' do + it 'configures option with out runtime,YAML or ENV options' do cfg = Aws::SessionStore::DynamoDB::Configuration.new - cfg.to_hash.should include(defaults) + expect(cfg.to_hash).to include(defaults) end - it "configures accurate option hash with runtime options, no YAML or ENV" do + it 'configures accurate option hash with runtime options, no YAML or ENV' do cfg = Aws::SessionStore::DynamoDB::Configuration.new(runtime_options) expected_opts = defaults.merge(runtime_options) - cfg.to_hash.should include(expected_opts) + expect(cfg.to_hash).to include(expected_opts) end - it "merge YAML and runtime options giving runtime precendence" do + it 'merge YAML and runtime options giving runtime precendence' do config_path = File.dirname(__FILE__) + '/app_config.yml' - runtime_opts = {:config_file => config_path}.merge(runtime_options) + runtime_opts = { config_file: config_path }.merge(runtime_options) expected_options(runtime_opts) end - it "loads options from YAML file based on Rails environment" do - rails = double('Rails', {:env => 'test', :root => ''}) - stub_const("Rails", rails) - config_path = File.dirname(__FILE__) + '/rails_app_config.yml' - runtime_opts = {:config_file => config_path}.merge(runtime_options) - expected_options(runtime_opts) - end - - it "has rails defiend but no file specified, no error thrown" do - rails = double('Rails', {:env => 'test', :root => ''}) - stub_const("Rails", rails) - cfg = Aws::SessionStore::DynamoDB::Configuration.new(runtime_options) - expected_opts = defaults.merge(runtime_options) - cfg.to_hash.should include(expected_opts) - end - - it "has rails defiend but and default rails YAML file loads" do - rails = double('Rails', {:env => 'test', :root => File.dirname(__FILE__)}) - stub_const("Rails", rails) - cfg = Aws::SessionStore::DynamoDB::Configuration.new(runtime_options) - expected_opts = defaults.merge(runtime_options) - cfg.to_hash.should include(expected_opts) - end - - it "throws an exception when wrong path for file" do + it 'throws an exception when wrong path for file' do config_path = 'Wrong path!' - runtime_opts = {:config_file => config_path}.merge(runtime_options) - expect{cfg = Aws::SessionStore::DynamoDB::Configuration.new(runtime_opts)}.to raise_error(Errno::ENOENT) + runtime_opts = { config_file: config_path }.merge(runtime_options) + expect { cfg = Aws::SessionStore::DynamoDB::Configuration.new(runtime_opts) }.to raise_error(Errno::ENOENT) end end end diff --git a/spec/aws/session_store/dynamo_db/error/default_error_handler_spec.rb b/spec/aws/session_store/dynamo_db/error/default_error_handler_spec.rb index 6bc5b70..4b8b3c3 100644 --- a/spec/aws/session_store/dynamo_db/error/default_error_handler_spec.rb +++ b/spec/aws/session_store/dynamo_db/error/default_error_handler_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"). You @@ -11,7 +13,6 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. - require 'spec_helper' describe Aws::SessionStore::DynamoDB do @@ -20,43 +21,44 @@ instance_exec(&ConstantHelpers) before do - @options = { :dynamo_db_client => client, :secret_key => 'meltingbutter' } + @options = { dynamo_db_client: client, secret_key: 'meltingbutter' } end let(:base_app) { MultiplierApplication.new } let(:app) { Aws::SessionStore::DynamoDB::RackMiddleware.new(base_app, @options) } let(:client) { double('Aws::DynamoDB::Client') } - context "Error handling for Rack Middleware with default error handler" do - it "raises error for missing secret key" do - client.stub(:update_item).and_raise(missing_key_error) - lambda { get "/" }.should raise_error(missing_key_error) + context 'Error handling for Rack Middleware with default error handler' do + it 'raises error for missing secret key' do + allow(client).to receive(:update_item).and_raise(missing_key_error) + expect { get '/' }.to raise_error(missing_key_error) end - it "catches exception for inaccurate table name and raises error " do - client.stub(:update_item).and_raise(resource_error) - lambda { get "/" }.should raise_error(resource_error) + it 'catches exception for inaccurate table name and raises error ' do + allow(client).to receive(:update_item).and_raise(resource_error) + expect { get '/' }.to raise_error(resource_error) end - it "catches exception for inaccurate table key" do - client.stub(:update_item).and_raise(key_error) - client.stub(:get_item).and_raise(key_error) - get "/" - last_request.env["rack.errors"].string.should include(key_error_msg) + it 'catches exception for inaccurate table key' do + allow(client).to receive(:update_item).and_raise(key_error) + allow(client).to receive(:get_item).and_raise(key_error) + + get '/' + expect(last_request.env['rack.errors'].string).to include(key_error_msg) end end - context "Test ExceptionHandler with true as return value for handle_error" do - it "raises all errors" do + context 'Test ExceptionHandler with true as return value for handle_error' do + it 'raises all errors' do @options[:raise_errors] = true - client.stub(:update_item).and_raise(client_error) - lambda { get "/" }.should raise_error(client_error) + allow(client).to receive(:update_item).and_raise(client_error) + expect { get '/' }.to raise_error(client_error) end - it "catches exception for inaccurate table key and raises error" do + it 'catches exception for inaccurate table key and raises error' do @options[:raise_errors] = true - client.stub(:update_item).and_raise(key_error) - lambda { get "/" }.should raise_error(key_error) + allow(client).to receive(:update_item).and_raise(key_error) + expect { get '/' }.to raise_error(key_error) end end end diff --git a/spec/aws/session_store/dynamo_db/garbage_collection_spec.rb b/spec/aws/session_store/dynamo_db/garbage_collection_spec.rb index f7071e0..76478e6 100644 --- a/spec/aws/session_store/dynamo_db/garbage_collection_spec.rb +++ b/spec/aws/session_store/dynamo_db/garbage_collection_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"). You @@ -14,80 +16,79 @@ require 'spec_helper' describe Aws::SessionStore::DynamoDB::GarbageCollection do - def member(min,max) - member = [] - for i in min..max - member << {"session_id"=>{:s=>"#{i}"}} + def items(min, max) + items = [] + (min..max).each do |i| + items << { 'session_id' => { s: i.to_s } } end - member + items end def format_scan_result - member = [] - for i in 31..49 - member << {"session_id"=>{:s=>"#{i}"}} + items = [] + (31..49).each do |i| + items << { 'session_id' => { s: i.to_s } } end - member.inject([]) do |rqst_array, item| - rqst_array << {:delete_request => {:key => item}} - rqst_array + items.each_with_object([]) do |item, rqst_array| + rqst_array << { delete_request: { key: item } } end end def collect_garbage - options = { :dynamo_db_client => dynamo_db_client, :max_age => 100, :max_stale => 100 } + options = { dynamo_db_client: dynamo_db_client, max_age: 100, max_stale: 100 } Aws::SessionStore::DynamoDB::GarbageCollection.collect_garbage(options) end - let(:scan_resp1){ + let(:scan_resp1) do resp = { - :member => member(0, 49), - :count => 50, - :scanned_count => 1000, - :last_evaluated_key => {} + items: items(0, 49), + count: 50, + scanned_count: 1000, + last_evaluated_key: {} } - } + end - let(:scan_resp2){ + let(:scan_resp2) do { - :member => member(0, 31), - :last_evaluated_key => {"session_id"=>{:s=>"31"}} + items: items(0, 31), + last_evaluated_key: { 'session_id' => { s: '31' } } } - } + end - let(:scan_resp3){ + let(:scan_resp3) do { - :member => member(31,49), - :last_evaluated_key => {} + items: items(31, 49), + last_evaluated_key: {} } - } + end - let(:write_resp1){ + let(:write_resp1) do { - :unprocessed_items => {} + unprocessed_items: {} } - } + end - let(:write_resp2){ + let(:write_resp2) do { - :unprocessed_items => { - "sessions" => [ + unprocessed_items: { + 'sessions' => [ { - :delete_request => { - :key => { - "session_id" => + delete_request: { + key: { + 'session_id' => { - :s => "1" + s: '1' } } } }, { - :delete_request => { - :key => { - "session_id" => + delete_request: { + key: { + 'session_id' => { - :s => "17" + s: '17' } } } @@ -95,64 +96,62 @@ def collect_garbage ] } } - } + end let(:dynamo_db_client) {Aws::DynamoDB::Client.new} - context "Mock DynamoDB client with garbage collection" do - - it "processes scan result greater than 25 and deletes in batches of 25" do - dynamo_db_client.should_receive(:scan). - exactly(1).times.and_return(scan_resp1) - dynamo_db_client.should_receive(:batch_write_item). + context 'Mock DynamoDB client with garbage collection' do + it 'processes scan result greater than 25 and deletes in batches of 25' do + expect(dynamo_db_client).to receive(:scan) + .exactly(1).times.and_return(scan_resp1) + expect(dynamo_db_client).to receive(:batch_write_item). exactly(2).times.and_return(write_resp1) collect_garbage end - it "gets scan results then returns last evaluated key and resumes scanning" do - dynamo_db_client.should_receive(:scan). + it 'gets scan results then returns last evaluated key and resumes scanning' do + expect(dynamo_db_client).to receive(:scan). exactly(1).times.and_return(scan_resp2) - dynamo_db_client.should_receive(:scan). + expect(dynamo_db_client).to receive(:scan). exactly(1).times.with(hash_including(exclusive_start_key: scan_resp2[:last_evaluated_key])). and_return(scan_resp3) - dynamo_db_client.should_receive(:batch_write_item). + expect(dynamo_db_client).to receive(:batch_write_item). exactly(3).times.and_return(write_resp1) - collect_garbage + collect_garbage end - it "it formats unprocessed_items and then batch deletes them" do - dynamo_db_client.should_receive(:scan). + it 'it formats unprocessed_items and then batch deletes them' do + expect(dynamo_db_client).to receive(:scan). exactly(1).times.and_return(scan_resp3) - dynamo_db_client.should_receive(:batch_write_item).ordered. - with(:request_items => {"sessions" => format_scan_result}). + expect(dynamo_db_client).to receive(:batch_write_item).ordered. + with(request_items: { 'sessions' => format_scan_result }). and_return(write_resp2) - dynamo_db_client.should_receive(:batch_write_item).ordered.with( - :request_items => - { - "sessions" => [ + expect(dynamo_db_client).to receive(:batch_write_item).ordered.with( + request_items: { + 'sessions' => [ { - :delete_request => { - :key => { - "session_id" => + delete_request: { + key: { + 'session_id' => { - :s => "1" + s: '1' } } } }, { - :delete_request => { - :key => { - "session_id" => + delete_request: { + key: { + 'session_id' => { - :s => "17" + s: '17' } } } } ] } - ).and_return(write_resp1) + ).and_return(write_resp1) collect_garbage end end diff --git a/spec/aws/session_store/dynamo_db/locking/threaded_sessions_spec.rb b/spec/aws/session_store/dynamo_db/locking/threaded_sessions_spec.rb index e4dbf29..bdd7c5e 100644 --- a/spec/aws/session_store/dynamo_db/locking/threaded_sessions_spec.rb +++ b/spec/aws/session_store/dynamo_db/locking/threaded_sessions_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"). You @@ -11,7 +13,6 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. - require 'spec_helper' describe Aws::SessionStore::DynamoDB::RackMiddleware do @@ -20,17 +21,17 @@ def thread(mul_val, time, check) Thread.new do sleep(time) - get "/" - last_request.session[:multiplier].should eq(mul_val) if check + get '/' + expect(last_request.session[:multiplier]).to eq(mul_val) if check end end def thread_exception(error) - Thread.new { expect { get "/" }.to raise_error(error) } + Thread.new { expect { get '/' }.to raise_error(error) } end def update_item_mock(options, update_method) - if options[:return_values] == "UPDATED_NEW" && options.has_key?(:expected) + if options[:return_values] == 'UPDATED_NEW' && options.key?(:expected) sleep(0.50) update_method.call(options) else @@ -41,23 +42,23 @@ def update_item_mock(options, update_method) let(:base_app) { MultiplierApplication.new } let(:app) { Aws::SessionStore::DynamoDB::RackMiddleware.new(base_app, @options) } - context "Mock Multiple Threaded Sessions", :integration => true do + context 'Mock Multiple Threaded Sessions', integration: true do before do @options = Aws::SessionStore::DynamoDB::Configuration.new.to_hash @options[:enable_locking] = true @options[:secret_key] = 'watermelon_smiles' update_method = @options[:dynamo_db_client].method(:update_item) - @options[:dynamo_db_client].should_receive(:update_item).at_least(:once) do |options| + expect(@options[:dynamo_db_client]).to receive(:update_item).at_least(:once) do |options| update_item_mock(options, update_method) end end - it "should wait for lock" do + it 'should wait for lock' do @options[:lock_expiry_time] = 2000 - get "/" - last_request.session[:multiplier].should eq(1) + get '/' + expect(last_request.session[:multiplier]).to eq(1) t1 = thread(2, 0, false) t2 = thread(4, 0.25, true) @@ -65,11 +66,11 @@ def update_item_mock(options, update_method) t2.join end - it "should bust lock" do + it 'should bust lock' do @options[:lock_expiry_time] = 100 - get "/" - last_request.session[:multiplier].should eq(1) + get '/' + expect(last_request.session[:multiplier]).to eq(1) t1 = thread_exception(Aws::DynamoDB::Errors::ConditionalCheckFailedException) t2 = thread(2, 0.25, true) @@ -77,13 +78,13 @@ def update_item_mock(options, update_method) t2.join end - it "should throw exceeded time spent aquiring lock error" do + it 'should throw exceeded time spent aquiring lock error' do @options[:lock_expiry_time] = 1000 @options[:lock_retry_delay] = 100 @options[:lock_max_wait_time] = 0.25 - get "/" - last_request.session[:multiplier].should eq(1) + get '/' + expect(last_request.session[:multiplier]).to eq(1) t1 = thread(2, 0, false) sleep(0.25) diff --git a/spec/aws/session_store/dynamo_db/rack_middleware_database_spec.rb b/spec/aws/session_store/dynamo_db/rack_middleware_database_spec.rb index 2bb75b7..6737c60 100644 --- a/spec/aws/session_store/dynamo_db/rack_middleware_database_spec.rb +++ b/spec/aws/session_store/dynamo_db/rack_middleware_database_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"). You @@ -22,28 +24,28 @@ module DynamoDB instance_exec(&ConstantHelpers) before do - @options = { :secret_key => 'watermelon_cherries' } + @options = { secret_key: 'watermelon_cherries' } end # Table options for client def table_opts(sid) { - :table_name => Configuration::DEFAULTS[:table_name], - :key => { Configuration::DEFAULTS[:table_key] => sid } + table_name: Configuration::DEFAULTS[:table_name], + key: { Configuration::DEFAULTS[:table_key] => sid } } end # Attributes to be retrieved via client def attr_opts { - :attributes_to_get => ["data", "created_at", "locked_at"], - :consistent_read => true + attributes_to_get: %w[data created_at locked_at], + consistent_read: true } end def extract_time(sid) options = table_opts(sid).merge(attr_opts) - Time.at((client.get_item(options)[:item]["created_at"]).to_f) + Time.at((client.get_item(options)[:item]['created_at']).to_f) end let(:base_app) { MultiplierApplication.new } @@ -51,76 +53,75 @@ def extract_time(sid) let(:config) { Configuration.new } let(:client) { config.dynamo_db_client } - context "Testing best case session storage", :integration => true do - it "stores session data in session object" do - get "/" - last_request.session[:multiplier].should eq(1) + context 'Testing best case session storage', integration: true do + it 'stores session data in session object' do + get '/' + expect(last_request.session[:multiplier]).to eq(1) end - it "creates a new HTTP cookie when Cookie not supplied" do - get "/" - last_response.body.should eq('All good!') - last_response['Set-Cookie'].should be_truthy + it 'creates a new HTTP cookie when Cookie not supplied' do + get '/' + expect(last_response.body).to eq('All good!') + expect(last_response['Set-Cookie']).to be_truthy end - it "does not rewrite Cookie if cookie previously/accuarately set" do - get "/" - last_response['Set-Cookie'].should_not be_nil - + it 'does not rewrite Cookie if cookie previously/accuarately set' do + get '/' + expect(last_response['Set-Cookie']).not_to be_nil - get "/" - last_response['Set-Cookie'].should be_nil + get '/' + expect(last_response['Set-Cookie']).to be_nil end - it "does not set cookie when defer option is specifed" do + it 'does not set cookie when defer option is specified' do @options[:defer] = true - get "/" - last_response['Set-Cookie'].should be_nil + get '/' + expect(last_response['Set-Cookie']).to be_nil end - it "creates new sessopm with false/nonexistant http-cookie id" do - get "/", {}, invalid_cookie.merge(invalid_session_data) - last_response['Set-Cookie'].should_not eq("rack.session=ApplePieBlueberries") - last_response['Set-Cookie'].should_not be_nil + it 'creates new session with false/nonexistant http-cookie id' do + get '/', {}, invalid_cookie.merge(invalid_session_data) + expect(last_response['Set-Cookie']).not_to eq('rack.session=ApplePieBlueberries') + expect(last_response['Set-Cookie']).not_to be_nil end - it "expires after specified time and sets date for cookie to expire" do + it 'expires after specified time and sets date for cookie to expire' do @options[:expire_after] = 1 - get "/" + get '/' session_cookie = last_response['Set-Cookie'] sleep(1.2) - get "/" - last_response['Set-Cookie'].should_not be_nil - last_response['Set-Cookie'].should_not eq(session_cookie) + get '/' + expect(last_response['Set-Cookie']).not_to be_nil + expect(last_response['Set-Cookie']).not_to eq(session_cookie) end - it "will not set a session cookie when defer is true" do + it 'will not set a session cookie when defer is true' do @options[:defer] = true - get "/" - last_response['Set-Cookie'].should eq(nil) + get '/' + expect(last_response['Set-Cookie']).to be_nil end - it "adds the created at attribute for a new session" do - get "/" - last_request.env["dynamo_db.new_session"].should eq("true") + it 'adds the created at attribute for a new session' do + get '/' + expect(last_request.env['dynamo_db.new_session']).to eq('true') sid = last_response['Set-Cookie'].split(/[;\=]/)[1] time = extract_time(sid) - time.should be_within(2).of(Time.now) + expect(time).to be_within(2).of(Time.now) - get "/" - last_request.env['dynamo_db.new_session'].should be(nil) + get '/' + expect(last_request.env['dynamo_db.new_session']).to be_nil end - it "releases pessimistic lock at finish of transaction" do + it 'releases pessimistic lock at finish of transaction' do @options[:enable_locking] = true - get "/" - last_request.env["dynamo_db.new_session"].should eq("true") + get '/' + expect(last_request.env['dynamo_db.new_session']).to eq('true') sid = last_response['Set-Cookie'].split(/[;\=]/)[1] - get "/" + get '/' options = table_opts(sid).merge(attr_opts) - client.get_item(options)[:item]["locked_at"].should be_nil + expect(client.get_item(options)[:item]['locked_at']).to be_nil end end end diff --git a/spec/aws/session_store/dynamo_db/rack_middleware_spec.rb b/spec/aws/session_store/dynamo_db/rack_middleware_spec.rb index d47e163..0b7f7d3 100644 --- a/spec/aws/session_store/dynamo_db/rack_middleware_spec.rb +++ b/spec/aws/session_store/dynamo_db/rack_middleware_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"). You @@ -22,19 +24,19 @@ module DynamoDB before { @options = {} } def ensure_data_updated(mutated_data) - dynamo_db_client.should_receive(:update_item) do |options| + expect(dynamo_db_client).to receive(:update_item) do |options| if mutated_data - options[:attribute_updates]["data"].should_not be_nil + expect(options[:attribute_updates]['data']).not_to be_nil else - options[:attribute_updates]["data"].should be_nil + expect(options[:attribute_updates]['data']).to be_nil end end end before do @options = { - :dynamo_db_client => dynamo_db_client, - :secret_key => 'watermelon_cherries' + dynamo_db_client: dynamo_db_client, + secret_key: 'watermelon_cherries' } end @@ -42,105 +44,101 @@ def ensure_data_updated(mutated_data) let(:app) { RackMiddleware.new(base_app, @options) } let(:sample_packed_data) do - [Marshal.dump("multiplier" => 1)].pack("m*") + [Marshal.dump('multiplier' => 1)].pack('m*') end let(:dynamo_db_client) do - client = double('Aws::DynamoDB::Client') - client.stub(:delete_item) { 'Deleted' } - client.stub(:list_tables) { {:table_names => ['Sessions']} } - client.stub(:get_item) do - { :item => { 'data' => sample_packed_data } } - end - client.stub(:update_item) do - { :attributes => { :created_at => 'now' } } - end - client + double( + 'Aws::DynamoDB::Client', + delete_item: 'Deleted', + list_tables: { table_names: ['Sessions'] }, + get_item: { item: { 'data' => sample_packed_data } }, + update_item: { attributes: { created_at: 'now' } } + ) end - context "Testing best case session storage with mock client" do - it "stores session data in session object" do - get "/" - last_request.session.to_hash.should eq("multiplier" => 1) + context 'Testing best case session storage with mock client' do + it 'stores session data in session object' do + get '/' + expect(last_request.session.to_hash).to eq('multiplier' => 1) end - it "creates a new HTTP cookie when Cookie not supplied" do - get "/" - last_response.body.should eq('All good!') - last_response['Set-Cookie'].should be_truthy + it 'creates a new HTTP cookie when Cookie not supplied' do + get '/' + expect(last_response.body).to eq('All good!') + expect(last_response['Set-Cookie']).to be_truthy end - it "loads/manipulates a session based on id from HTTP-Cookie" do - get "/" - last_request.session.to_hash.should eq("multiplier" => 1) + it 'loads/manipulates a session based on id from HTTP-Cookie' do + get '/' + expect(last_request.session.to_hash).to eq('multiplier' => 1) - get "/" - last_request.session.to_hash.should eq("multiplier" => 2) + get '/' + expect(last_request.session.to_hash).to eq('multiplier' => 2) end - it "does not rewrite Cookie if cookie previously/accuarately set" do - get "/" - last_response['Set-Cookie'].should_not be_nil + it 'does not rewrite Cookie if cookie previously/accuarately set' do + get '/' + expect(last_response['Set-Cookie']).not_to be_nil - get "/" - last_response['Set-Cookie'].should be_nil + get '/' + expect(last_response['Set-Cookie']).to be_nil end - it "does not set cookie when defer option is specifed" do + it 'does not set cookie when defer option is specifed' do @options[:defer] = true - get "/" - last_response['Set-Cookie'].should eq(nil) + get '/' + expect(last_response['Set-Cookie']).to be_nil end - it "creates new sessopm with false/nonexistant http-cookie id" do - get "/" - last_response['Set-Cookie'].should_not eq('1234') - last_response['Set-Cookie'].should_not be_nil + it 'creates new session with false/nonexistant http-cookie id' do + get '/' + expect(last_response['Set-Cookie']).not_to eq('1234') + expect(last_response['Set-Cookie']).not_to be_nil end - it "expires after specified time and sets date for cookie to expire" do + it 'expires after specified time and sets date for cookie to expire' do @options[:expire_after] = 0 - get "/" + get '/' session_cookie = last_response['Set-Cookie'] - get "/" - last_response['Set-Cookie'].should_not be_nil - last_response['Set-Cookie'].should_not eq(session_cookie) + get '/' + expect(last_response['Set-Cookie']).not_to be_nil + expect(last_response['Set-Cookie']).not_to eq(session_cookie) end it "doesn't reset Cookie if not outside expire date" do @options[:expire_after] = 3600 - get "/" + get '/' session_cookie = last_response['Set-Cookie'] - get "/" - last_response['Set-Cookie'].should eq(session_cookie) + get '/' + expect(last_response['Set-Cookie']).to eq(session_cookie) end - it "will not set a session cookie when defer is true" do + it 'will not set a session cookie when defer is true' do @options[:defer] = true - get "/" - last_response['Set-Cookie'].should eq(nil) + get '/' + expect(last_response['Set-Cookie']).to be_nil end - it "generates sid and migrates data to new sid when renew is selected" do + it 'generates sid and migrates data to new sid when renew is selected' do @options[:renew] = true - get "/" - last_request.session.to_hash.should eq("multiplier" => 1) + get '/' + expect(last_request.session.to_hash).to eq('multiplier' => 1) session_cookie = last_response['Set-Cookie'] - get "/" , "HTTP_Cookie" => session_cookie - last_response['Set-Cookie'].should_not eq(session_cookie) - last_request.session.to_hash.should eq("multiplier" => 2) - session_cookie = last_response['Set-Cookie'] + get '/', 'HTTP_Cookie' => session_cookie + expect(last_response['Set-Cookie']).not_to eq(session_cookie) + expect(last_request.session.to_hash).to eq('multiplier' => 2) end it "doesn't resend unmutated data" do ensure_data_updated(true) @options[:renew] = true - get "/" + get '/' ensure_data_updated(false) - get "/", {}, { "rack.session" => { "multiplier" => nil } } + get '/', {}, { 'rack.session' => { 'multiplier' => nil } } end end end diff --git a/spec/aws/session_store/dynamo_db/rails_app_config.yml b/spec/aws/session_store/dynamo_db/rails_app_config.yml deleted file mode 100644 index 6013d5d..0000000 --- a/spec/aws/session_store/dynamo_db/rails_app_config.yml +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. - -development: - key1: development value 1 -test: - table_name: NewTable - table_key: Somekey - consistent_read: true - AWS_ACCESS_KEY_ID: FakeKey - AWS_SECRET_ACCESS_KEY: Secret - AWS_REGION: New York -production: - key1: production value 1 diff --git a/spec/aws/session_store/dynamo_db/table_spec.rb b/spec/aws/session_store/dynamo_db/table_spec.rb index 068e2d4..429ad63 100644 --- a/spec/aws/session_store/dynamo_db/table_spec.rb +++ b/spec/aws/session_store/dynamo_db/table_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"). You @@ -19,22 +21,22 @@ module Aws module SessionStore module DynamoDB describe Table do - context "Mock Table Methods Tests", :integration => true do + context 'Mock Table Methods Tests', integration: true do let(:table_name) { "sessionstore-integration-test-#{Time.now.to_i}" } - let(:options) { {:table_name => table_name} } + let(:options) { { table_name: table_name } } let(:io) { StringIO.new } - before { Table.stub(:logger) { Logger.new(io) } } + before { allow(Table).to receive(:logger) { Logger.new(io) } } - it "Creates and deletes a new table" do + it 'Creates and deletes a new table' do Table.create_table(options) # second attempt should warn Table.create_table(options) - io.string.should include("Table #{table_name} created, waiting for activation...\n") - io.string.should include("Table #{table_name} is now ready to use.\n") - io.string.should include("Table #{table_name} already exists, skipping creation.\n") + expect(io.string).to include("Table #{table_name} created, waiting for activation...\n") + expect(io.string).to include("Table #{table_name} is now ready to use.\n") + expect(io.string).to include("Table #{table_name} already exists, skipping creation.\n") # now delete table Table.delete_table(options) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 5ad30e8..44da4da 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"). You @@ -19,7 +21,7 @@ rescue LoadError end -$: << File.join(File.dirname(File.dirname(__FILE__)), "lib") +$LOAD_PATH << File.join(File.dirname(File.dirname(__FILE__)), 'lib') require 'rspec' require 'aws-sessionstore-dynamodb' @@ -33,35 +35,36 @@ def call(env) else env['rack.session'][:multiplier] = 1 end - [200, {'Content-Type' => 'text/plain'}, ['All good!']] + [200, { 'Content-Type' => 'text/plain' }, ['All good!']] end end ConstantHelpers = lambda do let(:token_error_msg) { 'The security token included in the request is invalid' } - let(:resource_error) { + let(:resource_error) do Aws::DynamoDB::Errors::ResourceNotFoundException.new(double('Seahorse::Client::RequestContext'), resource_error_msg) - } + end let(:resource_error_msg) { 'The Resource is not found.' } let(:key_error) { Aws::DynamoDB::Errors::ValidationException.new(double('Seahorse::Client::RequestContext'), key_error_msg) } let(:key_error_msg) { 'The provided key element does not match the schema' } - let(:client_error) { + let(:client_error) do Aws::DynamoDB::Errors::UnrecognizedClientException.new(double('Seahorse::Client::RequestContext'), client_error_msg) - } + end let(:client_error_msg) { 'Unrecognized Client.'} - let(:invalid_cookie) { {"HTTP_COOKIE" => "rack.session=ApplePieBlueberries"} } - let(:invalid_session_data) { {"rack.session"=>{"multiplier" => 1}} } + let(:invalid_cookie) { { 'HTTP_COOKIE' => 'rack.session=ApplePieBlueberries' } } + let(:invalid_session_data) { { 'rack.session' => { 'multiplier' => 1 } } } let(:rack_default_error_msg) { "Warning! Aws::SessionStore::DynamoDB failed to save session. Content dropped.\n" } let(:missing_key_error) { Aws::SessionStore::DynamoDB::MissingSecretKeyError } end RSpec.configure do |c| - c.before(:each, :integration => true) do - opts = {:table_name => 'sessionstore-integration-test'} + c.raise_errors_for_deprecations! + c.before(:each, integration: true) do + opts = { table_name: 'sessionstore-integration-test' } defaults = Aws::SessionStore::DynamoDB::Configuration::DEFAULTS defaults = defaults.merge(opts) - stub_const("Aws::SessionStore::DynamoDB::Configuration::DEFAULTS", defaults) + stub_const('Aws::SessionStore::DynamoDB::Configuration::DEFAULTS', defaults) Aws::SessionStore::DynamoDB::Table.create_table(opts) end end