Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 75 additions & 1 deletion spec/tasks/abs_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@
include_context('with tmpdir')

def with_env(env_vars)
original = env_vars.keys.each_with_object({}) { |k, h| h[k] = ENV.fetch(k, nil) }
env_vars.each { |k, v| ENV[k] = v }
yield
ensure
env_vars.each { |k, _v| ENV.delete(k) }
original.each { |k, v| v.nil? ? ENV.delete(k) : ENV[k] = v }
end

before(:each) do
Expand Down Expand Up @@ -71,6 +72,27 @@
end,
)
end

it 'raises when both node_name and platform are given for tear_down' do
expect($stdin).to receive(:read).and_return('{"action":"tear_down","node_name":"foo","platform":"bar"}')
expect { ABSProvision.run }.to raise_error(RuntimeError, %r{specify only a node_name})
end

it 'raises when both node_name and platform are given for provision' do
expect($stdin).to receive(:read).and_return('{"action":"provision","node_name":"foo","platform":"bar"}')
expect { ABSProvision.run }.to raise_error(RuntimeError, %r{specify only a platform})
end

it 'outputs error and exits 1 when task raises' do
expect($stdin).to receive(:read).and_return('{"action":"provision","platform":"centos-8"}')
runner = ABSProvision.new
allow(ABSProvision).to receive(:new).and_return(runner)
allow(runner).to receive(:task).and_raise(StandardError, 'network error')
expect { ABSProvision.run }.to(
raise_error(SystemExit) { |e| expect(e.status).to eq(1) }
.and(output(%r{abs_failure}).to_stdout),
)
end
end

context 'when provisioning' do
Expand Down Expand Up @@ -120,7 +142,59 @@
expect(abs.task(**params)).to eq({ status: 'ok', nodes: 1 })
end

it 'raises an error if abs returns error response'

Check warning on line 145 in spec/tasks/abs_spec.rb

View workflow job for this annotation

GitHub Actions / Spec / Spec tests (Puppet: ~> 8.0, Ruby Ver: 3.2)

provision::abs when provisioning raises an error if abs returns error response Skipped: Not yet implemented

Check warning on line 145 in spec/tasks/abs_spec.rb

View workflow job for this annotation

GitHub Actions / Spec / Spec tests (Puppet: ~> 9.0, Ruby Ver: 4)

provision::abs when provisioning raises an error if abs returns error response Skipped: Not yet implemented

it 'uses AppVeyor job URL when running in AppVeyor CI' do
stub_request(:post, 'https://abs-prod.k8s.infracore.puppet.net/api/v2/request')
.with { |request| JSON.parse(request.body).dig('job', 'tags', 'jenkins_build_url') == 'https://ci.appveyor.com/project/org/repo/build/job/123' }
.to_return({ status: 202 }, { status: 200, body: response_body.to_json })
with_env('CI' => 'True', 'APPVEYOR' => 'True', 'APPVEYOR_REPO_NAME' => 'org/repo', 'APPVEYOR_JOB_ID' => '123') do
Comment thread
bronachfalls marked this conversation as resolved.
expect(abs.task(**params)).to eq({ status: 'ok', nodes: 1 })
end
end

it 'uses GitHub Actions job URL when running in GitHub Actions' do
stub_request(:post, 'https://abs-prod.k8s.infracore.puppet.net/api/v2/request')
.to_return({ status: 202 }, { status: 200, body: response_body.to_json })
with_env('GITHUB_ACTIONS' => 'true', 'GITHUB_REPOSITORY' => 'org/repo', 'GITHUB_RUN_ID' => '456') do
expect(abs.task(**params)).to eq({ status: 'ok', nodes: 1 })
end
end

it 'uses litmus_manual URL when not in a known CI environment' do
stub_request(:post, 'https://abs-prod.k8s.infracore.puppet.net/api/v2/request')
.to_return({ status: 202 }, { status: 200, body: response_body.to_json })
with_env('CI' => nil, 'TRAVIS' => nil, 'APPVEYOR' => nil, 'GITHUB_ACTIONS' => nil) do
expect(abs.task(**params)).to eq({ status: 'ok', nodes: 1 })
end
end

it 'uses ABS_SSH_PRIVATE_KEY when set' do
stub_request(:post, 'https://abs-prod.k8s.infracore.puppet.net/api/v2/request')
.to_return({ status: 202 }, { status: 200, body: response_body.to_json })
with_env('ABS_SSH_PRIVATE_KEY' => '/path/to/key') do
abs.task(**params)
end
target = YAML.load_file(inventory_file)['groups'].find { |g| g['name'] == 'ssh_nodes' }['targets'].first
expect(target.dig('config', 'ssh', 'private-key')).to eq('/path/to/key')
end

it 'provisions a Windows platform into winrm_nodes with vars' do
windows_response = [{ 'type' => 'windows-2019-x86_64', 'hostname' => 'win-host.test' }]
stub_request(:post, 'https://abs-prod.k8s.infracore.puppet.net/api/v2/request')
.to_return({ status: 202 }, { status: 200, body: windows_response.to_json })
windows_params = params.merge(platform: 'windows-2019-x86_64', vars: 'role: agent_win')
abs.task(**windows_params)
targets = YAML.load_file(inventory_file)['groups'].find { |g| g['name'] == 'winrm_nodes' }['targets']
expect(targets.size).to eq(1)
expect(targets.first['vars']).to eq({ 'role' => 'agent_win' })
end

it 'handles a Hash platform' do
stub_request(:post, 'https://abs-prod.k8s.infracore.puppet.net/api/v2/request')
.to_return({ status: 202 }, { status: 200, body: response_body.to_json })
expect(abs.task(action: 'provision', platform: { 'redhat-8-x86_64' => 1 }, inventory: inventory_file)).to eq({ status: 'ok', nodes: 1 })
end
end

context 'when tearing down' do
Expand Down Expand Up @@ -168,6 +242,6 @@
end
end

it 'raises an error if abs returns error response'

Check warning on line 245 in spec/tasks/abs_spec.rb

View workflow job for this annotation

GitHub Actions / Spec / Spec tests (Puppet: ~> 8.0, Ruby Ver: 3.2)

provision::abs when tearing down raises an error if abs returns error response Skipped: Not yet implemented

Check warning on line 245 in spec/tasks/abs_spec.rb

View workflow job for this annotation

GitHub Actions / Spec / Spec tests (Puppet: ~> 9.0, Ruby Ver: 4)

provision::abs when tearing down raises an error if abs returns error response Skipped: Not yet implemented
end
end
63 changes: 63 additions & 0 deletions spec/tasks/provision_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,22 @@
)
end
end

it 'calls provision and exits 0' do
allow($stdin).to receive(:read).and_return('{"action":"provision","platform":"centos-8"}')
runner = ProvisionService.new
allow(ProvisionService).to receive(:new).and_return(runner)
expect(runner).to receive(:provision).with('centos-8', instance_of(InventoryHelper), nil, nil).and_return({ status: 'ok', node_name: 'centos-8' })
expect { ProvisionService.run }.to raise_error(SystemExit) { |e| expect(e.status).to eq(0) }
end

it 'calls tear_down and exits 0' do
allow($stdin).to receive(:read).and_return('{"action":"tear_down","node_name":"some-node"}')
runner = ProvisionService.new
allow(ProvisionService).to receive(:new).and_return(runner)
allow(runner).to receive(:tear_down).and_return('{}')
expect { ProvisionService.run }.to raise_error(SystemExit) { |e| expect(e.status).to eq(0) }
end
end

describe '#provision' do
Expand Down Expand Up @@ -150,4 +166,51 @@
end
end
end

describe '#platform_to_cloud_request_parameters' do
let(:svc) { ProvisionService.new }

it 'handles an Array platform' do
result = svc.platform_to_cloud_request_parameters(['centos-8', 'ubuntu-20'], 'aws', 'us-east-1', 'a')
expect(result[:images]).to eq(['centos-8', 'ubuntu-20'])
end

it 'handles a Hash platform and wraps String images in an Array' do
platform = { cloud: 'gcp', images: 'centos-8' }
result = svc.platform_to_cloud_request_parameters(platform, nil, nil, nil)
expect(result[:images]).to eq(['centos-8'])
end

it 'handles a Hash platform and overrides the cloud' do
platform = { images: ['centos-8'] }
result = svc.platform_to_cloud_request_parameters(platform, 'aws', nil, nil)
expect(result[:cloud]).to eq('aws')
end
end

describe '#invoke_cloud_request' do
let(:svc) { ProvisionService.new }
let(:uri) { URI.parse('https://facade-release-6f3kfepqcq-ew.a.run.app/v1/provision') }

it 'sends a DELETE request' do
stub_request(:delete, uri.to_s).to_return(status: 200, body: '{}')
result = svc.invoke_cloud_request('some-uuid', uri, nil, 'delete', 0)
expect(result).to eq('{}')
end

it 'exits 1 with parsed JSON error details on a non-200 response' do
stub_request(:post, uri.to_s).to_return(status: 500, body: '{"error":"server error"}')
expect { svc.invoke_cloud_request({}, uri, nil, 'post', 0) }.to(
raise_error(SystemExit) { |e| expect(e.status).to eq(1) }
.and(output(include('"body":{"error":"server error"}', '"body_json":true')).to_stdout),
)
end

it 'exits 1 with raw body error details on a non-200 non-JSON response' do
stub_request(:post, uri.to_s).to_return(status: 500, body: 'Internal Server Error')
expect { svc.invoke_cloud_request({}, uri, nil, 'post', 0) }.to(
raise_error(SystemExit) { |e| expect(e.status).to eq(1) },
)
end
end
end
66 changes: 66 additions & 0 deletions spec/tasks/vagrant_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,70 @@
include('"status":"ok"', '"platform":"generic/debian10"', '"role":"worker1"'),
).to_stdout
end

describe '#vagrant_version' do
it 'returns the parsed vagrant version' do
allow(Open3).to receive(:capture3).with('vagrant --version', any_args).and_return(['Vagrant 2.3.4', '', 0])
expect(vagrant_version).to eq(Gem::Version.new('2.3.4'))
end

it 'memoizes the result' do
allow(Open3).to receive(:capture3).with('vagrant --version', any_args).and_return(['Vagrant 2.3.4', '', 0]).once
vagrant_version
vagrant_version
end
end

describe '#supports_windows_platform?' do
it 'returns true for vagrant >= 2.2.0' do
allow(Open3).to receive(:capture3).with('vagrant --version', any_args).and_return(['Vagrant 2.3.0', '', 0])
expect(supports_windows_platform?).to be true
end
end

describe '#generate_vagrantfile' do
before(:each) { allow(File).to receive(:read).and_call_original }

it 'includes a provider config block with cpus when specified' do
path = File.join(tmpdir, 'Vagrantfile')
generate_vagrantfile(path, 'ubuntu-20.04', false, nil, 2, nil, nil, nil, nil, nil)
content = File.read(path)
expect(content).to include('v.cpus = 2')
end

it 'includes box_url when specified, substituting the platform name' do
path = File.join(tmpdir, 'Vagrantfile')
generate_vagrantfile(path, 'ubuntu-20.04', false, 'virtualbox', nil, nil, nil, nil, nil, 'https://example.com/%BOX%.box')
content = File.read(path)
expect(content).to include("config.vm.box_url = 'https://example.com/ubuntu-20.04.box'")
end
end

describe 'validation errors' do
it 'raises when both node_name and platform given for provision' do
allow($stdin).to receive(:read).and_return({ action: 'provision', platform: 'foo', node_name: 'bar', inventory: tmpdir }.to_json)
expect { vagrant }.to raise_error(RuntimeError, %r{specify only a platform})
end

it 'raises when both node_name and platform given for tear_down' do
allow($stdin).to receive(:read).and_return({ action: 'tear_down', platform: 'foo', node_name: 'bar', inventory: tmpdir }.to_json)
expect { vagrant }.to raise_error(RuntimeError, %r{specify only a node_name})
end

it 'raises when both node_name and platform given for an unknown action' do
allow($stdin).to receive(:read).and_return({ action: 'other', platform: 'foo', node_name: 'bar', inventory: tmpdir }.to_json)
expect { vagrant }.to raise_error(RuntimeError, %r{specify only one of})
end
end

describe 'rescue' do
it 'exits 1 with an error JSON when provision raises' do
allow($stdin).to receive(:read).and_return({ platform: 'generic/ubuntu20', action: 'provision', inventory: tmpdir }.to_json)
allow(Open3).to receive(:capture3).with(%r{vagrant up}, any_args).and_return(['', 'vagrant failed!', 1])
expect { vagrant }.to(
raise_error(SystemExit) { |e| expect(e.status).to eq(1) }
.and(output(%r{vagrant_failure}).to_stdout),
)
end
end
end
15 changes: 15 additions & 0 deletions spec/unit/task_helper_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,19 @@
expect(platform_is_windows?('redhat8')).to be_falsey
end
end

describe '.token_from_fogfile' do
it 'returns nil and prints a warning when the fog file does not exist' do
allow(File).to receive(:file?).and_return(false)
result = nil
expect { result = token_from_fogfile }.to output(%r{Cannot file fog file}).to_stdout
expect(result).to be_nil
end

it 'prints a warning and returns nil when reading the fog file raises an error' do
allow(File).to receive(:file?).and_return(true)
allow(YAML).to receive(:load_file).and_raise(StandardError, 'bad file')
expect { token_from_fogfile }.to output(%r{Failed to get token}).to_stdout
end
end
end
Loading