vmc 0.5.0.rc1 → 0.5.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/lib/vmc/cli.rb +2 -1
  2. data/lib/vmc/cli/app/start.rb +81 -24
  3. data/lib/vmc/cli/space/create.rb +4 -0
  4. data/lib/vmc/cli/space/switch.rb +16 -0
  5. data/lib/vmc/cli/start/base.rb +21 -18
  6. data/lib/vmc/cli/user/base.rb +1 -1
  7. data/lib/vmc/cli/user/delete.rb +2 -0
  8. data/lib/vmc/version.rb +1 -1
  9. data/spec/assets/hello-sinatra/Gemfile.lock +17 -0
  10. data/spec/features/{new_user_flow_spec.rb → v1/new_user_flow_spec.rb} +12 -18
  11. data/spec/features/v2/account_lifecycle_spec.rb +64 -0
  12. data/spec/features/v2/push_flow_spec.rb +126 -0
  13. data/spec/spec_helper.rb +16 -3
  14. data/{lib/vmc/test_support → spec/support}/command_helper.rb +5 -5
  15. data/spec/support/config_helper.rb +15 -0
  16. data/spec/support/console_app_specker_matchers.rb +2 -2
  17. data/spec/support/fake_home_dir.rb +42 -0
  18. data/{lib/vmc/test_support → spec/support}/interact_helper.rb +1 -1
  19. data/spec/support/shared_examples/errors.rb +40 -0
  20. data/{lib/vmc/test_support/common_input_examples.rb → spec/support/shared_examples/input.rb} +0 -0
  21. data/spec/support/specker_runner.rb +17 -61
  22. data/spec/support/tracking_expector.rb +71 -0
  23. data/spec/vmc/cli/app/instances_spec.rb +3 -3
  24. data/spec/vmc/cli/app/start_spec.rb +201 -0
  25. data/spec/vmc/cli/app/stats_spec.rb +21 -15
  26. data/spec/vmc/cli/space/create_spec.rb +73 -0
  27. data/spec/vmc/cli/space/switch_space_spec.rb +55 -0
  28. data/spec/vmc/cli/start/info_spec.rb +3 -16
  29. data/spec/vmc/cli/start/login_spec.rb +97 -37
  30. data/spec/vmc/cli/start/logout_spec.rb +3 -16
  31. data/spec/vmc/cli/start/target_spec.rb +84 -0
  32. data/spec/vmc/cli/user/delete_spec.rb +51 -0
  33. data/spec/vmc/cli/user/passwd_spec.rb +1 -1
  34. data/spec/vmc/cli/user/register_spec.rb +1 -1
  35. data/spec/vmc/cli_spec.rb +38 -36
  36. metadata +65 -39
  37. data/lib/vmc/cli/space/take.rb +0 -16
  38. data/lib/vmc/test_support/fake_home_dir.rb +0 -16
data/lib/vmc/cli.rb CHANGED
@@ -26,7 +26,7 @@ module VMC
26
26
  option :help, :desc => "Show command usage", :alias => "-h",
27
27
  :default => false
28
28
 
29
- option :proxy, :desc => "Act as another user (admin)", :alias => "-u",
29
+ option :proxy, :desc => "Run this command as another user (admin)", :alias => "-u",
30
30
  :value => :email
31
31
 
32
32
  option :version, :desc => "Print version number", :alias => "-v",
@@ -398,6 +398,7 @@ module VMC
398
398
  @@client =
399
399
  case info[:version]
400
400
  when 2
401
+ fail "User switching not implemented for v2." if input[:proxy]
401
402
  CFoundry::V2::Client.new(target, token)
402
403
  when 1
403
404
  CFoundry::V1::Client.new(target, token)
@@ -19,16 +19,13 @@ module VMC::App
19
19
 
20
20
  switch_mode(app, input[:debug_mode])
21
21
 
22
- with_progress("Starting #{c(app.name, :name)}") do |s|
23
- if app.started?
24
- s.skip do
25
- err "Already started."
26
- end
27
- end
28
-
29
- app.start!
22
+ if app.started?
23
+ err "Application #{b(app.name)} is already started."
24
+ next
30
25
  end
31
26
 
27
+ log = start_app(app)
28
+ stream_start_log(log) if log
32
29
  check_application(app)
33
30
 
34
31
  if app.debug_mode && !quiet?
@@ -38,6 +35,33 @@ module VMC::App
38
35
  end
39
36
  end
40
37
 
38
+ private
39
+
40
+ def start_app(app)
41
+ log = nil
42
+ with_progress("Starting #{c(app.name, :name)}") do
43
+ app.start!(true) do |url|
44
+ log = url
45
+ end
46
+ end
47
+ log
48
+ end
49
+
50
+ def stream_start_log(log)
51
+ offset = 0
52
+
53
+ while true
54
+ begin
55
+ client.stream_url(log + "&tail&tail_offset=#{offset}") do |out|
56
+ offset += out.size
57
+ print out
58
+ end
59
+ rescue Timeout::Error
60
+ end
61
+ end
62
+ rescue CFoundry::APIError
63
+ end
64
+
41
65
  # set app debug mode, ensuring it's valid, and shutting it down
42
66
  def switch_mode(app, mode)
43
67
  mode = nil if mode == "none"
@@ -68,26 +92,59 @@ module VMC::App
68
92
  end
69
93
 
70
94
  def check_application(app)
71
- with_progress("Checking #{c(app.name, :name)}") do |s|
72
- if app.debug_mode == "suspend"
73
- s.skip do
74
- line "Application is in suspended debugging mode."
75
- line "It will wait for you to attach to it before starting."
76
- end
95
+ if app.debug_mode == "suspend"
96
+ line "Application is in suspended debugging mode."
97
+ line "It will wait for you to attach to it before starting."
98
+ return
99
+ end
100
+
101
+ line "Checking #{c(app.name, :name)}..."
102
+
103
+ seconds = 0
104
+ while instances = app.instances
105
+ indented { print_instances_summary(instances) }
106
+
107
+ if all_instances_running?(instances)
108
+ line "#{c("OK", :good)}"
109
+ return
77
110
  end
78
111
 
79
- seconds = 0
80
- until app.healthy?
81
- sleep 1
82
- seconds += 1
83
- if seconds == APP_CHECK_LIMIT
84
- s.give_up do
85
- err "Application failed to start."
86
- # TODO: print logs
87
- end
88
- end
112
+ if any_instance_flapping?(instances) || seconds == APP_CHECK_LIMIT
113
+ err "Application failed to start."
114
+ return
115
+ end
116
+
117
+ sleep 1
118
+ seconds += 1
119
+ end
120
+ end
121
+
122
+ def all_instances_running?(instances)
123
+ instances.all? { |i| i.state == "RUNNING" }
124
+ end
125
+
126
+ def any_instance_flapping?(instances)
127
+ instances.any? { |i| i.state == "FLAPPING" }
128
+ end
129
+
130
+ def print_instances_summary(instances)
131
+ counts = Hash.new { 0 }
132
+ instances.each do |i|
133
+ counts[i.state] += 1
134
+ end
135
+
136
+ states = []
137
+ %w{RUNNING STARTING DOWN FLAPPING}.each do |state|
138
+ if (num = counts[state]) > 0
139
+ states << "#{b(num)} #{c(state.downcase, state_color(state))}"
89
140
  end
90
141
  end
142
+
143
+ total = instances.count
144
+ running = counts["RUNNING"].to_s.rjust(total.to_s.size)
145
+
146
+ ratio = "#{running}#{d("/")}#{total} instances:"
147
+ line "#{ratio} #{states.join(", ")}"
91
148
  end
92
149
  end
93
150
  end
@@ -14,7 +14,11 @@ module VMC::Space
14
14
  input :manager, :desc => "Add yourself as manager", :default => true
15
15
  input :developer, :desc => "Add yourself as developer", :default => true
16
16
  input :auditor, :desc => "Add yourself as auditor", :default => false
17
+
17
18
  def create_space
19
+ return invoke :help,
20
+ :command => "create-space" if input[:organization].nil?
21
+
18
22
  space = client.space
19
23
  space.organization = input[:organization]
20
24
  space.name = input[:name]
@@ -0,0 +1,16 @@
1
+ require "vmc/cli/space/base"
2
+
3
+ module VMC::Space
4
+ class Switch < Base
5
+ desc "Switch to a space"
6
+ group :spaces, :hidden => true
7
+ input :name, :desc => "Space name", :argument => true
8
+ def switch_space
9
+ if (space = client.space_by_name(input[:name]))
10
+ invoke :target, :space => space
11
+ else
12
+ raise VMC::UserError, "The space #{input[:name]} does not exist, please create the space first."
13
+ end
14
+ end
15
+ end
16
+ end
@@ -34,34 +34,37 @@ module VMC
34
34
  end
35
35
  end
36
36
 
37
- def select_org_and_space(input, info)
38
- changed_org = false
39
-
37
+ def select_org(input, info)
40
38
  if input.has?(:organization) || !org_valid?(info[:organization])
41
39
  org = input[:organization]
42
- return unless org
43
-
44
- with_progress("Switching to organization #{c(org.name, :name)}") do
45
- info[:organization] = org.guid
46
- changed_org = true
47
- end
40
+ with_progress("Switching to organization #{c(org.name, :name)}") {} if org
41
+ org
48
42
  else
49
- org = client.current_organization
43
+ client.current_organization
50
44
  end
45
+ end
51
46
 
52
- # switching org means switching space
53
- if changed_org || input.has?(:space) || !space_valid?(info[:space])
47
+ def select_space(org, input, info, changed_org)
48
+ if input.has?(:space) || !space_valid?(info[:space])
54
49
  line if changed_org && !quiet?
55
-
56
50
  space = input[:space, org]
57
- return unless space
58
-
59
- with_progress("Switching to space #{c(space.name, :name)}") do
60
- info[:space] = space.guid
61
- end
51
+ with_progress("Switching to space #{c(space.name, :name)}") {} if space
52
+ space
53
+ else
54
+ client.current_space
62
55
  end
63
56
  end
64
57
 
58
+ def select_org_and_space(input, info)
59
+ org = select_org(input, info)
60
+ changed_org = client.current_organization != org
61
+ space = select_space(org, input, info, changed_org) if org
62
+ info.merge!(
63
+ :organization => (org ? org.guid : nil),
64
+ :space => (space ? space.guid : nil)
65
+ )
66
+ end
67
+
65
68
  def org_valid?(guid, user = client.current_user)
66
69
  return false unless guid
67
70
  client.organization(guid).users.include? user
@@ -19,7 +19,7 @@ module VMC
19
19
  end
20
20
 
21
21
  def validate_password_strength!(password)
22
- strength = client.password_score(password)
22
+ strength = client.base.password_score(password)
23
23
  msg = "Your password strength is: #{strength}"
24
24
  fail msg if strength == :weak
25
25
  line msg
@@ -8,6 +8,8 @@ module VMC::User
8
8
  input :really, :type => :boolean, :forget => true, :hidden => true,
9
9
  :default => proc { force? || interact }
10
10
  def delete_user
11
+ no_v2
12
+
11
13
  email = input[:email]
12
14
  return unless input[:really, email]
13
15
 
data/lib/vmc/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module VMC
2
- VERSION = "0.5.0.rc1".freeze
2
+ VERSION = "0.5.0.rc2".freeze
3
3
  end
@@ -0,0 +1,17 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ rack (1.5.2)
5
+ rack-protection (1.3.2)
6
+ rack
7
+ sinatra (1.3.4)
8
+ rack (~> 1.4)
9
+ rack-protection (~> 1.3)
10
+ tilt (~> 1.3, >= 1.3.3)
11
+ tilt (1.3.3)
12
+
13
+ PLATFORMS
14
+ ruby
15
+
16
+ DEPENDENCIES
17
+ sinatra
@@ -1,18 +1,18 @@
1
1
  require 'spec_helper'
2
- require "webmock/rspec"
3
-
4
- INTEGRATE_WITH = ENV["INTEGRATE_WITH"] || "default"
2
+ require 'webmock/rspec'
3
+ require 'ffaker'
5
4
 
6
5
  if ENV['VMC_TEST_USER'] && ENV['VMC_TEST_PASSWORD'] && ENV['VMC_TEST_TARGET']
7
- describe 'A new user tries to use VMC against v1 production', :ruby19 => true do
6
+ describe 'A new user tries to use VMC against v1 production', :ruby19 => true do
8
7
  include ConsoleAppSpeckerMatchers
9
8
  include VMC::Interactive
10
9
 
10
+ let(:output) { StringIO.new }
11
+ let(:out) { output.string.strip_progress_dots }
12
+
11
13
  let(:target) { ENV['VMC_TEST_TARGET'] }
12
14
  let(:username) { ENV['VMC_TEST_USER'] }
13
15
  let(:password) { ENV['VMC_TEST_PASSWORD'] }
14
- let(:output) { StringIO.new }
15
- let(:out) { output.string.strip_progress_dots }
16
16
 
17
17
  let(:app) do
18
18
  fuzz = defined?(TRAVIS_BUILD_ID) ? TRAVIS_BUILD_ID : Time.new.to_f.to_s.gsub(".", "_")
@@ -30,15 +30,6 @@ if ENV['VMC_TEST_USER'] && ENV['VMC_TEST_PASSWORD'] && ENV['VMC_TEST_TARGET']
30
30
  Interact::Progress::Dots.stop!
31
31
  end
32
32
 
33
- let(:vmc_bin) do
34
- vmc = File.expand_path("#{SPEC_ROOT}/../bin/vmc.dev")
35
- if INTEGRATE_WITH != 'default'
36
- "rvm #{INTEGRATE_WITH}@vmc do #{vmc}"
37
- else
38
- vmc
39
- end
40
- end
41
-
42
33
  it 'pushes a simple sinatra app using defaults as much as possible' do
43
34
  run("#{vmc_bin} target http://#{target}") do |runner|
44
35
  expect(runner).to say %r{Setting target to http://#{target}... OK}
@@ -98,7 +89,10 @@ if ENV['VMC_TEST_USER'] && ENV['VMC_TEST_PASSWORD'] && ENV['VMC_TEST_TARGET']
98
89
 
99
90
  expect(runner).to say "Uploading #{app}... OK"
100
91
  expect(runner).to say "Starting #{app}... OK"
101
- expect(runner).to say "Checking #{app}... OK", 30
92
+
93
+ expect(runner).to say "Checking #{app}..."
94
+ expect(runner).to say "1/1 instances"
95
+ expect(runner).to say "OK", 30
102
96
  end
103
97
  end
104
98
 
@@ -111,5 +105,5 @@ if ENV['VMC_TEST_USER'] && ENV['VMC_TEST_PASSWORD'] && ENV['VMC_TEST_TARGET']
111
105
  end
112
106
  end
113
107
  else
114
- $stderr.puts 'Skipping integration specs; please provide $VMC_TEST_TARGET, $VMC_TEST_USER, and $VMC_TEST_PASSWORD'
115
- end
108
+ $stderr.puts 'Skipping v1 integration specs; please provide $VMC_TEST_TARGET, $VMC_TEST_USER, and $VMC_TEST_PASSWORD'
109
+ end
@@ -0,0 +1,64 @@
1
+ require "spec_helper"
2
+ require "webmock/rspec"
3
+
4
+ if ENV['VMC_V2_TEST_USER'] && ENV['VMC_V2_TEST_PASSWORD'] && ENV['VMC_V2_TEST_TARGET']
5
+ describe 'A new user tries to use VMC against v2 production', :ruby19 => true do
6
+ include ConsoleAppSpeckerMatchers
7
+
8
+ let(:target) { ENV['VMC_V2_TEST_TARGET'] }
9
+ let(:username) { ENV['VMC_V2_TEST_USER'] }
10
+ let(:password) { ENV['VMC_V2_TEST_PASSWORD'] }
11
+
12
+ before do
13
+ Interact::Progress::Dots.start!
14
+ end
15
+
16
+ after do
17
+ Interact::Progress::Dots.stop!
18
+ end
19
+
20
+ it "registers a new account and deletes it" do
21
+ pending "until we get some v2 admin credentials somewhere to actually run this with"
22
+
23
+ email = Faker::Internet.email
24
+ run("#{vmc_bin} target #{target}") do |runner|
25
+ runner.wait_for_exit
26
+ end
27
+
28
+ run("#{vmc_bin} login #{username} --password #{password}") do |runner|
29
+ expect(runner).to say "Organization>"
30
+ runner.send_keys "1"
31
+ expect(runner).to say "Space>"
32
+ runner.send_keys "1"
33
+ end
34
+
35
+ puts "registering #{email}"
36
+ run("#{vmc_bin} register #{email} --password p") do |runner|
37
+ expect(runner).to say "Confirm Password>"
38
+ runner.send_keys 'p'
39
+ expect(runner).to say "Your password strength is: good"
40
+ expect(runner).to say "Creating user... OK"
41
+ expect(runner).to say "Authenticating... OK"
42
+ end
43
+
44
+ run("#{vmc_bin} logout") do |runner|
45
+ runner.wait_for_exit
46
+ end
47
+
48
+ run("#{vmc_bin} login #{username} --password #{password}") do |runner|
49
+ expect(runner).to say "Organization>"
50
+ runner.send_keys "1"
51
+ expect(runner).to say "Space>"
52
+ runner.send_keys "1"
53
+ end
54
+
55
+ run("#{vmc_bin} delete-user #{email}") do |runner|
56
+ expect(runner).to say "Really delete user #{email}?>"
57
+ runner.send_keys "y"
58
+ expect(runner).to say "Deleting #{email}... OK"
59
+ end
60
+ end
61
+ end
62
+ else
63
+ $stderr.puts 'Skipping v2 integration specs; please provide $VMC_V2_TEST_TARGET, $VMC_V2_TEST_USER, and $VMC_V2_TEST_PASSWORD'
64
+ end
@@ -0,0 +1,126 @@
1
+ require "spec_helper"
2
+ require "webmock/rspec"
3
+
4
+ if ENV['VMC_V2_TEST_USER'] && ENV['VMC_V2_TEST_PASSWORD'] && ENV['VMC_V2_TEST_TARGET']
5
+ describe 'A new user tries to use VMC against v2', :ruby19 => true do
6
+ include ConsoleAppSpeckerMatchers
7
+ include VMC::Interactive
8
+
9
+ let(:target) { ENV['VMC_V2_TEST_TARGET'] }
10
+ let(:username) { ENV['VMC_V2_TEST_USER'] }
11
+ let(:password) { ENV['VMC_V2_TEST_PASSWORD'] }
12
+
13
+ let(:app) do
14
+ fuzz = defined?(TRAVIS_BUILD_ID) ? TRAVIS_BUILD_ID : Time.new.to_f.to_s.gsub(".", "_")
15
+ "hello-sinatra-#{fuzz}"
16
+ end
17
+
18
+ before do
19
+ FileUtils.rm_rf File.expand_path(VMC::CONFIG_DIR)
20
+ WebMock.allow_net_connect!
21
+ Interact::Progress::Dots.start!
22
+ end
23
+
24
+ after do
25
+ vmc %W(delete #{app} -f --no-script)
26
+ Interact::Progress::Dots.stop!
27
+ end
28
+
29
+ it 'pushes a simple sinatra app using defaults as much as possible' do
30
+ run("#{vmc_bin} target http://#{target}") do |runner|
31
+ expect(runner).to say %r{Setting target to http://#{target}... OK}
32
+ end
33
+
34
+ run("#{vmc_bin} login") do |runner|
35
+ expect(runner).to say %r{target: https?://#{target}}
36
+
37
+ expect(runner).to say "Email>"
38
+ runner.send_keys username
39
+
40
+ expect(runner).to say "Password>"
41
+ runner.send_keys password
42
+
43
+ expect(runner).to say "Authenticating... OK"
44
+
45
+ expect(runner).to say "1:"
46
+ expect(runner).to say "Organization>"
47
+ runner.send_keys "1"
48
+
49
+ expect(runner).to say /Switching to organization .*\.\.\. OK/
50
+ expect(runner).to say /Switching to space .*\.\.\. OK/
51
+ end
52
+
53
+ run("#{vmc_bin} app #{app}") do |runner|
54
+ expect(runner).to say "Unknown app '#{app}'."
55
+ end
56
+
57
+ Dir.chdir("#{SPEC_ROOT}/assets/hello-sinatra") do
58
+ run("#{vmc_bin} push") do |runner|
59
+ expect(runner).to say "Name>"
60
+ runner.send_keys app
61
+
62
+ expect(runner).to say "Instances> 1"
63
+ runner.send_keys ""
64
+
65
+ expect(runner).to say ": other"
66
+ expect(runner).to say "Framework>"
67
+ runner.send_keys "other"
68
+
69
+ expect(runner).to say ": buildpack"
70
+ expect(runner).to say "Framework>"
71
+ runner.send_keys "buildpack"
72
+
73
+ expect(runner).to say "Use custom startup command?> "
74
+ runner.send_keys "y"
75
+
76
+ expect(runner).to say "Startup command> "
77
+ runner.send_keys "bundle exec ruby main.rb -p $PORT"
78
+
79
+ expect(runner).to say ": ruby19"
80
+ expect(runner).to say "Runtime>"
81
+ runner.send_keys "ruby19"
82
+
83
+ expect(runner).to say "Memory Limit>"
84
+ runner.send_keys "64M"
85
+
86
+ expect(runner).to say "Creating #{app}... OK"
87
+
88
+ expect(runner).to say "Subdomain> #{app}"
89
+ runner.send_keys ""
90
+
91
+ expect(runner).to say "1:"
92
+ expect(runner).to say "Domain>"
93
+ runner.send_keys "1"
94
+
95
+ expect(runner).to say(/Creating route #{app}\..*\.\.\. OK/)
96
+ expect(runner).to say(/Binding #{app}\..* to #{app}\.\.\. OK/)
97
+
98
+ expect(runner).to say "Create services for application?> n"
99
+ runner.send_keys ""
100
+
101
+ expect(runner).to say "Save configuration?> n"
102
+ runner.send_keys ""
103
+
104
+ expect(runner).to say "Uploading #{app}... OK"
105
+ expect(runner).to say "Starting #{app}... OK"
106
+
107
+ expect(runner).to say "Using Ruby", 10
108
+ expect(runner).to say "Your bundle is complete!", 30
109
+
110
+ expect(runner).to say "Checking #{app}..."
111
+ expect(runner).to say "1/1 instances"
112
+ expect(runner).to say "OK", 30
113
+ end
114
+ end
115
+
116
+ run("#{vmc_bin} delete #{app}") do |runner|
117
+ expect(runner).to say "Really delete #{app}?>"
118
+ runner.send_keys "y"
119
+
120
+ expect(runner).to say "Deleting #{app}... OK"
121
+ end
122
+ end
123
+ end
124
+ else
125
+ $stderr.puts 'Skipping integration specs; please provide $VMC_TEST_TARGET, $VMC_TEST_USER, and $VMC_TEST_PASSWORD'
126
+ end