engineyard 1.4.0 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -16,6 +16,6 @@ describe "ey web disable" do
16
16
  @ssh_commands.should have_command_like(/engineyard-serverside.*deploy enable_maintenance_page.*--app #{scenario[:application]}/)
17
17
  end
18
18
 
19
- it_should_behave_like "it takes an environment name and an app name and an account name"
20
- it_should_behave_like "it invokes engineyard-serverside"
19
+ include_examples "it takes an environment name and an app name and an account name"
20
+ include_examples "it invokes engineyard-serverside"
21
21
  end
@@ -16,8 +16,8 @@ describe "ey web enable" do
16
16
  @ssh_commands.should have_command_like(/engineyard-serverside.*deploy disable_maintenance_page.*--app #{scenario[:application]}/)
17
17
  end
18
18
 
19
- it_should_behave_like "it takes an environment name and an app name and an account name"
20
- it_should_behave_like "it invokes engineyard-serverside"
19
+ include_examples "it takes an environment name and an app name and an account name"
20
+ include_examples "it invokes engineyard-serverside"
21
21
 
22
22
  it "fails when given a bad option" do
23
23
  ey %w[web enable --lots --of --bogus --options], :expect_failure => true
data/spec/spec_helper.rb CHANGED
@@ -35,18 +35,20 @@ require 'engineyard'
35
35
  EY::Error
36
36
 
37
37
  # Spec stuff
38
- require 'spec/autorun'
38
+ require 'rspec'
39
39
  require 'tmpdir'
40
40
  require 'yaml'
41
41
  require 'pp'
42
42
  support = Dir[File.join(EY_ROOT,'/spec/support/*.rb')]
43
43
  support.each{|helper| require helper }
44
44
 
45
- Spec::Runner.configure do |config|
46
- config.include Spec::Helpers
47
- config.include Spec::GitRepo
48
- config.extend Spec::Helpers::SemanticNames
49
- config.extend Spec::Helpers::Fixtures
45
+ RSpec.configure do |config|
46
+ config.include SpecHelpers
47
+ config.include SpecHelpers::IntegrationHelpers
48
+
49
+ config.extend SpecHelpers::GitRepoHelpers
50
+ config.extend SpecHelpers::Given
51
+ config.extend SpecHelpers::Fixtures
50
52
 
51
53
  config.before(:all) do
52
54
  FakeWeb.allow_net_connect = false
@@ -62,21 +64,6 @@ Spec::Runner.configure do |config|
62
64
  end
63
65
  end
64
66
 
65
- Spec::Matchers.define :have_command_like do |regex|
66
- match do |command_list|
67
- @found = command_list.find{|c| c =~ regex }
68
- !!@found
69
- end
70
-
71
- failure_message_for_should do |command_list|
72
- "Didn't find a command matching #{regex} in commands:\n\n" + command_list.join("\n\n")
73
- end
74
-
75
- failure_message_for_should_not do |command_list|
76
- "Found unwanted command:\n\n#{@found}\n\n(matches regex #{regex})"
77
- end
78
- end
79
-
80
67
  EY.define_git_repo("default") do |git_dir|
81
68
  system("echo 'source :gemcutter' > Gemfile")
82
69
  system("git add Gemfile")
@@ -111,11 +98,3 @@ shared_examples_for "integration" do
111
98
  File.open(ENV['EYRC'], "w"){|f| YAML.dump(token, f) }
112
99
  end
113
100
  end
114
-
115
- shared_examples_for "it has an api" do
116
- before(:all) do
117
- @api = EY::API.new('asdf')
118
- end
119
- end
120
-
121
-
@@ -0,0 +1,51 @@
1
+ module EY
2
+ class << self
3
+ def fake_awsm
4
+ @fake_awsm ||= load_fake_awsm
5
+ end
6
+ alias_method :start_fake_awsm, :fake_awsm
7
+
8
+ def define_git_repo(name, &setup)
9
+ git_repo_setup[name] ||= setup
10
+ end
11
+
12
+ def refresh_git_repo(name)
13
+ git_repo_dir_cache.delete name
14
+ end
15
+
16
+ def git_repo_dir(name)
17
+ return git_repo_dir_cache[name] if git_repo_dir_cache.has_key?(name)
18
+ raise ArgumentError, "No definition for git repo #{name}" unless git_repo_setup[name]
19
+
20
+ git_dir = Pathname.new("/tmp/engineyard_test_repo_#{Time.now.tv_sec}_#{Time.now.tv_usec}_#{$$}")
21
+ git_dir.mkdir
22
+ Dir.chdir(git_dir) do
23
+ system("git init -q")
24
+ system('git config user.email ey@spec.test')
25
+ system('git config user.name "EY Specs"')
26
+ system("git remote add testremote user@git.host:path/to/repo.git")
27
+ git_repo_setup[name].call(git_dir)
28
+ end
29
+ git_repo_dir_cache[name] = git_dir
30
+ end
31
+
32
+ protected
33
+
34
+ def load_fake_awsm
35
+ config_ru = File.join(EY_ROOT, "spec/support/fake_awsm.ru")
36
+ unless system("ruby -c '#{config_ru}' > /dev/null")
37
+ raise SyntaxError, "There is a syntax error in fake_awsm.ru! fix it!"
38
+ end
39
+ @server = RealWeb.start_server_in_fork(config_ru)
40
+ "http://localhost:#{@server.port}"
41
+ end
42
+
43
+ def git_repo_setup
44
+ @git_repo_setup ||= {}
45
+ end
46
+
47
+ def git_repo_dir_cache
48
+ @git_repo_dir_cache ||= {}
49
+ end
50
+ end
51
+ end
@@ -5,241 +5,228 @@ require 'rest_client'
5
5
  require 'open4'
6
6
  require 'stringio'
7
7
 
8
- module Spec
9
- module Helpers
10
- class UnexpectedExit < StandardError
11
- def initialize(stdout, stderr)
12
- @stdout, @stderr = stdout, stderr
13
- end
14
-
15
- def message
16
- "Exited with an unexpected exit code\n---STDOUT---\n#{@stdout}\n---STDERR---\n#{@stderr}\n"
17
- end
8
+ module SpecHelpers
9
+ module Given
10
+ def given(name)
11
+ include_examples name
18
12
  end
19
- NonzeroExitStatus = Class.new(UnexpectedExit)
20
- ZeroExitStatus = Class.new(UnexpectedExit)
13
+ end
21
14
 
22
- def fast_ey(args)
23
- err, out = StringIO.new, StringIO.new
24
- capture_stderr_into(err) do
25
- capture_stdout_into(out) do
26
- with_env('DEBUG' => 'true') do
27
- EY::CLI.start(args)
28
- end
29
- end
30
- end
31
- ensure
32
- @err, @out = err.string, out.string
33
- @raw_ssh_commands, @ssh_commands = extract_ssh_commands(@out)
15
+ module Fixtures
16
+ def fixture_recipes_tgz
17
+ File.expand_path('../fixture_recipes.tgz', __FILE__)
34
18
  end
35
19
 
36
- def fast_failing_ey(*args)
37
- begin
38
- fast_ey(*args)
39
- raise ZeroExitStatus.new(@out, @err)
40
- rescue SystemExit => exit_status
41
- # SystemExit typically indicates a bogus command, which we
42
- # here in expected-to-fail land are entirely happy with.
43
- nil
44
- rescue EY::Error => e
45
- more_err, more_out = StringIO.new, StringIO.new
46
-
47
- capture_stderr_into(more_err) do
48
- capture_stdout_into(more_out) do
49
- EY.ui.print_exception(e)
50
- end
51
- end
20
+ def link_recipes_tgz(git_dir)
21
+ system("ln -s #{fixture_recipes_tgz} #{git_dir.join('recipes.tgz')}")
22
+ end
23
+ end
52
24
 
53
- @err << more_err.string
54
- @out << more_out.string
25
+ module IntegrationHelpers
26
+ def run_ey(command_options, ey_options={})
27
+ if respond_to?(:extra_ey_options) # needed for ssh tests
28
+ ey_options.merge!(extra_ey_options)
55
29
  end
56
- end
57
30
 
58
- def capture_stderr_into(stream)
59
- $stderr = stream
60
- yield
61
- ensure
62
- $stderr = STDERR
31
+ ey(command_to_run(command_options), ey_options)
63
32
  end
64
33
 
65
- def capture_stdout_into(stream)
66
- $stdout = stream
67
- yield
68
- ensure
69
- $stdout = STDOUT
34
+ def make_scenario(hash)
35
+ # since nil will silently turn to empty string when interpolated,
36
+ # and there's a lot of string matching involved in integration
37
+ # testing, it would be nice to have early notification of typos.
38
+ scenario = Hash.new { |h,k| raise "Tried to get key #{k.inspect}, but it's missing!" }
39
+ scenario.merge!(hash)
70
40
  end
41
+ end
71
42
 
72
- def ey(args = [], options = {}, &block)
73
- hide_err = options.has_key?(:hide_err) ? options[:hide_err] : options[:expect_failure]
74
- path_prepends = options[:prepend_to_path]
75
-
76
- ey_env = {'DEBUG' => 'true'}
77
- if options.has_key?(:debug)
78
- ey_env['DEBUG'] = options[:debug] ? "true" : nil
79
- end
43
+ module GitRepoHelpers
44
+ def define_git_repo(name, &setup)
45
+ # EY's ivars don't get cleared between examples, so we can keep
46
+ # a git repo around longer (and thus make our tests faster)
47
+ FakeFS.without { EY.define_git_repo(name, &setup) }
48
+ end
80
49
 
81
- if path_prepends
82
- tempdir = File.join(Dir.tmpdir, "ey_test_cmds_#{Time.now.tv_sec}#{Time.now.tv_usec}_#{$$}")
83
- Dir.mkdir(tempdir)
84
- path_prepends.each do |name, contents|
85
- File.open(File.join(tempdir, name), 'w') do |f|
86
- f.write(contents)
87
- f.chmod(0755)
88
- end
50
+ def use_git_repo(repo_name)
51
+ before(:all) do
52
+ FakeFS.without do
53
+ @_original_wd ||= []
54
+ @_original_wd << Dir.getwd
55
+ Dir.chdir(EY.git_repo_dir(repo_name))
89
56
  end
57
+ end
90
58
 
91
- ey_env['PATH'] = tempdir + ':' + ENV['PATH']
59
+ after(:all) do
60
+ FakeFS.without { Dir.chdir(@_original_wd.pop) }
92
61
  end
62
+ end
63
+ end
93
64
 
94
- eybin = File.expand_path('../bundled_ey', __FILE__)
65
+ class UnexpectedExit < StandardError
66
+ def initialize(stdout, stderr)
67
+ super "Exited with an unexpected exit code\n---STDOUT---\n#{stdout}\n---STDERR---\n#{stderr}\n"
68
+ end
69
+ end
70
+ NonzeroExitStatus = Class.new(UnexpectedExit)
71
+ ZeroExitStatus = Class.new(UnexpectedExit)
95
72
 
96
- with_env(ey_env) do
97
- exit_status = Open4::open4("#{eybin} #{Escape.shell_command(args)}") do |pid, stdin, stdout, stderr|
98
- block.call(stdin) if block
99
- @out = stdout.read
100
- @err = stderr.read
101
- end
73
+ def ey_api
74
+ @api ||= EY::API.new('asdf')
75
+ end
102
76
 
103
- if !exit_status.success? && !options[:expect_failure]
104
- raise NonzeroExitStatus.new(@out, @err)
105
- elsif exit_status.success? && options[:expect_failure]
106
- raise ZeroExitStatus.new(@out, @err)
77
+ def fast_ey(args)
78
+ err, out = StringIO.new, StringIO.new
79
+ capture_stderr_into(err) do
80
+ capture_stdout_into(out) do
81
+ with_env('DEBUG' => 'true') do
82
+ EY::CLI.start(args)
107
83
  end
108
84
  end
109
-
110
- @raw_ssh_commands, @ssh_commands = extract_ssh_commands(@out)
111
-
112
- puts @err unless @err.empty? || hide_err
113
- @out
114
85
  end
86
+ ensure
87
+ @err, @out = err.string, out.string
88
+ @raw_ssh_commands, @ssh_commands = extract_ssh_commands(@out)
89
+ end
115
90
 
116
- def extract_ssh_commands(output)
117
- raw_ssh_commands = @out.split(/\n/).find_all do |line|
118
- line =~ /^bash -lc/ || line =~ /^ssh/
119
- end
120
-
121
- ssh_commands = raw_ssh_commands.map do |cmd|
122
- # Strip off everything up to and including user@host, leaving
123
- # just the command that the remote system would run
124
- #
125
- # XXX: this is a really icky icky.
126
- # engineyard gem was written as if shelling out to run serverside
127
- # and running an ssh command will always be the same. This is a nasty
128
- # hack to get it working with Net::SSH for now so we can repair 1.9.2.
129
- ssh_prefix_removed = cmd.gsub(/^bash -lc /, '').gsub(/^ssh .*?\w+@\S*\s*/, '')
130
-
131
- # Its arguments have been double-escaped: one layer is to get
132
- # them through our local shell and into ssh, and the other
133
- # layer is to get them through the remote system's shell.
134
- #
135
- # Strip off one layer by running it through the shell.
136
- just_the_remote_command = ssh_prefix_removed.gsub(/>\s*\/dev\/null.*$/, '')
137
- `echo #{just_the_remote_command}`.strip
91
+ def fast_failing_ey(*args)
92
+ begin
93
+ fast_ey(*args)
94
+ raise ZeroExitStatus.new(@out, @err)
95
+ rescue SystemExit => exit_status
96
+ # SystemExit typically indicates a bogus command, which we
97
+ # here in expected-to-fail land are entirely happy with.
98
+ nil
99
+ rescue EY::Error => e
100
+ more_err, more_out = StringIO.new, StringIO.new
101
+
102
+ capture_stderr_into(more_err) do
103
+ capture_stdout_into(more_out) do
104
+ EY.ui.print_exception(e)
105
+ end
138
106
  end
139
107
 
140
- [raw_ssh_commands, ssh_commands]
108
+ @err << more_err.string
109
+ @out << more_out.string
141
110
  end
111
+ end
142
112
 
143
- def api_scenario(scenario, remote = "user@git.host:path/to/repo.git")
144
- response = ::RestClient.put(EY.fake_awsm + '/scenario', {"scenario" => scenario, "remote" => remote}, {})
145
- raise "Setting scenario failed: #{response.inspect}" unless response.code == 200
146
- end
113
+ def capture_stderr_into(stream)
114
+ $stderr = stream
115
+ yield
116
+ ensure
117
+ $stderr = STDERR
118
+ end
147
119
 
148
- def read_yaml(file="ey.yml")
149
- YAML.load_file(File.expand_path(file))
150
- end
120
+ def capture_stdout_into(stream)
121
+ $stdout = stream
122
+ yield
123
+ ensure
124
+ $stdout = STDOUT
125
+ end
126
+
127
+ def ey(args = [], options = {}, &block)
128
+ hide_err = options.has_key?(:hide_err) ? options[:hide_err] : options[:expect_failure]
129
+ path_prepends = options[:prepend_to_path]
151
130
 
152
- def write_yaml(data, file = "ey.yml")
153
- File.open(file, "w"){|f| YAML.dump(data, f) }
131
+ ey_env = {'DEBUG' => 'true'}
132
+ if options.has_key?(:debug)
133
+ ey_env['DEBUG'] = options[:debug] ? "true" : nil
154
134
  end
155
135
 
156
- def with_env(new_env_vars)
157
- raise ArgumentError, "with_env takes a block" unless block_given?
158
- old_env_vars = {}
159
- new_env_vars.each do |k, v|
160
- if ENV.has_key?(k)
161
- old_env_vars[k] = ENV[k]
136
+ if path_prepends
137
+ tempdir = File.join(Dir.tmpdir, "ey_test_cmds_#{Time.now.tv_sec}#{Time.now.tv_usec}_#{$$}")
138
+ Dir.mkdir(tempdir)
139
+ path_prepends.each do |name, contents|
140
+ File.open(File.join(tempdir, name), 'w') do |f|
141
+ f.write(contents)
142
+ f.chmod(0755)
162
143
  end
163
- ENV[k] = v
164
144
  end
165
145
 
166
- retval = yield
146
+ ey_env['PATH'] = tempdir + ':' + ENV['PATH']
147
+ end
167
148
 
168
- new_env_vars.keys.each do |k|
169
- if old_env_vars.has_key?(k)
170
- ENV[k] = old_env_vars[k]
171
- else
172
- ENV.delete(k)
173
- end
149
+ eybin = File.expand_path('../bundled_ey', __FILE__)
150
+
151
+ with_env(ey_env) do
152
+ exit_status = Open4::open4("#{eybin} #{Escape.shell_command(args)}") do |pid, stdin, stdout, stderr|
153
+ block.call(stdin) if block
154
+ @out = stdout.read
155
+ @err = stderr.read
156
+ end
157
+
158
+ if !exit_status.success? && !options[:expect_failure]
159
+ raise NonzeroExitStatus.new(@out, @err)
160
+ elsif exit_status.success? && options[:expect_failure]
161
+ raise ZeroExitStatus.new(@out, @err)
174
162
  end
175
- retval
176
163
  end
177
164
 
165
+ @raw_ssh_commands, @ssh_commands = extract_ssh_commands(@out)
166
+
167
+ puts @err unless @err.empty? || hide_err
168
+ @out
178
169
  end
179
- end
180
170
 
181
- module Spec
182
- module Helpers
183
- module SemanticNames
171
+ def extract_ssh_commands(output)
172
+ raw_ssh_commands = @out.split(/\n/).find_all do |line|
173
+ line =~ /^bash -lc/ || line =~ /^ssh/
174
+ end
184
175
 
185
- def given(name)
186
- it_should_behave_like name
187
- end
176
+ ssh_commands = raw_ssh_commands.map do |cmd|
177
+ # Strip off everything up to and including user@host, leaving
178
+ # just the command that the remote system would run
179
+ #
180
+ # XXX: this is a really icky icky.
181
+ # engineyard gem was written as if shelling out to run serverside
182
+ # and running an ssh command will always be the same. This is a nasty
183
+ # hack to get it working with Net::SSH for now so we can repair 1.9.2.
184
+ ssh_prefix_removed = cmd.gsub(/^bash -lc /, '').gsub(/^ssh .*?\w+@\S*\s*/, '')
188
185
 
186
+ # Its arguments have been double-escaped: one layer is to get
187
+ # them through our local shell and into ssh, and the other
188
+ # layer is to get them through the remote system's shell.
189
+ #
190
+ # Strip off one layer by running it through the shell.
191
+ just_the_remote_command = ssh_prefix_removed.gsub(/>\s*\/dev\/null.*$/, '')
192
+ `echo #{just_the_remote_command}`.strip
189
193
  end
190
194
 
191
- module Fixtures
192
- def fixture_recipes_tgz
193
- File.expand_path('../fixture_recipes.tgz', __FILE__)
194
- end
195
+ [raw_ssh_commands, ssh_commands]
196
+ end
195
197
 
196
- def link_recipes_tgz(git_dir)
197
- system("ln -s #{fixture_recipes_tgz} #{git_dir.join('recipes.tgz')}")
198
- end
199
- end
198
+ def api_scenario(scenario, remote = "user@git.host:path/to/repo.git")
199
+ response = ::RestClient.put(EY.fake_awsm + '/scenario', {"scenario" => scenario, "remote" => remote}, {})
200
+ raise "Setting scenario failed: #{response.inspect}" unless response.code == 200
200
201
  end
201
- end
202
202
 
203
- module EY
204
- class << self
205
- def fake_awsm
206
- @fake_awsm ||= begin
207
- config_ru = File.join(EY_ROOT, "spec/support/fake_awsm.ru")
208
- unless system("ruby -c '#{config_ru}' > /dev/null")
209
- raise SyntaxError, "There is a syntax error in fake_awsm.ru! fix it!"
210
- end
211
- @server = RealWeb.start_server_in_fork(config_ru)
212
- "http://localhost:#{@server.port}"
213
- end
214
- end
215
- alias_method :start_fake_awsm, :fake_awsm
203
+ def read_yaml(file="ey.yml")
204
+ YAML.load_file(File.expand_path(file))
205
+ end
216
206
 
217
- def define_git_repo(name, &setup)
218
- @git_repo_setup ||= {}
219
- return if @git_repo_setup.key?(name)
220
- @git_repo_setup[name] = setup
221
- end
207
+ def write_yaml(data, file = "ey.yml")
208
+ File.open(file, "w"){|f| YAML.dump(data, f) }
209
+ end
222
210
 
223
- def refresh_git_repo(name)
224
- @git_repo_dir_cache ||= {}
225
- @git_repo_dir_cache.delete name
211
+ def with_env(new_env_vars)
212
+ raise ArgumentError, "with_env takes a block" unless block_given?
213
+ old_env_vars = {}
214
+ new_env_vars.each do |k, v|
215
+ if ENV.has_key?(k)
216
+ old_env_vars[k] = ENV[k]
217
+ end
218
+ ENV[k] = v
226
219
  end
227
220
 
228
- def git_repo_dir(name)
229
- @git_repo_dir_cache ||= {}
230
- return @git_repo_dir_cache[name] if @git_repo_dir_cache.has_key?(name)
231
- raise ArgumentError, "No definition for git repo #{name}" unless @git_repo_setup[name]
221
+ retval = yield
232
222
 
233
- git_dir = Pathname.new("/tmp/engineyard_test_repo_#{Time.now.tv_sec}_#{Time.now.tv_usec}_#{$$}")
234
- git_dir.mkdir
235
- Dir.chdir(git_dir) do
236
- system("git init -q")
237
- system('git config user.email ey@spec.test')
238
- system('git config user.name "EY Specs"')
239
- system("git remote add testremote user@git.host:path/to/repo.git")
240
- @git_repo_setup[name].call(git_dir)
223
+ new_env_vars.keys.each do |k|
224
+ if old_env_vars.has_key?(k)
225
+ ENV[k] = old_env_vars[k]
226
+ else
227
+ ENV.delete(k)
241
228
  end
242
- @git_repo_dir_cache[name] = git_dir
243
229
  end
230
+ retval
244
231
  end
245
232
  end