rhc 1.6.8 → 1.7.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. data/autocomplete/rhc_bash +1167 -0
  2. data/features/README.md +1 -1
  3. data/features/domain.feature +1 -1
  4. data/features/lib/rhc_helper/persistable.rb +4 -1
  5. data/features/multiple_cartridge.feature +4 -3
  6. data/features/sshkey.feature +3 -3
  7. data/features/support/assumptions.rb +3 -3
  8. data/features/support/env.rb +10 -0
  9. data/features/support/platform_support.rb +2 -2
  10. data/lib/rhc.rb +6 -0
  11. data/lib/rhc/auth/token.rb +4 -0
  12. data/lib/rhc/autocomplete.rb +50 -52
  13. data/lib/rhc/autocomplete_templates/{rhc.erb → bash.erb} +8 -2
  14. data/lib/rhc/cartridge_helpers.rb +1 -1
  15. data/lib/rhc/cli.rb +1 -7
  16. data/lib/rhc/command_runner.rb +45 -16
  17. data/lib/rhc/commands.rb +75 -55
  18. data/lib/rhc/commands/account.rb +7 -51
  19. data/lib/rhc/commands/alias.rb +26 -17
  20. data/lib/rhc/commands/app.rb +75 -39
  21. data/lib/rhc/commands/authorization.rb +4 -2
  22. data/lib/rhc/commands/base.rb +31 -29
  23. data/lib/rhc/commands/cartridge.rb +66 -44
  24. data/lib/rhc/commands/domain.rb +20 -8
  25. data/lib/rhc/commands/git_clone.rb +3 -3
  26. data/lib/rhc/commands/logout.rb +51 -0
  27. data/lib/rhc/commands/port_forward.rb +15 -11
  28. data/lib/rhc/commands/setup.rb +25 -0
  29. data/lib/rhc/commands/snapshot.rb +20 -10
  30. data/lib/rhc/commands/sshkey.rb +21 -7
  31. data/lib/rhc/commands/tail.rb +2 -2
  32. data/lib/rhc/commands/threaddump.rb +2 -2
  33. data/lib/rhc/context_helper.rb +0 -4
  34. data/lib/rhc/core_ext.rb +96 -76
  35. data/lib/rhc/exceptions.rb +6 -0
  36. data/lib/rhc/help_formatter.rb +19 -2
  37. data/lib/rhc/helpers.rb +32 -194
  38. data/lib/rhc/highline_extensions.rb +412 -0
  39. data/lib/rhc/output_helpers.rb +31 -67
  40. data/lib/rhc/rest.rb +4 -2
  41. data/lib/rhc/rest/alias.rb +0 -2
  42. data/lib/rhc/rest/application.rb +9 -4
  43. data/lib/rhc/rest/authorization.rb +0 -2
  44. data/lib/rhc/rest/base.rb +1 -1
  45. data/lib/rhc/rest/client.rb +11 -9
  46. data/lib/rhc/rest/domain.rb +5 -1
  47. data/lib/rhc/rest/gear_group.rb +0 -2
  48. data/lib/rhc/rest/key.rb +0 -2
  49. data/lib/rhc/rest/mock.rb +32 -10
  50. data/lib/rhc/ssh_helpers.rb +2 -2
  51. data/lib/rhc/usage_templates/command_help.erb +20 -13
  52. data/lib/rhc/usage_templates/command_syntax_help.erb +1 -3
  53. data/lib/rhc/usage_templates/help.erb +15 -16
  54. data/lib/rhc/usage_templates/options_help.erb +7 -9
  55. data/lib/rhc/wizard.rb +193 -159
  56. data/spec/rest_spec_helper.rb +2 -2
  57. data/spec/rhc/cli_spec.rb +36 -5
  58. data/spec/rhc/command_spec.rb +94 -42
  59. data/spec/rhc/commands/account_spec.rb +1 -75
  60. data/spec/rhc/commands/alias_spec.rb +28 -28
  61. data/spec/rhc/commands/app_spec.rb +141 -33
  62. data/spec/rhc/commands/apps_spec.rb +4 -4
  63. data/spec/rhc/commands/authorization_spec.rb +8 -8
  64. data/spec/rhc/commands/cartridge_spec.rb +18 -9
  65. data/spec/rhc/commands/domain_spec.rb +16 -16
  66. data/spec/rhc/commands/git_clone_spec.rb +3 -3
  67. data/spec/rhc/commands/logout_spec.rb +86 -0
  68. data/spec/rhc/commands/port_forward_spec.rb +9 -9
  69. data/spec/rhc/commands/server_spec.rb +5 -5
  70. data/spec/rhc/commands/setup_spec.rb +19 -5
  71. data/spec/rhc/commands/snapshot_spec.rb +12 -12
  72. data/spec/rhc/commands/sshkey_spec.rb +11 -11
  73. data/spec/rhc/commands/tail_spec.rb +5 -5
  74. data/spec/rhc/commands/threaddump_spec.rb +3 -3
  75. data/spec/rhc/config_spec.rb +6 -6
  76. data/spec/rhc/helpers_spec.rb +72 -219
  77. data/spec/rhc/highline_extensions_spec.rb +269 -0
  78. data/spec/rhc/rest_application_spec.rb +28 -1
  79. data/spec/rhc/rest_client_spec.rb +20 -21
  80. data/spec/rhc/rest_spec.rb +10 -0
  81. data/spec/rhc/wizard_spec.rb +72 -32
  82. data/spec/spec_helper.rb +86 -56
  83. data/spec/wizard_spec_helper.rb +7 -4
  84. metadata +165 -160
  85. data/spec/spec.opts +0 -1
@@ -0,0 +1,269 @@
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
+
135
+ it "should wrap a table based on a max width" do
136
+ subject.table([["abcd efgh", "1234 6789 a"]], :width => 9, :heading => 'Test').to_a.should == [
137
+ 'Test',
138
+ '----',
139
+ "abcd 1234",
140
+ "efgh 6789",
141
+ " a"
142
+ ]
143
+ end
144
+
145
+ it "should allocate columns fairly in a table" do
146
+ subject.table([["abcd", "12345 67890"]], :width => 10).to_a.should == [
147
+ "abcd 12345",
148
+ " 67890",
149
+ ]
150
+ end
151
+
152
+ it "should not wrap without a width" do
153
+ subject.table([["abcd", "12345 67890"]]).to_a.should == [
154
+ "abcd 12345 67890",
155
+ ]
156
+ end
157
+ it "should implement each_line on the table" do
158
+ subject.table([["abcd", "12345 67890"]]).each_line.next.should == "abcd 12345 67890"
159
+ end
160
+
161
+ it "should display headers" do
162
+ subject.table([["abcd", "12345 67890"]], :header => ['abcdef', '123'], :width => 12).to_a.should == [
163
+ 'abcdef 123',
164
+ '------ -----',
165
+ "abcd 12345",
166
+ " 67890",
167
+ ]
168
+ end
169
+
170
+ it "should add a header to a table" do
171
+ subject.table([["abcd efgh", "1234 6789 a"]], :width => 9, :heading => "Alongtextstring").to_a.should == [
172
+ "Alongtext",
173
+ "string",
174
+ "---------",
175
+ "abcd 1234",
176
+ "efgh 6789",
177
+ " a"
178
+ ]
179
+ end
180
+
181
+ it "should indent a table" do
182
+ subject.table([["abcd efgh", "1234 6789 a"]], :indent => ' ', :width => 10).to_a.should == [
183
+ " abcd 1234",
184
+ " efgh 6789",
185
+ " a"
186
+ ]
187
+ end
188
+
189
+ it "should not wrap table when not enough minimum width" do
190
+ subject.table([["ab cd", "12 34"]], :width => 4).to_a.should == [
191
+ "ab cd 12 34",
192
+ ]
193
+ end
194
+
195
+ it "should not wrap table cells that are too wide based on a max width" do
196
+ subject.table([["abcdefgh", "1234567890"]], :width => 8).to_a.should == [
197
+ "abcdefgh 1234567890",
198
+ ]
199
+ end
200
+
201
+ it "should force wrap a table based on columns" do
202
+ subject.table([["ab cd", "123"]], :width => [6, 2]).to_a.should == [
203
+ "ab 123",
204
+ "cd",
205
+ ]
206
+ end
207
+
208
+ context "sections" do
209
+ let(:tests) { OutputTests.new(subject) }
210
+
211
+ it "should print out a paragraph with open endline on the same line" do
212
+ tests.section_same_line
213
+ subject.read.should == "section 1 word\n"
214
+ end
215
+
216
+ it "should print out a section without any line breaks" do
217
+ tests.section_no_breaks
218
+ subject.read.should == "section 1 \n"
219
+ end
220
+
221
+ it "should print out a section with trailing line break" do
222
+ tests.section_one_break
223
+ subject.read.should == "section 1\n"
224
+ end
225
+
226
+ it "should print out 2 sections with matching bottom and top margins generating one space between" do
227
+ tests.sections_equal_bottom_top
228
+ subject.read.should == "section 1\n\nsection 2\n"
229
+ end
230
+
231
+ it "should print out 2 sections with larger bottom margin generating two spaces between" do
232
+ tests.sections_larger_bottom
233
+ subject.read.should == "section 1\n\n\nsection 2\n"
234
+ end
235
+
236
+ it "should print out 2 sections with larger top margin generating two spaces between" do
237
+ tests.sections_larger_top
238
+ subject.read.should == "section 1\n\n\nsection 2\n"
239
+ end
240
+
241
+ it "should print out 4 sections and not collapse open sections" do
242
+ tests.sections_four_on_three_lines
243
+ subject.read.should == "section 1\n\nsection 2 \nsection 3\n\nsection 4\n"
244
+ end
245
+
246
+ it "should show the equivalence of paragaph to section(:top => 1, :bottom => 1)" do
247
+ tests.section_1_1
248
+ section_1_1 = tests.read
249
+
250
+ tests = OutputTests.new(MockHighLineTerminal.new)
251
+
252
+ tests.section_paragraph
253
+ paragraph = tests.read
254
+
255
+ section_1_1.should == paragraph
256
+ end
257
+ it "should combine sections" do
258
+ tests.section_1_1
259
+ tests.section_paragraph
260
+
261
+ subject.read.should == "section\n\nsection\n"
262
+ end
263
+
264
+ it "should not collapse explicit newline sections" do
265
+ tests.outside_newline
266
+ subject.read.should == "section 1\n\n\nsection 2\n"
267
+ end
268
+ end
269
+ end
@@ -7,13 +7,14 @@ module RHC
7
7
  describe Application do
8
8
  let (:client) { RHC::Rest::Client.new('test.domain.com', 'test_user', 'test pass') }
9
9
  let (:app_links) { mock_response_links(mock_app_links('mock_domain','mock_app')) }
10
+ let (:app_aliases) { ['alias1','alias2'] }
10
11
  let (:app_obj) {
11
12
  args = {
12
13
  'domain_id' => 'mock_domain',
13
14
  'name' => 'mock_app',
14
15
  'creation_time' => Time.now.to_s,
15
16
  'uuid' => 1234,
16
- 'aliases' => ['alias1','alias2'],
17
+ 'aliases' => app_aliases,
17
18
  'server_identity' => mock_uri,
18
19
  'links' => app_links
19
20
  }
@@ -65,6 +66,32 @@ module RHC
65
66
  end
66
67
  end
67
68
 
69
+ context "#aliases" do
70
+ context "when the server returns an array of strings" do
71
+ it{ app_obj.aliases.first.should be_an_instance_of RHC::Rest::Alias }
72
+ it("converts to an object"){ app_obj.aliases.map(&:id).should == app_aliases }
73
+ end
74
+
75
+ context "when the server returns an object" do
76
+ let(:app_aliases){ [{'id' => 'alias1'}, {'id' => 'alias2'}] }
77
+ it{ app_obj.aliases.first.should be_an_instance_of RHC::Rest::Alias }
78
+ it{ app_obj.aliases.map(&:id).should == ['alias1', 'alias2'] }
79
+ end
80
+
81
+ context "when the server doesn't return aliases" do
82
+ let(:app_aliases){ nil }
83
+ context "when the client supports LIST_ALIASES" do
84
+ before{ stub_api_request(:any, app_links['LIST_ALIASES']['relative']).to_return(mock_alias_response(2)) }
85
+ it{ app_obj.aliases.first.should be_an_instance_of RHC::Rest::Alias }
86
+ it{ app_obj.aliases.map(&:id).should == ['www.alias0.com', 'www.alias1.com'] }
87
+ end
88
+ context "when the client doesn't support LIST_ALIASES" do
89
+ before{ app_links['LIST_ALIASES'] = nil }
90
+ it{ app_obj.aliases.should == [] }
91
+ end
92
+ end
93
+ end
94
+
68
95
  context "#cartridges" do
69
96
  let(:num_carts){ 0 }
70
97
  before(:each) do
@@ -2,7 +2,7 @@ require 'base64'
2
2
  require 'spec_helper'
3
3
  require 'stringio'
4
4
  require 'rest_spec_helper'
5
- require 'rhc/rest/client'
5
+ require 'rhc/rest'
6
6
 
7
7
  # This object is used in a few cases where we need to inspect
8
8
  # the logged output.
@@ -22,24 +22,24 @@ module RHC
22
22
  module Rest
23
23
  describe Client do
24
24
 
25
+ after{ ENV['http_proxy'] = nil }
26
+ after{ ENV['HTTP_PROXY'] = nil }
27
+
25
28
  it 'should set the proxy protocol if it is missing' do
26
29
  ENV['http_proxy'] = 'foo.bar.com:8081'
27
- load 'rhc/rest/client.rb'
28
-
30
+ RHC::Rest::Client.new
29
31
  ENV['http_proxy'].should == 'http://foo.bar.com:8081'
30
32
  end
31
33
 
32
34
  it 'should not alter the proxy protocol if it is present' do
33
35
  ENV['http_proxy'] = 'http://foo.bar.com:8081'
34
- load 'rhc/rest/client.rb'
35
-
36
+ RHC::Rest::Client.new
36
37
  ENV['http_proxy'].should == 'http://foo.bar.com:8081'
37
38
  end
38
39
 
39
40
  it 'should not affect the proxy protocol if nil' do
40
41
  ENV['http_proxy'] = nil
41
- load 'rhc/rest/client.rb'
42
-
42
+ RHC::Rest::Client.new
43
43
  ENV['http_proxy'].should be_nil
44
44
  end
45
45
 
@@ -80,13 +80,13 @@ module RHC
80
80
  context "against an endpoint that won't connect" do
81
81
  let(:endpoint){ mock_href('api_error') }
82
82
  it "raises an error message" do
83
- expect{ client.api }.should raise_error
83
+ expect{ client.api }.to raise_error
84
84
  end
85
85
  end
86
86
  context "against an endpoint that has a generic error" do
87
87
  let(:endpoint){ mock_href('other_error') }
88
88
  it "raises a generic error for any other error condition" do
89
- expect{ client.api }.should raise_error(RHC::Rest::ConnectionException, "An unexpected error occured: Other Error")
89
+ expect{ client.api }.to raise_error(RHC::Rest::ConnectionException, "An unexpected error occured: Other Error")
90
90
  end
91
91
  end
92
92
  end
@@ -227,13 +227,13 @@ module RHC
227
227
  end
228
228
  it "returns a domain object for matching domain IDs" do
229
229
  match = nil
230
- expect { match = client.find_domain('mock_domain_0') }.should_not raise_error
230
+ expect { match = client.find_domain('mock_domain_0') }.to_not raise_error
231
231
 
232
232
  match.id.should == 'mock_domain_0'
233
233
  match.class.should == RHC::Rest::Domain
234
234
  end
235
235
  it "raise an error when no matching domain IDs can be found" do
236
- expect { client.find_domain('mock_domain_2') }.should raise_error(RHC::Rest::DomainNotFoundException)
236
+ expect { client.find_domain('mock_domain_2') }.to raise_error(RHC::Rest::DomainNotFoundException)
237
237
  end
238
238
  end
239
239
 
@@ -275,16 +275,16 @@ module RHC
275
275
  mock_response_links(mock_app_links(mock_domain, mock_app))
276
276
  end
277
277
  it "Raises an exception when no matching applications can be found" do
278
- expect { client.find_application(mock_domain, missing) }.should raise_error(RHC::Rest::ApplicationNotFoundException)
278
+ expect { client.find_application(mock_domain, missing) }.to raise_error(RHC::Rest::ApplicationNotFoundException)
279
279
  end
280
280
  it "Raises an exception when no matching domain can be found" do
281
- expect { client.find_application(missing, mock_app) }.should raise_error(RHC::Rest::DomainNotFoundException)
281
+ expect { client.find_application(missing, mock_app) }.to raise_error(RHC::Rest::DomainNotFoundException)
282
282
  end
283
283
  end
284
284
 
285
285
  describe RHC::Rest::Cartridge do
286
286
  subject do
287
- described_class.new({
287
+ RHC::Rest::Cartridge.new({
288
288
  :name => 'foo',
289
289
  :links => mock_response_links([
290
290
  ['GET', 'broker/rest/cartridge', 'get']
@@ -444,7 +444,7 @@ module RHC
444
444
  end
445
445
  it "returns a list of key objects for matching keys" do
446
446
  key = nil
447
- expect { key = client.find_key('mock_key_0') }.should_not raise_error
447
+ expect { key = client.find_key('mock_key_0') }.to_not raise_error
448
448
 
449
449
  key.class.should == RHC::Rest::Key
450
450
  key.name.should == 'mock_key_0'
@@ -454,7 +454,7 @@ module RHC
454
454
  mock_response_links(mock_key_links('mock_key_0'))
455
455
  end
456
456
  it "raise an error when no matching keys can be found" do
457
- expect { client.find_key('no_match') }.should raise_error(RHC::KeyNotFoundException)
457
+ expect { client.find_key('no_match') }.to raise_error(RHC::KeyNotFoundException)
458
458
  end
459
459
  end
460
460
 
@@ -521,12 +521,11 @@ module RHC
521
521
  end
522
522
 
523
523
  it "should delete keys" do
524
- expect { client.delete_key('mock_key_0') }.should be_true
524
+ expect { client.delete_key('mock_key_0') }.to be_true
525
525
  end
526
526
 
527
527
  it 'raises an error if nonexistent key is requested' do
528
- expect { client.find_key('no_match') }.
529
- should raise_error(RHC::KeyNotFoundException)
528
+ expect { client.find_key('no_match') }.to raise_error(RHC::KeyNotFoundException)
530
529
  end
531
530
  end
532
531
 
@@ -589,11 +588,11 @@ module RHC
589
588
  describe "#supports_sessions?" do
590
589
  before{ subject.should_receive(:api).at_least(2).times.and_return(stub) }
591
590
  context "with ADD_AUTHORIZATION link" do
592
- before{ subject.api.should_receive(:supports?).twice.with('ADD_AUTHORIZATION').and_return(true) }
591
+ before{ subject.api.should_receive(:supports?).with('ADD_AUTHORIZATION').and_return(true) }
593
592
  its(:supports_sessions?){ should be_true }
594
593
  end
595
594
  context "without ADD_AUTHORIZATION link" do
596
- before{ subject.api.should_receive(:supports?).twice.with('ADD_AUTHORIZATION').and_return(false) }
595
+ before{ subject.api.should_receive(:supports?).with('ADD_AUTHORIZATION').and_return(false) }
597
596
  its(:supports_sessions?){ should be_false }
598
597
  end
599
598
  end