1 (-*- text -*-)
2
3 Subversion Commandline Client: Test Suite
4 ==========================================
5
6The cmdline client test suite doesn't use the C-level testing
7framework, but is structured similarly. Instead of testing library
8APIs, it drives the client just like a user would, examining the
9output and the on-disk results (i.e., the working copy) carefully as
10it goes. In other words, this is "black box" testing of the
11command-line client. It has no access to code internals; it never
12looks inside the .svn/ directory; it only performs actions that a
13human user would do.
14
15These tests require Python 2.7 or later.
16
17 [ For more general information on Subversion's testing system,
18 please read the README in subversion/tests/. ]
19
20
21How To Run The Tests
22====================
23
24To run a test script over ra_local, invoke it from THIS DIRECTORY.
25
26 $ cd subversion/tests/cmdline/
27
28Invoke the script with no arguments to run all the tests in that
29script:
30
31 $ ./basic_tests.py
32
33Invoke with one or more numeric arguments to run those particular tests:
34
35 $ ./basic_tests.py 7 13 17
36
37Invoke with one or more function names to run those particular tests:
38
39 $ ./basic_tests.py basic_mkdir_wc_with_parents basic_switch basic_import
40
41And invoke with the "--list" option to list information about some or
42all tests available in that script:
43
44 $ ./basic_tests.py --list 2 3 4
45 $ ./basic_tests.py --list
46
47Note: if you are building Subversion in a directory other than the source
48directory (q.v. INSTALL), you will have to invoke the tests from within
49the build directory:
50
51 $ cd obj/subversion/tests/cmdline
52 $ ../../../../svn/subversion/tests/cmdline/basic_tests.py
53
54
55Running over mod_dav_svn
56------------------------
57
58Running a script over mod_dav_svn is basically the same, but you have to
59set up httpd 2.0 first (on the same machine, since the tests create
60repositories on the fly), and pass a URL argument to the test scripts.
61
62Assuming you have httpd 2.0 installed in /usr/local/apache2, just add
63two Location directives to /usr/local/apache2/conf/httpd.conf, with
64paths adjusted appropriately:
65
66 <Location /svn-test-work/repositories>
67 DAV svn
68 SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/repositories
69 AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
70 AuthType Basic
71 AuthName "Subversion Repository"
72 AuthUserFile /usr/local/apache2/conf/users
73 Require valid-user
74 </Location>
75
76 <Location /svn-test-work/local_tmp/repos>
77 DAV svn
78 SVNPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp/repos
79 AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
80 AuthType Basic
81 AuthName "Subversion Repository"
82 AuthUserFile /usr/local/apache2/conf/users
83 Require valid-user
84 </Location>
85
86 <Location /authz-test-work/anon>
87 DAV svn
88 SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp
89 AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
90 SVNListParentPath On
91 # This may seem unnecessary but granting access to everyone here is necessary
92 # to exercise a bug with httpd 2.3.x+. The "Require all granted" syntax is
93 # new to 2.3.x+ which we can detect with the mod_authz_core.c module
94 # signature. Use the "Allow from all" syntax with older versions for symmetry.
95 <IfModule mod_authz_core.c>
96 Require all granted
97 </IfModule>
98 <IfModule !mod_authz_core.c>
99 Allow from all
100 </IfMOdule>
101 </Location>
102 <Location /authz-test-work/mixed>
103 DAV svn
104 SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp
105 AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
106 SVNListParentPath On
107 AuthType Basic
108 AuthName "Subversion Repository"
109 AuthUserFile /usr/local/apache2/conf/users
110 Require valid-user
111 Satisfy Any
112 </Location>
113 <Location /authz-test-work/mixed-noauthwhenanon>
114 DAV svn
115 SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp
116 AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
117 SVNListParentPath On
118 AuthType Basic
119 AuthName "Subversion Repository"
120 AuthUserFile /usr/local/apache2/conf/users
121 Require valid-user
122 AuthzSVNNoAuthWhenAnonymousAllowed On
123 </Location>
124 <Location /authz-test-work/authn>
125 DAV svn
126 SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp
127 AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
128 SVNListParentPath On
129 AuthType Basic
130 AuthName "Subversion Repository"
131 AuthUserFile /usr/local/apache2/conf/users
132 Require valid-user
133 </Location>
134 <Location /authz-test-work/authn-anonoff>
135 DAV svn
136 SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp
137 AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
138 SVNListParentPath On
139 AuthType Basic
140 AuthName "Subversion Repository"
141 AuthUserFile /usr/local/apache2/conf/users
142 Require valid-user
143 AuthzSVNAnonymous Off
144 </Location>
145 <Location /authz-test-work/authn-lcuser>
146 DAV svn
147 SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp
148 AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
149 SVNListParentPath On
150 AuthType Basic
151 AuthName "Subversion Repository"
152 AuthUserFile /usr/local/apache2/conf/users
153 Require valid-user
154 AuthzForceUsernameCase Lower
155 </Location>
156 <Location /authz-test-work/authn-lcuser>
157 DAV svn
158 SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp
159 AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
160 SVNListParentPath On
161 AuthType Basic
162 AuthName "Subversion Repository"
163 AuthUserFile /usr/local/apache2/conf/users
164 Require valid-user
165 AuthzForceUsernameCase Lower
166 </Location>
167 <Location /authz-test-work/authn-group>
168 DAV svn
169 SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp
170 AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
171 SVNListParentPath On
172 AuthType Basic
173 AuthName "Subversion Repository"
174 AuthUserFile /usr/local/apache2/conf/users
175 AuthGroupFile /usr/local/apache2/conf/groups
176 Require group random
177 AuthzSVNAuthoritative Off
178 </Location>
179 <IfModule mod_authz_core.c>
180 <Location /authz-test-work/sallrany>
181 DAV svn
182 SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp
183 AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
184 SVNListParentPath On
185 AuthType Basic
186 AuthName "Subversion Repository"
187 AuthUserFile /usr/local/apache2/conf/users
188 AuthzSendForbiddenOnFailure On
189 Satisfy All
190 <RequireAny>
191 Require valid-user
192 Require expr req('ALLOW') == '1'
193 </RequireAny>
194 </Location>
195 <Location /authz-test-work/sallrall>
196 DAV svn
197 SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp
198 AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
199 SVNListParentPath On
200 AuthType Basic
201 AuthName "Subversion Repository"
202 AuthUserFile /usr/local/apache2/conf/users
203 AuthzSendForbiddenOnFailure On
204 Satisfy All
205 <RequireAll>
206 Require valid-user
207 Require expr req('ALLOW') == '1'
208 </RequireAll>
209 </Location>
210 </IfModule>
211
212
213 RedirectMatch permanent ^/svn-test-work/repositories/REDIRECT-PERM-(.*)$ /svn-test-work/repositories/$1
214 RedirectMatch ^/svn-test-work/repositories/REDIRECT-TEMP-(.*)$ /svn-test-work/repositories/$1
215
216Httpd should be running on port 80. You may also need to ensure that
217it's running as you, so it has read/write access to the repositories
218that are probably living in your Subversion working copy. To do this,
219set the User and Group directives in httpd.conf, something like this:
220
221 User yourusernamehere
222 Group users
223
224You need to run the tests over mod_dav_svn with authentication enabled, so
225just drop the following 2-line snippet into the
226/usr/local/apache2/conf/users file [1]:
227
228----------------------------
229jrandom:xCGl35kV9oWCY
230jconstant:xCGl35kV9oWCY
231JRANDOM:xCGl35kV9oWCY
232JCONSTANT:xCGl35kV9oWCY
233----------------------------
234
235and these lines into the
236/usr/local/apache/conf/groups file:
237----------------------------
238random: jrandom
239constant: jconstant
240----------------------------
241
242Now, (re)start Apache and run the tests over mod_dav_svn.
243
244You can run a test script over DAV:
245
246 $ ./basic_tests.py --url http://localhost
247 $ ./basic_tests.py --url http://localhost 3
248
249or
250
251 $ ./basic_tests.py --url=http://localhost
252 $ ./basic_tests.py --url=http://localhost 3
253
254If you run httpd on a port other than 80, you can specify the port in
255the URL: "http://localhost:15835" for example.
256
257To run all tests over DAV, pass BASE_URL when running 'make check'
258from the top of the build dir:
259
260 $ make check BASE_URL=http://localhost
261
262BASE_URL=URL can also be used when running individual tests:
263
264 $ ./basic_tests.py BASE_URL=http://localhost
265 $ ./basic_tests.py BASE_URL=http://localhost 3
266
267
268Note [1]: It would be quite too much to expect those password entries
269 to work on Windows... Apache httpd on Windows doesn't
270 understand crypted passwords, but it does understand
271 MD5-hashed passwords. The correct password entries for
272 Windows are:
273
274 ----------------------------
275 jrandom:$apr1$3p1.....$FQW6RceW5QhJ2blWDQgKn0
276 jconstant:$apr1$jp1.....$Usrqji1c9H6AbOxOGAzzb0
277 JRANDOM:$apr1$3p1.....$FQW6RceW5QhJ2blWDQgKn0
278 JCONSTANT:$apr1$jp1.....$Usrqji1c9H6AbOxOGAzzb0
279 ----------------------------
280
281
282As a shorthand to all of the above, ./davautocheck.sh will generate
283an Apache configuration listening on a random port on localhost and
284run some tests. Without arguments, or when invoking 'make davautocheck'
285on the top-level Makefile, it will run all tests. With arguments,
286it will run just one suite or just one test:
287
288 $ ./davautocheck.sh
289 $ ./davautocheck.sh basic
290 $ ./davautocheck.sh basic 15
291
292With '--no-tests' argument, it will start httpd but not run any tests. This is
293useful for manual testing --- create repositories in
294./svn-test-work/repositories/<$repo> and they will be accessible at
295<URL>/svn-test-work/repositories/<$repo>. You can also run individual tests by passing the --url option to them, as described above.
296
297davautocheck.sh also respects some environment variables; see the comments at
298the top of the script for details.
299
300Running over ra_svn
301-------------------
302
303It's also easy to run the tests against a local svnserve:
304
305$ subversion/svnserve/svnserve -d -r `pwd`/subversion/tests/cmdline
306$ make check BASE_URL=svn://localhost
307
308or, to run individual tests,
309
310$ ./basic_tests.py --url=svn://localhost 3
311
312To enable Cyrus SASL on the server side you should either set the
313ENABLE_SASL variable when calling make:
314
315$ make check BASE_URL=svn://localhost ENABLE_SASL=true
316
317or if you're running an individual test,
318
319$ ./basic_tests.py --url=svn://localhost --enable-sasl 3
320
321Note that to do this you'll have to have a svn.conf file in your
322SASL lib dir (i.e. something like /usr/lib/sasl2/svn.conf), it
323should contain something like:
324
325pwcheck_method: auxprop
326mech_list: CRAM-MD5
327
328And then you'll have to add the users jrandom and jconstant to your
329SASL password db,
330
331$ saslpasswd2 -c -u svntest jrandom
332$ saslpasswd2 -c -u svntest jconstant
333
334As usual, both users should use the password 'rayjandom'.
335
336To enable DUMP_LOAD_CROSS_CHECK to work a third user is required,
337
338$ saslpasswd2 -c -u svntest __dumpster__
339
340with password '__loadster__'.
341
342The user running the tests will need read access to the sasl database
343and on some systems this can be arranged by adding the user to the sasl
344group.
345
346There are 'make svnserveautocheck' and ./svnserveautocheck.sh commands,
347analogous to davautocheck.sh documented above.
348
349
350Running tests in a RAM disk
351--------------------------
352
353Test execution can be dramatically sped up by keeping Subversion test
354data on a RAM disk. On a Linux system, you can mount a RAM disk on the
355fly with the command:
356
357 mount -t tmpfs tmpfs /path/to/src/subversion/tests/cmdline/svn-test-work \
358 -o uid=$USER,mode=770,size=32m
359
360Or, for a more permanent solution, add lines like the following in your
361/etc/fstab file:
362
363 tmpfs /path/to/src/svn/subversion/tests/cmdline/svn-test-work tmpfs defaults,user,noauto,exec,size=32m
364
365The minimum required size for testing ramdisk is approximately 700MB.
366However, flagging your test targets for cleanup dramatically reduces
367the space requirements (as shown in the example configuration above),
368and thus your memory usage. Cleanup means more I/O, but since test
369data is in-memory, there will be no performance degradation. Example:
370
371 make check CLEANUP=true
372
373See http://svn.haxx.se/dev/archive-2003-02/0068.shtml for the original
374authoritative discussion on use of RAM disks.
375
376
377Directory Contents
378==================
379
380 *.py The tests themselves.
381
382 svntest/ Python package, provides test suite framework
383
384 /main.py: Global vars, utility routines; exports
385 run_tests(), the main test routine.
386
387 /tree.py: Infrastructure for SVNTreeNode class.
388 - tree constructors, tree comparison routines.
389 - routines to parse subcommand output into
390 specific kinds of trees.
391 - routines to parse a working copy and
392 entries files into specific kinds of trees.
393
394 /wc.py: Functions for interacting with a working
395 copy, and converting to/from trees.
396
397 /actions.py: Main API for driving subversion client and
398 using trees to verify results.
399
400 /verify.py: Verifies output from Subversion.
401
402 /testcase.py: Control of test case execution - contains
403 decorators for expected failures and conditionally
404 executed tests.
405
406 /sandbox.py: Tools for manipulating a test's working area
407 ("a sandbox"), those are handy for most simple
408 actions a test might want to perform on a wc.
409
410 /objects.py: Objects that keep track of state during a test.
411 (not directly used by the test scripts.)
412
413 /mergetrees.py: Routines that create merge scenarios.
414
415 /factory.py: Automatically generate a (near-)complete new
416 cmdline test from a series of shell commands.
417
418 /error.py: Error codes as constants, for convenience.
419 (auto-generated by tools/dev/gen-py-error.py)
420
421
422What the Python Tests are Doing
423===============================
424
425I. Theory
426
427 A. Types of Verification
428
429 The point of this test system is that it's *automated*: that is,
430 each test can algorithmically verify the results and indicate "PASS"
431 or "FAIL".
432
433 We've identified two broad classes of verification:
434
435 1. Verifying svn subcommand output.
436
437 Most important subcommands (co, up, ci, im, st) print results to
438 stdout as a list of paths. Even though the paths may be printed
439 out in an unpredictable order, we still want to make sure this
440 list is exactly the *set* of lines we expect to get.
441
442 2. Verifying the working copy itself.
443
444 Every time a subcommand could potentially change something on
445 disk, we need to inspect the working copy. Specifically, this
446 means we need to make sure the working copy has exactly the
447 tree-structure we expect, and each file has exactly the contents
448 and properties we expect.
449
450
451II. Practice: Trees
452
453 Sam TH <sam@uchicago.edu> proposed and began work on a solution
454 whereby all important, inspectable information is parsed into a
455 general, in-memory tree representation. By comparing actual
456 vs. expected tree structures, we get automated verification.
457
458 A. Tree node structure
459
460 Each "tree node" in a tree has these fields:
461
462 - name : the name of the node
463 - children: list of child nodes (if the node is a dir)
464 - contents: textual contents (if the node is a file)
465 - properties: a hash to hold subversion props
466 - atts: a hash of meta-information about tree nodes themselves
467
468
469 B. Parsing subcommand output into a tree
470
471 Special parsers examine lines printed by subcommands, and
472 convert them into a tree of tree-nodes. The 'contents' and
473 'properties' fields are empty; but prepending on the subcommand,
474 specific attributes in the 'atts' field are set in tree-nodes:
475
476 - svn co/up: a 'status' attribute is set to a two-character
477 value from the set (A, D, G, U, C, _, ' ') or
478 a 'verb' attribute is set to ('Restored')
479
480 - svn status: a 'status' attribute (as above), plus 'wc_rev'
481 and 'repos_rev' attributes to hold the wc
482 and repos revision numbers.
483
484 - svn ci/im: a 'verb' attribute is set to one of
485 (Adding, Sending, Deleting)
486
487
488 C. Parsing a working copy into a tree
489
490 We also have a routines that walks a regular working copy and
491 returns a tree representing disk contents and props. In this
492 case the 'atts' hash in each node is empty, but the 'contents'
493 and 'props' fields are filled in.
494
495
496
497How to Write New Tests
498======================
499
500If you'd like to write a new python test, first decide which file it
501might fit into; test scripts each contain collections of tests grouped
502by rough categories. (Is it testing a new subcommand? New
503enhancement? Tricky use-case? Regression test?)
504
505Next, read the long documentation comment at the top of
506svntest/tree.py. It will explain the general API that most tests use.
507
508Finally, try copying-and-pasting a simple test and then edit from
509there. Don't forget to add your test to the 'test_list' variable at
510the bottom of the file. To avoid renumbering of existing tests, you
511should add new tests to the end of the list.
512
513
514Testing Compatibility With Previous Release
515===========================================
516
517You can run the Python test suite against older installed versions of
518the Subversion servers. This mail fragment introduces the ability:
519
520 Message-ID: <1ea387f60804091828q48c9d18ah7bf8d89ef7d39461@mail.gmail.com>
521 Date: Wed, 9 Apr 2008 18:28:40 -0700
522 From: "David Glasser" <glasser@davidglasser.net>
523 To: "Subversion Developers" <dev@subversion.tigris.org>
524 Subject: backwards-compatibility testing!
525
526 I've updated the expectations on trunk so that you can cleanly run the
527 test suite against 1.4.x svnserve or DAV. You do this by adding
528 SERVER_MINOR_VERSION=4 with make check, or --server-minor-version 4 to
529 run_tests.py or a specific Python test.
530
531 [...]
532
533We expect that post-1.5, this support will expand in the obvious ways
534(allowing "--server-minor-version 5" and SERVER_MINOR_VERSION=5).
535