summaryrefslogtreecommitdiff
path: root/code/environments/production/modules/apt/spec
diff options
context:
space:
mode:
authorMike Gabriel <mike.gabriel@das-netzwerkteam.de>2018-09-16 22:59:26 +0200
committerMike Gabriel <mike.gabriel@das-netzwerkteam.de>2018-09-16 22:59:26 +0200
commit3f1bbf87bbcc3daa15cd7391b2949b5bf742781b (patch)
treee7c058c84b2d8aebb84db73bb00429cdf284fc13 /code/environments/production/modules/apt/spec
parent852be73c92e8a950dd0c3514cadd67058717b212 (diff)
downloadpuppet.FWSECK-3f1bbf87bbcc3daa15cd7391b2949b5bf742781b.tar.gz
puppet.FWSECK-3f1bbf87bbcc3daa15cd7391b2949b5bf742781b.tar.bz2
puppet.FWSECK-3f1bbf87bbcc3daa15cd7391b2949b5bf742781b.zip
modules/apt: Ship puppetlabs-apt module v4.5.1.
Diffstat (limited to 'code/environments/production/modules/apt/spec')
-rw-r--r--code/environments/production/modules/apt/spec/acceptance/apt_key_provider_spec.rb836
-rw-r--r--code/environments/production/modules/apt/spec/acceptance/apt_spec.rb66
-rw-r--r--code/environments/production/modules/apt/spec/acceptance/class_spec.rb16
-rw-r--r--code/environments/production/modules/apt/spec/acceptance/init_task_spec.rb11
-rw-r--r--code/environments/production/modules/apt/spec/acceptance/nodesets/centos-7-x64.yml10
-rw-r--r--code/environments/production/modules/apt/spec/acceptance/nodesets/debian-8-x64.yml10
-rw-r--r--code/environments/production/modules/apt/spec/acceptance/nodesets/default.yml10
-rw-r--r--code/environments/production/modules/apt/spec/acceptance/nodesets/docker/centos-7.yml12
-rw-r--r--code/environments/production/modules/apt/spec/acceptance/nodesets/docker/debian-8.yml11
-rw-r--r--code/environments/production/modules/apt/spec/acceptance/nodesets/docker/ubuntu-14.04.yml12
-rw-r--r--code/environments/production/modules/apt/spec/classes/apt_backports_spec.rb253
-rw-r--r--code/environments/production/modules/apt/spec/classes/apt_spec.rb387
-rw-r--r--code/environments/production/modules/apt/spec/classes/apt_update_spec.rb152
-rw-r--r--code/environments/production/modules/apt/spec/defines/conf_spec.rb90
-rw-r--r--code/environments/production/modules/apt/spec/defines/key_compat_spec.rb360
-rw-r--r--code/environments/production/modules/apt/spec/defines/key_spec.rb367
-rw-r--r--code/environments/production/modules/apt/spec/defines/pin_spec.rb148
-rw-r--r--code/environments/production/modules/apt/spec/defines/ppa_spec.rb379
-rw-r--r--code/environments/production/modules/apt/spec/defines/setting_spec.rb145
-rw-r--r--code/environments/production/modules/apt/spec/defines/source_compat_spec.rb154
-rw-r--r--code/environments/production/modules/apt/spec/defines/source_spec.rb452
-rw-r--r--code/environments/production/modules/apt/spec/spec_helper.rb23
-rw-r--r--code/environments/production/modules/apt/spec/spec_helper_acceptance.rb90
-rw-r--r--code/environments/production/modules/apt/spec/unit/facter/apt_dist_has_updates_spec.rb40
-rw-r--r--code/environments/production/modules/apt/spec/unit/facter/apt_dist_package_security_updates_spec.rb60
-rw-r--r--code/environments/production/modules/apt/spec/unit/facter/apt_dist_package_updates_spec.rb35
-rw-r--r--code/environments/production/modules/apt/spec/unit/facter/apt_dist_security_updates_spec.rb52
-rw-r--r--code/environments/production/modules/apt/spec/unit/facter/apt_dist_updates_spec.rb31
-rw-r--r--code/environments/production/modules/apt/spec/unit/facter/apt_has_updates_spec.rb38
-rw-r--r--code/environments/production/modules/apt/spec/unit/facter/apt_package_security_updates_spec.rb58
-rw-r--r--code/environments/production/modules/apt/spec/unit/facter/apt_package_updates_spec.rb33
-rw-r--r--code/environments/production/modules/apt/spec/unit/facter/apt_reboot_required_spec.rb25
-rw-r--r--code/environments/production/modules/apt/spec/unit/facter/apt_security_updates_spec.rb50
-rw-r--r--code/environments/production/modules/apt/spec/unit/facter/apt_update_last_success_spec.rb25
-rw-r--r--code/environments/production/modules/apt/spec/unit/facter/apt_updates_spec.rb30
-rw-r--r--code/environments/production/modules/apt/spec/unit/puppet/type/apt_key_spec.rb212
36 files changed, 4683 insertions, 0 deletions
diff --git a/code/environments/production/modules/apt/spec/acceptance/apt_key_provider_spec.rb b/code/environments/production/modules/apt/spec/acceptance/apt_key_provider_spec.rb
new file mode 100644
index 0000000..08bf61f
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/acceptance/apt_key_provider_spec.rb
@@ -0,0 +1,836 @@
+require 'spec_helper_acceptance'
+
+PUPPETLABS_GPG_KEY_SHORT_ID = 'EF8D349F'.freeze
+PUPPETLABS_GPG_KEY_LONG_ID = '7F438280EF8D349F'.freeze
+PUPPETLABS_GPG_KEY_FINGERPRINT = '6F6B15509CF8E59E6E469F327F438280EF8D349F'.freeze
+PUPPETLABS_APT_URL = 'apt.puppetlabs.com'.freeze
+PUPPETLABS_GPG_KEY_FILE = 'DEB-GPG-KEY-puppet'.freeze
+CENTOS_GPG_KEY_SHORT_ID = 'C105B9DE'.freeze
+CENTOS_GPG_KEY_LONG_ID = '0946FCA2C105B9DE'.freeze
+CENTOS_GPG_KEY_FINGERPRINT = 'C1DAC52D1664E8A4386DBA430946FCA2C105B9DE'.freeze
+CENTOS_REPO_URL = 'ftp.cvut.cz/centos'.freeze
+CENTOS_GPG_KEY_FILE = 'RPM-GPG-KEY-CentOS-6'.freeze
+
+SHOULD_NEVER_EXIST_ID = 'EF8D349F'.freeze
+
+KEY_CHECK_COMMAND = 'apt-key adv --list-keys --with-colons --fingerprint | grep '.freeze
+PUPPETLABS_KEY_CHECK_COMMAND = "#{KEY_CHECK_COMMAND} #{PUPPETLABS_GPG_KEY_FINGERPRINT}".freeze
+CENTOS_KEY_CHECK_COMMAND = "#{KEY_CHECK_COMMAND} #{CENTOS_GPG_KEY_FINGERPRINT}".freeze
+
+MAX_TIMEOUT_RETRY = 3
+TIMEOUT_RETRY_WAIT = 5
+TIMEOUT_ERROR_MATCHER = %r{no valid OpenPGP data found}
+
+def populate_default_options_pp(value)
+ default_options_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{value}',
+ ensure => 'present',
+ }
+ MANIFEST
+ default_options_pp
+end
+
+def install_key(key)
+ retry_on_error_matching(MAX_TIMEOUT_RETRY, TIMEOUT_RETRY_WAIT, TIMEOUT_ERROR_MATCHER) do
+ shell("apt-key adv --keyserver hkps.pool.sks-keyservers.net \
+ --recv-keys #{key}")
+ end
+end
+
+def apply_manifest_twice(manifest_pp)
+ apply_manifest(manifest_pp, catch_failures: true)
+ apply_manifest(manifest_pp, catch_changes: true)
+end
+
+invalid_key_length_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '8280EF8D349F',
+ }
+ MANIFEST
+
+ensure_absent_pp = <<-MANIFEST
+ apt_key { 'centos':
+ id => '#{CENTOS_GPG_KEY_LONG_ID}',
+ ensure => 'absent',
+ }
+ MANIFEST
+
+ensure_absent_long_key_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
+ ensure => 'absent',
+ }
+ MANIFEST
+
+gpg_key_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_FINGERPRINT}',
+ ensure => 'present',
+ content => "-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+ 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
+ 3xJn
+ =mMjt
+ -----END PGP PUBLIC KEY BLOCK-----",
+ }
+ MANIFEST
+
+multiple_keys_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_FINGERPRINT}',
+ ensure => 'present',
+ content => "-----BEGIN PGP PUBLIC KEY BLOCK-----
+ Version: GnuPG v1
+
+ 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
+ FPfZDNCu/TXoqyJk7434jJrcHgPryzrHFBLfEmc=
+ =TREp
+ -----END PGP PUBLIC KEY BLOCK----- ",
+ }
+ MANIFEST
+
+bogus_key_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
+ ensure => 'present',
+ content => 'For posterity: such content, much bogus, wow',
+ }
+ MANIFEST
+
+hkps_pool_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
+ ensure => 'present',
+ server => 'hkps.pool.sks-keyservers.net',
+ }
+ MANIFEST
+
+hkp_pool_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_FINGERPRINT}',
+ ensure => 'present',
+ server => 'hkp://hkps.pool.sks-keyservers.net:80',
+ }
+ MANIFEST
+
+nonexistant_key_server_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
+ ensure => 'present',
+ server => 'nonexistant.key.server',
+ }
+ MANIFEST
+
+dot_server_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
+ ensure => 'present',
+ server => '.pgp.key.server',
+ }
+ MANIFEST
+
+http_works_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
+ ensure => 'present',
+ source => 'http://#{PUPPETLABS_APT_URL}/#{PUPPETLABS_GPG_KEY_FILE}',
+ }
+ MANIFEST
+
+http_works_userinfo_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
+ ensure => 'present',
+ source => 'http://dummyuser:dummypassword@#{PUPPETLABS_APT_URL}/#{PUPPETLABS_GPG_KEY_FILE}',
+ }
+ MANIFEST
+
+four_oh_four_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
+ ensure => 'present',
+ source => 'http://#{PUPPETLABS_APT_URL}/herpderp.gpg',
+ }
+ MANIFEST
+
+socket_error_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
+ ensure => 'present',
+ source => 'http://apt.puppetlabss.com/herpderp.gpg',
+ }
+ MANIFEST
+
+ftp_works_pp = <<-MANIFEST
+ apt_key { 'CentOS 6':
+ id => '#{CENTOS_GPG_KEY_LONG_ID}',
+ ensure => 'present',
+ source => 'ftp://#{CENTOS_REPO_URL}/#{CENTOS_GPG_KEY_FILE}',
+ }
+ MANIFEST
+
+ftp_550_pp = <<-MANIFEST
+ apt_key { 'CentOS 6':
+ id => '#{SHOULD_NEVER_EXIST_ID}',
+ ensure => 'present',
+ source => 'ftp://#{CENTOS_REPO_URL}/herpderp.gpg',
+ }
+ MANIFEST
+
+ftp_socket_error_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
+ ensure => 'present',
+ source => 'ftp://apt.puppetlabss.com/herpderp.gpg',
+ }
+ MANIFEST
+
+https_works_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
+ ensure => 'present',
+ source => 'https://#{PUPPETLABS_APT_URL}/#{PUPPETLABS_GPG_KEY_FILE}',
+ }
+ MANIFEST
+
+https_userinfo_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
+ ensure => 'present',
+ source => 'https://dummyuser:dummypassword@#{PUPPETLABS_APT_URL}/#{PUPPETLABS_GPG_KEY_FILE}',
+ }
+ MANIFEST
+
+https_404_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{SHOULD_NEVER_EXIST_ID}',
+ ensure => 'present',
+ source => 'https://#{PUPPETLABS_APT_URL}/herpderp.gpg',
+ }
+ MANIFEST
+
+https_socket_error_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{SHOULD_NEVER_EXIST_ID}',
+ ensure => 'present',
+ source => 'https://apt.puppetlabss.com/herpderp.gpg',
+ }
+ MANIFEST
+
+path_exists_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => 'EF8D349F',
+ ensure => 'present',
+ source => '/tmp/puppetlabs-pubkey.gpg',
+ }
+ MANIFEST
+
+path_does_not_exist_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
+ ensure => 'present',
+ source => '/tmp/totally_bogus.file',
+ }
+ MANIFEST
+
+path_bogus_content_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
+ ensure => 'present',
+ source => '/tmp/fake-key.gpg',
+ }
+ MANIFEST
+
+debug_works_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
+ ensure => 'present',
+ options => 'debug',
+ }
+ MANIFEST
+
+fingerprint_match_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_FINGERPRINT}',
+ ensure => 'present',
+ source => 'https://#{PUPPETLABS_APT_URL}/#{PUPPETLABS_GPG_KEY_FILE}',
+ }
+ MANIFEST
+
+fingerprint_does_not_match_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '6F6B15509CF8E59E6E469F327F438280EF8D9999',
+ ensure => 'present',
+ source => 'https://#{PUPPETLABS_APT_URL}/#{PUPPETLABS_GPG_KEY_FILE}',
+ }
+ MANIFEST
+
+describe 'apt_key' do
+ before(:each) do
+ # Delete twice to make sure everything is cleaned
+ # up after the short key collision
+ shell("apt-key del #{PUPPETLABS_GPG_KEY_SHORT_ID}",
+ acceptable_exit_codes: [0, 1, 2])
+ shell("apt-key del #{PUPPETLABS_GPG_KEY_SHORT_ID}",
+ acceptable_exit_codes: [0, 1, 2])
+ end
+
+ describe 'default options' do
+ key_versions = {
+ '32bit key id' => PUPPETLABS_GPG_KEY_SHORT_ID.to_s,
+ '64bit key id' => PUPPETLABS_GPG_KEY_LONG_ID.to_s,
+ '160bit key fingerprint' => PUPPETLABS_GPG_KEY_FINGERPRINT.to_s,
+ '32bit lowercase key id' => PUPPETLABS_GPG_KEY_SHORT_ID.downcase.to_s,
+ '64bit lowercase key id' => PUPPETLABS_GPG_KEY_LONG_ID.downcase.to_s,
+ '160bit lowercase key fingerprint' => PUPPETLABS_GPG_KEY_FINGERPRINT.downcase.to_s,
+ '0x formatted 32bit key id' => "0x#{PUPPETLABS_GPG_KEY_SHORT_ID}",
+ '0x formatted 64bit key id' => "0x#{PUPPETLABS_GPG_KEY_LONG_ID}",
+ '0x formatted 160bit key fingerprint' => "0x#{PUPPETLABS_GPG_KEY_FINGERPRINT}",
+ '0x formatted 32bit lowercase key id' => "0x#{PUPPETLABS_GPG_KEY_SHORT_ID.downcase}",
+ '0x formatted 64bit lowercase key id' => "0x#{PUPPETLABS_GPG_KEY_LONG_ID.downcase}",
+ '0x formatted 160bit lowercase key fingerprint' => "0x#{PUPPETLABS_GPG_KEY_FINGERPRINT.downcase}",
+ }
+
+ key_versions.each do |key, value| # rubocop:disable Lint/UnusedBlockArgument
+ context 'when key.to_s' do
+ it 'works' do
+ apply_manifest_twice(populate_default_options_pp(value))
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
+ end
+ end
+ end
+
+ context 'with invalid length key id' do
+ it 'fails' do
+ apply_manifest(invalid_key_length_pp, expect_failures: true) do |r|
+ expect(r.stderr).to match(%r{Valid values match})
+ end
+ end
+ end
+ end
+
+ describe 'ensure =>' do
+ context 'when absent' do
+ it 'is removed' do
+ # Install the key first (retry because key pool may timeout)
+ install_key(CENTOS_GPG_KEY_FINGERPRINT)
+ shell(CENTOS_KEY_CHECK_COMMAND)
+
+ # Time to remove it using Puppet
+ apply_manifest_twice(ensure_absent_pp)
+
+ shell(CENTOS_KEY_CHECK_COMMAND, acceptable_exit_codes: [1])
+
+ # Re-Install the key (retry because key pool may timeout)
+ install_key(CENTOS_GPG_KEY_FINGERPRINT)
+ end
+ end
+
+ context 'when absent, added with long key', unless: (fact('operatingsystem') == 'Debian' && fact('operatingsystemmajrelease') == '6') do
+ it 'is removed' do
+ # Install the key first (retry because key pool may timeout)
+ install_key(PUPPETLABS_GPG_KEY_LONG_ID)
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
+
+ # Time to remove it using Puppet
+ apply_manifest_twice(ensure_absent_long_key_pp)
+
+ shell(PUPPETLABS_KEY_CHECK_COMMAND, acceptable_exit_codes: [1])
+ end
+ end
+ end
+
+ describe 'content =>' do
+ context 'with puppetlabs gpg key' do
+ it 'works' do
+ # Apply the manifest (Retry if timeout error is received from key pool)
+ retry_on_error_matching(MAX_TIMEOUT_RETRY, TIMEOUT_RETRY_WAIT, TIMEOUT_ERROR_MATCHER) do
+ apply_manifest(gpg_key_pp, catch_failures: true)
+ end
+
+ apply_manifest(gpg_key_pp, catch_changes: true)
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
+ end
+ end
+
+ context 'with multiple keys' do
+ it 'runs without errors' do
+ apply_manifest_twice(multiple_keys_pp)
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
+ end
+ end
+
+ context 'with bogus key' do
+ it 'fails' do
+ apply_manifest(bogus_key_pp, expect_failures: true) do |r|
+ expect(r.stderr).to match(%r{no valid OpenPGP data found})
+ end
+ end
+ end
+ end
+
+ describe 'server =>' do
+ context 'with hkps.pool.sks-keyservers.net' do
+ it 'works' do
+ # Apply the manifest (Retry if timeout error is received from key pool)
+ retry_on_error_matching(MAX_TIMEOUT_RETRY, TIMEOUT_RETRY_WAIT, TIMEOUT_ERROR_MATCHER) do
+ apply_manifest(hkps_pool_pp, catch_failures: true)
+ end
+
+ apply_manifest(hkps_pool_pp, catch_changes: true)
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
+ end
+ end
+
+ context 'with hkp://hkps.pool.sks-keyservers.net:80' do
+ it 'works' do
+ retry_on_error_matching(MAX_TIMEOUT_RETRY, TIMEOUT_RETRY_WAIT, TIMEOUT_ERROR_MATCHER) do
+ apply_manifest(hkp_pool_pp, catch_failures: true)
+ end
+
+ apply_manifest(hkp_pool_pp, catch_changes: true)
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
+ end
+ end
+
+ context 'with nonexistant.key.server' do
+ it 'fails' do
+ apply_manifest(nonexistant_key_server_pp, expect_failures: true) do |r|
+ expect(r.stderr).to match(%r{(Host not found|Couldn't resolve host)})
+ end
+ end
+ end
+
+ context 'with key server start with dot' do
+ it 'fails' do
+ apply_manifest(dot_server_pp, expect_failures: true) do |r|
+ expect(r.stderr).to match(%r{Invalid value ".pgp.key.server"})
+ end
+ end
+ end
+ end
+
+ describe 'source =>' do
+ context 'with http://' do
+ it 'works' do
+ apply_manifest_twice(http_works_pp)
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
+ end
+
+ it 'works with userinfo' do
+ apply_manifest_twice(http_works_userinfo_pp)
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
+ end
+
+ it 'fails with a 404' do
+ apply_manifest(four_oh_four_pp, expect_failures: true) do |r|
+ expect(r.stderr).to match(%r{404 Not Found})
+ end
+ end
+
+ it 'fails with a socket error' do
+ apply_manifest(socket_error_pp, expect_failures: true) do |r|
+ expect(r.stderr).to match(%r{could not resolve})
+ end
+ end
+ end
+
+ context 'with ftp://' do
+ before(:each) do
+ shell("apt-key del #{CENTOS_GPG_KEY_LONG_ID}",
+ acceptable_exit_codes: [0, 1, 2])
+ end
+
+ it 'works' do
+ apply_manifest_twice(ftp_works_pp)
+ shell(CENTOS_KEY_CHECK_COMMAND)
+ end
+
+ it 'fails with a 550' do
+ apply_manifest(ftp_550_pp, expect_failures: true) do |r|
+ expect(r.stderr).to match(%r{550 Failed to open})
+ end
+ end
+
+ it 'fails with a socket error' do
+ apply_manifest(ftp_socket_error_pp, expect_failures: true) do |r|
+ expect(r.stderr).to match(%r{could not resolve})
+ end
+ end
+ end
+
+ context 'with https://' do
+ it 'works' do
+ apply_manifest_twice(https_works_pp)
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
+ end
+
+ it 'works with userinfo' do
+ apply_manifest_twice(https_userinfo_pp)
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
+ end
+
+ it 'fails with a 404' do
+ apply_manifest(https_404_pp, expect_failures: true) do |r|
+ expect(r.stderr).to match(%r{404 Not Found})
+ end
+ end
+
+ it 'fails with a socket error' do
+ apply_manifest(https_socket_error_pp, expect_failures: true) do |r|
+ expect(r.stderr).to match(%r{could not resolve})
+ end
+ end
+ end
+
+ context 'with /path/that/exists' do
+ before(:each) do
+ shell("curl -o /tmp/puppetlabs-pubkey.gpg \
+ http://#{PUPPETLABS_APT_URL}/#{PUPPETLABS_GPG_KEY_FILE}")
+ end
+
+ after(:each) do
+ shell('rm /tmp/puppetlabs-pubkey.gpg')
+ end
+
+ it 'works' do
+ apply_manifest_twice(path_exists_pp)
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
+ end
+ end
+
+ context 'with /path/that/does/not/exist' do
+ it 'fails' do
+ apply_manifest(path_does_not_exist_pp, expect_failures: true) do |r|
+ expect(r.stderr).to match(%r{does not exist})
+ end
+ end
+ end
+
+ context 'with /path/that/exists/with/bogus/content' do
+ before(:each) do
+ shell('echo "here be dragons" > /tmp/fake-key.gpg')
+ end
+
+ after(:each) do
+ shell('rm /tmp/fake-key.gpg')
+ end
+ it 'fails' do
+ apply_manifest(path_bogus_content_pp, expect_failures: true) do |r|
+ expect(r.stderr).to match(%r{no valid OpenPGP data found})
+ end
+ end
+ end
+ end
+
+ describe 'options =>' do
+ context 'with debug' do
+ it 'works' do
+ apply_manifest_twice(debug_works_pp)
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
+ end
+ end
+ end
+
+ describe 'fingerprint validation against source/content' do
+ context 'with fingerprint in id matches fingerprint from remote key' do
+ it 'works' do
+ apply_manifest_twice(fingerprint_match_pp)
+ end
+ end
+
+ context 'with fingerprint in id does NOT match fingerprint from remote key' do
+ it 'works' do
+ apply_manifest(fingerprint_does_not_match_pp, expect_failures: true) do |r|
+ expect(r.stderr).to match(%r{don't match})
+ end
+ end
+ end
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/acceptance/apt_spec.rb b/code/environments/production/modules/apt/spec/acceptance/apt_spec.rb
new file mode 100644
index 0000000..5505748
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/acceptance/apt_spec.rb
@@ -0,0 +1,66 @@
+require 'spec_helper_acceptance'
+
+MAX_TIMEOUT_RETRY = 3
+TIMEOUT_RETRY_WAIT = 5
+TIMEOUT_ERROR_MATCHER = %r{no valid OpenPGP data found}
+
+everything_everything_pp = <<-MANIFEST
+ if $::lsbdistcodename == 'lucid' {
+ $sources = undef
+ } else {
+ $sources = {
+ 'puppetlabs' => {
+ 'ensure' => present,
+ 'location' => 'http://apt.puppetlabs.com',
+ 'repos' => 'main',
+ 'key' => {
+ 'id' => '6F6B15509CF8E59E6E469F327F438280EF8D349F',
+ 'server' => 'hkps.pool.sks-keyservers.net',
+ },
+ },
+ }
+ }
+ class { 'apt':
+ update => {
+ 'frequency' => 'always',
+ 'timeout' => 400,
+ 'tries' => 3,
+ },
+ purge => {
+ 'sources.list' => true,
+ 'sources.list.d' => true,
+ 'preferences' => true,
+ 'preferences.d' => true,
+ },
+ sources => $sources,
+ }
+ MANIFEST
+
+describe 'apt class' do
+ context 'with reset' do
+ it 'fixes the sources.list' do
+ shell('cp /etc/apt/sources.list /tmp')
+ end
+ end
+
+ context 'with all the things' do
+ it 'works with no errors' do
+ # Apply the manifest (Retry if timeout error is received from key pool)
+ retry_on_error_matching(MAX_TIMEOUT_RETRY, TIMEOUT_RETRY_WAIT, TIMEOUT_ERROR_MATCHER) do
+ apply_manifest(everything_everything_pp, catch_failures: true)
+ end
+
+ apply_manifest(everything_everything_pp, catch_failures: true)
+ end
+ it 'stills work' do
+ shell('apt-get update')
+ shell('apt-get -y --force-yes upgrade')
+ end
+ end
+
+ context 'with reset' do
+ it 'fixes the sources.list' do
+ shell('cp /tmp/sources.list /etc/apt')
+ end
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/acceptance/class_spec.rb b/code/environments/production/modules/apt/spec/acceptance/class_spec.rb
new file mode 100644
index 0000000..53d75f6
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/acceptance/class_spec.rb
@@ -0,0 +1,16 @@
+require 'spec_helper_acceptance'
+
+describe 'apt class' do
+ context 'with default parameters' do
+ # Using puppet_apply as a helper
+ it 'works with no errors' do
+ pp = <<-MANIFEST
+ class { 'apt': }
+ MANIFEST
+
+ # Run it twice and test for idempotency
+ apply_manifest(pp, catch_failures: true)
+ apply_manifest(pp, catch_changes: true)
+ end
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/acceptance/init_task_spec.rb b/code/environments/production/modules/apt/spec/acceptance/init_task_spec.rb
new file mode 100644
index 0000000..58f3ca7
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/acceptance/init_task_spec.rb
@@ -0,0 +1,11 @@
+# run a test task
+require 'spec_helper_acceptance'
+
+describe 'apt tasks' do
+ describe 'update and upgrade', if: pe_install? && puppet_version =~ %r{(5\.\d\.\d)} && fact_on(master, 'osfamily') == 'Debian' do
+ it 'execute arbitary sql' do
+ result = run_task(task_name: 'apt', params: 'action=update')
+ expect_multiple_regexes(result: result, regexes: [%r{Reading package lists}, %r{Job completed. 1/1 nodes succeeded}])
+ end
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/acceptance/nodesets/centos-7-x64.yml b/code/environments/production/modules/apt/spec/acceptance/nodesets/centos-7-x64.yml
new file mode 100644
index 0000000..5eebdef
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/acceptance/nodesets/centos-7-x64.yml
@@ -0,0 +1,10 @@
+HOSTS:
+ centos-7-x64:
+ roles:
+ - agent
+ - default
+ platform: el-7-x86_64
+ hypervisor: vagrant
+ box: puppetlabs/centos-7.2-64-nocm
+CONFIG:
+ type: foss
diff --git a/code/environments/production/modules/apt/spec/acceptance/nodesets/debian-8-x64.yml b/code/environments/production/modules/apt/spec/acceptance/nodesets/debian-8-x64.yml
new file mode 100644
index 0000000..fef6e63
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/acceptance/nodesets/debian-8-x64.yml
@@ -0,0 +1,10 @@
+HOSTS:
+ debian-8-x64:
+ roles:
+ - agent
+ - default
+ platform: debian-8-amd64
+ hypervisor: vagrant
+ box: puppetlabs/debian-8.2-64-nocm
+CONFIG:
+ type: foss
diff --git a/code/environments/production/modules/apt/spec/acceptance/nodesets/default.yml b/code/environments/production/modules/apt/spec/acceptance/nodesets/default.yml
new file mode 100644
index 0000000..dba339c
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/acceptance/nodesets/default.yml
@@ -0,0 +1,10 @@
+HOSTS:
+ ubuntu-1404-x64:
+ roles:
+ - agent
+ - default
+ platform: ubuntu-14.04-amd64
+ hypervisor: vagrant
+ box: puppetlabs/ubuntu-14.04-64-nocm
+CONFIG:
+ type: foss
diff --git a/code/environments/production/modules/apt/spec/acceptance/nodesets/docker/centos-7.yml b/code/environments/production/modules/apt/spec/acceptance/nodesets/docker/centos-7.yml
new file mode 100644
index 0000000..a3333aa
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/acceptance/nodesets/docker/centos-7.yml
@@ -0,0 +1,12 @@
+HOSTS:
+ centos-7-x64:
+ platform: el-7-x86_64
+ hypervisor: docker
+ image: centos:7
+ docker_preserve_image: true
+ docker_cmd: '["/usr/sbin/init"]'
+ # install various tools required to get the image up to usable levels
+ docker_image_commands:
+ - 'yum install -y crontabs tar wget openssl sysvinit-tools iproute which initscripts'
+CONFIG:
+ trace_limit: 200
diff --git a/code/environments/production/modules/apt/spec/acceptance/nodesets/docker/debian-8.yml b/code/environments/production/modules/apt/spec/acceptance/nodesets/docker/debian-8.yml
new file mode 100644
index 0000000..df5c319
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/acceptance/nodesets/docker/debian-8.yml
@@ -0,0 +1,11 @@
+HOSTS:
+ debian-8-x64:
+ platform: debian-8-amd64
+ hypervisor: docker
+ image: debian:8
+ docker_preserve_image: true
+ docker_cmd: '["/sbin/init"]'
+ docker_image_commands:
+ - 'apt-get update && apt-get install -y net-tools wget locales strace lsof && echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && locale-gen'
+CONFIG:
+ trace_limit: 200
diff --git a/code/environments/production/modules/apt/spec/acceptance/nodesets/docker/ubuntu-14.04.yml b/code/environments/production/modules/apt/spec/acceptance/nodesets/docker/ubuntu-14.04.yml
new file mode 100644
index 0000000..b1efa58
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/acceptance/nodesets/docker/ubuntu-14.04.yml
@@ -0,0 +1,12 @@
+HOSTS:
+ ubuntu-1404-x64:
+ platform: ubuntu-14.04-amd64
+ hypervisor: docker
+ image: ubuntu:14.04
+ docker_preserve_image: true
+ docker_cmd: '["/sbin/init"]'
+ docker_image_commands:
+ # ensure that upstart is booting correctly in the container
+ - 'rm /usr/sbin/policy-rc.d && rm /sbin/initctl && dpkg-divert --rename --remove /sbin/initctl && apt-get update && apt-get install -y net-tools wget && locale-gen en_US.UTF-8'
+CONFIG:
+ trace_limit: 200
diff --git a/code/environments/production/modules/apt/spec/classes/apt_backports_spec.rb b/code/environments/production/modules/apt/spec/classes/apt_backports_spec.rb
new file mode 100644
index 0000000..33022b9
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/classes/apt_backports_spec.rb
@@ -0,0 +1,253 @@
+require 'spec_helper'
+
+describe 'apt::backports', type: :class do
+ let(:pre_condition) { "class{ '::apt': }" }
+
+ describe 'debian/ubuntu tests' do
+ context 'with defaults on deb' do
+ let(:facts) do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ osfamily: 'Debian',
+ lsbdistcodename: 'wheezy',
+ puppetversion: Puppet.version,
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__source('backports').with(location: 'http://deb.debian.org/debian',
+ key: 'A1BD8E9D78F7FE5C3E65D8AF8B48AD6246925553',
+ repos: 'main contrib non-free',
+ release: 'wheezy-backports',
+ pin: { 'priority' => 200, 'release' => 'wheezy-backports' })
+ }
+ end
+ context 'with defaults on ubuntu' do
+ let(:facts) do
+ {
+ os: { family: 'Debian', name: 'Ubuntu', release: { major: '14', full: '14.04' } },
+ lsbdistid: 'Ubuntu',
+ osfamily: 'Debian',
+ lsbdistcodename: 'trusty',
+ lsbdistrelease: '14.04',
+ puppetversion: Puppet.version,
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__source('backports').with(location: 'http://archive.ubuntu.com/ubuntu',
+ key: '630239CC130E1A7FD81A27B140976EAF437D05B5',
+ repos: 'main universe multiverse restricted',
+ release: 'trusty-backports',
+ pin: { 'priority' => 200, 'release' => 'trusty-backports' })
+ }
+ end
+ context 'with everything set' do
+ let(:facts) do
+ {
+ os: { family: 'Debian', name: 'Ubuntu', release: { major: '14', full: '14.04' } },
+ lsbdistid: 'Ubuntu',
+ osfamily: 'Debian',
+ lsbdistcodename: 'trusty',
+ lsbdistrelease: '14.04',
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:params) do
+ {
+ location: 'http://archive.ubuntu.com/ubuntu-test',
+ release: 'vivid',
+ repos: 'main',
+ key: 'A1BD8E9D78F7FE5C3E65D8AF8B48AD6246925553',
+ pin: '90',
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__source('backports').with(location: 'http://archive.ubuntu.com/ubuntu-test',
+ key: 'A1BD8E9D78F7FE5C3E65D8AF8B48AD6246925553',
+ repos: 'main',
+ release: 'vivid',
+ pin: { 'priority' => 90, 'release' => 'vivid' })
+ }
+ end
+ context 'when set things with hashes' do
+ let(:facts) do
+ {
+ os: { family: 'Debian', name: 'Ubuntu', release: { major: '14', full: '14.04' } },
+ lsbdistid: 'Ubuntu',
+ osfamily: 'Debian',
+ lsbdistcodename: 'trusty',
+ lsbdistrelease: '14.04',
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:params) do
+ {
+ key: {
+ 'id' => 'A1BD8E9D78F7FE5C3E65D8AF8B48AD6246925553',
+ },
+ pin: {
+ 'priority' => '90',
+ },
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__source('backports').with(key: { 'id' => 'A1BD8E9D78F7FE5C3E65D8AF8B48AD6246925553' },
+ pin: { 'priority' => '90' })
+ }
+ end
+ end
+ describe 'mint tests' do
+ let(:facts) do
+ {
+ os: { family: 'Debian', name: 'Linuxmint', release: { major: '17', full: '17' } },
+ lsbdistid: 'linuxmint',
+ osfamily: 'Debian',
+ lsbdistcodename: 'qiana',
+ puppetversion: Puppet.version,
+ }
+ end
+
+ context 'with all the needed things set' do
+ let(:params) do
+ {
+ location: 'http://archive.ubuntu.com/ubuntu',
+ release: 'trusty-backports',
+ repos: 'main universe multiverse restricted',
+ key: '630239CC130E1A7FD81A27B140976EAF437D05B5',
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__source('backports').with(location: 'http://archive.ubuntu.com/ubuntu',
+ key: '630239CC130E1A7FD81A27B140976EAF437D05B5',
+ repos: 'main universe multiverse restricted',
+ release: 'trusty-backports',
+ pin: { 'priority' => 200, 'release' => 'trusty-backports' })
+ }
+ end
+ context 'with missing location' do
+ let(:params) do
+ {
+ release: 'trusty-backports',
+ repos: 'main universe multiverse restricted',
+ key: '630239CC130E1A7FD81A27B140976EAF437D05B5',
+ }
+ end
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{If not on Debian or Ubuntu, you must explicitly pass location, release, repos, and key})
+ end
+ end
+ context 'with missing release' do
+ let(:params) do
+ {
+ location: 'http://archive.ubuntu.com/ubuntu',
+ repos: 'main universe multiverse restricted',
+ key: '630239CC130E1A7FD81A27B140976EAF437D05B5',
+ }
+ end
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{If not on Debian or Ubuntu, you must explicitly pass location, release, repos, and key})
+ end
+ end
+ context 'with missing repos' do
+ let(:params) do
+ {
+ location: 'http://archive.ubuntu.com/ubuntu',
+ release: 'trusty-backports',
+ key: '630239CC130E1A7FD81A27B140976EAF437D05B5',
+ }
+ end
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{If not on Debian or Ubuntu, you must explicitly pass location, release, repos, and key})
+ end
+ end
+ context 'with missing key' do
+ let(:params) do
+ {
+ location: 'http://archive.ubuntu.com/ubuntu',
+ release: 'trusty-backports',
+ repos: 'main universe multiverse restricted',
+ }
+ end
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{If not on Debian or Ubuntu, you must explicitly pass location, release, repos, and key})
+ end
+ end
+ end
+ describe 'validation' do
+ let(:facts) do
+ {
+ os: { family: 'Debian', name: 'Ubuntu', release: { major: '14', full: '14.04' } },
+ lsbdistid: 'Ubuntu',
+ osfamily: 'Debian',
+ lsbdistcodename: 'trusty',
+ lsbdistrelease: '14.04',
+ puppetversion: Puppet.version,
+ }
+ end
+
+ context 'with invalid location' do
+ let(:params) do
+ {
+ location: true,
+ }
+ end
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{expects a})
+ end
+ end
+ context 'with invalid release' do
+ let(:params) do
+ {
+ release: true,
+ }
+ end
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{expects a})
+ end
+ end
+ context 'with invalid repos' do
+ let(:params) do
+ {
+ repos: true,
+ }
+ end
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{expects a})
+ end
+ end
+ context 'with invalid key' do
+ let(:params) do
+ {
+ key: true,
+ }
+ end
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{expects a})
+ end
+ end
+ context 'with invalid pin' do
+ let(:params) do
+ {
+ pin: true,
+ }
+ end
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{expects a})
+ end
+ end
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/classes/apt_spec.rb b/code/environments/production/modules/apt/spec/classes/apt_spec.rb
new file mode 100644
index 0000000..0c6333b
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/classes/apt_spec.rb
@@ -0,0 +1,387 @@
+require 'spec_helper'
+
+sources_list = { ensure: 'file',
+ path: '/etc/apt/sources.list',
+ owner: 'root',
+ group: 'root',
+ mode: '0644',
+ notify: 'Class[Apt::Update]' }
+
+sources_list_d = { ensure: 'directory',
+ path: '/etc/apt/sources.list.d',
+ owner: 'root',
+ group: 'root',
+ mode: '0644',
+ purge: false,
+ recurse: false,
+ notify: 'Class[Apt::Update]' }
+
+preferences = { ensure: 'file',
+ path: '/etc/apt/preferences',
+ owner: 'root',
+ group: 'root',
+ mode: '0644',
+ notify: 'Class[Apt::Update]' }
+
+preferences_d = { ensure: 'directory',
+ path: '/etc/apt/preferences.d',
+ owner: 'root',
+ group: 'root',
+ mode: '0644',
+ purge: false,
+ recurse: false,
+ notify: 'Class[Apt::Update]' }
+
+describe 'apt' do
+ let(:facts) do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ osfamily: 'Debian',
+ lsbdistcodename: 'wheezy',
+ puppetversion: Puppet.version,
+ }
+ end
+
+ context 'with defaults' do
+ it {
+ is_expected.to contain_file('sources.list').that_notifies('Class[Apt::Update]').only_with(sources_list)
+ }
+
+ it {
+ is_expected.to contain_file('sources.list.d').that_notifies('Class[Apt::Update]').only_with(sources_list_d)
+ }
+
+ it {
+ is_expected.to contain_file('preferences').that_notifies('Class[Apt::Update]').only_with(preferences)
+ }
+
+ it {
+ is_expected.to contain_file('preferences.d').that_notifies('Class[Apt::Update]').only_with(preferences_d)
+ }
+
+ it 'lays down /etc/apt/apt.conf.d/15update-stamp' do
+ is_expected.to contain_file('/etc/apt/apt.conf.d/15update-stamp').with(group: 'root',
+ mode: '0644',
+ owner: 'root').with_content(
+ %r{APT::Update::Post-Invoke-Success {"touch /var/lib/apt/periodic/update-success-stamp 2>/dev/null || true";};},
+ )
+ end
+
+ it {
+ is_expected.to contain_exec('apt_update').with(refreshonly: 'true')
+ }
+
+ it { is_expected.not_to contain_apt__setting('conf-proxy') }
+ end
+
+ describe 'proxy=' do
+ context 'when host=localhost' do
+ let(:params) { { proxy: { 'host' => 'localhost' } } }
+
+ it {
+ is_expected.to contain_apt__setting('conf-proxy').with(priority: '01').with_content(
+ %r{Acquire::http::proxy "http://localhost:8080/";},
+ ).without_content(
+ %r{Acquire::https::proxy},
+ )
+ }
+ end
+
+ context 'when host=localhost and port=8180' do
+ let(:params) { { proxy: { 'host' => 'localhost', 'port' => 8180 } } }
+
+ it {
+ is_expected.to contain_apt__setting('conf-proxy').with(priority: '01').with_content(
+ %r{Acquire::http::proxy "http://localhost:8180/";},
+ ).without_content(
+ %r{Acquire::https::proxy},
+ )
+ }
+ end
+
+ context 'when host=localhost and https=true' do
+ let(:params) { { proxy: { 'host' => 'localhost', 'https' => true } } }
+
+ it {
+ is_expected.to contain_apt__setting('conf-proxy').with(priority: '01').with_content(
+ %r{Acquire::http::proxy "http://localhost:8080/";},
+ ).with_content(
+ %r{Acquire::https::proxy "https://localhost:8080/";},
+ )
+ }
+ end
+
+ context 'when host=localhost and direct=true' do
+ let(:params) { { proxy: { 'host' => 'localhost', 'direct' => true } } }
+
+ it {
+ is_expected.to contain_apt__setting('conf-proxy').with(priority: '01').with_content(
+ %r{Acquire::http::proxy "http://localhost:8080/";},
+ ).with_content(
+ %r{Acquire::https::proxy "DIRECT";},
+ )
+ }
+ end
+
+ context 'when host=localhost and https=true and direct=true' do
+ let(:params) { { proxy: { 'host' => 'localhost', 'https' => true, 'direct' => true } } }
+
+ it {
+ is_expected.to contain_apt__setting('conf-proxy').with(priority: '01').with_content(
+ %r{Acquire::http::proxy "http://localhost:8080/";},
+ ).with_content(
+ %r{Acquire::https::proxy "https://localhost:8080/";},
+ )
+ }
+ it {
+ is_expected.to contain_apt__setting('conf-proxy').with(priority: '01').with_content(
+ %r{Acquire::http::proxy "http://localhost:8080/";},
+ ).without_content(
+ %r{Acquire::https::proxy "DIRECT";},
+ )
+ }
+ end
+
+ context 'when ensure=absent' do
+ let(:params) { { proxy: { 'ensure' => 'absent' } } }
+
+ it {
+ is_expected.to contain_apt__setting('conf-proxy').with(ensure: 'absent',
+ priority: '01')
+ }
+ end
+ end
+ context 'with lots of non-defaults' do
+ let :params do
+ {
+ update: { 'frequency' => 'always', 'timeout' => 1, 'tries' => 3 },
+ purge: { 'sources.list' => false, 'sources.list.d' => false,
+ 'preferences' => false, 'preferences.d' => false },
+ }
+ end
+
+ it {
+ is_expected.to contain_file('sources.list').with(content: nil)
+ }
+
+ it {
+ is_expected.to contain_file('sources.list.d').with(purge: false,
+ recurse: false)
+ }
+
+ it {
+ is_expected.to contain_file('preferences').with(ensure: 'file')
+ }
+
+ it {
+ is_expected.to contain_file('preferences.d').with(purge: false,
+ recurse: false)
+ }
+
+ it {
+ is_expected.to contain_exec('apt_update').with(refreshonly: false,
+ timeout: 1,
+ tries: 3)
+ }
+ end
+
+ context 'with sources defined on valid osfamily' do
+ let :facts do
+ { os: { family: 'Debian', name: 'Ubuntu', release: { major: '12', full: '12.04' } },
+ osfamily: 'Debian',
+ lsbdistcodename: 'precise',
+ lsbdistid: 'Ubuntu',
+ lsbdistrelease: '12.04',
+ puppetversion: Puppet.version }
+ end
+ let(:params) do
+ { sources: {
+ 'debian_unstable' => {
+ 'location' => 'http://debian.mirror.iweb.ca/debian/',
+ 'release' => 'unstable',
+ 'repos' => 'main contrib non-free',
+ 'key' => { 'id' => '150C8614919D8446E01E83AF9AA38DCD55BE302B', 'server' => 'subkeys.pgp.net' },
+ 'pin' => '-10',
+ 'include' => { 'src' => true },
+ },
+ 'puppetlabs' => {
+ 'location' => 'http://apt.puppetlabs.com',
+ 'repos' => 'main',
+ 'key' => { 'id' => '6F6B15509CF8E59E6E469F327F438280EF8D349F', 'server' => 'pgp.mit.edu' },
+ },
+ } }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-debian_unstable').with(ensure: 'present')
+ }
+
+ it { is_expected.to contain_file('/etc/apt/sources.list.d/debian_unstable.list').with_content(%r{^deb http://debian.mirror.iweb.ca/debian/ unstable main contrib non-free$}) }
+ it { is_expected.to contain_file('/etc/apt/sources.list.d/debian_unstable.list').with_content(%r{^deb-src http://debian.mirror.iweb.ca/debian/ unstable main contrib non-free$}) }
+
+ it {
+ is_expected.to contain_apt__setting('list-puppetlabs').with(ensure: 'present')
+ }
+
+ it { is_expected.to contain_file('/etc/apt/sources.list.d/puppetlabs.list').with_content(%r{^deb http://apt.puppetlabs.com precise main$}) }
+ end
+
+ context 'with confs defined on valid osfamily' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Ubuntu', release: { major: '12', full: '12.04.5' } },
+ osfamily: 'Debian',
+ lsbdistcodename: 'precise',
+ lsbdistid: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:params) do
+ { confs: {
+ 'foo' => {
+ 'content' => 'foo',
+ },
+ 'bar' => {
+ 'content' => 'bar',
+ },
+ } }
+ end
+
+ it {
+ is_expected.to contain_apt__conf('foo').with(content: 'foo')
+ }
+
+ it {
+ is_expected.to contain_apt__conf('bar').with(content: 'bar')
+ }
+ end
+
+ context 'with keys defined on valid osfamily' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Ubuntu', release: { major: '12', full: '12.04.5' } },
+ osfamily: 'Debian',
+ lsbdistcodename: 'precise',
+ lsbdistid: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:params) do
+ { keys: {
+ '55BE302B' => {
+ 'server' => 'subkeys.pgp.net',
+ },
+ 'EF8D349F' => {
+ 'server' => 'pgp.mit.edu',
+ },
+ } }
+ end
+
+ it {
+ is_expected.to contain_apt__key('55BE302B').with(server: 'subkeys.pgp.net')
+ }
+
+ it {
+ is_expected.to contain_apt__key('EF8D349F').with(server: 'pgp.mit.edu')
+ }
+ end
+
+ context 'with ppas defined on valid osfamily' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Ubuntu', release: { major: '12', full: '12.04.5' } },
+ osfamily: 'Debian',
+ lsbdistcodename: 'precise',
+ lsbdistid: 'ubuntu',
+ lsbdistrelease: '12.04',
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:params) do
+ { ppas: {
+ 'ppa:drizzle-developers/ppa' => {},
+ 'ppa:nginx/stable' => {},
+ } }
+ end
+
+ it { is_expected.to contain_apt__ppa('ppa:drizzle-developers/ppa') }
+ it { is_expected.to contain_apt__ppa('ppa:nginx/stable') }
+ end
+
+ context 'with settings defined on valid osfamily' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Ubuntu', release: { major: '12', full: '12.04.5' } },
+ osfamily: 'Debian',
+ lsbdistcodename: 'precise',
+ lsbdistid: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:params) do
+ { settings: {
+ 'conf-banana' => { 'content' => 'banana' },
+ 'pref-banana' => { 'content' => 'banana' },
+ } }
+ end
+
+ it { is_expected.to contain_apt__setting('conf-banana') }
+ it { is_expected.to contain_apt__setting('pref-banana') }
+ end
+
+ context 'with pins defined on valid osfamily' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Ubuntu', release: { major: '12', full: '12.04.5' } },
+ osfamily: 'Debian',
+ lsbdistcodename: 'precise',
+ lsbdistid: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:params) do
+ { pins: {
+ 'stable' => { 'priority' => 600, 'order' => 50 },
+ 'testing' => { 'priority' => 700, 'order' => 100 },
+ } }
+ end
+
+ it { is_expected.to contain_apt__pin('stable') }
+ it { is_expected.to contain_apt__pin('testing') }
+ end
+
+ describe 'failing tests' do
+ context "with purge['sources.list']=>'banana'" do
+ let(:params) { { purge: { 'sources.list' => 'banana' } } }
+
+ it do
+ is_expected.to raise_error(Puppet::Error)
+ end
+ end
+
+ context "with purge['sources.list.d']=>'banana'" do
+ let(:params) { { purge: { 'sources.list.d' => 'banana' } } }
+
+ it do
+ is_expected.to raise_error(Puppet::Error)
+ end
+ end
+
+ context "with purge['preferences']=>'banana'" do
+ let(:params) { { purge: { 'preferences' => 'banana' } } }
+
+ it do
+ is_expected.to raise_error(Puppet::Error)
+ end
+ end
+
+ context "with purge['preferences.d']=>'banana'" do
+ let(:params) { { purge: { 'preferences.d' => 'banana' } } }
+
+ it do
+ is_expected.to raise_error(Puppet::Error)
+ end
+ end
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/classes/apt_update_spec.rb b/code/environments/production/modules/apt/spec/classes/apt_update_spec.rb
new file mode 100644
index 0000000..675bbd2
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/classes/apt_update_spec.rb
@@ -0,0 +1,152 @@
+require 'spec_helper'
+
+describe 'apt::update', type: :class do
+ context "when apt::update['frequency']='always'" do
+ {
+ 'a recent run' => Time.now.to_i,
+ 'we are due for a run' => 1_406_660_561,
+ 'the update-success-stamp file does not exist' => -1,
+ }.each_pair do |desc, factval|
+ context "when $::apt_update_last_success indicates #{desc}" do
+ let(:facts) do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ osfamily: 'Debian',
+ apt_update_last_success: factval,
+ lsbdistcodename: 'wheezy',
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:pre_condition) do
+ "class{'::apt': update => {'frequency' => 'always' },}"
+ end
+
+ it 'triggers an apt-get update run' do
+ # set the apt_update exec's refreshonly attribute to false
+ is_expected.to contain_exec('apt_update').with('refreshonly' => false)
+ end
+ end
+ end
+ context 'when $::apt_update_last_success is nil' do
+ let(:facts) do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ osfamily: 'Debian',
+ lsbdistcodename: 'wheezy',
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:pre_condition) { "class{ '::apt': update => {'frequency' => 'always' },}" }
+
+ it 'triggers an apt-get update run' do
+ # set the apt_update exec\'s refreshonly attribute to false
+ is_expected.to contain_exec('apt_update').with('refreshonly' => false)
+ end
+ end
+ end
+ context "when apt::update['frequency']='reluctantly'" do
+ {
+ 'a recent run' => Time.now.to_i,
+ 'we are due for a run' => 1_406_660_561,
+ 'the update-success-stamp file does not exist' => -1,
+ }.each_pair do |desc, factval|
+ context "when $::apt_update_last_success indicates #{desc}" do
+ let(:facts) do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ osfamily: 'Debian',
+ apt_update_last_success: factval,
+ lsbdistcodename: 'wheezy',
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:pre_condition) { "class{ '::apt': update => {'frequency' => 'reluctantly' },}" }
+
+ it 'does not trigger an apt-get update run' do
+ # don't change the apt_update exec's refreshonly attribute. (it should be true)
+ is_expected.to contain_exec('apt_update').with('refreshonly' => true)
+ end
+ end
+ end
+ context 'when $::apt_update_last_success is nil' do
+ let(:facts) do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ osfamily: 'Debian',
+ lsbdistcodename: 'wheezy',
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:pre_condition) { "class{ '::apt': update => {'frequency' => 'reluctantly' },}" }
+
+ it 'does not trigger an apt-get update run' do
+ # don't change the apt_update exec's refreshonly attribute. (it should be true)
+ is_expected.to contain_exec('apt_update').with('refreshonly' => true)
+ end
+ end
+ end
+ %w[daily weekly].each do |update_frequency|
+ context "when apt::update['frequency'] has the value of #{update_frequency}" do
+ { 'we are due for a run' => 1_406_660_561, 'the update-success-stamp file does not exist' => -1 }.each_pair do |desc, factval|
+ context "when $::apt_update_last_success indicates #{desc}" do
+ let(:facts) do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ osfamily: 'Debian',
+ apt_update_last_success: factval,
+ lsbdistcodename: 'wheezy',
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:pre_condition) { "class{ '::apt': update => {'frequency' => '#{update_frequency}',} }" }
+
+ it 'triggers an apt-get update run' do
+ # set the apt_update exec\'s refreshonly attribute to false
+ is_expected.to contain_exec('apt_update').with('refreshonly' => false)
+ end
+ end
+ end
+ context 'when the $::apt_update_last_success fact has a recent value' do
+ let(:facts) do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ osfamily: 'Debian',
+ lsbdistcodename: 'wheezy',
+ apt_update_last_success: Time.now.to_i,
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:pre_condition) { "class{ '::apt': update => {'frequency' => '#{update_frequency}',} }" }
+
+ it 'does not trigger an apt-get update run' do
+ # don't change the apt_update exec\'s refreshonly attribute. (it should be true)
+ is_expected.to contain_exec('apt_update').with('refreshonly' => true)
+ end
+ end
+ context 'when $::apt_update_last_success is nil' do
+ let(:facts) do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ osfamily: 'Debian',
+ lsbdistcodename: 'wheezy',
+ apt_update_last_success: nil,
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:pre_condition) { "class{ '::apt': update => {'frequency' => '#{update_frequency}',} }" }
+
+ it 'triggers an apt-get update run' do
+ # set the apt_update exec\'s refreshonly attribute to false
+ is_expected.to contain_exec('apt_update').with('refreshonly' => false)
+ end
+ end
+ end
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/defines/conf_spec.rb b/code/environments/production/modules/apt/spec/defines/conf_spec.rb
new file mode 100644
index 0000000..d79cb22
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/defines/conf_spec.rb
@@ -0,0 +1,90 @@
+require 'spec_helper'
+describe 'apt::conf', type: :define do
+ let :pre_condition do
+ 'class { "apt": }'
+ end
+ let(:facts) do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ osfamily: 'Debian',
+ lsbdistcodename: 'wheezy',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :title do
+ 'norecommends'
+ end
+
+ describe 'when creating an apt preference' do
+ let :default_params do
+ {
+ priority: '00',
+ content: "Apt::Install-Recommends 0;\nApt::AutoRemove::InstallRecommends 1;\n",
+ }
+ end
+ let :params do
+ default_params
+ end
+
+ let :filename do
+ '/etc/apt/apt.conf.d/00norecommends'
+ end
+
+ it {
+ is_expected.to contain_file(filename).with('ensure' => 'present',
+ 'content' => %r{Apt::Install-Recommends 0;\nApt::AutoRemove::InstallRecommends 1;},
+ 'owner' => 'root',
+ 'group' => 'root',
+ 'mode' => '0644')
+ }
+
+ context 'with notify_update = true (default)' do
+ let :params do
+ default_params
+ end
+
+ it { is_expected.to contain_apt__setting("conf-#{title}").with_notify_update(true) }
+ end
+
+ context 'with notify_update = false' do
+ let :params do
+ default_params.merge(notify_update: false)
+ end
+
+ it { is_expected.to contain_apt__setting("conf-#{title}").with_notify_update(false) }
+ end
+ end
+
+ describe 'when creating a preference without content' do
+ let :params do
+ {
+ priority: '00',
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{pass in content})
+ end
+ end
+
+ describe 'when removing an apt preference' do
+ let :params do
+ {
+ ensure: 'absent',
+ priority: '00',
+ }
+ end
+
+ let :filename do
+ '/etc/apt/apt.conf.d/00norecommends'
+ end
+
+ it {
+ is_expected.to contain_file(filename).with('ensure' => 'absent',
+ 'owner' => 'root',
+ 'group' => 'root',
+ 'mode' => '0644')
+ }
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/defines/key_compat_spec.rb b/code/environments/production/modules/apt/spec/defines/key_compat_spec.rb
new file mode 100644
index 0000000..43ccbbc
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/defines/key_compat_spec.rb
@@ -0,0 +1,360 @@
+require 'spec_helper'
+
+def contains_apt_key_example(title)
+ { id: title,
+ ensure: 'present',
+ source: 'http://apt.puppetlabs.com/pubkey.gpg',
+ server: 'pgp.mit.edu',
+ content: params[:content],
+ options: 'debug' }
+end
+
+def apt_key_example(title)
+ { id: title,
+ ensure: 'present',
+ source: nil,
+ server: 'keyserver.ubuntu.com',
+ content: nil,
+ keyserver_options: nil }
+end
+
+describe 'apt::key', type: :define do
+ GPG_KEY_ID = '6F6B15509CF8E59E6E469F327F438280EF8D349F'.freeze
+
+ let(:facts) do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+
+ let :title do
+ GPG_KEY_ID
+ end
+
+ let :pre_condition do
+ 'include apt'
+ end
+
+ describe 'normal operation' do
+ describe 'default options' do
+ it {
+ is_expected.to contain_apt_key(title).with(id: title,
+ ensure: 'present',
+ source: nil,
+ server: 'keyserver.ubuntu.com',
+ content: nil)
+ }
+ it 'contains the apt_key present anchor' do
+ is_expected.to contain_anchor("apt_key #{title} present")
+ end
+ end
+
+ describe 'title and key =>' do
+ let :title do
+ 'puppetlabs'
+ end
+
+ let :params do
+ {
+ id: GPG_KEY_ID,
+ }
+ end
+
+ it 'contains the apt_key' do
+ is_expected.to contain_apt_key(title).with(id: GPG_KEY_ID,
+ ensure: 'present',
+ source: nil,
+ server: 'keyserver.ubuntu.com',
+ content: nil)
+ end
+ it 'contains the apt_key present anchor' do
+ is_expected.to contain_anchor("apt_key #{GPG_KEY_ID} present")
+ end
+ end
+
+ describe 'ensure => absent' do
+ let :params do
+ {
+ ensure: 'absent',
+ }
+ end
+
+ it 'contains the apt_key' do
+ is_expected.to contain_apt_key(title).with(id: title,
+ ensure: 'absent',
+ source: nil,
+ server: 'keyserver.ubuntu.com',
+ content: nil)
+ end
+ it 'contains the apt_key absent anchor' do
+ is_expected.to contain_anchor("apt_key #{title} absent")
+ end
+ end
+
+ describe 'set a bunch of things!' do
+ let :params do
+ {
+ content: 'GPG key content',
+ source: 'http://apt.puppetlabs.com/pubkey.gpg',
+ server: 'pgp.mit.edu',
+ options: 'debug',
+ }
+ end
+
+ it 'contains the apt_key' do
+ is_expected.to contain_apt_key(title).with(contains_apt_key_example(title))
+ end
+ it 'contains the apt_key present anchor' do
+ is_expected.to contain_anchor("apt_key #{title} present")
+ end
+ end
+
+ context 'when domain has dash' do
+ let(:params) do
+ {
+ server: 'p-gp.m-it.edu',
+ }
+ end
+
+ it 'contains the apt_key' do
+ is_expected.to contain_apt_key(title).with(id: title,
+ server: 'p-gp.m-it.edu')
+ end
+ end
+
+ context 'with url' do
+ let :params do
+ {
+ server: 'hkp://pgp.mit.edu',
+ }
+ end
+
+ it 'contains the apt_key' do
+ is_expected.to contain_apt_key(title).with(id: title,
+ server: 'hkp://pgp.mit.edu')
+ end
+ end
+ context 'with url and port number' do
+ let :params do
+ {
+ server: 'hkp://pgp.mit.edu:80',
+ }
+ end
+
+ it 'contains the apt_key' do
+ is_expected.to contain_apt_key(title).with(id: title,
+ server: 'hkp://pgp.mit.edu:80')
+ end
+ end
+ end
+
+ describe 'validation' do
+ context 'when domain begins with a dash' do
+ let(:params) do
+ {
+ server: '-pgp.mit.edu',
+ }
+ end
+
+ it 'fails' do
+ is_expected .to raise_error(%r{expects a match})
+ end
+ end
+
+ context 'when domain begins with dot' do
+ let(:params) do
+ {
+ server: '.pgp.mit.edu',
+ }
+ end
+
+ it 'fails' do
+ is_expected .to raise_error(%r{expects a match})
+ end
+ end
+
+ context 'when domain ends with dot' do
+ let(:params) do
+ {
+ server: 'pgp.mit.edu.',
+ }
+ end
+
+ it 'fails' do
+ is_expected .to raise_error(%r{expects a match})
+ end
+ end
+ context 'when url character limit is exceeded' do
+ let :params do
+ {
+ server: 'hkp://pgpiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii.mit.edu',
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a match})
+ end
+ end
+ context 'with incorrect port number url' do
+ let :params do
+ {
+ server: 'hkp://pgp.mit.edu:8008080',
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a match})
+ end
+ end
+ context 'with incorrect protocol for url' do
+ let :params do
+ {
+ server: 'abc://pgp.mit.edu:80',
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a match})
+ end
+ end
+ context 'with missing port number url' do
+ let :params do
+ {
+ server: 'hkp://pgp.mit.edu:',
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a match})
+ end
+ end
+ context 'with url ending with a dot' do
+ let :params do
+ {
+ server: 'hkp://pgp.mit.edu.',
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a match})
+ end
+ end
+ context 'with url begin with a dash' do
+ let(:params) do
+ {
+ server: 'hkp://-pgp.mit.edu',
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a match})
+ end
+ end
+ context 'with invalid key' do
+ let :title do
+ 'Out of rum. Why? Why are we out of rum?'
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a match})
+ end
+ end
+
+ context 'with invalid source' do
+ let :params do
+ {
+ source: 'afp://puppetlabs.com/key.gpg',
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a match})
+ end
+ end
+
+ context 'with invalid content' do
+ let :params do
+ {
+ content: [],
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a})
+ end
+ end
+
+ context 'with invalid server' do
+ let :params do
+ {
+ server: 'two bottles of rum',
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a match})
+ end
+ end
+
+ context 'with invalid keyserver_options' do
+ let :params do
+ {
+ options: {},
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a})
+ end
+ end
+
+ context 'with invalid ensure' do
+ let :params do
+ {
+ ensure: 'foo',
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{Enum\['absent', 'present'\]})
+ end
+ end
+
+ describe 'duplication - two apt::key resources for same key, different titles' do
+ let :pre_condition do
+ "#{super()}\napt::key { 'duplicate': id => '#{title}', }"
+ end
+
+ it 'contains the duplicate apt::key resource' do
+ is_expected.to contain_apt__key('duplicate').with(id: title,
+ ensure: 'present')
+ end
+
+ it 'contains the original apt::key resource' do
+ is_expected.to contain_apt__key(title).with(id: title,
+ ensure: 'present')
+ end
+
+ it 'contains the native apt_key' do
+ is_expected.to contain_apt_key('duplicate').with(apt_key_example(title))
+ end
+
+ it 'does not contain the original apt_key' do
+ is_expected.not_to contain_apt_key(title)
+ end
+ end
+
+ describe 'duplication - two apt::key resources, different ensure' do
+ let :pre_condition do
+ "#{super()}\napt::key { 'duplicate': id => '#{title}', ensure => 'absent', }"
+ end
+
+ it 'informs the user of the impossibility' do
+ is_expected.to raise_error(%r{already ensured as absent})
+ end
+ end
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/defines/key_spec.rb b/code/environments/production/modules/apt/spec/defines/key_spec.rb
new file mode 100644
index 0000000..6a5a89f
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/defines/key_spec.rb
@@ -0,0 +1,367 @@
+require 'spec_helper'
+
+GPG_KEY_ID = '6F6B15509CF8E59E6E469F327F438280EF8D349F'.freeze
+
+title_key_example = { id: GPG_KEY_ID,
+ ensure: 'present',
+ source: nil,
+ server: 'keyserver.ubuntu.com',
+ content: nil,
+ options: nil }
+
+def default_apt_key_example(title)
+ { id: title,
+ ensure: 'present',
+ source: nil,
+ server: 'keyserver.ubuntu.com',
+ content: nil,
+ options: nil }
+end
+
+def bunch_things_apt_key_example(title, params)
+ { id: title,
+ ensure: 'present',
+ source: 'http://apt.puppetlabs.com/pubkey.gpg',
+ server: 'pgp.mit.edu',
+ content: params[:content],
+ options: 'debug' }
+end
+
+def absent_apt_key(title)
+ { id: title,
+ ensure: 'absent',
+ source: nil,
+ server: 'keyserver.ubuntu.com',
+ content: nil,
+ keyserver: nil }
+end
+
+describe 'apt::key' do
+ let :pre_condition do
+ 'class { "apt": }'
+ end
+
+ let(:facts) do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ osfamily: 'Debian',
+ lsbdistcodename: 'wheezy',
+ puppetversion: Puppet.version,
+ }
+ end
+
+ let :title do
+ GPG_KEY_ID
+ end
+
+ describe 'normal operation' do
+ describe 'default options' do
+ it 'contains the apt_key' do
+ is_expected.to contain_apt_key(title).with(default_apt_key_example(title))
+ end
+ it 'contains the apt_key present anchor' do
+ is_expected.to contain_anchor("apt_key #{title} present")
+ end
+ end
+
+ describe 'title and key =>' do
+ let :title do
+ 'puppetlabs'
+ end
+
+ let :params do
+ {
+ id: GPG_KEY_ID,
+ }
+ end
+
+ it 'contains the apt_key' do
+ is_expected.to contain_apt_key(title).with(title_key_example)
+ end
+ it 'contains the apt_key present anchor' do
+ is_expected.to contain_anchor("apt_key #{GPG_KEY_ID} present")
+ end
+ end
+
+ describe 'ensure => absent' do
+ let :params do
+ {
+ ensure: 'absent',
+ }
+ end
+
+ it 'contains the apt_key' do
+ is_expected.to contain_apt_key(title).with(absent_apt_key(title))
+ end
+ it 'contains the apt_key absent anchor' do
+ is_expected.to contain_anchor("apt_key #{title} absent")
+ end
+ end
+
+ describe 'set a bunch of things!' do
+ let :params do
+ {
+ content: 'GPG key content',
+ source: 'http://apt.puppetlabs.com/pubkey.gpg',
+ server: 'pgp.mit.edu',
+ options: 'debug',
+ }
+ end
+
+ it 'contains the apt_key' do
+ is_expected.to contain_apt_key(title).with(bunch_things_apt_key_example(title, params))
+ end
+ it 'contains the apt_key present anchor' do
+ is_expected.to contain_anchor("apt_key #{title} present")
+ end
+ end
+
+ context 'when domain with dash' do
+ let(:params) do
+ {
+ server: 'p-gp.m-it.edu',
+ }
+ end
+
+ it 'contains the apt_key' do
+ is_expected.to contain_apt_key(title).with(id: title,
+ server: 'p-gp.m-it.edu')
+ end
+ end
+
+ context 'with url' do
+ let :params do
+ {
+ server: 'hkp://pgp.mit.edu',
+ }
+ end
+
+ it 'contains the apt_key' do
+ is_expected.to contain_apt_key(title).with(id: title,
+ server: 'hkp://pgp.mit.edu')
+ end
+ end
+ context 'when url with port number' do
+ let :params do
+ {
+ server: 'hkp://pgp.mit.edu:80',
+ }
+ end
+
+ it 'contains the apt_key' do
+ is_expected.to contain_apt_key(title).with(id: title,
+ server: 'hkp://pgp.mit.edu:80')
+ end
+ end
+ end
+
+ describe 'validation' do
+ context 'when domain begin with dash' do
+ let(:params) do
+ {
+ server: '-pgp.mit.edu',
+ }
+ end
+
+ it 'fails' do
+ is_expected .to raise_error(%r{expects a match})
+ end
+ end
+
+ context 'when domain begin with dot' do
+ let(:params) do
+ {
+ server: '.pgp.mit.edu',
+ }
+ end
+
+ it 'fails' do
+ is_expected .to raise_error(%r{expects a match})
+ end
+ end
+
+ context 'when domain end with dot' do
+ let(:params) do
+ {
+ server: 'pgp.mit.edu.',
+ }
+ end
+
+ it 'fails' do
+ is_expected .to raise_error(%r{expects a match})
+ end
+ end
+ context 'when character url exceeded' do
+ let :params do
+ {
+ server: 'hkp://pgpiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii.mit.edu',
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a match})
+ end
+ end
+ context 'with incorrect port number url' do
+ let :params do
+ {
+ server: 'hkp://pgp.mit.edu:8008080',
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a match})
+ end
+ end
+ context 'with incorrect protocol for url' do
+ let :params do
+ {
+ server: 'abc://pgp.mit.edu:80',
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a match})
+ end
+ end
+ context 'with missing port number url' do
+ let :params do
+ {
+ server: 'hkp://pgp.mit.edu:',
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a match})
+ end
+ end
+ context 'with url ending with a dot' do
+ let :params do
+ {
+ server: 'hkp://pgp.mit.edu.',
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a match})
+ end
+ end
+ context 'when url begins with a dash' do
+ let(:params) do
+ {
+ server: 'hkp://-pgp.mit.edu',
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a match})
+ end
+ end
+ context 'with invalid key' do
+ let :title do
+ 'Out of rum. Why? Why are we out of rum?'
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a match})
+ end
+ end
+
+ context 'with invalid source' do
+ let :params do
+ {
+ source: 'afp://puppetlabs.com/key.gpg',
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a match})
+ end
+ end
+
+ context 'with invalid content' do
+ let :params do
+ {
+ content: [],
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a})
+ end
+ end
+
+ context 'with invalid server' do
+ let :params do
+ {
+ server: 'two bottles of rum',
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a match})
+ end
+ end
+
+ context 'with invalid options' do
+ let :params do
+ {
+ options: {},
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{expects a})
+ end
+ end
+
+ context 'with invalid ensure' do
+ %w[foo aabsent absenta apresent presenta].each do |param|
+ let :params do
+ {
+ ensure: param,
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{for Enum\['absent', 'present'\], got})
+ end
+ end
+ end
+
+ describe 'duplication - two apt::key resources for same key, different titles' do
+ let :pre_condition do
+ "class { 'apt': }
+ apt::key { 'duplicate': id => '#{title}', }"
+ end
+
+ it 'contains two apt::key resource - duplicate' do
+ is_expected.to contain_apt__key('duplicate').with(id: title,
+ ensure: 'present')
+ end
+ it 'contains two apt::key resource - title' do
+ is_expected.to contain_apt__key(title).with(id: title,
+ ensure: 'present')
+ end
+
+ it 'contains only a single apt_key - duplicate' do
+ is_expected.to contain_apt_key('duplicate').with(default_apt_key_example(title))
+ end
+ it 'contains only a single apt_key - no title' do
+ is_expected.not_to contain_apt_key(title)
+ end
+ end
+
+ describe 'duplication - two apt::key resources, different ensure' do
+ let :pre_condition do
+ "class { 'apt': }
+ apt::key { 'duplicate': id => '#{title}', ensure => 'absent', }"
+ end
+
+ it 'informs the user of the impossibility' do
+ is_expected.to raise_error(%r{already ensured as absent})
+ end
+ end
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/defines/pin_spec.rb b/code/environments/production/modules/apt/spec/defines/pin_spec.rb
new file mode 100644
index 0000000..2329e9a
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/defines/pin_spec.rb
@@ -0,0 +1,148 @@
+require 'spec_helper'
+describe 'apt::pin', type: :define do
+ let :pre_condition do
+ 'class { "apt": }'
+ end
+ let(:facts) do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ osfamily: 'Debian',
+ lsbdistcodename: 'wheezy',
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:title) { 'my_pin' }
+
+ context 'with defaults' do
+ it { is_expected.to contain_apt__setting('pref-my_pin').with_content(%r{Explanation: : my_pin\nPackage: \*\nPin: release a=my_pin\nPin-Priority: 0\n}) }
+ end
+
+ context 'with set version' do
+ let :params do
+ {
+ 'packages' => 'vim',
+ 'version' => '1',
+ }
+ end
+
+ it { is_expected.to contain_apt__setting('pref-my_pin').with_content(%r{Explanation: : my_pin\nPackage: vim\nPin: version 1\nPin-Priority: 0\n}) }
+ end
+
+ context 'with set origin' do
+ let :params do
+ {
+ 'packages' => 'vim',
+ 'origin' => 'test',
+ }
+ end
+
+ it { is_expected.to contain_apt__setting('pref-my_pin').with_content(%r{Explanation: : my_pin\nPackage: vim\nPin: origin test\nPin-Priority: 0\n}) }
+ end
+
+ context 'without defaults' do
+ let :params do
+ {
+ 'explanation' => 'foo',
+ 'order' => 99,
+ 'release' => '1',
+ 'codename' => 'bar',
+ 'release_version' => '2',
+ 'component' => 'baz',
+ 'originator' => 'foobar',
+ 'label' => 'foobaz',
+ 'priority' => 10,
+ }
+ end
+
+ it { is_expected.to contain_apt__setting('pref-my_pin').with_content(%r{Explanation: foo\nPackage: \*\nPin: release a=1, n=bar, v=2, c=baz, o=foobar, l=foobaz\nPin-Priority: 10\n}) }
+ it {
+ is_expected.to contain_apt__setting('pref-my_pin').with('priority' => 99)
+ }
+ end
+
+ context 'with ensure absent' do
+ let :params do
+ {
+ 'ensure' => 'absent',
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('pref-my_pin').with('ensure' => 'absent')
+ }
+ end
+
+ context 'with bad characters' do
+ let(:title) { 'such bad && wow!' }
+
+ it { is_expected.to contain_apt__setting('pref-such__bad____wow_') }
+ end
+
+ describe 'validation' do
+ context 'with invalid order' do
+ let :params do
+ {
+ 'order' => 'foo',
+ }
+ end
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{expects an Integer value, got String})
+ end
+ end
+
+ context 'with packages == * and version' do
+ let :params do
+ {
+ 'version' => '1',
+ }
+ end
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{parameter version cannot be used in general form})
+ end
+ end
+
+ context 'with packages == * and release and origin' do
+ let :params do
+ {
+ 'origin' => 'test',
+ 'release' => 'foo',
+ }
+ end
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{parameters release and origin are mutually exclusive})
+ end
+ end
+
+ context 'with specific release and origin' do
+ let :params do
+ {
+ 'release' => 'foo',
+ 'origin' => 'test',
+ 'packages' => 'vim',
+ }
+ end
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{parameters release, origin, and version are mutually exclusive})
+ end
+ end
+
+ context 'with specific version and origin' do
+ let :params do
+ {
+ 'version' => '1',
+ 'origin' => 'test',
+ 'packages' => 'vim',
+ }
+ end
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{parameters release, origin, and version are mutually exclusive})
+ end
+ end
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/defines/ppa_spec.rb b/code/environments/production/modules/apt/spec/defines/ppa_spec.rb
new file mode 100644
index 0000000..b534186
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/defines/ppa_spec.rb
@@ -0,0 +1,379 @@
+require 'spec_helper'
+describe 'apt::ppa' do
+ let :pre_condition do
+ 'class { "apt": }'
+ end
+
+ describe 'defaults' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Ubuntu', release: { major: '11', full: '11.04' } },
+ lsbdistrelease: '11.04',
+ lsbdistcodename: 'natty',
+ operatingsystem: 'Ubuntu',
+ osfamily: 'Debian',
+ lsbdistid: 'Ubuntu',
+ puppetversion: Puppet.version,
+ }
+ end
+
+ let(:title) { 'ppa:needs/such.substitution/wow+type' }
+
+ it { is_expected.not_to contain_package('python-software-properties') }
+ it {
+ is_expected.to contain_exec('add-apt-repository-ppa:needs/such.substitution/wow+type').that_notifies('Class[Apt::Update]').with(environment: [],
+ command: '/usr/bin/add-apt-repository -y ppa:needs/such.substitution/wow+type', # rubocop:disable Metrics/LineLength
+ unless: '/usr/bin/test -f /etc/apt/sources.list.d/needs-such_substitution-wow_type-natty.list', # rubocop:disable Metrics/LineLength
+ user: 'root',
+ logoutput: 'on_failure')
+ }
+ end
+
+ describe 'Ubuntu 15.10 sources.list filename' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Ubuntu', release: { major: '15', full: '15.10' } },
+ lsbdistrelease: '15.10',
+ lsbdistcodename: 'wily',
+ operatingsystem: 'Ubuntu',
+ osfamily: 'Debian',
+ lsbdistid: 'Ubuntu',
+ puppetversion: Puppet.version,
+ }
+ end
+
+ let(:title) { 'ppa:user/foo' }
+
+ it {
+ is_expected.to contain_exec('add-apt-repository-ppa:user/foo').that_notifies('Class[Apt::Update]').with(environment: [],
+ command: '/usr/bin/add-apt-repository -y ppa:user/foo',
+ unless: '/usr/bin/test -f /etc/apt/sources.list.d/user-ubuntu-foo-wily.list',
+ user: 'root',
+ logoutput: 'on_failure')
+ }
+ end
+
+ describe 'package_name => software-properties-common' do
+ let :pre_condition do
+ 'class { "apt": }'
+ end
+ let :params do
+ {
+ package_name: 'software-properties-common',
+ package_manage: true,
+ }
+ end
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Ubuntu', release: { major: '11', full: '11.04' } },
+ lsbdistrelease: '11.04',
+ lsbdistcodename: 'natty',
+ operatingsystem: 'Ubuntu',
+ osfamily: 'Debian',
+ lsbdistid: 'Ubuntu',
+ puppetversion: Puppet.version,
+ }
+ end
+
+ let(:title) { 'ppa:needs/such.substitution/wow' }
+
+ it { is_expected.to contain_package('software-properties-common') }
+ it {
+ is_expected.to contain_exec('add-apt-repository-ppa:needs/such.substitution/wow').that_notifies('Class[Apt::Update]').with('environment' => [],
+ 'command' => '/usr/bin/add-apt-repository -y ppa:needs/such.substitution/wow', # rubocop:disable Metrics/LineLength
+ 'unless' => '/usr/bin/test -f /etc/apt/sources.list.d/needs-such_substitution-wow-natty.list', # rubocop:disable Metrics/LineLength
+ 'user' => 'root',
+ 'logoutput' => 'on_failure')
+ }
+
+ it {
+ is_expected.to contain_file('/etc/apt/sources.list.d/needs-such_substitution-wow-natty.list').that_requires('Exec[add-apt-repository-ppa:needs/such.substitution/wow]').with('ensure' => 'file')
+ }
+ end
+
+ describe 'package_manage => true, multiple ppas, MODULES-2873' do
+ let :pre_condition do
+ 'class { "apt": }
+ apt::ppa {"ppa:user/foo":
+ package_manage => true
+ }'
+ end
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Ubuntu', release: { major: '11', full: '11.04' } },
+ lsbdistrelease: '11.04',
+ lsbdistcodename: 'natty',
+ operatingsystem: 'Ubuntu',
+ osfamily: 'Debian',
+ lsbdistid: 'Ubuntu',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ package_manage: true,
+ }
+ end
+
+ let(:title) { 'ppa:user/bar' }
+
+ it { is_expected.to contain_package('python-software-properties') }
+ it {
+ is_expected.to contain_exec('add-apt-repository-ppa:user/bar').that_notifies('Class[Apt::Update]').with('environment' => [],
+ 'command' => '/usr/bin/add-apt-repository -y ppa:user/bar',
+ 'unless' => '/usr/bin/test -f /etc/apt/sources.list.d/user-bar-natty.list',
+ 'user' => 'root',
+ 'logoutput' => 'on_failure')
+ }
+
+ it {
+ is_expected.to contain_file('/etc/apt/sources.list.d/user-bar-natty.list').that_requires('Exec[add-apt-repository-ppa:user/bar]').with('ensure' => 'file')
+ }
+ end
+
+ describe 'package_manage => false' do
+ let :pre_condition do
+ 'class { "apt": }'
+ end
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Ubuntu', release: { major: '11', full: '11.04' } },
+ lsbdistrelease: '11.04',
+ lsbdistcodename: 'natty',
+ operatingsystem: 'Ubuntu',
+ osfamily: 'Debian',
+ lsbdistid: 'Ubuntu',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ package_manage: false,
+ }
+ end
+
+ let(:title) { 'ppa:needs/such.substitution/wow' }
+
+ it { is_expected.not_to contain_package('python-software-properties') }
+ it {
+ is_expected.to contain_exec('add-apt-repository-ppa:needs/such.substitution/wow').that_notifies('Class[Apt::Update]').with('environment' => [],
+ 'command' => '/usr/bin/add-apt-repository -y ppa:needs/such.substitution/wow', # rubocop:disable Metrics/LineLength
+ 'unless' => '/usr/bin/test -f /etc/apt/sources.list.d/needs-such_substitution-wow-natty.list', # rubocop:disable Metrics/LineLength
+ 'user' => 'root',
+ 'logoutput' => 'on_failure')
+ }
+
+ it {
+ is_expected.to contain_file('/etc/apt/sources.list.d/needs-such_substitution-wow-natty.list').that_requires('Exec[add-apt-repository-ppa:needs/such.substitution/wow]').with('ensure' => 'file')
+ }
+ end
+
+ describe 'apt included, no proxy' do
+ let :pre_condition do
+ 'class { "apt": }
+ apt::ppa { "ppa:user/foo2": }
+ '
+ end
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Ubuntu', release: { major: '14', full: '14.04' } },
+ lsbdistrelease: '14.04',
+ lsbdistcodename: 'trusty',
+ operatingsystem: 'Ubuntu',
+ lsbdistid: 'Ubuntu',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ options: '',
+ package_manage: true,
+ require: 'Apt::Ppa[ppa:user/foo2]',
+ }
+ end
+ let(:title) { 'ppa:user/foo' }
+
+ it { is_expected.to compile.with_all_deps }
+ it { is_expected.to contain_package('software-properties-common') }
+ it {
+ is_expected.to contain_exec('add-apt-repository-ppa:user/foo').that_notifies('Class[Apt::Update]').with(environment: [],
+ command: '/usr/bin/add-apt-repository ppa:user/foo',
+ unless: '/usr/bin/test -f /etc/apt/sources.list.d/user-foo-trusty.list',
+ user: 'root',
+ logoutput: 'on_failure')
+ }
+ end
+
+ describe 'apt included, proxy host' do
+ let :pre_condition do
+ 'class { "apt":
+ proxy => { "host" => "localhost" },
+ }'
+ end
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Ubuntu', release: { major: '14', full: '14.04' } },
+ lsbdistrelease: '14.04',
+ lsbdistcodename: 'trusty',
+ operatingsystem: 'Ubuntu',
+ lsbdistid: 'Ubuntu',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ 'options' => '',
+ 'package_manage' => true,
+ }
+ end
+ let(:title) { 'ppa:user/foo' }
+
+ it { is_expected.to contain_package('software-properties-common') }
+ it {
+ is_expected.to contain_exec('add-apt-repository-ppa:user/foo').that_notifies('Class[Apt::Update]').with(environment: ['http_proxy=http://localhost:8080'],
+ command: '/usr/bin/add-apt-repository ppa:user/foo',
+ unless: '/usr/bin/test -f /etc/apt/sources.list.d/user-foo-trusty.list',
+ user: 'root',
+ logoutput: 'on_failure')
+ }
+ end
+
+ describe 'apt included, proxy host and port' do
+ let :pre_condition do
+ 'class { "apt":
+ proxy => { "host" => "localhost", "port" => 8180 },
+ }'
+ end
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Ubuntu', release: { major: '14', full: '14.04' } },
+ lsbdistrelease: '14.04',
+ lsbdistcodename: 'trusty',
+ operatingsystem: 'Ubuntu',
+ lsbdistid: 'Ubuntu',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ options: '',
+ package_manage: true,
+ }
+ end
+ let(:title) { 'ppa:user/foo' }
+
+ it { is_expected.to contain_package('software-properties-common') }
+ it {
+ is_expected.to contain_exec('add-apt-repository-ppa:user/foo').that_notifies('Class[Apt::Update]').with(environment: ['http_proxy=http://localhost:8180'],
+ command: '/usr/bin/add-apt-repository ppa:user/foo',
+ unless: '/usr/bin/test -f /etc/apt/sources.list.d/user-foo-trusty.list',
+ user: 'root',
+ logoutput: 'on_failure')
+ }
+ end
+
+ describe 'apt included, proxy host and port and https' do
+ let :pre_condition do
+ 'class { "apt":
+ proxy => { "host" => "localhost", "port" => 8180, "https" => true },
+ }'
+ end
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Ubuntu', release: { major: '14', full: '14.04' } },
+ lsbdistrelease: '14.04',
+ lsbdistcodename: 'trusty',
+ operatingsystem: 'Ubuntu',
+ lsbdistid: 'Ubuntu',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ options: '',
+ package_manage: true,
+ }
+ end
+ let(:title) { 'ppa:user/foo' }
+
+ it { is_expected.to contain_package('software-properties-common') }
+ it {
+ is_expected.to contain_exec('add-apt-repository-ppa:user/foo').that_notifies('Class[Apt::Update]').with(environment: ['http_proxy=http://localhost:8180', 'https_proxy=https://localhost:8180'],
+ command: '/usr/bin/add-apt-repository ppa:user/foo',
+ unless: '/usr/bin/test -f /etc/apt/sources.list.d/user-foo-trusty.list',
+ user: 'root',
+ logoutput: 'on_failure')
+ }
+ end
+
+ describe 'ensure absent' do
+ let :pre_condition do
+ 'class { "apt": }'
+ end
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Ubuntu', release: { major: '14', full: '14.04' } },
+ lsbdistrelease: '14.04',
+ lsbdistcodename: 'trusty',
+ operatingsystem: 'Ubuntu',
+ lsbdistid: 'Ubuntu',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:title) { 'ppa:user/foo' }
+ let :params do
+ {
+ ensure: 'absent',
+ }
+ end
+
+ it {
+ is_expected.to contain_file('/etc/apt/sources.list.d/user-foo-trusty.list').that_notifies('Class[Apt::Update]').with(ensure: 'absent')
+ }
+ end
+
+ context 'with validation' do
+ describe 'no release' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Ubuntu', release: { major: '14', full: '14.04' } },
+ lsbdistrelease: '14.04',
+ operatingsystem: 'Ubuntu',
+ lsbdistid: 'Ubuntu',
+ osfamily: 'Debian',
+ lsbdistcodeanme: nil,
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:title) { 'ppa:user/foo' }
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{lsbdistcodename fact not available: release parameter required})
+ end
+ end
+
+ describe 'not ubuntu' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '6', full: '6.0.7' } },
+ lsbdistrelease: '6.0.7',
+ lsbdistcodename: 'wheezy',
+ operatingsystem: 'Debian',
+ lsbdistid: 'debian',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:title) { 'ppa:user/foo' }
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{not currently supported on Debian})
+ end
+ end
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/defines/setting_spec.rb b/code/environments/production/modules/apt/spec/defines/setting_spec.rb
new file mode 100644
index 0000000..1a94de7
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/defines/setting_spec.rb
@@ -0,0 +1,145 @@
+require 'spec_helper'
+
+describe 'apt::setting' do
+ let(:pre_condition) { 'class { "apt": }' }
+ let :facts do
+ {
+ os: { distro: { codename: 'wheezy' }, family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistrelease: '7.0',
+ lsbdistcodename: 'wheezy',
+ operatingsystem: 'Debian',
+ osfamily: 'Debian',
+ lsbdistid: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:title) { 'conf-teddybear' }
+
+ let(:default_params) { { content: 'di' } }
+
+ describe 'when using the defaults' do
+ context 'without source or content' do
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{needs either of })
+ end
+ end
+
+ context 'with title=conf-teddybear ' do
+ let(:params) { default_params }
+
+ it { is_expected.to contain_file('/etc/apt/apt.conf.d/50teddybear').that_notifies('Class[Apt::Update]') }
+ end
+
+ context 'with title=pref-teddybear' do
+ let(:title) { 'pref-teddybear' }
+ let(:params) { default_params }
+
+ it { is_expected.to contain_file('/etc/apt/preferences.d/teddybear.pref').that_notifies('Class[Apt::Update]') }
+ end
+
+ context 'with title=list-teddybear' do
+ let(:title) { 'list-teddybear' }
+ let(:params) { default_params }
+
+ it { is_expected.to contain_file('/etc/apt/sources.list.d/teddybear.list').that_notifies('Class[Apt::Update]') }
+ end
+
+ context 'with source' do
+ let(:params) { { source: 'puppet:///la/die/dah' } }
+
+ it {
+ is_expected.to contain_file('/etc/apt/apt.conf.d/50teddybear').that_notifies('Class[Apt::Update]').with(ensure: 'file',
+ owner: 'root',
+ group: 'root',
+ mode: '0644',
+ source: params[:source].to_s)
+ }
+ end
+
+ context 'with content' do
+ let(:params) { default_params }
+
+ it {
+ is_expected.to contain_file('/etc/apt/apt.conf.d/50teddybear').that_notifies('Class[Apt::Update]').with(ensure: 'file',
+ owner: 'root',
+ group: 'root',
+ mode: '0644',
+ content: params[:content].to_s)
+ }
+ end
+ end
+
+ describe 'settings requiring settings, MODULES-769' do
+ let(:pre_condition) do
+ 'class { "apt": }
+ apt::setting { "list-teddybear": content => "foo" }
+ '
+ end
+ let(:facts) do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ osfamily: 'Debian',
+ lsbdistcodename: 'wheezy',
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:title) { 'conf-teddybear' }
+ let(:default_params) { { content: 'di' } }
+
+ let(:params) { default_params.merge(require: 'Apt::Setting[list-teddybear]') }
+
+ it { is_expected.to compile.with_all_deps }
+ end
+
+ describe 'when trying to pull one over' do
+ context 'with source and content' do
+ let(:params) { default_params.merge(source: 'la') }
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{cannot have both })
+ end
+ end
+
+ context 'with title=ext-teddybear' do
+ let(:title) { 'ext-teddybear' }
+ let(:params) { default_params }
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{must start with either})
+ end
+ end
+
+ context 'with ensure=banana' do
+ let(:params) { default_params.merge(ensure: 'banana') }
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{Enum\['absent', 'file', 'present'\]})
+ end
+ end
+
+ context 'with priority=1.2' do
+ let(:params) { default_params.merge(priority: 1.2) }
+
+ if Puppet::Util::Package.versioncmp(Puppet.version, '4.0') >= 0 || ENV['FUTURE_PARSER'] == 'yes'
+ it { is_expected.to compile.and_raise_error(%r{expects a value of type}) }
+ else
+ it { is_expected.to compile.and_raise_error(%r{priority must be an integer or a zero-padded integer}) }
+ end
+ end
+ end
+
+ describe 'with priority=100' do
+ let(:params) { default_params.merge(priority: 100) }
+
+ it { is_expected.to contain_file('/etc/apt/apt.conf.d/100teddybear').that_notifies('Class[Apt::Update]') }
+ end
+
+ describe 'with ensure=absent' do
+ let(:params) { default_params.merge(ensure: 'absent') }
+
+ it {
+ is_expected.to contain_file('/etc/apt/apt.conf.d/50teddybear').that_notifies('Class[Apt::Update]').with(ensure: 'absent')
+ }
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/defines/source_compat_spec.rb b/code/environments/production/modules/apt/spec/defines/source_compat_spec.rb
new file mode 100644
index 0000000..f89f4be
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/defines/source_compat_spec.rb
@@ -0,0 +1,154 @@
+require 'spec_helper'
+
+describe 'apt::source', type: :define do
+ GPG_KEY_ID = '6F6B15509CF8E59E6E469F327F438280EF8D349F'.freeze
+
+ let :title do
+ 'my_source'
+ end
+
+ context 'with mostly defaults' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ lsbdistcodename: 'wheezy',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+
+ let :params do
+ {
+ 'include' => { 'deb' => false, 'src' => true },
+ 'location' => 'http://debian.mirror.iweb.ca/debian/',
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source').with_content(%r{# my_source\ndeb-src http://debian.mirror.iweb.ca/debian/ wheezy main\n})
+ }
+ end
+
+ context 'with no defaults' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ lsbdistcodename: 'wheezy',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ 'comment' => 'foo',
+ 'location' => 'http://debian.mirror.iweb.ca/debian/',
+ 'release' => 'sid',
+ 'repos' => 'testing',
+ 'include' => { 'src' => false },
+ 'key' => GPG_KEY_ID,
+ 'pin' => '10',
+ 'architecture' => 'x86_64',
+ 'allow_unsigned' => true,
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source').with_content(%r{# foo\ndeb \[arch=x86_64 trusted=yes\] http://debian.mirror.iweb.ca/debian/ sid testing\n})
+ .without_content(%r{deb-src})
+ }
+
+ it {
+ is_expected.to contain_apt__pin('my_source').that_comes_before('Apt::Setting[list-my_source]').with('ensure' => 'present',
+ 'priority' => '10',
+ 'origin' => 'debian.mirror.iweb.ca')
+ }
+
+ it {
+ is_expected.to contain_apt__key("Add key: #{GPG_KEY_ID} from Apt::Source my_source").that_comes_before('Apt::Setting[list-my_source]').with('ensure' => 'present',
+ 'id' => GPG_KEY_ID)
+ }
+ end
+
+ context 'when allow_unsigned true' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ lsbdistcodename: 'wheezy',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ 'include' => { 'src' => false },
+ 'location' => 'http://debian.mirror.iweb.ca/debian/',
+ 'allow_unsigned' => true,
+ }
+ end
+
+ it { is_expected.to contain_apt__setting('list-my_source').with_content(%r{# my_source\ndeb \[trusted=yes\] http://debian.mirror.iweb.ca/debian/ wheezy main\n}) }
+ end
+
+ context 'with architecture equals x86_64' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ lsbdistcodename: 'wheezy',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ 'location' => 'http://debian.mirror.iweb.ca/debian/',
+ 'architecture' => 'x86_64',
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source').with_content(%r{# my_source\ndeb \[arch=x86_64\] http://debian.mirror.iweb.ca/debian/ wheezy main\n})
+ }
+ end
+
+ context 'with ensure => absent' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ lsbdistcodename: 'wheezy',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ 'ensure' => 'absent',
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source').with('ensure' => 'absent')
+ }
+ end
+
+ describe 'validation' do
+ context 'with no release' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{lsbdistcodename fact not available: release parameter required})
+ end
+ end
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/defines/source_spec.rb b/code/environments/production/modules/apt/spec/defines/source_spec.rb
new file mode 100644
index 0000000..a9077e9
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/defines/source_spec.rb
@@ -0,0 +1,452 @@
+require 'spec_helper'
+
+describe 'apt::source' do
+ GPG_KEY_ID = '6F6B15509CF8E59E6E469F327F438280EF8D349F'.freeze
+
+ let :pre_condition do
+ 'class { "apt": }'
+ end
+
+ let :title do
+ 'my_source'
+ end
+
+ context 'with defaults' do
+ context 'without location' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ osfamily: 'Debian',
+ lsbdistcodename: 'wheezy',
+ puppetversion: Puppet.version,
+ }
+ end
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{source entry without specifying a location})
+ end
+ end
+ context 'with location' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ lsbdistcodename: 'wheezy',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:params) { { location: 'hello.there' } }
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source').with(ensure: 'present').without_content(%r{# my_source\ndeb-src hello.there wheezy main\n})
+ }
+ end
+ end
+
+ describe 'no defaults' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ lsbdistcodename: 'wheezy',
+ osfamily: 'Debian',
+ operatingsystem: 'Debian',
+ lsbdistrelease: '7.0',
+ puppetversion: Puppet.version,
+ }
+ end
+
+ context 'with complex pin' do
+ let :params do
+ {
+ location: 'hello.there',
+ pin: { 'release' => 'wishwash',
+ 'explanation' => 'wishwash',
+ 'priority' => 1001 },
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source').with(ensure: 'present').with_content(%r{hello.there wheezy main\n})
+ }
+
+ it { is_expected.to contain_file('/etc/apt/sources.list.d/my_source.list').that_notifies('Class[Apt::Update]') }
+
+ it {
+ is_expected.to contain_apt__pin('my_source').that_comes_before('Apt::Setting[list-my_source]').with(ensure: 'present',
+ priority: 1001,
+ explanation: 'wishwash',
+ release: 'wishwash')
+ }
+ end
+
+ context 'with simple key' do
+ let :params do
+ {
+ comment: 'foo',
+ location: 'http://debian.mirror.iweb.ca/debian/',
+ release: 'sid',
+ repos: 'testing',
+ key: GPG_KEY_ID,
+ pin: '10',
+ architecture: 'x86_64',
+ allow_unsigned: true,
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source').with(ensure: 'present').with_content(%r{# foo\ndeb \[arch=x86_64 trusted=yes\] http://debian.mirror.iweb.ca/debian/ sid testing\n})
+ .without_content(%r{deb-src})
+ }
+
+ it {
+ is_expected.to contain_apt__pin('my_source').that_comes_before('Apt::Setting[list-my_source]').with(ensure: 'present',
+ priority: '10',
+ origin: 'debian.mirror.iweb.ca')
+ }
+
+ it {
+ is_expected.to contain_apt__key("Add key: #{GPG_KEY_ID} from Apt::Source my_source").that_comes_before('Apt::Setting[list-my_source]').with(ensure: 'present',
+ id: GPG_KEY_ID)
+ }
+ end
+
+ context 'with complex key' do
+ let :params do
+ {
+ comment: 'foo',
+ location: 'http://debian.mirror.iweb.ca/debian/',
+ release: 'sid',
+ repos: 'testing',
+ key: { 'id' => GPG_KEY_ID, 'server' => 'pgp.mit.edu',
+ 'content' => 'GPG key content',
+ 'source' => 'http://apt.puppetlabs.com/pubkey.gpg' },
+ pin: '10',
+ architecture: 'x86_64',
+ allow_unsigned: true,
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source').with(ensure: 'present').with_content(%r{# foo\ndeb \[arch=x86_64 trusted=yes\] http://debian.mirror.iweb.ca/debian/ sid testing\n})
+ .without_content(%r{deb-src})
+ }
+
+ it {
+ is_expected.to contain_apt__pin('my_source').that_comes_before('Apt::Setting[list-my_source]').with(ensure: 'present',
+ priority: '10',
+ origin: 'debian.mirror.iweb.ca')
+ }
+
+ it {
+ is_expected.to contain_apt__key("Add key: #{GPG_KEY_ID} from Apt::Source my_source").that_comes_before('Apt::Setting[list-my_source]').with(ensure: 'present',
+ id: GPG_KEY_ID,
+ server: 'pgp.mit.edu',
+ content: 'GPG key content',
+ source: 'http://apt.puppetlabs.com/pubkey.gpg')
+ }
+ end
+
+ context 'with simple key' do
+ let :params do
+ {
+ comment: 'foo',
+ location: 'http://debian.mirror.iweb.ca/debian/',
+ release: 'sid',
+ repos: 'testing',
+ key: GPG_KEY_ID,
+ pin: '10',
+ architecture: 'x86_64',
+ allow_unsigned: true,
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source').with(ensure: 'present').with_content(%r{# foo\ndeb \[arch=x86_64 trusted=yes\] http://debian.mirror.iweb.ca/debian/ sid testing\n})
+ .without_content(%r{deb-src})
+ }
+
+ it {
+ is_expected.to contain_apt__pin('my_source').that_comes_before('Apt::Setting[list-my_source]').with(ensure: 'present',
+ priority: '10',
+ origin: 'debian.mirror.iweb.ca')
+ }
+
+ it {
+ is_expected.to contain_apt__key("Add key: #{GPG_KEY_ID} from Apt::Source my_source").that_comes_before('Apt::Setting[list-my_source]').with(ensure: 'present',
+ id: GPG_KEY_ID)
+ }
+ end
+ end
+
+ context 'with allow_unsigned true' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ lsbdistcodename: 'wheezy',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ location: 'hello.there',
+ allow_unsigned: true,
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source').with(ensure: 'present').with_content(%r{# my_source\ndeb \[trusted=yes\] hello.there wheezy main\n})
+ }
+ end
+
+ context 'with architecture equals x86_64' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ lsbdistcodename: 'wheezy',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ location: 'hello.there',
+ include: { 'deb' => false, 'src' => true },
+ architecture: 'x86_64',
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source').with(ensure: 'present').with_content(%r{# my_source\ndeb-src \[arch=x86_64\] hello.there wheezy main\n})
+ }
+ end
+
+ context 'with architecture fact and unset architecture parameter' do
+ let :facts do
+ {
+ architecture: 'amd64',
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ lsbdistcodename: 'wheezy',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ location: 'hello.there',
+ include: { 'deb' => false, 'src' => true },
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source').with(ensure: 'present').with_content(%r{# my_source\ndeb-src hello.there wheezy main\n})
+ }
+ end
+
+ context 'with include_src => true' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ lsbdistcodename: 'wheezy',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ location: 'hello.there',
+ include: { 'src' => true },
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source').with(ensure: 'present').with_content(%r{# my_source\ndeb hello.there wheezy main\ndeb-src hello.there wheezy main\n})
+ }
+ end
+
+ context 'with include deb => false' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'debian',
+ lsbdistcodename: 'wheezy',
+ osfamily: 'debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ include: { 'deb' => false },
+ location: 'hello.there',
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source').with(ensure: 'present').without_content(%r{deb-src hello.there wheezy main\n})
+ }
+ it { is_expected.to contain_apt__setting('list-my_source').without_content(%r{deb hello.there wheezy main\n}) }
+ end
+
+ context 'with include src => true and include deb => false' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'debian',
+ lsbdistcodename: 'wheezy',
+ osfamily: 'debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ include: { 'deb' => false, 'src' => true },
+ location: 'hello.there',
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source').with(ensure: 'present').with_content(%r{deb-src hello.there wheezy main\n})
+ }
+ it { is_expected.to contain_apt__setting('list-my_source').without_content(%r{deb hello.there wheezy main\n}) }
+ end
+
+ context 'with ensure => absent' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ lsbdistcodename: 'wheezy',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ ensure: 'absent',
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source').with(ensure: 'absent')
+ }
+ end
+
+ describe 'validation' do
+ context 'with no release' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:params) { { location: 'hello.there' } }
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{lsbdistcodename fact not available: release parameter required})
+ end
+ end
+
+ context 'with release is empty string' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let(:params) { { location: 'hello.there', release: '' } }
+
+ it { is_expected.to contain_apt__setting('list-my_source').with_content(%r{hello\.there main}) }
+ end
+
+ context 'with invalid pin' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ lsbdistcodename: 'wheezy',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ location: 'hello.there',
+ pin: true,
+ }
+ end
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{expects a value})
+ end
+ end
+
+ context 'with notify_update = undef (default)' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ lsbdistcodename: 'wheezy',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ location: 'hello.there',
+ }
+ end
+
+ it { is_expected.to contain_apt__setting("list-#{title}").with_notify_update(true) }
+ end
+
+ context 'with notify_update = true' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ lsbdistcodename: 'wheezy',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ location: 'hello.there',
+ notify_update: true,
+ }
+ end
+
+ it { is_expected.to contain_apt__setting("list-#{title}").with_notify_update(true) }
+ end
+
+ context 'with notify_update = false' do
+ let :facts do
+ {
+ os: { family: 'Debian', name: 'Debian', release: { major: '7', full: '7.0' } },
+ lsbdistid: 'Debian',
+ lsbdistcodename: 'wheezy',
+ osfamily: 'Debian',
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ location: 'hello.there',
+ notify_update: false,
+ }
+ end
+
+ it { is_expected.to contain_apt__setting("list-#{title}").with_notify_update(false) }
+ end
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/spec_helper.rb b/code/environments/production/modules/apt/spec/spec_helper.rb
new file mode 100644
index 0000000..15266c2
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/spec_helper.rb
@@ -0,0 +1,23 @@
+require 'puppetlabs_spec_helper/module_spec_helper'
+require 'rspec-puppet-facts'
+include RspecPuppetFacts
+
+default_facts = {
+ puppetversion: Puppet.version,
+ facterversion: Facter.version,
+}
+
+default_facts_path = File.expand_path(File.join(File.dirname(__FILE__), 'default_facts.yml'))
+default_module_facts_path = File.expand_path(File.join(File.dirname(__FILE__), 'default_module_facts.yml'))
+
+if File.exist?(default_facts_path) && File.readable?(default_facts_path)
+ default_facts.merge!(YAML.safe_load(File.read(default_facts_path)))
+end
+
+if File.exist?(default_module_facts_path) && File.readable?(default_module_facts_path)
+ default_facts.merge!(YAML.safe_load(File.read(default_module_facts_path)))
+end
+
+RSpec.configure do |c|
+ c.default_facts = default_facts
+end
diff --git a/code/environments/production/modules/apt/spec/spec_helper_acceptance.rb b/code/environments/production/modules/apt/spec/spec_helper_acceptance.rb
new file mode 100644
index 0000000..2ec2dba
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/spec_helper_acceptance.rb
@@ -0,0 +1,90 @@
+require 'beaker-rspec'
+require 'beaker/puppet_install_helper'
+require 'beaker/module_install_helper'
+
+def install_bolt_on(hosts)
+ on(hosts, "/opt/puppetlabs/puppet/bin/gem install --source http://rubygems.delivery.puppetlabs.net bolt -v '> 0.0.1'", acceptable_exit_codes: [0, 1]).stdout
+end
+
+def pe_install?
+ ENV['PUPPET_INSTALL_TYPE'] =~ %r{pe}i
+end
+
+run_puppet_install_helper
+install_bolt_on(hosts) unless pe_install?
+install_module_on(hosts)
+install_module_dependencies_on(hosts)
+
+UNSUPPORTED_PLATFORMS = %w[RedHat Suse windows AIX Solaris].freeze
+
+DEFAULT_PASSWORD = if default[:hypervisor] == 'vagrant'
+ 'vagrant'
+ elsif default[:hypervisor] == 'vcloud'
+ 'Qu@lity!'
+ end
+
+def puppet_version
+ (on default, puppet('--version')).output.chomp
+end
+
+def run_puppet_access_login(user:, password:
+ '~!@#$%^*-/ aZ', lifetime: '5y')
+ on(master, puppet('access', 'login', '--username', user, '--lifetime', lifetime), stdin: password)
+end
+
+def run_task(task_name:, params: nil, password: DEFAULT_PASSWORD)
+ if pe_install?
+ run_puppet_task(task_name: task_name, params: params)
+ else
+ run_bolt_task(task_name: task_name, params: params, password: password)
+ end
+end
+
+def run_bolt_task(task_name:, params: nil, password: DEFAULT_PASSWORD)
+ on(master, "/opt/puppetlabs/puppet/bin/bolt task run #{task_name} --modules /etc/puppetlabs/code/modules/service --nodes localhost --password #{password} #{params}", acceptable_exit_codes: [0, 1]).stdout # rubocop:disable Metrics/LineLength
+end
+
+def run_puppet_task(task_name:, params: nil)
+ on(master, puppet('task', 'run', task_name, '--nodes', fact_on(master, 'fqdn'), params.to_s), acceptable_exit_codes: [0, 1]).stdout
+end
+
+def expect_multiple_regexes(result:, regexes:)
+ regexes.each do |regex|
+ expect(result).to match(regex)
+ end
+end
+
+# This method allows a block to be passed in and if an exception is raised
+# that matches the 'error_matcher' matcher, the block will wait a set number
+# of seconds before retrying.
+# Params:
+# - max_retry_count - Max number of retries
+# - retry_wait_interval_secs - Number of seconds to wait before retry
+# - error_matcher - Matcher which the exception raised must match to allow retry
+# Example Usage:
+# retry_on_error_matching(3, 5, /OpenGPG Error/) do
+# apply_manifest(pp, :catch_failures => true)
+# end
+def retry_on_error_matching(max_retry_count = 3, retry_wait_interval_secs = 5, error_matcher = nil)
+ try = 0
+ begin
+ try += 1
+ yield
+ rescue StandardError => e
+ raise unless try < max_retry_count && (error_matcher.nil? || e.message =~ error_matcher)
+ sleep retry_wait_interval_secs
+ retry
+ end
+end
+
+RSpec.configure do |c|
+ File.expand_path(File.join(File.dirname(__FILE__), '..'))
+
+ # Readable test descriptions
+ c.formatter = :documentation
+
+ # Configure all nodes in nodeset
+ c.before :suite do
+ run_puppet_access_login(user: 'admin') if pe_install? && puppet_version =~ %r{(5\.\d\.\d)}
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/unit/facter/apt_dist_has_updates_spec.rb b/code/environments/production/modules/apt/spec/unit/facter/apt_dist_has_updates_spec.rb
new file mode 100644
index 0000000..ae67bcf
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/unit/facter/apt_dist_has_updates_spec.rb
@@ -0,0 +1,40 @@
+require 'spec_helper'
+
+describe 'apt_has_dist_updates fact' do
+ subject { Facter.fact(:apt_has_dist_updates).value }
+
+ after(:each) { Facter.clear }
+
+ describe 'on non-Debian distro' do
+ before(:each) do
+ Facter.fact(:osfamily).expects(:value).at_least(1).returns 'RedHat'
+ end
+ it { is_expected.to be_nil }
+ end
+
+ describe 'on Debian based distro missing apt-get' do
+ before(:each) do
+ Facter.fact(:osfamily).expects(:value).at_least(1).returns 'Debian'
+ File.stubs(:executable?) # Stub all other calls
+ File.expects(:executable?).with('/usr/bin/apt-get').returns false
+ end
+ it { is_expected.to be_nil }
+ end
+
+ describe 'on Debian based distro' do
+ before(:each) do
+ Facter.fact(:osfamily).expects(:value).at_least(1).returns 'Debian'
+ File.stubs(:executable?) # Stub all other calls
+ Facter::Util::Resolution.stubs(:exec) # Catch all other calls
+ File.expects(:executable?).with('/usr/bin/apt-get').returns true
+ Facter::Util::Resolution.expects(:exec).with('/usr/bin/apt-get -s -o Debug::NoLocking=true upgrade 2>&1').returns 'test'
+ File.expects(:executable?).with('/usr/bin/apt-get').returns true
+ apt_output = "Inst extremetuxracer [2015f-0+deb8u1] (2015g-0+deb8u1 Debian:stable-updates [all])\n" \
+ "Conf extremetuxracer (2015g-0+deb8u1 Debian:stable-updates [all])\n" \
+ "Inst planet.rb [13-1.1] (22-2~bpo8+1 Debian Backports:jessie-backports [all])\n" \
+ "Conf planet.rb (22-2~bpo8+1 Debian Backports:jessie-backports [all])\n"
+ Facter::Util::Resolution.expects(:exec).with('/usr/bin/apt-get -s -o Debug::NoLocking=true dist-upgrade 2>&1').returns apt_output
+ end
+ it { is_expected.to be true }
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/unit/facter/apt_dist_package_security_updates_spec.rb b/code/environments/production/modules/apt/spec/unit/facter/apt_dist_package_security_updates_spec.rb
new file mode 100644
index 0000000..7f4f16a
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/unit/facter/apt_dist_package_security_updates_spec.rb
@@ -0,0 +1,60 @@
+require 'spec_helper'
+
+describe 'apt_package_security_dist_updates fact' do
+ subject { Facter.fact(:apt_package_security_dist_updates).value }
+
+ after(:each) { Facter.clear }
+
+ describe 'when apt has no updates' do
+ before(:each) do
+ Facter.fact(:apt_has_dist_updates).stubs(:value).returns false
+ end
+ it { is_expected.to be nil }
+ end
+
+ describe 'when apt has updates' do
+ before(:each) do
+ Facter.fact(:osfamily).stubs(:value).returns 'Debian'
+ File.stubs(:executable?) # Stub all other calls
+ Facter::Util::Resolution.stubs(:exec) # Catch all other calls
+ File.expects(:executable?).with('/usr/bin/apt-get').returns true
+ Facter::Util::Resolution.expects(:exec).with('/usr/bin/apt-get -s -o Debug::NoLocking=true upgrade 2>&1').returns 'test'
+ File.expects(:executable?).with('/usr/bin/apt-get').returns true
+ Facter::Util::Resolution.expects(:exec).with('/usr/bin/apt-get -s -o Debug::NoLocking=true dist-upgrade 2>&1').returns apt_get_upgrade_output
+ end
+
+ describe 'on Debian' do
+ let(:apt_get_upgrade_output) do
+ "Inst extremetuxracer [2015f-0+deb8u1] (2015g-0+deb8u1 Debian:stable-updates [all])\n" \
+ "Conf extremetuxracer (2015g-0+deb8u1 Debian:stable-updates [all])\n" \
+ "Inst planet.rb [13-1.1] (22-2~bpo8+1 Debian Backports:jessie-backports [all])\n" \
+ "Conf planet.rb (22-2~bpo8+1 Debian Backports:jessie-backports [all])\n" \
+ "Inst vim [7.52.1-5] (7.52.1-5+deb9u2 Debian-Security:9/stable [amd64]) []\n" \
+ "Conf vim (7.52.1-5+deb9u2 Debian-Security:9/stable [amd64])\n" \
+ end
+
+ if Facter.version < '2.0.0'
+ it { is_expected.to eq('vim') }
+ else
+ it { is_expected.to eq(['vim']) }
+ end
+ end
+
+ describe 'on Ubuntu' do
+ let(:apt_get_upgrade_output) do
+ "Inst extremetuxracer [2016f-0ubuntu0.16.04] (2016j-0ubuntu0.16.04 Ubuntu:16.04/xenial-security, Ubuntu:16.04/xenial-updates [all])\n" \
+ "Conf extremetuxracer (2016j-0ubuntu0.16.04 Ubuntu:16.04/xenial-security, Ubuntu:16.04/xenial-updates [all])\n" \
+ "Inst vim [7.47.0-1ubuntu2] (7.47.0-1ubuntu2.2 Ubuntu:16.04/xenial-security [amd64]) []\n" \
+ "Conf vim (7.47.0-1ubuntu2.2 Ubuntu:16.04/xenial-security [amd64])\n" \
+ "Inst onioncircuits [2:3.3.10-4ubuntu2] (2:3.3.10-4ubuntu2.3 Ubuntu:16.04/xenial-updates [amd64])\n" \
+ "Conf onioncircuits (2:3.3.10-4ubuntu2.3 Ubuntu:16.04/xenial-updates [amd64])\n"
+ end
+
+ if Facter.version < '2.0.0'
+ it { is_expected.to eq('extremetuxracer,vim') }
+ else
+ it { is_expected.to eq(%w[extremetuxracer vim]) }
+ end
+ end
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/unit/facter/apt_dist_package_updates_spec.rb b/code/environments/production/modules/apt/spec/unit/facter/apt_dist_package_updates_spec.rb
new file mode 100644
index 0000000..080e21f
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/unit/facter/apt_dist_package_updates_spec.rb
@@ -0,0 +1,35 @@
+require 'spec_helper'
+
+describe 'apt_package_dist_updates fact' do
+ subject { Facter.fact(:apt_package_dist_updates).value }
+
+ after(:each) { Facter.clear }
+
+ describe 'when apt has no updates' do
+ before(:each) do
+ Facter.fact(:apt_has_dist_updates).stubs(:value).returns false
+ end
+ it { is_expected.to be nil }
+ end
+
+ describe 'when apt has updates' do
+ before(:each) do
+ Facter.fact(:osfamily).stubs(:value).returns 'Debian'
+ File.stubs(:executable?) # Stub all other calls
+ Facter::Util::Resolution.stubs(:exec) # Catch all other calls
+ File.expects(:executable?).with('/usr/bin/apt-get').returns true
+ Facter::Util::Resolution.expects(:exec).with('/usr/bin/apt-get -s -o Debug::NoLocking=true upgrade 2>&1').returns 'test'
+ File.expects(:executable?).with('/usr/bin/apt-get').returns true
+ apt_output = "Inst extremetuxracer [2015f-0+deb8u1] (2015g-0+deb8u1 Debian:stable-updates [all])\n" \
+ "Conf extremetuxracer (2015g-0+deb8u1 Debian:stable-updates [all])\n" \
+ "Inst planet.rb [13-1.1] (22-2~bpo8+1 Debian Backports:jessie-backports [all])\n" \
+ "Conf planet.rb (22-2~bpo8+1 Debian Backports:jessie-backports [all])\n"
+ Facter::Util::Resolution.expects(:exec).with('/usr/bin/apt-get -s -o Debug::NoLocking=true dist-upgrade 2>&1').returns apt_output
+ end
+ if Facter.version < '2.0.0'
+ it { is_expected.to eq('extremetuxracer,planet.rb') }
+ else
+ it { is_expected.to eq(['extremetuxracer', 'planet.rb']) }
+ end
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/unit/facter/apt_dist_security_updates_spec.rb b/code/environments/production/modules/apt/spec/unit/facter/apt_dist_security_updates_spec.rb
new file mode 100644
index 0000000..9b58b6e
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/unit/facter/apt_dist_security_updates_spec.rb
@@ -0,0 +1,52 @@
+require 'spec_helper'
+
+describe 'apt_security_updates fact' do
+ subject { Facter.fact(:apt_security_dist_updates).value }
+
+ after(:each) { Facter.clear }
+
+ describe 'when apt has no updates' do
+ before(:each) do
+ Facter.fact(:apt_has_dist_updates).stubs(:value).returns false
+ end
+ it { is_expected.to be nil }
+ end
+
+ describe 'when apt has security updates' do
+ before(:each) do
+ Facter.fact(:osfamily).stubs(:value).returns 'Debian'
+ File.stubs(:executable?) # Stub all other calls
+ Facter::Util::Resolution.stubs(:exec) # Catch all other calls
+ File.expects(:executable?).with('/usr/bin/apt-get').returns true
+ Facter::Util::Resolution.expects(:exec).with('/usr/bin/apt-get -s -o Debug::NoLocking=true upgrade 2>&1').returns 'test'
+ File.expects(:executable?).with('/usr/bin/apt-get').returns true
+ Facter::Util::Resolution.expects(:exec).with('/usr/bin/apt-get -s -o Debug::NoLocking=true dist-upgrade 2>&1').returns apt_get_upgrade_output
+ end
+
+ describe 'on Debian' do
+ let(:apt_get_upgrade_output) do
+ "Inst extremetuxracer [2015f-0+deb8u1] (2015g-0+deb8u1 Debian:stable-updates [all])\n" \
+ "Conf extremetuxracer (2015g-0+deb8u1 Debian:stable-updates [all])\n" \
+ "Inst planet.rb [13-1.1] (22-2~bpo8+1 Debian Backports:jessie-backports [all])\n" \
+ "Conf planet.rb (22-2~bpo8+1 Debian Backports:jessie-backports [all])\n" \
+ "Inst vim [7.52.1-5] (7.52.1-5+deb9u2 Debian-Security:9/stable [amd64]) []\n" \
+ "Conf vim (7.52.1-5+deb9u2 Debian-Security:9/stable [amd64])\n" \
+ end
+
+ it { is_expected.to eq(1) }
+ end
+
+ describe 'on Ubuntu' do
+ let(:apt_get_upgrade_output) do
+ "Inst extremetuxracer [2016f-0ubuntu0.16.04] (2016j-0ubuntu0.16.04 Ubuntu:16.04/xenial-security, Ubuntu:16.04/xenial-updates [all])\n" \
+ "Conf extremetuxracer (2016j-0ubuntu0.16.04 Ubuntu:16.04/xenial-security, Ubuntu:16.04/xenial-updates [all])\n" \
+ "Inst vim [7.47.0-1ubuntu2] (7.47.0-1ubuntu2.2 Ubuntu:16.04/xenial-security [amd64]) []\n" \
+ "Conf vim (7.47.0-1ubuntu2.2 Ubuntu:16.04/xenial-security [amd64])\n" \
+ "Inst onioncircuits [2:3.3.10-4ubuntu2] (2:3.3.10-4ubuntu2.3 Ubuntu:16.04/xenial-updates [amd64])\n" \
+ "Conf onioncircuits (2:3.3.10-4ubuntu2.3 Ubuntu:16.04/xenial-updates [amd64])\n"
+ end
+
+ it { is_expected.to eq(2) }
+ end
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/unit/facter/apt_dist_updates_spec.rb b/code/environments/production/modules/apt/spec/unit/facter/apt_dist_updates_spec.rb
new file mode 100644
index 0000000..737d1b6
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/unit/facter/apt_dist_updates_spec.rb
@@ -0,0 +1,31 @@
+require 'spec_helper'
+
+describe 'apt_updates fact' do
+ subject { Facter.fact(:apt_dist_updates).value }
+
+ after(:each) { Facter.clear }
+
+ describe 'when apt has no updates' do
+ before(:each) do
+ Facter.fact(:apt_has_dist_updates).stubs(:value).returns false
+ end
+ it { is_expected.to be nil }
+ end
+
+ describe 'when apt has updates' do
+ before(:each) do
+ Facter.fact(:osfamily).stubs(:value).returns 'Debian'
+ File.stubs(:executable?) # Stub all other calls
+ Facter::Util::Resolution.stubs(:exec) # Catch all other calls
+ File.expects(:executable?).with('/usr/bin/apt-get').returns true
+ Facter::Util::Resolution.expects(:exec).with('/usr/bin/apt-get -s -o Debug::NoLocking=true upgrade 2>&1').returns 'test'
+ File.expects(:executable?).with('/usr/bin/apt-get').returns true
+ apt_output = "Inst extremetuxracer [2015f-0+deb8u1] (2015g-0+deb8u1 Debian:stable-updates [all])\n" \
+ "Conf extremetuxracer (2015g-0+deb8u1 Debian:stable-updates [all])\n" \
+ "Inst planet.rb [13-1.1] (22-2~bpo8+1 Debian Backports:jessie-backports [all])\n" \
+ "Conf planet.rb (22-2~bpo8+1 Debian Backports:jessie-backports [all])\n"
+ Facter::Util::Resolution.expects(:exec).with('/usr/bin/apt-get -s -o Debug::NoLocking=true dist-upgrade 2>&1').returns apt_output
+ end
+ it { is_expected.to eq(2) }
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/unit/facter/apt_has_updates_spec.rb b/code/environments/production/modules/apt/spec/unit/facter/apt_has_updates_spec.rb
new file mode 100644
index 0000000..5c06c2f
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/unit/facter/apt_has_updates_spec.rb
@@ -0,0 +1,38 @@
+require 'spec_helper'
+
+describe 'apt_has_updates fact' do
+ subject { Facter.fact(:apt_has_updates).value }
+
+ after(:each) { Facter.clear }
+
+ describe 'on non-Debian distro' do
+ before(:each) do
+ Facter.fact(:osfamily).expects(:value).at_least(1).returns 'RedHat'
+ end
+ it { is_expected.to be_nil }
+ end
+
+ describe 'on Debian based distro missing apt-get' do
+ before(:each) do
+ Facter.fact(:osfamily).expects(:value).at_least(1).returns 'Debian'
+ File.stubs(:executable?) # Stub all other calls
+ File.expects(:executable?).with('/usr/bin/apt-get').returns false
+ end
+ it { is_expected.to be_nil }
+ end
+
+ describe 'on Debian based distro' do
+ before(:each) do
+ Facter.fact(:osfamily).expects(:value).at_least(1).returns 'Debian'
+ File.stubs(:executable?) # Stub all other calls
+ Facter::Util::Resolution.stubs(:exec) # Catch all other calls
+ File.expects(:executable?).with('/usr/bin/apt-get').returns true
+ apt_output = "Inst tzdata [2015f-0+deb8u1] (2015g-0+deb8u1 Debian:stable-updates [all])\n" \
+ "Conf tzdata (2015g-0+deb8u1 Debian:stable-updates [all])\n" \
+ "Inst unhide.rb [13-1.1] (22-2~bpo8+1 Debian Backports:jessie-backports [all])\n" \
+ "Conf unhide.rb (22-2~bpo8+1 Debian Backports:jessie-backports [all])\n"
+ Facter::Util::Resolution.expects(:exec).with('/usr/bin/apt-get -s -o Debug::NoLocking=true upgrade 2>&1').returns apt_output
+ end
+ it { is_expected.to be true }
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/unit/facter/apt_package_security_updates_spec.rb b/code/environments/production/modules/apt/spec/unit/facter/apt_package_security_updates_spec.rb
new file mode 100644
index 0000000..1cd992d
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/unit/facter/apt_package_security_updates_spec.rb
@@ -0,0 +1,58 @@
+require 'spec_helper'
+
+describe 'apt_package_security_updates fact' do
+ subject { Facter.fact(:apt_package_security_updates).value }
+
+ after(:each) { Facter.clear }
+
+ describe 'when apt has no updates' do
+ before(:each) do
+ Facter.fact(:apt_has_updates).stubs(:value).returns false
+ end
+ it { is_expected.to be nil }
+ end
+
+ describe 'when apt has updates' do
+ before(:each) do
+ Facter.fact(:osfamily).stubs(:value).returns 'Debian'
+ File.stubs(:executable?) # Stub all other calls
+ Facter::Util::Resolution.stubs(:exec) # Catch all other calls
+ File.expects(:executable?).with('/usr/bin/apt-get').returns true
+ Facter::Util::Resolution.expects(:exec).with('/usr/bin/apt-get -s -o Debug::NoLocking=true upgrade 2>&1').returns apt_get_upgrade_output
+ end
+
+ describe 'on Debian' do
+ let(:apt_get_upgrade_output) do
+ "Inst tzdata [2015f-0+deb8u1] (2015g-0+deb8u1 Debian:stable-updates [all])\n" \
+ "Conf tzdata (2015g-0+deb8u1 Debian:stable-updates [all])\n" \
+ "Inst unhide.rb [13-1.1] (22-2~bpo8+1 Debian Backports:jessie-backports [all])\n" \
+ "Conf unhide.rb (22-2~bpo8+1 Debian Backports:jessie-backports [all])\n" \
+ "Inst curl [7.52.1-5] (7.52.1-5+deb9u2 Debian-Security:9/stable [amd64]) []\n" \
+ "Conf curl (7.52.1-5+deb9u2 Debian-Security:9/stable [amd64])\n" \
+ end
+
+ if Facter.version < '2.0.0'
+ it { is_expected.to eq('curl') }
+ else
+ it { is_expected.to eq(['curl']) }
+ end
+ end
+
+ describe 'on Ubuntu' do
+ let(:apt_get_upgrade_output) do
+ "Inst tzdata [2016f-0ubuntu0.16.04] (2016j-0ubuntu0.16.04 Ubuntu:16.04/xenial-security, Ubuntu:16.04/xenial-updates [all])\n" \
+ "Conf tzdata (2016j-0ubuntu0.16.04 Ubuntu:16.04/xenial-security, Ubuntu:16.04/xenial-updates [all])\n" \
+ "Inst curl [7.47.0-1ubuntu2] (7.47.0-1ubuntu2.2 Ubuntu:16.04/xenial-security [amd64]) []\n" \
+ "Conf curl (7.47.0-1ubuntu2.2 Ubuntu:16.04/xenial-security [amd64])\n" \
+ "Inst procps [2:3.3.10-4ubuntu2] (2:3.3.10-4ubuntu2.3 Ubuntu:16.04/xenial-updates [amd64])\n" \
+ "Conf procps (2:3.3.10-4ubuntu2.3 Ubuntu:16.04/xenial-updates [amd64])\n"
+ end
+
+ if Facter.version < '2.0.0'
+ it { is_expected.to eq('tzdata,curl') }
+ else
+ it { is_expected.to eq(%w[tzdata curl]) }
+ end
+ end
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/unit/facter/apt_package_updates_spec.rb b/code/environments/production/modules/apt/spec/unit/facter/apt_package_updates_spec.rb
new file mode 100644
index 0000000..f24481a
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/unit/facter/apt_package_updates_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+
+describe 'apt_package_updates fact' do
+ subject { Facter.fact(:apt_package_updates).value }
+
+ after(:each) { Facter.clear }
+
+ describe 'when apt has no updates' do
+ before(:each) do
+ Facter.fact(:apt_has_updates).stubs(:value).returns false
+ end
+ it { is_expected.to be nil }
+ end
+
+ describe 'when apt has updates' do
+ before(:each) do
+ Facter.fact(:osfamily).stubs(:value).returns 'Debian'
+ File.stubs(:executable?) # Stub all other calls
+ Facter::Util::Resolution.stubs(:exec) # Catch all other calls
+ File.expects(:executable?).with('/usr/bin/apt-get').returns true
+ apt_output = "Inst tzdata [2015f-0+deb8u1] (2015g-0+deb8u1 Debian:stable-updates [all])\n" \
+ "Conf tzdata (2015g-0+deb8u1 Debian:stable-updates [all])\n" \
+ "Inst unhide.rb [13-1.1] (22-2~bpo8+1 Debian Backports:jessie-backports [all])\n" \
+ "Conf unhide.rb (22-2~bpo8+1 Debian Backports:jessie-backports [all])\n"
+ Facter::Util::Resolution.expects(:exec).with('/usr/bin/apt-get -s -o Debug::NoLocking=true upgrade 2>&1').returns apt_output
+ end
+ if Facter.version < '2.0.0'
+ it { is_expected.to eq('tzdata,unhide.rb') }
+ else
+ it { is_expected.to eq(['tzdata', 'unhide.rb']) }
+ end
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/unit/facter/apt_reboot_required_spec.rb b/code/environments/production/modules/apt/spec/unit/facter/apt_reboot_required_spec.rb
new file mode 100644
index 0000000..356f36b
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/unit/facter/apt_reboot_required_spec.rb
@@ -0,0 +1,25 @@
+require 'spec_helper'
+
+describe 'apt_reboot_required fact' do
+ subject { Facter.fact(:apt_reboot_required).value }
+
+ after(:each) { Facter.clear }
+
+ describe 'if a reboot is required' do
+ before(:each) do
+ Facter.fact(:osfamily).expects(:value).at_least(1).returns 'Debian'
+ File.stubs(:file?).returns true
+ File.expects(:file?).at_least(1).with('/var/run/reboot-required').returns true
+ end
+ it { is_expected.to eq true }
+ end
+
+ describe 'if a reboot is not required' do
+ before(:each) do
+ Facter.fact(:osfamily).expects(:value).at_least(1).returns 'Debian'
+ File.stubs(:file?).returns true
+ File.expects(:file?).at_least(1).with('/var/run/reboot-required').returns false
+ end
+ it { is_expected.to eq false }
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/unit/facter/apt_security_updates_spec.rb b/code/environments/production/modules/apt/spec/unit/facter/apt_security_updates_spec.rb
new file mode 100644
index 0000000..fc93552
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/unit/facter/apt_security_updates_spec.rb
@@ -0,0 +1,50 @@
+require 'spec_helper'
+
+describe 'apt_security_updates fact' do
+ subject { Facter.fact(:apt_security_updates).value }
+
+ after(:each) { Facter.clear }
+
+ describe 'when apt has no updates' do
+ before(:each) do
+ Facter.fact(:apt_has_updates).stubs(:value).returns false
+ end
+ it { is_expected.to be nil }
+ end
+
+ describe 'when apt has security updates' do
+ before(:each) do
+ Facter.fact(:osfamily).stubs(:value).returns 'Debian'
+ File.stubs(:executable?) # Stub all other calls
+ Facter::Util::Resolution.stubs(:exec) # Catch all other calls
+ File.expects(:executable?).with('/usr/bin/apt-get').returns true
+ Facter::Util::Resolution.expects(:exec).with('/usr/bin/apt-get -s -o Debug::NoLocking=true upgrade 2>&1').returns apt_get_upgrade_output
+ end
+
+ describe 'on Debian' do
+ let(:apt_get_upgrade_output) do
+ "Inst tzdata [2015f-0+deb8u1] (2015g-0+deb8u1 Debian:stable-updates [all])\n" \
+ "Conf tzdata (2015g-0+deb8u1 Debian:stable-updates [all])\n" \
+ "Inst unhide.rb [13-1.1] (22-2~bpo8+1 Debian Backports:jessie-backports [all])\n" \
+ "Conf unhide.rb (22-2~bpo8+1 Debian Backports:jessie-backports [all])\n" \
+ "Inst curl [7.52.1-5] (7.52.1-5+deb9u2 Debian-Security:9/stable [amd64]) []\n" \
+ "Conf curl (7.52.1-5+deb9u2 Debian-Security:9/stable [amd64])\n" \
+ end
+
+ it { is_expected.to eq(1) }
+ end
+
+ describe 'on Ubuntu' do
+ let(:apt_get_upgrade_output) do
+ "Inst tzdata [2016f-0ubuntu0.16.04] (2016j-0ubuntu0.16.04 Ubuntu:16.04/xenial-security, Ubuntu:16.04/xenial-updates [all])\n" \
+ "Conf tzdata (2016j-0ubuntu0.16.04 Ubuntu:16.04/xenial-security, Ubuntu:16.04/xenial-updates [all])\n" \
+ "Inst curl [7.47.0-1ubuntu2] (7.47.0-1ubuntu2.2 Ubuntu:16.04/xenial-security [amd64]) []\n" \
+ "Conf curl (7.47.0-1ubuntu2.2 Ubuntu:16.04/xenial-security [amd64])\n" \
+ "Inst procps [2:3.3.10-4ubuntu2] (2:3.3.10-4ubuntu2.3 Ubuntu:16.04/xenial-updates [amd64])\n" \
+ "Conf procps (2:3.3.10-4ubuntu2.3 Ubuntu:16.04/xenial-updates [amd64])\n"
+ end
+
+ it { is_expected.to eq(2) }
+ end
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/unit/facter/apt_update_last_success_spec.rb b/code/environments/production/modules/apt/spec/unit/facter/apt_update_last_success_spec.rb
new file mode 100644
index 0000000..60d7273
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/unit/facter/apt_update_last_success_spec.rb
@@ -0,0 +1,25 @@
+require 'spec_helper'
+
+describe 'apt_update_last_success fact' do
+ subject { Facter.fact(:apt_update_last_success).value }
+
+ before(:each) { Facter.clear }
+ after(:each) { Facter.clear }
+
+ describe 'on Debian based distro which has not yet created the update-success-stamp file' do
+ it 'has a value of -1' do
+ Facter.fact(:osfamily).stubs(:value).returns 'Debian'
+ File.expects(:exist?).with('/var/lib/apt/periodic/update-success-stamp').returns false
+ is_expected.to eq(-1)
+ end
+ end
+
+ describe 'on Debian based distro which has created the update-success-stamp' do
+ it 'has the value of the mtime of the file' do
+ Facter.fact(:osfamily).stubs(:value).returns 'Debian'
+ File.stubs(:exist?).returns true
+ File.stubs(:mtime).returns 1_407_660_561
+ is_expected.to eq(1_407_660_561)
+ end
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/unit/facter/apt_updates_spec.rb b/code/environments/production/modules/apt/spec/unit/facter/apt_updates_spec.rb
new file mode 100644
index 0000000..d0a5dbb
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/unit/facter/apt_updates_spec.rb
@@ -0,0 +1,30 @@
+require 'spec_helper'
+
+describe 'apt_updates fact' do
+ subject { Facter.fact(:apt_updates).value }
+
+ after(:each) { Facter.clear }
+
+ describe 'when apt has no updates' do
+ before(:each) do
+ Facter.fact(:apt_has_updates).stubs(:value).returns false
+ end
+ it { is_expected.to be nil }
+ end
+
+ describe 'when apt has updates' do
+ before(:each) do
+ Facter.fact(:osfamily).stubs(:value).returns 'Debian'
+ File.stubs(:executable?) # Stub all other calls
+ Facter::Util::Resolution.stubs(:exec) # Catch all other calls
+ File.expects(:executable?).with('/usr/bin/apt-get').returns true
+ apt_output = "Inst tzdata [2015f-0+deb8u1] (2015g-0+deb8u1 Debian:stable-updates [all])\n" \
+ "Conf tzdata (2015g-0+deb8u1 Debian:stable-updates [all])\n" \
+ "Inst unhide.rb [13-1.1] (22-2~bpo8+1 Debian Backports:jessie-backports [all])\n" \
+ "Conf unhide.rb (22-2~bpo8+1 Debian Backports:jessie-backports [all])\n"
+ puts apt_output
+ Facter::Util::Resolution.expects(:exec).with('/usr/bin/apt-get -s -o Debug::NoLocking=true upgrade 2>&1').returns apt_output
+ end
+ it { is_expected.to eq(2) }
+ end
+end
diff --git a/code/environments/production/modules/apt/spec/unit/puppet/type/apt_key_spec.rb b/code/environments/production/modules/apt/spec/unit/puppet/type/apt_key_spec.rb
new file mode 100644
index 0000000..a25d827
--- /dev/null
+++ b/code/environments/production/modules/apt/spec/unit/puppet/type/apt_key_spec.rb
@@ -0,0 +1,212 @@
+require 'spec_helper'
+require 'puppet'
+
+describe Puppet::Type.type(:apt_key) do
+ context 'with only namevar 32bit key id' do
+ let(:resource) do
+ Puppet::Type.type(:apt_key).new(
+ id: 'EF8D349F',
+ )
+ end
+
+ it 'id is set' do
+ expect(resource[:id]).to eq 'EF8D349F'
+ end
+
+ it 'name is set to id' do
+ expect(resource[:name]).to eq 'EF8D349F'
+ end
+
+ it 'keyserver is default' do
+ expect(resource[:server]).to eq :'keyserver.ubuntu.com'
+ end
+
+ it 'source is not set' do
+ expect(resource[:source]).to eq nil
+ end
+
+ it 'content is not set' do
+ expect(resource[:content]).to eq nil
+ end
+ end
+
+ context 'with a lowercase 32bit key id' do
+ let(:resource) do
+ Puppet::Type.type(:apt_key).new(
+ id: 'ef8d349f',
+ )
+ end
+
+ it 'id is set' do
+ expect(resource[:id]).to eq 'EF8D349F'
+ end
+ end
+
+ context 'with a 64bit key id' do
+ let(:resource) do
+ Puppet::Type.type(:apt_key).new(
+ id: 'FFFFFFFFEF8D349F',
+ )
+ end
+
+ it 'id is set' do
+ expect(resource[:id]).to eq 'FFFFFFFFEF8D349F'
+ end
+ end
+
+ context 'with a 0x formatted key id' do
+ let(:resource) do
+ Puppet::Type.type(:apt_key).new(
+ id: '0xEF8D349F',
+ )
+ end
+
+ it 'id is set' do
+ expect(resource[:id]).to eq 'EF8D349F'
+ end
+ end
+
+ context 'with a 0x formatted lowercase key id' do
+ let(:resource) do
+ Puppet::Type.type(:apt_key).new(
+ id: '0xef8d349f',
+ )
+ end
+
+ it 'id is set' do
+ expect(resource[:id]).to eq 'EF8D349F'
+ end
+ end
+
+ context 'with a 0x formatted 64bit key id' do
+ let(:resource) do
+ Puppet::Type.type(:apt_key).new(
+ id: '0xFFFFFFFFEF8D349F',
+ )
+ end
+
+ it 'id is set' do
+ expect(resource[:id]).to eq 'FFFFFFFFEF8D349F'
+ end
+ end
+
+ context 'with source' do
+ let(:resource) do
+ Puppet::Type.type(:apt_key).new(
+ id: 'EF8D349F',
+ source: 'http://apt.puppetlabs.com/pubkey.gpg',
+ )
+ end
+
+ it 'source is set to the URL' do
+ expect(resource[:source]).to eq 'http://apt.puppetlabs.com/pubkey.gpg'
+ end
+ end
+
+ context 'with content' do
+ let(:resource) do
+ Puppet::Type.type(:apt_key).new(
+ id: 'EF8D349F',
+ content: 'http://apt.puppetlabs.com/pubkey.gpg',
+ )
+ end
+
+ it 'content is set to the string' do
+ expect(resource[:content]).to eq 'http://apt.puppetlabs.com/pubkey.gpg'
+ end
+ end
+
+ context 'with keyserver' do
+ let(:resource) do
+ Puppet::Type.type(:apt_key).new(
+ id: 'EF8D349F',
+ server: 'http://keyring.debian.org',
+ )
+ end
+
+ it 'keyserver is set to Debian' do
+ expect(resource[:server]).to eq 'http://keyring.debian.org'
+ end
+ end
+
+ context 'with validation' do
+ it 'raises an error if content and source are set' do
+ expect {
+ Puppet::Type.type(:apt_key).new(id: 'EF8D349F',
+ source: 'http://apt.puppetlabs.com/pubkey.gpg',
+ content: 'Completely invalid as a GPG key')
+ }.to raise_error(%r{content and source are mutually exclusive})
+ end
+
+ it 'raises an error if a weird length key is used' do
+ expect {
+ Puppet::Type.type(:apt_key).new(id: 'FEF8D349F',
+ source: 'http://apt.puppetlabs.com/pubkey.gpg',
+ content: 'Completely invalid as a GPG key')
+ }.to raise_error(%r{Valid values match})
+ end
+
+ it 'raises an error when an invalid URI scheme is used in source' do
+ expect {
+ Puppet::Type.type(:apt_key).new(id: 'EF8D349F',
+ source: 'hkp://pgp.mit.edu')
+ }.to raise_error(%r{Valid values match})
+ end
+
+ it 'allows the http URI scheme in source' do
+ expect {
+ Puppet::Type.type(:apt_key).new(id: 'EF8D349F',
+ source: 'http://pgp.mit.edu')
+ }.not_to raise_error
+ end
+
+ it 'allows the http URI with username and password' do
+ expect {
+ Puppet::Type.type(:apt_key).new(id: '4BD6EC30',
+ source: 'http://testme:Password2@pgp.mit.edu')
+ }.not_to raise_error
+ end
+
+ it 'allows the https URI scheme in source' do
+ expect {
+ Puppet::Type.type(:apt_key).new(id: 'EF8D349F',
+ source: 'https://pgp.mit.edu')
+ }.not_to raise_error
+ end
+
+ it 'allows the https URI with username and password' do
+ expect {
+ Puppet::Type.type(:apt_key).new(id: 'EF8D349F',
+ source: 'https://testme:Password2@pgp.mit.edu')
+ }.not_to raise_error
+ end
+
+ it 'allows the ftp URI scheme in source' do
+ expect {
+ Puppet::Type.type(:apt_key).new(id: 'EF8D349F',
+ source: 'ftp://pgp.mit.edu')
+ }.not_to raise_error
+ end
+
+ it 'allows an absolute path in source' do
+ expect {
+ Puppet::Type.type(:apt_key).new(id: 'EF8D349F',
+ source: '/path/to/a/file')
+ }.not_to raise_error
+ end
+
+ it 'allows 5-digit ports' do
+ expect {
+ Puppet::Type.type(:apt_key).new(id: 'EF8D349F',
+ source: 'http://pgp.mit.edu:12345/key')
+ }.not_to raise_error
+ end
+
+ it 'allows 5-digit ports when using key servers' do
+ expect {
+ Puppet::Type.type(:apt_key).new(id: 'EF8D349F',
+ server: 'http://pgp.mit.edu:12345')
+ }.not_to raise_error
+ end
+ end
+end