engineyard 1.4.0 → 1.4.1

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.
@@ -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