require 'spec_helper' describe 'apache::vhost', :type => :define do let :pre_condition do 'class { "apache": default_vhost => false, }' end let :title do 'rspec.example.com' end let :default_params do { :docroot => '/rspec/docroot', :port => '84', } end describe 'os-dependent items' do context "on RedHat based systems" do let :default_facts do { :osfamily => 'RedHat', :operatingsystemrelease => '6', :concat_basedir => '/dne', } end let :params do default_params end let :facts do default_facts end it { should include_class("apache") } it { should include_class("apache::params") } end context "on Debian based systems" do let :default_facts do { :osfamily => 'Debian', :operatingsystemrelease => '6', :concat_basedir => '/dne', } end let :params do default_params end let :facts do default_facts end it { should include_class("apache") } it { should include_class("apache::params") } it { should contain_file("25-rspec.example.com.conf").with( :ensure => 'present', :path => '/etc/apache2/sites-available/25-rspec.example.com.conf' ) } it { should contain_file("25-rspec.example.com.conf symlink").with( :ensure => 'link', :path => '/etc/apache2/sites-enabled/25-rspec.example.com.conf', :target => '/etc/apache2/sites-available/25-rspec.example.com.conf' ) } end end describe 'os-independent items' do let :facts do { :osfamily => 'Debian', :operatingsystemrelease => '6', :concat_basedir => '/dne', } end describe 'basic assumptions' do let :params do default_params end it { should include_class("apache") } it { should include_class("apache::params") } it { should contain_apache__listen(params[:port]) } it { should contain_apache__namevirtualhost("*:#{params[:port]}") } end context ".conf content" do [ { :title => 'should contain docroot', :attr => 'docroot', :value => '/not/default', :match => [' DocumentRoot /not/default',' '], }, { :title => 'should set a port', :attr => 'port', :value => '8080', :match => '', }, { :title => 'should set an ip', :attr => 'ip', :value => '10.0.0.1', :match => '', }, { :title => 'should set a serveradmin', :attr => 'serveradmin', :value => 'test@test.com', :match => ' ServerAdmin test@test.com' }, { :title => 'should enable ssl', :attr => 'ssl', :value => true, :match => ' SSLEngine on', }, { :title => 'should set a servername', :attr => 'servername', :value => 'param.test', :match => ' ServerName param.test', }, { :title => 'should accept server aliases', :attr => 'serveraliases', :value => ['one.com','two.com'], :match => [' ServerAlias one.com',' ServerAlias two.com'], }, { :title => 'should accept setenv', :attr => 'setenv', :value => ['TEST1 one','TEST2 two'], :match => [' SetEnv TEST1 one',' SetEnv TEST2 two'], }, { :title => 'should accept setenvif', :attr => 'setenvif', ## These are bugged in rspec-puppet; the $1 is droped #:value => ['Host "^([^\.]*)\.website\.com$" CLIENT_NAME=$1'], #:match => [' SetEnvIf Host "^([^\.]*)\.website\.com$" CLIENT_NAME=$1'], :value => ['Host "^test\.com$" VHOST_ACCESS=test'], :match => [' SetEnvIf Host "^test\.com$" VHOST_ACCESS=test'], }, { :title => 'should accept options', :attr => 'options', :value => ['Fake','Options'], :match => ' Options Fake Options', }, { :title => 'should accept overrides', :attr => 'override', :value => ['Fake', 'Override'], :match => ' AllowOverride Fake Override', }, { :title => 'should accept logroot', :attr => 'logroot', :value => '/fake/log', :match => [/CustomLog \/fake\/log\//,/ErrorLog \/fake\/log\//], }, { :title => 'should accept pipe destination for access log', :attr => 'access_log_pipe', :value => '| /bin/fake/logging', :match => /CustomLog "| \/bin\/fake\/logging" combined$/, }, { :title => 'should accept pipe destination for error log', :attr => 'error_log_pipe', :value => '| /bin/fake/logging', :match => /ErrorLog "| \/bin\/fake\/logging" combined$/, }, { :title => 'should accept custom format for access logs', :attr => 'access_log_format', :value => '%h %{X-Forwarded-For}i %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\" \"Host: %{Host}i\" %T %D', :match => /CustomLog \/var\/log\/.+_access\.log "%h %\{X-Forwarded-For\}i %l %u %t \\"%r\\" %s %b \\"%\{Referer\}i\\" \\"%\{User-agent\}i\\" \\"Host: %\{Host\}i\\" %T %D"$/, }, { :title => 'should contain access logs', :attr => 'access_log', :value => true, :match => /CustomLog \/var\/log\/.+_access\.log combined$/, }, { :title => 'should not contain access logs', :attr => 'access_log', :value => false, :notmatch => /CustomLog \/var\/log\/.+_access\.log combined$/, }, { :title => 'should contain error logs', :attr => 'error_log', :value => true, :match => /ErrorLog.+$/, }, { :title => 'should not contain error logs', :attr => 'error_log', :value => false, :notmatch => /ErrorLog.+$/, }, { :title => 'should accept scriptaliases', :attr => 'scriptalias', :value => '/usr/scripts', :match => ' ScriptAlias /cgi-bin/ "/usr/scripts/"', }, { :title => 'should accept proxy destinations', :attr => 'proxy_dest', :value => 'http://fake.com', :match => [ ' ProxyPass / http://fake.com/', ' ProxyPassReverse / http://fake.com/', ], :notmatch => /ProxyPass .+!$/, }, { :title => 'should accept proxy_pass array of hash', :attr => 'proxy_pass', :value => [ { 'path' => '/path-a', 'url' => 'http://fake.com/a/' }, { 'path' => '/path-b', 'url' => 'http://fake.com/b/' }, ], :match => [ ' ProxyPass /path-a http://fake.com/a/', ' ProxyPassReverse /path-a http://fake.com/a/', ' ProxyPass /path-b http://fake.com/b/', ' ProxyPassReverse /path-b http://fake.com/b/', ], :notmatch => /ProxyPass .+!$/, }, { :title => 'should enable rack', :attr => 'rack_base_uris', :value => ['/rack1','/rack2'], :match => [' RackBaseURI /rack1',' RackBaseURI /rack2'], }, { :title => 'should accept request headers', :attr => 'request_headers', :value => ['append something', 'unset something_else'], :match => [ ' RequestHeader append something', ' RequestHeader unset something_else', ], }, { :title => 'should accept rewrite rules', :attr => 'rewrite_rule', :value => 'not a real rule', :match => ' RewriteRule not a real rule', }, { :title => 'should block scm', :attr => 'block', :value => 'scm', :match => ' ', }, { :title => 'should accept a custom fragment', :attr => 'custom_fragment', :value => " Some custom fragment line\n That spans multiple lines", :match => [ ' Some custom fragment line', ' That spans multiple lines', '', ], }, { :title => 'should accept an alias', :attr => 'aliases', :value => [ { 'alias' => '/', 'path' => '/var/www'} ], :match => ' Alias / /var/www', }, { :title => 'should accept multiple aliases', :attr => 'aliases', :value => [ { 'alias' => '/', 'path' => '/var/www'}, { 'alias' => '/cgi-bin', 'path' => '/var/www/cgi-bin'}, { 'alias' => '/css', 'path' => '/opt/someapp/css'}, ], :match => [ ' Alias / /var/www', ' Alias /cgi-bin /var/www/cgi-bin', ' Alias /css /opt/someapp/css' ], }, { :title => 'should accept a directory', :attr => 'directories', :value => [ { 'path' => '/opt/app' }], :notmatch => ' ', :match => [ ' ', ' AllowOverride None', ' Order allow,deny', ' Allow from all', ' ', ], }, { :title => 'should accept directory directives', :attr => 'directories', :value => [ { 'path' => '/opt/app', 'allow' => 'from rspec.org', 'allow_override' => 'Lol', 'deny' => 'from google.com', 'options' => '-MultiViews', 'order' => 'deny,yned', 'passenger_enabled' => 'onf', }, ], :match => [ ' ', ' Allow from rspec.org', ' AllowOverride Lol', ' Deny from google.com', ' Options -MultiViews', ' Order deny,yned', ' PassengerEnabled onf', ' ', ], }, { :title => 'should accept directory directives with arrays', :attr => 'directories', :value => [ { 'path' => '/opt/app', 'allow' => 'from rspec.org', 'allow_override' => ['AuthConfig','Indexes'], 'deny' => 'from google.com', 'options' => ['-MultiViews','+MultiViews'], 'order' => ['deny','yned'], 'passenger_enabled' => 'onf', }, ], :match => [ ' ', ' Allow from rspec.org', ' AllowOverride AuthConfig Indexes', ' Deny from google.com', ' Options -MultiViews +MultiViews', ' Order deny,yned', ' PassengerEnabled onf', ' ', ], }, { :title => 'should accept multiple directories', :attr => 'directories', :value => [ { 'path' => '/opt/app' }, { 'path' => '/var/www' }, { 'path' => '/rspec/docroot'} ], :match => [ ' ', ' ', ' ', ], }, { :title => 'should contain virtual_docroot', :attr => 'virtual_docroot', :value => '/not/default', :match => [ ' VirtualDocumentRoot /not/default', ], }, ].each do |param| describe "when #{param[:attr]} is #{param[:value]}" do let :params do default_params.merge({ param[:attr].to_sym => param[:value] }) end it { should contain_file("25-#{title}.conf").with_mode('0644') } it param[:title] do lines = subject.resource('file', "25-#{title}.conf").send(:parameters)[:content].split("\n") (Array(param[:match]).collect { |x| lines.grep x }.flatten.length).should == Array(param[:match]).length (Array(param[:notmatch]).collect { |x| lines.grep x }.flatten).should be_empty end end end end context 'attribute resources' do describe 'when access_log_file and access_log_pipe are specified' do let :params do default_params.merge({ :access_log_file => 'fake.log', :access_log_pipe => '| /bin/fake', }) end it 'should cause a failure' do expect {should raise_error(Puppet::Error, 'Apache::Vhost[${name}]: \'access_log_file\' and \'access_log_pipe\' cannot be defined at the same time') } end end describe 'when error_log_file and error_log_pipe are specified' do let :params do default_params.merge({ :error_log_file => 'fake.log', :error_log_pipe => '| /bin/fake', }) end it 'should cause a failure' do expect { should raise_error(Puppet::Error, 'Apache::Vhost[${name}]: \'error_log_file\' and \'error_log_pipe\' cannot be defined at the same time') } end end describe 'when docroot owner is specified' do let :params do default_params.merge({ :docroot_owner => 'testuser', :docroot_group => 'testgroup', }) end it 'should set vhost ownership' do should contain_file(params[:docroot]).with({ :ensure => :directory, :owner => 'testuser', :group => 'testgroup', }) end end describe 'when rewrite_rule and rewrite_cond are specified' do let :params do default_params.merge({ :rewrite_cond => '%{HTTPS} off', :rewrite_rule => '(.*) https://%{HTTPS_HOST}%{REQUEST_URI}', }) end it 'should set RewriteCond' do should contain_file("25-#{title}.conf").with_content( /^ RewriteCond %\{HTTPS\} off$/ ) end end describe 'priority/default settings' do describe 'when neither priority/default is specified' do let :params do default_params end it { should contain_file("25-#{title}.conf").with_path( /25-#{title}.conf/ ) } end describe 'when both priority/default_vhost is specified' do let :params do default_params.merge({ :priority => 15, :default_vhost => true, }) end it { should contain_file("15-#{title}.conf").with_path( /15-#{title}.conf/ ) } end describe 'when only priority is specified' do let :params do default_params.merge({ :priority => 14, }) end it { should contain_file("14-#{title}.conf").with_path( /14-#{title}.conf/ ) } end describe 'when only default is specified' do let :params do default_params.merge({ :default_vhost => true, }) end it { should contain_file("10-#{title}.conf").with_path( /10-#{title}.conf/ ) } end end describe 'various ip/port combos' do describe 'when ip_based is true' do let :params do default_params.merge({ :ip_based => true }) end it 'should not specify a NameVirtualHost' do should contain_apache__listen(params[:port]) should_not contain_apache__namevirtualhost("*:#{params[:port]}") end end describe 'when ip_based is default' do let :params do default_params end it 'should specify a NameVirtualHost' do should contain_apache__listen(params[:port]) should contain_apache__namevirtualhost("*:#{params[:port]}") end end describe 'when an ip is set' do let :params do default_params.merge({ :ip => '10.0.0.1' }) end it 'should specify a NameVirtualHost for the ip' do should_not contain_apache__listen(params[:port]) should contain_apache__listen("10.0.0.1:#{params[:port]}") should contain_apache__namevirtualhost("10.0.0.1:#{params[:port]}") end end describe 'an ip_based vhost without a port' do let :params do { :docroot => '/fake', :ip => '10.0.0.1', :ip_based => true, } end it 'should specify a NameVirtualHost for the ip' do should_not contain_apache__listen(params[:ip]) should_not contain_apache__namevirtualhost(params[:ip]) should contain_file("25-#{title}.conf").with_content %r{} end end end describe 'redirect rules' do describe 'without lockstep arrays' do let :params do default_params.merge({ :redirect_source => [ '/login', '/logout', ], :redirect_dest => [ 'http://10.0.0.10/login', 'http://10.0.0.10/logout', ], :redirect_status => [ 'permanent', '', ], }) end it { should contain_file("25-#{title}.conf").with_content %r{ Redirect permanent /login http://10\.0\.0\.10/login} } it { should contain_file("25-#{title}.conf").with_content %r{ Redirect /logout http://10\.0\.0\.10/logout} } end describe 'without a status' do let :params do default_params.merge({ :redirect_source => [ '/login', '/logout', ], :redirect_dest => [ 'http://10.0.0.10/login', 'http://10.0.0.10/logout', ], }) end it { should contain_file("25-#{title}.conf").with_content %r{ Redirect /login http://10\.0\.0\.10/login} } it { should contain_file("25-#{title}.conf").with_content %r{ Redirect /logout http://10\.0\.0\.10/logout} } end describe 'with a single status and dest' do let :params do default_params.merge({ :redirect_source => [ '/login', '/logout', ], :redirect_dest => 'http://10.0.0.10/test', :redirect_status => 'permanent', }) end it { should contain_file("25-#{title}.conf").with_content %r{ Redirect permanent /login http://10\.0\.0\.10/test} } it { should contain_file("25-#{title}.conf").with_content %r{ Redirect permanent /logout http://10\.0\.0\.10/test} } end end end end end