First off, what is PDK? PDK is Puppet's development kit. The bits we are interested in right now are:
- Validation
pdk validate...
- Testing
pdk test...
- Packaging
pdk build...
There's a lot more to PDK then just running simple tests though, PDK includes its own version of ruby and various other tools.
On Linux PDK behaves (or at least appears to behave...) like a thin wrapper
around ruby, in the same vein as RBENV/RVM. On Windows, things are more involved
since it needs to install specific system libraries and reference them at
runtime somehow. This is why running bundle install
on PDK project in windows
can cause strange and interesting blow-ups (don't do that!).
PDQTest provides an easy way to run acceptance tests using light-weight Docker containers which we abuse to the point of treating them almost like VMs in order to extract maximum speed. It offers a different approach to Beaker:
- Minimal to no project configuration required, just
metadata.json
and a few other files we setup for you - Simple acceptance tests written in BASH or PowerShell
- Provide good enough (but not perfect) testing:
- Generic Ubuntu, Centos, Windows test environments
- Capable of mocking large/slow/networked systems by replacing or installing
binaries inside the container at the OS level, eg:
- Fake installation of Database server's by mocking the installer your
puppet
exec
would call with a simple python script - Network tools such as
realmd
with a simple mockrealm
command written in Python - Complex OS commands that need to report different state between puppet
runs can be mocked with Python and a small SQLite database or simple
text files (eg the
sysctl
command) - Fake different Unix-like Operating Systems such as AIX by subverting the commands that your puppet code would execute. This is particularly useful in this case since there are no AIX desktop virtualisation solutions right now and there probably never will be
- See examples for real-world modules using these techniques
- Fake installation of Database server's by mocking the installer your
puppet
Of course, this will only ever give you an approximation of a real-world system but in many cases this is all that's needed. The complexity of setting up a 100% accurate test environment is a daunting task and one that may never provide ROI vs the effort spent configuring and maintaining it.
If perfect accuracy is indeed required, then PDQTest is not what you are looking for and you should look towards solutions like Beaker or Kitchen CI.
No, you don't have to choose! PDQTest integrates with PDK by making the minimal amount of invasive changes:
New projects should be created using PDK: pdk new module
.
This will give you all the PDK versioned files you would ever need. When you run
pdqtest init
on a new project created with PDK, we only copy in our own
integration files and do not not touch the PDK generated files at all (the ones
marked 🛠 below).
After running pdqtest init
, run pdk update
to have PDK process the
.sync.yml
we installed.
To make upgrading to PDQTest 2.0 + PDK easy for our existing users, we automate
the workflow normally carried out by pdk convert
.
We do not include the entire set of files that would have been generated by
pdk convert
or pdk new module
. If you want the full set, you should run
one of these commands yourself before pdqtest init
and the resulting files
will be left alone unless PDK starts writing new files that we are already
using.
metadata.json
- Enable PDK by adding the fields:
pdk-version
template-url
template-ref
The values for these fields are obtained automatically from PDK itself and are consistent with the system installed PDK (we generate a temporary project and read files/values from it).
Gemfile.project
If you require PDK to know about a particular gem for your project, add it to this file and then run:
Linux
make Gemfile.local
Windows
.\make.ps1 Gemfile.local
Depending on platform, this will symlink or copy Gemfile.project
to
Gemfile.local
respectively, then run pdk bundle install
to update PDK's
knowledge of the new gem.
Miscellaneous skeletons
When pdqtest init
is run, we install a small set of skeleton files in the root
of your project. This is a one-off operation to get you started and is only
done if your project is not already marked PDK compatible.
After your module has been marked as PDK compatible, you must only manage these files using PDK.
Skeletons are generated on the fly using PDK itself, so they are always up-to-date according to the PDK you have installed on your system.
If you have an existing Puppet project that does not use PDQTest or PDK (eg
created by hand or with the old puppet module generate
command), then the
recommended way to enable PDQTest is to first enable PDK by running
pdk convert
, then follow the wizard.
You may then enable PDQTest
by running pdqtest init
.
Depending on the state of your project, you may be able to bypass the
pdk convert
process by just running pdqtest init
but this isn't recommended
or supported.
- 🛠 - File generated by PDK
- ⚡ - File updated/replaced when you run
pdqtest upgrade
:
├── appveyor.yml ⚡
├── bitbucket-pipelines.yml ⚡
├── Gemfile 🛠
├── Gemfile.local
├── Gemfile.project
├── .gitattributes 🛠
├── .gitignore 🛠
├── Makefile ⚡
├── make.ps1 ⚡
├── .pdkignore 🛠
├── .pdqtest
│ ├── Gemfile ⚡
│ └── Gemfile.lock
├── .puppet-lint.rc
├── Rakefile 🛠
├── spec
│ ├── default_facts.yml 🛠
│ ├── fixtures
│ │ ├── hieradata
│ │ │ └── test.yaml
│ │ └── hiera.yaml
│ └── spec_helper.rb 🛠
└── .travis.yml ⚡
Notes:
appveyor.yml
- Complete test suite for Windows modules.travis.yml
- Complete test suite for Linux modulesbitbucket-pipelines.yaml
- logical testing only (unit/RSpec).puppet-lint.rc
- Make lint errors test failures, ignore double quotes, etcMakefile
- Essential launch script for Linuxmake.ps1
- Essential launch script for Windowsspec/fixtures/hiera.yaml
- Mock system-widehiera.yaml
filespec/fixtures/hieradata/test.yaml
- Mock system-wide hieradataGemfile.project
- Used to enable additional gems in PDK if needed (eg for RSpec)Gemfile.local
- Transient file created at runtime byMakefile
ormake.ps1
to enable additional PDK gems see details below.gitignore
- PDK has a massive list of files to ignore for new projects so these are imported and we add some of our own.gitattributes
- PDK doesn't process this onpdk update
so it ignores our.sync.yml
customisations. This is handy to force LF for teams working on windows.pdqtest/Gemfile
- it's impossible to share aGemfile
with PDK (believe me I tried) Therefore we need our own and it lives here. See details below..pdqtest/Gemfile.lock
- corresponding lock for PDQTest
PDK provides its own Gemfile
to select the gems available at runtime. There
are hooks in this file to load additional configuration from two locations:
~/.gemfile
YOUR_PROJECT/Gemfile.local
These are good for loading additional GEMs that run inside the PDK ruby
environment created by the pdk
command only! PDK modifies it's Gemfile
at
runtime according to the target being run and this which makes it unsafe for us
to load the pdqtest
gem here, because the bundle will change while it is being
used.
Using pdk bundle exec
as basically an alias for bundle exec
did not work as
PDQTest needs to call the pdk
command for its lifecycle targets. This caused
serious errors on Windows.
We are not supposed to store permanent data in Gemfile.local
as its in
PDK's generated .gitignore
. The workaround to this is for us to create our own
per-project Gemfile
with the gems we would have liked to have put in
Gemfile.local
and copy/symlink as required.
The main use of this is to load additional gems during the pdk test unit
phase
that without customising via .sync.yml
or a custom template repository
(although these should work too/instead).
For further background see:
Since PDK updates Gemfile
during execution, the only sensible option for
loading PDQTest is to have our own directory containing our own Gemfile
and Gemfile.lock
:
.pdqtest/Gemfile
.pdqtest/Gemfile.lock
This affords complete separation from PDK and lets us use the provided ruby. The
only caveat is that we must cd
into the .pdqtest
directory before executing
the pdqtest
command.
When you run pdqtest upgrade
, it will update .pdqtest/Gemfile
with the newer
version of the pdqtest
gem.
As ever, the per-project .pdqtest/Gemfile
means that we support side-by-side
installation of all versions of PDQTest while letting PDK take over the main
Gemfile
ensures full PDK compatibility.
To support these two scenarios, Makefile
and make.ps1
automate the project
preparation (bundling/symlinking) by providing the following targets:
Gemfile.local
:- Windows: Copy
Gemfile.project
toGemfile.local
, replacing any content, then runpdk bundle
to update PDKs gems - Linux: Symlink
Gemfile.local
toGemfile.project
, then runpdk bundle
to update PDKs gems
- Windows: Copy
pdqtestbundle
- runbundle install
using system/custom ruby against.pdqtest/Gemfile
pdkbundle
- runpdk bundle install
to re-bundle PDK
The remaining targets all work by jumping into the .pdqtest
directory and then
using .pdqtest/Gemfile
to launch pdqtest
. This avoids users having to jump
around the project directories to get work done.
For this reason, you must launch PDQTest using the provided Makefile
or
make.ps1
scripts, at until your familiar with jumping to the .pdqtest
directory to run bundle exec pdqtest
yourself.
When PDQTest is upgraded, we update the files above marked ⚡ in your project.
This doesn't impact PDK at all with the exception that we take over
.travis.yml
since the PDK one doesn't do what we want it to.
PDK operates independently from PDQTest and maintains its own files. Your free
to run pdk update
to upgrade the your files to the latest PDK templated ones
whenever you like.
To protect PDQTest files from alteration (notably .travis.yml
and
bitbucket-pipelines.yml
) we merge instructions to have PDK leave them alone
to .sync.yml
(merging with any existing rules) to prevent churn.
If you have further customisations to PDK controlled files your options are:
- Use git to revert any change by PDK
- Use
.sync.yml
to influence file (re)generation blog reference example
You can run any pdk
command as described in the PDK documentation. PDQTest
does not stop you running anything. If you find this not to be the case please
open a ticket
PDQTest | PDK |
---|---|
logical |
pdk validate metadata,puppet , pdk test unit |
all |
pdk validate metadata,puppet , pdk test unit , pdk build --force |
fast |
N/A - run puppet-lint and rake syntax to finish faster |
bundle exec pdqtest all
is the default target executed by make
and
.\make.ps1
. The complete run looks like this:
pdk validate 'metadata,puppet'
- Install modules listed in the
metadata.json
file using R10K against a temporaryPuppetfile
atPuppetfile.pdqtest
- Generate a
.fixtures.yml
file based onmetadata.json
pdk test unit
- Run all acceptance tests
puppet strings generate --format=markdown
to generateREFERENCE.md
pdk build --force
to generate your forge package
At each stage of the process, we output emoji's to keep you informed of progress. Any failure prevents running the next phase of testing and lint errors are considered failures.
This is a side effect of having to shell out to run PDK via system calls. There's really no other way to do this while maintaining full PDK compatibility (if you know different, please open a ticket and let me know how).
That said you might just want to run syntax and lint tests and acceptance tests as quick as possible, in which case run:
Linux
make fast
Windows
.\make.ps1 fast
This runs the syntax and lint tests using the original puppet-syntax
and
puppet-lint
libraries. We can't guarantee PDK identical behaviour or
compatibility when used this way but hey... its faster.
With PDK!:
pdk validate -a
We use our own gem version of puppet
and puppet-strings
because
puppet-strings
is not shipped by PDK.
We execute puppet strings
outside of ruby for simplicity.