From f5a585b3a47c2b82504b474f5035bf769f0dfc3c Mon Sep 17 00:00:00 2001 From: seenmyfate Date: Sun, 16 Jun 2013 13:08:15 +0100 Subject: [PATCH] Add integration tests for deploy task This commit adds the outlines of a testing framework for Cap tasks. Currently just the `cap install` and `cap deploy` tasks are covered. For now, these tests can only be run if it is `ssh localhost` will work for you and are currently excluded from the suite. It is my intention to eventually replace the `sshkit` backend with a test backend, but for now this is good enough to prevent simple regressions. --- spec/integration/deploy_finalize_spec.rb | 34 +++++++++++ spec/integration/deploy_finished_spec.rb | 36 ++++++++++++ spec/integration/deploy_started_spec.rb | 74 ++++++++++++++++++++++++ spec/integration/deploy_update_spec.rb | 45 ++++++++++++++ spec/integration/dsl_spec.rb | 16 +++++ spec/integration/installation_spec.rb | 9 +-- spec/integration_spec_helper.rb | 7 +++ spec/spec_helper.rb | 2 + spec/support/matchers.rb | 5 ++ spec/support/test_app.rb | 66 ++++++++++++++++++++- 10 files changed, 286 insertions(+), 8 deletions(-) create mode 100644 spec/integration/deploy_finalize_spec.rb create mode 100644 spec/integration/deploy_finished_spec.rb create mode 100644 spec/integration/deploy_started_spec.rb create mode 100644 spec/integration/deploy_update_spec.rb create mode 100644 spec/integration_spec_helper.rb create mode 100644 spec/support/matchers.rb diff --git a/spec/integration/deploy_finalize_spec.rb b/spec/integration/deploy_finalize_spec.rb new file mode 100644 index 00000000..d241672e --- /dev/null +++ b/spec/integration/deploy_finalize_spec.rb @@ -0,0 +1,34 @@ +require 'integration_spec_helper' + +describe 'cap deploy:finished', slow: true do + before do + install_test_app_with(config) + end + + describe 'deploy' do + let(:config) { + %{ + set :stage, :#{stage} + set :deploy_to, '#{deploy_to}' + set :repo, 'git://github.com/capistrano/capistrano.git' + set :branch, 'v3' + server 'localhost', roles: %w{web app}, user: '#{current_user}' + set :linked_files, %w{config/database.yml} + set :linked_dirs, %w{bin log public/system vendor/bundle} + } + } + + describe 'log_revision' do + before do + cap 'deploy:started' + cap 'deploy:update' + cap 'deploy:finalize' + cap 'deploy:finished' + end + + it 'writes the log file' do + expect(deploy_to.join('revisions.log')).to be_a_file + end + end + end +end diff --git a/spec/integration/deploy_finished_spec.rb b/spec/integration/deploy_finished_spec.rb new file mode 100644 index 00000000..8169c57e --- /dev/null +++ b/spec/integration/deploy_finished_spec.rb @@ -0,0 +1,36 @@ +require 'integration_spec_helper' + +describe 'cap deploy:finished', slow: true do + before do + install_test_app_with(config) + end + + describe 'deploy' do + let(:config) { + %{ + set :stage, :#{stage} + set :deploy_to, '#{deploy_to}' + set :repo, 'git://github.com/capistrano/capistrano.git' + set :branch, 'v3' + server 'localhost', roles: %w{web app}, user: '#{current_user}' + set :linked_files, %w{config/database.yml} + set :linked_dirs, %w{bin log public/system vendor/bundle} + } + } + + describe 'symlink' do + before do + cap 'deploy:started' + cap 'deploy:update' + cap 'deploy:finalize' + end + + describe 'release' do + it 'symlinks the release to `current`' do + expect(File.symlink?(current_path)).to be_true + expect(File.readlink(current_path)).to match /\/tmp\/test_app\/deploy_to\/releases\/\d{14}/ + end + end + end + end +end diff --git a/spec/integration/deploy_started_spec.rb b/spec/integration/deploy_started_spec.rb new file mode 100644 index 00000000..84f29ec8 --- /dev/null +++ b/spec/integration/deploy_started_spec.rb @@ -0,0 +1,74 @@ +require 'integration_spec_helper' + +describe 'cap deploy:started', slow: true do + before do + install_test_app_with(config) + end + + describe 'deploy:check' do + let(:config) { + %{ + set :stage, :#{stage} + set :deploy_to, '#{deploy_to}' + set :repo, 'git://github.com/capistrano/capistrano.git' + set :branch, 'v3' + server 'localhost', roles: %w{web app}, user: '#{current_user}' + set :linked_files, %w{config/database.yml} + set :linked_dirs, %w{bin log public/system vendor/bundle} + } + } + + describe 'directories' do + before do + cap 'deploy:check:directories' + end + + it 'ensures the directory structure' do + expect(shared_path).to be_a_directory + expect(releases_path).to be_a_directory + end + end + + describe 'linked_dirs' do + before do + cap 'deploy:check:linked_dirs' + end + + it 'ensure directories to be linked in `shared`' do + [ + shared_path.join('bin'), + shared_path.join('log'), + shared_path.join('public/system'), + shared_path.join('vendor/bundle'), + ].each do |dir| + expect(dir).to be_a_directory + end + end + end + + describe 'linked_files' do + + subject { cap 'deploy:check:linked_files' } + + context 'file does not exist' do + it 'fails' do + expect(subject).to match 'config/database.yml does not exist' + end + end + + context 'file exists' do + before do + create_shared_directory('config') + create_shared_file('config/database.yml') + end + + it 'suceeds' do + expect(subject).not_to match 'config/database.yml does not exist' + expect(subject).to match 'successful' + end + + end + end + end +end + diff --git a/spec/integration/deploy_update_spec.rb b/spec/integration/deploy_update_spec.rb new file mode 100644 index 00000000..d847b8c4 --- /dev/null +++ b/spec/integration/deploy_update_spec.rb @@ -0,0 +1,45 @@ +require 'integration_spec_helper' + +describe 'cap deploy:update', slow: true do + before do + install_test_app_with(config) + end + + describe 'deploy' do + let(:config) { + %{ + set :stage, :#{stage} + set :deploy_to, '#{deploy_to}' + set :repo, 'git://github.com/capistrano/capistrano.git' + set :branch, 'v3' + server 'localhost', roles: %w{web app}, user: '#{current_user}' + set :linked_files, %w{config/database.yml} + set :linked_dirs, %w{bin log public/system vendor/bundle} + } + } + + describe 'symlink' do + before do + cap 'deploy:started' + create_shared_directory('config') + create_shared_file('config/database.yml') + cap 'deploy:symlink:shared' + end + + describe 'linked_dirs' do + it 'symlinks the directories in shared to `current`' do + %w{bin log public/system vendor/bundle}.each do |dir| + expect(release_path.join(dir)).to be_a_symlink_to shared_path.join(dir) + end + end + end + + describe 'linked_files' do + it 'symlinks the files in shared to `current`' do + file = 'config/database.yml' + expect(release_path.join(file)).to be_a_symlink_to shared_path.join(file) + end + end + end + end +end diff --git a/spec/integration/dsl_spec.rb b/spec/integration/dsl_spec.rb index ac0e71b1..89539c16 100644 --- a/spec/integration/dsl_spec.rb +++ b/spec/integration/dsl_spec.rb @@ -13,6 +13,14 @@ describe Capistrano::DSL do dsl.server 'example4.com', roles: %w{app}, primary: true end + describe 'fetching all servers' do + subject { dsl.roles(:all) } + + it 'returns all servers' do + expect(subject.map(&:hostname)).to eq %w{example1.com example2.com example3.com example4.com} + end + end + describe 'fetching servers by role' do subject { dsl.roles(:app) } @@ -64,6 +72,14 @@ describe Capistrano::DSL do dsl.role :app, %w{example4.com}, primary: true end + describe 'fetching all servers' do + subject { dsl.roles(:all) } + + it 'returns all servers' do + expect(subject.map(&:hostname)).to eq %w{example1.com example2.com example3.com example4.com} + end + end + describe 'fetching servers by role' do subject { dsl.roles(:app) } diff --git a/spec/integration/installation_spec.rb b/spec/integration/installation_spec.rb index 05d22d43..c5043d87 100644 --- a/spec/integration/installation_spec.rb +++ b/spec/integration/installation_spec.rb @@ -1,9 +1,6 @@ -require 'spec_helper' -require 'support/test_app' +require 'integration_spec_helper' -include TestApp - -describe 'cap install' do +describe 'cap install', slow: true do context 'with defaults' do before :all do @@ -65,7 +62,7 @@ describe 'cap install' do expect(File.exists?(file)).to be_true end - it 'creates the stage files' do + it 'creates the stage files specified, not the defaults' do qa = test_app_path.join('config/deploy/qa.rb') production = test_app_path.join('config/deploy/production.rb') staging = test_app_path.join('config/deploy/staging.rb') diff --git a/spec/integration_spec_helper.rb b/spec/integration_spec_helper.rb new file mode 100644 index 00000000..4fbaf2f5 --- /dev/null +++ b/spec/integration_spec_helper.rb @@ -0,0 +1,7 @@ +require 'spec_helper' +require 'support/test_app' +require 'support/matchers' + +include TestApp + + diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ba3300c7..5adacbfc 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -9,6 +9,8 @@ require 'mocha/api' Dir['#{File.dirname(__FILE__)}/support/**/*.rb'].each {|f| require f} RSpec.configure do |config| + config.treat_symbols_as_metadata_keys_with_true_values = true config.mock_framework = :mocha config.order = 'random' + config.filter_run_excluding :slow end diff --git a/spec/support/matchers.rb b/spec/support/matchers.rb new file mode 100644 index 00000000..4283c055 --- /dev/null +++ b/spec/support/matchers.rb @@ -0,0 +1,5 @@ +RSpec::Matchers.define :be_a_symlink_to do |expected| + match do |actual| + File.identical?(expected, actual) + end +end diff --git a/spec/support/test_app.rb b/spec/support/test_app.rb index 88c2aa56..1cbdea90 100644 --- a/spec/support/test_app.rb +++ b/spec/support/test_app.rb @@ -1,7 +1,10 @@ +require 'fileutils' module TestApp def create_test_app - FileUtils.rm_rf(test_app_path) - FileUtils.mkdir(test_app_path) + [test_app_path, deploy_to].each do |path| + FileUtils.rm_rf(path) + FileUtils.mkdir(path) + end File.open(gemfile, 'w+') do |file| file.write "gem 'capistrano', path: '#{path_to_cap}'" @@ -12,11 +15,66 @@ module TestApp end end + def install_test_app_with(config) + create_test_app + Dir.chdir(test_app_path) do + %x[bundle exec cap install STAGES=#{stage}] + end + write_local_deploy_file(config) + end + + def write_local_deploy_file(config) + File.open(test_stage_path, 'w') do |file| + file.write config + end + end + + def create_shared_directory(path) + FileUtils.mkdir_p(shared_path.join(path)) + end + + def create_shared_file(path) + File.open(shared_path.join(path), 'w') + end + + def cap(task) + Dir.chdir(test_app_path) do + %x[bundle exec cap #{stage} #{task}] + end + end + + def stage + 'test' + end + + def test_stage_path + test_app_path.join('config/deploy/test.rb') + end def test_app_path Pathname.new('/tmp/test_app') end + def deploy_to + Pathname.new('/tmp/test_app/deploy_to') + end + + def shared_path + deploy_to.join('shared') + end + + def current_path + deploy_to.join('current') + end + + def releases_path + deploy_to.join('releases') + end + + def release_path + releases_path.join(Dir.entries(releases_path).last) + end + def path_to_cap File.expand_path('.') end @@ -24,4 +82,8 @@ module TestApp def gemfile test_app_path.join('Gemfile') end + + def current_user + `whoami`.chomp + end end