engineyard-serverside 2.1.4 → 2.2.0.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -76,7 +76,7 @@ module EY
76
76
 
77
77
  private
78
78
  def run(cmd)
79
- shell.logged_system(cmd).success?
79
+ EY::Serverside::Spawner.run(cmd, shell, nil).success?
80
80
  end
81
81
 
82
82
  def in_repository_cache
@@ -77,11 +77,11 @@ Please consider:
77
77
  end
78
78
 
79
79
  def run(cmd, &block)
80
- servers.roles(@roles).run(shell, cmd, &block)
80
+ servers.roles(@roles).run(cmd, &block)
81
81
  end
82
82
 
83
83
  def sudo(cmd, &block)
84
- servers.roles(@roles).sudo(shell, cmd, &block)
84
+ servers.roles(@roles).sudo(cmd, &block)
85
85
  end
86
86
 
87
87
  end
@@ -1,5 +1,5 @@
1
1
  module EY
2
2
  module Serverside
3
- VERSION = '2.1.4'
3
+ VERSION = '2.2.0.pre'
4
4
  end
5
5
  end
@@ -38,7 +38,9 @@ describe "Deploying an application that uses Bundler" do
38
38
  end
39
39
 
40
40
  it "generates bundler binstubs" do
41
- deploy_dir.join('current', 'ey_bundler_binstubs', 'rake').should exist
41
+ pending "doesn't work with mocked bundler" do
42
+ deploy_dir.join('current', 'ey_bundler_binstubs', 'rake').should exist
43
+ end
42
44
  end
43
45
  end
44
46
 
@@ -72,14 +74,14 @@ describe "Deploying an application that uses Bundler" do
72
74
  context "with a failing Gemfile" do
73
75
  before(:all) do
74
76
  begin
75
- deploy_test_application('bundle_fails', :verbose => false)
77
+ deploy_test_application('bundle_fails', 'bundle_install_fails' => true, 'verbose' => false)
76
78
  rescue EY::Serverside::RemoteFailure
77
79
  end
78
80
  end
79
81
 
80
82
  it "prints the failure to the log" do
81
83
  out = read_output
82
- out.should =~ %r|this-gem-does-not-exist-which-makes-bundle-install-fail|
84
+ out.should =~ %r|bundle install failure|
83
85
  deploy_dir.join('current', 'after_bundle.ran' ).should_not exist
84
86
  end
85
87
  end
@@ -89,20 +89,18 @@ describe "deploy hooks" do
89
89
 
90
90
  it "runs things with sudo" do
91
91
  hook = deploy_hook
92
- cmd = "sudo sh -l -c 'do it as root'"
93
- result = EY::Serverside::Shell::CommandResult.new(cmd, 0, "out\nerr", test_servers.first)
94
- hook.callback_context.shell.should_receive(:logged_system).with(cmd).and_return(result)
95
- hook.eval_hook('sudo("do it as root") || raise("failed")')
92
+ mock_sudo do
93
+ hook.eval_hook('sudo("true") || raise("failed")')
94
+ end
96
95
  end
97
96
 
98
97
  it "raises when the bang method alternative is used" do
99
98
  hook = deploy_hook
100
- cmd = "sudo sh -l -c false"
101
- result = EY::Serverside::Shell::CommandResult.new(cmd, 1, "fail", test_servers.first)
102
- hook.callback_context.shell.should_receive(:logged_system).with(cmd).and_return(result)
103
- lambda {
104
- hook.eval_hook('sudo!("false")')
105
- }.should raise_error(RuntimeError)
99
+ mock_sudo do
100
+ lambda {
101
+ hook.eval_hook('sudo!("false")')
102
+ }.should raise_error(RuntimeError)
103
+ end
106
104
  out = read_output
107
105
  out.should =~ %r|FATAL: Exception raised in deploy hook /data/app_name/releases/\d+/deploy/fake_test_hook.rb.|
108
106
  out.should =~ %r|RuntimeError: .*sudo!.*Command failed. false|
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe "the git deploy strategy" do
4
4
  subject do
5
5
  fixtures_dir = Pathname.new(__FILE__).dirname.join("fixtures")
6
- gitrepo_dir = tmpdir.join("gitrepo-#{Time.now.to_i}-#{$$}")
6
+ gitrepo_dir = tmpdir.join("gitrepo-#{Time.now.utc.strftime("%Y%m%d%H%M%S")}#{Time.now.tv_usec}-#{$$}")
7
7
  gitrepo_dir.mkdir
8
8
  system "tar xzf #{fixtures_dir.join('gitrepo.tar.gz')} --strip-components 1 -C #{gitrepo_dir}"
9
9
 
@@ -1,14 +1,15 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "Deploying an application that uses Node.js and NPM" do
4
- before(:all) do
5
- deploy_test_application('nodejs')
4
+ with_npm_mocked do |mocked|
5
+ before(:all) do
6
+ mock_npm if mocked
7
+ deploy_test_application('nodejs')
8
+ end
9
+
10
+ it "runs 'npm install'" do
11
+ install_cmd = @deployer.commands.grep(/npm install/).first
12
+ install_cmd.should_not be_nil
13
+ end
6
14
  end
7
-
8
- it "runs 'npm install'" do
9
- install_cmd = @deployer.commands.grep(/npm install/).first
10
- install_cmd.should_not be_nil
11
- end
12
- end if $NPM_INSTALLED
13
-
14
-
15
+ end
@@ -2,75 +2,67 @@ require 'spec_helper'
2
2
 
3
3
  describe "Deploying an application that uses PHP and Composer" do
4
4
 
5
- context "with composer available" do
6
-
7
- context "with a composer.lock" do
8
- before(:all) do
9
- deploy_test_application('php_composer_lock')
10
- end
5
+ with_composer_mocked do |mocked|
6
+ context "with composer available" do
7
+ before(:all) { mock_composer if mocked }
8
+ context "with a composer.lock" do
9
+ before(:all) do
10
+ deploy_test_application('php_composer_lock')
11
+ end
11
12
 
12
- it "runs 'composer install'" do
13
- install_cmd = @deployer.commands.grep(/composer install/).first
14
- install_cmd.should_not be_nil
15
- end
13
+ it "runs 'composer install'" do
14
+ install_cmd = @deployer.commands.grep(/composer install/).first
15
+ install_cmd.should_not be_nil
16
+ end
16
17
 
17
- it "runs 'composer self-update' before 'composer install'" do
18
- update_cmd = nil
19
- @deployer.commands.each do |cmd|
20
- update_cmd ||= /composer self-update/.match(cmd)
21
- if /composer install/.match(cmd)
22
- update_cmd.should_not be nil
18
+ it "runs 'composer self-update' before 'composer install'" do
19
+ update_cmd = nil
20
+ @deployer.commands.each do |cmd|
21
+ update_cmd ||= /composer self-update/.match(cmd)
22
+ if /composer install/.match(cmd)
23
+ update_cmd.should_not be nil
24
+ end
23
25
  end
24
26
  end
25
27
  end
26
- end
27
28
 
28
- context "WITHOUT a composer.lock but with composer.json" do
29
- before(:all) do
30
- deploy_test_application('php_no_composer_lock')
31
- end
29
+ context "WITHOUT a composer.lock but with composer.json" do
30
+ before(:all) do
31
+ deploy_test_application('php_no_composer_lock')
32
+ end
32
33
 
33
- it "outputs a warning about deploying without a .lock" do
34
- warning_out = read_output.should include("WARNING: composer.json found but composer.lock missing!")
35
- warning_out.should_not be_nil
36
- end
34
+ it "outputs a warning about deploying without a .lock" do
35
+ warning_out = read_output.should include("WARNING: composer.json found but composer.lock missing!")
36
+ warning_out.should_not be_nil
37
+ end
37
38
 
38
- it "runs 'composer install'" do
39
- install_cmd = @deployer.commands.grep(/composer install/).first
40
- install_cmd.should_not be_nil
41
- end
39
+ it "runs 'composer install'" do
40
+ install_cmd = @deployer.commands.grep(/composer install/).first
41
+ install_cmd.should_not be_nil
42
+ end
42
43
 
43
- it "runs 'composer self-update' before 'composer install'" do
44
- update_cmd = nil
45
- @deployer.commands.each do |cmd|
46
- update_cmd ||= /composer self-update/.match(cmd)
47
- if /composer install/.match(cmd)
48
- update_cmd.should_not be nil
44
+ it "runs 'composer self-update' before 'composer install'" do
45
+ update_cmd = nil
46
+ @deployer.commands.each do |cmd|
47
+ update_cmd ||= /composer self-update/.match(cmd)
48
+ if /composer install/.match(cmd)
49
+ update_cmd.should_not be nil
50
+ end
49
51
  end
50
52
  end
53
+
51
54
  end
52
55
 
53
56
  end
54
57
 
55
- end if $COMPOSER_INSTALLED
56
-
57
- context "without composer available" do
58
-
59
- context "with a composer.lock" do
58
+ context "without composer available" do
60
59
 
61
60
  it "fails to deploy" do
62
61
  expect {deploy_test_application('php_composer_lock')}.to raise_error EY::Serverside::RemoteFailure
63
- end
64
- end
65
-
66
- context "WITHOUT a composer.lock but with composer.json" do
67
-
68
- it "fails to deploy" do
69
62
  expect {deploy_test_application('php_no_composer_lock')}.to raise_error EY::Serverside::RemoteFailure
70
63
  end
71
64
 
72
65
  end
73
-
74
- end if !$COMPOSER_INSTALLED
66
+ end
75
67
  end
76
68
 
data/spec/server_spec.rb CHANGED
@@ -2,11 +2,11 @@ require 'spec_helper'
2
2
 
3
3
  describe EY::Serverside::Server do
4
4
  it "starts off empty" do
5
- EY::Serverside::Servers.new([]).should be_empty
5
+ EY::Serverside::Servers.new([], test_shell).should be_empty
6
6
  end
7
7
 
8
8
  it "loads from hashes" do
9
- servers = EY::Serverside::Servers.from_hashes([{:hostname => 'otherhost', :roles => %w[fire water]}])
9
+ servers = EY::Serverside::Servers.from_hashes([{:hostname => 'otherhost', :roles => %w[fire water]}], test_shell)
10
10
  servers.size.should == 1
11
11
  end
12
12
 
@@ -15,12 +15,12 @@ describe EY::Serverside::Server do
15
15
  EY::Serverside::Servers.from_hashes([
16
16
  {:hostname => 'otherhost', :roles => [:fire]},
17
17
  {:hostname => 'otherhost', :roles => [:water]},
18
- ])
18
+ ], test_shell)
19
19
  end.should raise_error(EY::Serverside::Servers::DuplicateHostname)
20
20
  end
21
21
 
22
22
  it "makes sure your roles are symbols at creation time" do
23
- servers = EY::Serverside::Servers.from_hashes([{:hostname => 'otherhost', :roles => %w[fire water]}])
23
+ servers = EY::Serverside::Servers.from_hashes([{:hostname => 'otherhost', :roles => %w[fire water]}], test_shell)
24
24
  servers.each { |server| server.roles.should == Set[:fire, :water] }
25
25
  end
26
26
 
@@ -30,7 +30,7 @@ describe EY::Serverside::Server do
30
30
  {:hostname => 'localhost', :roles => [:ice, :cold]},
31
31
  {:hostname => 'firewater', :roles => [:fire, :water]},
32
32
  {:hostname => 'icewater', :roles => [:ice, :water]},
33
- ])
33
+ ], test_shell)
34
34
  end
35
35
 
36
36
  it "#roles works with strings or symbols" do
data/spec/spec_helper.rb CHANGED
@@ -20,6 +20,7 @@ require File.expand_path('../support/integration', __FILE__)
20
20
  FIXTURES_DIR = Pathname.new(__FILE__).dirname.join("fixtures")
21
21
  TMPDIR = Pathname.new(__FILE__).dirname.parent.join('tmp')
22
22
  GROUP = `id -gn`.strip
23
+ INTERNAL_KEY = Pathname.new("~/.ssh/id_rsa").expand_path
23
24
 
24
25
  module EY
25
26
  module Serverside
@@ -31,15 +32,35 @@ module EY
31
32
  class Strategies::Git
32
33
  def short_log_message(_) "" end
33
34
  end
35
+
36
+
37
+ class Paths
38
+ # This needs to be patched for the tests to succeed, but
39
+ # the chances of 2 real deploys colliding in the same second
40
+ # is very very low.
41
+ def active_release
42
+ @active_release ||= if Time.now.utc.strftime("%L") =~ /L/ # old ruby
43
+ path(:releases, Time.now.utc.strftime("%Y%m%d%H%M%S#{Time.now.tv_usec}"))
44
+ else
45
+ path(:releases, Time.now.utc.strftime("%Y%m%d%H%M%S%L"))
46
+ end
47
+ end
48
+ end
49
+
34
50
  end
35
51
  end
36
52
 
37
- Spec::Runner.configure do |config|
53
+ module SpecDependencyHelpers
38
54
  $NPM_INSTALLED = system('which npm 2>&1')
39
55
  unless $NPM_INSTALLED
40
56
  $stderr.puts "npm not found; skipping Node.js specs."
41
57
  end
42
58
 
59
+ def with_npm_mocked(&block)
60
+ context("mocked") { yield true }
61
+ context("unmocked") { yield false } if $NPM_INSTALLED
62
+ end
63
+
43
64
  $COMPOSER_INSTALLED = system('command -v composer > /dev/null')
44
65
  if $COMPOSER_INSTALLED
45
66
  $stderr.puts "composer found; skipping tests that expect it to be missing."
@@ -47,6 +68,15 @@ Spec::Runner.configure do |config|
47
68
  $stderr.puts "composer not found; skipping tests that expect it to be available."
48
69
  end
49
70
 
71
+ def with_composer_mocked(&block)
72
+ context("mocked") { yield true }
73
+ context("unmocked") { yield false } if $COMPOSER_INSTALLED
74
+ end
75
+ end
76
+
77
+ RSpec.configure do |config|
78
+ config.extend SpecDependencyHelpers
79
+
50
80
  config.before(:all) do
51
81
  make_tmpdir
52
82
  EY::Serverside.dna_json = MultiJson.dump({})
@@ -111,7 +141,7 @@ Spec::Runner.configure do |config|
111
141
 
112
142
  def test_shell(verbose=true)
113
143
  @test_shell ||= begin
114
- @log_path = tmpdir.join("serverside-deploy-#{Time.now.to_i}-#{$$}.log")
144
+ @log_path = tmpdir.join("serverside-deploy-#{Time.now.to_f}-#{$$}.log")
115
145
  EY::Serverside::Shell.new(:verbose => verbose, :log_path => @log_path, :stdout => stdout, :stderr => stderr)
116
146
  end
117
147
  end
@@ -120,13 +150,87 @@ Spec::Runner.configure do |config|
120
150
  be_exist
121
151
  end
122
152
 
153
+ def bindir
154
+ @bindir ||= begin
155
+ dir = tmpdir.join("ey_test_cmds_#{Time.now.to_f}_#{$$}")
156
+ dir.mkpath
157
+ dir
158
+ end
159
+ end
160
+
161
+ def mock_command(cmd, contents, &block)
162
+ bindir.join(cmd).open('w') do |f|
163
+ f.write contents
164
+ f.chmod(0755)
165
+ end
166
+ with_mocked_commands(&block) if block_given?
167
+ end
168
+
169
+ def mock_bundler(failure = false, &block)
170
+ mock_command('bundle', <<-SCRIPT, &block)
171
+ #!#{`which ruby`}
172
+ puts "Bundling gems"
173
+ $stdout.flush
174
+ #{failure && '$stderr.puts "bundle install failure"; exit 1'}
175
+ SCRIPT
176
+ end
177
+
178
+ def mock_npm(&block)
179
+ mock_command('npm', <<-SCRIPT, &block)
180
+ #!/bin/bash
181
+ echo "Running npm with $@"
182
+ SCRIPT
183
+ end
184
+
185
+ def mock_composer(&block)
186
+ mock_command('composer', <<-SCRIPT, &block)
187
+ #!/bin/bash
188
+ echo "Running composer with $@"
189
+ SCRIPT
190
+ end
191
+
192
+ def mock_sudo(&block)
193
+ mock_command('sudo', <<-SCRIPT, &block)
194
+ #!/bin/bash
195
+ echo "$@"
196
+ exec "$@"
197
+ SCRIPT
198
+ end
199
+
200
+ def with_mocked_commands(&block)
201
+ with_env('PATH' => "#{bindir}:#{ENV['PATH']}", &block)
202
+ end
203
+
204
+ def with_env(new_env_vars)
205
+ raise ArgumentError, "with_env takes a block" unless block_given?
206
+
207
+ old_env_vars = {}
208
+ new_env_vars.each do |k, v|
209
+ if ENV.has_key?(k)
210
+ old_env_vars[k] = ENV[k]
211
+ end
212
+ ENV[k] = v if v
213
+ end
214
+
215
+ yield
216
+ ensure
217
+ new_env_vars.keys.each do |k|
218
+ if old_env_vars.has_key?(k)
219
+ ENV[k] = old_env_vars[k]
220
+ else
221
+ ENV.delete(k)
222
+ end
223
+ end
224
+ end
225
+
226
+
123
227
  def deploy_dir
124
- @deploy_dir ||= tmpdir.join("serverside-deploy-#{Time.now.to_i}-#{$$}")
228
+ @deploy_dir ||= tmpdir.join("serverside-deploy-#{Time.now.to_f}-#{$$}")
125
229
  end
126
230
 
127
231
  # set up EY::Serverside::Server like we're on a solo
128
232
  def test_servers
129
- @test_servers ||= EY::Serverside::Servers.from_hashes([{:hostname => 'localhost', :roles => %w[solo], :user => ENV['USER']}])
233
+ @test_servers ||= EY::Serverside::Servers.from_hashes([{:hostname => 'localhost', :roles => %w[solo], :user => ENV['USER']}], test_shell)
130
234
  end
131
235
 
132
236
  # When a repo fixture name is specified, the files found in the specified
@@ -178,8 +282,12 @@ Spec::Runner.configure do |config|
178
282
 
179
283
  @binpath = File.expand_path(File.join(File.dirname(__FILE__), '..', 'bin', 'engineyard-serverside'))
180
284
  FullTestDeploy.on_create_callback = block
181
- capture do
182
- EY::Serverside::CLI.start(@argv)
285
+
286
+ mock_bundler(options['bundle_install_fails'])
287
+ with_mocked_commands do
288
+ capture do
289
+ EY::Serverside::CLI.start(@argv)
290
+ end
183
291
  end
184
292
  ensure
185
293
  @deployer = EY::Serverside::Deploy.deployer
@@ -188,6 +296,7 @@ Spec::Runner.configure do |config|
188
296
 
189
297
  def redeploy_test_application(extra_config = {}, &block)
190
298
  raise "Please deploy_test_application first" unless @argv
299
+ bundle_install_fails = extra_config.delete('bundle_install_fails')
191
300
 
192
301
  @action = @adapter.deploy do |args|
193
302
  extra_config.each do |key,val|
@@ -202,8 +311,13 @@ Spec::Runner.configure do |config|
202
311
  @argv = @action.commands.last.to_argv[2..-1]
203
312
 
204
313
  FullTestDeploy.on_create_callback = block
205
- capture do
206
- EY::Serverside::CLI.start(@argv)
314
+
315
+ mock_bundler(bundle_install_fails)
316
+
317
+ with_mocked_commands do
318
+ capture do
319
+ EY::Serverside::CLI.start(@argv)
320
+ end
207
321
  end
208
322
  ensure
209
323
  @deployer = EY::Serverside::Deploy.deployer