New Upstream Snapshot - puppet-module-puppetlabs-apt
Ready changes
Summary
Merged new upstream version: 9.0.1+git20230201.1.790df53 (was: 9.0.1).
Resulting package
Built on 2023-02-09T16:47 (took 15m18s)
The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:
apt install -t fresh-snapshots puppet-module-puppetlabs-apt
Lintian Result
- puppet-module-puppetlabs-apt_9.0.1+git20230201.1.790df53-1~jan+nus1.dsc
- puppet-module-puppetlabs-apt_9.0.1+git20230201.1.790df53-1~jan+nus1_all.deb
- puppet-module-puppetlabs-apt_9.0.1+git20230201.1.790df53-1~jan+nus1_amd64.buildinfo
- puppet-module-puppetlabs-apt_9.0.1+git20230201.1.790df53-1~jan+nus1_amd64.changes
Diff
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
new file mode 100644
index 0000000..12ed4ff
--- /dev/null
+++ b/.devcontainer/Dockerfile
@@ -0,0 +1,6 @@
+FROM puppet/pdk:latest
+
+# [Optional] Uncomment this section to install additional packages.
+# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
+# && apt-get -y install --no-install-recommends <your-package-list-here>
+
diff --git a/.devcontainer/README.md b/.devcontainer/README.md
new file mode 100644
index 0000000..a719361
--- /dev/null
+++ b/.devcontainer/README.md
@@ -0,0 +1,38 @@
+# devcontainer
+
+
+For format details, see https://aka.ms/devcontainer.json.
+
+For config options, see the README at:
+https://github.com/microsoft/vscode-dev-containers/tree/v0.140.1/containers/puppet
+
+``` json
+{
+ "name": "Puppet Development Kit (Community)",
+ "dockerFile": "Dockerfile",
+
+ // Set *default* container specific settings.json values on container create.
+ "settings": {
+ "terminal.integrated.profiles.linux": {
+ "bash": {
+ "path": "bash",
+ }
+ }
+ },
+
+ // Add the IDs of extensions you want installed when the container is created.
+ "extensions": [
+ "puppet.puppet-vscode",
+ "rebornix.Ruby"
+ ],
+
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ "forwardPorts": [],
+
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "pdk --version",
+}
+```
+
+
+
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 0000000..fe7a8b1
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,17 @@
+{
+ "name": "Puppet Development Kit (Community)",
+ "dockerFile": "Dockerfile",
+
+ "settings": {
+ "terminal.integrated.profiles.linux": {
+ "bash": {
+ "path": "bash",
+ }
+ }
+ },
+
+ "extensions": [
+ "puppet.puppet-vscode",
+ "rebornix.Ruby"
+ ]
+}
diff --git a/.fixtures.yml b/.fixtures.yml
new file mode 100644
index 0000000..0157d6a
--- /dev/null
+++ b/.fixtures.yml
@@ -0,0 +1,9 @@
+fixtures:
+ repositories:
+ "stdlib":
+ "repo": "https://github.com/puppetlabs/puppetlabs-stdlib.git"
+ facts: 'https://github.com/puppetlabs/puppetlabs-facts.git'
+ puppet_agent: 'https://github.com/puppetlabs/puppetlabs-puppet_agent.git'
+ provision: 'https://github.com/puppetlabs/provision.git'
+ symlinks:
+ "apt": "#{source_dir}"
diff --git a/.github/workflows/auto_release.yml b/.github/workflows/auto_release.yml
deleted file mode 100644
index f4aed44..0000000
--- a/.github/workflows/auto_release.yml
+++ /dev/null
@@ -1,90 +0,0 @@
-name: "Auto release"
-
-on:
- workflow_dispatch:
-
-env:
- HONEYCOMB_WRITEKEY: 7f3c63a70eecc61d635917de46bea4e6
- HONEYCOMB_DATASET: litmus tests
- CHANGELOG_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
-jobs:
- auto_release:
- name: "Automatic release prep"
- runs-on: ubuntu-20.04
-
- steps:
-
- - name: "Honeycomb: Start recording"
- uses: puppetlabs/kvrhdn-gha-buildevents@pdk-templates-v1
- with:
- apikey: ${{ env.HONEYCOMB_WRITEKEY }}
- dataset: ${{ env.HONEYCOMB_DATASET }}
- job-status: ${{ job.status }}
-
- - name: "Honeycomb: start first step"
- run: |
- echo STEP_ID="auto-release" >> $GITHUB_ENV
- echo STEP_START=$(date +%s) >> $GITHUB_ENV
- - name: "Checkout Source"
- if: ${{ github.repository_owner == 'puppetlabs' }}
- uses: actions/checkout@v2
- with:
- fetch-depth: 0
- persist-credentials: false
-
- - name: "PDK Release prep"
- uses: docker://puppet/iac_release:ci
- with:
- args: 'release prep --force'
- env:
- CHANGELOG_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- - name: "Get Version"
- if: ${{ github.repository_owner == 'puppetlabs' }}
- id: gv
- run: |
- echo "::set-output name=ver::$(jq --raw-output .version metadata.json)"
-
- - name: "Check if a release is necessary"
- if: ${{ github.repository_owner == 'puppetlabs' }}
- id: check
- run: |
- git diff --quiet CHANGELOG.md && echo "::set-output name=release::false" || echo "::set-output name=release::true"
-
- - name: "Commit changes"
- if: ${{ github.repository_owner == 'puppetlabs' && steps.check.outputs.release == 'true' }}
- run: |
- git config --local user.email "${{ github.repository_owner }}@users.noreply.github.com"
- git config --local user.name "GitHub Action"
- git add .
- git commit -m "Release prep v${{ steps.gv.outputs.ver }}"
-
- - name: Create Pull Request
- id: cpr
- uses: puppetlabs/peter-evans-create-pull-request@v3
- if: ${{ github.repository_owner == 'puppetlabs' && steps.check.outputs.release == 'true' }}
- with:
- token: ${{ secrets.GITHUB_TOKEN }}
- commit-message: "Release prep v${{ steps.gv.outputs.ver }}"
- branch: "release-prep"
- delete-branch: true
- title: "Release prep v${{ steps.gv.outputs.ver }}"
- body: |
- Automated release-prep through [pdk-templates](https://github.com/puppetlabs/pdk-templates/blob/main/moduleroot/.github/workflows/auto_release.yml.erb) from commit ${{ github.sha }}.
- Please verify before merging:
- - [ ] last [nightly](https://github.com/${{ github.repository }}/actions/workflows/nightly.yml) run is green
- - [ ] [Changelog](https://github.com/${{ github.repository }}/blob/release-prep/CHANGELOG.md) is readable and has no unlabeled pull requests
- - [ ] Ensure the [changelog](https://github.com/${{ github.repository }}/blob/release-prep/CHANGELOG.md) version and [metadata](https://github.com/${{ github.repository }}/blob/release-prep/metadata.json) version match
- labels: "maintenance"
-
- - name: PR outputs
- if: ${{ github.repository_owner == 'puppetlabs' && steps.check.outputs.release == 'true' }}
- run: |
- echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
- echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
-
- - name: "Honeycomb: Record finish step"
- if: ${{ always() }}
- run: |
- buildevents step $TRACE_ID $STEP_ID $STEP_START 'Finished auto release workflow'
diff --git a/.github/workflows/labeller.yml b/.github/workflows/labeller.yml
deleted file mode 100644
index 5434d3f..0000000
--- a/.github/workflows/labeller.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-name: community-labeller
-
-on:
- issues:
- types:
- - opened
- pull_request_target:
- types:
- - opened
-
-jobs:
- label:
- runs-on: ubuntu-latest
- steps:
-
- - uses: puppetlabs/community-labeller@v0
- name: Label issues or pull requests
- with:
- label_name: community
- label_color: '5319e7'
- org_membership: puppetlabs
- token: ${{ secrets.IAC_COMMUNITY_LABELER }}
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
deleted file mode 100644
index 42816e7..0000000
--- a/.github/workflows/nightly.yml
+++ /dev/null
@@ -1,204 +0,0 @@
-name: "nightly"
-
-on:
- schedule:
- - cron: '0 0 * * *'
-
-
-env:
- HONEYCOMB_WRITEKEY: 7f3c63a70eecc61d635917de46bea4e6
- HONEYCOMB_DATASET: litmus tests
-
-jobs:
- setup_matrix:
- if: ${{ github.repository_owner == 'puppetlabs' }}
- name: "Setup Test Matrix"
- runs-on: ubuntu-20.04
- outputs:
- matrix: ${{ steps.get-matrix.outputs.matrix }}
-
- steps:
-
- - name: "Honeycomb: Start recording"
- uses: puppetlabs/kvrhdn-gha-buildevents@pdk-templates-v1
- with:
- apikey: ${{ env.HONEYCOMB_WRITEKEY }}
- dataset: ${{ env.HONEYCOMB_DATASET }}
- job-status: ${{ job.status }}
-
- - name: "Honeycomb: Start first step"
- run: |
- echo STEP_ID=setup-environment >> $GITHUB_ENV
- echo STEP_START=$(date +%s) >> $GITHUB_ENV
- - name: Checkout Source
- uses: actions/checkout@v2
- if: ${{ github.repository_owner == 'puppetlabs' }}
-
- - name: Activate Ruby 2.7
- uses: ruby/setup-ruby@v1
- if: ${{ github.repository_owner == 'puppetlabs' }}
- with:
- ruby-version: "2.7"
- bundler-cache: true
-
- - name: Print bundle environment
- if: ${{ github.repository_owner == 'puppetlabs' }}
- run: |
- echo ::group::bundler environment
- buildevents cmd $TRACE_ID $STEP_ID 'bundle env' -- bundle env
- echo ::endgroup::
-
- - name: "Honeycomb: Record Setup Environment time"
- if: ${{ github.repository_owner == 'puppetlabs' }}
- run: |
- buildevents step $TRACE_ID $STEP_ID $STEP_START 'Setup Environment'
- echo STEP_ID=Setup-Acceptance-Test-Matrix >> $GITHUB_ENV
- echo STEP_START=$(date +%s) >> $GITHUB_ENV
- - name: Setup Acceptance Test Matrix
- id: get-matrix
- if: ${{ github.repository_owner == 'puppetlabs' }}
- run: |
- if [ '${{ github.repository_owner }}' == 'puppetlabs' ]; then
- buildevents cmd $TRACE_ID $STEP_ID matrix_from_metadata -- bundle exec matrix_from_metadata_v2
- else
- echo "::set-output name=matrix::{}"
- fi
-
- - name: "Honeycomb: Record Setup Test Matrix time"
- if: ${{ always() }}
- run: |
- buildevents step $TRACE_ID $STEP_ID $STEP_START 'Setup Test Matrix'
- Acceptance:
- name: "${{matrix.platforms.label}}, ${{matrix.collection}}"
- needs:
- - setup_matrix
-
- runs-on: ubuntu-20.04
- strategy:
- fail-fast: false
- matrix: ${{fromJson(needs.setup_matrix.outputs.matrix)}}
-
- env:
- BUILDEVENT_FILE: '../buildevents.txt'
-
- steps:
- - run: |
- echo 'platform=${{ matrix.platforms.image }}' >> $BUILDEVENT_FILE
- echo 'collection=${{ matrix.collection }}' >> $BUILDEVENT_FILE
- echo 'label=${{ matrix.platforms.label }}' >> $BUILDEVENT_FILE
-
-
- - name: "Honeycomb: Start recording"
- uses: puppetlabs/kvrhdn-gha-buildevents@pdk-templates-v1
- with:
- apikey: ${{ env.HONEYCOMB_WRITEKEY }}
- dataset: ${{ env.HONEYCOMB_DATASET }}
- job-status: ${{ job.status }}
- matrix-key: ${{ matrix.platforms.label }}-${{ matrix.collection }}
-
- - name: "Honeycomb: start first step"
- run: |
- echo STEP_ID=${{ matrix.platforms.image }}-${{ matrix.collection }}-1 >> $GITHUB_ENV
- echo STEP_START=$(date +%s) >> $GITHUB_ENV
-
- - name: Checkout Source
- uses: actions/checkout@v2
-
- - name: Activate Ruby 2.7
- uses: ruby/setup-ruby@v1
- with:
- ruby-version: "2.7"
- bundler-cache: true
-
- - name: Print bundle environment
- run: |
- echo ::group::bundler environment
- buildevents cmd $TRACE_ID $STEP_ID 'bundle env' -- bundle env
- echo ::endgroup::
-
- - name: "Honeycomb: Record Setup Environment time"
- if: ${{ always() }}
- run: |
- buildevents step $TRACE_ID $STEP_ID $STEP_START 'Setup Environment'
- echo STEP_ID=${{ matrix.platforms.image }}-${{ matrix.collection }}-2 >> $GITHUB_ENV
- echo STEP_START=$(date +%s) >> $GITHUB_ENV
-
- - name: Provision test environment
- run: |
- buildevents cmd $TRACE_ID $STEP_ID 'rake litmus:provision ${{ matrix.platforms.image }}' -- bundle exec rake 'litmus:provision[${{matrix.platforms.provider}},${{ matrix.platforms.image }}]'
- echo ::group::=== REQUEST ===
- cat request.json || true
- echo
- echo ::endgroup::
- echo ::group::=== INVENTORY ===
- if [ -f 'spec/fixtures/litmus_inventory.yaml' ];
- then
- FILE='spec/fixtures/litmus_inventory.yaml'
- elif [ -f 'inventory.yaml' ];
- then
- FILE='inventory.yaml'
- fi
- sed -e 's/password: .*/password: "[redacted]"/' < $FILE || true
- echo ::endgroup::
-
- - name: Install agent
- run: |
- buildevents cmd $TRACE_ID $STEP_ID 'rake litmus:install_agent ${{ matrix.collection }}' -- bundle exec rake 'litmus:install_agent[${{ matrix.collection }}]'
-
- - name: Install module
- run: |
- buildevents cmd $TRACE_ID $STEP_ID 'rake litmus:install_module' -- bundle exec rake 'litmus:install_module'
-
- - name: "Honeycomb: Record deployment times"
- if: ${{ always() }}
- run: |
- echo ::group::honeycomb step
- buildevents step $TRACE_ID $STEP_ID $STEP_START 'Deploy test system'
- echo STEP_ID=${{ matrix.platforms.image }}-${{ matrix.collection }}-3 >> $GITHUB_ENV
- echo STEP_START=$(date +%s) >> $GITHUB_ENV
- echo ::endgroup::
-
- - name: Run acceptance tests
- run: |
- buildevents cmd $TRACE_ID $STEP_ID 'rake litmus:acceptance:parallel' -- bundle exec rake 'litmus:acceptance:parallel'
-
- - name: "Honeycomb: Record acceptance testing times"
- if: ${{ always() }}
- run: |
- buildevents step $TRACE_ID $STEP_ID $STEP_START 'Run acceptance tests'
- echo STEP_ID=${{ matrix.platforms.image }}-${{ matrix.collection }}-4 >> $GITHUB_ENV
- echo STEP_START=$(date +%s) >> $GITHUB_ENV
-
- - name: Remove test environment
- if: ${{ always() }}
- continue-on-error: true
- run: |
- if [[ -f inventory.yaml || -f spec/fixtures/litmus_inventory.yaml ]]; then
- buildevents cmd $TRACE_ID $STEP_ID 'rake litmus:tear_down' -- bundle exec rake 'litmus:tear_down'
- echo ::group::=== REQUEST ===
- cat request.json || true
- echo
- echo ::endgroup::
- fi
-
- - name: "Honeycomb: Record removal times"
- if: ${{ always() }}
- run: |
- buildevents step $TRACE_ID $STEP_ID $STEP_START 'Remove test environment'
-
- slack-workflow-status:
- if: ${{ github.repository_owner == 'puppetlabs' }}
- name: Post Workflow Status To Slack
- needs:
- - Acceptance
- runs-on: ubuntu-20.04
- steps:
- - name: Slack Workflow Notification
- uses: puppetlabs/Gamesight-slack-workflow-status@pdk-templates-v1
- with:
- # Required Input
- repo_token: ${{ secrets.GITHUB_TOKEN }}
- slack_webhook_url: ${{ secrets.SLACK_WEBHOOK }}
- # Optional Input
- channel: '#team-cat-bots'
- name: 'GABot'
diff --git a/.github/workflows/pr_test.yml b/.github/workflows/pr_test.yml
deleted file mode 100644
index fd310e6..0000000
--- a/.github/workflows/pr_test.yml
+++ /dev/null
@@ -1,185 +0,0 @@
-name: "PR Testing"
-
-on: [pull_request]
-
-
-env:
-
- HONEYCOMB_WRITEKEY: 7f3c63a70eecc61d635917de46bea4e6
- HONEYCOMB_DATASET: litmus tests
-
-jobs:
- setup_matrix:
- name: "Setup Test Matrix"
- runs-on: ubuntu-20.04
- outputs:
- matrix: ${{ steps.get-matrix.outputs.matrix }}
-
- steps:
-
- - name: "Honeycomb: Start recording"
- uses: puppetlabs/kvrhdn-gha-buildevents@pdk-templates-v1
- with:
- apikey: ${{ env.HONEYCOMB_WRITEKEY }}
- dataset: ${{ env.HONEYCOMB_DATASET }}
- job-status: ${{ job.status }}
-
- - name: "Honeycomb: Start first step"
- run: |
- echo STEP_ID=setup-environment >> $GITHUB_ENV
- echo STEP_START=$(date +%s) >> $GITHUB_ENV
- - name: Checkout Source
- uses: actions/checkout@v2
- if: ${{ github.repository_owner == 'puppetlabs' }}
-
- - name: Activate Ruby 2.7
- uses: ruby/setup-ruby@v1
- if: ${{ github.repository_owner == 'puppetlabs' }}
- with:
- ruby-version: "2.7"
- bundler-cache: true
-
- - name: Print bundle environment
- if: ${{ github.repository_owner == 'puppetlabs' }}
- run: |
- echo ::group::bundler environment
- buildevents cmd $TRACE_ID $STEP_ID 'bundle env' -- bundle env
- echo ::endgroup::
-
- - name: "Honeycomb: Record Setup Environment time"
- if: ${{ github.repository_owner == 'puppetlabs' }}
- run: |
- buildevents step $TRACE_ID $STEP_ID $STEP_START 'Setup Environment'
- echo STEP_ID=Setup-Acceptance-Test-Matrix >> $GITHUB_ENV
- echo STEP_START=$(date +%s) >> $GITHUB_ENV
- - name: Run validation steps
- run: |
- bundle exec rake validate
- if: ${{ github.repository_owner == 'puppetlabs' }}
-
- - name: Setup Acceptance Test Matrix
- id: get-matrix
- run: |
- if [ '${{ github.repository_owner }}' == 'puppetlabs' ]; then
- buildevents cmd $TRACE_ID $STEP_ID matrix_from_metadata -- bundle exec matrix_from_metadata_v2
- else
- echo "::set-output name=matrix::{}"
- fi
-
- - name: "Honeycomb: Record Setup Test Matrix time"
- if: ${{ always() }}
- run: |
- buildevents step $TRACE_ID $STEP_ID $STEP_START 'Setup Test Matrix'
- Acceptance:
- name: "${{matrix.platforms.label}}, ${{matrix.collection}}"
- needs:
- - setup_matrix
- if: ${{ needs.setup_matrix.outputs.matrix != '{}' }}
-
- runs-on: ubuntu-20.04
- strategy:
- fail-fast: false
- matrix: ${{fromJson(needs.setup_matrix.outputs.matrix)}}
-
- env:
- BUILDEVENT_FILE: '../buildevents.txt'
-
- steps:
- - run: |
- echo 'platform=${{ matrix.platforms.image }}' >> $BUILDEVENT_FILE
- echo 'collection=${{ matrix.collection }}' >> $BUILDEVENT_FILE
- echo 'label=${{ matrix.platforms.label }}' >> $BUILDEVENT_FILE
-
- - name: "Honeycomb: Start recording"
- uses: puppetlabs/kvrhdn-gha-buildevents@pdk-templates-v1
- with:
- apikey: ${{ env.HONEYCOMB_WRITEKEY }}
- dataset: ${{ env.HONEYCOMB_DATASET }}
- job-status: ${{ job.status }}
- matrix-key: ${{ matrix.platforms.label }}-${{ matrix.collection }}
-
- - name: "Honeycomb: start first step"
- run: |
- echo STEP_ID=${{ matrix.platforms.image }}-${{ matrix.collection }}-1 >> $GITHUB_ENV
- echo STEP_START=$(date +%s) >> $GITHUB_ENV
- - name: Checkout Source
- uses: actions/checkout@v2
-
- - name: Activate Ruby 2.7
- uses: ruby/setup-ruby@v1
- with:
- ruby-version: "2.7"
- bundler-cache: true
-
- - name: Print bundle environment
- run: |
- echo ::group::bundler environment
- buildevents cmd $TRACE_ID $STEP_ID 'bundle env' -- bundle env
- echo ::endgroup::
-
- - name: "Honeycomb: Record Setup Environment time"
- if: ${{ always() }}
- run: |
- buildevents step $TRACE_ID $STEP_ID $STEP_START 'Setup Environment'
- echo STEP_ID=${{ matrix.platforms.image }}-${{ matrix.collection }}-2 >> $GITHUB_ENV
- echo STEP_START=$(date +%s) >> $GITHUB_ENV
- - name: Provision test environment
- run: |
- buildevents cmd $TRACE_ID $STEP_ID 'rake litmus:provision ${{ matrix.platforms.image }}' -- bundle exec rake 'litmus:provision[${{matrix.platforms.provider}},${{ matrix.platforms.image }}]'
- echo ::group::=== REQUEST ===
- cat request.json || true
- echo
- echo ::endgroup::
- echo ::group::=== INVENTORY ===
- if [ -f 'spec/fixtures/litmus_inventory.yaml' ];
- then
- FILE='spec/fixtures/litmus_inventory.yaml'
- elif [ -f 'inventory.yaml' ];
- then
- FILE='inventory.yaml'
- fi
- sed -e 's/password: .*/password: "[redacted]"/' < $FILE || true
- echo ::endgroup::
-
- - name: Install agent
- run: |
- buildevents cmd $TRACE_ID $STEP_ID 'rake litmus:install_agent ${{ matrix.collection }}' -- bundle exec rake 'litmus:install_agent[${{ matrix.collection }}]'
-
- - name: Install module
- run: |
- buildevents cmd $TRACE_ID $STEP_ID 'rake litmus:install_module' -- bundle exec rake 'litmus:install_module'
-
- - name: "Honeycomb: Record deployment times"
- if: ${{ always() }}
- run: |
- echo ::group::honeycomb step
- buildevents step $TRACE_ID $STEP_ID $STEP_START 'Deploy test system'
- echo STEP_ID=${{ matrix.platforms.image }}-${{ matrix.collection }}-3 >> $GITHUB_ENV
- echo STEP_START=$(date +%s) >> $GITHUB_ENV
- echo ::endgroup::
- - name: Run acceptance tests
- run: |
- buildevents cmd $TRACE_ID $STEP_ID 'rake litmus:acceptance:parallel' -- bundle exec rake 'litmus:acceptance:parallel'
-
- - name: "Honeycomb: Record acceptance testing times"
- if: ${{ always() }}
- run: |
- buildevents step $TRACE_ID $STEP_ID $STEP_START 'Run acceptance tests'
- echo STEP_ID=${{ matrix.platforms.image }}-${{ matrix.collection }}-4 >> $GITHUB_ENV
- echo STEP_START=$(date +%s) >> $GITHUB_ENV
- - name: Remove test environment
- if: ${{ always() }}
- continue-on-error: true
- run: |
- if [[ -f inventory.yaml || -f spec/fixtures/litmus_inventory.yaml ]]; then
- buildevents cmd $TRACE_ID $STEP_ID 'rake litmus:tear_down' -- bundle exec rake 'litmus:tear_down'
- echo ::group::=== REQUEST ===
- cat request.json || true
- echo
- echo ::endgroup::
- fi
-
- - name: "Honeycomb: Record removal times"
- if: ${{ always() }}
- run: |
- buildevents step $TRACE_ID $STEP_ID $STEP_START 'Remove test environment'
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
deleted file mode 100644
index 1509f6e..0000000
--- a/.github/workflows/release.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-name: "Publish module"
-
-on:
- workflow_dispatch:
-
-jobs:
- create-github-release:
- name: Deploy GitHub Release
- runs-on: ubuntu-20.04
- steps:
- - name: Checkout code
- uses: actions/checkout@v2
- with:
- ref: ${{ github.ref }}
- clean: true
- fetch-depth: 0
- - name: Get Version
- id: gv
- run: |
- echo "::set-output name=ver::$(jq --raw-output .version metadata.json)"
- - name: Create Release
- uses: actions/create-release@v1
- id: create_release
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- with:
- tag_name: "v${{ steps.gv.outputs.ver }}"
- draft: false
- prerelease: false
-
- deploy-forge:
- name: Deploy to Forge
- runs-on: ubuntu-20.04
- steps:
- - name: Checkout code
- uses: actions/checkout@v2
- with:
- ref: ${{ github.ref }}
- clean: true
- - name: "PDK Build"
- uses: docker://puppet/pdk:nightly
- with:
- args: 'build'
- - name: "Push to Forge"
- uses: docker://puppet/pdk:nightly
- with:
- args: 'release publish --forge-token ${{ secrets.FORGE_API_KEY }} --force'
diff --git a/.github/workflows/spec.yml b/.github/workflows/spec.yml
deleted file mode 100644
index 6c1ae10..0000000
--- a/.github/workflows/spec.yml
+++ /dev/null
@@ -1,126 +0,0 @@
-name: "Spec Tests"
-
-on:
- schedule:
- - cron: '0 0 * * *'
- workflow_dispatch:
- pull_request:
-
-
-env:
- HONEYCOMB_WRITEKEY: 7f3c63a70eecc61d635917de46bea4e6
- HONEYCOMB_DATASET: litmus tests
-
-jobs:
- setup_matrix:
- name: "Setup Test Matrix"
- runs-on: ubuntu-20.04
- outputs:
- spec_matrix: ${{ steps.get-matrix.outputs.spec_matrix }}
-
- steps:
-
- - name: "Honeycomb: Start recording"
- uses: puppetlabs/kvrhdn-gha-buildevents@pdk-templates-v1
- with:
- apikey: ${{ env.HONEYCOMB_WRITEKEY }}
- dataset: ${{ env.HONEYCOMB_DATASET }}
- job-status: ${{ job.status }}
-
- - name: "Honeycomb: Start first step"
- run: |
- echo STEP_ID=setup-environment >> $GITHUB_ENV
- echo STEP_START=$(date +%s) >> $GITHUB_ENV
- - name: Checkout Source
- uses: actions/checkout@v2
- if: ${{ github.repository_owner == 'puppetlabs' }}
-
- - name: Activate Ruby 2.7
- uses: ruby/setup-ruby@v1
- if: ${{ github.repository_owner == 'puppetlabs' }}
- with:
- ruby-version: "2.7"
- bundler-cache: true
-
- - name: Print bundle environment
- if: ${{ github.repository_owner == 'puppetlabs' }}
- run: |
- echo ::group::bundler environment
- buildevents cmd $TRACE_ID $STEP_ID 'bundle env' -- bundle env
- echo ::endgroup::
- - name: "Honeycomb: Record Setup Environment time"
- if: ${{ github.repository_owner == 'puppetlabs' }}
- run: |
- buildevents step $TRACE_ID $STEP_ID $STEP_START 'Setup Environment'
- echo STEP_ID=Setup-Acceptance-Test-Matrix >> $GITHUB_ENV
- echo STEP_START=$(date +%s) >> $GITHUB_ENV
- - name: Run Static & Syntax Tests
- if: ${{ github.repository_owner == 'puppetlabs' }}
- run: |
- buildevents cmd $TRACE_ID $STEP_ID 'static_syntax_checks' -- bundle exec rake syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop
-
- - name: Setup Spec Test Matrix
- id: get-matrix
- run: |
- if [ '${{ github.repository_owner }}' == 'puppetlabs' ]; then
- buildevents cmd $TRACE_ID $STEP_ID matrix_from_metadata -- bundle exec matrix_from_metadata_v2
- else
- echo "::set-output name=spec_matrix::{}"
- fi
- - name: "Honeycomb: Record Setup Test Matrix time"
- if: ${{ always() }}
- run: |
- buildevents step $TRACE_ID $STEP_ID $STEP_START 'Setup Test Matrix'
- Spec:
- name: "Spec Tests (Puppet: ${{matrix.puppet_version}}, Ruby Ver: ${{matrix.ruby_version}})"
- needs:
- - setup_matrix
- if: ${{ needs.setup_matrix.outputs.spec_matrix != '{}' }}
-
- runs-on: ubuntu-20.04
- strategy:
- fail-fast: false
- matrix: ${{fromJson(needs.setup_matrix.outputs.spec_matrix)}}
-
- env:
- BUILDEVENT_FILE: '../buildevents.txt'
- PUPPET_GEM_VERSION: ${{ matrix.puppet_version }}
- FACTER_GEM_VERSION: 'https://github.com/puppetlabs/facter#main'
-
- steps:
- - run: |
- echo "SANITIZED_PUPPET_VERSION=$(echo '${{ matrix.puppet_version }}' | sed 's/~> //g')" >> $GITHUB_ENV
-
- - run: |
- echo 'puppet_version=${{ env.SANITIZED_PUPPET_VERSION }}' >> $BUILDEVENT_FILE
- - name: "Honeycomb: Start first step"
- run: |
- echo "STEP_ID=${{ env.SANITIZED_PUPPET_VERSION }}-spec" >> $GITHUB_ENV
- echo STEP_START=$(date +%s) >> $GITHUB_ENV
-
- - name: "Honeycomb: Start recording"
- uses: puppetlabs/kvrhdn-gha-buildevents@pdk-templates-v1
- with:
- apikey: ${{ env.HONEYCOMB_WRITEKEY }}
- dataset: ${{ env.HONEYCOMB_DATASET }}
- job-status: ${{ job.status }}
- matrix-key: ${{ env.SANITIZED_PUPPET_VERSION }}
- - name: Checkout Source
- uses: actions/checkout@v2
-
- - name: "Activate Ruby ${{ matrix.ruby_version }}"
- uses: ruby/setup-ruby@v1
- with:
- ruby-version: ${{matrix.ruby_version}}
- bundler-cache: true
-
- - name: Print bundle environment
- run: |
- echo ::group::bundler environment
- buildevents cmd $TRACE_ID $STEP_ID 'bundle env' -- bundle env
- echo ::endgroup::
-
-
- - name: Run parallel_spec tests
- run: |
- buildevents cmd $TRACE_ID $STEP_ID 'rake parallel_spec Puppet ${{ matrix.puppet_version }}, Ruby ${{ matrix.ruby_version }}' -- bundle exec rake parallel_spec
diff --git a/.gitpod.Dockerfile b/.gitpod.Dockerfile
deleted file mode 100644
index 0814c5e..0000000
--- a/.gitpod.Dockerfile
+++ /dev/null
@@ -1,18 +0,0 @@
-FROM gitpod/workspace-full
-RUN sudo wget https://apt.puppet.com/puppet-tools-release-bionic.deb && \
- wget https://apt.puppetlabs.com/puppet6-release-bionic.deb && \
- sudo dpkg -i puppet6-release-bionic.deb && \
- sudo dpkg -i puppet-tools-release-bionic.deb && \
- sudo apt-get update && \
- sudo apt-get install -y pdk zsh puppet-agent && \
- sudo apt-get clean && \
- sudo rm -rf /var/lib/apt/lists/*
-RUN sudo usermod -s $(which zsh) gitpod && \
- sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" && \
- echo "plugins=(git gitignore github gem pip bundler python ruby docker docker-compose)" >> /home/gitpod/.zshrc && \
- echo 'PATH="$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/opt/puppetlabs/bin:/opt/puppetlabs/puppet/bin"' >> /home/gitpod/.zshrc && \
- sudo /opt/puppetlabs/puppet/bin/gem install puppet-debugger hub -N && \
- mkdir -p /home/gitpod/.config/puppet && \
- /opt/puppetlabs/puppet/bin/ruby -r yaml -e "puts ({'disabled' => true}).to_yaml" > /home/gitpod/.config/puppet/analytics.yml
-RUN rm -f puppet6-release-bionic.deb puppet-tools-release-bionic.deb
-ENTRYPOINT /usr/bin/zsh
diff --git a/.gitpod.yml b/.gitpod.yml
deleted file mode 100644
index 9d89d9f..0000000
--- a/.gitpod.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-image:
- file: .gitpod.Dockerfile
-
-tasks:
- - init: pdk bundle install
-
-vscode:
- extensions:
- - puppet.puppet-vscode@1.2.0:f5iEPbmOj6FoFTOV6q8LTg==
diff --git a/.pdkignore b/.pdkignore
new file mode 100644
index 0000000..c538bea
--- /dev/null
+++ b/.pdkignore
@@ -0,0 +1,47 @@
+.git/
+.*.sw[op]
+.metadata
+.yardoc
+.yardwarns
+*.iml
+/.bundle/
+/.idea/
+/.vagrant/
+/coverage/
+/bin/
+/doc/
+/Gemfile.local
+/Gemfile.lock
+/junit/
+/log/
+/pkg/
+/spec/fixtures/manifests/
+/spec/fixtures/modules/
+/tmp/
+/vendor/
+/convert_report.txt
+/update_report.txt
+.DS_Store
+.project
+.envrc
+/inventory.yaml
+/spec/fixtures/litmus_inventory.yaml
+/appveyor.yml
+/.editorconfig
+/.fixtures.yml
+/Gemfile
+/.gitattributes
+/.gitignore
+/.gitlab-ci.yml
+/.pdkignore
+/.puppet-lint.rc
+/Rakefile
+/rakelib/
+/.rspec
+/.rubocop.yml
+/.travis.yml
+/.yardopts
+/spec/
+/.vscode/
+/.sync.yml
+/.devcontainer/
diff --git a/.puppet-lint.rc b/.puppet-lint.rc
new file mode 100644
index 0000000..6d61fb0
--- /dev/null
+++ b/.puppet-lint.rc
@@ -0,0 +1,2 @@
+--relative
+--no-anchor_resource-check
diff --git a/.rspec b/.rspec
new file mode 100644
index 0000000..16f9cdb
--- /dev/null
+++ b/.rspec
@@ -0,0 +1,2 @@
+--color
+--format documentation
diff --git a/.rubocop.yml b/.rubocop.yml
new file mode 100644
index 0000000..31e8248
--- /dev/null
+++ b/.rubocop.yml
@@ -0,0 +1,519 @@
+---
+require:
+- rubocop-performance
+- rubocop-rspec
+AllCops:
+ DisplayCopNames: true
+ TargetRubyVersion: '2.5'
+ Include:
+ - "**/*.rb"
+ Exclude:
+ - bin/*
+ - ".vendor/**/*"
+ - "**/Gemfile"
+ - "**/Rakefile"
+ - pkg/**/*
+ - spec/fixtures/**/*
+ - vendor/**/*
+ - "**/Puppetfile"
+ - "**/Vagrantfile"
+ - "**/Guardfile"
+Layout/LineLength:
+ Description: People have wide screens, use them.
+ Max: 200
+RSpec/BeforeAfterAll:
+ Description: Beware of using after(:all) as it may cause state to leak between tests.
+ A necessary evil in acceptance testing.
+ Exclude:
+ - spec/acceptance/**/*.rb
+RSpec/HookArgument:
+ Description: Prefer explicit :each argument, matching existing module's style
+ EnforcedStyle: each
+RSpec/DescribeSymbol:
+ Exclude:
+ - spec/unit/facter/**/*.rb
+Style/BlockDelimiters:
+ Description: Prefer braces for chaining. Mostly an aesthetical choice. Better to
+ be consistent then.
+ EnforcedStyle: braces_for_chaining
+Style/ClassAndModuleChildren:
+ Description: Compact style reduces the required amount of indentation.
+ EnforcedStyle: compact
+Style/EmptyElse:
+ Description: Enforce against empty else clauses, but allow `nil` for clarity.
+ EnforcedStyle: empty
+Style/FormatString:
+ Description: Following the main puppet project's style, prefer the % format format.
+ EnforcedStyle: percent
+Style/FormatStringToken:
+ Description: Following the main puppet project's style, prefer the simpler template
+ tokens over annotated ones.
+ EnforcedStyle: template
+Style/Lambda:
+ Description: Prefer the keyword for easier discoverability.
+ EnforcedStyle: literal
+Style/RegexpLiteral:
+ Description: Community preference. See https://github.com/voxpupuli/modulesync_config/issues/168
+ EnforcedStyle: percent_r
+Style/TernaryParentheses:
+ Description: Checks for use of parentheses around ternary conditions. Enforce parentheses
+ on complex expressions for better readability, but seriously consider breaking
+ it up.
+ EnforcedStyle: require_parentheses_when_complex
+Style/TrailingCommaInArguments:
+ Description: Prefer always trailing comma on multiline argument lists. This makes
+ diffs, and re-ordering nicer.
+ EnforcedStyleForMultiline: comma
+Style/TrailingCommaInArrayLiteral:
+ Description: Prefer always trailing comma on multiline literals. This makes diffs,
+ and re-ordering nicer.
+ EnforcedStyleForMultiline: comma
+Style/SymbolArray:
+ Description: Using percent style obscures symbolic intent of array's contents.
+ EnforcedStyle: brackets
+RSpec/MessageSpies:
+ EnforcedStyle: receive
+Style/Documentation:
+ Exclude:
+ - lib/puppet/parser/functions/**/*
+ - spec/**/*
+Style/WordArray:
+ EnforcedStyle: brackets
+Performance/AncestorsInclude:
+ Enabled: true
+Performance/BigDecimalWithNumericArgument:
+ Enabled: true
+Performance/BlockGivenWithExplicitBlock:
+ Enabled: true
+Performance/CaseWhenSplat:
+ Enabled: true
+Performance/ConstantRegexp:
+ Enabled: true
+Performance/MethodObjectAsBlock:
+ Enabled: true
+Performance/RedundantSortBlock:
+ Enabled: true
+Performance/RedundantStringChars:
+ Enabled: true
+Performance/ReverseFirst:
+ Enabled: true
+Performance/SortReverse:
+ Enabled: true
+Performance/Squeeze:
+ Enabled: true
+Performance/StringInclude:
+ Enabled: true
+Performance/Sum:
+ Enabled: true
+Style/CollectionMethods:
+ Enabled: true
+Style/MethodCalledOnDoEndBlock:
+ Enabled: true
+Style/StringMethods:
+ Enabled: true
+Bundler/InsecureProtocolSource:
+ Enabled: false
+Gemspec/DuplicatedAssignment:
+ Enabled: false
+Gemspec/OrderedDependencies:
+ Enabled: false
+Gemspec/RequiredRubyVersion:
+ Enabled: false
+Gemspec/RubyVersionGlobalsUsage:
+ Enabled: false
+Layout/ArgumentAlignment:
+ Enabled: false
+Layout/BeginEndAlignment:
+ Enabled: false
+Layout/ClosingHeredocIndentation:
+ Enabled: false
+Layout/EmptyComment:
+ Enabled: false
+Layout/EmptyLineAfterGuardClause:
+ Enabled: false
+Layout/EmptyLinesAroundArguments:
+ Enabled: false
+Layout/EmptyLinesAroundAttributeAccessor:
+ Enabled: false
+Layout/EndOfLine:
+ Enabled: false
+Layout/FirstArgumentIndentation:
+ Enabled: false
+Layout/HashAlignment:
+ Enabled: false
+Layout/HeredocIndentation:
+ Enabled: false
+Layout/LeadingEmptyLines:
+ Enabled: false
+Layout/SpaceAroundMethodCallOperator:
+ Enabled: false
+Layout/SpaceInsideArrayLiteralBrackets:
+ Enabled: false
+Layout/SpaceInsideReferenceBrackets:
+ Enabled: false
+Lint/BigDecimalNew:
+ Enabled: false
+Lint/BooleanSymbol:
+ Enabled: false
+Lint/ConstantDefinitionInBlock:
+ Enabled: false
+Lint/DeprecatedOpenSSLConstant:
+ Enabled: false
+Lint/DisjunctiveAssignmentInConstructor:
+ Enabled: false
+Lint/DuplicateElsifCondition:
+ Enabled: false
+Lint/DuplicateRequire:
+ Enabled: false
+Lint/DuplicateRescueException:
+ Enabled: false
+Lint/EmptyConditionalBody:
+ Enabled: false
+Lint/EmptyFile:
+ Enabled: false
+Lint/ErbNewArguments:
+ Enabled: false
+Lint/FloatComparison:
+ Enabled: false
+Lint/HashCompareByIdentity:
+ Enabled: false
+Lint/IdentityComparison:
+ Enabled: false
+Lint/InterpolationCheck:
+ Enabled: false
+Lint/MissingCopEnableDirective:
+ Enabled: false
+Lint/MixedRegexpCaptureTypes:
+ Enabled: false
+Lint/NestedPercentLiteral:
+ Enabled: false
+Lint/NonDeterministicRequireOrder:
+ Enabled: false
+Lint/OrderedMagicComments:
+ Enabled: false
+Lint/OutOfRangeRegexpRef:
+ Enabled: false
+Lint/RaiseException:
+ Enabled: false
+Lint/RedundantCopEnableDirective:
+ Enabled: false
+Lint/RedundantRequireStatement:
+ Enabled: false
+Lint/RedundantSafeNavigation:
+ Enabled: false
+Lint/RedundantWithIndex:
+ Enabled: false
+Lint/RedundantWithObject:
+ Enabled: false
+Lint/RegexpAsCondition:
+ Enabled: false
+Lint/ReturnInVoidContext:
+ Enabled: false
+Lint/SafeNavigationConsistency:
+ Enabled: false
+Lint/SafeNavigationWithEmpty:
+ Enabled: false
+Lint/SelfAssignment:
+ Enabled: false
+Lint/SendWithMixinArgument:
+ Enabled: false
+Lint/ShadowedArgument:
+ Enabled: false
+Lint/StructNewOverride:
+ Enabled: false
+Lint/ToJSON:
+ Enabled: false
+Lint/TopLevelReturnWithArgument:
+ Enabled: false
+Lint/TrailingCommaInAttributeDeclaration:
+ Enabled: false
+Lint/UnreachableLoop:
+ Enabled: false
+Lint/UriEscapeUnescape:
+ Enabled: false
+Lint/UriRegexp:
+ Enabled: false
+Lint/UselessMethodDefinition:
+ Enabled: false
+Lint/UselessTimes:
+ Enabled: false
+Metrics/AbcSize:
+ Enabled: false
+Metrics/BlockLength:
+ Enabled: false
+Metrics/BlockNesting:
+ Enabled: false
+Metrics/ClassLength:
+ Enabled: false
+Metrics/CyclomaticComplexity:
+ Enabled: false
+Metrics/MethodLength:
+ Enabled: false
+Metrics/ModuleLength:
+ Enabled: false
+Metrics/ParameterLists:
+ Enabled: false
+Metrics/PerceivedComplexity:
+ Enabled: false
+Migration/DepartmentName:
+ Enabled: false
+Naming/AccessorMethodName:
+ Enabled: false
+Naming/BlockParameterName:
+ Enabled: false
+Naming/HeredocDelimiterCase:
+ Enabled: false
+Naming/HeredocDelimiterNaming:
+ Enabled: false
+Naming/MemoizedInstanceVariableName:
+ Enabled: false
+Naming/MethodParameterName:
+ Enabled: false
+Naming/RescuedExceptionsVariableName:
+ Enabled: false
+Naming/VariableNumber:
+ Enabled: false
+Performance/BindCall:
+ Enabled: false
+Performance/DeletePrefix:
+ Enabled: false
+Performance/DeleteSuffix:
+ Enabled: false
+Performance/InefficientHashSearch:
+ Enabled: false
+Performance/UnfreezeString:
+ Enabled: false
+Performance/UriDefaultParser:
+ Enabled: false
+RSpec/Be:
+ Enabled: false
+RSpec/Capybara/CurrentPathExpectation:
+ Enabled: false
+RSpec/Capybara/FeatureMethods:
+ Enabled: false
+RSpec/Capybara/VisibilityMatcher:
+ Enabled: false
+RSpec/ContextMethod:
+ Enabled: false
+RSpec/ContextWording:
+ Enabled: false
+RSpec/DescribeClass:
+ Enabled: false
+RSpec/EmptyHook:
+ Enabled: false
+RSpec/EmptyLineAfterExample:
+ Enabled: false
+RSpec/EmptyLineAfterExampleGroup:
+ Enabled: false
+RSpec/EmptyLineAfterHook:
+ Enabled: false
+RSpec/ExampleLength:
+ Enabled: false
+RSpec/ExampleWithoutDescription:
+ Enabled: false
+RSpec/ExpectChange:
+ Enabled: false
+RSpec/ExpectInHook:
+ Enabled: false
+RSpec/FactoryBot/AttributeDefinedStatically:
+ Enabled: false
+RSpec/FactoryBot/CreateList:
+ Enabled: false
+RSpec/FactoryBot/FactoryClassName:
+ Enabled: false
+RSpec/HooksBeforeExamples:
+ Enabled: false
+RSpec/ImplicitBlockExpectation:
+ Enabled: false
+RSpec/ImplicitSubject:
+ Enabled: false
+RSpec/LeakyConstantDeclaration:
+ Enabled: false
+RSpec/LetBeforeExamples:
+ Enabled: false
+RSpec/MissingExampleGroupArgument:
+ Enabled: false
+RSpec/MultipleExpectations:
+ Enabled: false
+RSpec/MultipleMemoizedHelpers:
+ Enabled: false
+RSpec/MultipleSubjects:
+ Enabled: false
+RSpec/NestedGroups:
+ Enabled: false
+RSpec/PredicateMatcher:
+ Enabled: false
+RSpec/ReceiveCounts:
+ Enabled: false
+RSpec/ReceiveNever:
+ Enabled: false
+RSpec/RepeatedExampleGroupBody:
+ Enabled: false
+RSpec/RepeatedExampleGroupDescription:
+ Enabled: false
+RSpec/RepeatedIncludeExample:
+ Enabled: false
+RSpec/ReturnFromStub:
+ Enabled: false
+RSpec/SharedExamples:
+ Enabled: false
+RSpec/StubbedMock:
+ Enabled: false
+RSpec/UnspecifiedException:
+ Enabled: false
+RSpec/VariableDefinition:
+ Enabled: false
+RSpec/VoidExpect:
+ Enabled: false
+RSpec/Yield:
+ Enabled: false
+Security/Open:
+ Enabled: false
+Style/AccessModifierDeclarations:
+ Enabled: false
+Style/AccessorGrouping:
+ Enabled: false
+Style/AsciiComments:
+ Enabled: false
+Style/BisectedAttrAccessor:
+ Enabled: false
+Style/CaseLikeIf:
+ Enabled: false
+Style/ClassEqualityComparison:
+ Enabled: false
+Style/ColonMethodDefinition:
+ Enabled: false
+Style/CombinableLoops:
+ Enabled: false
+Style/CommentedKeyword:
+ Enabled: false
+Style/Dir:
+ Enabled: false
+Style/DoubleCopDisableDirective:
+ Enabled: false
+Style/EmptyBlockParameter:
+ Enabled: false
+Style/EmptyLambdaParameter:
+ Enabled: false
+Style/Encoding:
+ Enabled: false
+Style/EvalWithLocation:
+ Enabled: false
+Style/ExpandPathArguments:
+ Enabled: false
+Style/ExplicitBlockArgument:
+ Enabled: false
+Style/ExponentialNotation:
+ Enabled: false
+Style/FloatDivision:
+ Enabled: false
+Style/FrozenStringLiteralComment:
+ Enabled: false
+Style/GlobalStdStream:
+ Enabled: false
+Style/HashAsLastArrayItem:
+ Enabled: false
+Style/HashLikeCase:
+ Enabled: false
+Style/HashTransformKeys:
+ Enabled: false
+Style/HashTransformValues:
+ Enabled: false
+Style/IfUnlessModifier:
+ Enabled: false
+Style/KeywordParametersOrder:
+ Enabled: false
+Style/MinMax:
+ Enabled: false
+Style/MixinUsage:
+ Enabled: false
+Style/MultilineWhenThen:
+ Enabled: false
+Style/NegatedUnless:
+ Enabled: false
+Style/NumericPredicate:
+ Enabled: false
+Style/OptionalBooleanParameter:
+ Enabled: false
+Style/OrAssignment:
+ Enabled: false
+Style/RandomWithOffset:
+ Enabled: false
+Style/RedundantAssignment:
+ Enabled: false
+Style/RedundantCondition:
+ Enabled: false
+Style/RedundantConditional:
+ Enabled: false
+Style/RedundantFetchBlock:
+ Enabled: false
+Style/RedundantFileExtensionInRequire:
+ Enabled: false
+Style/RedundantRegexpCharacterClass:
+ Enabled: false
+Style/RedundantRegexpEscape:
+ Enabled: false
+Style/RedundantSelfAssignment:
+ Enabled: false
+Style/RedundantSort:
+ Enabled: false
+Style/RescueStandardError:
+ Enabled: false
+Style/SingleArgumentDig:
+ Enabled: false
+Style/SlicingWithRange:
+ Enabled: false
+Style/SoleNestedConditional:
+ Enabled: false
+Style/StderrPuts:
+ Enabled: false
+Style/StringConcatenation:
+ Enabled: false
+Style/Strip:
+ Enabled: false
+Style/SymbolProc:
+ Enabled: false
+Style/TrailingBodyOnClass:
+ Enabled: false
+Style/TrailingBodyOnMethodDefinition:
+ Enabled: false
+Style/TrailingBodyOnModule:
+ Enabled: false
+Style/TrailingCommaInHashLiteral:
+ Enabled: false
+Style/TrailingMethodEndStatement:
+ Enabled: false
+Style/UnpackFirst:
+ Enabled: false
+Lint/DuplicateBranch:
+ Enabled: false
+Lint/DuplicateRegexpCharacterClassElement:
+ Enabled: false
+Lint/EmptyBlock:
+ Enabled: false
+Lint/EmptyClass:
+ Enabled: false
+Lint/NoReturnInBeginEndBlocks:
+ Enabled: false
+Lint/ToEnumArguments:
+ Enabled: false
+Lint/UnexpectedBlockArity:
+ Enabled: false
+Lint/UnmodifiedReduceAccumulator:
+ Enabled: false
+Performance/CollectionLiteralInLoop:
+ Enabled: false
+Style/ArgumentsForwarding:
+ Enabled: false
+Style/CollectionCompact:
+ Enabled: false
+Style/DocumentDynamicEvalDefinition:
+ Enabled: false
+Style/NegatedIfElseCondition:
+ Enabled: false
+Style/NilLambda:
+ Enabled: false
+Style/RedundantArgument:
+ Enabled: false
+Style/SwapValues:
+ Enabled: false
diff --git a/.sync.yml b/.sync.yml
new file mode 100644
index 0000000..a096152
--- /dev/null
+++ b/.sync.yml
@@ -0,0 +1,37 @@
+---
+".gitlab-ci.yml":
+ delete: true
+appveyor.yml:
+ delete: true
+
+Gemfile:
+ optional:
+ ":development":
+ - gem: github_changelog_generator
+ version: '= 1.15.2'
+Rakefile:
+ changelog_max_issues: 500
+spec/spec_helper.rb:
+ mock_with: ":rspec"
+ coverage_report: true
+.gitpod.Dockerfile:
+ unmanaged: false
+.gitpod.yml:
+ unmanaged: false
+.github/workflows/pr_test.yml:
+ unmanaged: false
+.github/workflows/nightly.yml:
+ unmanaged: false
+.github/workflows/spec.yml:
+ checks: 'syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop'
+ unmanaged: false
+.github/workflows/release.yml:
+ unmanaged: false
+.github/workflows/auto_release.yml:
+ unmanaged: false
+.travis.yml:
+ delete: true
+changelog_since_tag: '5.0.1'
+Rakefile:
+ extra_disabled_lint_checks:
+ - anchor_resource
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 0000000..2f1e4f7
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,6 @@
+{
+ "recommendations": [
+ "puppet.puppet-vscode",
+ "rebornix.Ruby"
+ ]
+}
diff --git a/.yardopts b/.yardopts
new file mode 100644
index 0000000..29c933b
--- /dev/null
+++ b/.yardopts
@@ -0,0 +1 @@
+--markup markdown
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..a84b5ee
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,73 @@
+source ENV['GEM_SOURCE'] || 'https://rubygems.org'
+
+def location_for(place_or_version, fake_version = nil)
+ git_url_regex = %r{\A(?<url>(https?|git)[:@][^#]*)(#(?<branch>.*))?}
+ file_url_regex = %r{\Afile:\/\/(?<path>.*)}
+
+ if place_or_version && (git_url = place_or_version.match(git_url_regex))
+ [fake_version, { git: git_url[:url], branch: git_url[:branch], require: false }].compact
+ elsif place_or_version && (file_url = place_or_version.match(file_url_regex))
+ ['>= 0', { path: File.expand_path(file_url[:path]), require: false }]
+ else
+ [place_or_version, { require: false }]
+ end
+end
+
+group :development do
+ gem "json", '= 2.1.0', require: false if Gem::Requirement.create(['>= 2.5.0', '< 2.7.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
+ gem "json", '= 2.3.0', require: false if Gem::Requirement.create(['>= 2.7.0', '< 3.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
+ gem "json", '= 2.5.1', require: false if Gem::Requirement.create(['>= 3.0.0', '< 3.0.5']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
+ gem "json", '= 2.6.1', require: false if Gem::Requirement.create(['>= 3.1.0', '< 3.1.3']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
+ gem "json", '= 2.6.3', require: false if Gem::Requirement.create(['>= 3.2.0', '< 4.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
+ gem "voxpupuli-puppet-lint-plugins", '~> 3.1', require: false
+ gem "facterdb", '~> 1.18', require: false
+ gem "metadata-json-lint", '>= 2.0.2', '< 4.0.0', require: false
+ gem "puppetlabs_spec_helper", '>= 3.0.0', '< 5.0.0', require: false
+ gem "rspec-puppet-facts", '~> 2.0', require: false
+ gem "codecov", '~> 0.2', require: false
+ gem "dependency_checker", '~> 0.2', require: false
+ gem "parallel_tests", '~> 3.4', require: false
+ gem "pry", '~> 0.10', require: false
+ gem "simplecov-console", '~> 0.5', require: false
+ gem "puppet-debugger", '~> 1.0', require: false
+ gem "rubocop", '= 1.6.1', require: false
+ gem "rubocop-performance", '= 1.9.1', require: false
+ gem "rubocop-rspec", '= 2.0.1', require: false
+ gem "rb-readline", '= 0.5.5', require: false, platforms: [:mswin, :mingw, :x64_mingw]
+ gem "github_changelog_generator", '= 1.15.2', require: false
+end
+group :system_tests do
+ gem "puppet_litmus", '< 1.0.0', require: false, platforms: [:ruby]
+ gem "serverspec", '~> 2.41', require: false
+end
+
+puppet_version = ENV['PUPPET_GEM_VERSION']
+facter_version = ENV['FACTER_GEM_VERSION']
+hiera_version = ENV['HIERA_GEM_VERSION']
+
+gems = {}
+
+gems['puppet'] = location_for(puppet_version)
+
+# If facter or hiera versions have been specified via the environment
+# variables
+
+gems['facter'] = location_for(facter_version) if facter_version
+gems['hiera'] = location_for(hiera_version) if hiera_version
+
+gems.each do |gem_name, gem_params|
+ gem gem_name, *gem_params
+end
+
+# Evaluate Gemfile.local and ~/.gemfile if they exist
+extra_gemfiles = [
+ "#{__FILE__}.local",
+ File.join(Dir.home, '.gemfile'),
+]
+
+extra_gemfiles.each do |gemfile|
+ if File.file?(gemfile) && File.readable?(gemfile)
+ eval(File.read(gemfile), binding)
+ end
+end
+# vim: syntax=ruby
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..8fdf11b
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,91 @@
+# frozen_string_literal: true
+
+require 'bundler'
+require 'puppet_litmus/rake_tasks' if Bundler.rubygems.find_name('puppet_litmus').any?
+require 'puppetlabs_spec_helper/rake_tasks'
+require 'puppet-syntax/tasks/puppet-syntax'
+require 'puppet_blacksmith/rake_tasks' if Bundler.rubygems.find_name('puppet-blacksmith').any?
+require 'github_changelog_generator/task' if Bundler.rubygems.find_name('github_changelog_generator').any?
+require 'puppet-strings/tasks' if Bundler.rubygems.find_name('puppet-strings').any?
+
+def changelog_user
+ return unless Rake.application.top_level_tasks.include? "changelog"
+ returnVal = nil || JSON.load(File.read('metadata.json'))['author']
+ raise "unable to find the changelog_user in .sync.yml, or the author in metadata.json" if returnVal.nil?
+ puts "GitHubChangelogGenerator user:#{returnVal}"
+ returnVal
+end
+
+def changelog_project
+ return unless Rake.application.top_level_tasks.include? "changelog"
+
+ returnVal = nil
+ returnVal ||= begin
+ metadata_source = JSON.load(File.read('metadata.json'))['source']
+ metadata_source_match = metadata_source && metadata_source.match(%r{.*\/([^\/]*?)(?:\.git)?\Z})
+
+ metadata_source_match && metadata_source_match[1]
+ end
+
+ raise "unable to find the changelog_project in .sync.yml or calculate it from the source in metadata.json" if returnVal.nil?
+
+ puts "GitHubChangelogGenerator project:#{returnVal}"
+ returnVal
+end
+
+def changelog_future_release
+ return unless Rake.application.top_level_tasks.include? "changelog"
+ returnVal = "v%s" % JSON.load(File.read('metadata.json'))['version']
+ raise "unable to find the future_release (version) in metadata.json" if returnVal.nil?
+ puts "GitHubChangelogGenerator future_release:#{returnVal}"
+ returnVal
+end
+
+PuppetLint.configuration.send('disable_relative')
+PuppetLint.configuration.send('disable_anchor_resource')
+
+
+if Bundler.rubygems.find_name('github_changelog_generator').any?
+ GitHubChangelogGenerator::RakeTask.new :changelog do |config|
+ raise "Set CHANGELOG_GITHUB_TOKEN environment variable eg 'export CHANGELOG_GITHUB_TOKEN=valid_token_here'" if Rake.application.top_level_tasks.include? "changelog" and ENV['CHANGELOG_GITHUB_TOKEN'].nil?
+ config.user = "#{changelog_user}"
+ config.project = "#{changelog_project}"
+ config.since_tag = "5.0.1"
+ config.future_release = "#{changelog_future_release}"
+ config.exclude_labels = ['maintenance']
+ config.header = "# Change log\n\nAll notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org)."
+ config.add_pr_wo_labels = true
+ config.issues = false
+ config.merge_prefix = "### UNCATEGORIZED PRS; LABEL THEM ON GITHUB"
+ config.configure_sections = {
+ "Changed" => {
+ "prefix" => "### Changed",
+ "labels" => ["backwards-incompatible"],
+ },
+ "Added" => {
+ "prefix" => "### Added",
+ "labels" => ["enhancement", "feature"],
+ },
+ "Fixed" => {
+ "prefix" => "### Fixed",
+ "labels" => ["bug", "documentation", "bugfix"],
+ },
+ }
+ end
+else
+ desc 'Generate a Changelog from GitHub'
+ task :changelog do
+ raise <<EOM
+The changelog tasks depends on recent features of the github_changelog_generator gem.
+Please manually add it to your .sync.yml for now, and run `pdk update`:
+---
+Gemfile:
+ optional:
+ ':development':
+ - gem: 'github_changelog_generator'
+ version: '~> 1.15'
+ condition: "Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.3.0')"
+EOM
+ end
+end
+
diff --git a/debian/changelog b/debian/changelog
index ad253ed..ac33738 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+puppet-module-puppetlabs-apt (9.0.1+git20230201.1.790df53-1) UNRELEASED; urgency=low
+
+ * New upstream snapshot.
+
+ -- Debian Janitor <janitor@jelmer.uk> Thu, 09 Feb 2023 16:38:04 -0000
+
puppet-module-puppetlabs-apt (9.0.1-1) unstable; urgency=medium
* Team upload.
diff --git a/manifests/mark.pp b/manifests/mark.pp
index 08e396c..b2146b0 100644
--- a/manifests/mark.pp
+++ b/manifests/mark.pp
@@ -8,7 +8,7 @@
define apt::mark (
Enum['auto','manual','hold','unhold'] $setting,
) {
- if $title !~ /^[a-zA-Z0-9\-_]+$/ {
+ if $title !~ /^[a-z0-9][a-z0-9.+\-]+$/ {
fail("Invalid package name: ${title}")
}
diff --git a/manifests/ppa.pp b/manifests/ppa.pp
index 4e5e775..2a5b4a8 100644
--- a/manifests/ppa.pp
+++ b/manifests/ppa.pp
@@ -40,7 +40,7 @@ define apt::ppa (
}
# Validate the resource name
- if $name !~ /^ppa:([a-zA-Z0-9\-_]+)\/([a-zA-z0-9\-_\.]+)$/ {
+ if $name !~ /^ppa:([a-zA-Z0-9\-_.]+)\/([a-zA-z0-9\-_\.]+)$/ {
fail("Invalid PPA name: ${name}")
}
diff --git a/manifests/source.pp b/manifests/source.pp
index b1be300..420d19d 100644
--- a/manifests/source.pp
+++ b/manifests/source.pp
@@ -143,7 +143,7 @@ define apt::source (
'comment' => $comment,
'includes' => $includes,
'options' => delete_undef_values({
- 'arch' => $architecture,
+ 'arch' => $_architecture,
'trusted' => $allow_unsigned ? { true => 'yes', false => undef },
'allow-insecure' => $allow_insecure ? { true => 'yes', false => undef },
'signed-by' => $keyring,
diff --git a/manifests/update.pp b/manifests/update.pp
index ef37f52..a9f2486 100644
--- a/manifests/update.pp
+++ b/manifests/update.pp
@@ -5,7 +5,7 @@
class apt::update {
assert_private()
- #TODO: to catch if $apt_update_last_success has the value of -1 here. If we
+ #TODO: to catch if apt_update_last_success has the value of -1 here. If we
#opt to do this, a info/warn would likely be all you'd need likely to happen
#on the first run, but if it's not run in awhile something is likely borked
#with apt and we'd want to know about it.
@@ -18,8 +18,8 @@ class apt::update {
#compare current date with the apt_update_last_success fact to determine
#if we should kick apt_update.
$daily_threshold = (Integer(Timestamp().strftime('%s')) - 86400)
- if $apt::apt_update_last_success {
- if $apt::apt_update_last_success + 0 < $daily_threshold {
+ if $facts['apt_update_last_success'] {
+ if $facts['apt_update_last_success'] + 0 < $daily_threshold {
$_kick_apt = true
} else {
$_kick_apt = false
@@ -33,8 +33,8 @@ class apt::update {
#compare current date with the apt_update_last_success fact to determine
#if we should kick apt_update.
$weekly_threshold = (Integer(Timestamp().strftime('%s')) - 604800)
- if $apt::apt_update_last_success {
- if ( $apt::apt_update_last_success + 0 < $weekly_threshold ) {
+ if $facts['apt_update_last_success'] {
+ if $facts['apt_update_last_success'] + 0 < $weekly_threshold {
$_kick_apt = true
} else {
$_kick_apt = false
diff --git a/metadata.json b/metadata.json
index ace916f..4de8a1c 100644
--- a/metadata.json
+++ b/metadata.json
@@ -37,6 +37,6 @@
}
],
"template-url": "https://github.com/puppetlabs/pdk-templates.git#main",
- "template-ref": "tags/2.6.0-0-gd0490b9",
+ "template-ref": "2.7.1-0-g9a16c87",
"pdk-version": "2.5.0"
}
diff --git a/spec/acceptance/01_apt_class_spec.rb b/spec/acceptance/01_apt_class_spec.rb
new file mode 100644
index 0000000..1b50c7b
--- /dev/null
+++ b/spec/acceptance/01_apt_class_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+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/spec/acceptance/apt_backports_spec.rb b/spec/acceptance/apt_backports_spec.rb
new file mode 100644
index 0000000..5c4dcce
--- /dev/null
+++ b/spec/acceptance/apt_backports_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper_acceptance'
+
+describe 'apt::backports' do
+ context 'when using defaults' do
+ let(:pp) do
+ <<-MANIFEST
+ include apt::backports
+ MANIFEST
+ end
+
+ it 'applies idempotently' do
+ idempotent_apply(pp)
+ end
+
+ it 'provides backports apt sources' do
+ run_shell('apt policy | grep --quiet backports')
+ end
+ end
+end
diff --git a/spec/acceptance/apt_key_provider_spec.rb b/spec/acceptance/apt_key_provider_spec.rb
new file mode 100644
index 0000000..ee4a4c8
--- /dev/null
+++ b/spec/acceptance/apt_key_provider_spec.rb
@@ -0,0 +1,915 @@
+# frozen_string_literal: true
+
+require 'spec_helper_acceptance'
+
+PUPPETLABS_GPG_KEY_SHORT_ID = 'EF8D349F'
+PUPPETLABS_GPG_KEY_LONG_ID = '7F438280EF8D349F'
+PUPPETLABS_GPG_KEY_FINGERPRINT = '6F6B15509CF8E59E6E469F327F438280EF8D349F'
+PUPPETLABS_APT_URL = 'apt.puppetlabs.com'
+PUPPETLABS_GPG_KEY_FILE = 'DEB-GPG-KEY-puppet'
+CENTOS_GPG_KEY_SHORT_ID = 'C105B9DE'
+CENTOS_GPG_KEY_LONG_ID = '0946FCA2C105B9DE'
+CENTOS_GPG_KEY_FINGERPRINT = 'C1DAC52D1664E8A4386DBA430946FCA2C105B9DE'
+CENTOS_REPO_URL = 'ftp.cvut.cz/centos'
+CENTOS_GPG_KEY_FILE = 'RPM-GPG-KEY-CentOS-6'
+PUPPETLABS_EXP_KEY_LONG_ID = '47B320EB4C7C375AA9DAE1A01054B7A24BD6EC30'
+PUPPETLABS_EXP_KEY_DATES = 'pub:e:4096:1:1054B7A24BD6EC30:2010-07-10:2017-01-05::-:Puppet Labs Release Key'
+SHOULD_NEVER_EXIST_ID = 'EF8D349F'
+KEY_CHECK_COMMAND = 'apt-key adv --no-tty --list-keys --with-colons --fingerprint | grep '
+PUPPETLABS_KEY_CHECK_COMMAND = "#{KEY_CHECK_COMMAND} #{PUPPETLABS_GPG_KEY_FINGERPRINT}"
+CENTOS_KEY_CHECK_COMMAND = "#{KEY_CHECK_COMMAND} #{CENTOS_GPG_KEY_FINGERPRINT}"
+PUPPETLABS_EXP_CHECK_COMMAND = 'apt-key list | grep -F -A 1 \'pub rsa4096 2010-07-10 [SC] [expired: 2017-01-05]\' | grep \'47B3 20EB 4C7C 375A A9DA E1A0 1054 B7A2 4BD6 EC30\''
+
+def install_key(key)
+ retry_on_error_matching do
+ run_shell("apt-key adv --no-tty --keyserver pgp.mit.edu --recv-keys #{key}")
+ end
+end
+
+def apply_manifest_twice(manifest_pp)
+ retry_on_error_matching do
+ apply_manifest(manifest_pp, catch_failures: true)
+ end
+ retry_on_error_matching do
+ apply_manifest(manifest_pp, catch_changes: true)
+ end
+end
+
+refresh_pp = <<-MANIFEST
+ apt_key { '#{PUPPETLABS_EXP_KEY_LONG_ID}':
+ id => '#{PUPPETLABS_EXP_KEY_LONG_ID}',
+ ensure => 'present',
+ content => '-----BEGIN PGP PUBLIC KEY BLOCK-----
+ Version: GnuPG v1
+
+ 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
+ fBt3Tu1IYpw=
+ =cXcR
+ -----END PGP PUBLIC KEY BLOCK-----'
+ }
+ 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
+
+hkp_pool_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_FINGERPRINT}',
+ ensure => 'present',
+ server => 'hkp://keyserver.ubuntu.com:80',
+ }
+ MANIFEST
+
+hkps_protocol_supported = host_inventory['facter']['os']['family'] =~ %r{Ubuntu}i && \
+ host_inventory['facter']['os']['release']['major'] =~ %r{^18\.04}
+
+if hkps_protocol_supported
+ hkps_ubuntu_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
+ ensure => 'present',
+ server => 'hkps://keyserver.ubuntu.com',
+ }
+ MANIFEST
+end
+
+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_with_weak_ssl_works_pp = <<-MANIFEST
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
+ ensure => 'present',
+ source => 'https://#{PUPPETLABS_APT_URL}/#{PUPPETLABS_GPG_KEY_FILE}',
+ weak_ssl => true,
+ }
+ 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
+
+refresh_true_pp = <<-MANIFEST
+ apt_key { '#{PUPPETLABS_EXP_KEY_LONG_ID}':
+ id => '#{PUPPETLABS_EXP_KEY_LONG_ID}',
+ ensure => 'present',
+ refresh => true,
+ }
+ MANIFEST
+
+refresh_false_pp = <<-MANIFEST
+ apt_key { '#{PUPPETLABS_EXP_KEY_LONG_ID}':
+ id => '#{PUPPETLABS_EXP_KEY_LONG_ID}',
+ ensure => 'present',
+ refresh => false,
+ }
+MANIFEST
+
+refresh_del_key_pp = <<-MANIFEST
+ apt_key { '#{PUPPETLABS_EXP_KEY_LONG_ID}':
+ ensure => 'absent',
+ }
+MANIFEST
+
+refresh_check_for_dirmngr_pp = <<-MANIFEST
+ package { 'dirmngr':
+ ensure => 'present',
+ }
+MANIFEST
+
+describe 'apt_key' do
+ before(:each) do
+ # Delete twice to make sure everything is cleaned
+ # up after the short key collision
+ run_shell("apt-key del #{PUPPETLABS_GPG_KEY_SHORT_ID}", expect_failures: true)
+ run_shell("apt-key del #{PUPPETLABS_GPG_KEY_SHORT_ID}", expect_failures: true)
+ end
+
+ describe 'ensure =>' do
+ ensure_present_pp = <<-MANIFEST
+ apt_key { 'centos':
+ id => '#{CENTOS_GPG_KEY_LONG_ID}',
+ ensure => 'present',
+ }
+ MANIFEST
+
+ ensure_absent_pp = <<-MANIFEST
+ apt_key { 'centos':
+ id => '#{CENTOS_GPG_KEY_LONG_ID}',
+ ensure => 'absent',
+ }
+ MANIFEST
+
+ it 'add an apt_key resource' do
+ apply_manifest_twice(ensure_present_pp)
+ end
+ it 'remove the apt_key resource' do
+ apply_manifest_twice(ensure_absent_pp)
+ 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 do
+ apply_manifest(gpg_key_pp, catch_failures: true)
+ end
+
+ apply_manifest(gpg_key_pp, catch_changes: true)
+ run_shell(PUPPETLABS_KEY_CHECK_COMMAND)
+ end
+ end
+
+ context 'with multiple keys' do
+ it 'runs without errors' do
+ apply_manifest_twice(multiple_keys_pp)
+ run_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 hkp://pgp.mit.edu:80' do
+ it 'works' do
+ retry_on_error_matching do
+ apply_manifest(hkp_pool_pp, catch_failures: true)
+ end
+
+ apply_manifest(hkp_pool_pp, catch_changes: true)
+ run_shell(PUPPETLABS_KEY_CHECK_COMMAND)
+ end
+ end
+
+ if hkps_protocol_supported
+ context 'with hkps://keyserver.ubuntu.com' do
+ it 'works' do
+ retry_on_error_matching do
+ apply_manifest(hkps_ubuntu_pp, catch_failures: true)
+ end
+
+ apply_manifest(hkps_ubuntu_pp, catch_changes: true)
+ run_shell(PUPPETLABS_KEY_CHECK_COMMAND)
+ end
+ 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|No name)})
+ 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)
+ run_shell(PUPPETLABS_KEY_CHECK_COMMAND)
+ end
+
+ it 'works with userinfo' do
+ apply_manifest_twice(http_works_userinfo_pp)
+ run_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
+
+ # disabled when running in travis, security issues prevent FTP
+ context 'with ftp://', unless: (ENV['TRAVIS'] == 'true') do
+ before(:each) do
+ run_shell("apt-key del #{CENTOS_GPG_KEY_LONG_ID}", expect_failures: true)
+ end
+
+ it 'works' do
+ apply_manifest_twice(ftp_works_pp)
+ run_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)
+ run_shell(PUPPETLABS_KEY_CHECK_COMMAND)
+ end
+
+ it 'works with weak ssl' do
+ apply_manifest_twice(https_with_weak_ssl_works_pp)
+ run_shell(PUPPETLABS_KEY_CHECK_COMMAND)
+ end
+
+ it 'works with userinfo' do
+ apply_manifest_twice(https_userinfo_pp)
+ run_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
+ run_shell("curl -o /tmp/puppetlabs-pubkey.gpg \
+ http://#{PUPPETLABS_APT_URL}/#{PUPPETLABS_GPG_KEY_FILE}")
+ end
+
+ after(:each) do
+ run_shell('rm /tmp/puppetlabs-pubkey.gpg')
+ end
+
+ it 'works' do
+ apply_manifest_twice(path_exists_pp)
+ run_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
+ run_shell('echo "here be dragons" > /tmp/fake-key.gpg')
+ end
+
+ after(:each) do
+ run_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)
+ run_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
+
+ describe 'refresh' do
+ # Ensure dirmngr package is installed
+ apply_manifest(refresh_check_for_dirmngr_pp, acceptable_exit_codes: [0, 2])
+
+ before(:each) do
+ # Delete the Puppet Labs Release Key and install an expired version of the key
+ apply_manifest(refresh_del_key_pp)
+ apply_manifest(refresh_pp, catch_failures: true)
+ end
+ context 'when refresh => true' do
+ it 'updates an expired key' do
+ apply_manifest(refresh_true_pp)
+ # Check key has been updated to new version
+ run_shell(PUPPETLABS_EXP_CHECK_COMMAND.to_s)
+ end
+ end
+ context 'when refresh => false' do
+ it 'does not replace an expired key' do
+ apply_manifest(refresh_false_pp)
+ # Expired key is present and has not been updated by the new version
+ run_shell(PUPPETLABS_EXP_CHECK_COMMAND.to_s, expect_failures: true)
+ end
+ end
+ end
+end
diff --git a/spec/acceptance/apt_spec.rb b/spec/acceptance/apt_spec.rb
new file mode 100644
index 0000000..7e4fe37
--- /dev/null
+++ b/spec/acceptance/apt_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'spec_helper_acceptance'
+
+everything_everything_pp = <<-MANIFEST
+ $sources = {
+ 'puppetlabs' => {
+ 'ensure' => present,
+ 'location' => 'http://apt.puppetlabs.com',
+ 'repos' => 'main',
+ 'key' => {
+ 'id' => '6F6B15509CF8E59E6E469F327F438280EF8D349F',
+ 'server' => 'keyserver.ubuntu.com',
+ },
+ },
+ }
+ class { 'apt':
+ update => {
+ 'frequency' => 'always',
+ 'timeout' => 400,
+ 'tries' => 3,
+ },
+ purge => {
+ 'sources.list' => true,
+ 'sources.list.d' => true,
+ 'preferences' => true,
+ 'preferences.d' => true,
+ 'apt.conf.d' => true,
+ },
+ sources => $sources,
+ }
+ MANIFEST
+
+describe 'apt class' do
+ context 'with reset' do
+ it 'fixes the sources.list' do
+ run_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 do
+ apply_manifest(everything_everything_pp, catch_failures: true)
+ end
+ end
+ it 'stills work' do
+ run_shell('apt-get update')
+ run_shell('apt-get -y --force-yes upgrade')
+ end
+ end
+
+ context 'with reset' do
+ it 'fixes the sources.list' do
+ run_shell('cp /tmp/sources.list /etc/apt')
+ end
+ end
+end
diff --git a/spec/acceptance/init_task_spec.rb b/spec/acceptance/init_task_spec.rb
new file mode 100644
index 0000000..02b3f34
--- /dev/null
+++ b/spec/acceptance/init_task_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+# run a test task
+require 'spec_helper_acceptance'
+
+describe 'apt tasks' do
+ describe 'update' do
+ it 'updates package lists' do
+ result = run_bolt_task('apt', 'action' => 'update')
+ expect(result.stdout).to contain(%r{Reading package lists})
+ end
+ end
+ describe 'upgrade' do
+ it 'upgrades packages' do
+ result = run_bolt_task('apt', 'action' => 'upgrade')
+ expect(result.stdout).to contain(%r{\d+ upgraded, \d+ newly installed, \d+ to remove and \d+ not upgraded})
+ end
+ end
+ describe 'dist-upgrade' do
+ it 'dist-upgrades packages' do
+ result = run_bolt_task('apt', 'action' => 'dist-upgrade')
+ expect(result.stdout).to contain(%r{\d+ upgraded, \d+ newly installed, \d+ to remove and \d+ not upgraded})
+ end
+ end
+ describe 'autoremove' do
+ it 'autoremoves obsolete packages' do
+ result = run_bolt_task('apt', 'action' => 'autoremove')
+ expect(result.stdout).to contain(%r{\d+ upgraded, \d+ newly installed, \d+ to remove and \d+ not upgraded})
+ end
+ end
+end
diff --git a/spec/classes/apt_backports_spec.rb b/spec/classes/apt_backports_spec.rb
new file mode 100644
index 0000000..6f6d530
--- /dev/null
+++ b/spec/classes/apt_backports_spec.rb
@@ -0,0 +1,292 @@
+# frozen_string_literal: true
+
+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: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__source('backports').with(location: 'http://deb.debian.org/debian',
+ repos: 'main contrib non-free',
+ release: 'stretch-backports',
+ pin: { 'priority' => 200, 'release' => 'stretch-backports' })
+ }
+ end
+ context 'with defaults on ubuntu' do
+ let(:facts) do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Ubuntu',
+ release: {
+ major: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'bionac',
+ id: 'Ubuntu',
+ },
+ },
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__source('backports').with(location: 'http://archive.ubuntu.com/ubuntu',
+ key: '630239CC130E1A7FD81A27B140976EAF437D05B5',
+ repos: 'main universe multiverse restricted',
+ release: 'bionac-backports',
+ pin: { 'priority' => 200, 'release' => 'bionac-backports' })
+ }
+ end
+ context 'with everything set' do
+ let(:facts) do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Ubuntu',
+ release: {
+ major: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'bionac',
+ id: 'Ubuntu',
+ },
+ },
+ }
+ 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: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'bionac',
+ id: 'Ubuntu',
+ },
+ },
+ }
+ 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',
+ },
+ distro: {
+ codename: 'qiana',
+ id: 'LinuxMint',
+ },
+ },
+ }
+ 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: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'bionac',
+ id: 'Ubuntu',
+ },
+ },
+ }
+ 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/spec/classes/apt_spec.rb b/spec/classes/apt_spec.rb
new file mode 100644
index 0000000..1a7513c
--- /dev/null
+++ b/spec/classes/apt_spec.rb
@@ -0,0 +1,713 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+sources_list = { ensure: 'file',
+ path: '/etc/apt/sources.list',
+ owner: 'root',
+ group: 'root',
+ notify: 'Class[Apt::Update]' }
+
+sources_list_d = { ensure: 'directory',
+ path: '/etc/apt/sources.list.d',
+ owner: 'root',
+ group: 'root',
+ purge: false,
+ recurse: false,
+ notify: 'Class[Apt::Update]' }
+
+preferences = { ensure: 'file',
+ path: '/etc/apt/preferences',
+ owner: 'root',
+ group: 'root',
+ notify: 'Class[Apt::Update]' }
+
+preferences_d = { ensure: 'directory',
+ path: '/etc/apt/preferences.d',
+ owner: 'root',
+ group: 'root',
+ purge: false,
+ recurse: false,
+ notify: 'Class[Apt::Update]' }
+
+apt_conf_d = { ensure: 'directory',
+ path: '/etc/apt/apt.conf.d',
+ owner: 'root',
+ group: 'root',
+ purge: false,
+ recurse: false,
+ notify: 'Class[Apt::Update]' }
+
+describe 'apt' do
+ let(:facts) do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Debian',
+ release: {
+ major: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ }
+ 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 {
+ is_expected.to contain_file('apt.conf.d').that_notifies('Class[Apt::Update]').only_with(apt_conf_d)
+ }
+
+ it { is_expected.to contain_file('/etc/apt/auth.conf').with_ensure('absent') }
+
+ 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',
+ 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 per-host[proxyscope]=proxyhost' do
+ let(:params) { { proxy: { 'host' => 'localhost', 'perhost' => [{ 'scope' => 'proxyscope', 'host' => 'proxyhost' }] } } }
+
+ it {
+ is_expected.to contain_apt__setting('conf-proxy').with(priority: '01').with_content(
+ %r{Acquire::http::proxy::proxyscope "http://proxyhost:8080/";},
+ )
+ }
+ end
+
+ context 'when host=localhost and per-host[proxyscope]=proxyhost:8081' do
+ let(:params) { { proxy: { 'host' => 'localhost', 'perhost' => [{ 'scope' => 'proxyscope', 'host' => 'proxyhost', 'port' => 8081 }] } } }
+
+ it {
+ is_expected.to contain_apt__setting('conf-proxy').with(priority: '01').with_content(
+ %r{Acquire::http::proxy::proxyscope "http://proxyhost:8081/";},
+ )
+ }
+ end
+
+ context 'when host=localhost and per-host[proxyscope]=[https]proxyhost' do
+ let(:params) { { proxy: { 'host' => 'localhost', 'perhost' => [{ 'scope' => 'proxyscope', 'host' => 'proxyhost', 'https' => true }] } } }
+
+ it {
+ is_expected.to contain_apt__setting('conf-proxy').with(priority: '01').with_content(
+ %r{Acquire::https::proxy::proxyscope "https://proxyhost:8080/";},
+ )
+ }
+ end
+
+ context 'when host=localhost and per-host[proxyscope]=[direct]' do
+ let(:params) { { proxy: { 'host' => 'localhost', 'perhost' => [{ 'scope' => 'proxyscope', 'direct' => true }] } } }
+
+ it {
+ is_expected.to contain_apt__setting('conf-proxy').with(priority: '01').with_content(
+ %r{Acquire::http::proxy::proxyscope "DIRECT";},
+ )
+ }
+ end
+
+ context 'when host=localhost and per-host[proxyscope]=[https][direct]' do
+ let(:params) { { proxy: { 'host' => 'localhost', 'perhost' => [{ 'scope' => 'proxyscope', 'https' => true, 'direct' => true }] } } }
+
+ it {
+ is_expected.to contain_apt__setting('conf-proxy').with(priority: '01').with_content(
+ %r{Acquire::https::proxy::proxyscope "DIRECT";},
+ )
+ }
+ end
+
+ context 'when host=localhost and per-host[proxyscope]=proxyhost and per-host[proxyscope2]=proxyhost2' do
+ let(:params) { { proxy: { 'host' => 'localhost', 'perhost' => [{ 'scope' => 'proxyscope', 'host' => 'proxyhost' }, { 'scope' => 'proxyscope2', 'host' => 'proxyhost2' }] } } }
+
+ it {
+ is_expected.to contain_apt__setting('conf-proxy').with(priority: '01').with_content(
+ %r{Acquire::http::proxy::proxyscope "http://proxyhost:8080/";},
+ ).with_content(
+ %r{Acquire::http::proxy::proxyscope2 "http://proxyhost2:8080/";},
+ )
+ }
+ 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,
+ 'apt.conf.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_file('apt.conf.d').with(purge: false,
+ recurse: false)
+ }
+
+ it {
+ is_expected.to contain_exec('apt_update').with(refreshonly: false,
+ timeout: 1,
+ tries: 3)
+ }
+ end
+
+ context 'with lots of non-defaults' do
+ let :params do
+ {
+ update: { 'frequency' => 'always', 'timeout' => 1, 'tries' => 3 },
+ purge: { 'sources.list' => true, 'sources.list.d' => true,
+ 'preferences' => true, 'preferences.d' => true,
+ 'apt.conf.d' => true },
+ }
+ end
+
+ it {
+ is_expected.to contain_file('sources.list').with(content: "# Repos managed by puppet.\n")
+ }
+
+ it {
+ is_expected.to contain_file('sources.list.d').with(purge: true,
+ recurse: true)
+ }
+
+ it {
+ is_expected.to contain_file('preferences').with(ensure: 'absent')
+ }
+
+ it {
+ is_expected.to contain_file('preferences.d').with(purge: true,
+ recurse: true)
+ }
+
+ it {
+ is_expected.to contain_file('apt.conf.d').with(purge: true,
+ recurse: true)
+ }
+
+ it {
+ is_expected.to contain_exec('apt_update').with(refreshonly: false,
+ timeout: 1,
+ tries: 3)
+ }
+ end
+
+ context 'with defaults for sources_list_force' do
+ let :params do
+ {
+ update: { 'frequency' => 'always', 'timeout' => 1, 'tries' => 3 },
+ purge: { 'sources.list' => true },
+ sources_list_force: false,
+ }
+ end
+
+ it {
+ is_expected.to contain_file('sources.list').with(content: "# Repos managed by puppet.\n")
+ }
+ end
+
+ context 'with non defaults for sources_list_force' do
+ let :params do
+ {
+ update: { 'frequency' => 'always', 'timeout' => 1, 'tries' => 3 },
+ purge: { 'sources.list' => true },
+ sources_list_force: true,
+ }
+ end
+
+ it {
+ is_expected.to contain_file('sources.list').with(ensure: 'absent')
+ }
+ end
+
+ context 'with entries for /etc/apt/auth.conf' do
+ facts_hash = {
+ 'Ubuntu 18.04' => {
+ os: {
+ family: 'Debian',
+ name: 'Ubuntu',
+ release: {
+ major: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'bionic',
+ id: 'Ubuntu',
+ },
+ },
+ },
+ 'Debian 9.0' => {
+ os: {
+ family: 'Debian',
+ name: 'Debian',
+ release: {
+ major: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ },
+ 'Debian 10.0' => {
+ os: {
+ family: 'Debian',
+ name: 'Debian',
+ release: {
+ major: '10',
+ full: '10.0',
+ },
+ distro: {
+ codename: 'buster',
+ id: 'Debian',
+ },
+ },
+ },
+ }
+
+ facts_hash.each do |os, facts|
+ context "on #{os}" do
+ let(:facts) do
+ facts
+ end
+ let(:params) do
+ {
+ auth_conf_entries: [
+ {
+ machine: 'deb.example.net',
+ login: 'foologin',
+ password: 'secret',
+ },
+ {
+ machine: 'apt.example.com',
+ login: 'aptlogin',
+ password: 'supersecret',
+ },
+ ],
+ }
+ end
+
+ context 'with manage_auth_conf => true' do
+ let(:params) do
+ super().merge(manage_auth_conf: true)
+ end
+
+ auth_conf_content = "// This file is managed by Puppet. DO NOT EDIT.
+machine deb.example.net login foologin password secret
+machine apt.example.com login aptlogin password supersecret
+"
+
+ it {
+ is_expected.to contain_file('/etc/apt/auth.conf').with(ensure: 'present',
+ owner: '_apt',
+ group: 'root',
+ mode: '0600',
+ notify: 'Class[Apt::Update]',
+ content: sensitive(auth_conf_content))
+ }
+ end
+
+ context 'with manage_auth_conf => false' do
+ let(:params) do
+ super().merge(manage_auth_conf: false)
+ end
+
+ it {
+ is_expected.not_to contain_file('/etc/apt/auth.conf')
+ }
+ end
+ end
+
+ context 'with improperly specified entries for /etc/apt/auth.conf' do
+ let(:params) do
+ {
+ auth_conf_entries: [
+ {
+ machinn: 'deb.example.net',
+ username: 'foologin',
+ password: 'secret',
+ },
+ {
+ machine: 'apt.example.com',
+ login: 'aptlogin',
+ password: 'supersecret',
+ },
+ ],
+ }
+ end
+
+ it { is_expected.to raise_error(Puppet::Error) }
+ end
+ end
+ end
+
+ context 'with sources defined on valid os.family' do
+ let :facts do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Ubuntu',
+ release: {
+ major: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'bionic',
+ id: 'Ubuntu',
+ },
+ },
+ }
+ 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 bionic main$}) }
+ end
+
+ context 'with confs defined on valid os.family' do
+ let :facts do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Ubuntu',
+ release: {
+ major: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'bionic',
+ id: 'Ubuntu',
+ },
+ },
+ }
+ 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 os.family' do
+ let :facts do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Ubuntu',
+ release: {
+ major: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'bionic',
+ id: 'Ubuntu',
+ },
+ },
+ }
+ 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 os.family' do
+ let :facts do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Ubuntu',
+ release: {
+ major: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'bionic',
+ id: 'Ubuntu',
+ },
+ },
+ }
+ 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 os.family' do
+ let :facts do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Ubuntu',
+ release: {
+ major: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'bionic',
+ id: 'Ubuntu',
+ },
+ },
+ }
+ 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 os.family' do
+ let :facts do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Ubuntu',
+ release: {
+ major: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'bionic',
+ id: 'Ubuntu',
+ },
+ },
+ }
+ 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
+
+ context "with purge['apt.conf.d']=>'banana'" do
+ let(:params) { { purge: { 'apt.conf.d' => 'banana' } } }
+
+ it do
+ is_expected.to raise_error(Puppet::Error)
+ end
+ end
+ end
+end
diff --git a/spec/classes/apt_update_spec.rb b/spec/classes/apt_update_spec.rb
new file mode 100644
index 0000000..7177455
--- /dev/null
+++ b/spec/classes/apt_update_spec.rb
@@ -0,0 +1,233 @@
+# frozen_string_literal: true
+
+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: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ 'apt_update_last_success': factval,
+ }
+ 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: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ }
+ 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
+ context 'and Exec[apt_update] refreshonly is overridden to true and has recent run' do
+ let(:facts) do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Debian',
+ release: {
+ major: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ 'apt_update_last_success': Time.now.to_i,
+ }
+ end
+ let(:pre_condition) do
+ "
+ class{'::apt': update => {'frequency' => 'always' },}
+ Exec <| title=='apt_update' |> { refreshonly => true }
+ "
+ end
+
+ it 'skips 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' => true)
+ 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: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ 'apt_update_last_success': factval,
+ }
+ 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: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ }
+ 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
+ ['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: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ 'apt_update_last_success': factval,
+ }
+ 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: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ 'apt_update_last_success': Time.now.to_i,
+ }
+ 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: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ 'apt_update_last_success': nil,
+ }
+ 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/spec/default_facts.yml b/spec/default_facts.yml
new file mode 100644
index 0000000..f777abf
--- /dev/null
+++ b/spec/default_facts.yml
@@ -0,0 +1,8 @@
+# Use default_module_facts.yml for module specific facts.
+#
+# Facts specified here will override the values provided by rspec-puppet-facts.
+---
+ipaddress: "172.16.254.254"
+ipaddress6: "FE80:0000:0000:0000:AAAA:AAAA:AAAA"
+is_pe: false
+macaddress: "AA:AA:AA:AA:AA:AA"
diff --git a/spec/defines/conf_spec.rb b/spec/defines/conf_spec.rb
new file mode 100644
index 0000000..f1e42b5
--- /dev/null
+++ b/spec/defines/conf_spec.rb
@@ -0,0 +1,97 @@
+# frozen_string_literal: true
+
+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: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ }
+ 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')
+ }
+
+ 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')
+ }
+ end
+end
diff --git a/spec/defines/key_compat_spec.rb b/spec/defines/key_compat_spec.rb
new file mode 100644
index 0000000..d477937
--- /dev/null
+++ b/spec/defines/key_compat_spec.rb
@@ -0,0 +1,370 @@
+# frozen_string_literal: true
+
+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'
+
+ let(:facts) do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Debian',
+ release: {
+ major: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ }
+ 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{evaluating a Resource})
+ 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', 'refreshed'\]})
+ 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/spec/defines/key_spec.rb b/spec/defines/key_spec.rb
new file mode 100644
index 0000000..fd63965
--- /dev/null
+++ b/spec/defines/key_spec.rb
@@ -0,0 +1,418 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+GPG_KEY_ID = '6F6B15509CF8E59E6E469F327F438280EF8D349F'
+
+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,
+ refresh: false }
+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: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ }
+ 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 'ensure => refreshed' do
+ let :params do
+ {
+ ensure: 'refreshed',
+ }
+ end
+
+ it 'contains the apt_key with refresh => true' do
+ is_expected.to contain_apt_key(title).with(
+ ensure: 'present',
+ refresh: true,
+ )
+ 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{evaluating a Resource})
+ 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
+ ['foo', 'aabsent', 'absenta', 'apresent', 'presenta', 'refresh', 'arefreshed', 'refresheda'].each do |param|
+ let :params do
+ {
+ ensure: param,
+ }
+ end
+
+ it 'fails' do
+ is_expected.to raise_error(%r{for Enum\['absent', 'present', 'refreshed'\], 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
+
+ describe 'defaults' do
+ context 'when setting keyserver on the apt class' do
+ let :pre_condition do
+ 'class { "apt":
+ keyserver => "keyserver.example.com",
+ }'
+ end
+
+ it 'uses default keyserver' do
+ is_expected.to contain_apt_key(title).with_server('keyserver.example.com')
+ end
+ end
+
+ context 'when setting key_options on the apt class' do
+ let :pre_condition do
+ 'class { "apt":
+ key_options => "http-proxy=http://proxy.example.com:8080",
+ }'
+ end
+
+ it 'uses default keyserver' do
+ is_expected.to contain_apt_key(title).with_options('http-proxy=http://proxy.example.com:8080')
+ end
+ end
+ end
+end
diff --git a/spec/defines/mark_spec.rb b/spec/defines/mark_spec.rb
new file mode 100644
index 0000000..5375fe2
--- /dev/null
+++ b/spec/defines/mark_spec.rb
@@ -0,0 +1,106 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'apt::mark', type: :define do
+ let :title do
+ 'mysource'
+ end
+
+ let :facts do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Debian',
+ release: {
+ major: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ }
+ end
+
+ context 'with correct seting' do
+ let :params do
+ {
+ 'setting' => 'manual',
+ }
+ end
+
+ it {
+ is_expected.to contain_exec('apt-mark manual mysource')
+ }
+ end
+
+ describe 'with wrong setting' do
+ let :params do
+ {
+ 'setting' => 'foobar',
+ }
+ end
+
+ it do
+ is_expected.to raise_error(Puppet::PreformattedError, %r{expects a match for Enum\['auto', 'hold', 'manual', 'unhold'\], got 'foobar'})
+ end
+ end
+
+ [
+ 'package',
+ 'package1',
+ 'package.name',
+ 'package-name',
+ 'package+name',
+ 'p.ackagename',
+ 'p+ackagename',
+ 'p+',
+ ].each do |value|
+ describe 'with a valid resource title' do
+ let :title do
+ value
+ end
+
+ let :params do
+ {
+ 'setting' => 'manual',
+ }
+ end
+
+ it do
+ is_expected.to contain_exec("apt-mark manual #{title}")
+ end
+ end
+ end
+
+ # packagenames starting with + are not valid as the title according to puppet
+ # good thing this is also an illegal name for debian packages
+ [
+ '|| ls -la ||',
+ 'packakge with space',
+ 'package<>|',
+ '|| touch /tmp/foo.txt ||',
+ 'package_name',
+ 'PackageName',
+ '.p',
+ 'p',
+ ].each do |value|
+ describe "with an invalid resource title [#{value}]" do
+ let :title do
+ value
+ end
+
+ let :params do
+ {
+ 'setting' => 'manual',
+ }
+ end
+
+ it do
+ is_expected.to raise_error(Puppet::PreformattedError, %r{Invalid package name: #{title}})
+ end
+ end
+ end
+end
diff --git a/spec/defines/pin_spec.rb b/spec/defines/pin_spec.rb
new file mode 100644
index 0000000..5edc79c
--- /dev/null
+++ b/spec/defines/pin_spec.rb
@@ -0,0 +1,157 @@
+# frozen_string_literal: true
+
+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: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ }
+ 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/spec/defines/ppa_spec.rb b/spec/defines/ppa_spec.rb
new file mode 100644
index 0000000..00424dc
--- /dev/null
+++ b/spec/defines/ppa_spec.rb
@@ -0,0 +1,475 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+def ppa_exec_params(user, repo, distro = 'trusty', environment = [])
+ [
+ environment: environment,
+ command: "/opt/puppetlabs/puppet/cache/add-apt-repository-#{user}-ubuntu-#{repo}-#{distro}.sh",
+ logoutput: 'on_failure',
+ ]
+end
+
+describe 'apt::ppa' do
+ let :pre_condition do
+ 'class { "apt": }'
+ end
+
+ describe 'defaults' do
+ let :facts do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Ubuntu',
+ release: {
+ major: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'trusty',
+ id: 'Ubuntu',
+ },
+ },
+ puppet_vardir: '/opt/puppetlabs/puppet/cache'
+ }
+ end
+
+ let(:title) { 'ppa:needs/substitution' }
+
+ it { is_expected.not_to contain_package('python-software-properties') }
+ it {
+ is_expected.to contain_exec('add-apt-repository-ppa:needs/substitution')
+ .that_notifies('Class[Apt::Update]')
+ .with(*ppa_exec_params('needs', 'substitution'))
+ }
+ end
+
+ [
+ 'ppa:foo/bar',
+ 'ppa:foo/bar1.0',
+ 'ppa:foo10/bar10',
+ 'ppa:foo-/bar_',
+ ].each do |value|
+ describe 'valid resource names' do
+ let :facts do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Ubuntu',
+ release: {
+ major: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'trusty',
+ id: 'Ubuntu',
+ },
+ },
+ }
+ end
+
+ let(:title) { value }
+
+ it { is_expected.not_to raise_error }
+ it { is_expected.to contain_exec("add-apt-repository-#{value}") }
+ end
+ end
+
+ [
+ 'ppa:foo!/bar',
+ 'ppa:foo/bar!',
+ 'ppa:foo1,0/bar',
+ 'ppa:foo/bar/foobar',
+ '|| ls -la ||',
+ '|| touch /tmp/foo.txt ||',
+ ].each do |value|
+ describe 'invalid resource names' do
+ let :facts do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Ubuntu',
+ release: {
+ major: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'trusty',
+ id: 'Ubuntu',
+ },
+ },
+ }
+ end
+
+ let(:title) { value }
+
+ it { is_expected.to raise_error(Puppet::PreformattedError, %r{Invalid PPA name: #{value}}) }
+ end
+ end
+
+ describe 'Ubuntu 15.10 sources.list filename' do
+ let :facts do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Ubuntu',
+ release: {
+ major: '15',
+ full: '15.10',
+ },
+ distro: {
+ codename: 'wily',
+ id: 'Ubuntu',
+ },
+ },
+ puppet_vardir: '/opt/puppetlabs/puppet/cache',
+ }
+ end
+
+ let(:title) { 'ppa:user/foo' }
+
+ it {
+ is_expected.to contain_exec('add-apt-repository-ppa:user/foo')
+ .that_notifies('Class[Apt::Update]')
+ .with(*ppa_exec_params('user', 'foo', 'wily'))
+ }
+ 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: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'trusty',
+ id: 'Ubuntu',
+ },
+ },
+ puppet_vardir: '/opt/puppetlabs/puppet/cache',
+ }
+ end
+
+ let(:title) { 'ppa:needs/substitution' }
+
+ it { is_expected.to contain_package('software-properties-common') }
+ it {
+ is_expected.to contain_exec('add-apt-repository-ppa:needs/substitution')
+ .that_notifies('Class[Apt::Update]')
+ .with(*ppa_exec_params('needs', 'substitution'))
+ }
+ end
+
+ describe 'package_manage => false' do
+ let :pre_condition do
+ 'class { "apt": }'
+ end
+
+ let :facts do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Ubuntu',
+ release: {
+ major: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'trusty',
+ id: 'Ubuntu',
+ },
+ },
+ puppet_vardir: '/opt/puppetlabs/puppet/cache',
+ }
+ end
+
+ let :params do
+ {
+ package_manage: false,
+ }
+ end
+
+ let(:title) { 'ppa:needs/substitution' }
+
+ it { is_expected.not_to contain_package('python-software-properties') }
+ it {
+ is_expected.to contain_exec('add-apt-repository-ppa:needs/substitution')
+ .that_notifies('Class[Apt::Update]')
+ .with(*ppa_exec_params('needs', 'substitution'))
+ }
+ 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: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'trusty',
+ id: 'Ubuntu',
+ },
+ },
+ puppet_vardir: '/opt/puppetlabs/puppet/cache',
+ }
+ end
+
+ let :params do
+ {
+ 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(*ppa_exec_params('user', 'foo'))
+ }
+ 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: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'trusty',
+ id: 'Ubuntu',
+ },
+ },
+ puppet_vardir: '/opt/puppetlabs/puppet/cache',
+ }
+ end
+
+ let :params do
+ {
+ '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(*ppa_exec_params('user', 'foo', 'trusty', ['http_proxy=http://localhost:8080']))
+ }
+ 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: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'trusty',
+ id: 'Ubuntu',
+ },
+ },
+ puppet_vardir: '/opt/puppetlabs/puppet/cache',
+ }
+ end
+
+ let :params do
+ {
+ 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(*ppa_exec_params('user', 'foo', 'trusty', ['http_proxy=http://localhost:8180']))
+ }
+ 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: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'trusty',
+ id: 'Ubuntu',
+ },
+ },
+ puppet_vardir: '/opt/puppetlabs/puppet/cache',
+ }
+ end
+
+ let :params do
+ {
+ 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(*ppa_exec_params('user', 'foo', 'trusty', ['http_proxy=http://localhost:8180', 'https_proxy=https://localhost:8180']))
+ }
+ end
+
+ describe 'ensure absent' do
+ let :pre_condition do
+ 'class { "apt": }'
+ end
+
+ let :facts do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Ubuntu',
+ release: {
+ major: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: 'trusty',
+ id: 'Ubuntu',
+ },
+ },
+ puppet_vardir: '/opt/puppetlabs/puppet/cache',
+ }
+ end
+
+ let(:title) { 'ppa:user/foo' }
+
+ let :params do
+ {
+ ensure: 'absent',
+ }
+ end
+
+ it {
+ is_expected.to contain_tidy("remove-apt-repository-script-#{title}")
+ .with('path' => '/opt/puppetlabs/puppet/cache/add-apt-repository-user-ubuntu-foo-trusty.sh')
+
+ is_expected.to contain_tidy("remove-apt-repository-#{title}")
+ .with('path' => '/etc/apt/sources.list.d/user-ubuntu-foo-trusty.list')
+ .that_notifies('Class[Apt::Update]')
+ }
+ end
+
+ context 'with validation' do
+ describe 'no release' do
+ let :facts do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Ubuntu',
+ release: {
+ major: '18',
+ full: '18.04',
+ },
+ distro: {
+ codename: nil,
+ id: 'Ubuntu',
+ },
+ },
+ }
+ end
+
+ let(:title) { 'ppa:user/foo' }
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{os.distro.codename 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',
+ },
+ distro: {
+ codename: 'wheezy',
+ id: 'Debian',
+ },
+ },
+ }
+ 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/spec/defines/setting_spec.rb b/spec/defines/setting_spec.rb
new file mode 100644
index 0000000..97ebdc4
--- /dev/null
+++ b/spec/defines/setting_spec.rb
@@ -0,0 +1,153 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'apt::setting' do
+ let(:pre_condition) { 'class { "apt": }' }
+ let :facts do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Debian',
+ release: {
+ major: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ }
+ 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',
+ 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',
+ 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: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ }
+ 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) }
+
+ it { is_expected.to compile.and_raise_error(%r{expects a value of type}) }
+ 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/spec/defines/source_compat_spec.rb b/spec/defines/source_compat_spec.rb
new file mode 100644
index 0000000..d7dfb78
--- /dev/null
+++ b/spec/defines/source_compat_spec.rb
@@ -0,0 +1,146 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'apt::source', type: :define do
+ GPG_KEY_ID = '6F6B15509CF8E59E6E469F327F438280EF8D349F'
+
+ let :title do
+ 'my_source'
+ end
+
+ let :facts do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Debian',
+ release: {
+ major: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ }
+ end
+
+ context 'with mostly defaults' do
+ 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/ stretch main\n})
+ }
+ end
+
+ context 'with no defaults' do
+ 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_insecure true' do
+ let :params do
+ {
+ 'include' => { 'src' => false },
+ 'location' => 'http://debian.mirror.iweb.ca/debian/',
+ 'allow_insecure' => true,
+ }
+ end
+
+ it { is_expected.to contain_apt__setting('list-my_source').with_content(%r{# my_source\ndeb \[allow-insecure=yes\] http://debian.mirror.iweb.ca/debian/ stretch main\n}) }
+ end
+
+ context 'when allow_unsigned true' do
+ 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/ stretch main\n}) }
+ end
+
+ context 'with architecture equals x86_64' do
+ 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/ stretch main\n})
+ }
+ end
+
+ context 'with ensure => absent' do
+ 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: '8',
+ full: '8.0',
+ },
+ distro: {
+ id: 'Debian',
+ },
+ },
+ }
+ end
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{os.distro.codename fact not available: release parameter required})
+ end
+ end
+ end
+end
diff --git a/spec/defines/source_spec.rb b/spec/defines/source_spec.rb
new file mode 100644
index 0000000..6410895
--- /dev/null
+++ b/spec/defines/source_spec.rb
@@ -0,0 +1,479 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'apt::source' do
+ GPG_KEY_ID = '6F6B15509CF8E59E6E469F327F438280EF8D349F'
+
+ let :pre_condition do
+ 'class { "apt": }'
+ end
+
+ let :title do
+ 'my_source'
+ end
+
+ let :facts do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Debian',
+ release: {
+ major: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ }
+ end
+
+ context 'with defaults' do
+ context 'without location' do
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{source entry without specifying a location})
+ end
+ end
+ context 'with location' do
+ 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})
+ is_expected.not_to contain_package('apt-transport-https')
+ }
+ end
+ end
+
+ describe 'no defaults' do
+ 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 stretch 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: {
+ 'ensure' => 'refreshed',
+ 'id' => GPG_KEY_ID,
+ 'server' => 'pgp.mit.edu',
+ 'content' => 'GPG key content',
+ 'source' => 'http://apt.puppetlabs.com/pubkey.gpg',
+ 'weak_ssl' => true,
+ },
+ 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: 'refreshed',
+ id: GPG_KEY_ID,
+ server: 'pgp.mit.edu',
+ content: 'GPG key content',
+ source: 'http://apt.puppetlabs.com/pubkey.gpg',
+ weak_ssl: true)
+ }
+ end
+ end
+
+ context 'with allow_insecure true' do
+ let :params do
+ {
+ location: 'hello.there',
+ allow_insecure: true,
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source').with(ensure: 'present').with_content(%r{# my_source\ndeb \[allow-insecure=yes\] hello.there stretch main\n})
+ }
+ end
+
+ context 'with allow_unsigned true' do
+ 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 stretch main\n})
+ }
+ end
+
+ context 'with check_valid_until false' do
+ let :params do
+ {
+ location: 'hello.there',
+ check_valid_until: false,
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source').with(ensure: 'present').with_content(%r{# my_source\ndeb \[check-valid-until=false\] hello.there stretch main\n})
+ }
+ end
+
+ context 'with check_valid_until true' do
+ let :params do
+ {
+ location: 'hello.there',
+ check_valid_until: true,
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source').with(ensure: 'present').with_content(%r{# my_source\ndeb hello.there stretch main\n})
+ }
+ end
+
+ context 'with keyring set' do
+ let :params do
+ {
+ location: 'hello.there',
+ keyring: '/usr/share/keyrings/foo-archive-keyring.gpg',
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source')
+ .with(ensure: 'present')
+ .with_content(%r{# my_source\ndeb \[signed-by=/usr/share/keyrings/foo-archive-keyring.gpg\] hello.there stretch main\n})
+ }
+ end
+
+ context 'with keyring, architecture and allow_unsigned set' do
+ let :params do
+ {
+ location: 'hello.there',
+ architecture: 'amd64',
+ allow_unsigned: true,
+ keyring: '/usr/share/keyrings/foo-archive-keyring.gpg',
+ }
+ end
+
+ it {
+ is_expected.to contain_apt__setting('list-my_source')
+ .with(ensure: 'present')
+ .with_content(%r{# my_source\ndeb \[arch=amd64 trusted=yes signed-by=/usr/share/keyrings/foo-archive-keyring.gpg\] hello.there stretch main\n})
+ }
+ end
+
+ context 'with a https location, install apt-transport-https' do
+ let :params do
+ {
+ location: 'HTTPS://foo.bar',
+ allow_unsigned: false,
+ }
+ end
+
+ it {
+ is_expected.to contain_package('apt-transport-https')
+ }
+ end
+
+ context 'with a https location and custom release, install apt-transport-https' do
+ let :facts do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Debian',
+ release: {
+ major: '9',
+ full: '9.0',
+ },
+ distro: {
+ codename: 'stretch',
+ id: 'Debian',
+ },
+ },
+ puppetversion: Puppet.version,
+ }
+ end
+ let :params do
+ {
+ location: 'HTTPS://foo.bar',
+ allow_unsigned: false,
+ release: 'customrelease',
+ }
+ end
+
+ it {
+ is_expected.to contain_package('apt-transport-https')
+ }
+ end
+
+ context 'with a https location, do not install apt-transport-https on oses not in list eg buster' do
+ let :facts do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Debian',
+ release: {
+ major: '10',
+ full: '10.0',
+ },
+ distro: {
+ codename: 'buster',
+ id: 'Debian',
+ },
+ },
+ }
+ end
+ let :params do
+ {
+ location: 'https://foo.bar',
+ allow_unsigned: false,
+ }
+ end
+
+ it {
+ is_expected.not_to contain_package('apt-transport-https')
+ }
+ end
+
+ context 'with architecture equals x86_64' do
+ let :facts do
+ {
+ os: {
+ family: 'Debian',
+ name: 'Debian',
+ release: {
+ major: '7',
+ full: '7.0',
+ },
+ distro: {
+ codename: 'wheezy',
+ id: 'Debian',
+ },
+ },
+ }
+ 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
+ super().merge(architecture: 'amd64')
+ 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 stretch main\n})
+ }
+ end
+
+ context 'with include_src => true' do
+ 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 stretch main\ndeb-src hello.there stretch main\n})
+ }
+ end
+
+ context 'with include deb => false' do
+ 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 :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 stretch main\n})
+ }
+ it { is_expected.to contain_apt__setting('list-my_source').without_content(%r{deb hello.there stretch main\n}) }
+ end
+
+ context 'with ensure => absent' do
+ 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: '8',
+ full: '8.0',
+ },
+ distro: {
+ id: 'Debian',
+ },
+ },
+ }
+ end
+ let(:params) { { location: 'hello.there' } }
+
+ it do
+ is_expected.to raise_error(Puppet::Error, %r{os.distro.codename fact not available: release parameter required})
+ end
+ end
+
+ context 'with release is empty string' do
+ 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 :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 :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 :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 :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/spec/spec_helper.rb b/spec/spec_helper.rb
new file mode 100644
index 0000000..07db734
--- /dev/null
+++ b/spec/spec_helper.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+RSpec.configure do |c|
+ c.mock_with :rspec
+end
+
+require 'puppetlabs_spec_helper/module_spec_helper'
+require 'rspec-puppet-facts'
+
+require 'spec_helper_local' if File.file?(File.join(File.dirname(__FILE__), 'spec_helper_local.rb'))
+
+include RspecPuppetFacts
+
+default_facts = {
+ puppetversion: Puppet.version,
+ facterversion: Facter.version,
+}
+
+default_fact_files = [
+ File.expand_path(File.join(File.dirname(__FILE__), 'default_facts.yml')),
+ File.expand_path(File.join(File.dirname(__FILE__), 'default_module_facts.yml')),
+]
+
+default_fact_files.each do |f|
+ next unless File.exist?(f) && File.readable?(f) && File.size?(f)
+
+ begin
+ default_facts.merge!(YAML.safe_load(File.read(f), [], [], true))
+ rescue => e
+ RSpec.configuration.reporter.message "WARNING: Unable to load #{f}: #{e}"
+ end
+end
+
+# read default_facts and merge them over what is provided by facterdb
+default_facts.each do |fact, value|
+ add_custom_fact fact, value
+end
+
+RSpec.configure do |c|
+ c.default_facts = default_facts
+ c.before :each do
+ # set to strictest setting for testing
+ # by default Puppet runs at warning level
+ Puppet.settings[:strict] = :warning
+ Puppet.settings[:strict_variables] = true
+ end
+ c.filter_run_excluding(bolt: true) unless ENV['GEM_BOLT']
+ c.after(:suite) do
+ RSpec::Puppet::Coverage.report!(0)
+ end
+
+ # Filter backtrace noise
+ backtrace_exclusion_patterns = [
+ %r{spec_helper},
+ %r{gems},
+ ]
+
+ if c.respond_to?(:backtrace_exclusion_patterns)
+ c.backtrace_exclusion_patterns = backtrace_exclusion_patterns
+ elsif c.respond_to?(:backtrace_clean_patterns)
+ c.backtrace_clean_patterns = backtrace_exclusion_patterns
+ end
+end
+
+# Ensures that a module is defined
+# @param module_name Name of the module
+def ensure_module_defined(module_name)
+ module_name.split('::').reduce(Object) do |last_module, next_module|
+ last_module.const_set(next_module, Module.new) unless last_module.const_defined?(next_module, false)
+ last_module.const_get(next_module, false)
+ end
+end
+
+# 'spec_overrides' from sync.yml will appear below this line
diff --git a/spec/spec_helper_acceptance.rb b/spec/spec_helper_acceptance.rb
new file mode 100644
index 0000000..73a0238
--- /dev/null
+++ b/spec/spec_helper_acceptance.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+require 'puppet_litmus'
+PuppetLitmus.configure!
+
+require 'spec_helper_acceptance_local' if File.file?(File.join(File.dirname(__FILE__), 'spec_helper_acceptance_local.rb'))
diff --git a/spec/spec_helper_acceptance_local.rb b/spec/spec_helper_acceptance_local.rb
new file mode 100644
index 0000000..9f0cd18
--- /dev/null
+++ b/spec/spec_helper_acceptance_local.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+UNSUPPORTED_PLATFORMS = ['RedHat', 'Suse', 'windows', 'AIX', 'Solaris'].freeze
+RETRY_WAIT = 3
+ERROR_MATCHER = %r{(no valid OpenPGP data found|keyserver timed out|keyserver receive failed)}.freeze
+MAX_RETRY_COUNT = 10
+
+RSpec.configure do |c|
+ c.before :suite do
+ # lsb-release is needed for facter 3 (puppet 6) to resolve os.distro facts. Not needed with facter
+ # 4 (puppet 7).
+ lsb_package = <<-MANIFEST
+package { 'lsb-release':
+ ensure => installed,
+}
+MANIFEST
+ include PuppetLitmus
+ extend PuppetLitmus
+ apply_manifest(lsb_package)
+ 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 = MAX_RETRY_COUNT, retry_wait_interval_secs = RETRY_WAIT, error_matcher = ERROR_MATCHER)
+ try = 0
+ begin
+ puts "retry_on_error_matching: try #{try}" unless try.zero?
+ try += 1
+ yield
+ rescue StandardError => e
+ raise('Attempted this %{value0} times. Raising %{value1}' % { value0: max_retry_count, value1: e }) unless try < max_retry_count && (error_matcher.nil? || e.message =~ error_matcher)
+ sleep retry_wait_interval_secs
+ retry
+ end
+end
diff --git a/spec/spec_helper_local.rb b/spec/spec_helper_local.rb
new file mode 100644
index 0000000..ce4d062
--- /dev/null
+++ b/spec/spec_helper_local.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+if ENV['COVERAGE'] == 'yes'
+ require 'simplecov'
+ require 'simplecov-console'
+ require 'codecov'
+
+ SimpleCov.formatters = [
+ SimpleCov::Formatter::HTMLFormatter,
+ SimpleCov::Formatter::Console,
+ SimpleCov::Formatter::Codecov,
+ ]
+ SimpleCov.start do
+ track_files 'lib/**/*.rb'
+
+ add_filter '/spec'
+
+ # do not track vendored files
+ add_filter '/vendor'
+ add_filter '/.vendor'
+
+ # do not track gitignored files
+ # this adds about 4 seconds to the coverage check
+ # this could definitely be optimized
+ add_filter do |f|
+ # system returns true if exit status is 0, which with git-check-ignore means file is ignored
+ system("git check-ignore --quiet #{f.filename}")
+ end
+ end
+end
diff --git a/spec/unit/facter/apt_dist_has_updates_spec.rb b/spec/unit/facter/apt_dist_has_updates_spec.rb
new file mode 100644
index 0000000..3ed4f3b
--- /dev/null
+++ b/spec/unit/facter/apt_dist_has_updates_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'apt_has_dist_updates fact' do
+ subject { Facter.fact(:apt_has_dist_updates).value }
+
+ before(:each) { Facter.clear }
+
+ describe 'on non-Debian distro' do
+ before(:each) do
+ allow(Facter.fact(:osfamily)).to receive(:value).once.and_return('Redhat')
+ end
+ it { is_expected.to be_nil }
+ end
+
+ describe 'on Debian based distro missing apt-get' do
+ before(:each) do
+ allow(Facter.fact(:osfamily)).to receive(:value).once.and_return('Debian')
+ allow(File).to receive(:executable?) # Stub all other calls
+ allow(File).to receive(:executable?).with('/usr/bin/apt-get').and_return(false)
+ end
+ it { is_expected.to be_nil }
+ end
+
+ describe 'on Debian based distro' do
+ before(:each) do
+ allow(Facter.fact(:osfamily)).to receive(:value).once.and_return('Debian')
+ allow(File).to receive(:executable?) # Stub all other calls
+ allow(Facter::Core::Execution).to receive(:execute) # Catch all other calls
+ allow(File).to receive(:executable?).with('/usr/bin/apt-get').and_return(true)
+ allow(Facter::Core::Execution).to receive(:execute).with('/usr/bin/apt-get -s -o Debug::NoLocking=true upgrade 2>&1').and_return('test')
+ 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:stretch-backports [all])\n" \
+ "Conf planet.rb (22-2~bpo8+1 Debian Backports:stretch-backports [all])\n"
+ allow(Facter::Core::Execution).to receive(:execute).with('/usr/bin/apt-get -s -o Debug::NoLocking=true dist-upgrade 2>&1').and_return(apt_output)
+ end
+ it { is_expected.to be true }
+ end
+end
diff --git a/spec/unit/facter/apt_dist_package_security_updates_spec.rb b/spec/unit/facter/apt_dist_package_security_updates_spec.rb
new file mode 100644
index 0000000..f16ff52
--- /dev/null
+++ b/spec/unit/facter/apt_dist_package_security_updates_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'apt_package_security_dist_updates fact' do
+ subject { Facter.fact(:apt_package_security_dist_updates).value }
+
+ before(:each) { Facter.clear }
+
+ describe 'when apt has no updates' do
+ before(:each) do
+ allow(Facter.fact(:apt_has_dist_updates)).to receive(:value).and_return(false)
+ end
+ it { is_expected.to be nil }
+ end
+
+ describe 'when apt has updates' do
+ before(:each) do
+ allow(Facter.fact(:osfamily)).to receive(:value).and_return('Debian')
+ allow(File).to receive(:executable?) # Stub all other calls
+ allow(Facter::Core::Execution).to receive(:execute) # Catch all other calls
+ allow(File).to receive(:executable?).with('/usr/bin/apt-get').and_return(true)
+ allow(Facter::Core::Execution).to receive(:execute).with('/usr/bin/apt-get -s -o Debug::NoLocking=true upgrade 2>&1').and_return('test')
+ allow(File).to receive(:executable?).with('/usr/bin/apt-get').and_return(true)
+ allow(Facter::Core::Execution).to receive(:execute).with('/usr/bin/apt-get -s -o Debug::NoLocking=true dist-upgrade 2>&1').and_return(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:-backports [all])\n" \
+ "Conf planet.rb (22-2~bpo8+1 Debian Backports:-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(['vim']) }
+ end
+
+ describe 'on Ubuntu' do
+ let(:apt_get_upgrade_output) do
+ "Inst extremetuxracer [2016f-0ubuntu0.18.04] (2016j-0ubuntu0.18.04 Ubuntu:18.04/xenial-security, Ubuntu:18.04/xenial-updates [all])\n" \
+ "Conf extremetuxracer (2016j-0ubuntu0.18.04 Ubuntu:18.04/xenial-security, Ubuntu:18.04/xenial-updates [all])\n" \
+ "Inst vim [7.47.0-1ubuntu2] (7.47.0-1ubuntu2.2 Ubuntu:18.04/xenial-security [amd64]) []\n" \
+ "Conf vim (7.47.0-1ubuntu2.2 Ubuntu:18.04/xenial-security [amd64])\n" \
+ "Inst onioncircuits [2:3.3.10-4ubuntu2] (2:3.3.10-4ubuntu2.3 Ubuntu:18.04/xenial-updates [amd64])\n" \
+ "Conf onioncircuits (2:3.3.10-4ubuntu2.3 Ubuntu:18.04/xenial-updates [amd64])\n"
+ end
+
+ it { is_expected.to eq(['extremetuxracer', 'vim']) }
+ end
+ end
+end
diff --git a/spec/unit/facter/apt_dist_package_updates_spec.rb b/spec/unit/facter/apt_dist_package_updates_spec.rb
new file mode 100644
index 0000000..a27d607
--- /dev/null
+++ b/spec/unit/facter/apt_dist_package_updates_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'apt_package_dist_updates fact' do
+ subject { Facter.fact(:apt_package_dist_updates).value }
+
+ before(:each) { Facter.clear }
+
+ describe 'when apt has no updates' do
+ before(:each) do
+ allow(Facter.fact(:apt_has_dist_updates)).to receive(:value).and_return(false)
+ end
+ it { is_expected.to be nil }
+ end
+
+ describe 'when apt has updates' do
+ before(:each) do
+ allow(Facter.fact(:osfamily)).to receive(:value).and_return('Debian')
+ allow(File).to receive(:executable?) # Stub all other calls
+ allow(Facter::Core::Execution).to receive(:execute) # Catch all other calls
+ allow(File).to receive(:executable?).with('/usr/bin/apt-get').and_return(true)
+ allow(Facter::Core::Execution).to receive(:execute).with('/usr/bin/apt-get -s -o Debug::NoLocking=true upgrade 2>&1').and_return('test')
+ allow(File).to receive(:executable?).with('/usr/bin/apt-get').and_return(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:-backports [all])\n" \
+ "Conf planet.rb (22-2~bpo8+1 Debian Backports:-backports [all])\n"
+ allow(Facter::Core::Execution).to receive(:execute).with('/usr/bin/apt-get -s -o Debug::NoLocking=true dist-upgrade 2>&1').and_return(apt_output)
+ end
+ it { is_expected.to eq(['extremetuxracer', 'planet.rb']) }
+ end
+end
diff --git a/spec/unit/facter/apt_dist_security_updates_spec.rb b/spec/unit/facter/apt_dist_security_updates_spec.rb
new file mode 100644
index 0000000..aa21e64
--- /dev/null
+++ b/spec/unit/facter/apt_dist_security_updates_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'apt_security_updates fact' do
+ subject { Facter.fact(:apt_security_dist_updates).value }
+
+ before(:each) { Facter.clear }
+
+ describe 'when apt has no updates' do
+ before(:each) do
+ allow(Facter.fact(:apt_has_dist_updates)).to receive(:value).and_return(false)
+ end
+ it { is_expected.to be nil }
+ end
+
+ describe 'when apt has security updates' do
+ before(:each) do
+ allow(Facter.fact(:osfamily)).to receive(:value).and_return('Debian')
+ allow(File).to receive(:executable?) # Stub all other calls
+ allow(Facter::Core::Execution).to receive(:execute) # Catch all other calls
+ allow(File).to receive(:executable?).with('/usr/bin/apt-get').and_return(true)
+ allow(Facter::Core::Execution).to receive(:execute).with('/usr/bin/apt-get -s -o Debug::NoLocking=true upgrade 2>&1').and_return('test')
+ allow(File).to receive(:executable?).with('/usr/bin/apt-get').and_return(true)
+ allow(Facter::Core::Execution).to receive(:execute).with('/usr/bin/apt-get -s -o Debug::NoLocking=true dist-upgrade 2>&1').and_return(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:-backports [all])\n" \
+ "Conf planet.rb (22-2~bpo8+1 Debian Backports:-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.18.04] (2016j-0ubuntu0.18.04 Ubuntu:18.04/xenial-security, Ubuntu:18.04/xenial-updates [all])\n" \
+ "Conf extremetuxracer (2016j-0ubuntu0.18.04 Ubuntu:18.04/xenial-security, Ubuntu:18.04/xenial-updates [all])\n" \
+ "Inst vim [7.47.0-1ubuntu2] (7.47.0-1ubuntu2.2 Ubuntu:18.04/xenial-security [amd64]) []\n" \
+ "Conf vim (7.47.0-1ubuntu2.2 Ubuntu:18.04/xenial-security [amd64])\n" \
+ "Inst onioncircuits [2:3.3.10-4ubuntu2] (2:3.3.10-4ubuntu2.3 Ubuntu:18.04/xenial-updates [amd64])\n" \
+ "Conf onioncircuits (2:3.3.10-4ubuntu2.3 Ubuntu:18.04/xenial-updates [amd64])\n"
+ end
+
+ it { is_expected.to eq(2) }
+ end
+ end
+end
diff --git a/spec/unit/facter/apt_dist_updates_spec.rb b/spec/unit/facter/apt_dist_updates_spec.rb
new file mode 100644
index 0000000..21352b5
--- /dev/null
+++ b/spec/unit/facter/apt_dist_updates_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'apt_updates fact' do
+ subject { Facter.fact(:apt_dist_updates).value }
+
+ before(:each) { Facter.clear }
+
+ describe 'when apt has no updates' do
+ before(:each) do
+ allow(Facter.fact(:apt_has_dist_updates)).to receive(:value).and_return(false)
+ end
+ it { is_expected.to be nil }
+ end
+
+ describe 'when apt has updates' do
+ before(:each) do
+ allow(Facter.fact(:osfamily)).to receive(:value).and_return('Debian')
+ allow(File).to receive(:executable?) # Stub all other calls
+ allow(Facter::Core::Execution).to receive(:execute) # Catch all other calls
+ allow(File).to receive(:executable?).with('/usr/bin/apt-get').and_return(true)
+ allow(Facter::Core::Execution).to receive(:execute).with('/usr/bin/apt-get -s -o Debug::NoLocking=true upgrade 2>&1').and_return('test')
+ allow(File).to receive(:executable?).with('/usr/bin/apt-get').and_return(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:-backports [all])\n" \
+ "Conf planet.rb (22-2~bpo8+1 Debian Backports:-backports [all])\n"
+ allow(Facter::Core::Execution).to receive(:execute).with('/usr/bin/apt-get -s -o Debug::NoLocking=true dist-upgrade 2>&1').and_return(apt_output)
+ end
+ it { is_expected.to eq(2) }
+ end
+end
diff --git a/spec/unit/facter/apt_has_updates_spec.rb b/spec/unit/facter/apt_has_updates_spec.rb
new file mode 100644
index 0000000..0f0a740
--- /dev/null
+++ b/spec/unit/facter/apt_has_updates_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'apt_has_updates fact' do
+ subject { Facter.fact(:apt_has_updates).value }
+
+ before(:each) { Facter.clear }
+
+ describe 'on non-Debian distro' do
+ before(:each) do
+ allow(Facter.fact(:osfamily)).to receive(:value).once.and_return('Redhat')
+ end
+ it { is_expected.to be_nil }
+ end
+
+ describe 'on Debian based distro missing apt-get' do
+ before(:each) do
+ allow(Facter.fact(:osfamily)).to receive(:value).once.and_return('Debian')
+ allow(File).to receive(:executable?) # Stub all other calls
+ allow(File).to receive(:executable?).with('/usr/bin/apt-get').and_return(false)
+ end
+ it { is_expected.to be_nil }
+ end
+
+ describe 'on Debian based distro' do
+ before(:each) do
+ allow(Facter.fact(:osfamily)).to receive(:value).and_return('Debian')
+ allow(File).to receive(:executable?) # Stub all other calls
+ allow(Facter::Core::Execution).to receive(:execute) # Catch all other calls
+ allow(File).to receive(:executable?).with('/usr/bin/apt-get').and_return(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:-backports [all])\n" \
+ "Conf unhide.rb (22-2~bpo8+1 Debian Backports:-backports [all])\n"
+ allow(Facter::Core::Execution).to receive(:execute).with('/usr/bin/apt-get -s -o Debug::NoLocking=true upgrade 2>&1').and_return(apt_output)
+ end
+ it { is_expected.to be true }
+ end
+end
diff --git a/spec/unit/facter/apt_package_security_updates_spec.rb b/spec/unit/facter/apt_package_security_updates_spec.rb
new file mode 100644
index 0000000..28516ca
--- /dev/null
+++ b/spec/unit/facter/apt_package_security_updates_spec.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'apt_package_security_updates fact' do
+ subject { Facter.fact(:apt_package_security_updates).value }
+
+ before(:each) { Facter.clear }
+
+ describe 'when apt has no updates' do
+ before(:each) do
+ allow(Facter.fact(:apt_has_updates)).to receive(:value).and_return(false)
+ end
+ it { is_expected.to be nil }
+ end
+
+ describe 'when apt has updates' do
+ before(:each) do
+ allow(Facter.fact(:osfamily)).to receive(:value).and_return('Debian')
+ allow(File).to receive(:executable?) # Stub all other calls
+ allow(Facter::Core::Execution).to receive(:execute) # Catch all other calls
+ allow(File).to receive(:executable?).with('/usr/bin/apt-get').and_return(true)
+ allow(Facter::Core::Execution).to receive(:execute).with('/usr/bin/apt-get -s -o Debug::NoLocking=true upgrade 2>&1').and_return(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:-backports [all])\n" \
+ "Conf unhide.rb (22-2~bpo8+1 Debian Backports:-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(['curl']) }
+ end
+
+ describe 'on Ubuntu' do
+ let(:apt_get_upgrade_output) do
+ "Inst tzdata [2016f-0ubuntu0.18.04] (2016j-0ubuntu0.18.04 Ubuntu:18.04/xenial-security, Ubuntu:18.04/xenial-updates [all])\n" \
+ "Conf tzdata (2016j-0ubuntu0.18.04 Ubuntu:18.04/xenial-security, Ubuntu:18.04/xenial-updates [all])\n" \
+ "Inst curl [7.47.0-1ubuntu2] (7.47.0-1ubuntu2.2 Ubuntu:18.04/xenial-security [amd64]) []\n" \
+ "Conf curl (7.47.0-1ubuntu2.2 Ubuntu:18.04/xenial-security [amd64])\n" \
+ "Inst procps [2:3.3.10-4ubuntu2] (2:3.3.10-4ubuntu2.3 Ubuntu:18.04/xenial-updates [amd64])\n" \
+ "Conf procps (2:3.3.10-4ubuntu2.3 Ubuntu:18.04/xenial-updates [amd64])\n"
+ end
+
+ it { is_expected.to eq(['tzdata', 'curl']) }
+ end
+ end
+end
diff --git a/spec/unit/facter/apt_package_updates_spec.rb b/spec/unit/facter/apt_package_updates_spec.rb
new file mode 100644
index 0000000..69db490
--- /dev/null
+++ b/spec/unit/facter/apt_package_updates_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'apt_package_updates fact' do
+ subject { Facter.fact(:apt_package_updates).value }
+
+ before(:each) { Facter.clear }
+
+ describe 'when apt has no updates' do
+ before(:each) do
+ allow(Facter.fact(:apt_has_updates)).to receive(:value).and_return(false)
+ end
+ it { is_expected.to be nil }
+ end
+
+ describe 'when apt has updates' do
+ before(:each) do
+ allow(Facter.fact(:osfamily)).to receive(:value).and_return('Debian')
+ allow(File).to receive(:executable?) # Stub all other calls
+ allow(Facter::Core::Execution).to receive(:execute) # Catch all other calls
+ allow(File).to receive(:executable?).with('/usr/bin/apt-get').and_return(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:-backports [all])\n" \
+ "Conf unhide.rb (22-2~bpo8+1 Debian Backports:-backports [all])\n"
+ allow(Facter::Core::Execution).to receive(:execute).with('/usr/bin/apt-get -s -o Debug::NoLocking=true upgrade 2>&1').and_return(apt_output)
+ end
+ it { is_expected.to eq(['tzdata', 'unhide.rb']) }
+ end
+end
diff --git a/spec/unit/facter/apt_reboot_required_spec.rb b/spec/unit/facter/apt_reboot_required_spec.rb
new file mode 100644
index 0000000..7621872
--- /dev/null
+++ b/spec/unit/facter/apt_reboot_required_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'apt_reboot_required fact' do
+ subject { Facter.fact(:apt_reboot_required).value }
+
+ before(:each) { Facter.clear }
+
+ describe 'if a reboot is required' do
+ before(:each) do
+ allow(Facter.fact(:osfamily)).to receive(:value).and_return('Debian')
+ allow(File).to receive(:file?).and_return(true)
+ allow(File).to receive(:file?).once.with('/var/run/reboot-required').and_return(true)
+ end
+ it { is_expected.to eq true }
+ end
+
+ describe 'if a reboot is not required' do
+ before(:each) do
+ allow(Facter.fact(:osfamily)).to receive(:value).and_return('Debian')
+ allow(File).to receive(:file?).and_return(true)
+ allow(File).to receive(:file?).once.with('/var/run/reboot-required').and_return(false)
+ end
+ it { is_expected.to eq false }
+ end
+end
diff --git a/spec/unit/facter/apt_security_updates_spec.rb b/spec/unit/facter/apt_security_updates_spec.rb
new file mode 100644
index 0000000..9d3e587
--- /dev/null
+++ b/spec/unit/facter/apt_security_updates_spec.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'apt_security_updates fact' do
+ subject { Facter.fact(:apt_security_updates).value }
+
+ before(:each) { Facter.clear }
+
+ describe 'when apt has no updates' do
+ before(:each) do
+ allow(Facter.fact(:apt_has_updates)).to receive(:value).and_return(false)
+ end
+ it { is_expected.to be nil }
+ end
+
+ describe 'when apt has security updates' do
+ before(:each) do
+ allow(Facter.fact(:osfamily)).to receive(:value).and_return('Debian')
+ allow(File).to receive(:executable?) # Stub all other calls
+ allow(Facter::Core::Execution).to receive(:execute) # Catch all other calls
+ allow(File).to receive(:executable?).with('/usr/bin/apt-get').and_return(true)
+ allow(Facter::Core::Execution).to receive(:execute).with('/usr/bin/apt-get -s -o Debug::NoLocking=true upgrade 2>&1').and_return(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:-backports [all])\n" \
+ "Conf unhide.rb (22-2~bpo8+1 Debian Backports:-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.18.04] (2016j-0ubuntu0.18.04 Ubuntu:18.04/xenial-security, Ubuntu:18.04/xenial-updates [all])\n" \
+ "Conf tzdata (2016j-0ubuntu0.18.04 Ubuntu:18.04/xenial-security, Ubuntu:18.04/xenial-updates [all])\n" \
+ "Inst curl [7.47.0-1ubuntu2] (7.47.0-1ubuntu2.2 Ubuntu:18.04/xenial-security [amd64]) []\n" \
+ "Conf curl (7.47.0-1ubuntu2.2 Ubuntu:18.04/xenial-security [amd64])\n" \
+ "Inst procps [2:3.3.10-4ubuntu2] (2:3.3.10-4ubuntu2.3 Ubuntu:18.04/xenial-updates [amd64])\n" \
+ "Conf procps (2:3.3.10-4ubuntu2.3 Ubuntu:18.04/xenial-updates [amd64])\n"
+ end
+
+ it { is_expected.to eq(2) }
+ end
+ end
+end
diff --git a/spec/unit/facter/apt_sources_spec.rb b/spec/unit/facter/apt_sources_spec.rb
new file mode 100644
index 0000000..32d431a
--- /dev/null
+++ b/spec/unit/facter/apt_sources_spec.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'apt_sources fact' do
+ subject { Facter.fact(:apt_sources).value }
+
+ before(:each) { Facter.clear }
+
+ describe 'returns a list of .list files' do
+ let(:sources_raw) { ['/etc/apt/sources.list.d/puppet-tools.list', '/etc/apt/sources.list.d/some-cli.list'] }
+ let(:sources_want) { ['sources.list', 'puppet-tools.list', 'some-cli.list'] }
+
+ before(:each) do
+ allow(Dir).to receive(:glob).and_return(sources_raw)
+ end
+
+ it { is_expected.to eq(sources_want) }
+ end
+end
diff --git a/spec/unit/facter/apt_update_last_success_spec.rb b/spec/unit/facter/apt_update_last_success_spec.rb
new file mode 100644
index 0000000..c0b028a
--- /dev/null
+++ b/spec/unit/facter/apt_update_last_success_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'apt_update_last_success fact' do
+ subject { Facter.fact(:apt_update_last_success).value }
+
+ before(: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
+ allow(Facter.fact(:osfamily)).to receive(:value).and_return('Debian')
+ allow(File).to receive(:exist?).with('/var/lib/apt/periodic/update-success-stamp').and_return(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
+ allow(Facter.fact(:osfamily)).to receive(:value).and_return('Debian')
+ allow(File).to receive(:exist?).and_return(true)
+ allow(File).to receive(:mtime).and_return(1_407_660_561)
+ is_expected.to eq(1_407_660_561)
+ end
+ end
+end
diff --git a/spec/unit/facter/apt_updates_spec.rb b/spec/unit/facter/apt_updates_spec.rb
new file mode 100644
index 0000000..a8eacbf
--- /dev/null
+++ b/spec/unit/facter/apt_updates_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'apt_updates fact' do
+ subject { Facter.fact(:apt_updates).value }
+
+ before(:each) { Facter.clear }
+
+ describe 'when apt has no updates' do
+ before(:each) do
+ allow(Facter.fact(:apt_has_updates)).to receive(:value).and_return(false)
+ end
+ it { is_expected.to be nil }
+ end
+
+ describe 'when apt has updates' do
+ before(:each) do
+ allow(Facter.fact(:osfamily)).to receive(:value).and_return('Debian')
+ allow(File).to receive(:executable?) # Stub all other calls
+ allow(Facter::Core::Execution).to receive(:execute) # Catch all other calls
+ allow(File).to receive(:executable?).with('/usr/bin/apt-get').and_return(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:-backports [all])\n" \
+ "Conf unhide.rb (22-2~bpo8+1 Debian Backports:-backports [all])\n"
+ allow(Facter::Core::Execution).to receive(:execute).with('/usr/bin/apt-get -s -o Debug::NoLocking=true upgrade 2>&1').and_return(apt_output)
+ end
+ it { is_expected.to eq(2) }
+ end
+end
diff --git a/spec/unit/puppet/provider/apt_key_spec.rb b/spec/unit/puppet/provider/apt_key_spec.rb
new file mode 100644
index 0000000..b895817
--- /dev/null
+++ b/spec/unit/puppet/provider/apt_key_spec.rb
@@ -0,0 +1,218 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Puppet::Type.type(:apt_key).provider(:apt_key) do
+ describe 'instances' do
+ it 'has an instance method' do
+ expect(described_class).to respond_to :instances
+ end
+ end
+
+ describe 'prefetch' do
+ it 'has a prefetch method' do
+ expect(described_class).to respond_to :prefetch
+ end
+ end
+
+ context 'self.instances no key' do
+ before :each do
+ # Unable to remove `master` from below terminology as it relies on outside code
+ allow(described_class).to receive(:apt_key).with(
+ ['adv', '--no-tty', '--list-keys', '--with-colons', '--fingerprint', '--fixed-list-mode'],
+ ).and_return('uid:-::::1284991450::07BEBE04F4AE4A8E885A761325717D8509D9C1DC::Ubuntu Extras Archive Automatic Signing Key <ftpmaster@ubuntu.com>::::::::::0:')
+ end
+ it 'returns no resources' do
+ expect(described_class.instances.size).to eq(0)
+ end
+ end
+
+ context 'self.instances multiple keys' do
+ before :each do
+ command_output = <<-OUTPUT
+Executing: gpg --ignore-time-conflict --no-options --no-default-keyring --homedir /tmp/tmp.DU0GdRxjmE --no-auto-check-trustdb --trust-model always --keyring /etc/apt/trusted.gpg --primary-keyring /etc/apt/trusted.gpg --keyring /etc/apt/trusted.gpg.d/puppetlabs-pc1-keyring.gpg --no-tty --list-keys --with-colons --fingerprint --fixed-list-mode
+tru:t:1:1549900774:0:3:1:5
+pub:-:1024:17:40976EAF437D05B5:1095016255:::-:::scESC:
+fpr:::::::::630239CC130E1A7FD81A27B140976EAF437D05B5:
+uid:-::::1095016255::B84AE656F4F5A826C273A458512EF8E282754CE1::Ubuntu Archive Automatic Signing Key <ftpmaster@ubuntu.com>:
+sub:-:2048:16:251BEFF479164387:1095016263::::::e:
+pub:-:1024:17:46181433FBB75451:1104433784:::-:::scSC:
+fpr:::::::::C5986B4F1257FFA86632CBA746181433FBB75451:
+OUTPUT
+ allow(described_class).to receive(:apt_key).with(
+ ['adv', '--no-tty', '--list-keys', '--with-colons', '--fingerprint', '--fixed-list-mode'],
+ ).and_return(command_output)
+ end
+ it 'returns 2 resources' do
+ expect(described_class.instances.size).to eq(2)
+ expect(described_class.instances[0].name).to eq('630239CC130E1A7FD81A27B140976EAF437D05B5')
+ expect(described_class.instances[0].id).to eq('40976EAF437D05B5')
+ expect(described_class.instances[1].name).to eq('C5986B4F1257FFA86632CBA746181433FBB75451')
+ expect(described_class.instances[1].id).to eq('46181433FBB75451')
+ end
+ end
+
+ context 'create apt_key resource' do
+ it 'apt_key with content set and source nil' do
+ expect(described_class).to receive(:apt_key).with(['adv', '--no-tty',
+ '--keyserver',
+ :"keyserver.ubuntu.com",
+ '--recv-keys',
+ 'C105B9DE'])
+ resource = Puppet::Type::Apt_key.new(name: 'source and content nil',
+ id: 'C105B9DE',
+ ensure: 'present')
+
+ provider = described_class.new(resource)
+ expect(provider).not_to be_exist
+ provider.create
+ expect(provider).to be_exist
+ end
+
+ it 'apt_key content and source nil, options set' do
+ expect(described_class).to receive(:apt_key).with(['adv', '--no-tty',
+ '--keyserver',
+ :"keyserver.ubuntu.com",
+ '--keyserver-options',
+ 'jimno',
+ '--recv-keys',
+ 'C105B9DE'])
+ resource = Puppet::Type::Apt_key.new(name: 'source and content nil',
+ id: 'C105B9DE',
+ options: 'jimno',
+ ensure: 'present')
+
+ provider = described_class.new(resource)
+ expect(provider).not_to be_exist
+ provider.create
+ expect(provider).to be_exist
+ end
+
+ it 'apt_key with content set' do
+ expect(described_class).to receive(:apt_key).with(array_including('add', kind_of(String)))
+ resource = Puppet::Type::Apt_key.new(name: 'gsd',
+ id: 'C105B9DE',
+ content: 'asad',
+ ensure: 'present')
+
+ provider = described_class.new(resource)
+ expect(provider).not_to be_exist
+ expect(provider).to receive(:tempfile).and_return(Tempfile.new('foo'))
+ provider.create
+ expect(provider).to be_exist
+ end
+
+ it 'apt_key with source set' do
+ expect(described_class).to receive(:apt_key).with(array_including('add', kind_of(String)))
+ resource = Puppet::Type::Apt_key.new(name: 'gsd',
+ id: 'C105B9DE',
+ source: 'ftp://bla/herpderp.gpg',
+ ensure: 'present')
+
+ provider = described_class.new(resource)
+ expect(provider).not_to be_exist
+ expect(provider).to receive(:source_to_file).and_return(Tempfile.new('foo'))
+ provider.create
+ expect(provider).to be_exist
+ end
+
+ it 'apt_key with source and weak ssl verify set' do
+ expect(described_class).to receive(:apt_key).with(array_including('add', kind_of(String)))
+ resource = Puppet::Type::Apt_key.new(name: 'gsd',
+ id: 'C105B9DE',
+ source: 'https://bla/herpderp.gpg',
+ ensure: 'present',
+ weak_ssl: true)
+
+ provider = described_class.new(resource)
+ expect(provider).not_to be_exist
+ expect(provider).to receive(:source_to_file).and_return(Tempfile.new('foo'))
+ provider.create
+ expect(provider).to be_exist
+ end
+
+ describe 'different valid id keys' do
+ hash_of_keys = {
+ '32bit key id' => 'EF8D349F',
+ '64bit key id' => '7F438280EF8D349F',
+ '160bit key fingerprint' => '6F6B15509CF8E59E6E469F327F438280EF8D349F',
+ '32bit key id lowercase' => 'EF8D349F'.downcase,
+ '64bit key id lowercase' => '7F438280EF8D349F'.downcase,
+ '160bit key fingerprint lowercase' => '6F6B15509CF8E59E6E469F327F438280EF8D349F'.downcase,
+ '32bit key id 0x formatted' => '0xEF8D349F',
+ '64bit key id 0x formatted' => '0x7F438280EF8D349F',
+ '160bit key fingerprint 0x formatted' => '0x6F6B15509CF8E59E6E469F327F438280EF8D349F',
+ }
+ hash_of_keys.each do |key_type, value|
+ it "#{key_type} #{value} is valid" do
+ expect(described_class).to receive(:apt_key).with(array_including('adv', '--no-tty',
+ '--keyserver',
+ :"keyserver.ubuntu.com",
+ '--recv-keys'))
+ resource = Puppet::Type::Apt_key.new(name: 'source and content nil',
+ id: value,
+ ensure: 'present')
+
+ provider = described_class.new(resource)
+ expect(provider).not_to be_exist
+ provider.create
+ expect(provider).to be_exist
+ end
+ end
+ end
+
+ it 'apt_key with invalid key length' do
+ expect {
+ Puppet::Type::Apt_key.new(name: 'source and content nil',
+ id: '1',
+ ensure: 'present')
+ }.to raise_error(Puppet::ResourceError, %r{Parameter id failed on Apt_key})
+ end
+ end
+
+ context 'key_line_hash function' do
+ it 'matches rsa' do
+ expect(described_class.key_line_hash('pub:-:1024:1:40976EAF437D05B5:1095016255:::-:::scESC:', 'fpr:::::::::630239CC130E1A7FD81A27B140976EAF437D05B5:')).to include(
+ key_expiry: nil,
+ key_fingerprint: '630239CC130E1A7FD81A27B140976EAF437D05B5',
+ key_long: '40976EAF437D05B5',
+ key_short: '437D05B5',
+ key_size: '1024',
+ key_type: :rsa,
+ )
+ end
+
+ it 'matches dsa' do
+ expect(described_class.key_line_hash('pub:-:1024:17:40976EAF437D05B5:1095016255:::-:::scESC:', 'fpr:::::::::630239CC130E1A7FD81A27B140976EAF437D05B5:')).to include(
+ key_expiry: nil,
+ key_fingerprint: '630239CC130E1A7FD81A27B140976EAF437D05B5',
+ key_long: '40976EAF437D05B5',
+ key_short: '437D05B5',
+ key_size: '1024',
+ key_type: :dsa,
+ )
+ end
+
+ it 'matches ecc' do
+ expect(described_class.key_line_hash('pub:-:1024:18:40976EAF437D05B5:1095016255:::-:::scESC:', 'fpr:::::::::630239CC130E1A7FD81A27B140976EAF437D05B5:')).to include(
+ key_expiry: nil,
+ key_fingerprint: '630239CC130E1A7FD81A27B140976EAF437D05B5',
+ key_long: '40976EAF437D05B5',
+ key_short: '437D05B5',
+ key_size: '1024',
+ key_type: :ecc,
+ )
+ end
+
+ it 'matches ecdsa' do
+ expect(described_class.key_line_hash('pub:-:1024:19:40976EAF437D05B5:1095016255:::-:::scESC:', 'fpr:::::::::630239CC130E1A7FD81A27B140976EAF437D05B5:')).to include(
+ key_expiry: nil,
+ key_fingerprint: '630239CC130E1A7FD81A27B140976EAF437D05B5',
+ key_long: '40976EAF437D05B5',
+ key_short: '437D05B5',
+ key_size: '1024',
+ key_type: :ecdsa,
+ )
+ end
+ end
+end
diff --git a/spec/unit/puppet/type/apt_key_spec.rb b/spec/unit/puppet/type/apt_key_spec.rb
new file mode 100644
index 0000000..b20a09a
--- /dev/null
+++ b/spec/unit/puppet/type/apt_key_spec.rb
@@ -0,0 +1,245 @@
+# frozen_string_literal: true
+
+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
+
+ it 'refresh is not set' do
+ expect(resource[:refresh]).to eq nil
+ end
+
+ it 'weak_ssl is not set' do
+ expect(resource[:weak_ssl]).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 source and weak_ssl' do
+ let(:resource) do
+ Puppet::Type.type(:apt_key).new(
+ id: 'EF8D349F',
+ source: 'https://apt.puppetlabs.com/pubkey.gpg',
+ weak_ssl: true,
+ )
+ end
+
+ it 'source is set to the URL' do
+ expect(resource[:source]).to eq 'https://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 refresh => true and ensure => absent' do
+ expect {
+ Puppet::Type.type(:apt_key).new(id: 'EF8D349F',
+ source: 'http://apt.puppetlabs.com/pubkey.gpg',
+ ensure: :absent,
+ refresh: :true)
+ }.to raise_error(%r{ensure => absent and refresh => true 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
Debdiff
File lists identical (after any substitutions)
No differences were encountered in the control files