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.
Files changed (156) hide show
  1. checksums.yaml +7 -0
  2. data/COPYRIGHT +1 -0
  3. data/LICENSE +11 -0
  4. data/README.md +95 -0
  5. data/Rakefile +6 -0
  6. data/autocomplete/rhc_bash +1672 -0
  7. data/bin/app +37 -0
  8. data/conf/express.conf +8 -0
  9. data/features/assets/deploy.tar.gz +0 -0
  10. data/features/core_feature.rb +191 -0
  11. data/features/deployments_feature.rb +129 -0
  12. data/features/domains_feature.rb +58 -0
  13. data/features/keys_feature.rb +37 -0
  14. data/features/members_feature.rb +166 -0
  15. data/lib/rhc/auth/basic.rb +64 -0
  16. data/lib/rhc/auth/token.rb +102 -0
  17. data/lib/rhc/auth/token_store.rb +53 -0
  18. data/lib/rhc/auth.rb +5 -0
  19. data/lib/rhc/autocomplete.rb +66 -0
  20. data/lib/rhc/autocomplete_templates/bash.erb +39 -0
  21. data/lib/rhc/cartridge_helpers.rb +118 -0
  22. data/lib/rhc/cli.rb +40 -0
  23. data/lib/rhc/command_runner.rb +185 -0
  24. data/lib/rhc/commands/account.rb +25 -0
  25. data/lib/rhc/commands/alias.rb +124 -0
  26. data/lib/rhc/commands/app.rb +726 -0
  27. data/lib/rhc/commands/apps.rb +20 -0
  28. data/lib/rhc/commands/authorization.rb +115 -0
  29. data/lib/rhc/commands/base.rb +174 -0
  30. data/lib/rhc/commands/cartridge.rb +329 -0
  31. data/lib/rhc/commands/clone.rb +66 -0
  32. data/lib/rhc/commands/configure.rb +20 -0
  33. data/lib/rhc/commands/create.rb +100 -0
  34. data/lib/rhc/commands/delete.rb +19 -0
  35. data/lib/rhc/commands/deploy.rb +32 -0
  36. data/lib/rhc/commands/deployment.rb +82 -0
  37. data/lib/rhc/commands/domain.rb +172 -0
  38. data/lib/rhc/commands/env.rb +142 -0
  39. data/lib/rhc/commands/force_stop.rb +17 -0
  40. data/lib/rhc/commands/git_clone.rb +34 -0
  41. data/lib/rhc/commands/logout.rb +51 -0
  42. data/lib/rhc/commands/logs.rb +21 -0
  43. data/lib/rhc/commands/member.rb +148 -0
  44. data/lib/rhc/commands/port_forward.rb +197 -0
  45. data/lib/rhc/commands/reload.rb +17 -0
  46. data/lib/rhc/commands/restart.rb +17 -0
  47. data/lib/rhc/commands/scp.rb +54 -0
  48. data/lib/rhc/commands/server.rb +40 -0
  49. data/lib/rhc/commands/setup.rb +60 -0
  50. data/lib/rhc/commands/show.rb +43 -0
  51. data/lib/rhc/commands/snapshot.rb +137 -0
  52. data/lib/rhc/commands/ssh.rb +51 -0
  53. data/lib/rhc/commands/sshkey.rb +97 -0
  54. data/lib/rhc/commands/start.rb +17 -0
  55. data/lib/rhc/commands/stop.rb +17 -0
  56. data/lib/rhc/commands/tail.rb +47 -0
  57. data/lib/rhc/commands/threaddump.rb +14 -0
  58. data/lib/rhc/commands/tidy.rb +17 -0
  59. data/lib/rhc/commands.rb +396 -0
  60. data/lib/rhc/config.rb +321 -0
  61. data/lib/rhc/context_helper.rb +121 -0
  62. data/lib/rhc/core_ext.rb +202 -0
  63. data/lib/rhc/coverage_helper.rb +33 -0
  64. data/lib/rhc/deployment_helpers.rb +111 -0
  65. data/lib/rhc/exceptions.rb +256 -0
  66. data/lib/rhc/git_helpers.rb +106 -0
  67. data/lib/rhc/help_formatter.rb +55 -0
  68. data/lib/rhc/helpers.rb +481 -0
  69. data/lib/rhc/highline_extensions.rb +479 -0
  70. data/lib/rhc/json.rb +51 -0
  71. data/lib/rhc/output_helpers.rb +260 -0
  72. data/lib/rhc/rest/activation.rb +11 -0
  73. data/lib/rhc/rest/alias.rb +42 -0
  74. data/lib/rhc/rest/api.rb +87 -0
  75. data/lib/rhc/rest/application.rb +348 -0
  76. data/lib/rhc/rest/attributes.rb +36 -0
  77. data/lib/rhc/rest/authorization.rb +8 -0
  78. data/lib/rhc/rest/base.rb +79 -0
  79. data/lib/rhc/rest/cartridge.rb +162 -0
  80. data/lib/rhc/rest/client.rb +650 -0
  81. data/lib/rhc/rest/deployment.rb +18 -0
  82. data/lib/rhc/rest/domain.rb +98 -0
  83. data/lib/rhc/rest/environment_variable.rb +15 -0
  84. data/lib/rhc/rest/gear_group.rb +16 -0
  85. data/lib/rhc/rest/httpclient.rb +145 -0
  86. data/lib/rhc/rest/key.rb +44 -0
  87. data/lib/rhc/rest/membership.rb +105 -0
  88. data/lib/rhc/rest/mock.rb +1042 -0
  89. data/lib/rhc/rest/user.rb +32 -0
  90. data/lib/rhc/rest.rb +148 -0
  91. data/lib/rhc/scp_helpers.rb +27 -0
  92. data/lib/rhc/ssh_helpers.rb +380 -0
  93. data/lib/rhc/tar_gz.rb +51 -0
  94. data/lib/rhc/usage_templates/command_help.erb +51 -0
  95. data/lib/rhc/usage_templates/command_syntax_help.erb +11 -0
  96. data/lib/rhc/usage_templates/help.erb +61 -0
  97. data/lib/rhc/usage_templates/missing_help.erb +1 -0
  98. data/lib/rhc/usage_templates/options_help.erb +12 -0
  99. data/lib/rhc/vendor/okjson.rb +600 -0
  100. data/lib/rhc/vendor/parseconfig.rb +178 -0
  101. data/lib/rhc/vendor/sshkey.rb +253 -0
  102. data/lib/rhc/vendor/zliby.rb +628 -0
  103. data/lib/rhc/version.rb +5 -0
  104. data/lib/rhc/wizard.rb +637 -0
  105. data/lib/rhc.rb +34 -0
  106. data/spec/coverage_helper.rb +82 -0
  107. data/spec/direct_execution_helper.rb +339 -0
  108. data/spec/keys/example.pem +23 -0
  109. data/spec/keys/example_private.pem +27 -0
  110. data/spec/keys/server.pem +19 -0
  111. data/spec/rest_spec_helper.rb +31 -0
  112. data/spec/rhc/assets/cert.crt +22 -0
  113. data/spec/rhc/assets/cert_key_rsa +27 -0
  114. data/spec/rhc/assets/empty.txt +0 -0
  115. data/spec/rhc/assets/env_vars.txt +7 -0
  116. data/spec/rhc/assets/env_vars_2.txt +1 -0
  117. data/spec/rhc/assets/foo.txt +1 -0
  118. data/spec/rhc/assets/targz_corrupted.tar.gz +1 -0
  119. data/spec/rhc/assets/targz_sample.tar.gz +0 -0
  120. data/spec/rhc/auth_spec.rb +442 -0
  121. data/spec/rhc/cli_spec.rb +186 -0
  122. data/spec/rhc/command_spec.rb +435 -0
  123. data/spec/rhc/commands/account_spec.rb +42 -0
  124. data/spec/rhc/commands/alias_spec.rb +333 -0
  125. data/spec/rhc/commands/app_spec.rb +777 -0
  126. data/spec/rhc/commands/apps_spec.rb +39 -0
  127. data/spec/rhc/commands/authorization_spec.rb +157 -0
  128. data/spec/rhc/commands/cartridge_spec.rb +665 -0
  129. data/spec/rhc/commands/clone_spec.rb +41 -0
  130. data/spec/rhc/commands/deployment_spec.rb +327 -0
  131. data/spec/rhc/commands/domain_spec.rb +401 -0
  132. data/spec/rhc/commands/env_spec.rb +493 -0
  133. data/spec/rhc/commands/git_clone_spec.rb +102 -0
  134. data/spec/rhc/commands/logout_spec.rb +86 -0
  135. data/spec/rhc/commands/member_spec.rb +247 -0
  136. data/spec/rhc/commands/port_forward_spec.rb +217 -0
  137. data/spec/rhc/commands/scp_spec.rb +77 -0
  138. data/spec/rhc/commands/server_spec.rb +69 -0
  139. data/spec/rhc/commands/setup_spec.rb +118 -0
  140. data/spec/rhc/commands/snapshot_spec.rb +179 -0
  141. data/spec/rhc/commands/ssh_spec.rb +163 -0
  142. data/spec/rhc/commands/sshkey_spec.rb +188 -0
  143. data/spec/rhc/commands/tail_spec.rb +81 -0
  144. data/spec/rhc/commands/threaddump_spec.rb +84 -0
  145. data/spec/rhc/config_spec.rb +407 -0
  146. data/spec/rhc/helpers_spec.rb +531 -0
  147. data/spec/rhc/highline_extensions_spec.rb +314 -0
  148. data/spec/rhc/json_spec.rb +30 -0
  149. data/spec/rhc/rest_application_spec.rb +258 -0
  150. data/spec/rhc/rest_client_spec.rb +752 -0
  151. data/spec/rhc/rest_spec.rb +740 -0
  152. data/spec/rhc/targz_spec.rb +55 -0
  153. data/spec/rhc/wizard_spec.rb +756 -0
  154. data/spec/spec_helper.rb +575 -0
  155. data/spec/wizard_spec_helper.rb +330 -0
  156. metadata +469 -0
@@ -0,0 +1,531 @@
1
+ require 'spec_helper'
2
+ require 'rhc'
3
+ require 'rhc/ssh_helpers'
4
+ require 'rhc/cartridge_helpers'
5
+ require 'rhc/git_helpers'
6
+ require 'rhc/core_ext'
7
+ require 'rhc/config'
8
+ require 'rhc/rest/mock'
9
+ require 'date'
10
+ require 'resolv'
11
+ require 'ostruct'
12
+
13
+ class AllRhcHelpers
14
+ include RHC::Helpers
15
+ include RHC::SSHHelpers
16
+ include RHC::CartridgeHelpers
17
+
18
+ def config
19
+ @config ||= RHC::Config.new
20
+ end
21
+ def options
22
+ @options ||= OpenStruct.new(:server => nil)
23
+ end
24
+ end
25
+
26
+ describe AllRhcHelpers do
27
+ before do
28
+ mock_terminal
29
+ user_config
30
+ end
31
+
32
+ its(:openshift_server) { should == 'broker.startapp.bg' }
33
+ its(:openshift_url) { should == 'https://broker.startapp.bg' }
34
+
35
+ it("should display slashes"){ subject.system_path('foo/bar').should == 'foo/bar' }
36
+ context "on windows" do
37
+ it("should display backslashes"){ with_constants({:ALT_SEPARATOR => '\\'}, File) { subject.system_path('foo/bar').should == 'foo\\bar' } }
38
+ it("should handle drives"){ with_constants({:ALT_SEPARATOR => '\\'}, File) { subject.system_path('C:/foo/bar').should == 'C:\\foo\\bar' } }
39
+ end
40
+
41
+ it("should pluralize many") { subject.pluralize(3, 'fish').should == '3 fishs' }
42
+ it("should not pluralize one") { subject.pluralize(1, 'fish').should == '1 fish' }
43
+
44
+ it("should decode json"){ subject.decode_json("{\"a\" : 1}").should == {'a' => 1} }
45
+
46
+ shared_examples_for "colorized output" do
47
+ it("should be colorized") do
48
+ message = "this is #{_color} -"
49
+ output = capture{ subject.send(method,message) }
50
+ output.should be_colorized(message,_color)
51
+ end
52
+ it("should return true"){ subject.send(method,'anything').should be_true }
53
+ end
54
+
55
+ context "success output" do
56
+ let(:_color){ :green }
57
+ let(:method){ :success }
58
+ it_should_behave_like "colorized output"
59
+ end
60
+
61
+ context "warn output" do
62
+ let(:_color){ :yellow }
63
+ let(:method){ :warn }
64
+ it_should_behave_like "colorized output"
65
+ end
66
+
67
+ context "info output" do
68
+ let(:_color){ :cyan }
69
+ let(:method){ :info }
70
+ it_should_behave_like "colorized output"
71
+ end
72
+
73
+ it("should invoke debug from debug_error"){ expect{ subject.debug_error(double(:class => "Mock", :message => 'msg', :backtrace => [])) }.to call(:debug).on($terminal).with("msg (Mock)\n ") }
74
+
75
+ it("should draw a table") do
76
+ subject.table([[10,2], [3,40]]) do |i|
77
+ i.map(&:to_s)
78
+ end.to_a.should == ['10 2','3 40']
79
+ end
80
+
81
+ context "error output" do
82
+ let(:_color){ :red }
83
+ let(:method){ :error }
84
+ it_should_behave_like "colorized output"
85
+ end
86
+
87
+ it("should output a table") do
88
+ subject.send(:format_no_info, 'test').to_a.should == ['This test has no information to show']
89
+ end
90
+
91
+ it "should parse an RFC3339 date" do
92
+ d = subject.datetime_rfc3339('2012-06-24T20:48:20-04:00')
93
+ d.day.should == 24
94
+ d.month.should == 6
95
+ d.year.should == 2012
96
+ end
97
+
98
+ describe "#human_size" do
99
+ it{ subject.human_size(nil).should == 'unknown' }
100
+ it{ subject.human_size(1).should == '1 B' }
101
+ it{ subject.human_size(500).should == '500 B' }
102
+ it{ subject.human_size(1000).should == '1 KB' }
103
+ it{ subject.human_size(500000).should == '500 KB' }
104
+ it{ subject.human_size(1000*1000).should == '1 MB' }
105
+ it{ subject.human_size(1000*1000*1000).should == '1 GB' }
106
+ it{ subject.human_size(1000*1000*1000*1000).should == '1 TB' }
107
+ end
108
+
109
+ describe "#distance_of_time_in_words" do
110
+ it{ subject.distance_of_time_in_words(0, 1).should == 'less than 1 minute' }
111
+ it{ subject.distance_of_time_in_words(0, 60).should == '1 minute' }
112
+ it{ subject.distance_of_time_in_words(0, 130).should == '2 minutes' }
113
+ it{ subject.distance_of_time_in_words(0, 50*60).should == 'about 1 hour' }
114
+ it{ subject.distance_of_time_in_words(0, 3*60*60).should == 'about 3 hours' }
115
+ it{ subject.distance_of_time_in_words(0, 25*60*60).should == 'about 1 day' }
116
+ it{ subject.distance_of_time_in_words(0, 3*24*60*60).should == '3 days' }
117
+ it{ subject.distance_of_time_in_words(0, 40*24*60*60).should == 'about 1 month' }
118
+ it{ subject.distance_of_time_in_words(0, 10*30*24*60*60).should == 'about 10 months' }
119
+ end
120
+
121
+ context 'using the current time' do
122
+ let(:date){ Time.local(2008,1,2,1,1,0) }
123
+ let(:today){ Date.new(2008,1,2) }
124
+ before{ Date.stub(:today).and_return(today) }
125
+
126
+ let(:rfc3339){ '%Y-%m-%dT%H:%M:%S%z' }
127
+ it("should output the time for a date that is today") do
128
+ subject.date(date.strftime(rfc3339)).should =~ /^[0-9]/
129
+ end
130
+ it("should exclude the year for a date that is this year") do
131
+ subject.date(date.strftime(rfc3339)).should_not match(date.year.to_s)
132
+ end
133
+ it("should output the year for a date that is not this year") do
134
+ older = Date.today - 1*365
135
+ subject.date(older.strftime(rfc3339)).should match(older.year.to_s)
136
+ end
137
+ it("should handle invalid input") do
138
+ subject.date('Unknown date').should == 'Unknown date'
139
+ end
140
+
141
+ context 'when the year is different' do
142
+ let(:today){ Date.new(2007,1,2) }
143
+ it{ subject.date(date.strftime(rfc3339)).should match(date.year.to_s) }
144
+ end
145
+
146
+ context 'when the year of the day is different' do
147
+ let(:today){ Date.new(2008,1,1) }
148
+ it{ subject.date(date.strftime(rfc3339)).should_not match(date.year.to_s) }
149
+ end
150
+ end
151
+
152
+ context 'with LIBRA_SERVER environment variable' do
153
+ before do
154
+ ENV['LIBRA_SERVER'] = 'test.com'
155
+ user_config
156
+ end
157
+ its(:openshift_server) { should == 'test.com' }
158
+ its(:openshift_url) { should == 'https://test.com' }
159
+ after { ENV['LIBRA_SERVER'] = nil }
160
+ end
161
+ context 'with --server environment variable' do
162
+ before do
163
+ subject.options.server = "test.com"
164
+ end
165
+ its(:openshift_server) { should == 'test.com' }
166
+ its(:openshift_url) { should == 'https://test.com' }
167
+ after { ENV['LIBRA_SERVER'] = nil }
168
+ end
169
+
170
+ context "without RHC::Config" do
171
+ subject do
172
+ Class.new(Object){ include RHC::Helpers }.new
173
+ end
174
+
175
+ it("should raise on config"){ expect{ subject.config }.to raise_error }
176
+ end
177
+
178
+ context "with a bad timeout value" do
179
+ context "on the command line" do
180
+ let(:arguments){ ['help', '--timeout=string'] }
181
+ it{ expect{ run }.to exit_with_code(1) }
182
+ it{ run_output.should match("invalid argument: --timeout=string") }
183
+ end
184
+ context "that is a negative integer" do
185
+ let(:arguments){ ['help', '--timeout=0'] }
186
+ it{ expect{ run }.to exit_with_code(1) }
187
+ it{ run_output.should match("must be a positive integer") }
188
+ end
189
+ context "via the config" do
190
+ before{ base_config{ |c, d| d.add 'timeout', 'string' } }
191
+ let(:arguments){ ['help'] }
192
+ it{ expect{ run }.to exit_with_code(1) }
193
+ it{ run_output.should match(/The configuration file.*invalid setting: invalid value for Integer/) }
194
+ end
195
+ end
196
+ context "with a valid client cert file" do
197
+ let(:arguments){ ['help', '--ssl-client-cert-file=spec/keys/example.pem'] }
198
+ it{ expect{ run }.to exit_with_code(0) }
199
+ end
200
+
201
+ context "with a missing client cert file" do
202
+ context "on the command line" do
203
+ let(:arguments){ ['help', '--ssl-client-cert-file=not_a_file'] }
204
+ it{ expect{ run }.to exit_with_code(1) }
205
+ it{ run_output.should match("The certificate 'not_a_file' cannot be loaded: No such") }
206
+ end
207
+ context "via the config" do
208
+ before{ base_config{ |c, d| d.add 'ssl_client_cert_file', 'not_a_file' } }
209
+ let(:arguments){ ['help'] }
210
+ it{ expect{ run }.to exit_with_code(1) }
211
+ it{ run_output.should match("The certificate 'not_a_file' cannot be loaded: No such") }
212
+ end
213
+ end
214
+
215
+ context 'with a valid --ssl-version' do
216
+ let(:arguments){ ['help', '--ssl-version=sslv3'] }
217
+
218
+ context 'on an older version of HTTPClient' do
219
+ before{ HTTPClient::SSLConfig.stub(:method_defined?).with(:ssl_version).and_return(false) }
220
+ it('should print an error') { run_output.should =~ /You are using an older version of the httpclient.*--ssl-version/ }
221
+ it('should error out') { expect{ run }.to exit_with_code(1) }
222
+ end
223
+ context 'a newer version of HTTPClient' do
224
+ before{ HTTPClient::SSLConfig.stub(:method_defined?).with(:ssl_version).and_return(true) }
225
+ it('should not print an error') { run_output.should_not =~ /You are using an older version of the httpclient.*--ssl-version/ }
226
+ it('should error out') { expect{ run }.to exit_with_code(0) }
227
+ end
228
+ end
229
+
230
+ context "with an invalid SSLVersion" do
231
+ context "on the command line" do
232
+ let(:arguments){ ['help', '--ssl-version=ssl'] }
233
+ it{ expect{ run }.to exit_with_code(1) }
234
+ it{ run_output.should match("The provided SSL version 'ssl' is not valid. Supported values: ") }
235
+ end
236
+ context "via the config" do
237
+ before{ base_config{ |c, d| d.add 'ssl_version', 'ssl' } }
238
+ let(:arguments){ ['help'] }
239
+ it{ expect{ run }.to exit_with_code(1) }
240
+ it{ run_output.should match("The provided SSL version 'ssl' is not valid. Supported values: ") }
241
+ end
242
+ end
243
+
244
+ context "with an valid ssl CA file" do
245
+ let(:arguments){ ['help', '--ssl-ca-file=spec/keys/example.pem'] }
246
+ it{ expect{ run }.to exit_with_code(0) }
247
+ end
248
+
249
+ context "with an invalid ssl CA file" do
250
+ let(:arguments){ ['help', '--ssl-ca-file=not_a_file'] }
251
+ it{ expect{ run }.to exit_with_code(1) }
252
+ it{ run_output.should match("The certificate 'not_a_file' cannot be loaded: No such file or directory ") }
253
+ end
254
+
255
+ context "#get_properties" do
256
+ it{ subject.send(:get_properties, double(:plan_id => 'free'), :plan_id).should == [[:plan_id, 'Free']] }
257
+ context "when an error is raised" do
258
+ let(:bar){ double.tap{ |s| s.should_receive(:foo).and_raise(::Exception) } }
259
+ it{ subject.send(:get_properties, bar, :foo).should == [[:foo, '<error>']] }
260
+ end
261
+ end
262
+
263
+ describe "#exec" do
264
+ it{ subject.send(:exec, 'echo foo').should == [0, "foo\n"] }
265
+ end
266
+
267
+ context "Git Helpers" do
268
+ subject{ Class.new(Object){ include RHC::Helpers; include RHC::GitHelpers; def debug?; false; end }.new }
269
+ before{ subject.stub(:git_version){ raise "Fake Exception" } }
270
+ its(:has_git?) { should be_false }
271
+
272
+ context "without git" do
273
+ before{ subject.stub(:git_cmd){ "nonexistent_git" } }
274
+ its(:has_git?) { should be_false }
275
+ it { subject.git_config_get('key').should == nil }
276
+ end
277
+
278
+
279
+ context "git clone repo" do
280
+ let(:stdout){ 'fake git clone' }
281
+ let(:exit_status){ 0 }
282
+ let!(:spawn) do
283
+ out, err = stdout, stderr
284
+ Open4.should_receive(:spawn).and_return(exit_status) do |cmd, opts|
285
+ opts['stdout'] << out if out
286
+ opts['stderr'] << err if err
287
+ exit_status
288
+ end
289
+ true
290
+ end
291
+
292
+ it { capture{ subject.git_clone_repo("url", "repo").should == File.expand_path('repo') } }
293
+ it { capture_all{ subject.git_clone_repo("url", "repo") }.should match("fake git clone") }
294
+
295
+ context "does not succeed" do
296
+ let(:stderr){ 'fatal: error' }
297
+ let(:exit_status){ 1 }
298
+
299
+ it { capture{ expect{ subject.git_clone_repo("url", "repo") }.to raise_error(RHC::GitException) } }
300
+ it { capture_all{ subject.git_clone_repo("url", "repo") rescue nil }.should match("fake git clone") }
301
+ it { capture_all{ subject.git_clone_repo("url", "repo") rescue nil }.should match("fatal: error") }
302
+ end
303
+
304
+ context "directory is missing" do
305
+ let(:stderr){ "fatal: destination path 'foo' already exists and is not an empty directory." }
306
+ let(:exit_status){ 1 }
307
+
308
+ it { capture{ expect{ subject.git_clone_repo("url", "repo") }.to raise_error(RHC::GitDirectoryExists) } }
309
+ end
310
+
311
+ context "permission denied" do
312
+ let(:stderr){ "Permission denied (publickey,gssapi-mic)." }
313
+ let(:exit_status){ 1 }
314
+
315
+ it { capture{ expect{ subject.git_clone_repo("url", "repo") }.to raise_error(RHC::GitPermissionDenied) } }
316
+ end
317
+ end
318
+ end
319
+
320
+ context "SSH Key Helpers" do
321
+ it "should generate an ssh key then return nil when it tries to create another" do
322
+ FakeFS do
323
+ FakeFS::FileSystem.clear
324
+ subject.generate_ssh_key_ruby.should match("\.ssh/id_rsa\.pub")
325
+ subject.generate_ssh_key_ruby == nil
326
+ end
327
+ end
328
+
329
+ it "should print an error when finger print fails" do
330
+ Net::SSH::KeyFactory.should_receive(:load_public_key).with('1').and_raise(Net::SSH::Exception.new("An error"))
331
+ subject.should_receive(:error).with('An error')
332
+ subject.fingerprint_for_local_key('1').should be_nil
333
+ end
334
+
335
+ it "should catch exceptions from fingerprint failures" do
336
+ Net::SSH::KeyFactory.should_receive(:load_public_key).with('1').and_raise(StandardError.new("An error"))
337
+ subject.fingerprint_for_local_key('1').should be_nil
338
+ end
339
+
340
+ it "should handle a block in multi_ssh calls" do
341
+ expect_multi_ssh('foo', 'fakegearid0@fakesshurl.com' => 'bar')
342
+ subject.run_on_gears('foo', [RHC::Rest::Mock::MockRestGearGroup.new], :as => :gear){ |gear, data, group| data.should == 'bar'; 'test' }.should == ['test']
343
+ end
344
+
345
+ it "should handle a block in multi_ssh calls" do
346
+ expect_multi_ssh('foo', 'fakegearid0@fakesshurl.com' => 'bar')
347
+ capture{ subject.table_from_gears('foo', [RHC::Rest::Mock::MockRestGearGroup.new], :header => ['cart','col']) }.should match /cart.*col\n-+.*fakegearid0.*bar/m
348
+ end
349
+
350
+ it "should handle a run_on_gears error for unrecognized type" do
351
+ expect_multi_ssh('foo', {})
352
+ expect{ subject.run_on_gears('foo', RHC::Rest::Mock::MockRestGearGroup.new.gears) }.to raise_error(RuntimeError)
353
+ end
354
+
355
+ it "should handle an error for unrecognized type" do
356
+ expect_multi_ssh('foo', {'fakegearid0@fakesshurl.com' => 'bar'}, true)
357
+ subject.run_on_gears('foo', [RHC::Rest::Mock::MockRestGearGroup.new])
358
+ end
359
+
360
+ it "should rescue load errors from ssh-multi" do
361
+ RHC::SSHHelpers::MultipleGearTask.any_instance.should_receive(:require).and_raise(LoadError)
362
+ expect{ RHC::SSHHelpers::MultipleGearTask.new(nil,nil,nil).send(:requires_ssh_multi!) }.to raise_error RHC::OperationNotSupportedException, /must install Net::SSH::Multi/
363
+ end
364
+ end
365
+
366
+ describe "#wrap" do
367
+ it{ "abc".wrap(1).should == "a\nb\nc" }
368
+ end
369
+
370
+ describe "#textwrap_ansi" do
371
+ it{ "".textwrap_ansi(80).should == [] }
372
+ it{ "\n".textwrap_ansi(80).should == ["",""] }
373
+ it{ "a".textwrap_ansi(1).should == ['a'] }
374
+ it{ "ab".textwrap_ansi(1).should == ['a','b'] }
375
+ it{ "ab".textwrap_ansi(2).should == ['ab'] }
376
+ it{ "ab cd".textwrap_ansi(4).should == ['ab', 'cd'] }
377
+ it{ " ab".textwrap_ansi(2).should == [' a','b'] }
378
+ it{ "a b".textwrap_ansi(1).should == ['a','b'] }
379
+ it{ "a w b".textwrap_ansi(2).should == ['a','w','b'] }
380
+ it{ "a w b".textwrap_ansi(3).should == ['a w','b'] }
381
+ it{ "a\nb".textwrap_ansi(1).should == ['a','b'] }
382
+ it{ "\e[1m".textwrap_ansi(1).should == ["\e[1m\e[0m"] }
383
+ it{ "\e[31;1m".textwrap_ansi(1).should == ["\e[31;1m\e[0m"] }
384
+ it{ "\e[1ma".textwrap_ansi(1).should == ["\e[1ma\e[0m"] }
385
+ it{ "a\e[12m".textwrap_ansi(1).should == ["a\e[12m\e[0m"] }
386
+ it{ "a\e[12m\e[34mb".textwrap_ansi(1).should == ["a\e[12m\e[34m\e[0m","\e[12m\e[34mb\e[0m"] }
387
+ it{ "\e[12;34ma".textwrap_ansi(1).should == ["\e[12;34ma\e[0m"] }
388
+ it{ "\e[1m\e[1m".textwrap_ansi(1).should == ["\e[1m\e[1m\e[0m"] }
389
+ it{ "\e[1m \e[1m".textwrap_ansi(1).should == ["\e[1m\e[0m", "\e[1m\e[1m\e[0m"] }
390
+ it{ "\e[1ma\nb".textwrap_ansi(80).should == ["\e[1ma","b"] }
391
+
392
+ it{ "ab".textwrap_ansi(1,false).should == ['ab'] }
393
+ it{ " abc".textwrap_ansi(3,false).should == [' abc'] }
394
+ it{ "abcd".textwrap_ansi(3,false).should == ['abcd'] }
395
+ it{ "abcd\e[1m".textwrap_ansi(3,false).should == ["abcd\e[1m\e[0m"] }
396
+ it{ "abcd efg a".textwrap_ansi(3,false).should == ['abcd', 'efg', 'a'] }
397
+ it('next line'){ "abcd e a".textwrap_ansi(5,false).should == ['abcd', 'e a'] }
398
+ it{ "abcd efgh a".textwrap_ansi(3,false).should == ['abcd', 'efgh', 'a'] }
399
+ it{ " abcd efg a".textwrap_ansi(3,false).should == [' abcd', 'efg', 'a'] }
400
+ end
401
+
402
+ describe "#strip_ansi" do
403
+ it{ "\e[1m \e[1m".strip_ansi.should == " " }
404
+ it{ "\eiei0".strip_ansi.should == "\eiei0" }
405
+ it{ "\e[iei0]".strip_ansi.should == "\e[iei0]" }
406
+ end
407
+
408
+ context "Resolv helper" do
409
+ let(:resolver) { Object.new }
410
+ let(:existent_host) { 'real_host' }
411
+ let(:nonexistent_host) { 'fake_host' }
412
+
413
+ before do
414
+ Resolv::Hosts.stub(:new) { resolver }
415
+ resolver.stub(:getaddress).with(existent_host) { existent_host }
416
+ resolver.stub(:getaddress).with(nonexistent_host){ Resolv::ResolvError }
417
+ end
418
+
419
+ context "when hosts file has the desired host" do
420
+ it "does not raise error" do
421
+ expect {
422
+ subject.hosts_file_contains?(existent_host)
423
+ }.to_not raise_error
424
+ end
425
+ end
426
+
427
+ context "when hosts file does not have the desired host" do
428
+ it "does not raise error" do
429
+ expect {
430
+ subject.hosts_file_contains?(nonexistent_host)
431
+ }.to_not raise_error
432
+ end
433
+ end
434
+ end
435
+
436
+ context "cartridge helpers" do
437
+ before{ mock_terminal }
438
+
439
+ describe '#check_cartridges' do
440
+ let(:cartridges){ [] }
441
+ let(:find_cartridges){ [] }
442
+ context "with a generic object" do
443
+ it { expect{ subject.send(:check_cartridges, 'foo', :from => cartridges) }.to raise_error(RHC::CartridgeNotFoundException, 'There are no cartridges that match \'foo\'.') }
444
+ end
445
+ end
446
+
447
+ describe '#match_cart' do
448
+ context 'with a nil cart' do
449
+ let(:cart){ OpenStruct.new(:name => nil, :description => nil, :tags => nil) }
450
+ it{ subject.send(:match_cart, cart, 'foo').should be_false }
451
+ end
452
+ context 'with simple strings' do
453
+ let(:cart){ OpenStruct.new(:name => 'FOO-more_max any', :description => 'bar word', :tags => [:baz]) }
454
+ it{ subject.send(:match_cart, cart, 'foo').should be_true }
455
+ it{ subject.send(:match_cart, cart, 'fo').should be_true }
456
+ it{ subject.send(:match_cart, cart, 'oo').should be_true }
457
+ it{ subject.send(:match_cart, cart, 'bar').should be_true }
458
+ it{ subject.send(:match_cart, cart, 'word').should be_true }
459
+ it{ subject.send(:match_cart, cart, 'bar word').should be_true }
460
+ it{ subject.send(:match_cart, cart, 'wor').should be_false }
461
+ it{ subject.send(:match_cart, cart, 'baz').should be_true }
462
+ it{ subject.send(:match_cart, cart, 'more max').should be_true }
463
+ it{ subject.send(:match_cart, cart, 'foo more max any').should be_true }
464
+ it{ subject.send(:match_cart, cart, 'foo_more max-any').should be_true }
465
+ end
466
+ end
467
+ end
468
+
469
+ describe "#collect_env_vars" do
470
+ it { subject.collect_env_vars('FOO=BAR').first.to_hash.should == { :name => 'FOO', :value => 'BAR' } }
471
+ it { subject.collect_env_vars('FOO2=BAR2').first.to_hash.should == { :name => 'FOO2', :value => 'BAR2' } }
472
+ it { subject.collect_env_vars('FOO_BAR=ZEE').first.to_hash.should == { :name => 'FOO_BAR', :value => 'ZEE' } }
473
+ it { subject.collect_env_vars('_FOO=BAR').first.to_hash.should == { :name => '_FOO', :value => 'BAR' } }
474
+ it { subject.collect_env_vars('FOO=').first.to_hash.should == { :name => 'FOO', :value => '' } }
475
+ it { subject.collect_env_vars('FOO==').first.to_hash.should == { :name => 'FOO', :value => '=' } }
476
+ it { subject.collect_env_vars('FOO=BAR=ZEE').first.to_hash.should == { :name => 'FOO', :value => 'BAR=ZEE' } }
477
+ it { subject.collect_env_vars('foo25_=BAR=\][#%*').first.to_hash.should == { :name => 'foo25_', :value => 'BAR=\][#%*' } }
478
+ it { subject.collect_env_vars('FOO=Test 1 2 3').first.to_hash.should == { :name => 'FOO', :value => 'Test 1 2 3' } }
479
+ it { subject.collect_env_vars('2FOO=BAR').empty?.should be_true }
480
+ it { subject.collect_env_vars('FOO.2=BAR').empty?.should be_true }
481
+ it { subject.collect_env_vars('FOO BAR=ZEE').empty?.should be_true }
482
+ it { subject.collect_env_vars('FOO*BAR=ZEE').empty?.should be_true }
483
+ it { subject.collect_env_vars('FOO&BAR=ZEE').empty?.should be_true }
484
+ it { subject.collect_env_vars('FOO:BAR=ZEE').empty?.should be_true }
485
+ it { subject.collect_env_vars('FOO@BAR=ZEE').empty?.should be_true }
486
+ it { subject.collect_env_vars('FOO!BAR=ZEE').empty?.should be_true }
487
+ end
488
+ end
489
+
490
+ describe RHC::Helpers::StringTee do
491
+ let(:other){ StringIO.new }
492
+ subject{ RHC::Helpers::StringTee.new(other) }
493
+ context "It should copy output" do
494
+ before{ subject << 'foo' }
495
+ its(:string) { should == 'foo' }
496
+ it("should tee to other") { other.string.should == 'foo' }
497
+ end
498
+ end
499
+
500
+ describe Object do
501
+ context 'present?' do
502
+ specify('nil') { nil.present?.should be_false }
503
+ specify('empty array') { [].present?.should be_false }
504
+ specify('array') { [1].present?.should be_true }
505
+ specify('string') { 'a'.present?.should be_true }
506
+ specify('empty string') { ''.present?.should be_false }
507
+ end
508
+
509
+ context 'presence' do
510
+ specify('nil') { nil.presence.should be_nil }
511
+ specify('empty array') { [].presence.should be_nil }
512
+ specify('array') { [1].presence.should == [1] }
513
+ specify('string') { 'a'.presence.should == 'a' }
514
+ specify('empty string') { ''.presence.should be_nil }
515
+ end
516
+
517
+ context 'blank?' do
518
+ specify('nil') { nil.blank?.should be_true }
519
+ specify('empty array') { [].blank?.should be_true }
520
+ specify('array') { [1].blank?.should be_false }
521
+ specify('string') { 'a'.blank?.should be_false }
522
+ specify('empty string') { ''.blank?.should be_true }
523
+ end
524
+ end
525
+
526
+ describe OpenURI do
527
+ context 'redirectable?' do
528
+ specify('http to https') { OpenURI.redirectable?(URI.parse('http://foo.com'), URI.parse('https://foo.com')).should be_true }
529
+ specify('https to http') { OpenURI.redirectable?(URI.parse('https://foo.com'), URI.parse('http://foo.com')).should be_false }
530
+ end
531
+ end