rhc 1.6.8 → 1.7.8

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 (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