Finish the conversion to RSpec

- Convert serializers/mixin_json_test.rb to rspec
- Convert functional/thread_safety_test.rb to rspec
- Convert functional/controller_test.rb to rspec
- Move the dummy app from test to spec, delete test dir
This commit is contained in:
Jared Beck 2017-06-10 01:28:48 -04:00
parent c8e15deb6b
commit 94b9306647
91 changed files with 185 additions and 287 deletions

View File

@ -7,10 +7,7 @@ https://stackoverflow.com/tags/paper-trail-gem
**Please do not use github issues to ask usage questions.**
On github, we appreciate bug reports, feature
suggestions, and especially pull requests.
Thanks, and happy (paper) trails :)
On github, we appreciate bug reports, feature suggestions, and pull requests.
## Reporting Bugs
@ -32,13 +29,13 @@ Testing is a little awkward because the test suite:
```
# Create the appropriate database config. file
rm test/dummy/config/database.yml
rm spec/dummy_app/config/database.yml
DB=sqlite bundle exec rake prepare
# If this is the first test run ever, create databases.
# We can't use `appraisal` inside the test dummy, so we must set `BUNDLE_GEMFILE`.
# See test/dummy/config/boot.rb for a complete explanation.
cd test/dummy
# We can't use `appraisal` inside the dummy app, so we must set `BUNDLE_GEMFILE`.
# See spec/dummy_app/config/boot.rb for a complete explanation.
cd spec/dummy_app
export BUNDLE_GEMFILE=../../gemfiles/ar_4.2.gemfile
RAILS_ENV=test bundle exec rake db:setup
RAILS_ENV=foo bundle exec rake db:setup
@ -49,8 +46,7 @@ cd ../..
# Run tests
DB=sqlite bundle exec appraisal ar-4.2 rake
# Run a single test file
DB=sqlite bundle exec appraisal ar-4.2 ruby -I test test/unit/associations_test.rb
# Run a single test
DB=sqlite bundle exec appraisal ar-4.2 rspec spec/paper_trail/serializers/json_spec.rb
```
@ -58,13 +54,13 @@ DB=sqlite bundle exec appraisal ar-4.2 rspec spec/paper_trail/serializers/json_s
```
# Create the appropriate database config. file
rm test/dummy/config/database.yml
rm spec/dummy_app/config/database.yml
DB=sqlite bundle exec rake prepare
# If this is the first test run ever, create databases.
# We can't use `appraisal` inside the test dummy, so we must set `BUNDLE_GEMFILE`.
# See test/dummy/config/boot.rb for a complete explanation.
cd test/dummy
# We can't use `appraisal` inside the dummy app, so we must set `BUNDLE_GEMFILE`.
# See spec/dummy_app/config/boot.rb for a complete explanation.
cd spec/dummy_app
export BUNDLE_GEMFILE=../../gemfiles/ar_5.0.gemfile
RAILS_ENV=test bundle exec rake db:environment:set db:setup
RAILS_ENV=foo bundle exec rake db:environment:set db:setup
@ -80,13 +76,13 @@ DB=sqlite bundle exec appraisal ar-5.0 rake
```
# Create the appropriate database config. file
rm test/dummy/config/database.yml
rm spec/dummy_app/config/database.yml
DB=mysql bundle exec rake prepare
# If this is the first test run ever, create databases.
# We can't use `appraisal` inside the test dummy, so we must set `BUNDLE_GEMFILE`.
# See test/dummy/config/boot.rb for a complete explanation.
cd test/dummy
# We can't use `appraisal` inside the dummy app, so we must set `BUNDLE_GEMFILE`.
# See spec/dummy_app/config/boot.rb for a complete explanation.
cd spec/dummy_app
export BUNDLE_GEMFILE=../../gemfiles/ar_5.0.gemfile
RAILS_ENV=test bundle exec rake db:environment:set db:setup
RAILS_ENV=foo bundle exec rake db:environment:set db:setup
@ -102,14 +98,14 @@ DB=mysql bundle exec appraisal ar-5.0 rake
```
# Create the appropriate database config. file
rm test/dummy/config/database.yml
rm spec/dummy_app/config/database.yml
DB=postgres bundle exec rake prepare
# If this is the first test run ever, create databases.
# Unlike mysql, use create/migrate instead of setup.
# We can't use `appraisal` inside the test dummy, so we must set `BUNDLE_GEMFILE`.
# See test/dummy/config/boot.rb for a complete explanation.
cd test/dummy
# We can't use `appraisal` inside the dummy app, so we must set `BUNDLE_GEMFILE`.
# See spec/dummy_app/config/boot.rb for a complete explanation.
cd spec/dummy_app
export BUNDLE_GEMFILE=../../gemfiles/ar_5.0.gemfile
DB=postgres RAILS_ENV=test bundle exec rake db:drop db:create db:migrate
DB=postgres RAILS_ENV=foo bundle exec rake db:drop db:create db:migrate
@ -124,10 +120,10 @@ DB=postgres bundle exec appraisal ar-5.0 rake
## Editing the migration
After editing `test/dummy/db/migrate/20110208155312_set_up_test_tables.rb` ..
After editing `spec/dummy_app/db/migrate/20110208155312_set_up_test_tables.rb` ..
```
cd test/dummy
cd spec/dummy_app
export BUNDLE_GEMFILE=../../gemfiles/ar_5.1.gemfile
RAILS_ENV=test bundle exec rake db:environment:set db:drop db:create db:migrate
RAILS_ENV=foo bundle exec rake db:environment:set db:drop db:create db:migrate

8
.gitignore vendored
View File

@ -2,10 +2,10 @@ gemfiles/*.lock
NOTES
test/debug.log
test/paper_trail_plugin.sqlite3.db
test/dummy/config/database.yml
test/dummy/db/*.sqlite3
test/dummy/log/*
test/dummy/tmp/*
spec/dummy_app/config/database.yml
spec/dummy_app/db/*.sqlite3
spec/dummy_app/log/*
spec/dummy_app/tmp/*
spec/dummy/
coverage
pkg/*

View File

@ -12,7 +12,7 @@ inherit_from: .rubocop_todo.yml
AllCops:
Exclude:
- gemfiles/vendor/bundle/**/* # This dir only shows up on travis ¯\_(ツ)_/¯
- test/dummy/db/schema.rb # Generated, out of our control
- spec/dummy_app/db/schema.rb # Generated, out of our control
# Set to lowest supported version
TargetRubyVersion: 2.1
@ -21,7 +21,7 @@ AllCops:
# from these is of questionable value.
Metrics/AbcSize:
Exclude:
- 'test/dummy/db/migrate/*'
- 'spec/dummy_app/db/migrate/*'
# Not a useful metric compared to, e.g. `AbcSize`.
Metrics/BlockLength:

View File

@ -4,7 +4,10 @@ Bundler::GemHelper.install_tasks
desc "Set a relevant database.yml for testing"
task :prepare do
ENV["DB"] ||= "sqlite"
FileUtils.cp "test/dummy/config/database.#{ENV['DB']}.yml", "test/dummy/config/database.yml"
FileUtils.cp(
"spec/dummy_app/config/database.#{ENV['DB']}.yml",
"spec/dummy_app/config/database.yml"
)
end
require "rake/testtask"

View File

@ -17,7 +17,7 @@ module PaperTrail
# Since the test suite has test coverage for this, we want to declare
# the association when the test suite is running. This makes it pass when
# DB is not initialized prior to test runs such as when we run on Travis
# CI (there won't be a db in `test/dummy/db/`).
# CI (there won't be a db in `spec/dummy_app/db/`).
if PaperTrail.config.track_associations?
has_many :version_associations, dependent: :destroy
end

View File

@ -30,10 +30,9 @@ has been destroyed.
s.add_development_dependency "appraisal", "~> 2.1"
s.add_development_dependency "rake", "~> 12.0"
s.add_development_dependency "shoulda", "~> 3.5"
s.add_development_dependency "ffaker", "~> 2.5"
# Why `railties`? Possibly used by `test/dummy` boot up?
# Why `railties`? Possibly used by `spec/dummy_app` boot up?
s.add_development_dependency "railties", [">= 4.0", "< 5.2"]
s.add_development_dependency "rack-test", "~> 0.6.3"

View File

@ -0,0 +1,85 @@
require "spec_helper"
RSpec.describe WidgetsController, type: :controller, versioning: true do
before { request.env["REMOTE_ADDR"] = "127.0.0.1" }
after { RequestStore.store[:paper_trail] = nil }
describe "#create" do
context "PT enabled" do
it "stores information like IP address in version" do
post(:create, params_wrapper(widget: { name: "Flugel" }))
widget = assigns(:widget)
expect(widget.versions.length).to(eq(1))
expect(widget.versions.last.whodunnit.to_i).to(eq(153))
expect(widget.versions.last.ip).to(eq("127.0.0.1"))
expect(widget.versions.last.user_agent).to(eq("Rails Testing"))
end
it "controller metadata methods should get evaluated" do
request.env["HTTP_USER_AGENT"] = "User-Agent"
post :create, params_wrapper(widget: { name: "Flugel" })
expect(PaperTrail.enabled_for_controller?).to(eq(true))
expect(PaperTrail.whodunnit).to(eq(153))
expect(PaperTrail.controller_info.present?).to(eq(true))
expect(PaperTrail.controller_info.keys.include?(:ip)).to(eq(true))
expect(PaperTrail.controller_info.keys.include?(:user_agent)).to(eq(true))
end
end
context "PT disabled" do
it "does not save a version, and metadata is not set" do
request.env["HTTP_USER_AGENT"] = "Disable User-Agent"
post :create, params_wrapper(widget: { name: "Flugel" })
expect(assigns(:widget).versions.length).to(eq(0))
expect(PaperTrail).not_to be_enabled_for_controller
expect(PaperTrail.whodunnit).to be_nil
expect(PaperTrail.controller_info).to eq({})
end
end
end
describe "#destroy" do
it "can be disabled" do
request.env["HTTP_USER_AGENT"] = "Disable User-Agent"
post(:create, params_wrapper(widget: { name: "Flugel" }))
w = assigns(:widget)
expect(w.versions.length).to(eq(0))
delete(:destroy, params_wrapper(id: w.id))
expect(PaperTrail::Version.with_item_keys("Widget", w.id).size).to(eq(0))
end
it "stores information like IP address in version" do
w = Widget.create(name: "Roundel")
expect(w.versions.length).to(eq(1))
delete(:destroy, params_wrapper(id: w.id))
widget = assigns(:widget)
expect(widget.versions.length).to(eq(2))
expect(widget.versions.last.ip).to(eq("127.0.0.1"))
expect(widget.versions.last.user_agent).to(eq("Rails Testing"))
expect(widget.versions.last.whodunnit.to_i).to(eq(153))
end
end
describe "#update" do
it "stores information like IP address in version" do
w = Widget.create(name: "Duvel")
expect(w.versions.length).to(eq(1))
put(:update, params_wrapper(id: w.id, widget: { name: "Bugle" }))
widget = assigns(:widget)
expect(widget.versions.length).to(eq(2))
expect(widget.versions.last.whodunnit.to_i).to(eq(153))
expect(widget.versions.last.ip).to(eq("127.0.0.1"))
expect(widget.versions.last.user_agent).to(eq("Rails Testing"))
end
it "can be disabled" do
request.env["HTTP_USER_AGENT"] = "Disable User-Agent"
post(:create, params_wrapper(widget: { name: "Flugel" }))
w = assigns(:widget)
expect(w.versions.length).to(eq(0))
put(:update, params_wrapper(id: w.id, widget: { name: "Bugle" }))
widget = assigns(:widget)
expect(widget.versions.length).to(eq(0))
end
end
end

View File

@ -0,0 +1,18 @@
require "spec_helper"
require_relative "../../support/custom_json_serializer"
RSpec.describe CustomJsonSerializer do
describe ".load" do
it "deserializes, removing pairs with blank keys or values" do
hash = { "key1" => "banana", "tkey" => nil, "" => "foo" }
expect(described_class.load(hash.to_json)).to(eq("key1" => "banana"))
end
end
describe ".dump" do
it "serializes to JSON, removing pairs with nil values" do
hash = { "key1" => "banana", "tkey" => nil, "" => "foo" }
expect(described_class.dump(hash)).to(eq('{"key1":"banana","":"foo"}'))
end
end
end

View File

@ -0,0 +1,44 @@
require "spec_helper"
RSpec.describe PaperTrail do
describe "#set_paper_trail_whodunnit" do
it "is thread-safe" do
blocked = true
slow_thread = Thread.new do
controller = TestController.new
controller.send(:set_paper_trail_whodunnit)
sleep(0.001) while blocked
described_class.whodunnit
end
fast_thread = Thread.new do
controller = TestController.new
controller.send(:set_paper_trail_whodunnit)
who = described_class.whodunnit
blocked = false
who
end
expect(fast_thread.value).not_to(eq(slow_thread.value))
end
end
describe "#without_versioning" do
it "is thread-safe" do
enabled = nil
slow_thread = Thread.new do
Widget.new.paper_trail.without_versioning do
sleep(0.01)
enabled = Widget.paper_trail.enabled?
sleep(0.01)
end
enabled
end
fast_thread = Thread.new do
sleep(0.005)
Widget.paper_trail.enabled?
end
expect(fast_thread.value).not_to(eq(slow_thread.value))
expect(Widget.paper_trail.enabled?).to(eq(true))
expect(described_class.enabled_for_model?(Widget)).to(eq(true))
end
end
end

View File

@ -1,13 +1,13 @@
require "pry"
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= "test"
ENV["DB"] ||= "sqlite"
unless File.exist?(File.expand_path("../../test/dummy/config/database.yml", __FILE__))
unless File.exist?(File.expand_path("dummy_app/config/database.yml", __dir__))
warn "WARNING: No database.yml detected for the dummy app, please run `rake prepare` first"
end
require "pry"
RSpec.configure do |config|
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
@ -52,18 +52,14 @@ def params_wrapper(args)
end
end
require File.expand_path("../../test/dummy/config/environment", __FILE__)
require File.expand_path("../dummy_app/config/environment", __FILE__)
require "rspec/rails"
require "paper_trail/frameworks/rspec"
require "ffaker"
require "timecop"
# prevent Test::Unit's AutoRunner from executing during RSpec's rake task
Test::Unit.run = true if defined?(Test::Unit) && Test::Unit.respond_to?(:run=)
# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.check_pending! if ActiveRecord::Migration.respond_to?(:check_pending!)
# Run any available migration
ActiveRecord::Migrator.migrate File.expand_path("dummy_app/db/migrate/", __dir__)
require "database_cleaner"
DatabaseCleaner.strategy = :truncation

View File

@ -1,90 +0,0 @@
require "test_helper"
class ControllerTest < ActionController::TestCase
tests WidgetsController
setup do
@request.env["REMOTE_ADDR"] = "127.0.0.1"
end
# Mimick what RequestStore will do outside of the test env, since it is
# middleware, and doesn't get executed in controller / request specs
teardown do
RequestStore.store[:paper_trail] = nil
end
test "disable on create" do
@request.env["HTTP_USER_AGENT"] = "Disable User-Agent"
post :create, params_wrapper(widget: { name: "Flugel" })
assert_equal 0, assigns(:widget).versions.length
end
test "disable on update" do
@request.env["HTTP_USER_AGENT"] = "Disable User-Agent"
post :create, params_wrapper(widget: { name: "Flugel" })
w = assigns(:widget)
assert_equal 0, w.versions.length
put :update, params_wrapper(id: w.id, widget: { name: "Bugle" })
widget = assigns(:widget)
assert_equal 0, widget.versions.length
end
test "disable on destroy" do
@request.env["HTTP_USER_AGENT"] = "Disable User-Agent"
post :create, params_wrapper(widget: { name: "Flugel" })
w = assigns(:widget)
assert_equal 0, w.versions.length
delete :destroy, params_wrapper(id: w.id)
assert_equal 0, PaperTrail::Version.with_item_keys("Widget", w.id).size
end
test "create" do
post :create, params_wrapper(widget: { name: "Flugel" })
widget = assigns(:widget)
assert_equal 1, widget.versions.length
assert_equal 153, widget.versions.last.whodunnit.to_i
assert_equal "127.0.0.1", widget.versions.last.ip
assert_equal "Rails Testing", widget.versions.last.user_agent
end
test "update" do
w = Widget.create name: "Duvel"
assert_equal 1, w.versions.length
put :update, params_wrapper(id: w.id, widget: { name: "Bugle" })
widget = assigns(:widget)
assert_equal 2, widget.versions.length
assert_equal 153, widget.versions.last.whodunnit.to_i
assert_equal "127.0.0.1", widget.versions.last.ip
assert_equal "Rails Testing", widget.versions.last.user_agent
end
test "destroy" do
w = Widget.create name: "Roundel"
assert_equal 1, w.versions.length
delete :destroy, params_wrapper(id: w.id)
widget = assigns(:widget)
assert_equal 2, widget.versions.length
assert_equal "127.0.0.1", widget.versions.last.ip
assert_equal "Rails Testing", widget.versions.last.user_agent
assert_equal 153, widget.versions.last.whodunnit.to_i
end
test "controller metadata methods should get evaluated if PT enabled for controller" do
@request.env["HTTP_USER_AGENT"] = "User-Agent"
post :create, params_wrapper(widget: { name: "Flugel" })
assert PaperTrail.enabled_for_controller?
assert_equal 153, PaperTrail.whodunnit
assert PaperTrail.controller_info.present?
assert PaperTrail.controller_info.keys.include?(:ip)
assert PaperTrail.controller_info.keys.include?(:user_agent)
end
test "controller metadata methods should not get evaluated if PT disabled for controller" do
@request.env["HTTP_USER_AGENT"] = "Disable User-Agent"
post :create, params_wrapper(widget: { name: "Flugel" })
assert_equal 0, assigns(:widget).versions.length
assert !PaperTrail.enabled_for_controller?
assert PaperTrail.whodunnit.nil?
assert PaperTrail.controller_info.nil?
end
end

View File

@ -1,46 +0,0 @@
require "test_helper"
class ThreadSafetyTest < ActionController::TestCase
test "thread-safe when using #set_paper_trail_whodunnit" do
blocked = true
slow_thread = Thread.new do
controller = TestController.new
controller.send :set_paper_trail_whodunnit
sleep 0.001 while blocked
PaperTrail.whodunnit
end
fast_thread = Thread.new do
controller = TestController.new
controller.send :set_paper_trail_whodunnit
who = PaperTrail.whodunnit
blocked = false
who
end
assert_not_equal slow_thread.value, fast_thread.value
end
test "thread-safe when using #without_versioning" do
enabled = nil
slow_thread = Thread.new do
Widget.new.paper_trail.without_versioning do
sleep(0.01)
enabled = Widget.paper_trail.enabled?
sleep(0.01)
end
enabled
end
fast_thread = Thread.new do
sleep(0.005)
Widget.paper_trail.enabled?
end
assert_not_equal slow_thread.value, fast_thread.value
assert Widget.paper_trail.enabled?
assert PaperTrail.enabled_for_model?(Widget)
end
end

View File

@ -1,68 +0,0 @@
require "pry"
ENV["RAILS_ENV"] = "test"
ENV["DB"] ||= "sqlite"
unless File.exist?(File.expand_path("../../test/dummy/config/database.yml", __FILE__))
warn "WARNING: No database.yml detected for the dummy app, please run `rake prepare` first"
end
def using_mysql?
@using_mysql ||= ActiveRecord::Base.connection_config[:adapter].to_sym == :mysql2
end
require File.expand_path("../dummy/config/environment.rb", __FILE__)
require "rails/test_help"
require "shoulda"
require "ffaker"
require "database_cleaner"
def active_record_gem_version
Gem::Version.new(ActiveRecord::VERSION::STRING)
end
if active_record_gem_version >= Gem::Version.new("5.0.0.beta1")
# See https://github.com/rails/rails-controller-testing/issues/5
ActionController::TestCase.send(:include, Rails::Controller::Testing::TestProcess)
end
Rails.backtrace_cleaner.remove_silencers!
# Run any available migration
ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
# Load support files
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
# DatabaseCleaner is apparently necessary for doing proper transactions within MySQL (ugh)
DatabaseCleaner.strategy = :truncation
# global setup block resetting Thread.current
module ActiveSupport
class TestCase
if using_mysql?
if respond_to? :use_transactional_tests=
self.use_transactional_tests = false
else
self.use_transactional_fixtures = false
end
setup { DatabaseCleaner.start }
end
teardown do
DatabaseCleaner.clean if using_mysql?
Thread.current[:paper_trail] = nil
end
end
end
# Wrap args in a hash to support the ActionController::TestCase and
# ActionDispatch::Integration HTTP request method switch to keyword args
# (see https://github.com/rails/rails/blob/master/actionpack/CHANGELOG.md)
def params_wrapper(args)
if defined?(::Rails) && active_record_gem_version >= Gem::Version.new("5.0.0.beta1")
{ params: args }
else
args
end
end

View File

@ -1,39 +0,0 @@
require "test_helper"
require_relative "../../../spec/support/custom_json_serializer"
class MixinJsonTest < ActiveSupport::TestCase
setup do
# Setup a hash with random values, ensuring some values are nil
@hash = {}
(1..4).each do |i|
@hash["key#{i}"] = [FFaker::Lorem.word, nil].sample
end
@hash["tkey"] = nil
@hash[""] = "foo"
@hash_as_json = @hash.to_json
end
context "`load` class method" do
should "exist" do
assert CustomJsonSerializer.respond_to?(:load)
end
should "`deserialize` JSON to Ruby, removing pairs with `blank` keys or values" do
assert_equal(
@hash.reject { |k, v| k.blank? || v.blank? },
CustomJsonSerializer.load(@hash_as_json)
)
end
end
context "`dump` class method" do
should "exist" do
assert CustomJsonSerializer.respond_to?(:dump)
end
should "`serialize` Ruby to JSON, removing pairs with `nil` values" do
assert_equal @hash.reject { |_k, v| v.nil? }.to_json,
CustomJsonSerializer.dump(@hash)
end
end
end