gpgscm,tests: Add new functions to the test environment.
[gnupg.git] / tests / openpgp / README
1 #                                   Emacs, this is an -*- org -*- file.
2
3 * How to run the test suite
4 From your build directory, run
5
6   obj $ make -C tests/openpgp check
7
8 to run all tests or
9
10   obj $ make -C tests/openpgp check XTESTS=your-test.scm
11
12 to run a specific test (or any number of tests separated by spaces).
13
14 If you want to debug a test, add verbose=1 to see messages printed by
15 spawned programs to their standard error stream, verbose=2 to see what
16 programs are executed, or verbose=3 to see even more program output
17 and exit codes.
18
19 ** Passing options to the test driver
20
21 You can set TESTFLAGS to pass flags to 'run-tests.scm'.  For example,
22 to speed up the test suite when bisecting, do
23
24   obj $ make -C tests/openpgp check TESTFLAGS=--parallel
25
26 See below for the arguments supported by the driver.
27
28 ** Calling the test driver directly
29 This is a bit tricky because one needs to manually set some
30 environment variables.  We should make that easier.  See discussion
31 below.  From your build directory, do:
32
33   obj $ TMP=/tmp srcdir=<path to>/tests/openpgp \
34         GPGSCM_PATH=<path to>/tests/gpgscm:<path to>/tests/openpgp \
35         $(pwd)/tests/gpgscm/gpgscm [gpgscm args] \
36         run-tests.scm [test suite runner args]
37
38 *** Arguments supported by the test suite runner
39 The test suite runner supports four modes of operation,
40 {sequential,parallel}x{isolated,shared}.  You can select the mode of
41 operation using a combination of the flags --parallel, --sequential,
42 --shared, and --isolated.
43
44 By default the tests are run in sequential order, each one in a clean
45 environment.
46
47 You can specify the tests to run as positional arguments relative to
48 srcdir (e.g. just 'version.scm').  By default all tests listed in
49 run-tests.scm are executed.  Note that you do not have to specify
50 setup.scm and finish.scm, they are executed implicitly.
51
52 The test suite runner can be executed in any location that the current
53 user can write to.  It will create temporary files and directories,
54 but will in general clean up all of them.
55 *** Discussion of the various environment variables
56 **** srcdir
57 Must be set to the source of the openpgp test suite.  Used to locate
58 data files.
59 **** GPGSCM_PATH
60 Used to locate the Scheme library as well as code used by the test
61 suite.
62 **** BIN_PREFIX
63 The test suite does not hardcode any paths to tools.  If set it is
64 used to locate the tools to test, otherwise the test suite assumes to
65 be run from the build directory.
66 **** MKTDATA and GPG_PRESET_PASSPHRASE
67 These two tools are not installed by 'make install', hence we need to
68 explicitly override their position.  In fact, the location of any tool
69 used by the test suite can be overridden this way.  See defs.scm.
70 **** argv[0]
71 run-tests.scm depends on being able to re-exec gpgscm.  It uses
72 argv[0] for that.  Therefore you must use an absolute path to invoke
73 gpgscm.
74 * How to write tests
75 gpgscm provides a number of functions to aid you in writing tests, as
76 well as bindings to process management abstractions provided by GnuPG.
77 For the Scheme environment provided by TinySCHEME, see the TinySCHEME
78 manual that is included in tests/gpgscm/Manual.txt.
79
80 For a quick start, please have a look at various tests that are
81 already implemented, e.g. 'encrypt.scm'.
82 ** The test framework
83 The functions info, error, and skip display their first argument and
84 flush the output buffers.  error and skip will also terminate the
85 process, signaling that the test failed or should be skipped.
86
87 (for-each-p msg proc list) will display msg, and call proc with each
88 element of list while displaying the progress appropriately.
89 for-each-p' is similar, but accepts another callback before the 'list'
90 argument to format each item.  for-each-p can be safely nested, and
91 the inner progress indicator will be abbreviated using '.'.
92 ** Debugging tests
93
94 Say you are working on a new test called 'your-test.scm', you can run
95 it on its own using
96
97   obj $ make -C tests/openpgp check XTESTS=your-test.scm
98
99 but something isn't working as expected.  There are several little
100 gadgets that might help.  The first one is 'trace', a function that
101 prints the value given to it and evaluates to it.  E.g.
102
103   (trace (+ 2 3))
104
105 prints '5' and evaluates to 5.  Also, there is an 'assert' macro that
106 aborts the execution if its argument does not evaluate to a trueish
107 value.  Feel free to express invariants with it.
108
109 You can also get an interactive repl by dropping
110
111   (interactive-repl (current-environment))
112
113 anywhere you like.  Or, if you want to examine the environment from an
114 operating system shell, use
115
116   (interactive-shell)
117
118 ** Interfacing with gpg
119
120 defs.scm defines several convenience functions.  Say you want to parse
121 the colon output from gpg, there is gpg-with-colons that splits the
122 result at newlines and colons, so you can use the result like this:
123
124  (define (fpr some-key)
125    (list-ref (assoc "fpr" (gpg-with-colons
126                            `(--with-fingerprint
127                              --list-secret-keys ,some-key)))
128              9))
129
130 Or if you want to count all non-revoked uids for a given key, do
131
132  (define (count-uids-of-secret-key some-key)
133    (length (filter (lambda (x) (and (string=? "uid" (car x))
134                                     (string=? "u" (cadr x))))
135                    (gpg-with-colons
136                     `(--with-fingerprint
137                       --list-secret-keys ,some-key)))))
138
139 ** Temporary files
140 (lettmp <bindings> <body>) will create and delete temporary files that
141 you can use in <body>.  (with-temporary-working-directory <body>) will
142 create a temporary director, change to that, and clean it up after
143 executing <body>).
144
145 make-temporary-file will create a temporary file.  You can optionally
146 provide an argument to that function that will serve as tag so you can
147 distinguish the files for debugging.  remove-temporary-file will
148 delete a file created using make-temporary-file.
149
150 ** Monadic transformer and pipe support
151 Tests often perform sequential transformations on files, or connect
152 processes using pipes.  To aid you in this, the test framework
153 provides two monadic data structures.
154
155 (Currently, the implementation mashes the 'bind' operation together
156 with the application of the monad.  Also, there is no 'return'
157 operation.  I guess all of that could be implemented on top of
158 call/cc, but it isn't at the moment.)
159 *** pipe
160 The pipe monad constructs pipe lines.  It consists of a function
161 pipe:do that binds the functions together and manages the execution of
162 the child processes, a family of functions that act as sources, a
163 function to spawn processes, and a family of functions acting as
164 sinks.
165
166 Sources are pipe:open, pipe:defer, pipe:echo.  To spawn a process use
167 pipe:spawn, or the convenience function pipe:gpg.  To sink the data
168 use pipe:splice, or pipe:write-to.
169
170 Example:
171
172   (pipe:do
173     (pipe:echo "3\n1\n2\n")
174     (pipe:spawn '("/usr/bin/sort"))
175     (pipe:write-to "sorted" (logior O_WRONLY O_CREAT) #o600))
176
177 Caveats: Due to the single-threaded nature of gpgscm you cannot use
178 both a source and sink that is implemented in Scheme.  pipe:defer and
179 pipe:echo are executing in gpgscm, and so does pipe:splice.
180 *** tr
181 The transformer monad describes sequential file transformations.
182
183 There is one source function, tr:open.  To describe a transformation
184 using some process, use tr:spawn, tr:gpg, or tr:pipe-do.  There are
185 several sinks, although sink is not quite the right term, because the
186 data is not consumed, and hence one can use them at any position.  The
187 "sinks" are tr:write-to, tr:call-with-content, tr:assert-identity, and
188 tr:assert-weak-identity.
189
190 A somewhat contrived example demonstrating many functions is:
191
192   (tr:do
193     (tr:pipe-do
194       (pipe:echo "3\n1\n2\n")
195       (pipe:spawn '("/usr/bin/sort")))
196     (tr:write-to "reference")
197     (tr:call-with-content
198      (lambda (c)
199        (echo "currently, c contains" (string-length c) "bytes")))
200     (tr:spawn "" '("/usr/bin/gcc" -x c "-E" -o **out** **in**))
201     (tr:pipe-do
202       (pipe:spawn '("/bin/grep" -v "#")))
203     (tr:assert-identity "reference"))
204
205 Caveats: As a convenience, gpgscm allows one to specify command line
206 arguments as Scheme symbols.  Scheme symbols, however, are
207 case-insensitive, and get converted to lower case.  Therefore, the -E
208 argument must be given as a string in the example above.  Similarly,
209 you need to quote numerical values.
210 ** Process management
211 If you just need to execute a single command, there is (call-with-fds
212 cmdline infd outfd errfd) which executes cmdline with the given file
213 descriptors bound to it, and waits for its completion returning the
214 status code.  There is (call cmdline) which is similar, but calls the
215 command with a closed stdin, connecting stdout and stderr to stderr if
216 gpgscm is executed with --verbose.  (call-check cmdline) raises an
217 exception if the command does not return 0.
218
219 (call-popen cmdline input) calls a command, writes input to its stdin,
220 and returns any output from stdout, or raises an exception containing
221 stderr on failure.
222 * Sample messages