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,314 @@
1
+ require 'spec_helper'
2
+
3
+ class OutputTests < SimpleDelegator
4
+ def initialize(terminal)
5
+ super
6
+ @print_num = 0
7
+ end
8
+
9
+ [:say, :agree, :ask, :choose].each do |sym|
10
+ define_method(sym) do |*args, &block|
11
+ __getobj__.send(sym, *args, &block)
12
+ end
13
+ end
14
+
15
+ def next_print_num
16
+ @print_num += 1
17
+ end
18
+
19
+ def output
20
+ say "section #{next_print_num}"
21
+ end
22
+
23
+ def output_no_breaks
24
+ say "section #{next_print_num} "
25
+ end
26
+
27
+ def section_same_line
28
+ section { output_no_breaks; say 'word' }
29
+ end
30
+
31
+ def section_no_breaks
32
+ section { output_no_breaks }
33
+ end
34
+
35
+ def section_one_break
36
+ section { output }
37
+ end
38
+
39
+ def sections_equal_bottom_top
40
+ section(:bottom => 1) { output }
41
+ section(:top => 1) { output }
42
+ end
43
+
44
+ def sections_larger_bottom
45
+ section(:bottom => 2) { output }
46
+ section(:top => 1) { output }
47
+ end
48
+
49
+ def sections_larger_top
50
+ section(:bottom => 1) { output }
51
+ section(:top => 2) { output }
52
+ end
53
+
54
+ def sections_four_on_three_lines
55
+ section { output }
56
+ section(:top => 1) { output_no_breaks }
57
+ section(:bottom => 1) { output }
58
+ section(:top => 1) { output }
59
+ end
60
+
61
+ def outside_newline
62
+ section(:bottom => -1) { output }
63
+ say "\n"
64
+ section(:top => 1) { output }
65
+ end
66
+
67
+ def section_1_1
68
+ section(:top => 1, :bottom => 1) { say "section" }
69
+ end
70
+
71
+ def section_paragraph
72
+ paragraph { say "section" }
73
+ end
74
+
75
+ # call section without output to reset spacing to 0
76
+ def reset
77
+ __getobj__.instance_variable_set(:@margin, 0)
78
+ end
79
+ end
80
+
81
+
82
+ describe HighLine::Header do
83
+ it("should join a header"){ described_class.new("ab cd", 0).to_a.should == ["ab cd", '-----'] }
84
+ it("should wrap a header"){ described_class.new("ab cd", 4).to_a.should == ["ab", "cd", '--'] }
85
+ it("should wrap an array header"){ described_class.new(["ab cd"], 4).to_a.should == ["ab", "cd", '--'] }
86
+ it("should combine an array header"){ described_class.new(["ab", "cd"], 5).to_a.should == ["ab cd", '-----'] }
87
+ it("should wrap on array header boundaries"){ described_class.new(["abcd", "e"], 5).to_a.should == ["abcd", "e", '----'] }
88
+ it("should indent an array header"){ described_class.new(["ab", "cd"], 4, ' ').to_a.should == ["ab", " cd", '---'] }
89
+ it("should indent after a wrap"){ described_class.new(["ab cd", "ef gh", "ij"], 4, ' ').to_a.should == ["ab", "cd", " ef", " gh", " ij", '---'] }
90
+ end
91
+
92
+ describe HighLineExtension do
93
+ subject{ MockHighLineTerminal.new }
94
+
95
+ it("default_max_width should depend on wrap"){ subject.wrap_at = nil; subject.default_max_width.should be_nil}
96
+ it("default_max_width should handle indentation"){ subject.wrap_at = 10; subject.indent{ subject.default_max_width.should == 10 - subject.indentation.length } }
97
+
98
+ it "should wrap the terminal" do
99
+ subject.wrap_at = 10
100
+ subject.say "Lorem ipsum dolor sit amet"
101
+ output = subject.read
102
+ output.should match "Lorem\nipsum\ndolor sit\namet\n"
103
+ end
104
+ it "should wrap the terminal" do
105
+ subject.wrap_at = 16
106
+ subject.say "Lorem ipsum dolor sit amet"
107
+ output = subject.read
108
+ output.should == "Lorem ipsum\ndolor sit amet\n"
109
+ end
110
+ it "should not wrap the terminal" do
111
+ subject.wrap_at = 50
112
+ subject.say "Lorem ipsum dolor sit amet"
113
+ output = subject.read
114
+ output.should == "Lorem ipsum dolor sit amet\n"
115
+ end
116
+ it "should wrap the terminal when using color codes" do
117
+ subject.wrap_at = 10
118
+ subject.say subject.color("Lorem ipsum", :red)
119
+ output = subject.read
120
+ output.should == "\e[31mLorem\e\[0m\n\e[31mipsum\e[0m\n"
121
+ end
122
+ it "should wrap the terminal with other escape characters" do
123
+ subject.wrap_at = 10
124
+ subject.say "Lorem ipsum dolor sit am\eet"
125
+ output = subject.read
126
+ output.should == "Lorem\nipsum\ndolor sit\nam\eet\n"
127
+ end
128
+ it "should wrap the terminal when words are smaller than wrap length" do
129
+ subject.wrap_at = 3
130
+ subject.say "Antidisestablishmentarianism"
131
+ output = subject.read
132
+ output.should == "Antidisestablishmentarianism\n"
133
+ end
134
+ it "should terminate an open line if wrapping occurs" do
135
+ subject.wrap_at = 10
136
+ subject.say "Foo "
137
+ subject.say "Lorem ipsum"
138
+ output = subject.read
139
+ output.should match "Foo \nLorem\nipsum\n"
140
+ end
141
+
142
+ it "should handle an empty table" do
143
+ subject.table([]).to_a.should == []
144
+ end
145
+
146
+ it "should handle a nested empty table" do
147
+ subject.table([[]]).to_a.should == []
148
+ end
149
+
150
+ it "should normalize variables" do
151
+ subject.table([
152
+ ["a", 5],
153
+ [nil, ['a', 'b']],
154
+ ]).to_a.should == [
155
+ "a 5",
156
+ " a",
157
+ " b",
158
+ ]
159
+ end
160
+
161
+ it "should wrap a table based on a max width" do
162
+ subject.table([["abcd efgh", "1234 6789 a"]], :width => 9, :heading => 'Test').to_a.should == [
163
+ 'Test',
164
+ '----',
165
+ "abcd 1234",
166
+ "efgh 6789",
167
+ " a"
168
+ ]
169
+ end
170
+
171
+ # FIXME: Ragged edges still left by the algorithm
172
+ # 104 total width, 1: 32/52, 2: 8/61, 113 total width
173
+ it "should handle when columns are evenly split" do
174
+ subject.table([
175
+ ["#{'a'*32} #{'b'*19}", "#{'c'*8} "*6+"d"*7]
176
+ ], :width => 104).to_a.should == [
177
+ "a"*32+" "+'b'*19+" "+Array.new(5, 'c'*8).join(' '),
178
+ ' '*53+"#{'c'*8} "+'d'*7
179
+ ]
180
+ end
181
+
182
+ it "should allocate columns fairly in a table" do
183
+ subject.table([["abcd", "12345 67890"]], :width => 10).to_a.should == [
184
+ "abcd 12345",
185
+ " 67890",
186
+ ]
187
+ end
188
+
189
+ it "should not wrap without a width" do
190
+ subject.table([["abcd", "12345 67890"]]).to_a.should == [
191
+ "abcd 12345 67890",
192
+ ]
193
+ end
194
+ it "should implement each_line on the table" do
195
+ subject.table([["abcd", "12345 67890"]]).each_line.next.should == "abcd 12345 67890"
196
+ end
197
+
198
+ it "should display headers" do
199
+ subject.table([["abcd", "12345 67890"]], :header => ['abcdef', '123'], :width => 12).to_a.should == [
200
+ 'abcdef 123',
201
+ '------ -----',
202
+ "abcd 12345",
203
+ " 67890",
204
+ ]
205
+ end
206
+
207
+ it "should give the header priority over width when color is involved" do
208
+ subject.table([["\e[31mabcd\e[0m", "1234567890"]], :header => ['abcdef', '123'], :width => 12).to_a.should == [
209
+ 'abcdef 123',
210
+ '------ ----------',
211
+ "\e[31mabcd\e[0m 1234567890",
212
+ ]
213
+ end
214
+
215
+ it "should add a header to a table" do
216
+ subject.table([["abcd efgh", "1234 6789 a"]], :width => 9, :heading => "Alongtextstring").to_a.should == [
217
+ "Alongtext",
218
+ "string",
219
+ "---------",
220
+ "abcd 1234",
221
+ "efgh 6789",
222
+ " a"
223
+ ]
224
+ end
225
+
226
+ it "should indent a table" do
227
+ subject.table([["abcd efgh", "1234 6789 a"]], :indent => ' ', :width => 10).to_a.should == [
228
+ " abcd 1234",
229
+ " efgh 6789",
230
+ " a"
231
+ ]
232
+ end
233
+
234
+ it "should not wrap table when not enough minimum width" do
235
+ subject.table([["ab cd", "12 34"]], :width => 4).to_a.should == [
236
+ "ab cd 12 34",
237
+ ]
238
+ end
239
+
240
+ it "should not wrap table cells that are too wide based on a max width" do
241
+ subject.table([["abcdefgh", "1234567890"]], :width => 8).to_a.should == [
242
+ "abcdefgh 1234567890",
243
+ ]
244
+ end
245
+
246
+ it "should force wrap a table based on columns" do
247
+ subject.table([["ab cd", "123"]], :width => [6, 2]).to_a.should == [
248
+ "ab 123",
249
+ "cd",
250
+ ]
251
+ end
252
+
253
+ context "sections" do
254
+ let(:tests) { OutputTests.new(subject) }
255
+
256
+ it "should print out a paragraph with open endline on the same line" do
257
+ tests.section_same_line
258
+ subject.read.should == "section 1 word\n"
259
+ end
260
+
261
+ it "should print out a section without any line breaks" do
262
+ tests.section_no_breaks
263
+ subject.read.should == "section 1 \n"
264
+ end
265
+
266
+ it "should print out a section with trailing line break" do
267
+ tests.section_one_break
268
+ subject.read.should == "section 1\n"
269
+ end
270
+
271
+ it "should print out 2 sections with matching bottom and top margins generating one space between" do
272
+ tests.sections_equal_bottom_top
273
+ subject.read.should == "section 1\n\nsection 2\n"
274
+ end
275
+
276
+ it "should print out 2 sections with larger bottom margin generating two spaces between" do
277
+ tests.sections_larger_bottom
278
+ subject.read.should == "section 1\n\n\nsection 2\n"
279
+ end
280
+
281
+ it "should print out 2 sections with larger top margin generating two spaces between" do
282
+ tests.sections_larger_top
283
+ subject.read.should == "section 1\n\n\nsection 2\n"
284
+ end
285
+
286
+ it "should print out 4 sections and not collapse open sections" do
287
+ tests.sections_four_on_three_lines
288
+ subject.read.should == "section 1\n\nsection 2 \nsection 3\n\nsection 4\n"
289
+ end
290
+
291
+ it "should show the equivalence of paragaph to section(:top => 1, :bottom => 1)" do
292
+ tests.section_1_1
293
+ section_1_1 = tests.read
294
+
295
+ tests = OutputTests.new(MockHighLineTerminal.new)
296
+
297
+ tests.section_paragraph
298
+ paragraph = tests.read
299
+
300
+ section_1_1.should == paragraph
301
+ end
302
+ it "should combine sections" do
303
+ tests.section_1_1
304
+ tests.section_paragraph
305
+
306
+ subject.read.should == "section\n\nsection\n"
307
+ end
308
+
309
+ it "should not collapse explicit newline sections" do
310
+ tests.outside_newline
311
+ subject.read.should == "section 1\n\n\nsection 2\n"
312
+ end
313
+ end
314
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+ require 'rhc/json'
3
+
4
+ describe RHC::Json do
5
+
6
+ context 'with simple decoded hash as a string' do
7
+ subject { RHC::Json.decode '{"abc":[123,-456.789e0],"def":[456,-456.789e0],"ghi":"ghj"}' }
8
+ its(:length) { should == 3 }
9
+ it('should contain key') { subject.has_key?("abc").should be_true }
10
+ it('should contain key') { subject.has_key?("def").should be_true }
11
+ it('should contain key') { subject.has_key?("ghi").should be_true }
12
+ it('should not contain invalid key') { subject.has_key?("ghj").should be_false }
13
+ it('should contain value for key') { subject.has_value?("ghj").should be_true }
14
+ it('should contain array value') { subject["abc"].is_a?(Array).should be_true }
15
+ it('should contain array with two elements') { subject["abc"].length.should == 2 }
16
+ it('should contain array with an integer') { subject["abc"][0].should == 123 }
17
+ it('should contain array with a float') { subject["abc"][1].should == -456.789e0 }
18
+ end
19
+
20
+ context 'with simple hash' do
21
+ subject { RHC::Json.encode({"key" => "value"}) }
22
+ it('should encode to proper json') { subject.should == '{"key":"value"}' }
23
+ it('should encode and decode to the same hash') { RHC::Json.decode(subject).should == {"key" => "value"} }
24
+ it('should decode and encode to the same string') { RHC::Json.encode(RHC::Json.decode('{"x":"y"}')).should == '{"x":"y"}' }
25
+ it('should decode symbol keys') { RHC::Json.decode('{"key":"ok"}', {:symbolize_keys => true}).has_key?(:key).should be_true }
26
+ it('should decode symbol keys') { RHC::Json.decode('{"key":"ok"}', {:symbolize_keys => true})[:key].should == "ok" }
27
+ it('should encode symbol keys') { RHC::Json.encode({:key => "ok"}).should == '{"key":"ok"}' }
28
+ end
29
+
30
+ end
@@ -0,0 +1,258 @@
1
+ require 'spec_helper'
2
+ require 'rest_spec_helper'
3
+ require 'base64'
4
+
5
+ module RHC
6
+ module Rest
7
+ describe Application do
8
+ let (:client) { RHC::Rest::Client.new('test.domain.com', 'test_user', 'test pass') }
9
+ let (:app_links) { mock_response_links(mock_app_links('mock_domain','mock_app')) }
10
+ let (:app_aliases) { ['alias1','alias2'] }
11
+ let (:app_obj) {
12
+ args = {
13
+ 'domain_id' => 'mock_domain',
14
+ 'name' => 'mock_app',
15
+ 'creation_time' => Time.now.to_s,
16
+ 'uuid' => 1234,
17
+ 'aliases' => app_aliases,
18
+ 'server_identity' => mock_uri,
19
+ 'links' => app_links
20
+ }
21
+ args.merge!(attributes) if defined?(attributes)
22
+ RHC::Rest::Application.new(args, client)
23
+ }
24
+ context "#new" do
25
+ it "returns an application object" do
26
+ app = app_obj
27
+ app.should be_an_instance_of RHC::Rest::Application
28
+ app.send(:links).length.should equal(app_links.length)
29
+ end
30
+ end
31
+
32
+ describe "#ssh_string" do
33
+ context "with valid url" do
34
+ subject{ described_class.new('ssh_url' => "ssh://foo@bar.com/path") }
35
+ its(:ssh_string){ should == "foo@bar.com" }
36
+ end
37
+ context "with bad url" do
38
+ subject{ described_class.new('ssh_url' => "ssh://") }
39
+ its(:ssh_string){ should == "ssh://" }
40
+ end
41
+ end
42
+
43
+ describe "#host" do
44
+ context "with bad url" do
45
+ subject{ described_class.new('app_url' => "http://") }
46
+ its(:app_url){ should == "http://" }
47
+ its(:host){ should be_nil }
48
+ end
49
+ context "with http url" do
50
+ subject{ described_class.new('app_url' => "http://bar.com/path") }
51
+ its(:app_url){ should == "http://bar.com/path" }
52
+ its(:host){ should == "bar.com" }
53
+ end
54
+ end
55
+
56
+ context "#add_cartridge" do
57
+ context "with a name" do
58
+ before{ stub_api_request(:any, app_links['ADD_CARTRIDGE']['relative'], false).with(:body => {:name => 'mock_cart_0'}.to_json).to_return(mock_cartridge_response) }
59
+ it "accepts a string" do
60
+ cart = app_obj.add_cartridge('mock_cart_0')
61
+ cart.should be_an_instance_of RHC::Rest::Cartridge
62
+ cart.name.should == 'mock_cart_0'
63
+ end
64
+ it "accepts an object" do
65
+ cart = app_obj.add_cartridge(double(:name => 'mock_cart_0', :url => nil))
66
+ cart.should be_an_instance_of RHC::Rest::Cartridge
67
+ cart.name.should == 'mock_cart_0'
68
+ end
69
+ it "accepts a hash" do
70
+ cart = app_obj.add_cartridge(:name => 'mock_cart_0')
71
+ cart.should be_an_instance_of RHC::Rest::Cartridge
72
+ cart.name.should == 'mock_cart_0'
73
+ end
74
+ end
75
+
76
+ context "with a URL cart" do
77
+ before{ stub_api_request(:any, app_links['ADD_CARTRIDGE']['relative'], false).with(:body => {:url => 'http://foo.com'}.to_json).to_return(mock_cartridge_response(1, true)) }
78
+ it "raises without a param" do
79
+ app_obj.should_receive(:has_param?).with('ADD_CARTRIDGE','url').and_return(false)
80
+ expect{ app_obj.add_cartridge({:url => 'http://foo.com'}) }.to raise_error(RHC::Rest::DownloadingCartridgesNotSupported)
81
+ end
82
+ it "accepts a hash" do
83
+ app_obj.should_receive(:has_param?).with('ADD_CARTRIDGE','url').and_return(true)
84
+ cart = app_obj.add_cartridge({:url => 'http://foo.com'})
85
+ cart.should be_an_instance_of RHC::Rest::Cartridge
86
+ cart.name.should == 'mock_cart_0'
87
+ cart.url.should == 'http://a.url/0'
88
+ cart.short_name.should == 'mock_cart_0'
89
+ cart.display_name.should == 'mock_cart_0'
90
+ cart.only_in_new?.should be_true
91
+ cart.only_in_existing?.should be_false
92
+ end
93
+ it "accepts an object" do
94
+ app_obj.should_receive(:has_param?).with('ADD_CARTRIDGE','url').and_return(true)
95
+ cart = app_obj.add_cartridge(double(:url => 'http://foo.com'))
96
+ cart.should be_an_instance_of RHC::Rest::Cartridge
97
+ cart.name.should == 'mock_cart_0'
98
+ cart.url.should == 'http://a.url/0'
99
+ cart.short_name.should == 'mock_cart_0'
100
+ cart.display_name.should == 'mock_cart_0'
101
+ cart.only_in_new?.should be_true
102
+ cart.only_in_existing?.should be_false
103
+ end
104
+ end
105
+ end
106
+
107
+ context "#aliases" do
108
+ context "when the server returns an array of strings" do
109
+ it{ app_obj.aliases.first.should be_an_instance_of RHC::Rest::Alias }
110
+ it("converts to an object"){ app_obj.aliases.map(&:id).should == app_aliases }
111
+ end
112
+
113
+ context "when the server returns an object" do
114
+ let(:app_aliases){ [{'id' => 'alias1'}, {'id' => 'alias2'}] }
115
+ it{ app_obj.aliases.first.should be_an_instance_of RHC::Rest::Alias }
116
+ it{ app_obj.aliases.map(&:id).should == ['alias1', 'alias2'] }
117
+ end
118
+
119
+ context "when the server doesn't return aliases" do
120
+ let(:app_aliases){ nil }
121
+ context "when the client supports LIST_ALIASES" do
122
+ before{ stub_api_request(:any, app_links['LIST_ALIASES']['relative'], false).to_return(mock_alias_response(2)) }
123
+ it{ app_obj.aliases.first.should be_an_instance_of RHC::Rest::Alias }
124
+ it{ app_obj.aliases.map(&:id).should == ['www.alias0.com', 'www.alias1.com'] }
125
+ end
126
+ context "when the client doesn't support LIST_ALIASES" do
127
+ before{ app_links['LIST_ALIASES'] = nil }
128
+ it{ app_obj.aliases.should == [] }
129
+ end
130
+ end
131
+ end
132
+
133
+ context "#cartridges" do
134
+ let(:num_carts){ 0 }
135
+ before do
136
+ stub_api_request(:any, app_links['LIST_CARTRIDGES']['relative'], false).
137
+ to_return(mock_cartridge_response(num_carts))
138
+ end
139
+ context "with carts" do
140
+ let(:num_carts){ 2 }
141
+ it "returns a list of all cartridges in the current application" do
142
+ app = app_obj
143
+ carts = app.cartridges
144
+ carts.length.should == 2
145
+ (0..1).each do |idx|
146
+ carts[idx].should be_an_instance_of RHC::Rest::Cartridge
147
+ carts[idx].name.should == "mock_cart_#{idx}"
148
+ end
149
+ end
150
+ end
151
+ context "without carts" do
152
+ it "returns an empty list" do
153
+ app = app_obj
154
+ carts = app.cartridges
155
+ carts.length.should == 0
156
+ end
157
+ end
158
+ context "with carts included in initial reponse" do
159
+ let(:attributes){ {:cartridges => RHC::Json.decode(mock_cartridge_response(2)[:body])['data'] }}
160
+ it "returns a list of all cartridges in the current application" do
161
+ app = app_obj
162
+ carts = app.cartridges
163
+ carts.length.should == 2
164
+ (0..1).each do |idx|
165
+ carts[idx].should be_an_instance_of RHC::Rest::Cartridge
166
+ carts[idx].name.should == "mock_cart_#{idx}"
167
+ end
168
+ end
169
+ end
170
+ end
171
+
172
+ context "#gear_groups" do
173
+ before do
174
+ stub_api_request(:any, app_links['GET_GEAR_GROUPS']['relative'], false).
175
+ to_return(mock_gear_groups_response())
176
+ end
177
+ it "returns a list of all gear groups the current application" do
178
+ app = app_obj
179
+ gear_groups = app.gear_groups
180
+ gear_groups.length.should equal(1)
181
+ gear_groups[0].should be_an_instance_of RHC::Rest::GearGroup
182
+ end
183
+ end
184
+
185
+ # These application control tests are subtle; the key lies in making sure the
186
+ # webmock specifies the expected body that is sent in the request.
187
+ # This is currently of the form "event=foo"
188
+ shared_examples_for "a control method" do
189
+ before do
190
+ @control_method = control_data[:method]
191
+ @control_call = [@control_method]
192
+ if control_data.has_key?(:arg)
193
+ @control_call << control_data[:arg]
194
+ end
195
+ @control_event = control_data.has_key?(:event) ? control_data[:event] : @control_method.to_s
196
+ @control_link = control_data.has_key?(:link) ? control_data[:link].upcase : @control_method.to_s.upcase
197
+ @control_output = control_data.has_key?(:result) ? control_data[:result] : @control_event
198
+ @with_payload = control_data.has_key?(:payload) ? control_data[:payload] : true
199
+ if @with_payload
200
+ stub_api_request(:any, app_links[@control_link]['relative'], false).
201
+ with(:body => { 'event' => @control_event }). # This is the critical part
202
+ to_return({ :body => { :data => @control_event }.to_json, :status => 200 })
203
+ else
204
+ stub_api_request(:any, app_links[@control_link]['relative'], false).
205
+ to_return({ :body => { :data => @control_event }.to_json, :status => 200 })
206
+ end
207
+ end
208
+ it "sends the control request to the server" do
209
+ app = app_obj
210
+ expect { app.send(*@control_call) }.to_not raise_error
211
+ app.send(*@control_call).should == @control_output
212
+ end
213
+ end
214
+
215
+ context "#start" do
216
+ let(:control_data) { { :method => :start } }
217
+ it_should_behave_like "a control method"
218
+ end
219
+
220
+ context "#stop" do
221
+ context " and the request is not forced (force == false)" do
222
+ let(:control_data) { { :method => :stop } }
223
+ it_should_behave_like "a control method"
224
+ end
225
+ context " and the request is forced (force == true)" do
226
+ let(:control_data) { { :method => :stop, :arg => true, :event => 'force-stop', :link => 'stop' } }
227
+ it_should_behave_like "a control method"
228
+ end
229
+ end
230
+
231
+ context "#restart" do
232
+ let(:control_data) { { :method => :restart } }
233
+ it_should_behave_like "a control method"
234
+ end
235
+
236
+ context "#delete" do
237
+ let(:control_data) { { :method => :delete, :payload => false } }
238
+ it_should_behave_like "a control method"
239
+ end
240
+
241
+ context "#destroy" do
242
+ let(:control_data) { { :method => :destroy, :event => 'delete', :link => 'delete', :payload => false } }
243
+ it_should_behave_like "a control method"
244
+ end
245
+
246
+ context "#scale_up" do
247
+ let(:control_data) { { :method => :scale_up, :event => 'scale-up', :link => 'scale_up', :payload => false } }
248
+ it_should_behave_like "a control method"
249
+ end
250
+
251
+ context "#scale_down" do
252
+ let(:control_data) { { :method => :scale_down, :event => 'scale-down', :link => 'scale_down', :payload => false } }
253
+ it_should_behave_like "a control method"
254
+ end
255
+ end
256
+ end
257
+ end
258
+