vcloud-launcher 0.1.0 → 0.2.0
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.
- data/.gitignore +1 -0
- data/.travis.yml +2 -0
- data/CHANGELOG.md +13 -0
- data/CONTRIBUTING.md +66 -0
- data/Gemfile +2 -2
- data/Rakefile +3 -9
- data/bin/vcloud-launch +1 -44
- data/lib/vcloud/launcher.rb +2 -0
- data/lib/vcloud/launcher/cli.rb +103 -0
- data/lib/vcloud/launcher/launch.rb +36 -1
- data/lib/vcloud/launcher/preamble.rb +60 -0
- data/lib/vcloud/launcher/version.rb +1 -1
- data/lib/vcloud/launcher/vm_orchestrator.rb +10 -5
- data/spec/integration/README.md +1 -1
- data/spec/integration/launcher/data/storage_profile.yaml.erb +0 -30
- data/spec/integration/launcher/{vcloud_launcher_spec.rb → launch_spec.rb} +42 -31
- data/spec/integration/launcher/storage_profile_integration_spec.rb +23 -35
- data/spec/spec_helper.rb +29 -0
- data/spec/vcloud/launcher/cli_spec.rb +214 -0
- data/spec/vcloud/launcher/launch_spec.rb +107 -1
- data/spec/vcloud/launcher/preamble_spec.rb +214 -0
- data/spec/vcloud/launcher/vapp_orchestrator_spec.rb +14 -14
- data/spec/vcloud/launcher/vm_orchestrator_spec.rb +109 -22
- data/vcloud-launcher.gemspec +8 -8
- metadata +40 -71
- data/features/step_definitions/vcloud-launch_steps.rb +0 -3
- data/features/support/env.rb +0 -16
- data/features/vcloud-launch.feature +0 -18
data/spec/integration/README.md
CHANGED
@@ -12,7 +12,7 @@
|
|
12
12
|
|
13
13
|
There is a [template file](/spec/integration/vcloud_tools_testing_config.yaml.template) to help with this. Copy the template file to `/spec/integration` (i.e. next to the template file) and remove the `.template`. This file will now be ignored by Git and you can safely add the parameters relevant to your environment.
|
14
14
|
|
15
|
-
- You need to include the set-up for your testing environment in your [fog file](https://github.com/
|
15
|
+
- You need to include the set-up for your testing environment in your [fog file](https://github.com/gds-operations/vcloud-launcher#credentials).
|
16
16
|
|
17
17
|
- The tests use the [vCloud Tools Tester](http://rubygems.org/gems/vcloud-tools-tester) gem. You do not need to install this, `bundler` will do this for you.
|
18
18
|
|
@@ -5,44 +5,14 @@ vapps:
|
|
5
5
|
catalog_name: <%= catalog %>
|
6
6
|
vapp_template_name: <%= vapp_template %>
|
7
7
|
vm:
|
8
|
-
hardware_config: &hardware_config
|
9
|
-
memory: 4096
|
10
|
-
cpu: 2
|
11
|
-
bootstrap: &bootstrap
|
12
|
-
script_path: <%= bootstrap_script %>
|
13
|
-
vars:
|
14
|
-
message: hello world
|
15
8
|
storage_profile: <%= storage_profile %>
|
16
9
|
- name: <%= vapp_name_2 %>
|
17
10
|
vdc_name: <%= vdc_2_name %>
|
18
11
|
catalog_name: <%= catalog %>
|
19
12
|
vapp_template_name: <%= vapp_template %>
|
20
13
|
vm:
|
21
|
-
hardware_config:
|
22
|
-
<<: *hardware_config
|
23
|
-
bootstrap:
|
24
|
-
<<: *bootstrap
|
25
14
|
storage_profile: <%= storage_profile %>
|
26
15
|
- name: <%= vapp_name_3 %>
|
27
16
|
vdc_name: <%= vdc_1_name %>
|
28
17
|
catalog_name: <%= catalog %>
|
29
18
|
vapp_template_name: <%= vapp_template %>
|
30
|
-
vm:
|
31
|
-
hardware_config:
|
32
|
-
<<: *hardware_config
|
33
|
-
metadata:
|
34
|
-
storage_profile_test_vm: true
|
35
|
-
bootstrap:
|
36
|
-
<<: *bootstrap
|
37
|
-
- name: <%= vapp_name_4 %>
|
38
|
-
vdc_name: <%= vdc_1_name %>
|
39
|
-
catalog_name: <%= catalog %>
|
40
|
-
vapp_template_name: <%= vapp_template %>
|
41
|
-
vm:
|
42
|
-
hardware_config:
|
43
|
-
<<: *hardware_config
|
44
|
-
metadata:
|
45
|
-
storage_profile_test_vm: true
|
46
|
-
bootstrap:
|
47
|
-
<<: *bootstrap
|
48
|
-
storage_profile: <%= nonsense_storage_profile %>
|
@@ -18,15 +18,15 @@ describe Vcloud::Launcher::Launch do
|
|
18
18
|
@provisioned_vapp_id = vapp_query_result[:href].split('/').last
|
19
19
|
provisioned_vapp = @fog_interface.get_vapp @provisioned_vapp_id
|
20
20
|
|
21
|
-
provisioned_vapp.
|
22
|
-
provisioned_vapp[:name].
|
23
|
-
provisioned_vapp[:Children][:Vm].count.
|
21
|
+
expect(provisioned_vapp).not_to be_nil
|
22
|
+
expect(provisioned_vapp[:name]).to eq(test_data_1[:vapp_name])
|
23
|
+
expect(provisioned_vapp[:Children][:Vm].count).to eq(1)
|
24
24
|
end
|
25
25
|
|
26
26
|
after(:each) do
|
27
27
|
unless ENV['VCLOUD_TOOLS_RSPEC_NO_DELETE_VAPP']
|
28
28
|
File.delete @minimum_data_yaml
|
29
|
-
@fog_interface.delete_vapp(@provisioned_vapp_id).
|
29
|
+
expect(@fog_interface.delete_vapp(@provisioned_vapp_id)).to eq(true)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
@@ -50,69 +50,69 @@ describe Vcloud::Launcher::Launch do
|
|
50
50
|
|
51
51
|
context 'provision vapp' do
|
52
52
|
it 'should create a vapp' do
|
53
|
-
@vapp[:name].
|
54
|
-
@vapp[:'ovf:NetworkSection'][:'ovf:Network'].count.
|
53
|
+
expect(@vapp[:name]).to eq(@test_data[:vapp_name])
|
54
|
+
expect(@vapp[:'ovf:NetworkSection'][:'ovf:Network'].count).to eq(2)
|
55
55
|
vapp_networks = @vapp[:'ovf:NetworkSection'][:'ovf:Network'].collect { |connection| connection[:ovf_name] }
|
56
|
-
vapp_networks.
|
56
|
+
expect(vapp_networks).to match_array([@test_data[:network_1], @test_data[:network_2]])
|
57
57
|
end
|
58
58
|
|
59
59
|
it "should create vm within vapp" do
|
60
|
-
@vm.
|
60
|
+
expect(@vm).not_to be_nil
|
61
61
|
end
|
62
62
|
|
63
63
|
end
|
64
64
|
|
65
65
|
context "customize vm" do
|
66
66
|
it "change cpu for given vm" do
|
67
|
-
extract_memory(@vm).
|
68
|
-
extract_cpu(@vm).
|
67
|
+
expect(extract_memory(@vm)).to eq('8192')
|
68
|
+
expect(extract_cpu(@vm)).to eq('4')
|
69
69
|
end
|
70
70
|
|
71
71
|
it "should have added the right number of metadata values" do
|
72
|
-
@vm_metadata.count.
|
72
|
+
expect(@vm_metadata.count).to eq(6)
|
73
73
|
end
|
74
74
|
|
75
75
|
it "the metadata should be equivalent to our input" do
|
76
|
-
@vm_metadata[:is_true].
|
77
|
-
@vm_metadata[:is_integer].
|
78
|
-
@vm_metadata[:is_string].
|
76
|
+
expect(@vm_metadata[:is_true]).to eq(true)
|
77
|
+
expect(@vm_metadata[:is_integer]).to eq(-999)
|
78
|
+
expect(@vm_metadata[:is_string]).to eq('Hello World')
|
79
79
|
end
|
80
80
|
|
81
81
|
it "should attach extra hard disks to vm" do
|
82
82
|
disks = extract_disks(@vm)
|
83
|
-
disks.count.
|
83
|
+
expect(disks.count).to eq(3)
|
84
84
|
[{:name => 'Hard disk 2', :size => '1024'}, {:name => 'Hard disk 3', :size => '2048'}].each do |new_disk|
|
85
|
-
disks.
|
85
|
+
expect(disks).to include(new_disk)
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
89
|
it "should configure the vm network interface" do
|
90
90
|
vm_network_connection = @vm[:NetworkConnectionSection][:NetworkConnection]
|
91
|
-
vm_network_connection.
|
92
|
-
vm_network_connection.count.
|
91
|
+
expect(vm_network_connection).not_to be_nil
|
92
|
+
expect(vm_network_connection.count).to eq(2)
|
93
93
|
|
94
94
|
|
95
95
|
primary_nic = vm_network_connection.detect { |connection| connection[:network] == @test_data[:network_1] }
|
96
|
-
primary_nic[:network].
|
97
|
-
primary_nic[:NetworkConnectionIndex].
|
98
|
-
primary_nic[:IpAddress].
|
99
|
-
primary_nic[:IpAddressAllocationMode].
|
96
|
+
expect(primary_nic[:network]).to eq(@test_data[:network_1])
|
97
|
+
expect(primary_nic[:NetworkConnectionIndex]).to eq(@vm[:NetworkConnectionSection][:PrimaryNetworkConnectionIndex])
|
98
|
+
expect(primary_nic[:IpAddress]).to eq(@test_data[:network_1_ip])
|
99
|
+
expect(primary_nic[:IpAddressAllocationMode]).to eq('MANUAL')
|
100
100
|
|
101
101
|
second_nic = vm_network_connection.detect { |connection| connection[:network] == @test_data[:network_2] }
|
102
|
-
second_nic[:network].
|
103
|
-
second_nic[:NetworkConnectionIndex].
|
104
|
-
second_nic[:IpAddress].
|
105
|
-
second_nic[:IpAddressAllocationMode].
|
102
|
+
expect(second_nic[:network]).to eq(@test_data[:network_2])
|
103
|
+
expect(second_nic[:NetworkConnectionIndex]).to eq('1')
|
104
|
+
expect(second_nic[:IpAddress]).to eq(@test_data[:network_2_ip])
|
105
|
+
expect(second_nic[:IpAddressAllocationMode]).to eq('MANUAL')
|
106
106
|
|
107
107
|
end
|
108
108
|
|
109
109
|
it 'should assign guest customization script to the VM' do
|
110
|
-
@vm[:GuestCustomizationSection][:CustomizationScript].
|
111
|
-
@vm[:GuestCustomizationSection][:ComputerName].
|
110
|
+
expect(@vm[:GuestCustomizationSection][:CustomizationScript]).to match(/message: hello world/)
|
111
|
+
expect(@vm[:GuestCustomizationSection][:ComputerName]).to eq(@test_data[:vapp_name])
|
112
112
|
end
|
113
113
|
|
114
114
|
it "should assign storage profile to the VM" do
|
115
|
-
@vm[:StorageProfile][:name].
|
115
|
+
expect(@vm[:StorageProfile][:name]).to eq(@test_data[:storage_profile])
|
116
116
|
end
|
117
117
|
|
118
118
|
end
|
@@ -120,7 +120,7 @@ describe Vcloud::Launcher::Launch do
|
|
120
120
|
after(:all) do
|
121
121
|
unless ENV['VCLOUD_TOOLS_RSPEC_NO_DELETE_VAPP']
|
122
122
|
File.delete @config_yaml
|
123
|
-
@fog_interface.delete_vapp(@vapp_id).
|
123
|
+
expect(@fog_interface.delete_vapp(@vapp_id)).to eq(true)
|
124
124
|
end
|
125
125
|
end
|
126
126
|
|
@@ -143,7 +143,18 @@ describe Vcloud::Launcher::Launch do
|
|
143
143
|
def define_test_data
|
144
144
|
config_file = File.join(File.dirname(__FILE__),
|
145
145
|
"../vcloud_tools_testing_config.yaml")
|
146
|
-
|
146
|
+
required_user_params = [
|
147
|
+
"vdc_1_name",
|
148
|
+
"catalog",
|
149
|
+
"vapp_template",
|
150
|
+
"storage_profile",
|
151
|
+
"network_1",
|
152
|
+
"network_2",
|
153
|
+
"network_1_ip",
|
154
|
+
"network_2_ip",
|
155
|
+
]
|
156
|
+
|
157
|
+
parameters = Vcloud::Tools::Tester::TestSetup.new(config_file, required_user_params).test_params
|
147
158
|
{
|
148
159
|
vapp_name: "vapp-vcloud-tools-tests-#{Time.now.strftime('%s')}",
|
149
160
|
vdc_name: parameters.vdc_1_name,
|
@@ -24,58 +24,35 @@ describe Vcloud::Launcher::Launch do
|
|
24
24
|
@vapp_3 = @fog_interface.get_vapp @vapp_id_3
|
25
25
|
@vm_3 = @vapp_3[:Children][:Vm].first
|
26
26
|
|
27
|
-
@vapp_query_result_4 = @fog_interface.get_vapp_by_name_and_vdc_name(@test_data[:vapp_name_4], @test_data[:vdc_1_name])
|
28
|
-
@vapp_id_4 = @vapp_query_result_4[:href].split('/').last
|
29
|
-
@vapp_4 = @fog_interface.get_vapp @vapp_id_4
|
30
|
-
@vm_4 = @vapp_4[:Children][:Vm].first
|
31
27
|
end
|
32
28
|
|
33
29
|
it "vdc 1 should have a storage profile without the href being specified" do
|
34
|
-
@vm_1[:StorageProfile][:name].
|
30
|
+
expect(@vm_1[:StorageProfile][:name]).to eq(@test_data[:storage_profile])
|
35
31
|
end
|
36
32
|
|
37
33
|
it "vdc 1's storage profile should have the expected href" do
|
38
|
-
@vm_1[:StorageProfile][:href].
|
34
|
+
expect(@vm_1[:StorageProfile][:href]).to eq(@test_data[:vdc_1_sp_href])
|
39
35
|
end
|
40
36
|
|
41
37
|
it "vdc 2 should have the same named storage profile as vdc 1" do
|
42
|
-
@vm_2[:StorageProfile][:name].
|
38
|
+
expect(@vm_2[:StorageProfile][:name]).to eq(@test_data[:storage_profile])
|
43
39
|
end
|
44
40
|
|
45
41
|
it "the storage profile in vdc 2 should have a different href to the storage profile in vdc 1" do
|
46
|
-
@vm_2[:StorageProfile][:href].
|
42
|
+
expect(@vm_2[:StorageProfile][:href]).to eq(@test_data[:vdc_2_sp_href])
|
47
43
|
end
|
48
44
|
|
49
|
-
it "when a storage profile is not specified, vm uses the default
|
50
|
-
@vm_3[:StorageProfile][:name].
|
51
|
-
@vm_3[:StorageProfile][:href].
|
52
|
-
end
|
53
|
-
|
54
|
-
it "when a storage profile is not specified, customize continues with other customizations" do
|
55
|
-
@vm_3_id = @vm_3[:href].split('/').last
|
56
|
-
@vm_3_metadata = Vcloud::Core::Vm.get_metadata @vm_3_id
|
57
|
-
@vm_3_metadata[:storage_profile_test_vm].should eq(true)
|
58
|
-
end
|
59
|
-
|
60
|
-
it "when a storage profile specified does not exist, vm uses the default" do
|
61
|
-
@vm_4[:StorageProfile][:name].should eq(@test_data[:default_storage_profile_name])
|
62
|
-
@vm_4[:StorageProfile][:href].should eq(@test_data[:default_storage_profile_href])
|
63
|
-
end
|
64
|
-
|
65
|
-
# This is a bug - if it has failed customization it should let the user know
|
66
|
-
it "when storage profile specified doesn't exist, it errors and continues" do
|
67
|
-
@vm_4_id = @vm_4[:href].split('/').last
|
68
|
-
@vm_4_metadata = Vcloud::Core::Vm.get_metadata @vm_4_id
|
69
|
-
@vm_4_metadata[:storage_profile_test_vm].should be_nil
|
45
|
+
it "when a storage profile is not specified, vm uses the default" do
|
46
|
+
expect(@vm_3[:StorageProfile][:name]).to eq(@test_data[:default_storage_profile_name])
|
47
|
+
expect(@vm_3[:StorageProfile][:href]).to eq(@test_data[:default_storage_profile_href])
|
70
48
|
end
|
71
49
|
|
72
50
|
after(:all) do
|
73
51
|
unless ENV['VCLOUD_TOOLS_RSPEC_NO_DELETE_VAPP']
|
74
52
|
File.delete @config_yaml
|
75
|
-
@fog_interface.delete_vapp(@vapp_id_1).
|
76
|
-
@fog_interface.delete_vapp(@vapp_id_2).
|
77
|
-
@fog_interface.delete_vapp(@vapp_id_3).
|
78
|
-
@fog_interface.delete_vapp(@vapp_id_4).should eq(true)
|
53
|
+
expect(@fog_interface.delete_vapp(@vapp_id_1)).to eq(true)
|
54
|
+
expect(@fog_interface.delete_vapp(@vapp_id_2)).to eq(true)
|
55
|
+
expect(@fog_interface.delete_vapp(@vapp_id_3)).to eq(true)
|
79
56
|
end
|
80
57
|
end
|
81
58
|
|
@@ -86,12 +63,23 @@ end
|
|
86
63
|
def define_test_data
|
87
64
|
config_file = File.join(File.dirname(__FILE__),
|
88
65
|
"../vcloud_tools_testing_config.yaml")
|
89
|
-
|
66
|
+
required_user_parameters = [
|
67
|
+
"vdc_1_name",
|
68
|
+
"vdc_2_name",
|
69
|
+
"catalog",
|
70
|
+
"vapp_template",
|
71
|
+
"storage_profile",
|
72
|
+
"vdc_1_storage_profile_href",
|
73
|
+
"vdc_2_storage_profile_href",
|
74
|
+
"default_storage_profile_name",
|
75
|
+
"default_storage_profile_href",
|
76
|
+
]
|
77
|
+
|
78
|
+
parameters = Vcloud::Tools::Tester::TestSetup.new(config_file, required_user_parameters).test_params
|
90
79
|
{
|
91
80
|
vapp_name_1: "vdc-1-sp-#{Time.now.strftime('%s')}",
|
92
81
|
vapp_name_2: "vdc-2-sp-#{Time.now.strftime('%s')}",
|
93
82
|
vapp_name_3: "vdc-3-sp-#{Time.now.strftime('%s')}",
|
94
|
-
vapp_name_4: "vdc-4-sp-#{Time.now.strftime('%s')}",
|
95
83
|
vdc_1_name: parameters.vdc_1_name,
|
96
84
|
vdc_2_name: parameters.vdc_2_name,
|
97
85
|
catalog: parameters.catalog,
|
data/spec/spec_helper.rb
CHANGED
@@ -1,2 +1,31 @@
|
|
1
|
+
# SimpleCov must run _first_ according to its README
|
2
|
+
if ENV['COVERAGE']
|
3
|
+
require 'simplecov'
|
4
|
+
|
5
|
+
# monkey-patch to prevent SimpleCov from reporting coverage percentage
|
6
|
+
class SimpleCov::Formatter::HTMLFormatter
|
7
|
+
def output_message(_message)
|
8
|
+
nil
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
SimpleCov.adapters.define 'gem' do
|
13
|
+
add_filter '/spec/'
|
14
|
+
add_filter '/features/'
|
15
|
+
add_filter '/vendor/'
|
16
|
+
|
17
|
+
add_group 'Libraries', '/lib/'
|
18
|
+
end
|
19
|
+
|
20
|
+
SimpleCov.minimum_coverage(99)
|
21
|
+
SimpleCov.start 'gem'
|
22
|
+
end
|
23
|
+
|
1
24
|
require 'erb_helper'
|
2
25
|
require 'vcloud/launcher'
|
26
|
+
|
27
|
+
RSpec.configure do |config|
|
28
|
+
config.expect_with :rspec do |c|
|
29
|
+
c.syntax = :expect
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,214 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class CommandRun
|
4
|
+
attr_accessor :stdout, :stderr, :exitstatus
|
5
|
+
|
6
|
+
def initialize(args)
|
7
|
+
out = StringIO.new
|
8
|
+
err = StringIO.new
|
9
|
+
|
10
|
+
$stdout = out
|
11
|
+
$stderr = err
|
12
|
+
|
13
|
+
begin
|
14
|
+
Vcloud::Launcher::Cli.new(args).run
|
15
|
+
@exitstatus = 0
|
16
|
+
rescue SystemExit => e
|
17
|
+
# Capture exit(n) value.
|
18
|
+
@exitstatus = e.status
|
19
|
+
end
|
20
|
+
|
21
|
+
@stdout = out.string.strip
|
22
|
+
@stderr = err.string.strip
|
23
|
+
|
24
|
+
$stdout = STDOUT
|
25
|
+
$stderr = STDERR
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe Vcloud::Launcher::Cli do
|
30
|
+
subject { CommandRun.new(args) }
|
31
|
+
|
32
|
+
let(:mock_launch) {
|
33
|
+
double(:launch, :run => true)
|
34
|
+
}
|
35
|
+
let(:config_file) { 'config.yaml' }
|
36
|
+
|
37
|
+
describe "under normal usage" do
|
38
|
+
shared_examples "a good CLI command" do
|
39
|
+
it "passes the right CLI options and exits normally" do
|
40
|
+
expect(Vcloud::Launcher::Launch).to receive(:new).
|
41
|
+
and_return(mock_launch)
|
42
|
+
expect(mock_launch).to receive(:run).
|
43
|
+
with(config_file, cli_options)
|
44
|
+
expect(subject.exitstatus).to eq(0)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when given a single config file" do
|
49
|
+
let(:args) { [ config_file ] }
|
50
|
+
let(:cli_options) {
|
51
|
+
{
|
52
|
+
"dont-power-on" => false,
|
53
|
+
"continue-on-error" => false,
|
54
|
+
"quiet" => false,
|
55
|
+
"verbose" => false,
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
it_behaves_like "a good CLI command"
|
60
|
+
end
|
61
|
+
|
62
|
+
context "when asked not to power VMs on" do
|
63
|
+
let(:args) { [ config_file, "--dont-power-on" ] }
|
64
|
+
let(:cli_options) {
|
65
|
+
{
|
66
|
+
"dont-power-on" => true,
|
67
|
+
"continue-on-error" => false,
|
68
|
+
"quiet" => false,
|
69
|
+
"verbose" => false,
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
it_behaves_like "a good CLI command"
|
74
|
+
end
|
75
|
+
|
76
|
+
context "when asked to continue on error" do
|
77
|
+
let(:args) { [ config_file, "--continue-on-error" ] }
|
78
|
+
let(:cli_options) {
|
79
|
+
{
|
80
|
+
"dont-power-on" => false,
|
81
|
+
"continue-on-error" => true,
|
82
|
+
"quiet" => false,
|
83
|
+
"verbose" => false,
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
it_behaves_like "a good CLI command"
|
88
|
+
end
|
89
|
+
|
90
|
+
context "when asked to be quiet" do
|
91
|
+
let(:args) { [ config_file, "--quiet" ] }
|
92
|
+
let(:cli_options) {
|
93
|
+
{
|
94
|
+
"dont-power-on" => false,
|
95
|
+
"continue-on-error" => false,
|
96
|
+
"quiet" => true,
|
97
|
+
"verbose" => false,
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
it_behaves_like "a good CLI command"
|
102
|
+
end
|
103
|
+
|
104
|
+
context "when asked to be verbose" do
|
105
|
+
let(:args) { [ config_file, "--verbose" ] }
|
106
|
+
let(:cli_options) {
|
107
|
+
{
|
108
|
+
"dont-power-on" => false,
|
109
|
+
"continue-on-error" => false,
|
110
|
+
"quiet" => false,
|
111
|
+
"verbose" => true,
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
it_behaves_like "a good CLI command"
|
116
|
+
end
|
117
|
+
|
118
|
+
context "when asked to be verbose and continue on errors" do
|
119
|
+
let(:args) { [ config_file, "--continue-on-error", "--verbose" ] }
|
120
|
+
let(:cli_options) {
|
121
|
+
{
|
122
|
+
"dont-power-on" => false,
|
123
|
+
"continue-on-error" => true,
|
124
|
+
"quiet" => false,
|
125
|
+
"verbose" => true,
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
it_behaves_like "a good CLI command"
|
130
|
+
end
|
131
|
+
|
132
|
+
context "when asked to display version" do
|
133
|
+
let(:args) { %w{--version} }
|
134
|
+
|
135
|
+
it "does not call Launch" do
|
136
|
+
expect(Vcloud::Launcher::Launch).not_to receive(:new)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "prints version and exits normally" do
|
140
|
+
expect(subject.stdout).to eq(Vcloud::Launcher::VERSION)
|
141
|
+
expect(subject.exitstatus).to eq(0)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context "when asked to display help" do
|
146
|
+
let(:args) { %w{--help} }
|
147
|
+
|
148
|
+
it "does not call Launch" do
|
149
|
+
expect(Vcloud::Launcher::Launch).not_to receive(:new)
|
150
|
+
end
|
151
|
+
|
152
|
+
it "prints usage and exits normally" do
|
153
|
+
expect(subject.stderr).to match(/\AUsage: \S+ \[options\] config_file\n/)
|
154
|
+
expect(subject.exitstatus).to eq(0)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe "incorrect usage" do
|
160
|
+
shared_examples "print usage and exit abnormally" do |error|
|
161
|
+
it "does not call Launch" do
|
162
|
+
expect(Vcloud::Launcher::Launch).not_to receive(:new)
|
163
|
+
end
|
164
|
+
|
165
|
+
it "prints error message and usage" do
|
166
|
+
expect(subject.stderr).to match(/\A\S+: #{error}\nUsage: \S+/)
|
167
|
+
end
|
168
|
+
|
169
|
+
it "exits abnormally for incorrect usage" do
|
170
|
+
expect(subject.exitstatus).to eq(2)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
context "when run without any arguments" do
|
175
|
+
let(:args) { %w{} }
|
176
|
+
|
177
|
+
it_behaves_like "print usage and exit abnormally", "must supply config_file"
|
178
|
+
end
|
179
|
+
|
180
|
+
context "when given multiple config files" do
|
181
|
+
let(:args) { %w{one.yaml two.yaml} }
|
182
|
+
|
183
|
+
it_behaves_like "print usage and exit abnormally", "must supply config_file"
|
184
|
+
end
|
185
|
+
|
186
|
+
context "when given an unrecognised argument" do
|
187
|
+
let(:args) { %w{--this-is-garbage} }
|
188
|
+
|
189
|
+
it_behaves_like "print usage and exit abnormally", "invalid option: --this-is-garbage"
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
describe "error handling" do
|
194
|
+
context "when underlying code raises an exception" do
|
195
|
+
let(:args) { %w{test.yaml} }
|
196
|
+
|
197
|
+
it "should print error without backtrace and exit abnormally" do
|
198
|
+
expect(Vcloud::Launcher::Launch).to receive(:new).
|
199
|
+
and_raise("something went horribly wrong")
|
200
|
+
expect(subject.stderr).to eq("something went horribly wrong")
|
201
|
+
expect(subject.exitstatus).to eq(1)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context "when passed an non-existent configuration file" do
|
206
|
+
let(:args) { %w{non-existent.yaml} }
|
207
|
+
|
208
|
+
it "raises a descriptive error" do
|
209
|
+
expect(subject.stderr).to match("No such file or directory(?: @ rb_sysopen)? - non-existent.yaml")
|
210
|
+
expect(subject.exitstatus).to eq(1)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|