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

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 (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
@@ -2,15 +2,25 @@ SPEC_ROOT = File.dirname(__FILE__).freeze
2
2
 
3
3
  require "rspec"
4
4
  require "cfoundry"
5
- require "cfoundry/spec_helper"
5
+ require "cfoundry/test_support"
6
6
  require "vmc"
7
+ require "vmc/test_support"
7
8
 
8
9
  Dir[File.expand_path('../support/**/*.rb', __FILE__)].each do |file|
9
10
  require file
10
11
  end
11
12
 
12
13
  RSpec.configure do |c|
14
+ c.include Fake::FakeMethods
13
15
  c.mock_with :rr
16
+
17
+ c.include VMC::TestSupport::FakeHomeDir
18
+ c.include VMC::TestSupport::CommandHelper
19
+ c.include VMC::TestSupport::InteractHelper
20
+
21
+ c.before do
22
+ VMC::CLI.send(:class_variable_set, :@@client, nil)
23
+ end
14
24
  end
15
25
 
16
26
  class String
@@ -25,17 +35,6 @@ class String
25
35
  end
26
36
  end
27
37
 
28
- def with_output_to(output = StringIO.new)
29
- old_out = $stdout
30
- old_err = $stderr
31
- $stdout = output
32
- $stderr = output
33
- yield output
34
- ensure
35
- $stdout = old_out
36
- $stderr = old_err
37
- end
38
-
39
38
  def name_list(xs)
40
39
  if xs.empty?
41
40
  "none"
@@ -43,3 +42,16 @@ def name_list(xs)
43
42
  xs.collect(&:name).join(", ")
44
43
  end
45
44
  end
45
+
46
+ def invoke_cli(cli, *args)
47
+ stub.proxy(cli).invoke.with_any_args
48
+ stub(cli.class).new { cli }
49
+ cli.invoke(*args)
50
+ end
51
+
52
+ def stub_output(cli)
53
+ stub(cli).print
54
+ stub(cli).puts
55
+ stub(Interact::Progress::Dots).start!
56
+ stub(Interact::Progress::Dots).stop!
57
+ end
@@ -5,7 +5,6 @@ describe VMC::App::Stats do
5
5
  let(:global) { { :color => false } }
6
6
  let(:inputs) { {:app => apps[0]} }
7
7
  let(:given) { {} }
8
- let(:output) { StringIO.new }
9
8
  let(:client) { fake_client(:apps => apps) }
10
9
  let(:apps) { [fake(:app, :name => "basic_app")] }
11
10
  let(:time) { Time.local(2012,11,1,2,30)}
@@ -25,7 +24,7 @@ describe VMC::App::Stats do
25
24
  end
26
25
 
27
26
  subject do
28
- with_output_to output do
27
+ capture_output do
29
28
  Mothership.new.invoke(:instances, inputs, given, global)
30
29
  end
31
30
  end
@@ -51,16 +50,12 @@ describe VMC::App::Stats do
51
50
 
52
51
  it 'prints out the instances in the correct order' do
53
52
  subject
54
-
55
- output.rewind
56
- expect(output.string).to match /.*instance \#1.*instance \#2.*instance \#12.*/m
53
+ expect(stdout.string).to match /.*instance \#1.*instance \#2.*instance \#12.*/m
57
54
  end
58
55
 
59
56
  it 'prints out one of the instances correctly' do
60
57
  subject
61
-
62
- output.rewind
63
- expect(output.string).to include <<-OUT.strip_heredoc
58
+ expect(stdout.string).to include <<-OUT.strip_heredoc
64
59
  instance #2: started
65
60
  started: #{time.strftime("%F %r")}
66
61
  debugger: port bar at foo
@@ -46,7 +46,8 @@ describe VMC::App::Create do
46
46
  :framework => framework,
47
47
  :runtime => runtime,
48
48
  :memory => "1G",
49
- :command => "ruby main.rb"
49
+ :command => "ruby main.rb",
50
+ :buildpack => "git://example.com"
50
51
  }
51
52
  end
52
53
 
@@ -59,6 +60,7 @@ describe VMC::App::Create do
59
60
  its([:command]) { should eq "ruby main.rb" }
60
61
  its([:runtime]) { should eq runtime }
61
62
  its([:memory]) { should eq 1024 }
63
+ its([:buildpack]) { should eq "git://example.com" }
62
64
  end
63
65
 
64
66
  context 'when certain inputs are not given' do
@@ -279,7 +281,8 @@ describe VMC::App::Create do
279
281
  :framework => framework,
280
282
  :runtime => runtime,
281
283
  :production => false,
282
- :memory => 1024
284
+ :memory => 1024,
285
+ :buildpack => "git://example.com"
283
286
  }
284
287
  end
285
288
 
@@ -288,15 +291,15 @@ describe VMC::App::Create do
288
291
  subject { create.create_app(attributes) }
289
292
 
290
293
  it 'creates an app based on the resulting inputs' do
291
- attributes.each do |key, val|
292
- mock(app).__send__(:"#{key}=", val)
293
- end
294
-
295
294
  mock(create).filter(:create_app, app) { app }
296
295
 
297
296
  mock(app).create!
298
297
 
299
298
  subject
299
+
300
+ attributes.each do |key, val|
301
+ expect(app.send(key)).to eq val
302
+ end
300
303
  end
301
304
  end
302
305
 
@@ -337,7 +340,7 @@ describe VMC::App::Create do
337
340
  mock_ask('URL', anything) { url_choices.first }
338
341
 
339
342
  mock(create).invoke(:map, :app => app, :url => url_choices.first) do
340
- raise CFoundry::RouteHostTaken.new(nil, nil, "foo", 1234)
343
+ raise CFoundry::RouteHostTaken.new("foo", 1234)
341
344
  end
342
345
  end
343
346
 
@@ -120,7 +120,7 @@ describe VMC::App::Push do
120
120
 
121
121
  it 'outputs the changed instances' do
122
122
  mock(push).line("Changes:")
123
- mock(push).line("instances: 1 -> 2")
123
+ mock(push).line("total_instances: 1 -> 2")
124
124
  stub(app).update!
125
125
  subject
126
126
  end
@@ -95,7 +95,7 @@ describe VMC::App::Rename do
95
95
 
96
96
  context 'and the name already exists' do
97
97
  it 'fails' do
98
- mock(renamed_app).update! { raise CFoundry::AppNameTaken.new(nil, nil, "Bad Name", 404) }
98
+ mock(renamed_app).update! { raise CFoundry::AppNameTaken.new("Bad Name", 404) }
99
99
  expect { subject }.to raise_error(CFoundry::AppNameTaken)
100
100
  end
101
101
  end
@@ -0,0 +1,81 @@
1
+ require "spec_helper"
2
+ require "webmock/rspec"
3
+
4
+ describe VMC::App::Scale do
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
+ subject { invoke_cli(cli, :scale, inputs, given, global) }
16
+
17
+ context "when the --disk flag is given" do
18
+ let(:before_value) { 512 }
19
+ let(:app) { fake :app, :disk_quota => before_value }
20
+ let(:inputs) { { :app => app, :disk => "1G" } }
21
+
22
+ it "changes the application's disk quota" do
23
+ mock(app).update!
24
+ expect { subject }.to change(app, :disk_quota).from(before_value).to(1024)
25
+ end
26
+ end
27
+
28
+ context "when the --memory flag is given" do
29
+ let(:before_value) { 512 }
30
+ let(:app) { fake :app, :memory => before_value }
31
+ let(:inputs) { { :app => app, :memory => "1G" } }
32
+
33
+ it "changes the application's memory" do
34
+ mock(app).update!
35
+ expect { subject }.to change(app, :memory).from(before_value).to(1024)
36
+ end
37
+
38
+ context "if --restart is true" do
39
+ it "restarts the application" do
40
+ stub(app).update!
41
+ stub(app).started? { true }
42
+ mock(cli).invoke :restart, :app => app
43
+ subject
44
+ end
45
+ end
46
+ end
47
+
48
+ context "when the --instances flag is given" do
49
+ let(:before_value) { 3 }
50
+ let(:app) { fake :app, :total_instances => before_value }
51
+
52
+ let(:inputs) { { :app => app, :instances => 5 } }
53
+
54
+ it "changes the application's number of instances" do
55
+ mock(app).update!
56
+ expect { subject }.to change(app, :total_instances).from(before_value).to(5)
57
+ end
58
+ end
59
+
60
+ context "when the --plan flag is given" do
61
+ context "when the plan name begins with a 'p'" do
62
+ let(:app) { fake :app, :production => false }
63
+ let(:inputs) { { :app => app, :plan => "P100" } }
64
+
65
+ it "changes the application's 'production' flag to true" do
66
+ mock(app).update!
67
+ expect { subject }.to change(app, :production).from(false).to(true)
68
+ end
69
+ end
70
+
71
+ context "when the plan name does not begin with a 'p'" do
72
+ let(:app) { fake :app, :production => true }
73
+ let(:inputs) { { :app => app, :plan => "D100" } }
74
+
75
+ it "changes the application's 'production' flag to false" do
76
+ mock(app).update!
77
+ expect { subject }.to change(app, :production).from(true).to(false)
78
+ end
79
+ end
80
+ end
81
+ end
@@ -5,7 +5,6 @@ describe VMC::App::Stats do
5
5
  let(:global) { { :color => false } }
6
6
  let(:inputs) { {:app => apps[0]} }
7
7
  let(:given) { {} }
8
- let(:output) { StringIO.new }
9
8
  let(:client) { fake_client(:apps => apps) }
10
9
  let(:apps) { [fake(:app, :name => "basic_app")] }
11
10
 
@@ -33,9 +32,7 @@ describe VMC::App::Stats do
33
32
  end
34
33
 
35
34
  subject do
36
- with_output_to output do
37
- Mothership.new.invoke(:stats, inputs, given, global)
38
- end
35
+ capture_output { Mothership.new.invoke(:stats, inputs, given, global) }
39
36
  end
40
37
 
41
38
  describe 'metadata' do
@@ -59,8 +56,7 @@ describe VMC::App::Stats do
59
56
 
60
57
  it 'prints out the stats' do
61
58
  subject
62
-
63
- output.rewind
64
- expect(output.readlines.last).to match /.*0\s+0\.0% of\s+cores\s+29\.9M of 288M\s+14\.9M of 256M.*/
59
+ stdout.rewind
60
+ expect(stdout.readlines.last).to match /.*0\s+0\.0% of\s+cores\s+29\.9M of 288M\s+14\.9M of 256M.*/
65
61
  end
66
62
  end
@@ -0,0 +1,140 @@
1
+ require 'spec_helper'
2
+
3
+ describe VMC::Domain::Map do
4
+ let(:global) { { :color => false } }
5
+ let(:given) { {} }
6
+ let(:client) { fake_client :current_organization => organization, :current_space => space }
7
+ let!(:cli) { described_class.new }
8
+
9
+ before do
10
+ stub(cli).client { client }
11
+ stub_output(cli)
12
+ end
13
+
14
+ let(:organization) { fake(:organization) }
15
+ let(:space) { fake(:space) }
16
+ let(:domain) { fake(:domain, :name => domain_name) }
17
+ let(:domain_name) { "some.domain.com" }
18
+
19
+ subject { invoke_cli(cli, :map_domain, inputs, given, global) }
20
+
21
+ shared_examples "binding a domain to a space" do
22
+ it "adds the domain to the space's organization" do
23
+ mock(space.organization).add_domain(domain)
24
+ stub(space).add_domain(domain)
25
+ subject
26
+ end
27
+
28
+ it 'adds the domain to the space' do
29
+ stub(space.organization).add_domain(domain)
30
+ mock(space).add_domain(domain)
31
+ subject
32
+ end
33
+ end
34
+
35
+ shared_examples "binding a domain to an organization" do
36
+ it 'does NOT add the domain to a space' do
37
+ any_instance_of(space.class) do |space|
38
+ dont_allow(space).add_domain(domain)
39
+ end
40
+ end
41
+
42
+ it 'adds the domain to the organization' do
43
+ mock(organization).add_domain(domain)
44
+ subject
45
+ end
46
+ end
47
+
48
+ shared_examples "mapping a domain to a space" do
49
+ context "when the domain does NOT exist" do
50
+ before do
51
+ stub(client).domain { domain }
52
+ stub(domain).create!
53
+ stub(space.organization).add_domain(domain)
54
+ stub(space).add_domain(domain)
55
+ end
56
+
57
+ it 'creates the domain' do
58
+ mock(domain).create!
59
+ subject
60
+ expect(domain.name).to eq domain_name
61
+ expect(domain.owning_organization).to eq organization
62
+ end
63
+
64
+ include_examples "binding a domain to a space"
65
+ end
66
+
67
+ context "when the domain already exists" do
68
+ let(:client) {
69
+ fake_client :domains => [domain],
70
+ :current_organization => organization,
71
+ :current_space => space
72
+ }
73
+
74
+ include_examples "binding a domain to a space"
75
+ end
76
+ end
77
+
78
+ context 'when a domain and a space are passed' do
79
+ let(:inputs) { { :space => space, :name => domain_name } }
80
+
81
+ include_examples "mapping a domain to a space"
82
+ end
83
+
84
+ context 'when a domain and an organization are passed' do
85
+ let(:inputs) { { :organization => organization, :name => domain_name } }
86
+
87
+ context "and the domain does NOT exist" do
88
+ before do
89
+ stub(client).domain { domain }
90
+ stub(domain).create!
91
+ stub(organization).add_domain(domain)
92
+ end
93
+
94
+ include_examples "binding a domain to an organization"
95
+
96
+ it 'adds the domain to the organization' do
97
+ mock(organization).add_domain(domain)
98
+ subject
99
+ end
100
+
101
+ context "and the --shared option is passed" do
102
+ let(:inputs) { { :organization => organization, :name => domain_name, :shared => true } }
103
+
104
+ it 'adds the domain to the organization' do
105
+ mock(domain).create!
106
+ subject
107
+ expect(domain.name).to eq domain_name
108
+ end
109
+
110
+ it "does not add the domain to a specific organization" do
111
+ stub(domain).create!
112
+ subject
113
+ expect(domain.owning_organization).to be_nil
114
+ end
115
+ end
116
+ end
117
+
118
+ context "and the domain already exists" do
119
+ let(:client) {
120
+ fake_client :domains => [domain],
121
+ :current_organization => organization,
122
+ :current_space => space
123
+ }
124
+
125
+ include_examples "binding a domain to an organization"
126
+ end
127
+ end
128
+
129
+ context 'when a domain, organization, and space is passed' do
130
+ let(:inputs) { { :name => domain_name, :organization => organization, :space => space } }
131
+
132
+ include_examples "mapping a domain to a space"
133
+ end
134
+
135
+ context 'when only a domain is passed' do
136
+ let(:inputs) { { :name => domain_name } }
137
+
138
+ include_examples "mapping a domain to a space"
139
+ end
140
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe VMC::Domain::Unmap do
4
+ let(:global) { { :color => false } }
5
+ let(:given) { {} }
6
+ let(:client) { fake_client :current_organization => organization, :current_space => space }
7
+ let!(:cli) { described_class.new }
8
+
9
+ before do
10
+ stub(cli).client { client }
11
+ stub_output(cli)
12
+ end
13
+
14
+ let(:organization) { fake(:organization) }
15
+ let(:space) { fake(:space) }
16
+ let(:domain) { fake(:domain, :name => domain_name) }
17
+ let(:domain_name) { "some.domain.com" }
18
+
19
+ subject { invoke_cli(cli, :unmap_domain, inputs, given, global) }
20
+
21
+ context "when the --delete flag is given" do
22
+ let(:inputs) { { :domain => domain, :delete => true } }
23
+
24
+ it "asks for a confirmation" do
25
+ mock_ask("Really delete #{domain_name}?", :default => false) { false }
26
+ stub(domain).delete!
27
+ subject
28
+ end
29
+
30
+ context "and the user answers 'no' to the confirmation" do
31
+ it "does NOT delete the domain" do
32
+ stub_ask("Really delete #{domain_name}?", anything) { false }
33
+ dont_allow(domain).delete!
34
+ subject
35
+ end
36
+ end
37
+
38
+ context "and the user answers 'yes' to the confirmation" do
39
+ it "deletes the domain" do
40
+ stub_ask("Really delete #{domain_name}?", anything) { true }
41
+ mock(domain).delete!
42
+ subject
43
+ end
44
+ end
45
+ end
46
+
47
+ context "when a space is given" do
48
+ let(:inputs) { { :domain => domain, :space => space } }
49
+
50
+ it "unmaps the domain from the space" do
51
+ mock(space).remove_domain(domain)
52
+ subject
53
+ end
54
+ end
55
+
56
+ context "when an organization is given" do
57
+ let(:inputs) { { :domain => domain, :organization => organization } }
58
+
59
+ it "unmaps the domain from the organization" do
60
+ mock(organization).remove_domain(domain)
61
+ subject
62
+ end
63
+ end
64
+
65
+ context "when only the domain is given" do
66
+ let(:inputs) { { :domain => domain } }
67
+
68
+ it "unmaps the domain from the current space" do
69
+ mock(client.current_space).remove_domain(domain)
70
+ subject
71
+ end
72
+ end
73
+ end