1#!/usr/bin/env perl
2
3use strict;
4
5use Cwd qw(abs_path);
6use File::Spec;
7use Getopt::Long;
8use Test::Harness qw(&runtests $verbose);
9
10my $opts = {};
11GetOptions($opts, 'h|help', 'C|class=s@', 'K|keep-tmpfiles', 'F|file-pattern=s',
12  'V|verbose');
13
14if ($opts->{h}) {
15  usage();
16}
17
18if ($opts->{K}) {
19  $ENV{KEEP_TMPFILES} = 1;
20}
21
22if ($opts->{V}) {
23  $ENV{TEST_VERBOSE} = 1;
24  $verbose = 1;
25}
26
27# We use this, rather than use(), since use() is equivalent to a BEGIN
28# block, and we want the module to be loaded at run-time.
29
30my $test_dir = (File::Spec->splitpath(abs_path(__FILE__)))[1];
31push(@INC, "$test_dir/t/lib");
32
33require ProFTPD::TestSuite::Utils;
34import ProFTPD::TestSuite::Utils qw(:testsuite);
35
36# This is to handle the case where this tests.pl script might be
37# being used to run test files other than those that ship with proftpd,
38# e.g. to run the tests that come with third-party modules.
39unless (defined($ENV{PROFTPD_TEST_BIN})) {
40  $ENV{PROFTPD_TEST_BIN} = File::Spec->catfile($test_dir, '..', 'proftpd');
41}
42
43# Set this environment variable, for other test cases which may want to
44# know the directory, and not necessarily just the location of the uninstalled
45# `proftpd' binary.  This is useful, for example, for using the utilities.
46$ENV{PROFTPD_TEST_PATH} = $test_dir;
47
48$| = 1;
49
50my $test_files;
51
52if (scalar(@ARGV) > 0) {
53  $test_files = [@ARGV];
54
55} else {
56  $test_files = [qw(
57    t/http.t
58    t/smtp.t
59    t/ssh2.t
60    t/logins.t
61    t/commands/user.t
62    t/commands/pass.t
63    t/commands/pwd.t
64    t/commands/cwd.t
65    t/commands/cdup.t
66    t/commands/syst.t
67    t/commands/type.t
68    t/commands/mkd.t
69    t/commands/rmd.t
70    t/commands/dele.t
71    t/commands/mdtm.t
72    t/commands/size.t
73    t/commands/mode.t
74    t/commands/stru.t
75    t/commands/allo.t
76    t/commands/noop.t
77    t/commands/feat.t
78    t/commands/help.t
79    t/commands/quit.t
80    t/commands/rang.t
81    t/commands/rnfr.t
82    t/commands/rnto.t
83    t/commands/rest.t
84    t/commands/pasv.t
85    t/commands/epsv.t
86    t/commands/port.t
87    t/commands/eprt.t
88    t/commands/nlst.t
89    t/commands/list.t
90    t/commands/retr.t
91    t/commands/stor.t
92    t/commands/stou.t
93    t/commands/appe.t
94    t/commands/stat.t
95    t/commands/abor.t
96    t/commands/mlsd.t
97    t/commands/mlst.t
98    t/commands/mff.t
99    t/commands/mfmt.t
100    t/commands/opts.t
101    t/commands/host.t
102    t/commands/clnt.t
103    t/commands/site/chgrp.t
104    t/commands/site/chmod.t
105    t/config/accessdenymsg.t
106    t/config/accessgrantmsg.t
107    t/config/allowfilter.t
108    t/config/allowforeignaddress.t
109    t/config/allowoverwrite.t
110    t/config/anonrejectpasswords.t
111    t/config/anonrequirepassword.t
112    t/config/authaliasonly.t
113    t/config/authgroupfile.t
114    t/config/authorder.t
115    t/config/authuserfile.t
116    t/config/authusingalias.t
117    t/config/classes.t
118    t/config/commandbuffersize.t
119    t/config/createhome.t
120    t/config/defaultchdir.t
121    t/config/defaultroot.t
122    t/config/deferwelcome.t
123    t/config/deleteabortedstores.t
124    t/config/denyfilter.t
125    t/config/dirfakegroup.t
126    t/config/dirfakemode.t
127    t/config/dirfakeuser.t
128    t/config/displaychdir.t
129    t/config/displayconnect.t
130    t/config/displayfiletransfer.t
131    t/config/displaylogin.t
132    t/config/displayquit.t
133    t/config/envvars.t
134    t/config/factsoptions.t
135    t/config/groupowner.t
136    t/config/hiddenstores.t
137    t/config/hidefiles.t
138    t/config/hidegroup.t
139    t/config/hidenoaccess.t
140    t/config/hideuser.t
141    t/config/ifdefine.t
142    t/config/include.t
143    t/config/listoptions.t
144    t/config/logoptions.t
145    t/config/masqueradeaddress.t
146    t/config/maxclients.t
147    t/config/maxclientsperclass.t
148    t/config/maxclientsperhost.t
149    t/config/maxclientsperuser.t
150    t/config/maxcommandrate.t
151    t/config/maxconnectionsperhost.t
152    t/config/maxinstances.t
153    t/config/maxloginattempts.t
154    t/config/maxpasswordsize.t
155    t/config/maxretrievefilesize.t
156    t/config/maxstorefilesize.t
157    t/config/maxtransfersperhost.t
158    t/config/maxtransfersperuser.t
159    t/config/multilinerfc2228.t
160    t/config/order.t
161    t/config/passiveports.t
162    t/config/pathallowfilter.t
163    t/config/pathdenyfilter.t
164    t/config/pidfile.t
165    t/config/protocols.t
166    t/config/requirevalidshell.t
167    t/config/rewritehome.t
168    t/config/rlimitchroot.t
169    t/config/rlimitcpu.t
170    t/config/rlimitmemory.t
171    t/config/rlimitopenfiles.t
172    t/config/rootrevoke.t
173    t/config/serveradmin.t
174    t/config/serverident.t
175    t/config/setenv.t
176    t/config/showsymlinks.t
177    t/config/socketoptions.t
178    t/config/storeuniqueprefix.t
179    t/config/sysloglevel.t
180    t/config/timeoutidle.t
181    t/config/timeoutlogin.t
182    t/config/timeoutnotransfer.t
183    t/config/timeoutsession.t
184    t/config/timeoutstalled.t
185    t/config/trace.t
186    t/config/traceoptions.t
187    t/config/transferrate.t
188    t/config/umask.t
189    t/config/useftpusers.t
190    t/config/useglobbing.t
191    t/config/useralias.t
192    t/config/userowner.t
193    t/config/userpassword.t
194    t/config/usesendfile.t
195    t/config/virtualhost.t
196    t/config/directory/limits.t
197    t/config/directory/umask.t
198    t/config/ftpaccess/dele.t
199    t/config/ftpaccess/empty.t
200    t/config/ftpaccess/merging.t
201    t/config/ftpaccess/retr.t
202    t/config/limit/anonymous.t
203    t/config/limit/login.t
204    t/config/limit/mfmt.t
205    t/config/limit/opts.t
206    t/config/limit/rmd.t
207    t/config/limit/xmkd.t
208    t/config/limit/filters.t
209    t/config/limit/subdirs.t
210    t/logging/extendedlog.t
211    t/logging/serverlog.t
212    t/logging/systemlog.t
213    t/logging/transferlog.t
214    t/signals/term.t
215    t/signals/hup.t
216    t/signals/segv.t
217    t/signals/abrt.t
218    t/telnet.t
219    t/utils/ftpcount.t
220    t/utils/ftpwho.t
221  )];
222
223  # Now interrogate the build to see which module/feature-specific test files
224  # should be added to the list.
225  my $order = 0;
226
227  my $FEATURE_TESTS = {
228    't/modules/mod_auth_file.t' => {
229      order => ++$order,
230      test_class => [qw(mod_auth_file)],
231    },
232
233    't/modules/mod_auth_otp.t' => {
234      order => ++$order,
235      test_class => [qw(mod_auth_otp mod_sql mod_sql_sqlite)],
236    },
237
238    't/modules/mod_auth_otp/sftp.t' => {
239      order => ++$order,
240      test_class => [qw(mod_auth_otp mod_sftp mod_sql mod_sql_sqlite)],
241    },
242
243    't/modules/mod_ban.t' => {
244      order => ++$order,
245      test_class => [qw(mod_ban)],
246    },
247
248    't/modules/mod_ban/memcache.t' => {
249      order => ++$order,
250      test_class => [qw(mod_ban mod_memcache)],
251    },
252
253    't/modules/mod_cap.t' => {
254      order => ++$order,
255      test_class => [qw(mod_cap)],
256    },
257
258    't/modules/mod_copy.t' => {
259      order => ++$order,
260      test_class => [qw(mod_copy)],
261    },
262
263    't/modules/mod_ctrls.t' => {
264      order => ++$order,
265      test_class => [qw(mod_ctrls)],
266    },
267
268    't/modules/mod_deflate.t' => {
269      order => ++$order,
270      test_class => [qw(mod_deflate)],
271    },
272
273    't/modules/mod_delay.t' => {
274      order => ++$order,
275      test_class => [qw(mod_delay)],
276    },
277
278    't/modules/mod_digest.t' => {
279      order => ++$order,
280      test_class => [qw(mod_digest)],
281    },
282
283    't/modules/mod_dynmasq.t' => {
284      order => ++$order,
285      test_class => [qw(mod_dynmasq)],
286    },
287
288    't/modules/mod_exec.t' => {
289      order => ++$order,
290      test_class => [qw(mod_exec)],
291    },
292
293    't/modules/mod_facl.t' => {
294      order => ++$order,
295      test_class => [qw(mod_facl)],
296    },
297
298    't/modules/mod_facts.t' => {
299      order => ++$order,
300      test_class => [qw(mod_facts)],
301    },
302
303    't/modules/mod_geoip.t' => {
304      order => ++$order,
305      test_class => [qw(mod_geoip)],
306    },
307
308    't/modules/mod_geoip/sql.t' => {
309      order => ++$order,
310      test_class => [qw(mod_geoip mod_sql mod_sql_sqlite)],
311    },
312
313    't/modules/mod_ifversion.t' => {
314      order => ++$order,
315      test_class => [qw(mod_ifversion)],
316    },
317
318    't/modules/mod_lang.t' => {
319      order => ++$order,
320      test_class => [qw(mod_lang)],
321    },
322
323    't/modules/mod_log_forensic.t' => {
324      order => ++$order,
325      test_class => [qw(mod_log_forensic)],
326    },
327
328    't/modules/mod_quotatab_file.t' => {
329      order => ++$order,
330      test_class => [qw(mod_quotatab mod_quotatab_file)],
331    },
332
333    't/modules/mod_quotatab_sql.t' => {
334      order => ++$order,
335      test_class => [qw(mod_quotatab mod_quotatab_sql mod_sql_sqlite)],
336    },
337
338    't/modules/mod_quotatab/copy.t' => {
339      order => ++$order,
340      test_class => [qw(mod_copy mod_quotatab mod_quotatab_sql mod_sql_sqlite)],
341    },
342
343    't/modules/mod_quotatab/site_misc.t' => {
344      order => ++$order,
345      test_class => [qw(
346        mod_copy
347        mod_quotatab
348        mod_quotatab_sql
349        mod_sql_sqlite
350        mod_site_misc
351      )],
352    },
353
354    't/modules/mod_ratio.t' => {
355      order => ++$order,
356      test_class => [qw(mod_ratio)],
357    },
358
359    't/modules/mod_readme.t' => {
360      order => ++$order,
361      test_class => [qw(mod_readme)],
362    },
363
364    't/modules/mod_redis.t' => {
365      order => ++$order,
366      test_class => [qw(mod_redis)],
367    },
368
369    't/modules/mod_rewrite.t' => {
370      order => ++$order,
371      test_class => [qw(mod_rewrite)],
372    },
373
374    't/modules/mod_rlimit.t' => {
375      order => ++$order,
376      test_class => [qw(mod_rlimit)],
377    },
378
379    't/modules/mod_sftp.t' => {
380      order => ++$order,
381      test_class => [qw(mod_sftp)],
382    },
383
384    't/modules/mod_sftp/ban.t' => {
385      order => ++$order,
386      test_class => [qw(mod_ban mod_sftp)],
387    },
388
389    't/modules/mod_sftp/exec.t' => {
390      order => ++$order,
391      test_class => [qw(mod_exec mod_sftp)],
392    },
393
394    't/modules/mod_sftp/fips.t' => {
395      order => ++$order,
396      test_class => [qw(feat_openssl_fips mod_sftp)],
397    },
398
399    't/modules/mod_sftp/rewrite.t' => {
400      order => ++$order,
401      test_class => [qw(mod_rewrite mod_sftp)],
402    },
403
404    't/modules/mod_sftp/sql.t' => {
405      order => ++$order,
406      test_class => [qw(mod_sftp mod_sql_sqlite)],
407    },
408
409    't/modules/mod_sftp/wrap2.t' => {
410      order => ++$order,
411      test_class => [qw(mod_sftp mod_wrap2)],
412    },
413
414    't/modules/mod_sftp_pam.t' => {
415      order => ++$order,
416      test_class => [qw(mod_sftp mod_sftp_pam)],
417    },
418
419    't/modules/mod_sftp_sql.t' => {
420      order => ++$order,
421      test_class => [qw(mod_sftp mod_sftp_sql mod_sql_sqlite)],
422    },
423
424    't/modules/mod_shaper.t' => {
425      order => ++$order,
426      test_class => [qw(mod_shaper)],
427    },
428
429    't/modules/mod_site.t' => {
430      order => ++$order,
431      test_class => [qw(mod_site)],
432    },
433
434    't/modules/mod_site_misc.t' => {
435      order => ++$order,
436      test_class => [qw(mod_site_misc)],
437    },
438
439    't/modules/mod_snmp.t' => {
440      order => ++$order,
441      test_class => [qw(mod_snmp)],
442    },
443
444    't/modules/mod_sql.t' => {
445      order => ++$order,
446      test_class => [qw(mod_sql)],
447    },
448
449    't/modules/mod_sql_passwd.t' => {
450      order => ++$order,
451      test_class => [qw(mod_sql_passwd mod_sql_sqlite)],
452    },
453
454    't/modules/mod_sql_passwd/fips.t' => {
455      order => ++$order,
456      test_class => [qw(feat_openssl_fips mod_sql_passwd mod_sql_sqlite mod_sftp)],
457    },
458
459    't/modules/mod_sql_odbc.t' => {
460      order => ++$order,
461      test_class => [qw(mod_sql_odbc)],
462    },
463
464    't/modules/mod_sql_sqlite.t' => {
465      order => ++$order,
466      test_class => [qw(mod_sql_sqlite)],
467    },
468
469    't/modules/mod_statcache.t' => {
470      order => ++$order,
471      test_class => [qw(mod_statcache)],
472    },
473
474    't/modules/mod_statcache/sftp.t' => {
475      order => ++$order,
476      test_class => [qw(mod_sftp mod_statcache)],
477    },
478
479    't/modules/mod_tls.t' => {
480      order => ++$order,
481      test_class => [qw(mod_tls)],
482    },
483
484    't/modules/mod_tls/sni.t' => {
485      order => ++$order,
486      test_class => [qw(mod_tls)],
487    },
488
489    't/modules/mod_tls_fscache.t' => {
490      order => ++$order,
491      test_class => [qw(mod_tls_fscache)],
492    },
493
494    't/modules/mod_tls_memcache.t' => {
495      order => ++$order,
496      test_class => [qw(mod_tls_memcache)],
497    },
498
499    't/modules/mod_tls_shmcache.t' => {
500      order => ++$order,
501      test_class => [qw(mod_tls_shmcache)],
502    },
503
504    't/modules/mod_unique_id.t' => {
505      order => ++$order,
506      test_class => [qw(mod_unique_id)],
507    },
508
509    't/modules/mod_wrap.t' => {
510      order => ++$order,
511      test_class => [qw(mod_wrap)],
512    },
513
514    't/modules/mod_wrap2_file.t' => {
515      order => ++$order,
516      test_class => [qw(mod_wrap2_file)],
517    },
518
519    't/modules/mod_wrap2_redis.t' => {
520      order => ++$order,
521      test_class => [qw(mod_redis mod_wrap2_redis)],
522    },
523
524    't/modules/mod_wrap2_sql.t' => {
525      order => ++$order,
526      test_class => [qw(mod_sql_sqlite mod_wrap2_sql)],
527    },
528  };
529
530  my @feature_tests = testsuite_get_runnable_tests($FEATURE_TESTS);
531  my $feature_ntests = scalar(@feature_tests);
532  if ($feature_ntests > 1 ||
533      ($feature_ntests == 1 && $feature_tests[0] ne 'testsuite_empty_test')) {
534    push(@$test_files, @feature_tests);
535  }
536}
537
538$ENV{PROFTPD_TEST} = 1;
539
540if (defined($opts->{C})) {
541  $ENV{PROFTPD_TEST_ENABLE_CLASS} = join(':', @{ $opts->{C} });
542
543} else {
544  # Disable all 'inprogress' and 'slow' tests by default
545  $ENV{PROFTPD_TEST_DISABLE_CLASS} = 'inprogress:slow';
546}
547
548if (defined($opts->{F})) {
549  # Using the provided string as a regex, and run only the tests whose
550  # files match the pattern
551
552  my $file_pattern = $opts->{F};
553
554  my $filtered_files = [];
555  foreach my $test_file (@$test_files) {
556    if ($test_file =~ /$file_pattern/) {
557      push(@$filtered_files, $test_file);
558    }
559  }
560
561  $test_files = $filtered_files;
562}
563
564runtests(@$test_files) if scalar(@$test_files) > 0;
565
566exit 0;
567
568sub usage {
569  print STDOUT <<EOH;
570
571$0: [--help] [--class=\$name] [--verbose]
572
573Examples:
574
575  perl $0
576  perl $0 --class foo
577  perl $0 --class bar --class baz
578
579EOH
580  exit 0;
581}
582