vcloud-launcher 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|