1Config::Model::Tester(3U)ser Contributed Perl DocumentatiCoonnfig::Model::Tester(3)
2
3
4
6 Config::Model::Tester - Test framework for Config::Model
7
9 version 3.007
10
12 In your test file (typically "t/model_test.t"):
13
14 use warnings;
15 use strict;
16
17 use Config::Model::Tester ;
18 use ExtUtils::testlib;
19
20 run_tests() ;
21
22 Run tests with:
23
24 perl t/model_test.t [ --log ] [--error] [--trace] [ subtest [ test_case ] ]
25
27 This class provides a way to test configuration models with tests
28 files. This class was designed to tests several models and several
29 tests cases per model.
30
31 A specific layout for test files must be followed.
32
33 Sub test specification
34 Each subtest is defined in a file like:
35
36 t/model_tests.d/<app-name>-test-conf.pl
37
38 This file specifies that "app-name" (which is defined in
39 "lib/Config/Model/*.d" directory) will be used for the test cases
40 defined in the "*-test-conf.pl" file.
41
42 This file contains a list of test case (explained below) and expects a
43 set of files used as test data. The layout of these test data files is
44 explained in next section.
45
46 Simple test file layout
47 Each test case is represented by a configuration file (not a directory)
48 in the "*-examples" directory. This configuration file will be used by
49 the model to test and is copied as "$confdir/$conf_file_name" using the
50 global variables explained below.
51
52 In the example below, we have 1 app model to test: "lcdproc" and 2
53 tests cases. The app name matches the file specified in
54 "lib/Config/Model/*.d" directory. In this case, the app name matches
55 "lib/Config/Model/system.d/lcdproc"
56
57 t
58 |-- model_test.t
59 \-- model_tests.d # do not change directory name
60 |-- lcdproc-test-conf.pl # subtest specification for lcdproc app
61 \-- lcdproc-examples
62 |-- t0 # test case t0
63 \-- LCDD-0.5.5 # test case for older LCDproc
64
65 Subtest specification is written in "lcdproc-test-conf.pl" file (i.e.
66 this modules looks for files named like "<app-name>-test-conf.pl>").
67
68 Subtests data is provided in files in directory "lcdproc-examples" (
69 i.e. this modules looks for test data in directory
70 "<model-name>-examples>". "lcdproc-test-conf.pl" contains instructions
71 so that each file will be used as a "/etc/LCDd.conf" file during each
72 test case.
73
74 "lcdproc-test-conf.pl" can contain specifications for more test cases.
75 Each test case requires a new file in "lcdproc-examples" directory.
76
77 See "Examples" for a link to the actual LCDproc model tests
78
79 Test file layout for multi-file configuration
80 When a configuration is spread over several files, each test case is
81 provided in a sub-directory. This sub-directory is copied in $conf_dir
82 (a global variable as explained below)
83
84 In the example below, the test specification is written in
85 "dpkg-test-conf.pl". Dpkg layout requires several files per test case.
86 "dpkg-test-conf.pl" will contain instructions so that each directory
87 under "dpkg-examples" will be used.
88
89 t/model_tests.d
90 \-- dpkg-test-conf.pl # subtest specification
91 \-- dpkg-examples
92 \-- libversion # example subdir, used as test case name
93 \-- debian # directory for used by test case
94 |-- changelog
95 |-- compat
96 |-- control
97 |-- copyright
98 |-- rules
99 |-- source
100 | \-- format
101 \-- watch
102
103 See "Examples" for a link to the (many) Dpkg model tests
104
105 More complex file layout
106 Each test case is a sub-directory on the "*-examples" directory and
107 contains several files. The destination of the test files may depend on
108 the system (e.g. the OS). For instance, system wide "ssh_config" is
109 stored in "/etc/ssh" on Linux, and directly in "/etc" on MacOS.
110
111 These files are copied in a test directory using a "setup" parameter:
112
113 setup => {
114 test_file_in_example_dir => 'destination'
115 }
116
117 Let's consider this example of 2 tests cases for ssh:
118
119 t/model_tests.d/
120 |-- ssh-test-conf.pl
121 |-- ssh-examples
122 \-- basic
123 |-- system_ssh_config
124 \-- user_ssh_config
125
126 Unfortunately, "user_ssh_config" is a user file, so you specify where
127 the home directory for the tests with another global variable:
128
129 $home_for_test = '/home/joe' ;
130
131 For Linux only, the "setup" parameter is:
132
133 setup => {
134 'system_ssh_config' => '/etc/ssh/ssh_config',
135 'user_ssh_config' => "~/.ssh/config"
136 }
137
138 On the other hand, system wide config file is different on MacOS and
139 the test file must be copied in the correct location. When the value of
140 the "setup" hash is another hash, the key of this other hash is used as
141 to specify the target location for other OS (as returned by Perl $^O
142 variable:
143
144 setup => {
145 'system_ssh_config' => {
146 'darwin' => '/etc/ssh_config',
147 'default' => '/etc/ssh/ssh_config',
148 },
149 'user_ssh_config' => "~/.ssh/config"
150 }
151
152 See the actual Ssh and Sshd model tests
153 <https://github.com/dod38fr/config-model-
154 openssh/tree/master/t/model_tests.d>
155
156 Basic test specification
157 Each model subtest is specified in "<model>-test-conf.pl". This file
158 contains a set of global variables. (yes, global variables are often
159 bad ideas in programs, but they are handy for tests):
160
161 # config file name (used to copy test case into test wr_root/model_tests directory)
162 $conf_file_name = "fstab" ;
163 # config dir where to copy the file (optional)
164 #$conf_dir = "etc" ;
165 # home directory for this test
166 $home_for_test = '/home/joe' ;
167
168 Here, "t0" file will be copied in
169 "wr_root/model_tests/test-t0/etc/fstab".
170
171 # config model name to test
172 $model_to_test = "Fstab" ;
173
174 # list of tests. This modules looks for @tests global variable
175 @tests = (
176 {
177 # test name
178 name => 't0',
179 # add optional specification here for t0 test
180 },
181 {
182 name => 't1',
183 # add optional specification here for t1 test
184 },
185 );
186
187 1; # to keep Perl happy
188
189 You can suppress warnings by specifying "no_warnings => 1". On the
190 other hand, you may also want to check for warnings specified to your
191 model. In this case, you should avoid specifying "no_warnings" here and
192 specify warning tests or warning filters as mentioned below.
193
194 See actual fstab test <https://github.com/dod38fr/config-
195 model/blob/master/t/model_tests.d/fstab-test-conf.pl>.
196
197 Skip a test
198 A test file can be skipped using $skip global variable.
199
200 In this example, test is skipped when not running on a Debian system:
201
202 eval { require AptPkg::Config; };
203 $skip = ( $@ or not -r '/etc/debian_version' ) ? 1 : 0;
204
205 Internal tests or backend tests
206 Some tests will require the creation of a configuration class dedicated
207 for test (typically to test corner cases on a backend).
208
209 This test class can be created directly in the test specification by
210 calling create_config_class on $model variable. See for instance the
211 layer test <https://github.com/dod38fr/config-
212 model/blob/master/t/model_tests.d/layer-test-conf.pl> or the test for
213 shellvar backend <https://github.com/dod38fr/config-
214 model/blob/master/t/model_tests.d/backend-shellvar-test-conf.pl>.
215
216 Test specification with arbitrary file names
217 In some models like "Multistrap", the config file is chosen by the
218 user. In this case, the file name must be specified for each tests
219 case:
220
221 # not needed if test file is named multistrap-test-conf.pl
222 $model_to_test = "Multistrap";
223
224 @tests = (
225 {
226 name => 'arm',
227 config_file => '/home/foo/my_arm.conf',
228 check => {},
229 },
230 );
231
232 See the actual multistrap test <https://github.com/dod38fr/config-
233 model/blob/master/t/model_tests.d/multistrap-test-conf.pl>.
234
235 Backend argument
236 Some application like systemd requires a backend argument specified by
237 User (e.g. a service name for systemd). The parameter "backend_arg" can
238 be specified to emulate this behavior.
239
240 Re-use test data
241 When the input data for test is quite complex (several files), it may
242 be interested to re-use these data for other tests case. Knowing that
243 test name must must unique, you can re-use test data with "data_from"
244 parameter. For instance:
245
246 @tests = (
247 {
248 name => 'some-test',
249 # ...
250 },
251 {
252 name => 'some-other-test',
253 data_from => 'some-test', # re-use data from test above
254 # ...
255 },
256
257 See plainfile backend test <https://github.com/dod38fr/config-
258 model/blob/master/t/model_tests.d/backend-plainfile-test-conf.pl> for a
259 real life example.
260
261 Test scenario
262 Each subtest follow a sequence explained below. Each step of this
263 sequence may be altered by adding specification in
264 "<model-to-test>-test-conf.pl":
265
266 · Setup test in "wr_root/model_tests/<subtest name>/". If your
267 configuration file layout depend on the target system, you will
268 have to specify the path using "setup" parameter. See "Test file
269 layout depending on system".
270
271 · Create configuration instance, load config data and check its
272 validity. Use "load_check => 'no'" if your file is not valid.
273
274 · Check for config data warnings. You should pass the list of
275 expected warnings that are emitted through Log::Log4Perl. The array
276 ref is passed as is to the "expect" function of "expect" in
277 Test::Log::Lo4Perl. E.g:
278
279 log4perl_load_warnings => [
280 [ 'Tree.Node', (warn => qr/deprecated/) x 2 ] ,
281 [ 'Tree.Element.Value' , ( warn => qr/skipping/) x 2 ]
282 ]
283
284 The Log classes are specified in "cme/Logging".
285
286 Log levels below "warn" are ignored.
287
288 Config::Model is currently transitioning from traditional "warn" to
289 warn logs. To avoid breaking all tests based on this module, the
290 warnings are emitted through Log::Log4Perl only when
291 c<$::_use_log4perl_to_warn> is set. This hack will be removed once
292 all warnings checks in tests are ported to log4perl checks.
293
294 · DEPRECATED. Check for config data warning. You should pass the list
295 of expected warnings. E.g.
296
297 load_warnings => [ qr/Missing/, (qr/deprecated/) x 3 , ],
298
299 Use an empty array_ref to mask load warnings.
300
301 · Optionally run update command:
302
303 update => {
304 [ returns => 'foo' , ]
305 no_warnings => [ 0 | 1 ], # default 0
306 quiet => [ 0 | 1], # default 0, passed to update method
307 loag4perl_update_warnings => [ ... ] # Test::Log::Log4Perl::expect arguments
308 }
309
310 Where:
311
312 · "returns" is the expected return value (optional).
313
314 · "no_warnings" to suppress the warnings coming from
315 Config::Model::Value. Note that "no_warnings => 1" may be
316 useful for less verbose test.
317
318 · "quiet" to suppress progress messages during update.
319
320 · "log4perl_update_warnings" is used to check the warnings
321 produced
322 during update. The argument is passed to "expect" function of
323 Test::Log::Log4Perl. See "load_warnings" parameter above for
324 more
325 details.
326
327 · DEPRECATED. "update_warnings" is an array ref of quoted regexp
328 (See qr operator) to check the warnings produced during update.
329 use "update => []" to check that no warnings are issued during
330 update.
331
332 All other arguments are passed to "update" method.
333
334 · Optionally load configuration data. You should design this config
335 data to suppress any error or warning mentioned above. E.g:
336
337 load => 'binary:seaview Synopsis="multiplatform interface for sequence alignment"',
338
339 See Config::Model::Loader for the syntax of the string accepted by
340 "load" parameter.
341
342 · Optionally, run a check before running apply_fix (if any). This
343 step is useful to check warning messages:
344
345 check_before_fix => {
346 dump_errors => [ ... ] # optional, see below
347 load4perl_dump_warnings => [ ... ] # optional, see below
348 }
349
350 Use "dump_errors" if you expect issues:
351
352 check_before_fix => {
353 dump_errors => [
354 # the issues and a way to fix the issue using Config::Model::Node::load
355 qr/mandatory/ => 'Files:"*" Copyright:0="(c) foobar"',
356 qr/mandatory/ => ' License:FOO text="foo bar" ! Files:"*" License short_name="FOO" '
357 ],
358 }
359
360 Likewise, specify any expected warnings:
361
362 check_before_fix => {
363 log4perl_dump_warnings => [ ... ],
364 }
365
366 "log4perl_dump_warnings" passes the array ref content to "expect"
367 function of Test::Log::Log4Perl.
368
369 Both "log4perl_dump_warnings" and "dump_errors" can be specified in
370 "check_before_fix" hash.
371
372 · Optionally, call apply_fixes:
373
374 apply_fix => 1,
375
376 · Call dump_tree to check the validity of the data after optional
377 "apply_fix". This step is not optional.
378
379 As with "check_before_fix", both "dump_errors" or "dump_warnings"
380 can be used.
381
382 · Run specific content check to verify that configuration data was
383 retrieved correctly:
384
385 check => {
386 'fs:/proc fs_spec' => "proc",
387 'fs:/proc fs_file' => "/proc",
388 'fs:/home fs_file' => "/home",
389 },
390
391 The keys of the hash points to the value to be checked using the
392 syntax described in "grab" in Config::Model::Role::Grab.
393
394 Multiple check on the same item can be applied with a array ref:
395
396 check => [
397 Synopsis => 'fix undefined path_max for st_size zero',
398 Description => [ qr/^The downstream/, qr/yada yada/ ]
399 ]
400
401 You can run check using different check modes (See "fetch" in
402 Config::Model::Value) by passing a hash ref instead of a scalar :
403
404 check => {
405 'sections:debian packages:0' => { mode => 'layered', value => 'dpkg-dev' },
406 'sections:base packages:0' => { mode => 'layered', value => "gcc-4.2-base' },
407 },
408
409 The whole hash content (except "value") is passed to grab and
410 fetch
411
412 A regexp can also be used to check value:
413
414 check => {
415 "License text" => qr/gnu/i,
416 }
417
418 And specification can nest hash or array style:
419
420 check => {
421 "License:0 text" => qr/gnu/i,
422 "License:1 text" => [ qr/gnu/i, qr/Stallman/ ],
423 "License:2 text" => { mode => 'custom', value => [ qr/gnu/i , qr/Stallman/ ] },
424 "License:3 text" => [ qr/General/], { mode => 'custom', value => [ qr/gnu/i , qr/Stallman/ ] },
425 }
426
427 · Verify if a hash contains one or more keys (or keys matching a
428 regexp):
429
430 has_key => [
431 'sections' => 'debian', # sections must point to a hash element
432 'control' => [qw/source binary/],
433 'copyright Files' => qr/.c$/,
434 'copyright Files' => [qr/\.h$/], qr/\.c$/],
435 ],
436
437 · Verify that a hash has not a key (or a key matching a regexp):
438
439 has_not_key => [
440 'copyright Files' => qr/.virus$/ # silly, isn't ?
441 ],
442
443 · Verify annotation extracted from the configuration file comments:
444
445 verify_annotation => {
446 'source Build-Depends' => "do NOT add libgtk2-perl to build-deps (see bug #554704)",
447 'source Maintainer' => "what a fine\nteam this one is",
448 },
449
450 · Write back the config data in "wr_root/model_tests/<subtest
451 name>/". Note that write back is forced, so the tested
452 configuration files are written back even if the configuration
453 values were not changed during the test.
454
455 You can skip warning when writing back with the global :
456
457 no_warnings => 1,
458
459 · Check the content of the written files(s) with
460 Test::File::Contents. Tests can be grouped in an array ref:
461
462 file_contents => {
463 "/home/foo/my_arm.conf" => "really big string" ,
464 "/home/bar/my_arm.conf" => [ "really big string" , "another"], ,
465 }
466
467 file_contents_like => {
468 "/home/foo/my_arm.conf" => [ qr/should be there/, qr/as well/ ] ,
469 }
470
471 file_contents_unlike => {
472 "/home/foo/my_arm.conf" => qr/should NOT be there/ ,
473 }
474
475 · Check the mode of the written files:
476
477 file_mode => {
478 "~/.ssh/ssh_config" => 0600, # octal mode
479 "debian/stuff.postinst" => 0755,
480 }
481
482 Only the last four octets of the mode are tested. I.e. the test is
483 done with " $file_mode & 07777 "
484
485 Note: this test is skipped on Windows
486
487 · Check added or removed configuration files. If you expect changes,
488 specify a subref to alter the file list:
489
490 file_check_sub => sub {
491 my $list_ref = shift ;
492 # file added during tests
493 push @$list_ref, "/debian/source/format" ;
494 },
495
496 Note that actual and expected file lists are sorted before check,
497 adding a file can be done with "push".
498
499 · Copy all config data from "wr_root/model_tests/<subtest name>/" to
500 "wr_root/model_tests/<subtest name>-w/". This steps is necessary to
501 check that configuration written back has the same content as the
502 original configuration.
503
504 · Create a second configuration instance to read the conf file that
505 was just copied (configuration data is checked.)
506
507 · You can skip the load check if the written file still contain
508 errors (e.g. some errors were ignored and cannot be fixed) with
509 "load_check2 => 'no'"
510
511 · Optionally load configuration data in the second instance. You
512 should design this config data to suppress any error or warning
513 that occur in the step below. E.g:
514
515 load2 => 'binary:seaview',
516
517 See Config::Model::Loader for the syntax of the string accepted by
518 "load2" parameter.
519
520 · Compare data read from original data.
521
522 · Run specific content check on the written config file to verify
523 that configuration data was written and retrieved correctly:
524
525 wr_check => {
526 'fs:/proc fs_spec' => "proc" ,
527 'fs:/proc fs_file' => "/proc",
528 'fs:/home fs_file' => "/home",
529 },
530
531 Like the "check" item explained above, you can run "wr_check" using
532 different check modes.
533
534 Running the test
535 Run all tests with one of these commands:
536
537 prove -l t/model_test.t :: [ --trace ] [ --log ] [ --error ] [ <model_name> [ <regexp> ]]
538 perl -Ilib t/model_test.t [ --trace ] [ --log ] [ --error ] [ <model_name> [ <regexp> ]]
539
540 By default, all tests are run on all models.
541
542 You can pass arguments to "t/model_test.t":
543
544 · Optional parameters: "--trace" to get test traces. "--error" to get
545 stack trace in case of errors, "--log" to have logs. E.g.
546
547 # run with log and error traces
548 prove -lv t/model_test.t :: --error --logl
549
550 · The model name to tests. E.g.:
551
552 # run only fstab tests
553 prove -lv t/model_test.t :: fstab
554
555 · A regexp to filter subtest E.g.:
556
557 # run only fstab tests foobar subtest
558 prove -lv t/model_test.t :: fstab foobar
559
560 # run only fstab tests foo subtest
561 prove -lv t/model_test.t :: fstab '^foo$'
562
564 · LCDproc <http://lcdproc.org> has a single configuration file:
565 "/etc/LCDd.conf". Here's LCDproc test layout
566 <https://github.com/dod38fr/config-model-
567 lcdproc/tree/master/t/model_tests.d> and the test specification
568 <https://github.com/dod38fr/config-model-
569 lcdproc/blob/master/t/model_tests.d/lcdd-test-conf.pl>
570
571 · Dpkg packages are constructed from several files. These files are
572 handled like configuration files by Config::Model::Dpkg. The test
573 layout <http://anonscm.debian.org/gitweb/?p=pkg-
574 perl/packages/libconfig-model-dpkg-
575 perl.git;a=tree;f=t/model_tests.d;hb=HEAD> features test with
576 multiple file in dpkg-examples
577 <http://anonscm.debian.org/gitweb/?p=pkg-perl/packages/libconfig-
578 model-dpkg-perl.git;a=tree;f=t/model_tests.d/dpkg-
579 examples;hb=HEAD>. The test is specified in dpkg-test-conf.pl
580 <http://anonscm.debian.org/gitweb/?p=pkg-perl/packages/libconfig-
581 model-dpkg-perl.git;a=blob_plain;f=t/model_tests.d/dpkg-test-
582 conf.pl;hb=HEAD>
583
584 · multistrap-test-conf.pl <https://github.com/dod38fr/config-
585 model/blob/master/t/model_tests.d/multistrap-test-conf.pl> and
586 multistrap-examples <https://github.com/dod38fr/config-
587 model/tree/master/t/model_tests.d/multistrap-examples> specify a
588 test where the configuration file name is not imposed by the
589 application. The file name must then be set in the test
590 specification.
591
592 · backend-shellvar-test-conf.pl <https://github.com/dod38fr/config-
593 model/blob/master/t/model_tests.d/backend-shellvar-test-conf.pl> is
594 a more complex example showing how to test a backend. The test is
595 done creating a dummy model within the test specification.
596
598 · Config::Model
599
600 · Test::More
601
603 Dominique Dumont
604
606 This software is Copyright (c) 2013-2018 by Dominique Dumont.
607
608 This is free software, licensed under:
609
610 The GNU Lesser General Public License, Version 2.1, February 1999
611
613 Websites
614 The following websites have more information about this module, and may
615 be of help to you. As always, in addition to those websites please use
616 your favorite search engine to discover more resources.
617
618 · Search CPAN
619
620 The default CPAN search engine, useful to view POD in HTML format.
621
622 <http://search.cpan.org/dist/Config-Model-Tester>
623
624 · AnnoCPAN
625
626 The AnnoCPAN is a website that allows community annotations of Perl
627 module documentation.
628
629 <http://annocpan.org/dist/Config-Model-Tester>
630
631 · CPAN Ratings
632
633 The CPAN Ratings is a website that allows community ratings and
634 reviews of Perl modules.
635
636 <http://cpanratings.perl.org/d/Config-Model-Tester>
637
638 · CPANTS
639
640 The CPANTS is a website that analyzes the Kwalitee ( code metrics )
641 of a distribution.
642
643 <http://cpants.cpanauthors.org/dist/Config-Model-Tester>
644
645 · CPAN Testers
646
647 The CPAN Testers is a network of smoke testers who run automated
648 tests on uploaded CPAN distributions.
649
650 <http://www.cpantesters.org/distro/C/Config-Model-Tester>
651
652 · CPAN Testers Matrix
653
654 The CPAN Testers Matrix is a website that provides a visual
655 overview of the test results for a distribution on various
656 Perls/platforms.
657
658 <http://matrix.cpantesters.org/?dist=Config-Model-Tester>
659
660 · CPAN Testers Dependencies
661
662 The CPAN Testers Dependencies is a website that shows a chart of
663 the test results of all dependencies for a distribution.
664
665 <http://deps.cpantesters.org/?module=Config::Model::Tester>
666
667 Bugs / Feature Requests
668 Please report any bugs or feature requests by email to "ddumont at
669 cpan.org", or through the web interface at
670 <https://github.com/dod38fr/config-model-tester/issues>. You will be
671 automatically notified of any progress on the request by the system.
672
673 Source Code
674 The code is open to the world, and available for you to hack on. Please
675 feel free to browse it and play with it, or whatever. If you want to
676 contribute patches, please send me a diff or prod me to pull from your
677 repository :)
678
679 <http://github.com/dod38fr/config-model-tester.git>
680
681 git clone git://github.com/dod38fr/config-model-tester.git
682
683
684
685perl v5.28.1 2019-02-02 Config::Model::Tester(3)