startapp 0.1.6
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.
- checksums.yaml +7 -0
- data/COPYRIGHT +1 -0
- data/LICENSE +11 -0
- data/README.md +95 -0
- data/Rakefile +6 -0
- data/autocomplete/rhc_bash +1672 -0
- data/bin/app +37 -0
- data/conf/express.conf +8 -0
- data/features/assets/deploy.tar.gz +0 -0
- data/features/core_feature.rb +191 -0
- data/features/deployments_feature.rb +129 -0
- data/features/domains_feature.rb +58 -0
- data/features/keys_feature.rb +37 -0
- data/features/members_feature.rb +166 -0
- data/lib/rhc/auth/basic.rb +64 -0
- data/lib/rhc/auth/token.rb +102 -0
- data/lib/rhc/auth/token_store.rb +53 -0
- data/lib/rhc/auth.rb +5 -0
- data/lib/rhc/autocomplete.rb +66 -0
- data/lib/rhc/autocomplete_templates/bash.erb +39 -0
- data/lib/rhc/cartridge_helpers.rb +118 -0
- data/lib/rhc/cli.rb +40 -0
- data/lib/rhc/command_runner.rb +185 -0
- data/lib/rhc/commands/account.rb +25 -0
- data/lib/rhc/commands/alias.rb +124 -0
- data/lib/rhc/commands/app.rb +726 -0
- data/lib/rhc/commands/apps.rb +20 -0
- data/lib/rhc/commands/authorization.rb +115 -0
- data/lib/rhc/commands/base.rb +174 -0
- data/lib/rhc/commands/cartridge.rb +329 -0
- data/lib/rhc/commands/clone.rb +66 -0
- data/lib/rhc/commands/configure.rb +20 -0
- data/lib/rhc/commands/create.rb +100 -0
- data/lib/rhc/commands/delete.rb +19 -0
- data/lib/rhc/commands/deploy.rb +32 -0
- data/lib/rhc/commands/deployment.rb +82 -0
- data/lib/rhc/commands/domain.rb +172 -0
- data/lib/rhc/commands/env.rb +142 -0
- data/lib/rhc/commands/force_stop.rb +17 -0
- data/lib/rhc/commands/git_clone.rb +34 -0
- data/lib/rhc/commands/logout.rb +51 -0
- data/lib/rhc/commands/logs.rb +21 -0
- data/lib/rhc/commands/member.rb +148 -0
- data/lib/rhc/commands/port_forward.rb +197 -0
- data/lib/rhc/commands/reload.rb +17 -0
- data/lib/rhc/commands/restart.rb +17 -0
- data/lib/rhc/commands/scp.rb +54 -0
- data/lib/rhc/commands/server.rb +40 -0
- data/lib/rhc/commands/setup.rb +60 -0
- data/lib/rhc/commands/show.rb +43 -0
- data/lib/rhc/commands/snapshot.rb +137 -0
- data/lib/rhc/commands/ssh.rb +51 -0
- data/lib/rhc/commands/sshkey.rb +97 -0
- data/lib/rhc/commands/start.rb +17 -0
- data/lib/rhc/commands/stop.rb +17 -0
- data/lib/rhc/commands/tail.rb +47 -0
- data/lib/rhc/commands/threaddump.rb +14 -0
- data/lib/rhc/commands/tidy.rb +17 -0
- data/lib/rhc/commands.rb +396 -0
- data/lib/rhc/config.rb +321 -0
- data/lib/rhc/context_helper.rb +121 -0
- data/lib/rhc/core_ext.rb +202 -0
- data/lib/rhc/coverage_helper.rb +33 -0
- data/lib/rhc/deployment_helpers.rb +111 -0
- data/lib/rhc/exceptions.rb +256 -0
- data/lib/rhc/git_helpers.rb +106 -0
- data/lib/rhc/help_formatter.rb +55 -0
- data/lib/rhc/helpers.rb +481 -0
- data/lib/rhc/highline_extensions.rb +479 -0
- data/lib/rhc/json.rb +51 -0
- data/lib/rhc/output_helpers.rb +260 -0
- data/lib/rhc/rest/activation.rb +11 -0
- data/lib/rhc/rest/alias.rb +42 -0
- data/lib/rhc/rest/api.rb +87 -0
- data/lib/rhc/rest/application.rb +348 -0
- data/lib/rhc/rest/attributes.rb +36 -0
- data/lib/rhc/rest/authorization.rb +8 -0
- data/lib/rhc/rest/base.rb +79 -0
- data/lib/rhc/rest/cartridge.rb +162 -0
- data/lib/rhc/rest/client.rb +650 -0
- data/lib/rhc/rest/deployment.rb +18 -0
- data/lib/rhc/rest/domain.rb +98 -0
- data/lib/rhc/rest/environment_variable.rb +15 -0
- data/lib/rhc/rest/gear_group.rb +16 -0
- data/lib/rhc/rest/httpclient.rb +145 -0
- data/lib/rhc/rest/key.rb +44 -0
- data/lib/rhc/rest/membership.rb +105 -0
- data/lib/rhc/rest/mock.rb +1042 -0
- data/lib/rhc/rest/user.rb +32 -0
- data/lib/rhc/rest.rb +148 -0
- data/lib/rhc/scp_helpers.rb +27 -0
- data/lib/rhc/ssh_helpers.rb +380 -0
- data/lib/rhc/tar_gz.rb +51 -0
- data/lib/rhc/usage_templates/command_help.erb +51 -0
- data/lib/rhc/usage_templates/command_syntax_help.erb +11 -0
- data/lib/rhc/usage_templates/help.erb +61 -0
- data/lib/rhc/usage_templates/missing_help.erb +1 -0
- data/lib/rhc/usage_templates/options_help.erb +12 -0
- data/lib/rhc/vendor/okjson.rb +600 -0
- data/lib/rhc/vendor/parseconfig.rb +178 -0
- data/lib/rhc/vendor/sshkey.rb +253 -0
- data/lib/rhc/vendor/zliby.rb +628 -0
- data/lib/rhc/version.rb +5 -0
- data/lib/rhc/wizard.rb +637 -0
- data/lib/rhc.rb +34 -0
- data/spec/coverage_helper.rb +82 -0
- data/spec/direct_execution_helper.rb +339 -0
- data/spec/keys/example.pem +23 -0
- data/spec/keys/example_private.pem +27 -0
- data/spec/keys/server.pem +19 -0
- data/spec/rest_spec_helper.rb +31 -0
- data/spec/rhc/assets/cert.crt +22 -0
- data/spec/rhc/assets/cert_key_rsa +27 -0
- data/spec/rhc/assets/empty.txt +0 -0
- data/spec/rhc/assets/env_vars.txt +7 -0
- data/spec/rhc/assets/env_vars_2.txt +1 -0
- data/spec/rhc/assets/foo.txt +1 -0
- data/spec/rhc/assets/targz_corrupted.tar.gz +1 -0
- data/spec/rhc/assets/targz_sample.tar.gz +0 -0
- data/spec/rhc/auth_spec.rb +442 -0
- data/spec/rhc/cli_spec.rb +186 -0
- data/spec/rhc/command_spec.rb +435 -0
- data/spec/rhc/commands/account_spec.rb +42 -0
- data/spec/rhc/commands/alias_spec.rb +333 -0
- data/spec/rhc/commands/app_spec.rb +777 -0
- data/spec/rhc/commands/apps_spec.rb +39 -0
- data/spec/rhc/commands/authorization_spec.rb +157 -0
- data/spec/rhc/commands/cartridge_spec.rb +665 -0
- data/spec/rhc/commands/clone_spec.rb +41 -0
- data/spec/rhc/commands/deployment_spec.rb +327 -0
- data/spec/rhc/commands/domain_spec.rb +401 -0
- data/spec/rhc/commands/env_spec.rb +493 -0
- data/spec/rhc/commands/git_clone_spec.rb +102 -0
- data/spec/rhc/commands/logout_spec.rb +86 -0
- data/spec/rhc/commands/member_spec.rb +247 -0
- data/spec/rhc/commands/port_forward_spec.rb +217 -0
- data/spec/rhc/commands/scp_spec.rb +77 -0
- data/spec/rhc/commands/server_spec.rb +69 -0
- data/spec/rhc/commands/setup_spec.rb +118 -0
- data/spec/rhc/commands/snapshot_spec.rb +179 -0
- data/spec/rhc/commands/ssh_spec.rb +163 -0
- data/spec/rhc/commands/sshkey_spec.rb +188 -0
- data/spec/rhc/commands/tail_spec.rb +81 -0
- data/spec/rhc/commands/threaddump_spec.rb +84 -0
- data/spec/rhc/config_spec.rb +407 -0
- data/spec/rhc/helpers_spec.rb +531 -0
- data/spec/rhc/highline_extensions_spec.rb +314 -0
- data/spec/rhc/json_spec.rb +30 -0
- data/spec/rhc/rest_application_spec.rb +258 -0
- data/spec/rhc/rest_client_spec.rb +752 -0
- data/spec/rhc/rest_spec.rb +740 -0
- data/spec/rhc/targz_spec.rb +55 -0
- data/spec/rhc/wizard_spec.rb +756 -0
- data/spec/spec_helper.rb +575 -0
- data/spec/wizard_spec_helper.rb +330 -0
- metadata +469 -0
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
require 'coverage_helper'
|
|
2
|
+
require 'webmock/rspec'
|
|
3
|
+
require 'fakefs/safe'
|
|
4
|
+
require 'rbconfig'
|
|
5
|
+
|
|
6
|
+
require 'pry' if ENV['PRY']
|
|
7
|
+
|
|
8
|
+
# Environment reset
|
|
9
|
+
ENV['http_proxy'] = nil
|
|
10
|
+
ENV['HTTP_PROXY'] = nil
|
|
11
|
+
ENV['OPENSHIFT_CONFIG'] = nil
|
|
12
|
+
|
|
13
|
+
class FakeFS::Mode
|
|
14
|
+
def initialize(mode_s)
|
|
15
|
+
@s = mode_s
|
|
16
|
+
end
|
|
17
|
+
def to_s(*args)
|
|
18
|
+
@s
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
class FakeFS::Stat
|
|
22
|
+
attr_reader :mode
|
|
23
|
+
def initialize(mode_s)
|
|
24
|
+
@mode = FakeFS::Mode.new(mode_s)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# chmod isn't implemented in the released fakefs gem
|
|
29
|
+
# but is in git. Once the git version is released we
|
|
30
|
+
# should remove this and actively check permissions
|
|
31
|
+
class FakeFS::File
|
|
32
|
+
def self.chmod(*args)
|
|
33
|
+
# noop
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.stat(path)
|
|
37
|
+
FakeFS::Stat.new(mode(path))
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.mode(path)
|
|
41
|
+
@modes && @modes[path] || '664'
|
|
42
|
+
end
|
|
43
|
+
def self.expect_mode(path, mode)
|
|
44
|
+
(@modes ||= {})[path] = mode
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# FakeFS incorrectly assigns this to '/'
|
|
48
|
+
remove_const(:PATH_SEPARATOR) rescue nil
|
|
49
|
+
const_set(:PATH_SEPARATOR, ":")
|
|
50
|
+
const_set(:ALT_SEPARATOR, '') rescue nil
|
|
51
|
+
|
|
52
|
+
def self.executable?(path)
|
|
53
|
+
# if the file exists we will assume it is executable
|
|
54
|
+
# for testing purposes
|
|
55
|
+
self.exists?(path)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
IO.instance_eval{ alias :read_orig :read }
|
|
60
|
+
|
|
61
|
+
module FakeFS
|
|
62
|
+
class << self
|
|
63
|
+
alias_method :activate_orig, :activate!
|
|
64
|
+
alias_method :deactivate_orig, :deactivate!
|
|
65
|
+
|
|
66
|
+
def activate!
|
|
67
|
+
IO.instance_eval{ def self.read(path); FakeFS::File.read(path); end }
|
|
68
|
+
activate_orig
|
|
69
|
+
end
|
|
70
|
+
def deactivate!
|
|
71
|
+
IO.instance_eval{ alias :read :read_orig }
|
|
72
|
+
deactivate_orig
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
require 'rhc/cli'
|
|
78
|
+
|
|
79
|
+
class MockHighLineTerminal < HighLineExtension
|
|
80
|
+
def self.use_color?
|
|
81
|
+
true
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def initialize(input=StringIO.new, output=StringIO.new)
|
|
85
|
+
super
|
|
86
|
+
@last_read_pos = 0
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
##
|
|
90
|
+
# read
|
|
91
|
+
#
|
|
92
|
+
# seeks to the last read in the IO stream and reads
|
|
93
|
+
# the data from that position so we don't repeat
|
|
94
|
+
# reads or get empty data due to writes moving
|
|
95
|
+
# the caret to the end of the stream
|
|
96
|
+
def read
|
|
97
|
+
@output.seek(@last_read_pos)
|
|
98
|
+
result = @output.read
|
|
99
|
+
@last_read_pos = @output.pos
|
|
100
|
+
result
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
##
|
|
104
|
+
# write_line
|
|
105
|
+
#
|
|
106
|
+
# writes a line of data to the end of the
|
|
107
|
+
# input stream appending a newline so
|
|
108
|
+
# highline knows to stop processing and then
|
|
109
|
+
# resets the caret position to the last read
|
|
110
|
+
def write_line(str)
|
|
111
|
+
reset_pos = @input.pos
|
|
112
|
+
# seek end so we don't overwrite anything
|
|
113
|
+
@input.seek(0, IO::SEEK_END)
|
|
114
|
+
result = @input.write "#{str}\n"
|
|
115
|
+
@input.seek(reset_pos)
|
|
116
|
+
result
|
|
117
|
+
end
|
|
118
|
+
def close_write
|
|
119
|
+
@input.close_write
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
include WebMock::API
|
|
124
|
+
|
|
125
|
+
require 'httpclient'
|
|
126
|
+
require 'webmock/http_lib_adapters/httpclient_adapter'
|
|
127
|
+
#
|
|
128
|
+
# Patched from WebMock 1.11, needs to be upstreamed
|
|
129
|
+
#
|
|
130
|
+
class WebMockHTTPClient
|
|
131
|
+
def do_get(req, proxy, conn, stream = false, &block)
|
|
132
|
+
request_signature = build_request_signature(req, :reuse_existing)
|
|
133
|
+
|
|
134
|
+
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
|
|
135
|
+
|
|
136
|
+
if webmock_responses[request_signature]
|
|
137
|
+
webmock_response = webmock_responses.delete(request_signature)
|
|
138
|
+
response = build_httpclient_response(webmock_response, stream, &block)
|
|
139
|
+
@request_filter.each do |filter|
|
|
140
|
+
# CHANGED
|
|
141
|
+
r = filter.filter_response(req, response)
|
|
142
|
+
res = do_get(req, proxy, conn, stream, &block) if r == :retry
|
|
143
|
+
# END CHANGES
|
|
144
|
+
end
|
|
145
|
+
res = conn.push(response)
|
|
146
|
+
WebMock::CallbackRegistry.invoke_callbacks(
|
|
147
|
+
{:lib => :httpclient}, request_signature, webmock_response)
|
|
148
|
+
res
|
|
149
|
+
elsif WebMock.net_connect_allowed?(request_signature.uri)
|
|
150
|
+
# in case there is a nil entry in the hash...
|
|
151
|
+
webmock_responses.delete(request_signature)
|
|
152
|
+
|
|
153
|
+
res = if stream
|
|
154
|
+
do_get_stream_without_webmock(req, proxy, conn, &block)
|
|
155
|
+
else
|
|
156
|
+
do_get_block_without_webmock(req, proxy, conn, &block)
|
|
157
|
+
end
|
|
158
|
+
res = conn.pop
|
|
159
|
+
conn.push(res)
|
|
160
|
+
if WebMock::CallbackRegistry.any_callbacks?
|
|
161
|
+
webmock_response = build_webmock_response(res)
|
|
162
|
+
WebMock::CallbackRegistry.invoke_callbacks(
|
|
163
|
+
{:lib => :httpclient, :real_request => true}, request_signature,
|
|
164
|
+
webmock_response)
|
|
165
|
+
end
|
|
166
|
+
res
|
|
167
|
+
else
|
|
168
|
+
raise WebMock::NetConnectNotAllowedError.new(request_signature)
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def stderr
|
|
174
|
+
$stderr.rewind
|
|
175
|
+
# some systems might redirect warnings to stderr
|
|
176
|
+
[$stderr,$terminal].map(&:read).delete_if{|x| x.strip.empty?}.join(' ')
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
module Commander::UI
|
|
180
|
+
alias :enable_paging_old :enable_paging
|
|
181
|
+
def enable_paging
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
module CommandExampleHelpers
|
|
187
|
+
#
|
|
188
|
+
# Allow this example to stub command methods
|
|
189
|
+
# by guaranteeing the instance exists prior
|
|
190
|
+
# to command execution. Use with methods on
|
|
191
|
+
# CommandHelpers
|
|
192
|
+
#
|
|
193
|
+
def using_command_instance
|
|
194
|
+
subject{ described_class }
|
|
195
|
+
let(:instance) { described_class.new }
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
#
|
|
199
|
+
# Helper methods for executing commands and
|
|
200
|
+
# stubbing/mocking methods
|
|
201
|
+
#
|
|
202
|
+
module CommandHelpers
|
|
203
|
+
def command_runner(*args)
|
|
204
|
+
mock_terminal
|
|
205
|
+
new_command_runner *args do
|
|
206
|
+
instance #ensure instance is created before subject :new is mocked
|
|
207
|
+
subject.stub(:new).and_return(instance)
|
|
208
|
+
RHC::Commands.to_commander
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
def run!(*args)
|
|
212
|
+
command_runner(*args).run!
|
|
213
|
+
end
|
|
214
|
+
def expects_running(*args, &block)
|
|
215
|
+
r = command_runner(*args)
|
|
216
|
+
lambda { r.run! }
|
|
217
|
+
end
|
|
218
|
+
def command_for(*args)
|
|
219
|
+
command = nil
|
|
220
|
+
RHC::Commands.stub(:execute){ |cmd, method, args| command = cmd; 0 }
|
|
221
|
+
command_runner(*args).run!
|
|
222
|
+
command
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
#
|
|
226
|
+
# These methods assume the example has declared
|
|
227
|
+
# let(:arguments){ [<arguments>] }
|
|
228
|
+
#
|
|
229
|
+
|
|
230
|
+
def run_command(args=arguments)
|
|
231
|
+
mock_terminal
|
|
232
|
+
input.each { |i| $terminal.write_line(i) } if respond_to?(:input)
|
|
233
|
+
$terminal.close_write
|
|
234
|
+
run!(*args)
|
|
235
|
+
end
|
|
236
|
+
def command_output(args=arguments)
|
|
237
|
+
run_command(args)
|
|
238
|
+
rescue SystemExit => e
|
|
239
|
+
"#{@output.string}\n#{$stderr.string}#{e}"
|
|
240
|
+
else
|
|
241
|
+
"#{@output.string}\n#{$stderr.string}"
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
#
|
|
245
|
+
# These methods bypass normal command stubbing.
|
|
246
|
+
# Should really be used when stubbing the whole
|
|
247
|
+
# path. Most specs should use run_instance.
|
|
248
|
+
#
|
|
249
|
+
def run(input=[])
|
|
250
|
+
mock_terminal
|
|
251
|
+
input.each { |i| $terminal.write_line(i) }
|
|
252
|
+
$terminal.close_write
|
|
253
|
+
RHC::CLI.start(arguments)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def run_output(input=[])
|
|
257
|
+
run(input)
|
|
258
|
+
rescue SystemExit => e
|
|
259
|
+
"#{@output.string}\n#{$stderr.string}#{e}"
|
|
260
|
+
else
|
|
261
|
+
"#{@output.string}\n#{$stderr.string}"
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
module ClassSpecHelpers
|
|
267
|
+
|
|
268
|
+
include Commander::Delegates
|
|
269
|
+
|
|
270
|
+
def const_for(obj=nil)
|
|
271
|
+
if obj
|
|
272
|
+
Object.const_set(const_for, obj)
|
|
273
|
+
else
|
|
274
|
+
"#{example.full_description}".split(" ").map{|word| word.capitalize}.join.gsub(/[^\w]/, '')
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def with_constants(constants, base=Object, &block)
|
|
279
|
+
constants.each do |constant, val|
|
|
280
|
+
base.const_set(constant, val)
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
block.call
|
|
284
|
+
ensure
|
|
285
|
+
constants.each do |constant, val|
|
|
286
|
+
base.send(:remove_const, constant)
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
def new_command_runner *args, &block
|
|
291
|
+
Commander::Runner.instance_variable_set :"@singleton", RHC::CommandRunner.new(args)
|
|
292
|
+
program :name, 'test'
|
|
293
|
+
program :version, '1.2.3'
|
|
294
|
+
program :description, 'something'
|
|
295
|
+
program :help_formatter, RHC::HelpFormatter
|
|
296
|
+
|
|
297
|
+
#create_test_command
|
|
298
|
+
yield if block
|
|
299
|
+
Commander::Runner.instance
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def mock_terminal
|
|
303
|
+
@input = StringIO.new
|
|
304
|
+
@output = StringIO.new
|
|
305
|
+
$stdout = @output
|
|
306
|
+
$stderr = (@error = StringIO.new)
|
|
307
|
+
$terminal = MockHighLineTerminal.new @input, @output
|
|
308
|
+
end
|
|
309
|
+
def input_line(s)
|
|
310
|
+
$terminal.write_line s
|
|
311
|
+
end
|
|
312
|
+
def last_output(&block)
|
|
313
|
+
if block_given?
|
|
314
|
+
yield $terminal.read
|
|
315
|
+
else
|
|
316
|
+
$terminal.read
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def capture(&block)
|
|
321
|
+
old_stdout = $stdout
|
|
322
|
+
old_stderr = $stderr
|
|
323
|
+
old_terminal = $terminal
|
|
324
|
+
@input = StringIO.new
|
|
325
|
+
@output = StringIO.new
|
|
326
|
+
$stdout = @output
|
|
327
|
+
$stderr = (@error = StringIO.new)
|
|
328
|
+
$terminal = MockHighLineTerminal.new @input, @output
|
|
329
|
+
yield
|
|
330
|
+
@output.string
|
|
331
|
+
ensure
|
|
332
|
+
$stdout = old_stdout
|
|
333
|
+
$stderr = old_stderr
|
|
334
|
+
$terminal = old_terminal
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def capture_all(&block)
|
|
338
|
+
old_stdout = $stdout
|
|
339
|
+
old_stderr = $stderr
|
|
340
|
+
old_terminal = $terminal
|
|
341
|
+
@input = StringIO.new
|
|
342
|
+
@output = StringIO.new
|
|
343
|
+
$stdout = @output
|
|
344
|
+
$stderr = @output
|
|
345
|
+
$terminal = MockHighLineTerminal.new @input, @output
|
|
346
|
+
yield
|
|
347
|
+
@output.string
|
|
348
|
+
ensure
|
|
349
|
+
$stdout = old_stdout
|
|
350
|
+
$stderr = old_stderr
|
|
351
|
+
$terminal = old_terminal
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
#
|
|
355
|
+
# usage: stub_request(...).with(&user_agent_header)
|
|
356
|
+
#
|
|
357
|
+
def user_agent_header
|
|
358
|
+
lambda do |request|
|
|
359
|
+
#User-Agent is not sent to mock by httpclient
|
|
360
|
+
#request.headers['User-Agent'] =~ %r{\Arhc/\d+\.\d+.\d+ \(.*?ruby.*?\)}
|
|
361
|
+
true
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
def base_config(&block)
|
|
366
|
+
config = RHC::Config.new
|
|
367
|
+
config.stub(:load_config_files)
|
|
368
|
+
defaults = config.instance_variable_get(:@defaults)
|
|
369
|
+
yield config, defaults if block_given?
|
|
370
|
+
RHC::Config.stub(:default).and_return(config)
|
|
371
|
+
RHC::Config.stub(:new).and_return(config)
|
|
372
|
+
config
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
def user_config
|
|
376
|
+
user = respond_to?(:username) ? self.username : 'test_user'
|
|
377
|
+
password = respond_to?(:password) ? self.password : 'test pass'
|
|
378
|
+
server = respond_to?(:server) ? self.server : nil
|
|
379
|
+
|
|
380
|
+
base_config do |config, defaults|
|
|
381
|
+
defaults.add 'default_rhlogin', user
|
|
382
|
+
defaults.add 'password', password
|
|
383
|
+
defaults.add 'libra_server', server if server
|
|
384
|
+
end.tap do |c|
|
|
385
|
+
opts = c.to_options
|
|
386
|
+
opts[:rhlogin].should == user
|
|
387
|
+
opts[:password].should == password
|
|
388
|
+
opts[:server].should == server if server
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
def expect_multi_ssh(command, hosts, check_error=false)
|
|
393
|
+
require 'net/ssh/multi'
|
|
394
|
+
|
|
395
|
+
session = double('Multi::SSH::Session')
|
|
396
|
+
described_class.any_instance.stub(:requires_ssh_multi!)
|
|
397
|
+
channels = hosts.inject({}) do |h, (k,v)|
|
|
398
|
+
c = double(:properties => {}, :connection => double(:properties => {}))
|
|
399
|
+
h[k] = c
|
|
400
|
+
h
|
|
401
|
+
end
|
|
402
|
+
session.should_receive(:use).exactly(hosts.count).times.with do |host, opts|
|
|
403
|
+
opts[:properties].should_not be_nil
|
|
404
|
+
opts[:properties][:gear].should_not be_nil
|
|
405
|
+
hosts.should have_key(host)
|
|
406
|
+
channels[host].connection.properties.merge!(opts[:properties])
|
|
407
|
+
true
|
|
408
|
+
end
|
|
409
|
+
session.stub(:_command).and_return(command)
|
|
410
|
+
session.stub(:_hosts).and_return(hosts)
|
|
411
|
+
session.stub(:_channels).and_return(channels)
|
|
412
|
+
session.instance_eval do
|
|
413
|
+
def exec(arg1, *args, &block)
|
|
414
|
+
arg1.should == _command
|
|
415
|
+
_hosts.to_a.sort{ |a,b| a[0] <=> b[0] }.each do |(k,v)|
|
|
416
|
+
block.call(_channels[k], :stdout, v)
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
session.should_receive(:loop) unless hosts.empty?
|
|
421
|
+
Net::SSH::Multi.should_receive(:start).and_yield(session).with do |opts|
|
|
422
|
+
opts.should have_key(:on_error)
|
|
423
|
+
capture_all{ opts[:on_error].call('test') }.should =~ /Unable to connect to gear test/ if check_error
|
|
424
|
+
true
|
|
425
|
+
end
|
|
426
|
+
session
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
module ExitCodeMatchers
|
|
431
|
+
RSpec::Matchers.define :exit_with_code do |code|
|
|
432
|
+
actual = nil
|
|
433
|
+
match do |block|
|
|
434
|
+
begin
|
|
435
|
+
actual = block.call
|
|
436
|
+
rescue SystemExit => e
|
|
437
|
+
actual = e.status
|
|
438
|
+
end
|
|
439
|
+
actual and actual == code
|
|
440
|
+
end
|
|
441
|
+
failure_message_for_should do |block|
|
|
442
|
+
"expected block to call exit(#{code}) but exit" +
|
|
443
|
+
(actual.nil? ? " not called" : "(#{actual}) was called")
|
|
444
|
+
end
|
|
445
|
+
failure_message_for_should_not do |block|
|
|
446
|
+
"expected block not to call exit(#{code})"
|
|
447
|
+
end
|
|
448
|
+
description do
|
|
449
|
+
"expect block to call exit(#{code})"
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
module CommanderInvocationMatchers
|
|
455
|
+
InvocationMatch = Class.new(RuntimeError)
|
|
456
|
+
|
|
457
|
+
RSpec::Matchers.define :call do |method|
|
|
458
|
+
chain :on do |object|
|
|
459
|
+
@object = object
|
|
460
|
+
end
|
|
461
|
+
chain :with do |*args|
|
|
462
|
+
@args = args
|
|
463
|
+
end
|
|
464
|
+
chain :and_stop do
|
|
465
|
+
@stop = true
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
match do |block|
|
|
469
|
+
e = @object.should_receive(method)
|
|
470
|
+
e.and_raise(InvocationMatch) if @stop
|
|
471
|
+
e.with(*@args) if @args
|
|
472
|
+
begin
|
|
473
|
+
block.call
|
|
474
|
+
true
|
|
475
|
+
rescue InvocationMatch => e
|
|
476
|
+
true
|
|
477
|
+
rescue SystemExit => e
|
|
478
|
+
false
|
|
479
|
+
end
|
|
480
|
+
end
|
|
481
|
+
description do
|
|
482
|
+
"expect block to invoke '#{method}' on #{@object} with #{@args}"
|
|
483
|
+
end
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
RSpec::Matchers.define :not_call do |method|
|
|
487
|
+
chain :on do |object|
|
|
488
|
+
@object = object
|
|
489
|
+
end
|
|
490
|
+
chain :with do |*args|
|
|
491
|
+
@args = args
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
match do |block|
|
|
495
|
+
e = @object.should_not_receive(method)
|
|
496
|
+
e.with(*@args) if @args
|
|
497
|
+
begin
|
|
498
|
+
block.call
|
|
499
|
+
true
|
|
500
|
+
rescue SystemExit => e
|
|
501
|
+
false
|
|
502
|
+
end
|
|
503
|
+
end
|
|
504
|
+
description do
|
|
505
|
+
"expect block to invoke '#{method}' on #{@object} with #{@args}"
|
|
506
|
+
end
|
|
507
|
+
end
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
module ColorMatchers
|
|
511
|
+
COLORS = {
|
|
512
|
+
:green => 32,
|
|
513
|
+
:yellow => 33,
|
|
514
|
+
:cyan => 36,
|
|
515
|
+
:red => 31,
|
|
516
|
+
:clear => 0
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
RSpec::Matchers.define :be_colorized do |msg,color|
|
|
520
|
+
match do |actual|
|
|
521
|
+
actual == colorized_message(msg,color)
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
failure_message_for_should do |actual|
|
|
525
|
+
failure_message(actual,msg,color)
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
failure_message_for_should_not do |actual|
|
|
529
|
+
failure_message(actual,msg,color)
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
def failure_message(actual,msg,color)
|
|
533
|
+
"expected: #{colorized_message(msg,color).inspect}\n" +
|
|
534
|
+
" got: #{actual.inspect}"
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
def ansi_code(color)
|
|
538
|
+
"\e[#{ColorMatchers::COLORS[color]}m"
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
def colorized_message(msg,color)
|
|
542
|
+
[
|
|
543
|
+
ansi_code(color),
|
|
544
|
+
msg,
|
|
545
|
+
ansi_code(:clear),
|
|
546
|
+
"\n"
|
|
547
|
+
].join('')
|
|
548
|
+
end
|
|
549
|
+
end
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
def mac?
|
|
553
|
+
RbConfig::CONFIG['host_os'] =~ /^darwin/
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
RSpec.configure do |config|
|
|
557
|
+
config.include(ExitCodeMatchers)
|
|
558
|
+
config.include(CommanderInvocationMatchers)
|
|
559
|
+
config.include(ColorMatchers)
|
|
560
|
+
config.include(ClassSpecHelpers)
|
|
561
|
+
config.include(CommandHelpers)
|
|
562
|
+
config.extend(CommandExampleHelpers)
|
|
563
|
+
config.backtrace_clean_patterns = [] if ENV['FULL_BACKTRACE']
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
module TestEnv
|
|
567
|
+
extend ClassSpecHelpers
|
|
568
|
+
class << self
|
|
569
|
+
attr_accessor :instance, :subject
|
|
570
|
+
def instance=(i)
|
|
571
|
+
self.subject = i.class
|
|
572
|
+
@instance = i
|
|
573
|
+
end
|
|
574
|
+
end
|
|
575
|
+
end
|