vmc 0.5.0.beta.7 → 0.5.0.beta.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/LICENSE +1277 -746
  2. data/Rakefile +22 -23
  3. data/lib/vmc/cli.rb +21 -27
  4. data/lib/vmc/cli/app/push.rb +1 -0
  5. data/lib/vmc/cli/app/push/create.rb +3 -2
  6. data/lib/vmc/cli/app/push/sync.rb +11 -8
  7. data/lib/vmc/cli/app/scale.rb +19 -17
  8. data/lib/vmc/cli/domain/map.rb +55 -0
  9. data/lib/vmc/cli/domain/unmap.rb +56 -0
  10. data/lib/vmc/cli/route/map.rb +74 -0
  11. data/lib/vmc/cli/route/unmap.rb +94 -0
  12. data/lib/vmc/cli/service/create.rb +4 -1
  13. data/lib/vmc/cli/start/base.rb +2 -2
  14. data/lib/vmc/cli/start/login.rb +5 -2
  15. data/lib/vmc/cli/start/target.rb +4 -3
  16. data/lib/vmc/cli/user/base.rb +19 -0
  17. data/lib/vmc/cli/user/passwd.rb +7 -19
  18. data/lib/vmc/cli/{start → user}/register.rb +12 -23
  19. data/lib/vmc/constants.rb +1 -1
  20. data/lib/vmc/test_support.rb +4 -0
  21. data/lib/vmc/test_support/command_helper.rb +38 -0
  22. data/{spec/support → lib/vmc/test_support}/common_input_examples.rb +0 -0
  23. data/lib/vmc/test_support/fake_home_dir.rb +16 -0
  24. data/lib/vmc/test_support/interact_helper.rb +29 -0
  25. data/lib/vmc/version.rb +1 -1
  26. data/spec/features/new_user_flow_spec.rb +43 -51
  27. data/spec/spec_helper.rb +24 -12
  28. data/spec/vmc/cli/app/instances_spec.rb +3 -8
  29. data/spec/vmc/cli/app/push/create_spec.rb +10 -7
  30. data/spec/vmc/cli/app/push_spec.rb +1 -1
  31. data/spec/vmc/cli/app/rename_spec.rb +1 -1
  32. data/spec/vmc/cli/app/scale_spec.rb +81 -0
  33. data/spec/vmc/cli/app/stats_spec.rb +3 -7
  34. data/spec/vmc/cli/domain/map_spec.rb +140 -0
  35. data/spec/vmc/cli/domain/unmap_spec.rb +73 -0
  36. data/spec/vmc/cli/organization/orgs_spec.rb +13 -16
  37. data/spec/vmc/cli/organization/rename_spec.rb +1 -1
  38. data/spec/vmc/cli/route/map_spec.rb +142 -0
  39. data/spec/vmc/cli/route/unmap_spec.rb +215 -0
  40. data/spec/vmc/cli/service/rename_spec.rb +1 -1
  41. data/spec/vmc/cli/space/rename_spec.rb +15 -18
  42. data/spec/vmc/cli/space/spaces_spec.rb +18 -25
  43. data/spec/vmc/cli/start/info_spec.rb +44 -46
  44. data/spec/vmc/cli/start/login_spec.rb +40 -0
  45. data/spec/vmc/cli/user/create_spec.rb +54 -0
  46. data/spec/vmc/cli/user/passwd_spec.rb +7 -14
  47. data/spec/vmc/cli/{start → user}/register_spec.rb +26 -22
  48. data/spec/vmc/cli_spec.rb +164 -6
  49. metadata +46 -39
  50. data/lib/vmc/cli/app/routes.rb +0 -100
  51. data/lib/vmc/cli/domain/add_domain.rb +0 -25
  52. data/lib/vmc/cli/domain/create_domain.rb +0 -28
  53. data/lib/vmc/cli/domain/delete_domain.rb +0 -56
  54. data/lib/vmc/cli/domain/remove_domain.rb +0 -28
  55. data/lib/vmc/cli/route/create_route.rb +0 -49
  56. data/lib/vmc/cli/route/delete.rb +0 -47
  57. data/spec/support/feature_helpers.rb +0 -16
  58. data/spec/support/interact_helpers.rb +0 -27
  59. data/spec/vmc/cli/route/delete_route_spec.rb +0 -162
@@ -21,9 +21,7 @@ describe VMC::Organization::Orgs do
21
21
  end
22
22
 
23
23
  subject do
24
- with_output_to output do
25
- Mothership.new.invoke(:orgs, inputs, given, global)
26
- end
24
+ capture_output { Mothership.new.invoke(:orgs, inputs, given, global) }
27
25
  end
28
26
 
29
27
  describe 'metadata' do
@@ -47,10 +45,9 @@ describe VMC::Organization::Orgs do
47
45
 
48
46
  it 'should have the correct first two lines' do
49
47
  subject
50
-
51
- output.rewind
52
- expect(output.readline).to match /Getting organizations.*OK/
53
- expect(output.readline).to eq "\n"
48
+ stdout.rewind
49
+ expect(stdout.readline).to match /Getting organizations.*OK/
50
+ expect(stdout.readline).to eq "\n"
54
51
  end
55
52
 
56
53
  context 'when there are no orgnaizations' do
@@ -71,9 +68,9 @@ describe VMC::Organization::Orgs do
71
68
  it 'should show only the progress' do
72
69
  subject
73
70
 
74
- output.rewind
75
- expect(output.readline).to match /Getting organizations.*OK/
76
- expect(output).to be_eof
71
+ stdout.rewind
72
+ expect(stdout.readline).to match /Getting organizations.*OK/
73
+ expect(stdout).to be_eof
77
74
  end
78
75
  end
79
76
  end
@@ -96,15 +93,15 @@ describe VMC::Organization::Orgs do
96
93
  it 'displays tabular output with names, spaces and domains' do
97
94
  subject
98
95
 
99
- output.rewind
100
- output.readline
101
- output.readline
96
+ stdout.rewind
97
+ stdout.readline
98
+ stdout.readline
102
99
 
103
- expect(output.readline).to match /name\s+spaces\s+domains/
100
+ expect(stdout.readline).to match /name\s+spaces\s+domains/
104
101
  organizations.sort_by(&:name).each do |org|
105
- expect(output.readline).to match /#{org.name}\s+#{name_list(org.spaces)}\s+#{name_list(org.domains)}/
102
+ expect(stdout.readline).to match /#{org.name}\s+#{name_list(org.spaces)}\s+#{name_list(org.domains)}/
106
103
  end
107
- expect(output).to be_eof
104
+ expect(stdout).to be_eof
108
105
  end
109
106
  end
110
107
  end
@@ -104,7 +104,7 @@ describe VMC::Organization::Rename do
104
104
 
105
105
  context 'and the name already exists' do
106
106
  it 'fails' do
107
- mock(renamed_organization).update! { raise CFoundry::OrganizationNameTaken.new(nil, nil, "Bad error", 200) }
107
+ mock(renamed_organization).update! { raise CFoundry::OrganizationNameTaken.new("Bad error", 200) }
108
108
  expect { subject }.to raise_error(CFoundry::OrganizationNameTaken)
109
109
  end
110
110
  end
@@ -0,0 +1,142 @@
1
+ require 'spec_helper'
2
+
3
+ describe VMC::Route::Map do
4
+ let(:global) { { :color => false } }
5
+ let(:given) { {} }
6
+ let(:client) { fake_client }
7
+ let!(:cli) { described_class.new }
8
+
9
+ before do
10
+ stub(cli).client { client }
11
+ stub_output(cli)
12
+ end
13
+
14
+ let(:app){ fake(:app, :space => space, :name => "app-name") }
15
+ let(:space) { fake(:space, :name => "space-name", :domains => space_domains) }
16
+ let(:domain) { fake(:domain, :name => domain_name ) }
17
+ let(:domain_name) { "some-domain.com" }
18
+ let(:host_name) { "some-host" }
19
+ let(:url) { "#{host_name}.#{domain_name}" }
20
+ let(:space_domains) { [] }
21
+
22
+ subject { invoke_cli(cli, :map, inputs, given, global) }
23
+
24
+ context 'when targeting v2' do
25
+ shared_examples "mapping the route to the app" do
26
+ context 'and the domain is mapped to the space' do
27
+ let(:space_domains) { [domain] }
28
+
29
+ context 'and the route is mapped to the space' do
30
+ let(:client) { fake_client :routes => [route] }
31
+ let(:route) { fake(:route, :space => space, :host => host_name, :domain => domain) }
32
+
33
+ it 'binds the route to the app' do
34
+ mock(app).add_route(route)
35
+ subject
36
+ end
37
+ end
38
+
39
+ context 'and the route is not mapped to the space' do
40
+ let(:new_route) { fake(:route) }
41
+
42
+ before do
43
+ stub(client).route { new_route }
44
+ stub(app).add_route
45
+ stub(new_route).create!
46
+ end
47
+
48
+ it 'indicates that it is creating a route' do
49
+ mock(cli).print("Creating route #{host_name}.#{domain_name}")
50
+ subject
51
+ end
52
+
53
+ it "creates the route in the app's space" do
54
+ mock(new_route).create!
55
+ subject
56
+ expect(new_route.host).to eq host_name
57
+ expect(new_route.domain).to eq domain
58
+ expect(new_route.space).to eq space
59
+ end
60
+
61
+ it 'indicates that it is binding the route' do
62
+ mock(cli).print("Binding #{host_name}.#{domain_name} to app-name")
63
+ subject
64
+ end
65
+
66
+ it 'binds the route to the app' do
67
+ mock(app).add_route(new_route)
68
+ subject
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ context 'when an app is specified' do
75
+ let(:inputs) { { :url => url, :app => app } }
76
+
77
+ context 'and the domain is not already mapped to the space' do
78
+ it 'indicates that the domain is invalid' do
79
+ expect { subject }.to raise_error(VMC::UserError, /Invalid domain/)
80
+ end
81
+ end
82
+
83
+ include_examples "mapping the route to the app"
84
+ end
85
+
86
+ context 'when a space is specified' do
87
+ let(:inputs) { { :url => url, :space => space } }
88
+
89
+ context 'and the domain is not mapped to the space' do
90
+ it 'indicates that the domain is invalid' do
91
+ expect { subject }.to raise_error(VMC::UserError, /Invalid domain/)
92
+ end
93
+ end
94
+
95
+ context 'and the domain is mapped to the space' do
96
+ let(:domain) { fake(:domain, :client => client, :name => domain_name ) }
97
+ let(:new_route) { fake(:route, :host => "new-route-host") }
98
+
99
+ before do
100
+ stub(client).route { new_route }
101
+ stub(new_route).create!
102
+ stub(space).domain_by_name(domain_name, anything) { domain }
103
+ end
104
+
105
+ context 'and the route does not exist' do
106
+ it 'indicates that it is creating a route' do
107
+ mock(cli).print("Creating route #{host_name}.#{domain_name}")
108
+ subject
109
+ end
110
+
111
+ it 'creates the route in the given space' do
112
+ mock(new_route).create!
113
+ subject
114
+ expect(new_route.host).to eq host_name
115
+ expect(new_route.domain).to eq domain
116
+ expect(new_route.space).to eq space
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ context 'when neither an app nor a space is specified' do
123
+ let(:inputs) { { :url => url } }
124
+ let(:space_domains) { [domain] }
125
+ let(:new_route) { fake(:route) }
126
+
127
+ before { stub_ask("Which application?", anything) { app } }
128
+
129
+ it 'asks for an app' do
130
+ stub(client).route { new_route }
131
+ stub(app).add_route
132
+ stub(new_route).create!
133
+ mock_ask("Which application?", anything) { app }
134
+ subject
135
+ end
136
+
137
+ include_examples "mapping the route to the app"
138
+ end
139
+ end
140
+
141
+ context 'when targeting v1'
142
+ end
@@ -0,0 +1,215 @@
1
+ require 'spec_helper'
2
+
3
+ describe VMC::Route::Unmap do
4
+ let(:global) { { :color => false } }
5
+ let(:given) { {} }
6
+ let(:inputs) { {} }
7
+ let(:client) { fake_client }
8
+ let!(:cli) { described_class.new }
9
+ let(:app){ fake(:app, :space => space, :name => "app-name") }
10
+ let(:space) { fake(:space, :name => "space-name", :domains => space_domains) }
11
+ let(:domain) { fake(:domain, :name => domain_name ) }
12
+ let(:domain_name) { "some-domain.com" }
13
+ let(:host_name) { "some-host" }
14
+ let(:url) { "#{host_name}.#{domain_name}" }
15
+ let(:space_domains) { [domain] }
16
+
17
+ before do
18
+ stub(cli).client { client }
19
+ stub_output(cli)
20
+ end
21
+
22
+ subject { invoke_cli(cli, :unmap, inputs, given, global) }
23
+
24
+ describe 'metadata' do
25
+ let(:command) { Mothership.commands[:delete_service] }
26
+
27
+ describe 'command' do
28
+ subject { command }
29
+ its(:description) { should eq "Delete a service" }
30
+ it { expect(Mothership::Help.group(:services, :manage)).to include(subject) }
31
+ end
32
+
33
+ include_examples 'inputs must have descriptions'
34
+
35
+ describe 'arguments' do
36
+ subject { command.arguments }
37
+ it 'has the correct argument order' do
38
+ should eq([{:type => :optional, :value => nil, :name => :service }])
39
+ end
40
+ end
41
+ end
42
+
43
+ context 'when targeting v2' do
44
+ context "when an app and a url are specified" do
45
+ let(:given) { { :url => url } }
46
+ let(:inputs) { { :app => app } }
47
+
48
+ context "when the given route is mapped to the given app" do
49
+ let(:client) { fake_client :routes => [route] }
50
+ let(:app) { fake(:app, :space => space, :name => "app-name", :routes => [route]) }
51
+ let(:route) { fake(:route, :space => space, :host => host_name, :domain => domain) }
52
+
53
+ it "unmaps the url from the app" do
54
+ mock(app).remove_route(route)
55
+ subject
56
+ end
57
+ end
58
+
59
+ context "when the given route is NOT mapped to the given app" do
60
+ it "displays an error" do
61
+ expect { subject }.to raise_error(VMC::UserError, /Unknown route/)
62
+ end
63
+ end
64
+ end
65
+
66
+ context "when only an app is specified" do
67
+ let(:other_route) { fake(:route, :host => "abcd", :domain => domain) }
68
+ let(:route) { fake(:route, :host => "efgh", :domain => domain) }
69
+ let(:app) { fake(:app, :space => space, :routes => [route, other_route] )}
70
+ let(:inputs) { { :app => app } }
71
+
72
+ before { stub(app).remove_route(route) }
73
+
74
+ it "asks the user to select from the app's urls" do
75
+ mock_ask("Which URL?", anything) do |_, opts|
76
+ expect(opts[:choices]).to eq [other_route, route]
77
+ route
78
+ end
79
+
80
+ subject
81
+ end
82
+
83
+ it "unmaps the selected url from the app" do
84
+ stub_ask("Which URL?", anything) { route }
85
+ mock(app).remove_route(route)
86
+ subject
87
+ end
88
+ end
89
+
90
+ context "when an app is specified and the --all option is given" do
91
+ let(:other_route) { fake(:route, :host => "abcd", :domain => domain) }
92
+ let(:route) { fake(:route, :host => "efgh", :domain => domain) }
93
+ let(:app) { fake(:app, :routes => [route, other_route]) }
94
+ let(:inputs) { { :app => app, :all => true } }
95
+
96
+ it "unmaps all routes from the given app" do
97
+ mock(app).remove_route(route)
98
+ mock(app).remove_route(other_route)
99
+ subject
100
+ end
101
+ end
102
+
103
+ context "when a url is specified and the --delete option is given" do
104
+ let(:route) { fake(:route, :host => host_name, :domain => domain) }
105
+ let(:client) { fake_client :routes => [route] }
106
+ let(:given) { { :url => url } }
107
+ let(:inputs) { { :delete => true } }
108
+
109
+ it "deletes the route" do
110
+ mock(route).delete!
111
+ subject
112
+ end
113
+ end
114
+
115
+ context "when the --delete and --all options are both passed" do
116
+ let(:inputs) { { :delete => true, :all => true } }
117
+ let(:other_route) { fake(:route, :host => "abcd", :domain => domain) }
118
+ let(:route) { fake(:route, :host => "efgh", :domain => domain) }
119
+ let(:client) { fake_client :routes => [route, other_route] }
120
+
121
+ it "asks if the user really wants to unmap all urls" do
122
+ mock_ask("Really delete ALL URLS?", :default => false) { false }
123
+ subject
124
+ end
125
+
126
+ context "when the user responds with a yes" do
127
+ before { stub_ask("Really delete ALL URLS?", anything) { true } }
128
+
129
+ it "deletes all the user's routes" do
130
+ client.routes.each { |r| mock(r).delete! }
131
+ subject
132
+ end
133
+ end
134
+
135
+ context "when the user responds with a no" do
136
+ before { stub_ask("Really delete ALL URLS?", anything) { false } }
137
+
138
+ it "does not delete any routes" do
139
+ any_instance_of(route.class) do |route|
140
+ dont_allow(route).delete!
141
+ end
142
+ subject
143
+ end
144
+ end
145
+ end
146
+
147
+ context "when only a url is passed" do
148
+ let(:route) { fake(:route, :host => host_name, :domain => domain) }
149
+ let(:client) { fake_client :routes => [route] }
150
+ let(:given) { { :url => url } }
151
+
152
+ it "displays an error message" do
153
+ expect { subject }.to raise_error(VMC::UserError, /Missing either --delete or --app/)
154
+ end
155
+ end
156
+ end
157
+
158
+ context 'when targeting v1' do
159
+ let(:client) { CFoundry::V1::Client.new }
160
+ let(:app) { CFoundry::V1::App.new("some-app", client) }
161
+ let(:other_url) { "some.other.url.com" }
162
+
163
+ context "when an app and a url are specified" do
164
+ let(:given) { { :url => url } }
165
+ let(:inputs) { { :app => app } }
166
+
167
+ context "when the given url is not mapped to the app" do
168
+ before { app.urls = [other_url] }
169
+
170
+ it "displays an error message" do
171
+ expect { subject }.to raise_error(VMC::UserError, /URL.*not mapped/)
172
+ end
173
+ end
174
+
175
+ context "when the given url is mapped to the app" do
176
+ before { app.urls = [url, other_url] }
177
+
178
+ it "unmaps the url from the app" do
179
+ mock(app).update!
180
+ subject
181
+ expect(app.urls).to eq [other_url]
182
+ end
183
+ end
184
+ end
185
+
186
+ context "when only an app is specified" do
187
+ let(:inputs) { { :app => app } }
188
+ before { app.urls = [url, other_url] }
189
+
190
+ it "asks for the url" do
191
+ mock_ask("Which URL?", :choices => [url, other_url]) { url }
192
+ stub(app).update!
193
+ subject
194
+ end
195
+
196
+ it "unmaps the selected url from the app" do
197
+ stub_ask("Which URL?", anything) { url }
198
+ mock(app).update!
199
+ subject
200
+ expect(app.urls).to eq [other_url]
201
+ end
202
+ end
203
+
204
+ context "when an app is specified and the --all option is given" do
205
+ let(:inputs) { { :app => app, :all => true } }
206
+
207
+ it "unmaps all routes from the given app" do
208
+ app.urls = ["foo", "bar"]
209
+ mock(app).update!
210
+ subject
211
+ expect(app.urls).to eq []
212
+ end
213
+ end
214
+ end
215
+ end
@@ -95,7 +95,7 @@ describe VMC::Service::Rename do
95
95
 
96
96
  context 'and the name already exists' do
97
97
  it 'fails' do
98
- mock(renamed_service).update! { raise CFoundry::ServiceInstanceNameTaken.new nil, nil, "Taken", 200 }
98
+ mock(renamed_service).update! { raise CFoundry::ServiceInstanceNameTaken.new("Taken", 200) }
99
99
  expect { subject }.to raise_error(CFoundry::ServiceInstanceNameTaken)
100
100
  end
101
101
  end
@@ -2,23 +2,18 @@ require 'spec_helper'
2
2
  require "vmc/cli/space/rename"
3
3
 
4
4
  describe VMC::Space::Rename do
5
- let(:global) { { :color => false, :quiet => true } }
6
- let(:inputs) { {} }
7
- let(:given) { {} }
8
5
  let(:spaces) { fake_list(:space, 3) }
9
6
  let(:organization) { fake(:organization, :spaces => spaces) }
10
7
  let(:client) { fake_client(:current_organization => organization, :spaces => spaces) }
11
8
  let(:new_name) { "some-new-name" }
12
9
 
13
10
  before do
14
- any_instance_of(VMC::CLI) do |cli|
11
+ any_instance_of described_class do |cli|
15
12
  stub(cli).client { client }
16
13
  stub(cli).precondition { nil }
17
14
  end
18
15
  end
19
16
 
20
- subject { Mothership.new.invoke(:rename_space, inputs, given, global) }
21
-
22
17
  describe 'metadata' do
23
18
  let(:command) { Mothership.commands[:rename_space] }
24
19
 
@@ -45,12 +40,19 @@ describe VMC::Space::Rename do
45
40
  let(:spaces) { [] }
46
41
 
47
42
  context 'and a space is given' do
48
- let(:given) { { :space => "some-invalid-space" } }
49
- it { expect { subject }.to raise_error(VMC::UserError, "Unknown space 'some-invalid-space'.") }
43
+ subject { vmc %W[rename-space --space some-invalid-space --no-force --no-quiet] }
44
+ it 'prints out an error message' do
45
+ subject
46
+ expect(stderr.string).to include "Unknown space 'some-invalid-space'."
47
+ end
50
48
  end
51
49
 
52
50
  context 'and a space is not given' do
53
- it { expect { subject }.to raise_error(VMC::UserError, "No spaces.") }
51
+ subject { vmc %W[rename-space --no-force] }
52
+ it 'prints out an error message' do
53
+ subject
54
+ expect(stderr.string).to include "No spaces."
55
+ end
54
56
  end
55
57
  end
56
58
 
@@ -58,6 +60,8 @@ describe VMC::Space::Rename do
58
60
  let(:renamed_space) { spaces.first }
59
61
 
60
62
  context 'when the defaults are used' do
63
+ subject { vmc %W[rename-space --no-force --no-quiet] }
64
+
61
65
  it 'asks for the space and new name and renames' do
62
66
  mock_ask("Rename which space?", anything) { renamed_space }
63
67
  mock_ask("New name") { new_name }
@@ -68,7 +72,7 @@ describe VMC::Space::Rename do
68
72
  end
69
73
 
70
74
  context 'when no name is provided, but a space is' do
71
- let(:given) { { :space => renamed_space.name } }
75
+ subject { vmc %W[rename-space --space #{renamed_space.name} --no-force] }
72
76
 
73
77
  it 'asks for the new name and renames' do
74
78
  dont_allow_ask("Rename which space?", anything)
@@ -80,7 +84,7 @@ describe VMC::Space::Rename do
80
84
  end
81
85
 
82
86
  context 'when a space is provided and a name' do
83
- let(:inputs) { { :space => renamed_space, :name => new_name } }
87
+ subject { vmc %W[rename-space --space #{renamed_space.name} --name #{new_name} --no-force] }
84
88
 
85
89
  it 'renames the space' do
86
90
  mock(renamed_space).update!
@@ -93,13 +97,6 @@ describe VMC::Space::Rename do
93
97
 
94
98
  subject
95
99
  end
96
-
97
- context 'and the name already exists' do
98
- it 'fails' do
99
- mock(renamed_space).update! { raise CFoundry::SpaceNameTaken.new nil, nil, "Taken", 404 }
100
- expect { subject }.to raise_error(CFoundry::SpaceNameTaken)
101
- end
102
- end
103
100
  end
104
101
  end
105
102
  end