Files
puppet-openstacklib/spec/unit/provider/openstack_spec.rb
Clayton O'Neill efa9181201 Properly handle embedded newlines in csv
When parsing the response from the OpenStack client values (like
keystone tenant descriptions) can have embedded newline. To avoid this
issue, we drop lines that don't start with a double quoted value until
the first one we find.

Change-Id: Ie952161b503d2c46637e6a6e1c83b2dfce1c03a7
2015-03-17 09:57:35 +00:00

261 lines
9.1 KiB
Ruby

# Load libraries from aviator here to simulate how they live together in a real puppet run
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'modules', 'aviator', 'lib'))
require 'puppet'
require 'spec_helper'
require 'puppet/provider/openstack'
describe Puppet::Provider::Openstack do
before(:each) do
ENV['OS_USERNAME'] = nil
ENV['OS_PASSWORD'] = nil
ENV['OS_TENANT_NAME'] = nil
ENV['OS_AUTH_URL'] = nil
end
let(:type) do
Puppet::Type.newtype(:test_resource) do
newparam(:name, :namevar => true)
newparam(:auth)
newparam(:log_file)
end
end
shared_examples 'authenticating with environment variables' do
it 'makes a successful request' do
ENV['OS_USERNAME'] = 'test'
ENV['OS_PASSWORD'] = 'abc123'
ENV['OS_TENANT_NAME'] = 'test'
ENV['OS_AUTH_URL'] = 'http://127.0.0.1:35357/v2.0'
if provider.class == Class
provider.stubs(:openstack)
.with('project', 'list', '--quiet', '--format', 'csv', [[ '--long' ]])
.returns('"ID","Name","Description","Enabled"
"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
')
else
provider.class.stubs(:openstack)
.with('project', 'list', '--quiet', '--format', 'csv', [[ '--long' ]])
.returns('"ID","Name","Description","Enabled"
"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
')
end
response = provider.request('project', 'list', nil, nil, '--long' )
expect(response.first[:description]).to match /Test tenant/
end
end
shared_examples 'it has no credentials' do
it 'fails to authenticate' do
expect{ provider.request('project', 'list', nil, nil, '--long') }.to raise_error(Puppet::Error::OpenstackAuthInputError, /No credentials provided/)
end
end
describe '#request' do
context 'with valid password credentials in parameters' do
let(:resource_attrs) do
{
:name => 'stubresource',
:auth => {
'username' => 'test',
'password' => 'abc123',
'tenant_name' => 'test',
'auth_url' => 'http://127.0.0.1:5000/v2.0',
}
}
end
let(:provider) do
Puppet::Provider::Openstack.new(type.new(resource_attrs))
end
it 'makes a successful request' do
provider.class.stubs(:openstack)
.with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'test', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
.returns('"ID","Name","Description","Enabled"
"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
')
response = provider.request('project', 'list', nil, resource_attrs[:auth], '--long')
expect(response.first[:description]).to match /Test tenant/
end
end
context 'with valid openrc file in parameters' do
mock = "export OS_USERNAME='test'\nexport OS_PASSWORD='abc123'\nexport OS_TENANT_NAME='test'\nexport OS_AUTH_URL='http://127.0.0.1:5000/v2.0'"
let(:resource_attrs) do
{
:name => 'stubresource',
:auth => {
'openrc' => '/root/openrc'
}
}
end
let(:provider) do
Puppet::Provider::Openstack.new(type.new(resource_attrs))
end
it 'makes a successful request' do
File.expects(:open).with('/root/openrc').returns(StringIO.new(mock))
provider.class.stubs(:openstack)
.with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'test', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
.returns('"ID","Name","Description","Enabled"
"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
')
response = provider.request('project', 'list', nil, resource_attrs[:auth], '--long')
expect(response.first[:description]).to match /Test tenant/
end
end
context 'with valid service token in parameters' do
let(:resource_attrs) do
{
:name => 'stubresource',
:auth => {
'token' => 'secrettoken',
'auth_url' => 'http://127.0.0.1:5000/v2.0'
}
}
end
let(:provider) do
Puppet::Provider::Openstack.new(type.new(resource_attrs))
end
it 'makes a successful request' do
provider.class.stubs(:openstack)
.with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-token', 'secrettoken', '--os-url', 'http://127.0.0.1:5000/v2.0']])
.returns('"ID","Name","Description","Enabled"
"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
')
response = provider.request('project', 'list', nil, resource_attrs[:auth], '--long')
expect(response.first[:description]).to match /Test tenant/
end
it 'makes a successful show request' do
provider.class.stubs(:openstack)
.with('project', 'show', '--format', 'shell', [['test', '--os-token', 'secrettoken', '--os-url', 'http://127.0.0.1:5000/v2.0']])
.returns('ID="1cb05cfed7c24279be884ba4f6520262"
Name="test"
Description="Test Tenant"
Enabled="True"
')
response = provider.request('project', 'show', 'test', resource_attrs[:auth])
expect(response[:description]).to match /Test Tenant/
expect(response[:id]).to match /1cb05cfed7c24279be884ba4f6520262/
expect(response[:name]).to match /test/
expect(response[:enabled]).to match /True/
end
end
context 'with valid password credentials in environment variables' do
it_behaves_like 'authenticating with environment variables' do
let(:resource_attrs) do
{
:name => 'stubresource',
}
end
let(:provider) do
Puppet::Provider::Openstack.new(type.new(resource_attrs))
end
end
end
context 'with no valid credentials' do
it_behaves_like 'it has no credentials' do
let(:resource_attrs) do
{
:name => 'stubresource',
}
end
let(:provider) do
Puppet::Provider::Openstack.new(type.new(resource_attrs))
end
end
end
context 'it retries on connection errors' do
let(:resource_attrs) do
{
:name => 'stubresource',
:auth => {
'username' => 'test',
'password' => 'abc123',
'tenant_name' => 'test',
'auth_url' => 'http://127.0.0.1:5000/v2.0',
}
}
end
let(:provider) do
Puppet::Provider::Openstack.new(type.new(resource_attrs))
end
it 'retries' do
provider.class.stubs(:openstack)
.with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'test', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
.raises(Puppet::ExecutionFailure, 'Unable to establish connection')
.then
.returns('')
provider.class.expects(:sleep).with(2).returns(nil)
provider.request('project', 'list', nil, resource_attrs[:auth], '--long')
end
end
end
describe '::request' do
context 'with valid password credentials in environment variables' do
it_behaves_like 'authenticating with environment variables' do
let(:resource_attrs) do
{
:name => 'stubresource',
}
end
let(:provider) do
Puppet::Provider::Openstack.dup
end
end
end
context 'with no valid credentials' do
it_behaves_like 'it has no credentials' do
let(:provider) { Puppet::Provider::Openstack.dup }
end
end
end
describe 'parse_csv' do
context 'with mixed stderr' do
text = "ERROR: Testing\n\"field\",\"test\",1,2,3\n"
csv = Puppet::Provider::Openstack.parse_csv(text)
it 'should ignore non-CSV text at the beginning of the input' do
expect(csv).to be_kind_of(Array)
expect(csv[0]).to match_array(['field', 'test', '1', '2', '3'])
expect(csv.size).to eq(1)
end
end
context 'with \r\n line endings' do
text = "ERROR: Testing\r\n\"field\",\"test\",1,2,3\r\n"
csv = Puppet::Provider::Openstack.parse_csv(text)
it 'ignore the carriage returns' do
expect(csv).to be_kind_of(Array)
expect(csv[0]).to match_array(['field', 'test', '1', '2', '3'])
expect(csv.size).to eq(1)
end
end
context 'with embedded newlines' do
text = "ERROR: Testing\n\"field\",\"te\nst\",1,2,3\n"
csv = Puppet::Provider::Openstack.parse_csv(text)
it 'should parse correctly' do
expect(csv).to be_kind_of(Array)
expect(csv[0]).to match_array(['field', "te\nst", '1', '2', '3'])
expect(csv.size).to eq(1)
end
end
end
end