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,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
+