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,752 @@
1
+ require 'base64'
2
+ require 'spec_helper'
3
+ require 'stringio'
4
+ require 'rest_spec_helper'
5
+ require 'rhc/rest'
6
+
7
+ module RHC
8
+ module Rest
9
+ describe Client do
10
+
11
+ after{ ENV['http_proxy'] = nil }
12
+ after{ ENV['HTTP_PROXY'] = nil }
13
+
14
+ it 'should set the proxy protocol if it is missing' do
15
+ ENV['http_proxy'] = 'foo.bar.com:8081'
16
+ expect{ RHC::Rest::Client.new.send(:httpclient_for, {}) }.to raise_error(ArgumentError)
17
+ end
18
+
19
+ it 'should not alter the proxy protocol if it is present' do
20
+ ENV['http_proxy'] = 'http://foo.bar.com:8081'
21
+ RHC::Rest::Client.new.send(:httpclient_for, {}).proxy.to_s.should == URI.parse(ENV['http_proxy']).to_s
22
+ end
23
+
24
+ it 'should not affect the proxy protocol if nil' do
25
+ ENV['http_proxy'] = nil
26
+ RHC::Rest::Client.new.send(:httpclient_for, {}).proxy.should be_nil
27
+ ENV['http_proxy'].should be_nil
28
+ end
29
+
30
+ let(:endpoint){ mock_href }
31
+ let(:username){ nil }
32
+ let(:password){ nil }
33
+ let(:use_debug){ false }
34
+ let(:client) do
35
+ respond_to?(:spec_versions) ?
36
+ RHC::Rest::Client.new(endpoint, username, password, use_debug, spec_versions) :
37
+ RHC::Rest::Client.new(endpoint, username, password, use_debug)
38
+ end
39
+
40
+ let(:client_links) { mock_response_links(mock_client_links) }
41
+ let(:domain_0_links) { mock_response_links(mock_domain_links('mock_domain_0')) }
42
+ let(:domain_1_links) { mock_response_links(mock_domain_links('mock_domain_1')) }
43
+ let(:app_0_links) { mock_response_links(mock_app_links('mock_domain_0', 'mock_app')) }
44
+ let(:user_links) { mock_response_links(mock_user_links) }
45
+ let(:key_links) { mock_response_links(mock_key_links) }
46
+ let(:api_links) { client_links }
47
+
48
+ context "#new" do
49
+ before do
50
+ stub_api_request(:get, '').
51
+ to_return({ :body => { :data => client_links, :supported_api_versions => [1.0, 1.1] }.to_json,
52
+ :status => 200
53
+ })
54
+ stub_api_request(:get, 'api_error').
55
+ to_raise(HTTPClient::BadResponseError.new('API Error'))
56
+ stub_api_request(:get, 'other_error').
57
+ to_raise(StandardError.new('Other Error'))
58
+ end
59
+
60
+ it "returns a client object from the required arguments" do
61
+ credentials = Base64.strict_encode64(mock_user + ":" + mock_pass)
62
+ client.api.send(:links).should == client_links
63
+ end
64
+ context "against an endpoint that won't connect" do
65
+ let(:endpoint){ mock_href('api_error') }
66
+ it "raises an error message" do
67
+ expect{ client.api }.to raise_error
68
+ end
69
+ end
70
+ context "against an endpoint that has a generic error" do
71
+ let(:endpoint){ mock_href('other_error') }
72
+ it "raises a generic error for any other error condition" do
73
+ expect{ client.api }.to raise_error(RHC::Rest::ConnectionException, "An unexpected error occured: Other Error")
74
+ end
75
+ end
76
+ end
77
+
78
+ describe "#new" do
79
+ context "when server supports API versions [1.0, 1.1]" do
80
+ before :each do
81
+ stub_api_request(:get, '').
82
+ with(:headers => {'Accept' => 'application/json'}).
83
+ to_return({ :status => 200, :body => { :data => client_links, :version => '1.0', :supported_api_versions => [1.0, 1.1] }.to_json })
84
+ stub_api_request(:get, '').
85
+ with(:headers => {'Accept' => 'application/json;version=1.0'}).
86
+ to_return({ :status => 200, :body => { :data => client_links, :version => '1.0', :supported_api_versions => [1.0, 1.1] }.to_json })
87
+ stub_api_request(:get, '').
88
+ with(:headers => {'Accept' => 'application/json;version=1.1'}).
89
+ to_return({ :status => 200, :body => { :data => client_links, :version => '1.1', :supported_api_versions => [1.0, 1.1] }.to_json })
90
+ stub_api_request(:get, '').
91
+ with(:headers => {'Accept' => /application\/json;version=(1.2|1.3)/}).
92
+ to_raise(StandardError.new('Bad Version'))
93
+ stub_api_request(:get, 'api_error').
94
+ to_raise(HTTPClient::BadResponseError.new('API Error'))
95
+ stub_api_request(:get, 'other_error').
96
+ to_raise(StandardError.new('Other Error'))
97
+ end
98
+
99
+ context "when client is instantiated with [1.0, 1.1] as the preferred API versions" do
100
+ let(:spec_versions){ [1.0, 1.1] }
101
+ it "settles on 1.1 as the API version" do
102
+ client.api.api_version_negotiated.should == 1.1
103
+ end
104
+ end
105
+
106
+ context "when client is instantiated with [1.1, 1.0] as the preferred API versions" do
107
+ let(:spec_versions){ [1.1, 1.0] }
108
+ it "settles on 1.0 as the API version" do
109
+ client.api.api_version_negotiated.should == 1.0
110
+ end
111
+ end
112
+
113
+ context "when client is instantiated with [1.2, 1.3] as the preferred API versions" do
114
+ let(:spec_versions){ [1.2, 1.3] }
115
+ it "fails to negotiate an agreeable API version" do
116
+ client.api.api_version_negotiated.should be_nil
117
+ end
118
+ end
119
+
120
+ context "when client is instantiated with [1.1, 1.0, 1.3] as the preferred API versions" do
121
+ let(:spec_versions){ [1.1, 1.0, 1.3] }
122
+ it "settles on 1.0 as the API version" do
123
+ client.api.api_version_negotiated.should == 1.0
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ context "with an instantiated client " do
130
+ before do
131
+ stub_api_request(:get, '').
132
+ to_return({ :body => {
133
+ :data => api_links,
134
+ :supported_api_versions => [1.0, 1.1]
135
+ }.to_json,
136
+ :status => 200
137
+ })
138
+ end
139
+
140
+ context "#add_domain" do
141
+ before do
142
+ stub_api_request(:any, api_links['ADD_DOMAIN']['relative']).
143
+ to_return({ :body => {
144
+ :type => 'domain',
145
+ :supported_api_versions => [1.0, 1.1],
146
+ :data => {
147
+ :id => 'mock_domain',
148
+ :links => mock_response_links(mock_domain_links('mock_domain')),
149
+ }
150
+ }.to_json,
151
+ :status => 200
152
+ })
153
+ end
154
+ it "returns a domain object" do
155
+ domain = client.add_domain('mock_domain')
156
+ domain.class.should == RHC::Rest::Domain
157
+ domain.name.should == 'mock_domain'
158
+ domain.send(:links).should ==
159
+ mock_response_links(mock_domain_links('mock_domain'))
160
+ end
161
+ end
162
+
163
+ context "#update_members" do
164
+ subject{ RHC::Rest::Application.new }
165
+ it "raises when the update link is disabled" do
166
+ subject.should_receive(:supports_members?).and_return(true)
167
+ expect{ subject.update_members([]) }.to raise_error(RHC::ChangeMembersOnResourceNotSupported)
168
+ end
169
+ end
170
+
171
+ context "#domains" do
172
+ before(:each) do
173
+ stub_api_request(:any, api_links['LIST_DOMAINS']['relative']).
174
+ to_return({ :body => {
175
+ :type => 'domains',
176
+ :data =>
177
+ [{ :id => 'mock_domain_0',
178
+ :links => mock_response_links(mock_domain_links('mock_domain_0')),
179
+ },
180
+ { :id => 'mock_domain_1',
181
+ :links => mock_response_links(mock_domain_links('mock_domain_1')),
182
+ }]
183
+ }.to_json,
184
+ :status => 200
185
+ }).
186
+ to_return({ :body => {
187
+ :type => 'domains',
188
+ :data => []
189
+ }.to_json,
190
+ :status => 200
191
+ })
192
+ end
193
+ it "returns a list of existing domains" do
194
+ domains = client.domains
195
+ domains.length.should equal(2)
196
+ (0..1).each do |idx|
197
+ domains[idx].class.should == RHC::Rest::Domain
198
+ domains[idx].name.should == "mock_domain_#{idx}"
199
+ domains[idx].send(:links).should ==
200
+ mock_response_links(mock_domain_links("mock_domain_#{idx}"))
201
+ end
202
+ end
203
+ it "returns an empty list when no domains exist" do
204
+ # Disregard the first response; this is for the previous expectiation.
205
+ domains = client.domains
206
+ client.instance_variable_set(:@domains, nil)
207
+ domains = client.domains
208
+ domains.length.should equal(0)
209
+ end
210
+ end
211
+
212
+ context "#find_domain" do
213
+ context "when server does not support SHOW_DOMAIN" do
214
+ before do
215
+ stub_api_request(:any, api_links['LIST_DOMAINS']['relative']).
216
+ to_return({ :body => {
217
+ :type => 'domains',
218
+ :data =>
219
+ [{ :id => 'mock_domain_0',
220
+ :links => mock_response_links(mock_domain_links('mock_domain_0')),
221
+ },
222
+ { :id => 'mock_domain_1',
223
+ :links => mock_response_links(mock_domain_links('mock_domain_1')),
224
+ }]
225
+ }.to_json,
226
+ :status => 200
227
+ })
228
+ end
229
+ it "returns a domain object for matching domain IDs" do
230
+ match = nil
231
+ expect { match = client.find_domain('mock_domain_0') }.to_not raise_error
232
+ match.name.should == 'mock_domain_0'
233
+ match.class.should == RHC::Rest::Domain
234
+ end
235
+ it "returns a domain object for matching case-insensitive domain IDs" do
236
+ match = nil
237
+ expect { match = client.find_domain('MOCK_DOMAIN_0') }.to_not raise_error
238
+ match.name.should == 'mock_domain_0'
239
+ match.class.should == RHC::Rest::Domain
240
+ end
241
+ it "raise an error when no matching domain IDs can be found" do
242
+ expect { client.find_domain('mock_domain_2') }.to raise_error(RHC::Rest::DomainNotFoundException)
243
+ end
244
+ end
245
+
246
+ context "when server supports SHOW_DOMAIN" do
247
+ let(:api_links){ client_links.merge!(mock_response_links([['SHOW_DOMAIN', 'domains/:name', 'get']])) }
248
+ before do
249
+ stub_api_request(:any, api_links['SHOW_DOMAIN']['relative'].gsub(/:name/, 'mock_domain_0')).
250
+ to_return({ :body => {
251
+ :type => 'domain',
252
+ :data =>
253
+ { :id => 'mock_domain_0',
254
+ :links => mock_response_links(mock_domain_links('mock_domain_0')),
255
+ }
256
+ }.to_json,
257
+ :status => 200
258
+ })
259
+ stub_api_request(:any, api_links['SHOW_DOMAIN']['relative'].gsub(/:name/, 'mock_domain_%^&')).
260
+ to_return({ :body => {
261
+ :type => 'domain',
262
+ :data =>
263
+ { :id => 'mock_domain_%^&',
264
+ :links => mock_response_links(mock_domain_links('mock_domain_0')),
265
+ }
266
+ }.to_json,
267
+ :status => 200
268
+ })
269
+ stub_api_request(:any, api_links['SHOW_DOMAIN']['relative'].gsub(/:name/, 'mock_domain_2')).
270
+ to_return({ :body => {:messages => [{:exit_code => 127}, {:severity => 'warning', :text => 'A warning'}]}.to_json,
271
+ :status => 404
272
+ })
273
+ end
274
+ it "returns a domain object for matching domain IDs" do
275
+ match = nil
276
+ expect { match = client.find_domain('mock_domain_0') }.to_not raise_error
277
+ match.name.should == 'mock_domain_0'
278
+ match.class.should == RHC::Rest::Domain
279
+ end
280
+ it "encodes special characters" do
281
+ match = nil
282
+ expect { match = client.find_domain('mock_domain_%^&') }.to_not raise_error
283
+ match.name.should == 'mock_domain_%^&'
284
+ match.class.should == RHC::Rest::Domain
285
+ end
286
+ it "raise an error when no matching domain IDs can be found" do
287
+ expect{ client.find_domain('mock_domain_2') }.to raise_error(RHC::Rest::DomainNotFoundException)
288
+ end
289
+ it "prints a warning when an error is returned" do
290
+ client.should_receive(:warn).with('A warning')
291
+ expect{ client.find_domain('mock_domain_2') }.to raise_error(RHC::Rest::DomainNotFoundException)
292
+ end
293
+ end
294
+ end
295
+
296
+ context "when server supports LIST_DOMAINS_BY_OWNER" do
297
+ let(:api_links){ client_links.merge!(mock_response_links([['LIST_DOMAINS_BY_OWNER', 'domains', 'get']])) }
298
+ before do
299
+ stub_api_request(:any, "#{api_links['LIST_DOMAINS_BY_OWNER']['relative']}?owner=@self").
300
+ to_return({ :body => {
301
+ :type => 'domains',
302
+ :data => [{
303
+ :id => 'mock_domain_0',
304
+ :links => mock_response_links(mock_domain_links('mock_domain_0')),
305
+ }]
306
+ }.to_json,
307
+ :status => 200
308
+ })
309
+ end
310
+ it "returns owned domains when called" do
311
+ match = nil
312
+ expect { match = client.owned_domains }.to_not raise_error
313
+ match.length.should == 1
314
+ match.first.name.should == 'mock_domain_0'
315
+ match.first.class.should == RHC::Rest::Domain
316
+ end
317
+ end
318
+
319
+ context "find_application" do
320
+ let(:mock_domain){ 'mock_domain_0' }
321
+ let(:mock_app){ 'mock_app' }
322
+ let(:missing){ 'no_match' }
323
+ before(:each) do
324
+ stub_one_application(mock_domain, mock_app)
325
+ stub_one_application(mock_domain, missing, {
326
+ :type => nil,
327
+ :data => nil,
328
+ :messages => [{
329
+ :exit_code => 101,
330
+ :field => nil,
331
+ :severity => 'error',
332
+ :text => "Application #{missing} not found"
333
+ }],
334
+ :status => 'not_found'
335
+ }, 404)
336
+ stub_one_application(missing, mock_app, {
337
+ :type => nil,
338
+ :data => nil,
339
+ :messages => [{
340
+ :exit_code => 127,
341
+ :field => nil,
342
+ :severity => 'error',
343
+ :text => "Domain #{missing} not found"
344
+ }],
345
+ :status => 'not_found'
346
+ }, 404)
347
+ end
348
+ it "returns application object for nested application IDs" do
349
+ match = client.find_application(mock_domain, mock_app)
350
+ match.class.should == RHC::Rest::Application
351
+ match.name.should == mock_app
352
+ match.domain_id.should == mock_domain
353
+ match.send(:links).should ==
354
+ mock_response_links(mock_app_links(mock_domain, mock_app))
355
+ end
356
+ it "Raises an exception when no matching applications can be found" do
357
+ expect { client.find_application(mock_domain, missing) }.to raise_error(RHC::Rest::ApplicationNotFoundException)
358
+ end
359
+ it "Raises an exception when no matching domain can be found" do
360
+ expect { client.find_application(missing, mock_app) }.to raise_error(RHC::Rest::DomainNotFoundException)
361
+ end
362
+ end
363
+
364
+ context "#find_application_by_id" do
365
+ context "when server does not support SHOW_APPLICATION" do
366
+ let(:server){ mock_uri }
367
+ let(:endpoint){ "https://#{server}/broker/rest/api"}
368
+ before do
369
+ stub_api
370
+ stub_one_domain('test')
371
+ stub_one_application('test', 'app1')
372
+ end
373
+ it "returns an app object for matching IDs" do
374
+ match = nil
375
+ expect { match = client.find_application_by_id(1) }.to_not raise_error
376
+ match.id.should == 1
377
+ match.class.should == RHC::Rest::Application
378
+ end
379
+ it "raise an error when no matching app IDs can be found" do
380
+ expect { client.find_application_by_id('2') }.to raise_error(RHC::Rest::ApplicationNotFoundException)
381
+ end
382
+ end
383
+
384
+ context "when server supports SHOW_APPLICATION" do
385
+ let(:api_links){ mock_response_links([['SHOW_APPLICATION', 'application/:id', 'get']]) }
386
+ before do
387
+ stub_api_request(:any, api_links['SHOW_APPLICATION']['relative'].gsub(/:id/, 'app_0')).
388
+ to_return({ :body => {
389
+ :type => 'application',
390
+ :data =>
391
+ { :id => 'app_0',
392
+ :links => mock_response_links(mock_app_links('app_0')),
393
+ }
394
+ }.to_json,
395
+ :status => 200
396
+ })
397
+ stub_api_request(:any, api_links['SHOW_APPLICATION']['relative'].gsub(/:id/, 'app_1')).
398
+ to_return({ :body => {:messages => [{:exit_code => 101}]}.to_json,
399
+ :status => 404
400
+ })
401
+ end
402
+ it "returns an app object for matching IDs" do
403
+ match = nil
404
+ expect { match = client.find_application_by_id('app_0') }.to_not raise_error
405
+ match.id.should == 'app_0'
406
+ match.class.should == RHC::Rest::Application
407
+ end
408
+ it "raise an error when no matching IDs can be found" do
409
+ expect { client.find_application_by_id('app_1') }.to raise_error(RHC::Rest::ApplicationNotFoundException)
410
+ end
411
+ it "should fetch application ids" do
412
+ client.api
413
+ client.should_receive(:request).with(:url => "#{api_links['SHOW_APPLICATION']['href'].gsub(/:id/, 'app_2')}", :method => "GET", :payload => {}).and_return(1)
414
+ client.find_application_by_id('app_2').should == 1
415
+ end
416
+ it "should fetch application gear groups" do
417
+ client.api
418
+ client.should_receive(:request).with(:url => "#{api_links['SHOW_APPLICATION']['href'].gsub(/:id/, 'app_2')}/gear_groups", :method => "GET", :payload => {}).and_return(1)
419
+ client.find_application_by_id_gear_groups('app_2').should == 1
420
+ end
421
+ end
422
+ end
423
+
424
+ describe RHC::Rest::Cartridge do
425
+ subject do
426
+ RHC::Rest::Cartridge.new({
427
+ :name => 'foo',
428
+ :links => mock_response_links([
429
+ ['GET', 'broker/rest/cartridge', 'get']
430
+ ])}, client)
431
+ end
432
+ context "when several messages are present" do
433
+ before do
434
+ stub_api_request(:get, 'broker/rest/cartridge', true).
435
+ with(:query => {:include => 'status_messages'}).
436
+ to_return(:body => {
437
+ :type => 'cartridge',
438
+ :data => {
439
+ :status_messages => [{:message => 'Test'}]
440
+ }
441
+ }.to_json)
442
+ end
443
+ its(:status){ should == [{'message' => 'Test'}] }
444
+ end
445
+ end
446
+
447
+ context "#cartridges" do
448
+ before(:each) do
449
+ stub_api_request(:any, api_links['LIST_CARTRIDGES']['relative']).
450
+ to_return({ :body => {
451
+ :type => 'cartridges',
452
+ :data =>
453
+ [{ :name => 'mock_cart_0',
454
+ :type => 'mock_cart_0_type',
455
+ :links => mock_response_links(mock_cart_links('mock_cart_0')),
456
+ },
457
+ { :name => 'mock_cart_1',
458
+ :type => 'mock_cart_1_type',
459
+ :links => mock_response_links(mock_cart_links('mock_cart_1')),
460
+ }]
461
+ }.to_json,
462
+ :status => 200
463
+ }).
464
+ to_return({ :body => {
465
+ :type => 'cartridges',
466
+ :data => []
467
+ }.to_json,
468
+ :status => 200
469
+ })
470
+ end
471
+ it "returns a list of existing cartridges" do
472
+ carts = client.cartridges
473
+ carts.length.should equal(2)
474
+ (0..1).each do |idx|
475
+ carts[idx].class.should == RHC::Rest::Cartridge
476
+ carts[idx].name.should == "mock_cart_#{idx}"
477
+ carts[idx].type.should == "mock_cart_#{idx}_type"
478
+ carts[idx].send(:links).should ==
479
+ mock_response_links(mock_cart_links("mock_cart_#{idx}"))
480
+ end
481
+ end
482
+ it "caches cartridges on the client" do
483
+ # Disregard the first response; this is for the previous expectiation.
484
+ old = client.cartridges.length
485
+ client.cartridges.length.should equal(old)
486
+ client.instance_variable_set(:@cartridges, nil)
487
+ client.cartridges.length.should equal(0)
488
+ end
489
+ end
490
+
491
+ context "#find_cartridges" do
492
+ before(:each) do
493
+ stub_api_request(:any, api_links['LIST_CARTRIDGES']['relative']).
494
+ to_return({ :body => {
495
+ :type => 'cartridges',
496
+ :data =>
497
+ [{ :name => 'mock_cart_0',
498
+ :type => 'mock_cart_0_type',
499
+ :links => mock_response_links(mock_cart_links('mock_cart_0')),
500
+ },
501
+ { :name => 'mock_cart_1',
502
+ :type => 'mock_cart_1_type',
503
+ :links => mock_response_links(mock_cart_links('mock_cart_1')),
504
+ },
505
+ { :name => 'mock_nomatch_cart_0',
506
+ :type => 'mock_nomatch_cart_0_type',
507
+ :links => mock_response_links(mock_cart_links('mock_nomatch_cart_0')),
508
+ }
509
+ ]
510
+ }.to_json,
511
+ :status => 200
512
+ })
513
+ end
514
+ it "returns a list of cartridge objects for matching cartridges" do
515
+ matches = client.find_cartridges('mock_cart_0')
516
+ matches.length.should equal(1)
517
+ matches[0].class.should == RHC::Rest::Cartridge
518
+ matches[0].name.should == 'mock_cart_0'
519
+ matches[0].type.should == 'mock_cart_0_type'
520
+ matches[0].send(:links).should ==
521
+ mock_response_links(mock_cart_links('mock_cart_0'))
522
+ end
523
+ it "returns an empty list when no matching cartridges can be found" do
524
+ matches = client.find_cartridges('no_match')
525
+ matches.length.should equal(0)
526
+ end
527
+ it "returns multiple cartridge matches" do
528
+ matches = client.find_cartridges :regex => "mock_cart_[0-9]"
529
+ matches.length.should equal(2)
530
+ end
531
+ end
532
+
533
+ context "#user" do
534
+ before(:each) do
535
+ stub_api_request(:any, api_links['GET_USER']['relative']).
536
+ to_return({ :body => {
537
+ :type => 'user',
538
+ :data =>
539
+ { :login => mock_user,
540
+ :links => mock_response_links(mock_user_links)
541
+ }
542
+ }.to_json,
543
+ :status => 200
544
+ })
545
+ end
546
+ it "returns the user object associated with this client connection" do
547
+ user = client.user
548
+ user.class.should == RHC::Rest::User
549
+ user.login.should == mock_user
550
+ user.send(:links).should == mock_response_links(mock_user_links)
551
+ end
552
+ end
553
+
554
+ context "#find_key" do
555
+ before(:each) do
556
+ stub_api_request(:any, api_links['GET_USER']['relative']).
557
+ to_return({ :body => {
558
+ :type => 'user',
559
+ :data =>
560
+ { :login => mock_user,
561
+ :links => mock_response_links(mock_user_links)
562
+ }
563
+ }.to_json,
564
+ :status => 200
565
+ })
566
+ stub_api_request(:any, user_links['LIST_KEYS']['relative']).
567
+ to_return({ :body => {
568
+ :type => 'keys',
569
+ :data =>
570
+ [{ :name => 'mock_key_0',
571
+ :type => 'mock_key_0_type',
572
+ :content => '123456789:0',
573
+ :links => mock_response_links(mock_key_links('mock_key_0'))
574
+ },
575
+ { :name => 'mock_key_1',
576
+ :type => 'mock_key_1_type',
577
+ :content => '123456789:1',
578
+ :links => mock_response_links(mock_key_links('mock_key_1'))
579
+ }]
580
+ }.to_json,
581
+ :status => 200
582
+ })
583
+ end
584
+ it "returns a list of key objects for matching keys" do
585
+ key = nil
586
+ expect { key = client.find_key('mock_key_0') }.to_not raise_error
587
+
588
+ key.class.should == RHC::Rest::Key
589
+ key.name.should == 'mock_key_0'
590
+ key.type.should == 'mock_key_0_type'
591
+ key.content.should == '123456789:0'
592
+ key.send(:links).should ==
593
+ mock_response_links(mock_key_links('mock_key_0'))
594
+ end
595
+ it "raise an error when no matching keys can be found" do
596
+ expect { client.find_key('no_match') }.to raise_error(RHC::KeyNotFoundException)
597
+ end
598
+ end
599
+
600
+ context "#delete_key" do
601
+ before(:each) do
602
+ stub_api_request(:any, api_links['GET_USER']['relative']).
603
+ to_return({ :body => {
604
+ :type => 'user',
605
+ :data =>
606
+ { :login => mock_user,
607
+ :links => mock_response_links(mock_user_links)
608
+ }
609
+ }.to_json,
610
+ :status => 200
611
+ })
612
+ stub_api_request(:any, user_links['LIST_KEYS']['relative']).
613
+ to_return({ :body => {
614
+ :type => 'keys',
615
+ :data =>
616
+ [{ :name => 'mock_key_0',
617
+ :type => 'mock_key_0_type',
618
+ :content => '123456789:0',
619
+ :links => mock_response_links(mock_key_links('mock_key_0'))
620
+ },
621
+ { :name => 'mock_key_1',
622
+ :type => 'mock_key_1_type',
623
+ :content => '123456789:1',
624
+ :links => mock_response_links(mock_key_links('mock_key_1'))
625
+ }]
626
+ }.to_json,
627
+ :status => 200
628
+ })
629
+
630
+ stub_api_request(:post, key_links['DELETE']['relative']).
631
+ to_return({ :body => {}.to_json,
632
+ :status => 200
633
+ })
634
+ end
635
+
636
+ it "should delete keys" do
637
+ expect { client.delete_key('mock_key_0') }.to be_true
638
+ end
639
+
640
+ it 'raises an error if nonexistent key is requested' do
641
+ expect { client.find_key('no_match') }.to raise_error(RHC::KeyNotFoundException)
642
+ end
643
+ end
644
+ end
645
+
646
+ context "when server supports API versions 1.0 and 1.1" do
647
+ before :each do
648
+ stub_api_request(:get, '').
649
+ to_return({ :body => {
650
+ :data => api_links,
651
+ :supported_api_versions => [1.0, 1.1]
652
+ }.to_json,
653
+ :status => 200
654
+ })
655
+ end
656
+
657
+ context "when client supports API version 1.1" do
658
+ let(:spec_versions){ [1.1] }
659
+
660
+ describe "#api_version_negotiated" do
661
+ it "returns 1.1" do
662
+ client.api.api_version_negotiated.to_s.should == '1.1'
663
+ end
664
+ end
665
+ end
666
+
667
+ context "when client supports only API version 1.2" do
668
+ let(:spec_versions){ [1.2] }
669
+
670
+ describe "#api_version_negotiated" do
671
+ it 'returns nil' do
672
+ client.api.api_version_negotiated.should be_nil
673
+ end
674
+ end
675
+ end
676
+
677
+ context "when client supports only API version 0.9" do
678
+ describe "#new" do
679
+ let(:spec_versions){ [0.9] }
680
+ it "warns user that it is outdated" do
681
+ capture do
682
+ client.api
683
+ @output.rewind
684
+ @output.read.should =~ /client version may be outdated/
685
+ end
686
+ end
687
+ end
688
+ end
689
+ end
690
+
691
+ describe "#supports_sessions?" do
692
+ before{ subject.should_receive(:api).at_least(2).times.and_return(double) }
693
+ context "with ADD_AUTHORIZATION link" do
694
+ before{ subject.api.should_receive(:supports?).with('ADD_AUTHORIZATION').and_return(true) }
695
+ its(:supports_sessions?){ should be_true }
696
+ end
697
+ context "without ADD_AUTHORIZATION link" do
698
+ before{ subject.api.should_receive(:supports?).with('ADD_AUTHORIZATION').and_return(false) }
699
+ its(:supports_sessions?){ should be_false }
700
+ end
701
+ end
702
+
703
+ describe "#authorizations" do
704
+ before do
705
+ stub_api_request(:get, '').to_return({:body => {
706
+ :data => mock_response_links(mock_api_with_authorizations),
707
+ :supported_api_versions => [1.0, 1.1]
708
+ }.to_json,
709
+ :status => 200
710
+ })
711
+ stub_authorizations
712
+ end
713
+ it{ client.authorizations.first.token.should == 'a_token_value' }
714
+ it{ client.authorizations.first.note.should == 'an_authorization' }
715
+ it{ client.authorizations.first.expires_in_seconds.should == 60 }
716
+ end
717
+ end
718
+ end
719
+ end
720
+
721
+ module RHC
722
+ module Rest
723
+ describe HTTPClient do
724
+ end
725
+
726
+ describe WWWAuth::DeferredCredential do
727
+ subject{ described_class.new(nil, nil) }
728
+ its(:user){ should be_nil }
729
+ its(:passwd){ should be_nil }
730
+
731
+ context "with a username and password" do
732
+ subject{ described_class.new(username, password) }
733
+ let(:username){ 'a_user' }
734
+ let(:password){ 'a_password' }
735
+
736
+ its(:user){ should == username }
737
+ its(:passwd){ should == password }
738
+ its(:to_str){ should == ["#{username}:#{password}"].pack('m').tr("\n", '') }
739
+ end
740
+
741
+ context "with a deferred username and password" do
742
+ subject{ described_class.new(username, password) }
743
+ let(:username){ lambda{ 'a_user' } }
744
+ let(:password){ lambda{ 'a_password' } }
745
+
746
+ its(:user){ should == username.call }
747
+ its(:passwd){ should == password.call }
748
+ its(:to_str){ should == ["#{username.call}:#{password.call}"].pack('m').tr("\n", '') }
749
+ end
750
+ end
751
+ end
752
+ end