af 0.3.22 → 0.5.0.beta.1

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 (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