From: Ken Barber Date: Mon, 14 Jan 2013 03:22:29 +0000 (+0000) Subject: Update test framework to the modern age X-Git-Tag: 0.1.0~11^2 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=fa699cb3dc9cd29a21c8ca3de2b66950d6c94bdb;p=puppet-modules%2Fpuppetlabs-firewall.git Update test framework to the modern age * Install puppetalbs_spec_helper and removed the stuff we were using previously * Get tests running on 3.0.x * Update gemspecs to more recent revisions of test tooling Signed-off-by: Ken Barber --- diff --git a/.gitignore b/.gitignore index 01d0a08..0035ace 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ pkg/ +# TODO: Ignore this for now until we decide what to do with it +spec/fixtures/manifests/ diff --git a/.travis.yml b/.travis.yml index d67d338..49d71fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,65 +3,38 @@ language: ruby script: rake spec notifications: email: false -gemfile: - - gemfiles/gemfile.ci rvm: - 1.8.7 - - 1.9.2 - 1.9.3 env: + # Latest 3.0.x & Facter 1.6.x + - BUILD_PUPPET_VER=3.0.2 BUILD_FACTER_VER=1.6.17 # Latest 2.7.x & Facter 1.6.x - - BUILD_PUPPET_VER=2.7.14 BUILD_FACTER_VER=1.6.9 + - BUILD_PUPPET_VER=2.7.20 BUILD_FACTER_VER=1.6.17 # Latest 2.6.x & Facter 1.6.x - - BUILD_PUPPET_VER=2.6.16 BUILD_FACTER_VER=1.6.9 + - BUILD_PUPPET_VER=2.6.17 BUILD_FACTER_VER=1.6.17 - # Mageia 2 - - BUILD_PUPPET_VER=2.7.11 BUILD_FACTER_VER=1.6.6 # Ubuntu 12.04 - BUILD_PUPPET_VER=2.7.11 BUILD_FACTER_VER=1.6.5 - # openSUSE 12.1 - - BUILD_PUPPET_VER=2.7.6 BUILD_FACTER_VER=1.6.0 - # Ubuntu 11.10 & Mandriva 2011 Contrib + # Ubuntu 11.10 - BUILD_PUPPET_VER=2.7.1 BUILD_FACTER_VER=1.5.9 # RHEL 5/6 EPEL - BUILD_PUPPET_VER=2.6.16 BUILD_FACTER_VER=1.6.6 - # Mageia 1 - - BUILD_PUPPET_VER=2.6.8 BUILD_FACTER_VER=1.5.8 - # Ubuntu 11.04 & openSUSE 11.4 + # Ubuntu 11.04 - BUILD_PUPPET_VER=2.6.4 BUILD_FACTER_VER=1.5.8 - # Debian 6 Main & Mandriva 2010 Contrib Backports + # Debian 6 Main - BUILD_PUPPET_VER=2.6.2 BUILD_FACTER_VER=1.5.7 matrix: exclude: # Puppet 2.6.x is not compatible with Ruby 1.9.x - - rvm: 1.9.2 - gemfile: gemfiles/gemfile.ci - env: BUILD_PUPPET_VER=2.6.16 BUILD_FACTER_VER=1.6.9 - rvm: 1.9.3 - gemfile: gemfiles/gemfile.ci - env: BUILD_PUPPET_VER=2.6.16 BUILD_FACTER_VER=1.6.9 - - rvm: 1.9.2 - gemfile: gemfiles/gemfile.ci - env: BUILD_PUPPET_VER=2.6.16 BUILD_FACTER_VER=1.6.6 + env: BUILD_PUPPET_VER=2.6.17 BUILD_FACTER_VER=1.6.17 - rvm: 1.9.3 - gemfile: gemfiles/gemfile.ci env: BUILD_PUPPET_VER=2.6.16 BUILD_FACTER_VER=1.6.6 - - rvm: 1.9.2 - gemfile: gemfiles/gemfile.ci - env: BUILD_PUPPET_VER=2.6.8 BUILD_FACTER_VER=1.5.8 - rvm: 1.9.3 - gemfile: gemfiles/gemfile.ci env: BUILD_PUPPET_VER=2.6.8 BUILD_FACTER_VER=1.5.8 - - rvm: 1.9.2 - gemfile: gemfiles/gemfile.ci - env: BUILD_PUPPET_VER=2.6.4 BUILD_FACTER_VER=1.5.8 - rvm: 1.9.3 - gemfile: gemfiles/gemfile.ci env: BUILD_PUPPET_VER=2.6.4 BUILD_FACTER_VER=1.5.8 - - rvm: 1.9.2 - gemfile: gemfiles/gemfile.ci - env: BUILD_PUPPET_VER=2.6.2 BUILD_FACTER_VER=1.5.7 - rvm: 1.9.3 - gemfile: gemfiles/gemfile.ci env: BUILD_PUPPET_VER=2.6.2 BUILD_FACTER_VER=1.5.7 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..3b09bd8 --- /dev/null +++ b/Gemfile @@ -0,0 +1,22 @@ +source :rubygems + +gem 'rake', '~> 10.0.3' + +group :test do + gem 'rspec', '~> 2.12.0' + gem 'mocha', '~> 0.13.1', :require => 'mocha/api' + gem 'puppetlabs_spec_helper', '~> 0.4.0', + :require => 'puppetlabs_spec_helper/module_spec_helper' + + if puppetversion = ENV['BUILD_PUPPET_VER'] + gem 'puppet', puppetversion + else + gem 'puppet' + end + + if facterversion = ENV['BUILD_FACTER_VER'] + gem 'facter', facterversion + else + gem 'facter' + end +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..e7c0c12 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,39 @@ +GEM + remote: http://rubygems.org/ + specs: + diff-lcs (1.1.3) + facter (1.6.17) + hiera (1.0.0) + metaclass (0.0.1) + mocha (0.13.1) + metaclass (~> 0.0.1) + puppet (3.0.2) + facter (~> 1.6.11) + hiera (~> 1.0.0) + puppetlabs_spec_helper (0.4.0) + mocha (>= 0.10.5) + rake + rspec (>= 2.9.0) + rspec-puppet (>= 0.1.1) + rake (10.0.3) + rspec (2.12.0) + rspec-core (~> 2.12.0) + rspec-expectations (~> 2.12.0) + rspec-mocks (~> 2.12.0) + rspec-core (2.12.2) + rspec-expectations (2.12.1) + diff-lcs (~> 1.1.3) + rspec-mocks (2.12.1) + rspec-puppet (0.1.5) + rspec + +PLATFORMS + ruby + +DEPENDENCIES + facter + mocha (~> 0.13.1) + puppet + puppetlabs_spec_helper (~> 0.4.0) + rake (~> 10.0.3) + rspec (~> 2.12.0) diff --git a/README.markdown b/README.markdown index 663a2cc..5466f89 100644 --- a/README.markdown +++ b/README.markdown @@ -1,5 +1,7 @@ ## puppetlabs-firewall module +[![Build Status](https://travis-ci.org/puppetlabs/puppetlabs-firewall.png?branch=master)](https://travis-ci.org/puppetlabs/puppetlabs-firewall) + ## User Guide ### Overview diff --git a/Rakefile b/Rakefile index cac9471..79d29df 100644 --- a/Rakefile +++ b/Rakefile @@ -1,22 +1,11 @@ -require 'rake' +require 'rubygems' +require 'bundler/setup' + +Bundler.require :default + require 'rspec/core/rake_task' +require 'puppetlabs_spec_helper/rake_tasks' task :default do sh %{rake -T} end - -# Aliases for spec. The (s) versions are used by rvm specs/tests. -task :test => [:spec] -task :tests => [:spec] -task :specs => [:spec] - -desc 'Run all RSpec tests' -RSpec::Core::RakeTask.new(:spec) do |t| - t.rspec_opts = ['--color'] -end - -desc 'Generate code coverage' -RSpec::Core::RakeTask.new(:coverage) do |t| - t.rcov = true - t.rcov_opts = ['--exclude', 'spec'] -end diff --git a/gemfiles/gemfile.ci b/gemfiles/gemfile.ci deleted file mode 100644 index d98382c..0000000 --- a/gemfiles/gemfile.ci +++ /dev/null @@ -1,11 +0,0 @@ -source 'http://rubygems.org' - -gem 'rspec', '2.10.0' -gem 'rspec-core', '2.10.1' -gem 'rspec-expectations', '2.10.0' -gem 'rspec-mocks', '2.10.1' -gem 'rake', '0.9.2.2' -gem 'mocha', '0.11.4' -gem 'diff-lcs', '1.1.3' -gem 'puppet', ENV['BUILD_PUPPET_VER'] -gem 'facter', ENV['BUILD_FACTER_VER'] diff --git a/lib/puppet/provider/firewall/ip6tables.rb b/lib/puppet/provider/firewall/ip6tables.rb index 0b64501..f063e38 100644 --- a/lib/puppet/provider/firewall/ip6tables.rb +++ b/lib/puppet/provider/firewall/ip6tables.rb @@ -16,8 +16,10 @@ Puppet::Type.type(:firewall).provide :ip6tables, :parent => :iptables, :source = has_feature :tcp_flags has_feature :pkttype - commands :iptables => '/sbin/ip6tables' - commands :iptables_save => '/sbin/ip6tables-save' + optional_commands({ + :iptables => '/sbin/ip6tables', + :iptables_save => '/sbin/ip6tables-save', + }) @resource_map = { :burst => "--limit-burst", diff --git a/lib/puppet/provider/firewall/iptables.rb b/lib/puppet/provider/firewall/iptables.rb index 34a17e6..209ce5b 100644 --- a/lib/puppet/provider/firewall/iptables.rb +++ b/lib/puppet/provider/firewall/iptables.rb @@ -21,8 +21,10 @@ Puppet::Type.type(:firewall).provide :iptables, :parent => Puppet::Provider::Fir has_feature :tcp_flags has_feature :pkttype - commands :iptables => '/sbin/iptables' - commands :iptables_save => '/sbin/iptables-save' + optional_commands({ + :iptables => '/sbin/iptables', + :iptables_save => '/sbin/iptables-save', + }) defaultfor :kernel => :linux diff --git a/spec/monkey_patches/alias_should_to_must.rb b/spec/monkey_patches/alias_should_to_must.rb deleted file mode 100755 index 1a11117..0000000 --- a/spec/monkey_patches/alias_should_to_must.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'rspec' - -class Object - # This is necessary because the RAL has a 'should' - # method. - alias :must :should - alias :must_not :should_not -end diff --git a/spec/monkey_patches/publicize_methods.rb b/spec/monkey_patches/publicize_methods.rb deleted file mode 100755 index b39e9c0..0000000 --- a/spec/monkey_patches/publicize_methods.rb +++ /dev/null @@ -1,11 +0,0 @@ -# Some monkey-patching to allow us to test private methods. -class Class - def publicize_methods(*methods) - saved_private_instance_methods = methods.empty? ? self.private_instance_methods : methods - - self.class_eval { public(*saved_private_instance_methods) } - yield - self.class_eval { private(*saved_private_instance_methods) } - end -end - diff --git a/spec/puppet_spec/files.rb b/spec/puppet_spec/files.rb deleted file mode 100755 index 30fb4fc..0000000 --- a/spec/puppet_spec/files.rb +++ /dev/null @@ -1,53 +0,0 @@ -require 'fileutils' -require 'tempfile' - -# A support module for testing files. -module PuppetSpec::Files - # This code exists only to support tests that run as root, pretty much. - # Once they have finally been eliminated this can all go... --daniel 2011-04-08 - if Puppet.features.posix? then - def self.in_tmp(path) - path =~ /^\/tmp/ or path =~ /^\/var\/folders/ - end - elsif Puppet.features.microsoft_windows? - def self.in_tmp(path) - tempdir = File.expand_path(File.join(Dir::LOCAL_APPDATA, "Temp")) - path =~ /^#{tempdir}/ - end - else - fail "Help! Can't find in_tmp for this platform" - end - - def self.cleanup - $global_tempfiles ||= [] - while path = $global_tempfiles.pop do - fail "Not deleting tmpfile #{path} outside regular tmpdir" unless in_tmp(path) - - begin - FileUtils.rm_r path, :secure => true - rescue Errno::ENOENT - # nothing to do - end - end - end - - def tmpfile(name) - # Generate a temporary file, just for the name... - source = Tempfile.new(name) - path = source.path - source.close! - - # ...record it for cleanup, - $global_tempfiles ||= [] - $global_tempfiles << File.expand_path(path) - - # ...and bam. - path - end - - def tmpdir(name) - path = tmpfile(name) - FileUtils.mkdir_p(path) - path - end -end diff --git a/spec/puppet_spec/fixtures.rb b/spec/puppet_spec/fixtures.rb deleted file mode 100755 index 7f6bc2a..0000000 --- a/spec/puppet_spec/fixtures.rb +++ /dev/null @@ -1,28 +0,0 @@ -module PuppetSpec::Fixtures - def fixtures(*rest) - File.join(PuppetSpec::FIXTURE_DIR, *rest) - end - def my_fixture_dir - callers = caller - while line = callers.shift do - next unless found = line.match(%r{/spec/(.*)_spec\.rb:}) - return fixtures(found[1]) - end - fail "sorry, I couldn't work out your path from the caller stack!" - end - def my_fixture(name) - file = File.join(my_fixture_dir, name) - unless File.readable? file then - fail Puppet::DevError, "fixture '#{name}' for #{my_fixture_dir} is not readable" - end - return file - end - def my_fixtures(glob = '*', flags = 0) - files = Dir.glob(File.join(my_fixture_dir, glob), flags) - unless files.length > 0 then - fail Puppet::DevError, "fixture '#{glob}' for #{my_fixture_dir} had no files!" - end - block_given? and files.each do |file| yield file end - files - end -end diff --git a/spec/puppet_spec/matchers.rb b/spec/puppet_spec/matchers.rb deleted file mode 100644 index 77f5803..0000000 --- a/spec/puppet_spec/matchers.rb +++ /dev/null @@ -1,87 +0,0 @@ -require 'stringio' - -######################################################################## -# Backward compatibility for Jenkins outdated environment. -module RSpec - module Matchers - module BlockAliases - alias_method :to, :should unless method_defined? :to - alias_method :to_not, :should_not unless method_defined? :to_not - alias_method :not_to, :should_not unless method_defined? :not_to - end - end -end - - -######################################################################## -# Custom matchers... -RSpec::Matchers.define :have_matching_element do |expected| - match do |actual| - actual.any? { |item| item =~ expected } - end -end - - -RSpec::Matchers.define :exit_with do |expected| - actual = nil - match do |block| - begin - block.call - rescue SystemExit => e - actual = e.status - end - actual and actual == expected - end - failure_message_for_should do |block| - "expected exit with code #{expected} but " + - (actual.nil? ? " exit was not called" : "we exited with #{actual} instead") - end - failure_message_for_should_not do |block| - "expected that exit would not be called with #{expected}" - end - description do - "expect exit with #{expected}" - end -end - - -RSpec::Matchers.define :have_printed do |expected| - match do |block| - $stderr = $stdout = StringIO.new - - begin - block.call - ensure - $stdout.rewind - @actual = $stdout.read - - $stdout = STDOUT - $stderr = STDERR - end - - if @actual then - case expected - when String - @actual.include? expected - when Regexp - expected.match @actual - else - raise ArgumentError, "No idea how to match a #{@actual.class.name}" - end - end - end - - failure_message_for_should do |actual| - if actual.nil? then - "expected #{expected.inspect}, but nothing was printed" - else - "expected #{expected.inspect} to be printed; got:\n#{actual}" - end - end - - description do - "expect #{expected.inspect} to be printed" - end - - diffable -end diff --git a/spec/puppet_spec/verbose.rb b/spec/puppet_spec/verbose.rb deleted file mode 100755 index d9834f2..0000000 --- a/spec/puppet_spec/verbose.rb +++ /dev/null @@ -1,9 +0,0 @@ -# Support code for running stuff with warnings disabled. -module Kernel - def with_verbose_disabled - verbose, $VERBOSE = $VERBOSE, nil - result = yield - $VERBOSE = verbose - return result - end -end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index c9b0b22..3d8b197 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -4,81 +4,18 @@ $LOAD_PATH.unshift File.join(dir, 'lib') # Don't want puppet getting the command line arguments for rake or autotest ARGV.clear -require 'puppet' -require 'mocha' -gem 'rspec', '>=2.0.0' -require 'rspec/expectations' +require 'rubygems' +require 'bundler/setup' -# So everyone else doesn't have to include this base constant. -module PuppetSpec - FIXTURE_DIR = File.join(dir = File.expand_path(File.dirname(__FILE__)), "fixtures") unless defined?(FIXTURE_DIR) -end +Bundler.require :default, :test require 'pathname' require 'tmpdir' -require 'puppet_spec/verbose' -require 'puppet_spec/files' -require 'puppet_spec/fixtures' -require 'puppet_spec/matchers' -require 'monkey_patches/alias_should_to_must' -require 'monkey_patches/publicize_methods' - Pathname.glob("#{dir}/shared_behaviours/**/*.rb") do |behaviour| require behaviour.relative_path_from(Pathname.new(dir)) end RSpec.configure do |config| - include PuppetSpec::Fixtures - config.mock_with :mocha - - config.before :each do - GC.disable - - # these globals are set by Application - $puppet_application_mode = nil - $puppet_application_name = nil - - # REVISIT: I think this conceals other bad tests, but I don't have time to - # fully diagnose those right now. When you read this, please come tell me - # I suck for letting this float. --daniel 2011-04-21 - Signal.stubs(:trap) - - # Set the confdir and vardir to gibberish so that tests - # have to be correctly mocked. - Puppet[:confdir] = "/dev/null" - Puppet[:vardir] = "/dev/null" - - # Avoid opening ports to the outside world - Puppet.settings[:bindaddress] = "127.0.0.1" - - @logs = [] - # This tests allows the spec_helper to be >2.6.7 and >2.7.1 compatible - # as the Puppet::Test::LogCollector facility wasn't available until 2.7.x - if Puppet.const_defined?("Test") and Puppet::Test.const_defined?("LogCollector") - Puppet::Util::Log.newdestination(Puppet::Test::LogCollector.new(@logs)) - else - Puppet::Util::Log.newdestination(@logs) - end - - @log_level = Puppet::Util::Log.level - end - - config.after :each do - Puppet.settings.clear - Puppet::Node::Environment.clear - Puppet::Util::Storage.clear - if Puppet::Util.const_defined?("ExecutionStub") - Puppet::Util::ExecutionStub.reset - end - - PuppetSpec::Files.cleanup - - @logs.clear - Puppet::Util::Log.close_all - Puppet::Util::Log.level = @log_level - - GC.enable - end end diff --git a/spec/unit/puppet/provider/iptables_chain_spec.rb b/spec/unit/puppet/provider/iptables_chain_spec.rb index f8c013c..ffe4df7 100755 --- a/spec/unit/puppet/provider/iptables_chain_spec.rb +++ b/spec/unit/puppet/provider/iptables_chain_spec.rb @@ -61,9 +61,9 @@ describe 'iptables chain provider' do it 'should be able to get a list of existing rules' do # Pretend to return nil from iptables - provider.expects(:execute).with(['/sbin/ebtables-save']).returns("") - provider.expects(:execute).with(['/sbin/iptables-save']).returns("") - provider.expects(:execute).with(['/sbin/ip6tables-save']).returns("") + provider.stubs(:execute).with(['/sbin/ip6tables-save']).returns("") + provider.stubs(:execute).with(['/sbin/ebtables-save']).returns("") + provider.stubs(:execute).with(['/sbin/iptables-save']).returns("") provider.instances.each do |chain| chain.should be_instance_of(provider) diff --git a/spec/unit/puppet/provider/iptables_spec.rb b/spec/unit/puppet/provider/iptables_spec.rb index 4fab55d..b696e20 100644 --- a/spec/unit/puppet/provider/iptables_spec.rb +++ b/spec/unit/puppet/provider/iptables_spec.rb @@ -49,12 +49,13 @@ describe 'iptables provider' do # Stub iptables version Facter.fact(:iptables_version).stubs(:value).returns("1.4.2") + + Puppet::Util::Execution.stubs(:execute).returns "" + Puppet::Util.stubs(:which).with("/sbin/iptables-save"). + returns "/sbin/iptables-save" end it 'should be able to get a list of existing rules' do - # Pretend to return nil from iptables - provider.expects(:execute).with(['/sbin/iptables-save']).returns("") - provider.instances.each do |rule| rule.should be_instance_of(provider) rule.properties[:provider].to_s.should == provider.name.to_s @@ -62,7 +63,8 @@ describe 'iptables provider' do end it 'should ignore lines with fatal errors' do - provider.expects(:execute).with(['/sbin/iptables-save']).returns("FATAL: Could not load /lib/modules/2.6.18-028stab095.1/modules.dep: No such file or directory") + Puppet::Util::Execution.stubs(:execute).with(['/sbin/iptables-save']). + returns("FATAL: Could not load /lib/modules/2.6.18-028stab095.1/modules.dep: No such file or directory") provider.instances.length.should == 0 end @@ -121,10 +123,6 @@ describe 'iptables provider' do describe 'when creating resources' do let(:instance) { provider.new(resource) } - before :each do - provider.expects(:execute).with(['/sbin/iptables-save']).returns("") - end - it 'insert_args should be an array' do instance.insert_args.class.should == Array end @@ -133,10 +131,6 @@ describe 'iptables provider' do describe 'when modifying resources' do let(:instance) { provider.new(resource) } - before :each do - provider.expects(:execute).with(['/sbin/iptables-save']).returns "" - end - it 'update_args should be an array' do instance.update_args.class.should == Array end diff --git a/spec/unit/puppet/type/firewall_spec.rb b/spec/unit/puppet/type/firewall_spec.rb index 6fa5e8e..d0a02a3 100755 --- a/spec/unit/puppet/type/firewall_spec.rb +++ b/spec/unit/puppet/type/firewall_spec.rb @@ -163,11 +163,11 @@ describe firewall do end it "should not accept something invalid for #{port}" do - expect { @resource[port] = 'something odd' }.to raise_error(Puppet::Error, /^Parameter .+ failed: Munging failed for value ".+" in class .+: no such service/) + expect { @resource[port] = 'something odd' }.to raise_error(Puppet::Error, /^Parameter .+ failed.+Munging failed for value ".+" in class .+: no such service/) end it "should not accept something invalid in an array for #{port}" do - expect { @resource[port] = ['something odd','something even odder'] }.to raise_error(Puppet::Error, /^Parameter .+ failed: Munging failed for value ".+" in class .+: no such service/) + expect { @resource[port] = ['something odd','something even odder'] }.to raise_error(Puppet::Error, /^Parameter .+ failed.+Munging failed for value ".+" in class .+: no such service/) end end end diff --git a/spec/unit/puppet/type/firewallchain_spec.rb b/spec/unit/puppet/type/firewallchain_spec.rb index cbd3df1..e967927 100755 --- a/spec/unit/puppet/type/firewallchain_spec.rb +++ b/spec/unit/puppet/type/firewallchain_spec.rb @@ -98,7 +98,7 @@ describe firewallchain do expect { klass.new({:name => 'testchain:filter:IPv4', :policy => policy }) }.to raise_error(Puppet::Error) end it "non-inbuilt chains can accept policies on protocol = ethernet (policy #{policy})" do - klass.new({:name => 'testchain:filter:ethernet', :policy => policy }).should be_instance_of(@provider) + klass.new({:name => 'testchain:filter:ethernet', :policy => policy }) end end diff --git a/spec/unit/puppet/util/firewall_spec.rb b/spec/unit/puppet/util/firewall_spec.rb index 097782d..31794a6 100644 --- a/spec/unit/puppet/util/firewall_spec.rb +++ b/spec/unit/puppet/util/firewall_spec.rb @@ -28,8 +28,8 @@ describe 'Puppet::Util::Firewall' do %w{inet5 inet8 foo}.each do |proto| it "should reject invalid proto #{proto}" do - expect { subject.icmp_name_to_number('echo-reply', proto) }.should - raise_error(ArgumentError, "unsupported protocol family '#{proto}'") + expect { subject.icmp_name_to_number('echo-reply', proto) }. + to raise_error(ArgumentError, "unsupported protocol family '#{proto}'") end end end