startapp 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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