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.
@@ -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/alphagov/vcloud-launcher#credentials).
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.should_not be_nil
22
- provisioned_vapp[:name].should eq(test_data_1[:vapp_name])
23
- provisioned_vapp[:Children][:Vm].count.should eq(1)
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).should eq(true)
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].should eq(@test_data[:vapp_name])
54
- @vapp[:'ovf:NetworkSection'][:'ovf:Network'].count.should eq(2)
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.should =~ [@test_data[:network_1], @test_data[:network_2]]
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.should_not be_nil
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).should eq('8192')
68
- extract_cpu(@vm).should eq('4')
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.should eq(6)
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].should eq(true)
77
- @vm_metadata[:is_integer].should eq(-999)
78
- @vm_metadata[:is_string].should eq('Hello World')
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.should eq(3)
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.should include(new_disk)
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.should_not be_nil
92
- vm_network_connection.count.should eq(2)
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].should eq(@test_data[:network_1])
97
- primary_nic[:NetworkConnectionIndex].should eq(@vm[:NetworkConnectionSection][:PrimaryNetworkConnectionIndex])
98
- primary_nic[:IpAddress].should eq(@test_data[:network_1_ip])
99
- primary_nic[:IpAddressAllocationMode].should eq('MANUAL')
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].should eq(@test_data[:network_2])
103
- second_nic[:NetworkConnectionIndex].should eq('1')
104
- second_nic[:IpAddress].should eq(@test_data[:network_2_ip])
105
- second_nic[:IpAddressAllocationMode].should eq('MANUAL')
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].should =~ /message: hello world/
111
- @vm[:GuestCustomizationSection][:ComputerName].should eq(@test_data[:vapp_name])
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].should eq(@test_data[:storage_profile])
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).should eq(true)
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
- parameters = Vcloud::Tools::Tester::TestParameters.new(config_file)
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].should eq(@test_data[:storage_profile])
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].should eq(@test_data[:vdc_1_sp_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].should eq(@test_data[:storage_profile])
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].should eq(@test_data[:vdc_2_sp_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 and continues" do
50
- @vm_3[:StorageProfile][:name].should eq(@test_data[:default_storage_profile_name])
51
- @vm_3[:StorageProfile][:href].should eq(@test_data[:default_storage_profile_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).should eq(true)
76
- @fog_interface.delete_vapp(@vapp_id_2).should eq(true)
77
- @fog_interface.delete_vapp(@vapp_id_3).should eq(true)
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
- parameters = Vcloud::Tools::Tester::TestParameters.new(config_file)
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,
@@ -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