kitchen-pester 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +401 -0
- data/kitchen-pester.gemspec +14 -7
- data/lib/kitchen/verifier/pester.rb +233 -69
- data/lib/kitchen/verifier/pester_version.rb +31 -1
- data/lib/support/modules/PesterUtil/PesterUtil.psm1 +20 -0
- metadata +41 -22
- data/Gemfile +0 -29
- data/Rakefile +0 -57
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2265777e3844674d88d2c9fee716b53e51931370db862b9ae1ab1e0e146a0d3f
|
|
4
|
+
data.tar.gz: ea5c52a19e982eb5f762d342a098160723120b4800734b611c1da782a0a49b62
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 521b9f823e6e4229dc55753e1a19c809056a70855276a5ab512ebcc4e41f9301396cd05deba5a8fe40528f1df25705f069c73401eeb8d67acd3501d9e7f3e502
|
|
7
|
+
data.tar.gz: 1294cc1198df01d440000612209d21b23d4904129d0b9fe2092b37a9186030819c87a145b88ea37526f544ce40e2ede8f616d2ea428f57bd878fc01d6b8902cc
|
data/README.md
ADDED
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
# kitchen-pester
|
|
2
|
+
|
|
3
|
+
[](http://badge.fury.io/rb/kitchen-pester)
|
|
4
|
+
|
|
5
|
+
Run [Pester](https://pester.dev/) tests against a machine that
|
|
6
|
+
[Test Kitchen](https://kitchen.ci/) built for you.
|
|
7
|
+
|
|
8
|
+
Test Kitchen creates the machine, your provisioner configures it, and
|
|
9
|
+
kitchen-pester copies your `*.Tests.ps1` files onto it, installs Pester, runs
|
|
10
|
+
the tests, and brings the results back. No Busser layer in between.
|
|
11
|
+
|
|
12
|
+
It works on Windows and on Linux or macOS instances with
|
|
13
|
+
[PowerShell](https://github.com/PowerShell/PowerShell) installed.
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
### 1. Install the gem
|
|
18
|
+
|
|
19
|
+
This verifier ships as part of [Cinc Workstation](https://cinc.sh/start/workstation/).
|
|
20
|
+
If you have Cinc Workstation installed, there is nothing else to install.
|
|
21
|
+
|
|
22
|
+
To install it into a standalone Ruby:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
gem install kitchen-pester
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
or add it to your `Gemfile`:
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
gem "kitchen-pester"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The examples below use the `cinc` commands. Everything here works identically
|
|
35
|
+
with Chef Workstation — see [Using with Chef](#using-with-chef).
|
|
36
|
+
|
|
37
|
+
### 2. Point Test Kitchen at it
|
|
38
|
+
|
|
39
|
+
In `kitchen.yml`:
|
|
40
|
+
|
|
41
|
+
```yaml
|
|
42
|
+
verifier:
|
|
43
|
+
name: pester
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
You can set this at the top level, per platform, or per suite.
|
|
47
|
+
|
|
48
|
+
### 3. Put your tests where it will find them
|
|
49
|
+
|
|
50
|
+
For a suite named `default`, that is `tests/integration/default/`:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
tests/
|
|
54
|
+
└── integration/
|
|
55
|
+
├── default/
|
|
56
|
+
│ └── myapp.Tests.ps1
|
|
57
|
+
└── helpers/ # optional, copied to every suite
|
|
58
|
+
└── Assertions.ps1
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 4. Write a test
|
|
62
|
+
|
|
63
|
+
An ordinary Pester file — nothing kitchen-specific:
|
|
64
|
+
|
|
65
|
+
```powershell
|
|
66
|
+
Describe 'myapp' {
|
|
67
|
+
It 'installed the binary' {
|
|
68
|
+
'C:\Program Files\myapp\myapp.exe' | Should -Exist
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
It 'is listening on 8080' {
|
|
72
|
+
Get-NetTCPConnection -LocalPort 8080 | Should -Not -BeNullOrEmpty
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 5. Run it
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
cinc kitchen verify
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Results are written to `./testresults/PesterTestResults.xml` in NUnit format,
|
|
84
|
+
ready for a CI system to pick up. A failing Pester test fails `cinc kitchen verify`.
|
|
85
|
+
|
|
86
|
+
## How it works
|
|
87
|
+
|
|
88
|
+
Worth knowing when something goes wrong:
|
|
89
|
+
|
|
90
|
+
1. **Sandbox.** Your suite's tests, any `helpers/`, anything in `copy_folders`,
|
|
91
|
+
and kitchen-pester's own `PesterUtil` PowerShell module are staged into a
|
|
92
|
+
local temp directory.
|
|
93
|
+
2. **Transfer.** Test Kitchen ships that sandbox to the instance, under
|
|
94
|
+
`$env:TEMP/verifier` on Windows or `/tmp/verifier` elsewhere.
|
|
95
|
+
3. **Prepare.** kitchen-pester prepends the sandbox's `modules/` folder to
|
|
96
|
+
`$env:PSModulePath`, then installs Pester and anything in
|
|
97
|
+
`install_modules`.
|
|
98
|
+
4. **Run.** It writes a `kitchen_cmd.ps1` on the instance and invokes it. Your
|
|
99
|
+
tests run from the `suites/` folder inside the sandbox.
|
|
100
|
+
5. **Download.** Everything in `downloads` is copied back — including when the
|
|
101
|
+
run fails, so you always get the results file.
|
|
102
|
+
|
|
103
|
+
Every step is generated PowerShell. If a run misbehaves, `kitchen_cmd.ps1` on
|
|
104
|
+
the instance is the exact script that ran.
|
|
105
|
+
|
|
106
|
+
## Pester versions
|
|
107
|
+
|
|
108
|
+
kitchen-pester supports **Pester 5** (the default) and **Pester 4**.
|
|
109
|
+
|
|
110
|
+
It detects the installed version on the instance and adapts: Pester 5 gets a
|
|
111
|
+
`PesterConfiguration` object built from your `pester_configuration`, Pester 4
|
|
112
|
+
gets loose `Invoke-Pester` parameters. You do not need to tell it which one
|
|
113
|
+
you are on.
|
|
114
|
+
|
|
115
|
+
To stay on Pester 4, cap the install:
|
|
116
|
+
|
|
117
|
+
```yaml
|
|
118
|
+
verifier:
|
|
119
|
+
name: pester
|
|
120
|
+
pester_install:
|
|
121
|
+
MaximumVersion: '4.99.999'
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Configuration
|
|
125
|
+
|
|
126
|
+
All of these go under `verifier:` in `kitchen.yml`.
|
|
127
|
+
|
|
128
|
+
### Common
|
|
129
|
+
|
|
130
|
+
| Option | Type | Default | What it does |
|
|
131
|
+
| --- | --- | --- | --- |
|
|
132
|
+
| `test_folder` | string | `tests` | Where your tests live. See [Test discovery](#test-discovery). |
|
|
133
|
+
| `downloads` | map | `{"./PesterTestResults.xml" => "./testresults/"}` | Files to copy back from the instance. See [Downloads](#downloads). |
|
|
134
|
+
| `environment` | map | `{}` | Environment variables to set for your tests. |
|
|
135
|
+
| `copy_folders` | array | `[]` | Local folders to copy to the instance and put on `$env:PSModulePath`. |
|
|
136
|
+
| `pester_configuration` | map | see [below](#pester_configuration) | Passed through to Pester. |
|
|
137
|
+
| `root_path` | string | driver default | Directory on the SUT the sandbox is copied into. Relative `copy_folders` sources and the `suites` directory resolve against it, and `PesterTestResults.xml` is written there. |
|
|
138
|
+
| `suite_name` | string | the suite name | Name of the suite, used when locating its tests. |
|
|
139
|
+
|
|
140
|
+
### Installing Pester and its dependencies
|
|
141
|
+
|
|
142
|
+
| Option | Type | Default | What it does |
|
|
143
|
+
| --- | --- | --- | --- |
|
|
144
|
+
| `pester_install` | map | `{SkipPublisherCheck: true, Force: true, ErrorAction: "Stop"}` | Splatted to `Install-Module -Name Pester`. |
|
|
145
|
+
| `skip_pester_install` | bool | `false` | Use whatever Pester is already on the box. |
|
|
146
|
+
| `install_modules` | array | `[]` | Extra modules to install from a gallery. |
|
|
147
|
+
| `register_repository` | array | `[]` | PSRepositories to register first, for private feeds. |
|
|
148
|
+
| `bootstrap` | map | `{repository_url: "https://www.powershellgallery.com/api/v2", modules: []}` | Modules to fetch straight from a NuGet feed, before PowerShellGet is usable. |
|
|
149
|
+
| `remove_builtin_pester` | bool | `true` | Remove the Pester 3.4.0 that ships with Windows. |
|
|
150
|
+
| `remove_builtin_powershellget` | bool | `true` | Remove the PowerShellGet and PackageManagement 1.0.0.1 that ship with Windows. |
|
|
151
|
+
|
|
152
|
+
### Platform and shell
|
|
153
|
+
|
|
154
|
+
| Option | Type | Default | What it does |
|
|
155
|
+
| --- | --- | --- | --- |
|
|
156
|
+
| `shell` | string | `nil` | Shell binary to use. Defaults to `powershell` on Windows, `pwsh` elsewhere. |
|
|
157
|
+
| `sudo` | bool | `false` | Run PowerShell under sudo. Non-Windows only. |
|
|
158
|
+
| `restart_winrm` | bool | `false` | Restart WinRM via a scheduled task before verifying. Windows only. |
|
|
159
|
+
|
|
160
|
+
### Test discovery
|
|
161
|
+
|
|
162
|
+
`test_folder` is where kitchen-pester starts looking. It may be relative to
|
|
163
|
+
the directory you run `kitchen` from, or absolute, and it must exist.
|
|
164
|
+
|
|
165
|
+
If `<test_folder>/integration` exists, that becomes the root instead — which is
|
|
166
|
+
why the default `tests` finds `tests/integration`. Within that root:
|
|
167
|
+
|
|
168
|
+
- `<root>/<suite_name>/` is copied to the instance and is what Pester runs.
|
|
169
|
+
Nest files however you like; Pester recurses.
|
|
170
|
+
- `<root>/helpers/` is copied alongside **every** suite.
|
|
171
|
+
|
|
172
|
+
### Downloads
|
|
173
|
+
|
|
174
|
+
The key is the file on the instance, the value is where to put it locally.
|
|
175
|
+
|
|
176
|
+
The **source** may be relative to the verifier folder (`$env:TEMP/verifier` by
|
|
177
|
+
default) or absolute (`/var/tmp/file.zip`, `C:\Windows\Temp\file.zip`).
|
|
178
|
+
|
|
179
|
+
The **destination** may be relative to the current directory or absolute, may
|
|
180
|
+
end in `/` or `\` to mean "a directory, keep the filename", and may contain
|
|
181
|
+
`%{instance_name}` to keep results from different instances apart:
|
|
182
|
+
|
|
183
|
+
```yaml
|
|
184
|
+
verifier:
|
|
185
|
+
name: pester
|
|
186
|
+
downloads:
|
|
187
|
+
PesterTestResults.xml: "testresults/%{instance_name}/"
|
|
188
|
+
kitchen_cmd.ps1: "testresults/%{instance_name}/"
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Downloading `kitchen_cmd.ps1` like that is a useful debugging trick: it is the
|
|
192
|
+
generated script that actually ran.
|
|
193
|
+
|
|
194
|
+
### pester_configuration
|
|
195
|
+
|
|
196
|
+
Defaults to:
|
|
197
|
+
|
|
198
|
+
```yaml
|
|
199
|
+
run:
|
|
200
|
+
path: "."
|
|
201
|
+
PassThru: true
|
|
202
|
+
TestResult:
|
|
203
|
+
Enabled: true
|
|
204
|
+
OutputPath: PesterTestResults.xml
|
|
205
|
+
TestSuiteName: ""
|
|
206
|
+
Output:
|
|
207
|
+
Verbosity: Detailed
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**On Pester 5**, this becomes a `PesterConfiguration` via
|
|
211
|
+
`New-PesterConfiguration -Hashtable`. Three keys are filled in for you if you
|
|
212
|
+
leave them unset:
|
|
213
|
+
|
|
214
|
+
| Key | Filled in with |
|
|
215
|
+
| --- | --- |
|
|
216
|
+
| `Run.Path` | `$env:TEMP/verifier/suites` |
|
|
217
|
+
| `TestResult.TestSuiteName` | `Pester - <kitchen instance name>` |
|
|
218
|
+
| `TestResult.OutputPath` | `$env:TEMP/verifier/PesterTestResults.xml` |
|
|
219
|
+
|
|
220
|
+
**On Pester 4**, keys matching a real `Invoke-Pester` parameter are used and
|
|
221
|
+
the rest are ignored. These defaults apply unless you set them:
|
|
222
|
+
|
|
223
|
+
| Parameter | Default |
|
|
224
|
+
| --- | --- |
|
|
225
|
+
| `Script` | `$env:TEMP/verifier/suites` |
|
|
226
|
+
| `OutputFile` | `$env:TEMP/verifier/PesterTestResults.xml` |
|
|
227
|
+
| `OutputFormat` | `NUnitXml` |
|
|
228
|
+
| `PassThru` | `true` |
|
|
229
|
+
| `PesterOption` | `New-PesterOption -TestSuiteName "Pester - <instance name>"` |
|
|
230
|
+
|
|
231
|
+
### register_repository
|
|
232
|
+
|
|
233
|
+
Each entry is splatted to `Register-PSRepository`, or `Set-PSRepository` if the
|
|
234
|
+
repository already exists:
|
|
235
|
+
|
|
236
|
+
```yaml
|
|
237
|
+
verifier:
|
|
238
|
+
name: pester
|
|
239
|
+
register_repository:
|
|
240
|
+
- Name: MyPrivateNuget
|
|
241
|
+
SourceLocation: https://mypsrepo.local/api/v2
|
|
242
|
+
InstallationPolicy: trusted
|
|
243
|
+
PackageManagementProvider: Nuget
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### install_modules
|
|
247
|
+
|
|
248
|
+
Plain names, or maps splatted to `Install-Module`:
|
|
249
|
+
|
|
250
|
+
```yaml
|
|
251
|
+
verifier:
|
|
252
|
+
name: pester
|
|
253
|
+
install_modules:
|
|
254
|
+
- PSScriptAnalyzer
|
|
255
|
+
- Name: MyModule
|
|
256
|
+
Repository: MyPrivateRepo
|
|
257
|
+
SkipPublisherCheck: true
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### bootstrap
|
|
261
|
+
|
|
262
|
+
For machines where PowerShellGet is too old to install anything — notably a
|
|
263
|
+
stock Windows image. Modules are downloaded and unzipped straight from the
|
|
264
|
+
NuGet API, bypassing `Install-Module` entirely.
|
|
265
|
+
|
|
266
|
+
The feed must serve `$repository_url/package/<ModuleName>`, which some private
|
|
267
|
+
feed implementations do not.
|
|
268
|
+
|
|
269
|
+
```yaml
|
|
270
|
+
verifier:
|
|
271
|
+
name: pester
|
|
272
|
+
bootstrap:
|
|
273
|
+
repository_url: https://www.powershellgallery.com/api/v2
|
|
274
|
+
modules:
|
|
275
|
+
- PackageManagement
|
|
276
|
+
- PowerShellGet
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
> **Note:** this key is replaced wholesale, not merged. If you set `modules`,
|
|
280
|
+
> set `repository_url` too.
|
|
281
|
+
|
|
282
|
+
## Examples
|
|
283
|
+
|
|
284
|
+
### Testing a PowerShell module you just built
|
|
285
|
+
|
|
286
|
+
`copy_folders` puts your build output on the instance's `$env:PSModulePath`,
|
|
287
|
+
so your tests can `Import-Module MyModule` as if it were installed:
|
|
288
|
+
|
|
289
|
+
```yaml
|
|
290
|
+
verifier:
|
|
291
|
+
name: pester
|
|
292
|
+
copy_folders:
|
|
293
|
+
- output/MyModule
|
|
294
|
+
downloads:
|
|
295
|
+
PesterTestResults.xml: "testresults/%{instance_name}/"
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### A stock Windows image
|
|
299
|
+
|
|
300
|
+
Windows ships Pester 3.4.0 and PowerShellGet 1.0.0.1, neither of which can
|
|
301
|
+
install a modern Pester on its own. The defaults already remove both; bootstrap
|
|
302
|
+
replacements from NuGet so the install has something to work with:
|
|
303
|
+
|
|
304
|
+
```yaml
|
|
305
|
+
verifier:
|
|
306
|
+
name: pester
|
|
307
|
+
bootstrap:
|
|
308
|
+
repository_url: https://www.powershellgallery.com/api/v2
|
|
309
|
+
modules:
|
|
310
|
+
- PackageManagement
|
|
311
|
+
- PowerShellGet
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Linux, with PowerShell installed on the fly
|
|
315
|
+
|
|
316
|
+
Use Test Kitchen's lifecycle hooks to install `pwsh` after the machine comes
|
|
317
|
+
up. A recent `pwsh` ships a usable PowerShellGet, so no bootstrap is needed:
|
|
318
|
+
|
|
319
|
+
```yaml
|
|
320
|
+
provisioner:
|
|
321
|
+
name: shell
|
|
322
|
+
script: tests/integration/provisioning.ps1
|
|
323
|
+
|
|
324
|
+
verifier:
|
|
325
|
+
name: pester
|
|
326
|
+
|
|
327
|
+
platforms:
|
|
328
|
+
- name: ubuntu-22.04
|
|
329
|
+
lifecycle:
|
|
330
|
+
post_create:
|
|
331
|
+
- remote: sudo snap install powershell --classic
|
|
332
|
+
|
|
333
|
+
suites:
|
|
334
|
+
- name: default
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
If `pwsh` is only reachable through sudo — as with a snap install on some
|
|
338
|
+
systems — add `sudo: true` to the verifier.
|
|
339
|
+
|
|
340
|
+
### Passing secrets and settings to your tests
|
|
341
|
+
|
|
342
|
+
```yaml
|
|
343
|
+
verifier:
|
|
344
|
+
name: pester
|
|
345
|
+
environment:
|
|
346
|
+
API_KEY: <%= ENV['API_KEY'] %>
|
|
347
|
+
PUSH_URI: https://push.example.com
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
```powershell
|
|
351
|
+
Describe 'configuration' {
|
|
352
|
+
It 'received the API key' {
|
|
353
|
+
$env:API_KEY | Should -Not -BeNullOrEmpty
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## Troubleshooting
|
|
359
|
+
|
|
360
|
+
**`cinc kitchen verify` fails but I get no results file.** You should still get one
|
|
361
|
+
— downloads run even when the verify fails. If the file is missing, the run
|
|
362
|
+
died before Pester started; check the `cinc kitchen verify` output for the install
|
|
363
|
+
step.
|
|
364
|
+
|
|
365
|
+
**I want to see the script that ran.** Add `kitchen_cmd.ps1` to `downloads`,
|
|
366
|
+
or look for it in `$env:TEMP/verifier` on the instance.
|
|
367
|
+
|
|
368
|
+
**`Install-Module` cannot find a repository.** The built-in PowerShellGet was
|
|
369
|
+
removed (the default) and nothing replaced it. Either `bootstrap` a newer
|
|
370
|
+
PowerShellGet, or set `remove_builtin_powershellget: false` if the machine's
|
|
371
|
+
own copy works.
|
|
372
|
+
|
|
373
|
+
**Tests are not found.** Check that your files are under
|
|
374
|
+
`<test_folder>/integration/<suite_name>/` and match Pester's discovery
|
|
375
|
+
pattern (`*.Tests.ps1`), and that the suite name in `kitchen.yml` matches the
|
|
376
|
+
folder name.
|
|
377
|
+
|
|
378
|
+
**PowerShell is not installed on a Linux instance.** kitchen-pester does not
|
|
379
|
+
install it. Use a lifecycle hook or your provisioner.
|
|
380
|
+
|
|
381
|
+
## Using with Chef
|
|
382
|
+
|
|
383
|
+
This verifier runs Pester and does not depend on Cinc or Chef being installed on
|
|
384
|
+
the system under test — it works with any Test Kitchen driver and provisioner.
|
|
385
|
+
|
|
386
|
+
The examples above use [Cinc Workstation](https://cinc.sh/start/workstation/) and
|
|
387
|
+
the `cinc kitchen` commands. With
|
|
388
|
+
[Chef Workstation](https://www.chef.io/downloads/tools/workstation) run `kitchen`
|
|
389
|
+
instead of `cinc kitchen`. No verifier configuration changes are needed.
|
|
390
|
+
|
|
391
|
+
## Contributing
|
|
392
|
+
|
|
393
|
+
Bug reports and pull requests are welcome on
|
|
394
|
+
[GitHub](https://github.com/test-kitchen/kitchen-pester). See
|
|
395
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) for development setup, how to run the unit
|
|
396
|
+
specs, the PowerShell module specs, and the integration suite, and how the
|
|
397
|
+
documentation is generated.
|
|
398
|
+
|
|
399
|
+
## License
|
|
400
|
+
|
|
401
|
+
MIT. See [LICENSE](LICENSE).
|
data/kitchen-pester.gemspec
CHANGED
|
@@ -1,24 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
lib = File.expand_path("lib", __dir__)
|
|
2
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
5
|
|
|
4
6
|
require "kitchen/verifier/pester_version"
|
|
5
7
|
|
|
6
8
|
Gem::Specification.new do |spec|
|
|
7
|
-
spec.name
|
|
9
|
+
spec.name = "kitchen-pester"
|
|
10
|
+
spec.required_ruby_version = ">= 3.1"
|
|
8
11
|
spec.version = Kitchen::Verifier::PESTER_VERSION
|
|
9
12
|
spec.authors = ["Steven Murawski"]
|
|
10
13
|
spec.email = ["steven.murawski@gmail.com"]
|
|
11
14
|
spec.summary = "Test-Kitchen verifier for Pester."
|
|
12
15
|
spec.description = "Skip all that Busser stuff and jump right into Pester."
|
|
13
16
|
spec.homepage = "https://github.com/test-kitchen/kitchen-pester"
|
|
14
|
-
spec.license = "
|
|
17
|
+
spec.license = "MIT"
|
|
15
18
|
|
|
16
|
-
|
|
19
|
+
# README.md is what YARD picks up as the front page of the generated docs,
|
|
20
|
+
# which is how rubydoc.info renders this gem.
|
|
21
|
+
spec.files = %w{LICENSE README.md kitchen-pester.gemspec} + Dir.glob("lib/**/*")
|
|
17
22
|
spec.require_paths = ["lib"]
|
|
18
23
|
|
|
19
24
|
spec.add_development_dependency "rake"
|
|
20
|
-
spec.add_development_dependency "minitest", "
|
|
21
|
-
spec.add_development_dependency "mocha", "
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
spec.add_development_dependency "minitest", ">= 5.25", "< 7"
|
|
26
|
+
spec.add_development_dependency "mocha", ">= 2.0", "< 4"
|
|
27
|
+
spec.add_development_dependency "yard", "~> 0.9"
|
|
28
|
+
# 3.6.0 is the first release to require Ruby >= 3.1, which this gem also
|
|
29
|
+
# requires, so anything older cannot be installed alongside it in practice.
|
|
30
|
+
spec.add_dependency "test-kitchen", ">= 3.6", "< 5"
|
|
24
31
|
end
|
|
@@ -1,31 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# Author:: Steven Murawski (<steven.murawski@gmail.com>)
|
|
2
4
|
#
|
|
3
|
-
# Copyright (
|
|
5
|
+
# Copyright (c) 2015 Steven Murawski
|
|
4
6
|
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
# furnished to do so, subject to the following conditions:
|
|
8
13
|
#
|
|
9
|
-
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be included in
|
|
15
|
+
# all copies or substantial portions of the Software.
|
|
10
16
|
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
23
|
+
# THE SOFTWARE.
|
|
16
24
|
|
|
17
25
|
require "fileutils" unless defined?(FileUtils)
|
|
18
26
|
require "pathname" unless defined?(Pathname)
|
|
19
27
|
require "kitchen/util"
|
|
20
28
|
require "kitchen/verifier/base"
|
|
21
|
-
require "kitchen/version"
|
|
22
|
-
require "base64" unless defined?(Base64)
|
|
23
29
|
require_relative "pester_version"
|
|
24
30
|
|
|
25
31
|
module Kitchen
|
|
26
32
|
|
|
27
33
|
module Verifier
|
|
28
34
|
|
|
35
|
+
# A Test Kitchen verifier that runs Pester tests on the system under test.
|
|
36
|
+
#
|
|
37
|
+
# The verifier does almost all of its work by generating PowerShell source
|
|
38
|
+
# locally and handing it to the transport to execute remotely. Each command
|
|
39
|
+
# hook -- {#install_command}, {#init_command}, {#prepare_command} and
|
|
40
|
+
# {#run_command} -- returns a script string rather than performing the work
|
|
41
|
+
# itself.
|
|
42
|
+
#
|
|
43
|
+
# Test files, helper files and any folders named in `copy_folders` are
|
|
44
|
+
# staged into a sandbox by {#create_sandbox}, shipped to the instance, and
|
|
45
|
+
# discovered there through `$Env:PSModulePath`.
|
|
46
|
+
#
|
|
47
|
+
# @example configuring the verifier in kitchen.yml
|
|
48
|
+
#
|
|
49
|
+
# verifier:
|
|
50
|
+
# name: pester
|
|
51
|
+
# test_folder: tests
|
|
52
|
+
# install_modules:
|
|
53
|
+
# - PSScriptAnalyzer
|
|
54
|
+
# downloads:
|
|
55
|
+
# ./PesterTestResults.xml: ./testresults/
|
|
56
|
+
#
|
|
57
|
+
# @see https://pester.dev/ Pester
|
|
29
58
|
class Pester < Kitchen::Verifier::Base
|
|
30
59
|
|
|
31
60
|
kitchen_verifier_api_version 1
|
|
@@ -95,6 +124,8 @@ module Kitchen
|
|
|
95
124
|
# # any further file copies, preparations, etc.
|
|
96
125
|
# end
|
|
97
126
|
# end
|
|
127
|
+
#
|
|
128
|
+
# @return [void]
|
|
98
129
|
def create_sandbox
|
|
99
130
|
super
|
|
100
131
|
prepare_supporting_psmodules
|
|
@@ -192,13 +223,16 @@ module Kitchen
|
|
|
192
223
|
source = source.to_s
|
|
193
224
|
destination = destination.gsub("%{instance_name}", instance.name)
|
|
194
225
|
info(" resolving remote source's absolute path.")
|
|
195
|
-
unless source.match?(
|
|
226
|
+
unless source.match?(%r{^/|^[a-zA-Z]:[\\/]}) # is Absolute?
|
|
196
227
|
info(" '#{source}' is a relative path, resolving to: #{File.join(config[:root_path], source)}")
|
|
197
228
|
source = File.join(config[:root_path], source.to_s).to_s
|
|
198
229
|
end
|
|
199
230
|
|
|
200
|
-
if destination.match?(
|
|
201
|
-
|
|
231
|
+
if destination.match?(%r{[\\/]$}) # is Folder (ends with / or \)
|
|
232
|
+
# Append to the separator the user already supplied. File.join
|
|
233
|
+
# would add a second one, of whichever flavour the workstation
|
|
234
|
+
# happens to use.
|
|
235
|
+
destination = "#{destination}#{remote_basename(source)}"
|
|
202
236
|
end
|
|
203
237
|
info(" Destination: #{destination}")
|
|
204
238
|
if !File.directory?(File.dirname(destination))
|
|
@@ -209,33 +243,34 @@ module Kitchen
|
|
|
209
243
|
|
|
210
244
|
[ source, destination ]
|
|
211
245
|
end
|
|
246
|
+
.to_h # Hash#map yields pairs; keep :downloads the hash it started as
|
|
212
247
|
nil # make sure we do not return anything
|
|
213
248
|
end
|
|
214
249
|
|
|
215
|
-
#
|
|
216
|
-
#
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
rescue
|
|
229
|
-
# If the verifier reports failure, we need to download the files ourselves.
|
|
230
|
-
# Test Kitchen's base verifier doesn't have the download in an `ensure` block.
|
|
231
|
-
info("Rescue to download test files.")
|
|
232
|
-
download_test_files(state) unless config[:downloads].nil?
|
|
233
|
-
# Rethrow original exception, we still want to register the failure.
|
|
234
|
-
raise
|
|
235
|
-
end
|
|
250
|
+
# Runs the verifier on the instance, retrieving the test results even
|
|
251
|
+
# when the run fails.
|
|
252
|
+
#
|
|
253
|
+
# @param state [Hash] mutable instance state
|
|
254
|
+
# @raise [Kitchen::ActionFailed] if the verification failed
|
|
255
|
+
# @return [void]
|
|
256
|
+
def call(state)
|
|
257
|
+
super
|
|
258
|
+
rescue
|
|
259
|
+
info("Rescue to download test files.")
|
|
260
|
+
download_test_files(state) unless config[:downloads].nil?
|
|
261
|
+
# Rethrow the original exception; the failure still has to register.
|
|
262
|
+
raise
|
|
236
263
|
end
|
|
237
264
|
|
|
238
|
-
#
|
|
265
|
+
# Returns the PowerShell that imports Pester and invokes it.
|
|
266
|
+
#
|
|
267
|
+
# Two dialects are emitted behind a version check evaluated on the SUT:
|
|
268
|
+
# Pester 4 and earlier take loose parameters, Pester 5 and later take a
|
|
269
|
+
# `PesterConfiguration` object. The script exits with Pester's failed
|
|
270
|
+
# test count so the transport registers the failure.
|
|
271
|
+
#
|
|
272
|
+
# @return [String] a PowerShell script
|
|
273
|
+
# @api private
|
|
239
274
|
def invoke_pester_scriptblock
|
|
240
275
|
<<-PS1
|
|
241
276
|
$PesterModule = Import-Module -Name Pester -Force -ErrorAction Stop -PassThru
|
|
@@ -308,7 +343,7 @@ module Kitchen
|
|
|
308
343
|
|
|
309
344
|
$resultXmlPath = (Join-Path -Path $TestPath -ChildPath 'result.xml')
|
|
310
345
|
if (Test-Path -Path $resultXmlPath) {
|
|
311
|
-
$result | Export-CliXml -Path
|
|
346
|
+
$result | Export-CliXml -Path $resultXmlPath
|
|
312
347
|
}
|
|
313
348
|
|
|
314
349
|
$LASTEXITCODE = $result.FailedCount
|
|
@@ -318,6 +353,17 @@ module Kitchen
|
|
|
318
353
|
PS1
|
|
319
354
|
end
|
|
320
355
|
|
|
356
|
+
# Returns the commands that install the bootstrap modules straight from
|
|
357
|
+
# a NuGet feed.
|
|
358
|
+
#
|
|
359
|
+
# This runs before PowerShellGet is available, so it uses
|
|
360
|
+
# `Install-ModuleFromNuget` from PesterUtil.psm1 rather than
|
|
361
|
+
# `Install-Module`. Each entry of `bootstrap.modules` may be a plain
|
|
362
|
+
# module name or a hash of parameters.
|
|
363
|
+
#
|
|
364
|
+
# @return [Array<String>, nil] one PowerShell fragment per module, or nil
|
|
365
|
+
# when no bootstrap modules are configured
|
|
366
|
+
# @api private
|
|
321
367
|
def get_powershell_modules_from_nugetapi
|
|
322
368
|
# don't return anything is the modules subkey or bootstrap is null
|
|
323
369
|
return if config.dig(:bootstrap, :modules).nil?
|
|
@@ -365,7 +411,7 @@ module Kitchen
|
|
|
365
411
|
# Returns the string command set the PSGallery as trusted, and
|
|
366
412
|
# Install Pester from gallery based on the params from Pester_install_params config
|
|
367
413
|
#
|
|
368
|
-
# @return
|
|
414
|
+
# @return [String] command to install Pester Module
|
|
369
415
|
# @api private
|
|
370
416
|
def install_pester
|
|
371
417
|
return if config[:skip_pester_install]
|
|
@@ -386,7 +432,7 @@ module Kitchen
|
|
|
386
432
|
end
|
|
387
433
|
|
|
388
434
|
# returns a piece of PS scriptblock for each Module to install
|
|
389
|
-
# from gallery that has been
|
|
435
|
+
# from gallery that has been specified in install_modules config.
|
|
390
436
|
#
|
|
391
437
|
# @return [Array<String>] array of PS commands.
|
|
392
438
|
# @api private
|
|
@@ -414,13 +460,31 @@ module Kitchen
|
|
|
414
460
|
end
|
|
415
461
|
end
|
|
416
462
|
|
|
463
|
+
# Note for anyone adding to the script builders below: Kitchen::Util.outdent!
|
|
464
|
+
# mutates the string it is handed, and this file sets
|
|
465
|
+
# `frozen_string_literal: true`. Interpolated literals are not frozen, so
|
|
466
|
+
# every heredoc that reaches outdent! today is fine -- but a heredoc with
|
|
467
|
+
# no `#{}` in it would be frozen and would raise FrozenError at runtime.
|
|
468
|
+
# Use +dup+ on any such string before passing it along.
|
|
469
|
+
|
|
470
|
+
# Wraps generated PowerShell in the platform's shell invocation.
|
|
471
|
+
#
|
|
472
|
+
# @param code [String] the PowerShell to run on the instance
|
|
473
|
+
# @return [String] a shell command string
|
|
474
|
+
# @api private
|
|
417
475
|
def really_wrap_shell_code(code)
|
|
418
476
|
windows_os? ? really_wrap_windows_shell_code(code) : really_wrap_posix_shell_code(code)
|
|
419
477
|
end
|
|
420
478
|
|
|
421
|
-
#
|
|
422
|
-
#
|
|
423
|
-
#
|
|
479
|
+
# Returns the shell binary used to run the generated script.
|
|
480
|
+
#
|
|
481
|
+
# An explicit `shell` config wins, which allows pwsh-preview or a full
|
|
482
|
+
# path to a specific binary. Otherwise Windows uses powershell and every
|
|
483
|
+
# other platform uses pwsh. `sudo` is honoured everywhere except the
|
|
484
|
+
# Windows branch, where it is meaningless.
|
|
485
|
+
#
|
|
486
|
+
# @return [String] the shell command, prefixed with sudo when configured
|
|
487
|
+
# @api private
|
|
424
488
|
def shell_cmd
|
|
425
489
|
if !config[:shell].nil?
|
|
426
490
|
config[:sudo] ? "sudo #{config[:shell]}" : "#{config[:shell]}"
|
|
@@ -431,6 +495,15 @@ module Kitchen
|
|
|
431
495
|
end
|
|
432
496
|
end
|
|
433
497
|
|
|
498
|
+
# Wraps PowerShell for a Windows instance.
|
|
499
|
+
#
|
|
500
|
+
# The payload is written to kitchen_cmd.ps1 and invoked, rather than
|
|
501
|
+
# passed on the command line, so that quoting and length limits do not
|
|
502
|
+
# apply to it.
|
|
503
|
+
#
|
|
504
|
+
# @param code [String] the PowerShell to run on the instance
|
|
505
|
+
# @return [String] a shell command string
|
|
506
|
+
# @api private
|
|
434
507
|
def really_wrap_windows_shell_code(code)
|
|
435
508
|
my_command = <<-PWSH
|
|
436
509
|
echo "Running as '$(whoami)'..."
|
|
@@ -456,8 +529,15 @@ module Kitchen
|
|
|
456
529
|
wrap_shell_code(Util.outdent!(my_command))
|
|
457
530
|
end
|
|
458
531
|
|
|
459
|
-
#
|
|
460
|
-
#
|
|
532
|
+
# Wraps PowerShell for a non-Windows instance.
|
|
533
|
+
#
|
|
534
|
+
# Writes the payload to kitchen_cmd.ps1 through a quoted heredoc, so the
|
|
535
|
+
# POSIX shell does not interpolate PowerShell variables, adds a pwsh
|
|
536
|
+
# shebang and invokes it.
|
|
537
|
+
#
|
|
538
|
+
# @param code [String] the PowerShell to run on the instance
|
|
539
|
+
# @return [String] a shell command string
|
|
540
|
+
# @api private
|
|
461
541
|
def really_wrap_posix_shell_code(code)
|
|
462
542
|
my_command = <<-BASH
|
|
463
543
|
echo "Running as '$(whoami)'"
|
|
@@ -478,6 +558,12 @@ module Kitchen
|
|
|
478
558
|
Util.outdent!(my_command)
|
|
479
559
|
end
|
|
480
560
|
|
|
561
|
+
# Prefixes a script with the preamble that makes the sandbox's modules
|
|
562
|
+
# folder importable.
|
|
563
|
+
#
|
|
564
|
+
# @param script [String] the PowerShell to run after the preamble
|
|
565
|
+
# @return [String] the script with the PSModulePath preamble prepended
|
|
566
|
+
# @api private
|
|
481
567
|
def use_local_powershell_modules(script)
|
|
482
568
|
<<-PS1
|
|
483
569
|
Write-Host -Object ("{0} - PowerShell {1}" -f $PSVersionTable.OS,$PSVersionTable.PSVersion)
|
|
@@ -497,6 +583,16 @@ module Kitchen
|
|
|
497
583
|
PS1
|
|
498
584
|
end
|
|
499
585
|
|
|
586
|
+
# Returns the PowerShell that prepares the SUT once the sandbox has been
|
|
587
|
+
# transferred.
|
|
588
|
+
#
|
|
589
|
+
# Runs after the transfer so that PesterUtil.psm1 is available to import.
|
|
590
|
+
# Composes, in order: the NuGet bootstrap, any PSRepository registration,
|
|
591
|
+
# the Pester install, and any gallery modules. Each section is omitted
|
|
592
|
+
# when its config is nil.
|
|
593
|
+
#
|
|
594
|
+
# @return [String] a PowerShell script
|
|
595
|
+
# @api private
|
|
500
596
|
def install_command_script
|
|
501
597
|
<<-PS1
|
|
502
598
|
$PSModPathToPrepend = "#{config[:root_path]}"
|
|
@@ -513,8 +609,16 @@ module Kitchen
|
|
|
513
609
|
PS1
|
|
514
610
|
end
|
|
515
611
|
|
|
612
|
+
# Returns the command that schedules and runs a WinRM restart.
|
|
613
|
+
#
|
|
614
|
+
# The restart is driven through a scheduled task so that it survives the
|
|
615
|
+
# WinRM session being torn down by the restart itself.
|
|
616
|
+
#
|
|
617
|
+
# @return [String, nil] a shell command string, or nil on a non-Windows
|
|
618
|
+
# instance
|
|
619
|
+
# @api private
|
|
516
620
|
def restart_winrm_service
|
|
517
|
-
return unless
|
|
621
|
+
return unless windows_os?
|
|
518
622
|
|
|
519
623
|
cmd = "schtasks /Create /TN restart_winrm /TR " \
|
|
520
624
|
'"powershell -Command Restart-Service winrm" ' \
|
|
@@ -526,6 +630,12 @@ module Kitchen
|
|
|
526
630
|
))
|
|
527
631
|
end
|
|
528
632
|
|
|
633
|
+
# Retrieves the configured result files from the instance.
|
|
634
|
+
#
|
|
635
|
+
# @param state [Hash] mutable instance state, used to open the transport
|
|
636
|
+
# connection
|
|
637
|
+
# @return [void]
|
|
638
|
+
# @api private
|
|
529
639
|
def download_test_files(state)
|
|
530
640
|
if config[:downloads].nil?
|
|
531
641
|
info("Skipped downloading test result file from #{instance.to_str}; 'downloads' hash is empty.")
|
|
@@ -581,8 +691,9 @@ module Kitchen
|
|
|
581
691
|
end
|
|
582
692
|
|
|
583
693
|
# Copies all common testing helper files into the suites directory in
|
|
584
|
-
# the sandbox.
|
|
694
|
+
# the sandbox, stripping the `helpers/` prefix from their paths.
|
|
585
695
|
#
|
|
696
|
+
# @return [void]
|
|
586
697
|
# @api private
|
|
587
698
|
def prepare_helpers
|
|
588
699
|
base = File.join(test_folder, "helpers")
|
|
@@ -595,9 +706,15 @@ module Kitchen
|
|
|
595
706
|
end
|
|
596
707
|
end
|
|
597
708
|
|
|
598
|
-
#
|
|
599
|
-
#
|
|
709
|
+
# Renders a Ruby value as PowerShell source.
|
|
710
|
+
#
|
|
711
|
+
# Hashes become hashtables, arrays become arrays, booleans become $true
|
|
712
|
+
# or $false, and everything else is quoted as a string -- PowerShell is
|
|
713
|
+
# generally able to coerce it back to the type it needs.
|
|
600
714
|
#
|
|
715
|
+
# @param obj [Object] the value to render
|
|
716
|
+
# @param depth [Integer] current nesting depth, used for indentation
|
|
717
|
+
# @return [String] PowerShell source for the value
|
|
601
718
|
# @api private
|
|
602
719
|
def ps_hash(obj, depth = 0)
|
|
603
720
|
if [true, false].include? obj
|
|
@@ -617,32 +734,51 @@ module Kitchen
|
|
|
617
734
|
else
|
|
618
735
|
# When the object is not a string nor a hash or array, it will be quoted as a string.
|
|
619
736
|
# In most cases, PS is smart enough to convert back to the type it needs.
|
|
620
|
-
|
|
737
|
+
ps_single_quote(obj)
|
|
621
738
|
end
|
|
622
739
|
end
|
|
623
740
|
|
|
624
741
|
# Creates environment variable assignments from a ruby map.
|
|
625
742
|
#
|
|
743
|
+
# @param obj [Hash] variable names mapped to their values
|
|
744
|
+
# @return [String] newline-separated `$env:NAME = 'value'` assignments
|
|
626
745
|
# @api private
|
|
627
746
|
def ps_environment(obj)
|
|
628
747
|
commands = obj.map do |k, v|
|
|
629
|
-
"$env:#{k} =
|
|
748
|
+
"$env:#{k} = #{ps_single_quote(v)}"
|
|
630
749
|
end
|
|
631
750
|
|
|
632
751
|
commands.join("\n")
|
|
633
752
|
end
|
|
634
753
|
|
|
635
|
-
#
|
|
636
|
-
#
|
|
754
|
+
# Renders a value as a single-quoted PowerShell string literal.
|
|
755
|
+
#
|
|
756
|
+
# PowerShell escapes a literal quote inside a single-quoted string by
|
|
757
|
+
# doubling it. Without this an apostrophe anywhere in the config -- a
|
|
758
|
+
# module name, an environment value, a password -- closes the string
|
|
759
|
+
# early and corrupts the rest of the generated script.
|
|
760
|
+
#
|
|
761
|
+
# @param value [Object] any value; #to_s is used
|
|
762
|
+
# @return [String] a quoted, escaped PowerShell string literal
|
|
763
|
+
# @api private
|
|
764
|
+
def ps_single_quote(value)
|
|
765
|
+
"'#{value.to_s.gsub("'", "''")}'"
|
|
766
|
+
end
|
|
767
|
+
|
|
768
|
+
# Returns the path of the modules subfolder in the sandbox, where PS
|
|
769
|
+
# modules and folders will be copied to.
|
|
637
770
|
#
|
|
771
|
+
# @return [String] absolute path to the sandbox's modules folder
|
|
638
772
|
# @api private
|
|
639
773
|
def sandbox_module_path
|
|
640
774
|
File.join(sandbox_path, "modules")
|
|
641
775
|
end
|
|
642
776
|
|
|
643
|
-
#
|
|
644
|
-
# so
|
|
777
|
+
# Copies the folders named in `copy_folders` into the sandbox's modules
|
|
778
|
+
# folder, so they can be discovered through the updated
|
|
779
|
+
# $Env:PSModulePath.
|
|
645
780
|
#
|
|
781
|
+
# @return [void]
|
|
646
782
|
# @api private
|
|
647
783
|
def prepare_copy_folders
|
|
648
784
|
return if config[:copy_folders].nil?
|
|
@@ -656,12 +792,13 @@ module Kitchen
|
|
|
656
792
|
end
|
|
657
793
|
end
|
|
658
794
|
|
|
659
|
-
#
|
|
660
|
-
#
|
|
661
|
-
#
|
|
662
|
-
# the sandbox.
|
|
795
|
+
# Creates a flat list of the files contained in a folder.
|
|
796
|
+
#
|
|
797
|
+
# Useful when debugging what has actually been copied to the sandbox.
|
|
663
798
|
#
|
|
664
|
-
# @
|
|
799
|
+
# @param path [String] the folder to list
|
|
800
|
+
# @return [Array<String>] paths of the entries at the top level and
|
|
801
|
+
# nested beneath it
|
|
665
802
|
# @api private
|
|
666
803
|
def list_files(path)
|
|
667
804
|
base_directory_content = Dir.glob(File.join(path, "*"))
|
|
@@ -671,6 +808,7 @@ module Kitchen
|
|
|
671
808
|
|
|
672
809
|
# Copies all test suite files into the suites directory in the sandbox.
|
|
673
810
|
#
|
|
811
|
+
# @return [void]
|
|
674
812
|
# @api private
|
|
675
813
|
def prepare_pester_tests
|
|
676
814
|
info("Preparing to copy files from '#{suite_test_folder}' to the SUT.")
|
|
@@ -678,15 +816,23 @@ module Kitchen
|
|
|
678
816
|
copy_if_src_exists(suite_test_folder, sandboxed_suites_path)
|
|
679
817
|
end
|
|
680
818
|
|
|
819
|
+
# Copies PesterUtil.psm1 into the sandbox's modules folder, where the
|
|
820
|
+
# updated $Env:PSModulePath will find it.
|
|
821
|
+
#
|
|
822
|
+
# @return [void]
|
|
823
|
+
# @api private
|
|
681
824
|
def prepare_supporting_psmodules
|
|
682
825
|
info("Preparing to copy files from '#{support_psmodule_folder}' to the SUT.")
|
|
683
826
|
sandbox_module_path = File.join(sandbox_path, "modules")
|
|
684
827
|
copy_if_src_exists(support_psmodule_folder, sandbox_module_path)
|
|
685
828
|
end
|
|
686
829
|
|
|
687
|
-
# Copies a folder recursively preserving its layers
|
|
688
|
-
#
|
|
830
|
+
# Copies a folder recursively, preserving its layers. Mostly used to
|
|
831
|
+
# copy into the sandbox. Does nothing when the source does not exist.
|
|
689
832
|
#
|
|
833
|
+
# @param src_to_validate [String] folder to copy
|
|
834
|
+
# @param destination [String] folder to copy into, created if missing
|
|
835
|
+
# @return [void]
|
|
690
836
|
# @api private
|
|
691
837
|
def copy_if_src_exists(src_to_validate, destination)
|
|
692
838
|
unless Dir.exist?(src_to_validate)
|
|
@@ -703,27 +849,45 @@ module Kitchen
|
|
|
703
849
|
FileUtils.cp_r(src_to_validate, destination, preserve: true)
|
|
704
850
|
end
|
|
705
851
|
|
|
706
|
-
#
|
|
707
|
-
#
|
|
852
|
+
# Returns the folder containing the test suites, falling back to
|
|
853
|
+
# `test_base_path` when `test_folder` is not set.
|
|
708
854
|
#
|
|
855
|
+
# @return [String] path to the folder holding the suites
|
|
709
856
|
# @api private
|
|
710
857
|
def test_folder
|
|
711
858
|
config[:test_folder].nil? ? config[:test_base_path] : absolute_test_folder
|
|
712
859
|
end
|
|
713
860
|
|
|
714
|
-
#
|
|
715
|
-
#
|
|
861
|
+
# Resolves `test_folder` to an absolute path, descending into an
|
|
862
|
+
# `integration` subfolder when one exists.
|
|
716
863
|
#
|
|
864
|
+
# @return [String] absolute path to the folder holding the suites
|
|
717
865
|
# @api private
|
|
718
866
|
def absolute_test_folder
|
|
719
867
|
path = (Pathname.new config[:test_folder]).realpath
|
|
720
868
|
integration_path = File.join(path, "integration")
|
|
721
|
-
Dir.exist?(integration_path) ? integration_path : path
|
|
869
|
+
Dir.exist?(integration_path) ? integration_path : path.to_s
|
|
870
|
+
end
|
|
871
|
+
|
|
872
|
+
# Returns the final segment of a path that lives on the SUT.
|
|
873
|
+
#
|
|
874
|
+
# File.basename applies the *workstation's* separator rules, so a Windows
|
|
875
|
+
# remote path such as 'C:\results\out.xml' comes back unchanged when
|
|
876
|
+
# kitchen runs on macOS or Linux -- the usual case for a Windows SUT.
|
|
877
|
+
# Split on either separator instead.
|
|
878
|
+
#
|
|
879
|
+
# @param path [String] a path as it exists on the instance
|
|
880
|
+
# @return [String] the last path segment
|
|
881
|
+
# @api private
|
|
882
|
+
def remote_basename(path)
|
|
883
|
+
path.to_s.split(%r{[\\/]}).last.to_s
|
|
722
884
|
end
|
|
723
885
|
|
|
724
|
-
#
|
|
725
|
-
#
|
|
886
|
+
# Returns a run of spaces of the given width, used to pad messages and
|
|
887
|
+
# indent generated PowerShell hashtables.
|
|
726
888
|
#
|
|
889
|
+
# @param depth [Integer] number of spaces
|
|
890
|
+
# @return [String] the padding
|
|
727
891
|
# @api private
|
|
728
892
|
def pad(depth = 0)
|
|
729
893
|
" " * depth
|
|
@@ -1,5 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2015 Steven Murawski
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
|
13
|
+
# all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
# THE SOFTWARE.
|
|
22
|
+
|
|
23
|
+
# Test Kitchen's top-level namespace.
|
|
1
24
|
module Kitchen
|
|
25
|
+
# Namespace for Test Kitchen verifier plugins.
|
|
2
26
|
module Verifier
|
|
3
|
-
|
|
27
|
+
# Version of the kitchen-pester gem.
|
|
28
|
+
#
|
|
29
|
+
# Kept in its own file so that the gemspec can read it without loading
|
|
30
|
+
# test-kitchen, which is not yet available when the gemspec is evaluated.
|
|
31
|
+
#
|
|
32
|
+
# @return [String] the gem version
|
|
33
|
+
PESTER_VERSION = "1.2.1"
|
|
4
34
|
end
|
|
5
35
|
end
|
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
# Copyright (c) 2015 Steven Murawski
|
|
2
|
+
#
|
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
# furnished to do so, subject to the following conditions:
|
|
9
|
+
#
|
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
|
11
|
+
# all copies or substantial portions of the Software.
|
|
12
|
+
#
|
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
+
# THE SOFTWARE.
|
|
20
|
+
|
|
1
21
|
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
|
|
2
22
|
|
|
3
23
|
function Install-ModuleFromNuget {
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kitchen-pester
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.2.
|
|
4
|
+
version: 1.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Steven Murawski
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-08-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|
|
@@ -28,56 +28,76 @@ dependencies:
|
|
|
28
28
|
name: minitest
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- - "
|
|
31
|
+
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '5.
|
|
33
|
+
version: '5.25'
|
|
34
34
|
- - "<"
|
|
35
35
|
- !ruby/object:Gem::Version
|
|
36
|
-
version: '
|
|
36
|
+
version: '7'
|
|
37
37
|
type: :development
|
|
38
38
|
prerelease: false
|
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
|
40
40
|
requirements:
|
|
41
|
-
- - "
|
|
41
|
+
- - ">="
|
|
42
42
|
- !ruby/object:Gem::Version
|
|
43
|
-
version: '5.
|
|
43
|
+
version: '5.25'
|
|
44
44
|
- - "<"
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
|
-
version: '
|
|
46
|
+
version: '7'
|
|
47
47
|
- !ruby/object:Gem::Dependency
|
|
48
48
|
name: mocha
|
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '2.0'
|
|
54
|
+
- - "<"
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: '4'
|
|
57
|
+
type: :development
|
|
58
|
+
prerelease: false
|
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
60
|
+
requirements:
|
|
61
|
+
- - ">="
|
|
62
|
+
- !ruby/object:Gem::Version
|
|
63
|
+
version: '2.0'
|
|
64
|
+
- - "<"
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
version: '4'
|
|
67
|
+
- !ruby/object:Gem::Dependency
|
|
68
|
+
name: yard
|
|
49
69
|
requirement: !ruby/object:Gem::Requirement
|
|
50
70
|
requirements:
|
|
51
71
|
- - "~>"
|
|
52
72
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: '
|
|
73
|
+
version: '0.9'
|
|
54
74
|
type: :development
|
|
55
75
|
prerelease: false
|
|
56
76
|
version_requirements: !ruby/object:Gem::Requirement
|
|
57
77
|
requirements:
|
|
58
78
|
- - "~>"
|
|
59
79
|
- !ruby/object:Gem::Version
|
|
60
|
-
version: '
|
|
80
|
+
version: '0.9'
|
|
61
81
|
- !ruby/object:Gem::Dependency
|
|
62
82
|
name: test-kitchen
|
|
63
83
|
requirement: !ruby/object:Gem::Requirement
|
|
64
84
|
requirements:
|
|
65
85
|
- - ">="
|
|
66
86
|
- !ruby/object:Gem::Version
|
|
67
|
-
version: '
|
|
87
|
+
version: '3.6'
|
|
68
88
|
- - "<"
|
|
69
89
|
- !ruby/object:Gem::Version
|
|
70
|
-
version: '
|
|
90
|
+
version: '5'
|
|
71
91
|
type: :runtime
|
|
72
92
|
prerelease: false
|
|
73
93
|
version_requirements: !ruby/object:Gem::Requirement
|
|
74
94
|
requirements:
|
|
75
95
|
- - ">="
|
|
76
96
|
- !ruby/object:Gem::Version
|
|
77
|
-
version: '
|
|
97
|
+
version: '3.6'
|
|
78
98
|
- - "<"
|
|
79
99
|
- !ruby/object:Gem::Version
|
|
80
|
-
version: '
|
|
100
|
+
version: '5'
|
|
81
101
|
description: Skip all that Busser stuff and jump right into Pester.
|
|
82
102
|
email:
|
|
83
103
|
- steven.murawski@gmail.com
|
|
@@ -85,18 +105,17 @@ executables: []
|
|
|
85
105
|
extensions: []
|
|
86
106
|
extra_rdoc_files: []
|
|
87
107
|
files:
|
|
88
|
-
- Gemfile
|
|
89
108
|
- LICENSE
|
|
90
|
-
-
|
|
109
|
+
- README.md
|
|
91
110
|
- kitchen-pester.gemspec
|
|
92
111
|
- lib/kitchen/verifier/pester.rb
|
|
93
112
|
- lib/kitchen/verifier/pester_version.rb
|
|
94
113
|
- lib/support/modules/PesterUtil/PesterUtil.psm1
|
|
95
114
|
homepage: https://github.com/test-kitchen/kitchen-pester
|
|
96
115
|
licenses:
|
|
97
|
-
-
|
|
116
|
+
- MIT
|
|
98
117
|
metadata: {}
|
|
99
|
-
post_install_message:
|
|
118
|
+
post_install_message:
|
|
100
119
|
rdoc_options: []
|
|
101
120
|
require_paths:
|
|
102
121
|
- lib
|
|
@@ -104,15 +123,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
104
123
|
requirements:
|
|
105
124
|
- - ">="
|
|
106
125
|
- !ruby/object:Gem::Version
|
|
107
|
-
version: '
|
|
126
|
+
version: '3.1'
|
|
108
127
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
128
|
requirements:
|
|
110
129
|
- - ">="
|
|
111
130
|
- !ruby/object:Gem::Version
|
|
112
131
|
version: '0'
|
|
113
132
|
requirements: []
|
|
114
|
-
rubygems_version: 3.
|
|
115
|
-
signing_key:
|
|
133
|
+
rubygems_version: 3.5.9
|
|
134
|
+
signing_key:
|
|
116
135
|
specification_version: 4
|
|
117
136
|
summary: Test-Kitchen verifier for Pester.
|
|
118
137
|
test_files: []
|
data/Gemfile
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
source "https://rubygems.org"
|
|
2
|
-
|
|
3
|
-
# Specify your gem's dependencies in kitchen-pester.gemspec
|
|
4
|
-
gemspec
|
|
5
|
-
|
|
6
|
-
group :integration do
|
|
7
|
-
gem "berkshelf"
|
|
8
|
-
gem "kitchen-inspec"
|
|
9
|
-
gem "kitchen-azurerm"
|
|
10
|
-
gem "kitchen-chocolatey"
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
group :changelog do
|
|
14
|
-
gem "github_changelog_generator", "1.16.4"
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
group :debug do
|
|
18
|
-
gem "pry", "~>0.13.1"
|
|
19
|
-
gem "pry-byebug", "~>3.9.0"
|
|
20
|
-
gem "pry-stack_explorer"
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
group :chefstyle do
|
|
24
|
-
gem "chefstyle"
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
group :docs do
|
|
28
|
-
gem "yard"
|
|
29
|
-
end
|
data/Rakefile
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
require "bundler/gem_tasks"
|
|
2
|
-
|
|
3
|
-
require "rake/testtask"
|
|
4
|
-
Rake::TestTask.new(:unit) do |t|
|
|
5
|
-
t.libs.push "lib"
|
|
6
|
-
t.test_files = FileList["spec/**/*_spec.rb"]
|
|
7
|
-
t.verbose = true
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
task test: :unit
|
|
11
|
-
|
|
12
|
-
begin
|
|
13
|
-
require "chefstyle"
|
|
14
|
-
require "rubocop/rake_task"
|
|
15
|
-
RuboCop::RakeTask.new(:style) do |task|
|
|
16
|
-
task.options += ["--display-cop-names", "--no-color"]
|
|
17
|
-
end
|
|
18
|
-
rescue LoadError
|
|
19
|
-
puts "chefstyle is not available. (sudo) gem install chefstyle to do style checking."
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
desc "Run all quality tasks"
|
|
23
|
-
task quality: :style
|
|
24
|
-
|
|
25
|
-
begin
|
|
26
|
-
require "yard" unless defined?(YARD)
|
|
27
|
-
YARD::Rake::YardocTask.new
|
|
28
|
-
rescue LoadError
|
|
29
|
-
puts "yard is not available. (sudo) gem install yard to generate yard documentation."
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
task default: %i{test quality}
|
|
33
|
-
|
|
34
|
-
begin
|
|
35
|
-
require "github_changelog_generator/task"
|
|
36
|
-
require "kitchen/verifier/pester_version"
|
|
37
|
-
|
|
38
|
-
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
|
|
39
|
-
config.future_release = "v#{Kitchen::Verifier::PESTER_VERSION}"
|
|
40
|
-
config.issues = false
|
|
41
|
-
config.pulls = true
|
|
42
|
-
config.user = "test-kitchen"
|
|
43
|
-
config.project = "kitchen-pester"
|
|
44
|
-
end
|
|
45
|
-
rescue LoadError
|
|
46
|
-
puts "github_changelog_generator is not available." \
|
|
47
|
-
" (sudo) gem install github_changelog_generator to generate changelogs"
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
namespace :docs do
|
|
51
|
-
desc "Deploy docs"
|
|
52
|
-
task :deploy do
|
|
53
|
-
sh "cd docs && hugo"
|
|
54
|
-
sh "aws --profile chef-cd s3 sync docs/public s3://test-kitchen-legacy.cd.chef.co --delete --acl public-read"
|
|
55
|
-
sh "aws --profile chef-cd cloudfront create-invalidation --distribution-id EQD8MRW086SRT --paths '/*'"
|
|
56
|
-
end
|
|
57
|
-
end
|