X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;ds=sidebyside;f=3rdparty%2Fmodules%2Fneutron%2Fspec%2Funit%2Fprovider%2Fneutron_spec.rb;fp=3rdparty%2Fmodules%2Fneutron%2Fspec%2Funit%2Fprovider%2Fneutron_spec.rb;h=fed14ece2958f769d4523b5c3dda282be22f96f6;hb=4631045ebb77ee8622f6fa09277a50c372bcc02e;hp=0000000000000000000000000000000000000000;hpb=3d4dc4fd9e59bd0e07646c99f6b356c7d9d859aa;p=dsa-puppet.git diff --git a/3rdparty/modules/neutron/spec/unit/provider/neutron_spec.rb b/3rdparty/modules/neutron/spec/unit/provider/neutron_spec.rb new file mode 100644 index 00000000..fed14ece --- /dev/null +++ b/3rdparty/modules/neutron/spec/unit/provider/neutron_spec.rb @@ -0,0 +1,246 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/neutron' +require 'tempfile' + +describe Puppet::Provider::Neutron do + + def klass + described_class + end + + let :credential_hash do + { + 'auth_host' => '192.168.56.210', + 'auth_port' => '35357', + 'auth_protocol' => 'https', + 'admin_tenant_name' => 'admin_tenant', + 'admin_user' => 'admin', + 'admin_password' => 'password', + } + end + + let :auth_endpoint do + 'https://192.168.56.210:35357/v2.0/' + end + + let :credential_error do + /Neutron types will not work/ + end + + let :exec_error do + /Neutron or Keystone API is not avalaible/ + end + + after :each do + klass.reset + end + + describe 'when determining credentials' do + + it 'should fail if config is empty' do + conf = {} + klass.expects(:neutron_conf).returns(conf) + expect do + klass.neutron_credentials + end.to raise_error(Puppet::Error, credential_error) + end + + it 'should fail if config does not have keystone_authtoken section.' do + conf = {'foo' => 'bar'} + klass.expects(:neutron_conf).returns(conf) + expect do + klass.neutron_credentials + end.to raise_error(Puppet::Error, credential_error) + end + + it 'should fail if config does not contain all auth params' do + conf = {'keystone_authtoken' => {'invalid_value' => 'foo'}} + klass.expects(:neutron_conf).returns(conf) + expect do + klass.neutron_credentials + end.to raise_error(Puppet::Error, credential_error) + end + + it 'should use specified host/port/protocol in the auth endpoint' do + conf = {'keystone_authtoken' => credential_hash} + klass.expects(:neutron_conf).returns(conf) + klass.get_auth_endpoint.should == auth_endpoint + end + + it 'should find region_name if specified' do + conf = { + 'keystone_authtoken' => credential_hash, + 'DEFAULT' => { 'nova_region_name' => 'REGION_NAME' } + } + klass.expects(:neutron_conf).returns(conf) + klass.neutron_credentials['nova_region_name'] == 'REGION_NAME' + end + + end + + describe 'when invoking the neutron cli' do + + it 'should set auth credentials in the environment' do + authenv = { + :OS_AUTH_URL => auth_endpoint, + :OS_USERNAME => credential_hash['admin_user'], + :OS_TENANT_NAME => credential_hash['admin_tenant_name'], + :OS_PASSWORD => credential_hash['admin_password'], + } + klass.expects(:get_neutron_credentials).with().returns(credential_hash) + klass.expects(:withenv).with(authenv) + klass.auth_neutron('test_retries') + end + + it 'should set region in the environment if needed' do + authenv = { + :OS_AUTH_URL => auth_endpoint, + :OS_USERNAME => credential_hash['admin_user'], + :OS_TENANT_NAME => credential_hash['admin_tenant_name'], + :OS_PASSWORD => credential_hash['admin_password'], + :OS_REGION_NAME => 'REGION_NAME', + } + + cred_hash = credential_hash.merge({'nova_region_name' => 'REGION_NAME'}) + klass.expects(:get_neutron_credentials).with().returns(cred_hash) + klass.expects(:withenv).with(authenv) + klass.auth_neutron('test_retries') + end + + ['[Errno 111] Connection refused', + '400-{\'message\': \'\'}', + '(HTTP 400)', + '503 Service Unavailable', + '504 Gateway Time-out', + 'Maximum attempts reached', + 'Unauthorized: bad credentials', + 'Max retries exceeded'].reverse.each do |valid_message| + it "should retry when neutron cli returns with error #{valid_message}" do + klass.expects(:get_neutron_credentials).with().returns({}) + klass.expects(:sleep).with(2).returns(nil) + klass.expects(:neutron).twice.with(['test_retries']).raises( + Puppet::ExecutionFailure, valid_message).then.returns('') + klass.auth_neutron('test_retries') + end + end + + end + + describe 'when listing neutron resources' do + + it 'should exclude the column header' do + output = <<-EOT + id + net1 + net2 + EOT + klass.expects(:auth_neutron).returns(output) + result = klass.list_neutron_resources('foo') + result.should eql(['net1', 'net2']) + end + + it 'should return empty list when there are no neutron resources' do + output = <<-EOT + EOT + klass.stubs(:auth_neutron).returns(output) + result = klass.list_neutron_resources('foo') + result.should eql([]) + end + + it 'should fail if resources list is nil' do + klass.stubs(:auth_neutron).returns(nil) + expect do + klass.list_neutron_resources('foo') + end.to raise_error(Puppet::Error, exec_error) + end + + end + + describe 'when retrieving attributes for neutron resources' do + + it 'should parse single-valued attributes into a key-value pair' do + klass.expects(:auth_neutron).returns('admin_state_up="True"') + result = klass.get_neutron_resource_attrs('foo', 'id') + result.should eql({"admin_state_up" => 'True'}) + end + + it 'should parse multi-valued attributes into a key-list pair' do + output = <<-EOT +subnets="subnet1 +subnet2 +subnet3" + EOT + klass.expects(:auth_neutron).returns(output) + result = klass.get_neutron_resource_attrs('foo', 'id') + result.should eql({"subnets" => ['subnet1', 'subnet2', 'subnet3']}) + end + + end + + describe 'when listing router ports' do + + let :router do + 'router1' + end + + it 'should handle an empty port list' do + klass.expects(:auth_neutron).with('router-port-list', + '--format=csv', + router) + result = klass.list_router_ports(router) + result.should eql([]) + end + + it 'should handle several ports' do + output = <<-EOT +"id","name","mac_address","fixed_ips" +"1345e576-a21f-4c2e-b24a-b245639852ab","","fa:16:3e:e3:e6:38","{""subnet_id"": ""839a1d2d-2c6e-44fb-9a2b-9b011dce8c2f"", ""ip_address"": ""10.0.0.1""}" +"de0dc526-02b2-467c-9832-2c3dc69ac2b4","","fa:16:3e:f6:b5:72","{""subnet_id"": ""e4db0abd-276a-4f69-92ea-8b9e4eacfd43"", ""ip_address"": ""172.24.4.226""}" + EOT + expected = + [{ "fixed_ips"=> + "{\"subnet_id\": \"839a1d2d-2c6e-44fb-9a2b-9b011dce8c2f\", \ +\"ip_address\": \"10.0.0.1\"}", + "name"=>"", + "subnet_id"=>"839a1d2d-2c6e-44fb-9a2b-9b011dce8c2f", + "id"=>"1345e576-a21f-4c2e-b24a-b245639852ab", + "mac_address"=>"fa:16:3e:e3:e6:38"}, + {"fixed_ips"=> + "{\"subnet_id\": \"e4db0abd-276a-4f69-92ea-8b9e4eacfd43\", \ +\"ip_address\": \"172.24.4.226\"}", + "name"=>"", + "subnet_id"=>"e4db0abd-276a-4f69-92ea-8b9e4eacfd43", + "id"=>"de0dc526-02b2-467c-9832-2c3dc69ac2b4", + "mac_address"=>"fa:16:3e:f6:b5:72"}] + klass.expects(:auth_neutron). + with('router-port-list', '--format=csv', router). + returns(output) + result = klass.list_router_ports(router) + result.should eql(expected) + end + + end + + describe 'when parsing creation output' do + + it 'should parse valid output into a hash' do + data = <<-EOT +Created a new network: +admin_state_up="True" +id="5f9cbed2-d31c-4e9c-be92-87229acb3f69" +name="foo" +tenant_id="3056a91768d948d399f1d79051a7f221" + EOT + expected = { + 'admin_state_up' => 'True', + 'id' => '5f9cbed2-d31c-4e9c-be92-87229acb3f69', + 'name' => 'foo', + 'tenant_id' => '3056a91768d948d399f1d79051a7f221', + } + klass.parse_creation_output(data).should == expected + end + + end + +end