af 0.3.22 → 0.5.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (157) hide show
  1. checksums.yaml +14 -6
  2. data/LICENSE +1277 -24
  3. data/Rakefile +24 -87
  4. data/bin/af +7 -2
  5. data/lib/af/version.rb +3 -0
  6. data/lib/vmc.rb +7 -2
  7. data/lib/vmc/cli.rb +475 -0
  8. data/lib/vmc/cli/app/app.rb +45 -0
  9. data/lib/vmc/cli/app/apps.rb +105 -0
  10. data/lib/vmc/cli/app/base.rb +82 -0
  11. data/lib/vmc/cli/app/crashes.rb +46 -0
  12. data/lib/vmc/cli/app/delete.rb +95 -0
  13. data/lib/vmc/cli/app/deprecated.rb +11 -0
  14. data/lib/vmc/cli/app/env.rb +78 -0
  15. data/lib/vmc/cli/app/files.rb +137 -0
  16. data/lib/vmc/cli/app/health.rb +26 -0
  17. data/lib/vmc/cli/app/instances.rb +53 -0
  18. data/lib/vmc/cli/app/logs.rb +76 -0
  19. data/lib/vmc/cli/app/push.rb +107 -0
  20. data/lib/vmc/cli/app/push/create.rb +150 -0
  21. data/lib/vmc/cli/app/push/interactions.rb +100 -0
  22. data/lib/vmc/cli/app/push/sync.rb +64 -0
  23. data/lib/vmc/cli/app/rename.rb +39 -0
  24. data/lib/vmc/cli/app/restart.rb +20 -0
  25. data/lib/vmc/cli/app/scale.rb +71 -0
  26. data/lib/vmc/cli/app/start.rb +93 -0
  27. data/lib/vmc/cli/app/stats.rb +67 -0
  28. data/lib/vmc/cli/app/stop.rb +27 -0
  29. data/lib/vmc/cli/domain/base.rb +12 -0
  30. data/lib/vmc/cli/domain/domains.rb +40 -0
  31. data/lib/vmc/cli/domain/map.rb +55 -0
  32. data/lib/vmc/cli/domain/unmap.rb +56 -0
  33. data/lib/vmc/cli/help.rb +16 -0
  34. data/lib/vmc/cli/interactive.rb +105 -0
  35. data/lib/vmc/cli/organization/base.rb +14 -0
  36. data/lib/vmc/cli/organization/create.rb +32 -0
  37. data/lib/vmc/cli/organization/delete.rb +73 -0
  38. data/lib/vmc/cli/organization/org.rb +45 -0
  39. data/lib/vmc/cli/organization/orgs.rb +35 -0
  40. data/lib/vmc/cli/organization/rename.rb +36 -0
  41. data/lib/vmc/cli/route/base.rb +12 -0
  42. data/lib/vmc/cli/route/map.rb +80 -0
  43. data/lib/vmc/cli/route/routes.rb +26 -0
  44. data/lib/vmc/cli/route/unmap.rb +94 -0
  45. data/lib/vmc/cli/service/base.rb +8 -0
  46. data/lib/vmc/cli/service/bind.rb +44 -0
  47. data/lib/vmc/cli/service/create.rb +126 -0
  48. data/lib/vmc/cli/service/delete.rb +86 -0
  49. data/lib/vmc/cli/service/rename.rb +35 -0
  50. data/lib/vmc/cli/service/service.rb +42 -0
  51. data/lib/vmc/cli/service/services.rb +115 -0
  52. data/lib/vmc/cli/service/unbind.rb +38 -0
  53. data/lib/vmc/cli/space/base.rb +21 -0
  54. data/lib/vmc/cli/space/create.rb +56 -0
  55. data/lib/vmc/cli/space/delete.rb +95 -0
  56. data/lib/vmc/cli/space/rename.rb +39 -0
  57. data/lib/vmc/cli/space/space.rb +64 -0
  58. data/lib/vmc/cli/space/spaces.rb +55 -0
  59. data/lib/vmc/cli/space/take.rb +16 -0
  60. data/lib/vmc/cli/start/base.rb +80 -0
  61. data/lib/vmc/cli/start/colors.rb +13 -0
  62. data/lib/vmc/cli/start/info.rb +122 -0
  63. data/lib/vmc/cli/start/login.rb +92 -0
  64. data/lib/vmc/cli/start/logout.rb +13 -0
  65. data/lib/vmc/cli/start/target.rb +64 -0
  66. data/lib/vmc/cli/start/target_interactions.rb +37 -0
  67. data/lib/vmc/cli/start/targets.rb +16 -0
  68. data/lib/vmc/cli/user/base.rb +29 -0
  69. data/lib/vmc/cli/user/create.rb +39 -0
  70. data/lib/vmc/cli/user/delete.rb +25 -0
  71. data/lib/vmc/cli/user/passwd.rb +50 -0
  72. data/lib/vmc/cli/user/register.rb +42 -0
  73. data/lib/vmc/cli/user/users.rb +32 -0
  74. data/lib/vmc/constants.rb +13 -0
  75. data/lib/vmc/detect.rb +134 -0
  76. data/lib/vmc/errors.rb +17 -0
  77. data/lib/vmc/plugin.rb +56 -0
  78. data/lib/vmc/spacing.rb +89 -0
  79. data/lib/vmc/spec_helper.rb +1 -0
  80. data/lib/vmc/test_support.rb +4 -0
  81. data/lib/vmc/test_support/command_helper.rb +32 -0
  82. data/lib/vmc/test_support/common_input_examples.rb +14 -0
  83. data/lib/vmc/test_support/fake_home_dir.rb +16 -0
  84. data/lib/vmc/test_support/interact_helper.rb +29 -0
  85. data/lib/vmc/version.rb +3 -0
  86. data/spec/assets/hello-sinatra/Gemfile +3 -0
  87. data/spec/assets/hello-sinatra/main.rb +6 -0
  88. data/spec/features/new_user_flow_spec.rb +71 -0
  89. data/spec/spec_helper.rb +63 -0
  90. data/spec/vmc/cli/app/base_spec.rb +17 -0
  91. data/spec/vmc/cli/app/delete_spec.rb +188 -0
  92. data/spec/vmc/cli/app/instances_spec.rb +65 -0
  93. data/spec/vmc/cli/app/push/create_spec.rb +571 -0
  94. data/spec/vmc/cli/app/push_spec.rb +369 -0
  95. data/spec/vmc/cli/app/rename_spec.rb +104 -0
  96. data/spec/vmc/cli/app/scale_spec.rb +81 -0
  97. data/spec/vmc/cli/app/stats_spec.rb +62 -0
  98. data/spec/vmc/cli/domain/map_spec.rb +140 -0
  99. data/spec/vmc/cli/domain/unmap_spec.rb +73 -0
  100. data/spec/vmc/cli/organization/orgs_spec.rb +108 -0
  101. data/spec/vmc/cli/organization/rename_spec.rb +113 -0
  102. data/spec/vmc/cli/route/map_spec.rb +138 -0
  103. data/spec/vmc/cli/route/unmap_spec.rb +215 -0
  104. data/spec/vmc/cli/service/bind_spec.rb +25 -0
  105. data/spec/vmc/cli/service/delete_spec.rb +22 -0
  106. data/spec/vmc/cli/service/rename_spec.rb +105 -0
  107. data/spec/vmc/cli/service/service_spec.rb +23 -0
  108. data/spec/vmc/cli/service/unbind_spec.rb +25 -0
  109. data/spec/vmc/cli/space/rename_spec.rb +102 -0
  110. data/spec/vmc/cli/space/spaces_spec.rb +104 -0
  111. data/spec/vmc/cli/start/info_spec.rb +153 -0
  112. data/spec/vmc/cli/start/login_spec.rb +71 -0
  113. data/spec/vmc/cli/user/create_spec.rb +54 -0
  114. data/spec/vmc/cli/user/passwd_spec.rb +102 -0
  115. data/spec/vmc/cli/user/register_spec.rb +148 -0
  116. data/spec/vmc/cli_spec.rb +448 -0
  117. data/spec/vmc/detect_spec.rb +54 -0
  118. metadata +231 -124
  119. data/README.md +0 -155
  120. data/caldecott_helper/Gemfile +0 -10
  121. data/caldecott_helper/Gemfile.lock +0 -48
  122. data/caldecott_helper/server.rb +0 -43
  123. data/config/clients.yml +0 -17
  124. data/config/micro/offline.conf +0 -2
  125. data/config/micro/paths.yml +0 -22
  126. data/config/micro/refresh_ip.rb +0 -20
  127. data/lib/cli.rb +0 -48
  128. data/lib/cli/commands/admin.rb +0 -81
  129. data/lib/cli/commands/apps.rb +0 -1358
  130. data/lib/cli/commands/base.rb +0 -233
  131. data/lib/cli/commands/manifest.rb +0 -56
  132. data/lib/cli/commands/micro.rb +0 -115
  133. data/lib/cli/commands/misc.rb +0 -147
  134. data/lib/cli/commands/services.rb +0 -217
  135. data/lib/cli/commands/user.rb +0 -70
  136. data/lib/cli/config.rb +0 -176
  137. data/lib/cli/console_helper.rb +0 -163
  138. data/lib/cli/core_ext.rb +0 -122
  139. data/lib/cli/errors.rb +0 -19
  140. data/lib/cli/file_helper.rb +0 -123
  141. data/lib/cli/frameworks.rb +0 -265
  142. data/lib/cli/manifest_helper.rb +0 -316
  143. data/lib/cli/runner.rb +0 -633
  144. data/lib/cli/services_helper.rb +0 -104
  145. data/lib/cli/tunnel_helper.rb +0 -336
  146. data/lib/cli/usage.rb +0 -129
  147. data/lib/cli/version.rb +0 -7
  148. data/lib/cli/zip_util.rb +0 -102
  149. data/lib/vmc/client.rb +0 -574
  150. data/lib/vmc/const.rb +0 -27
  151. data/lib/vmc/micro.rb +0 -56
  152. data/lib/vmc/micro/switcher/base.rb +0 -97
  153. data/lib/vmc/micro/switcher/darwin.rb +0 -19
  154. data/lib/vmc/micro/switcher/dummy.rb +0 -15
  155. data/lib/vmc/micro/switcher/linux.rb +0 -16
  156. data/lib/vmc/micro/switcher/windows.rb +0 -31
  157. data/lib/vmc/micro/vmrun.rb +0 -158
@@ -0,0 +1,113 @@
1
+ require 'spec_helper'
2
+ require "vmc/cli/organization/rename"
3
+
4
+ describe VMC::Organization::Rename do
5
+ let(:global) { { :color => false, :quiet => true } }
6
+ let(:inputs) { {} }
7
+ let(:given) { {} }
8
+ let(:organizations) { fake_list(:organization, 3) }
9
+ let(:client) { fake_client(:organizations => organizations) }
10
+ let(:new_name) { "some-new-name" }
11
+
12
+ before do
13
+ any_instance_of(VMC::CLI) do |cli|
14
+ stub(cli).client { client }
15
+ stub(cli).precondition { nil }
16
+ end
17
+ end
18
+
19
+ subject { Mothership.new.invoke(:rename_org, inputs, given, global) }
20
+
21
+ describe 'metadata' do
22
+ let(:command) { Mothership.commands[:rename_org] }
23
+
24
+ describe 'command' do
25
+ subject { command }
26
+ its(:description) { should eq "Rename an organization" }
27
+ it { expect(Mothership::Help.group(:organizations)).to include(subject) }
28
+ end
29
+
30
+ describe 'inputs' do
31
+ subject { command.inputs }
32
+
33
+ it "is not missing any descriptions" do
34
+ subject.each do |input, attrs|
35
+ expect(attrs[:description]).to be
36
+ expect(attrs[:description].strip).to_not be_empty
37
+ end
38
+ end
39
+ end
40
+
41
+ describe 'arguments' do
42
+ subject { command.arguments }
43
+ it 'has the correct argument order' do
44
+ should eq([
45
+ { :type => :optional, :value => nil, :name => :organization },
46
+ { :type => :optional, :value => nil, :name => :name }
47
+ ])
48
+ end
49
+ end
50
+ end
51
+
52
+ context 'when there are no organizations' do
53
+ let(:organizations) { [] }
54
+
55
+ context 'and an organization is given' do
56
+ let(:given) { { :organization => "some-invalid-organization" } }
57
+ it { expect { subject }.to raise_error(VMC::UserError, "Unknown organization 'some-invalid-organization'.") }
58
+ end
59
+
60
+ context 'and an organization is not given' do
61
+ it { expect { subject }.to raise_error(VMC::UserError, "No organizations.") }
62
+ end
63
+ end
64
+
65
+ context 'when there are organizations' do
66
+ let(:renamed_organization) { organizations.first }
67
+
68
+ context 'when the defaults are used' do
69
+ it 'asks for the organization and new name and renames' do
70
+ mock_ask("Rename which organization?", anything) { renamed_organization }
71
+ mock_ask("New name") { new_name }
72
+ mock(renamed_organization).name=(new_name)
73
+ mock(renamed_organization).update!
74
+ subject
75
+ end
76
+ end
77
+
78
+ context 'when no name is provided, but an organization is' do
79
+ let(:given) { { :organization => renamed_organization.name } }
80
+
81
+ it 'asks for the new name and renames' do
82
+ dont_allow_ask("Rename which organization?", anything)
83
+ mock_ask("New name") { new_name }
84
+ mock(renamed_organization).name=(new_name)
85
+ mock(renamed_organization).update!
86
+ subject
87
+ end
88
+ end
89
+
90
+ context 'when an organization is provided and a name' do
91
+ let(:inputs) { { :organization => renamed_organization, :name => new_name } }
92
+
93
+ it 'renames the organization' do
94
+ mock(renamed_organization).update!
95
+ subject
96
+ end
97
+
98
+ it 'displays the progress' do
99
+ mock_with_progress("Renaming to #{new_name}")
100
+ mock(renamed_organization).update!
101
+
102
+ subject
103
+ end
104
+
105
+ context 'and the name already exists' do
106
+ it 'fails' do
107
+ mock(renamed_organization).update! { raise CFoundry::OrganizationNameTaken.new("Bad error", 200) }
108
+ expect { subject }.to raise_error(CFoundry::OrganizationNameTaken)
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,138 @@
1
+ require 'spec_helper'
2
+
3
+ describe VMC::Route::Map do
4
+ let(:inputs) { {} }
5
+ let(:global) { { :color => false } }
6
+ let(:given) { {} }
7
+ let(:client) { fake_client }
8
+ let!(:cli) { described_class.new }
9
+
10
+ before do
11
+ stub(cli).client { client }
12
+ stub_output(cli)
13
+ end
14
+
15
+ let(:app){ fake(:app, :space => space, :name => "app-name") }
16
+ let(:space) { fake(:space, :name => "space-name", :domains => space_domains) }
17
+ let(:domain) { fake(:domain, :name => domain_name ) }
18
+ let(:domain_name) { "some-domain.com" }
19
+ let(:host_name) { "some-host" }
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) { { :domain => domain, :host => host_name, :app => app } }
76
+
77
+ context 'and the domain is not already mapped to the space' do
78
+ let(:space_domains) { [] }
79
+ let(:inputs) { { :app => app } }
80
+ let(:given) { { :domain => "some-bad-domain" }}
81
+
82
+ it 'indicates that the domain is invalid' do
83
+ expect { subject }.to raise_error(VMC::UserError, /Unknown domain/)
84
+ end
85
+ end
86
+
87
+ include_examples "mapping the route to the app"
88
+ end
89
+
90
+ context 'when an app is not specified' do
91
+ let(:inputs) { { :domain => domain, :host => host_name } }
92
+ let(:space_domains) { [domain] }
93
+ let(:new_route) { fake(:route) }
94
+
95
+ before { stub_ask("Which application?", anything) { app } }
96
+
97
+ it 'asks for an app' do
98
+ stub(client).route { new_route }
99
+ stub(app).add_route
100
+ stub(new_route).create!
101
+ mock_ask("Which application?", anything) { app }
102
+ subject
103
+ end
104
+
105
+ include_examples "mapping the route to the app"
106
+ end
107
+
108
+ context "when a host is not specified" do
109
+ let(:inputs) { { :domain => domain, :app => app } }
110
+ let(:new_route) { fake(:route) }
111
+
112
+ before do
113
+ stub(client).route { new_route }
114
+ stub(app).add_route
115
+ stub(new_route).create!
116
+ end
117
+
118
+ it "creates a route with an empty string as its host" do
119
+ mock(new_route).create!
120
+ subject
121
+ expect(new_route.host).to eq ""
122
+ end
123
+ end
124
+ end
125
+
126
+ context 'when targeting v1' do
127
+ let(:given) { { :domain => "foo.bar.com" } }
128
+ let(:app) { v1_fake :app, :name => "foo" }
129
+ let(:client) { v1_fake_client }
130
+ let(:inputs) { { :app => app } }
131
+
132
+ it "adds the domain to the app's urls" do
133
+ stub(app).update!
134
+ subject
135
+ expect(app.urls).to include "foo.bar.com"
136
+ end
137
+ end
138
+ 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