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,17 @@
1
+ module VMC
2
+ class UserError < RuntimeError
3
+ def initialize(msg)
4
+ @message = msg
5
+ end
6
+
7
+ def to_s
8
+ @message
9
+ end
10
+ end
11
+
12
+ class NotAuthorized < UserError
13
+ def initialize
14
+ @message = "Not authorized."
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,56 @@
1
+ require "set"
2
+ require "yaml"
3
+
4
+ require "vmc/constants"
5
+ require "vmc/cli"
6
+
7
+ module VMC
8
+ module Plugin
9
+ @@plugins = []
10
+
11
+ def self.load_all
12
+ # auto-load gems with 'vmc-plugin' in their name
13
+ matching =
14
+ if Gem::Specification.respond_to? :find_all
15
+ Gem::Specification.find_all do |s|
16
+ s.name =~ /vmc-plugin/
17
+ end
18
+ else
19
+ Gem.source_index.find_name(/vmc-plugin/)
20
+ end
21
+
22
+ enabled = Set.new(matching.collect(&:name))
23
+
24
+ vmc_gems = Gem.loaded_specs["vmc"]
25
+ ((vmc_gems && vmc_gems.dependencies) || Gem.loaded_specs.values).each do |dep|
26
+ if dep.name =~ /vmc-plugin/
27
+ require "#{dep.name}/plugin"
28
+ enabled.delete dep.name
29
+ end
30
+ end
31
+
32
+ # allow explicit enabling/disabling of gems via config
33
+ plugins = File.expand_path(VMC::PLUGINS_FILE)
34
+ if File.exists?(plugins) && yaml = YAML.load_file(plugins)
35
+ enabled += yaml["enabled"] if yaml["enabled"]
36
+ enabled -= yaml["disabled"] if yaml["disabled"]
37
+ end
38
+
39
+ # load up each gem's 'plugin' file
40
+ #
41
+ # we require this file specifically so people can require the gem
42
+ # without it plugging into VMC
43
+ enabled.each do |gemname|
44
+ begin
45
+ require "#{gemname}/plugin"
46
+ rescue Gem::LoadError => e
47
+ puts "Failed to load #{gemname}:"
48
+ puts " #{e}"
49
+ puts
50
+ puts "You may need to update or remove this plugin."
51
+ puts
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,89 @@
1
+ module VMC
2
+ module Spacing
3
+ @@indentation = 0
4
+
5
+ def indented
6
+ @@indentation += 1
7
+ yield
8
+ ensure
9
+ @@indentation -= 1
10
+ end
11
+
12
+ def line(msg = "")
13
+ return puts "" if msg.empty?
14
+
15
+ start_line(msg)
16
+ puts ""
17
+ end
18
+
19
+ def start_line(msg)
20
+ print " " * @@indentation unless quiet?
21
+ print msg
22
+ end
23
+
24
+ def lines(blob)
25
+ blob.each_line do |line|
26
+ start_line(line)
27
+ end
28
+
29
+ line
30
+ end
31
+
32
+ def quiet?
33
+ false
34
+ end
35
+
36
+ def spaced(vals)
37
+ num = 0
38
+ vals.each do |val|
39
+ line unless quiet? || num == 0
40
+ yield val
41
+ num += 1
42
+ end
43
+ end
44
+
45
+ def tabular(*rows)
46
+ spacings = []
47
+ rows.each do |row|
48
+ next unless row
49
+
50
+ row.each.with_index do |col, i|
51
+ next unless col
52
+
53
+ width = text_width(col)
54
+
55
+ if !spacings[i] || width > spacings[i]
56
+ spacings[i] = width
57
+ end
58
+ end
59
+ end
60
+
61
+ columns = spacings.size
62
+ rows.each do |row|
63
+ next unless row
64
+
65
+ row.each.with_index do |col, i|
66
+ next unless col
67
+
68
+ start_line justify(col, spacings[i])
69
+ print " " unless i + 1 == columns
70
+ end
71
+
72
+ line
73
+ end
74
+ end
75
+
76
+ def trim_escapes(str)
77
+ str.gsub(/\e\[\d+m/, "")
78
+ end
79
+
80
+ def text_width(str)
81
+ trim_escapes(str).size
82
+ end
83
+
84
+ def justify(str, width)
85
+ trimmed = trim_escapes(str)
86
+ str.ljust(width + (str.size - trimmed.size))
87
+ end
88
+ end
89
+ end
@@ -0,0 +1 @@
1
+ require File.expand_path("../../../spec/spec_helper", __FILE__)
@@ -0,0 +1,4 @@
1
+ module VMC::TestSupport
2
+ end
3
+
4
+ Dir.glob(File.expand_path("../test_support/*", __FILE__)).each { |file| require file }
@@ -0,0 +1,32 @@
1
+ module VMC::TestSupport::CommandHelper
2
+ def vmc(argv)
3
+ Mothership.new.exit_status 0
4
+ stub(VMC::CLI).exit { |code| code }
5
+ capture_output { VMC::CLI.start(argv + ["--debug"]) }
6
+ end
7
+
8
+ def expect_status_and_output(status = 0, out = "", err = "")
9
+ expect([
10
+ status,
11
+ stdout.string.strip_progress_dots,
12
+ stderr.string.strip_progress_dots
13
+ ]).to eq([status, out, err])
14
+ end
15
+
16
+ def bool_flag(flag)
17
+ "#{'no-' unless send(flag)}#{flag.to_s.gsub('_', '-')}"
18
+ end
19
+
20
+ attr_reader :stdout, :stderr, :status
21
+
22
+ def capture_output
23
+ real_stdout = $stdout
24
+ real_stderr = $stderr
25
+ $stdout = @stdout = StringIO.new
26
+ $stderr = @stderr = StringIO.new
27
+ @status = yield
28
+ ensure
29
+ $stdout = real_stdout
30
+ $stderr = real_stderr
31
+ end
32
+ end
@@ -0,0 +1,14 @@
1
+ shared_examples_for 'inputs must have descriptions' do
2
+ describe 'inputs' do
3
+ subject { command.inputs }
4
+
5
+ it "is not missing any descriptions" do
6
+ subject.each do |_, attrs|
7
+ next if attrs[:hidden]
8
+
9
+ expect(attrs[:description]).to be
10
+ expect(attrs[:description].strip).to_not be_empty
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ module VMC::TestSupport::FakeHomeDir
2
+ def self.included(klass)
3
+ def klass.use_fake_home_dir(&block)
4
+ around do |example|
5
+ dir = instance_exec(&block)
6
+ original_home_dir = ENV['HOME']
7
+ ENV['HOME'] = dir
8
+ begin
9
+ example.call
10
+ ensure
11
+ ENV['HOME'] = original_home_dir
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,29 @@
1
+ module VMC::TestSupport::InteractHelper
2
+ def stub_ask(*args, &block)
3
+ a_stub = nil
4
+ any_instance_of VMC::CLI do |interactive|
5
+ a_stub = stub(interactive).ask(*args, &block)
6
+ end
7
+ a_stub
8
+ end
9
+
10
+ def mock_ask(*args, &block)
11
+ a_mock = nil
12
+ any_instance_of VMC::CLI do |interactive|
13
+ a_mock = mock(interactive).ask(*args, &block)
14
+ end
15
+ a_mock
16
+ end
17
+
18
+ def dont_allow_ask(*args)
19
+ any_instance_of VMC::CLI do |interactive|
20
+ dont_allow(interactive).ask(*args)
21
+ end
22
+ end
23
+
24
+ def mock_with_progress(message)
25
+ any_instance_of VMC::CLI do |interactive|
26
+ mock(interactive).with_progress(message) { |_, block| block.call }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ module VMC
2
+ VERSION = "0.5.0.beta.13".freeze
3
+ end
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "sinatra"
@@ -0,0 +1,6 @@
1
+ require "rubygems"
2
+ require "sinatra"
3
+
4
+ get "/" do
5
+ "Hello, world!"
6
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+ require "webmock/rspec"
3
+
4
+ if ENV['VMC_TEST_USER'] && ENV['VMC_TEST_PASSWORD'] && ENV['VMC_TEST_TARGET']
5
+ describe 'A new user tries to use VMC against v1 production' do
6
+ let(:target) { ENV['VMC_TEST_TARGET'] }
7
+ let(:username) { ENV['VMC_TEST_USER'] }
8
+ let(:password) { ENV['VMC_TEST_PASSWORD'] }
9
+ let(:output) { StringIO.new }
10
+ let(:out) { output.string.strip_progress_dots }
11
+
12
+ let(:app) do
13
+ fuzz = defined?(TRAVIS_BUILD_ID) ? TRAVIS_BUILD_ID : Time.new.to_f.to_s.gsub(".", "_")
14
+ "hello-sinatra-#{fuzz}"
15
+ end
16
+
17
+ before do
18
+ FileUtils.rm_rf File.expand_path(VMC::CONFIG_DIR)
19
+ WebMock.allow_net_connect!
20
+ end
21
+
22
+ after { vmc %W(delete #{app} -f --no-script) }
23
+
24
+ it 'and pushes a simple sinatra app using defaults as much as possible' do
25
+ vmc %W[target #{target} --no-script]
26
+ expect_status_and_output 0, <<-OUT.strip_heredoc
27
+ Setting target to https://#{target}... OK
28
+ OUT
29
+
30
+ vmc %W[login #{username} --password #{password} --no-script]
31
+ expect_status_and_output 0, <<-OUT.strip_heredoc
32
+ target: https://#{target}
33
+
34
+ Authenticating... OK
35
+ OUT
36
+
37
+ vmc %W[app #{app} --no-script]
38
+ expect_status_and_output 1, "", <<-OUT.strip_heredoc
39
+ Unknown app '#{app}'.
40
+ OUT
41
+
42
+ Dir.chdir("#{SPEC_ROOT}/assets/hello-sinatra") do
43
+ vmc %W[push #{app} --runtime ruby19 --domain #{app}-vmc-test.cloudfoundry.com -f --no-script]
44
+ expect_status_and_output 0, <<-OUT.strip_heredoc
45
+ Creating #{app}... OK
46
+
47
+ Updating #{app}... OK
48
+ Uploading #{app}... OK
49
+ Starting #{app}... OK
50
+ Checking #{app}... OK
51
+ OUT
52
+
53
+ vmc %W[push #{app} --no-script]
54
+ expect_status_and_output 0, <<-OUT.strip_heredoc
55
+ Uploading #{app}... OK
56
+ Stopping #{app}... OK
57
+
58
+ Starting #{app}... OK
59
+ Checking #{app}... OK
60
+ OUT
61
+ end
62
+
63
+ vmc %W[delete #{app} -f --no-script]
64
+ expect_status_and_output 0, <<-OUT.strip_heredoc
65
+ Deleting #{app}... OK
66
+ OUT
67
+ end
68
+ end
69
+ else
70
+ $stderr.puts 'Skipping integration specs; please provide $VMC_TEST_TARGET, $VMC_TEST_USER, and $VMC_TEST_PASSWORD'
71
+ end
@@ -0,0 +1,63 @@
1
+ SPEC_ROOT = File.dirname(__FILE__).freeze
2
+
3
+ require "rspec"
4
+ require "cfoundry"
5
+ require "cfoundry/test_support"
6
+ require "vmc"
7
+ require "vmc/test_support"
8
+ require "webmock"
9
+
10
+ Dir[File.expand_path('../support/**/*.rb', __FILE__)].each do |file|
11
+ require file
12
+ end
13
+
14
+ RSpec.configure do |c|
15
+ c.include Fake::FakeMethods
16
+ c.include V1Fake::FakeMethods
17
+ c.mock_with :rr
18
+
19
+ c.include VMC::TestSupport::FakeHomeDir
20
+ c.include VMC::TestSupport::CommandHelper
21
+ c.include VMC::TestSupport::InteractHelper
22
+
23
+ c.before(:all) do
24
+ WebMock.disable_net_connect!
25
+ end
26
+
27
+ c.before do
28
+ VMC::CLI.send(:class_variable_set, :@@client, nil)
29
+ end
30
+ end
31
+
32
+ class String
33
+ def strip_heredoc
34
+ min = scan(/^[ \t]*(?=\S)/).min
35
+ indent = min ? min.size : 0
36
+ gsub(/^[ \t]{#{indent}}/, '')
37
+ end
38
+
39
+ def strip_progress_dots
40
+ gsub(/\. \x08([\x08\. ]+)/, "... ")
41
+ end
42
+ end
43
+
44
+ def name_list(xs)
45
+ if xs.empty?
46
+ "none"
47
+ else
48
+ xs.collect(&:name).join(", ")
49
+ end
50
+ end
51
+
52
+ def invoke_cli(cli, *args)
53
+ stub.proxy(cli).invoke.with_any_args
54
+ stub(cli.class).new { cli }
55
+ cli.invoke(*args)
56
+ end
57
+
58
+ def stub_output(cli)
59
+ stub(cli).print
60
+ stub(cli).puts
61
+ stub(Interact::Progress::Dots).start!
62
+ stub(Interact::Progress::Dots).stop!
63
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+ require "vmc/cli/app/base"
3
+
4
+ describe VMC::App::Base do
5
+ describe '#human_size' do
6
+ let(:base) { VMC::App::Base.new }
7
+
8
+ it { base.human_size(1_023).should == "1023.0B" }
9
+ it { base.human_size(1_024).should == "1.0K" }
10
+ it { base.human_size(1_024 * 1_024).should == "1.0M" }
11
+ it { base.human_size(1_024 * 1_024 * 1.5).should == "1.5M" }
12
+ it { base.human_size(1_024 * 1_024 * 1_024).should == "1.0G" }
13
+ it { base.human_size(1_024 * 1_024 * 1_024 * 1.5).should == "1.5G" }
14
+ it { base.human_size(1_024 * 1_024 * 1_024 * 1.234, 3).should == "1.234G" }
15
+ it { base.human_size(31395840).should == "29.9M" } # tests against floating point errors
16
+ end
17
+ end
@@ -0,0 +1,188 @@
1
+ require 'spec_helper'
2
+ require "vmc/cli/app/delete"
3
+
4
+ describe VMC::App::Delete do
5
+ let(:global) { { :color => false, :quiet => true } }
6
+ let(:inputs) { {} }
7
+ let(:given) { {} }
8
+ let(:client) { fake_client }
9
+ let(:app) {}
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(:delete, inputs, given, global) }
20
+
21
+ describe 'metadata' do
22
+ let(:command) { Mothership.commands[:delete] }
23
+
24
+ describe 'command' do
25
+ subject { command }
26
+ its(:description) { should eq "Delete an application" }
27
+ it { expect(Mothership::Help.group(:apps, :manage)).to include(subject) }
28
+ end
29
+
30
+ include_examples 'inputs must have descriptions'
31
+
32
+ describe 'arguments' do
33
+ subject { command.arguments }
34
+ it 'has the correct argument order' do
35
+ should eq([{ :type => :splat, :value => nil, :name => :apps }])
36
+ end
37
+ end
38
+ end
39
+
40
+ context 'when there are no apps' do
41
+ context 'and an app is given' do
42
+ let(:given) { { :app => "some-app" } }
43
+ it { expect { subject }.to raise_error(VMC::UserError, "Unknown app 'some-app'.") }
44
+ end
45
+
46
+ context 'and an app is not given' do
47
+ it { expect { subject }.to raise_error(VMC::UserError, "No applications.") }
48
+ end
49
+ end
50
+
51
+ context 'when there are apps' do
52
+ let(:client) { fake_client(:apps => apps) }
53
+ let(:apps) { [basic_app, app_with_orphans, app_without_orphans] }
54
+ let(:service_1) { fake :service_instance }
55
+ let(:service_2) { fake :service_instance }
56
+ let(:basic_app) { fake(:app, :name => "basic_app") }
57
+ let(:app_with_orphans) {
58
+ fake :app,
59
+ :name => "app_with_orphans",
60
+ :service_bindings => [
61
+ fake(:service_binding, :service_instance => service_1),
62
+ fake(:service_binding, :service_instance => service_2)
63
+ ]
64
+ }
65
+ let(:app_without_orphans) {
66
+ fake :app,
67
+ :name => "app_without_orphans",
68
+ :service_bindings => [
69
+ fake(:service_binding, :service_instance => service_1)
70
+ ]
71
+ }
72
+
73
+ context 'and no app is given' do
74
+ it 'asks for the app' do
75
+ mock_ask("Delete which application?", anything) { basic_app }
76
+ stub_ask { true }
77
+ stub(basic_app).delete!
78
+ subject
79
+ end
80
+ end
81
+
82
+ context 'and a basic app is given' do
83
+ let(:deleted_app) { basic_app }
84
+ let(:given) { { :app => deleted_app.name } }
85
+
86
+ context 'and it asks for confirmation' do
87
+ context 'and the user answers no' do
88
+ it 'does not delete the application' do
89
+ mock_ask("Really delete #{deleted_app.name}?", anything) { false }
90
+ dont_allow(deleted_app).delete!
91
+ subject
92
+ end
93
+ end
94
+
95
+ context 'and the user answers yes' do
96
+ it 'deletes the application' do
97
+ mock_ask("Really delete #{deleted_app.name}?", anything) { true }
98
+ mock(deleted_app).delete!
99
+ subject
100
+ end
101
+ end
102
+ end
103
+
104
+ context 'and --force is given' do
105
+ let(:global) { { :force => true, :color => false, :quiet => true } }
106
+
107
+ it 'deletes the application without asking to confirm' do
108
+ dont_allow_ask
109
+ mock(deleted_app).delete!
110
+ subject
111
+ end
112
+ end
113
+ end
114
+
115
+ context 'and an app with orphaned services is given' do
116
+ let(:deleted_app) { app_with_orphans }
117
+ let(:inputs) { { :app => deleted_app } }
118
+
119
+ context 'and it asks for confirmation' do
120
+ context 'and the user answers yes' do
121
+ it 'asks to delete orphaned services' do
122
+ stub_ask("Really delete #{deleted_app.name}?", anything) { true }
123
+ stub(deleted_app).delete!
124
+
125
+ stub(service_2).invalidate!
126
+
127
+ mock_ask("Delete orphaned service #{service_2.name}?", anything) { true }
128
+
129
+ any_instance_of(VMC::App::Delete) do |del|
130
+ mock(del).invoke :delete_service, :service => service_2,
131
+ :really => true
132
+ end
133
+
134
+ subject
135
+ end
136
+ end
137
+
138
+ context 'and the user answers no' do
139
+ it 'does not ask to delete orphaned serivces, or delete them' do
140
+ stub_ask("Really delete #{deleted_app.name}?", anything) { false }
141
+ dont_allow(deleted_app).delete!
142
+
143
+ stub(service_2).invalidate!
144
+
145
+ dont_allow_ask("Delete orphaned service #{service_2.name}?")
146
+
147
+ any_instance_of(VMC::App::Delete) do |del|
148
+ dont_allow(del).invoke(:delete_service, anything)
149
+ end
150
+
151
+ subject
152
+ end
153
+ end
154
+ end
155
+
156
+ context 'and --force is given' do
157
+ let(:global) { { :force => true, :color => false, :quiet => true } }
158
+
159
+ it 'does not delete orphaned services' do
160
+ dont_allow_ask
161
+ stub(deleted_app).delete!
162
+
163
+ any_instance_of(VMC::App::Delete) do |del|
164
+ dont_allow(del).invoke(:delete_service, anything)
165
+ end
166
+
167
+ subject
168
+ end
169
+ end
170
+
171
+ context 'and --delete-orphaned is given' do
172
+ let(:inputs) { { :app => deleted_app, :delete_orphaned => true } }
173
+
174
+ it 'deletes the orphaned services' do
175
+ stub_ask("Really delete #{deleted_app.name}?", anything) { true }
176
+ stub(deleted_app).delete!
177
+
178
+ any_instance_of(VMC::App::Delete) do |del|
179
+ mock(del).invoke :delete_service, :service => service_2,
180
+ :really => true
181
+ end
182
+
183
+ subject
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end