README
======
This directory contains various tests for the daemon program. Note that
these tests do not verify their own behaviour. Most of the tests send
messages to syslog so you have to monitor syslog destinations (e.g.
/var/log/messages). Some of the tests run in the foreground with pseudo
terminals. A user has to be there to see that things (like window resizing)
work. So this file describes what to expect for each test. Note that the
daemon.conf file used for these tests turns on debugging and verbose messages
and limits respawning such that most tests will terminate by themselves (all
but one).

ASSUMPTIONS
===========
These tests make the following assumptions:

 1 - They must be executed from the current directory
 2 - The current directory must be "safe" (man daemon_path_is_safe(3))
 3 - The daemon(1) binary to be tested is in the parent directory

test1
-----
The client prints the numbers from 0 to 4, sleeping for a second before
printing each one. daemon will respawn the client but since it only runs for
5 seconds, the burst/wait respawn cycle is triggered. So the client should
run twice, then wait 10 seconds, then run twice more before giving up.

test2
-----
The client prints the numbers from 0 to 4, sleeping a second before printing
each one. Then, the client closes stdout and stderr and then sleeps for a
further 2 seconds before terminating. daemon will respawn the client but
since it only runs for 7 seconds, the burst/wait respawn cycle is triggered.
So the client should run twice, then wait 10 seconds, then run twice more
before giving up.

test3
-----
The client prints the numbers from 0 to 10, sleeping for a second before
printing each one. daemon will respawn the client and since it runs for
11 seconds, it will be respawned indefinitely. The client has to be stopped
manually with:

  ../daemon --name=test3 --stop

You can see if it's running with:

  ../daemon --name=test3 --verbose --running

test4
-----
Note: This test must be run as root.

The client changes the user id to nobody, changes to the tmp directory
(within this test directory), sets the umask to 0777 and sets the
environment to the following variables:

  HOME=/tmp
  LOGNAME=foobar
  PATH=/bin:/usr/bin

After it has run, check that the current directory contains a "tmp"
directory. It should contain a file called "test4.client.output" that is
owned by "nobody" with permissions set to "rw-------". This file should
contain the aforementioned environment variables and nothing else. If it
does contain a few other variables (e.g. PWD, SHLVL), don't worry. They
are added by the shell.

Note that this test should also test --chroot but there's too much to setup
first (e.g. /dev/log, restart syslogd, /etc/passwd, /etc/group). It would
never work on enough platforms so I didn't bother. If you really want to try
chroot (trivially), run test4 like:

  CHROOT="-R /" ./test4

test5
-----
The client is run with --safe. The client is a C program. It just prints
"test5". If the current directory is safe, then "test5.client" is safe
and will run.

test6
-----
The client is run with --safe. The client is a C program. It just prints
"test6". However, "test6.client" is not safe and daemon will refuse to run
it.

test7
-----
The client is run with --safe. It is a shell script that starts with
"#!/bin/sh". It just prints "test7". This test checks that the safety test
checks #! interpreters. If it fails, make sure that /bin/sh really is safe.

test8
-----
The client is run with --safe. It is a shell script that starts with
"#!/usr/bin/env sh". It just prints "test8". This test checks that the
safety test checks indirect #!/usr/bin/env interpreters. If it fails,
check that /usr/bin/env and /bin/sh really are safe.

test9
-----
The client is run with --safe. It is a group writable shell script that
starts with "#!/bin/sh". It just prints "test9". Since the script is unsafe,
daemon will refuse to run it. This test checks that the safety test
recognises an unsafe script file.

test10
------
The client is run with --safe. It is a script that starts with
"#!`pwd`/test10.interpreter" which is group writable. Since the interpreter
is unsafe, daemon will refuse to run the script. This test checks that the
safety test recognises an unsafe interpreter.

test11
------
The client is run with --safe. It is a script that starts with
"#!/usr/bin/env test11.interpreter" which is group writable. Since the
interpreter is unsafe, daemon will refuse to run the script. This test
checks that the safety test recognises an unsafe interpreter via
/usr/bin/env.

test12
------
The client is run in the foreground. The client is "less /etc/services". Run
this from a terminal so that the pseudo terminal code is exercised. Make
sure that less behaves properly. In particular, resize the window if
possible to check that SIGWINCH is propagated to the client correctly.

test13
------
The client (cat) is run in the foreground with an explicit pseudo terminal
set to noecho mode. It reads stdin until eof, printing out each line as soon
as it is received. In this test, daemon is run without a controlling
terminal. Input to the terminal from which "test13" is run is propagated to
daemon's stdin via pipes. daemon then propagates this input to the client
via a pseudo terminal which prints it out. daemon reads this over a pseudo
terminal and propagates it back via pipes to the controlling terminal of
"test13". The client's pseudo terminal is set to noecho mode to prevent what
you type from appearing twice.

Don't forget that you have to type in something, and end the test with EOF
(i.e. Ctrl-D).

Note that when compiling "test13.daemon", it isn't assumed that libslack is
installed so compilation might fail (it's ok on Linux). If so, fiddle with
"test13.compile" to get it to compile. If you have the version of libslack
that came with daemon installed, you can just uncomment the compile command
that uses libslack-config.

test14
------
The client (sort) is run in the foreground with an explicit pseudo terminal
set to noecho mode. It reads stdin until eof and then prints its input
sorted. This is identical to Test13 except that the client is sort, not cat.
It even uses the same test harness (test13.daemon). This test checks that
daemon can end the input of the client and continue to read its output.

Don't forget that you have to type in multiple lines, and end with EOF.

test15
------
This is very like test13 with one bizarre twist. The client is just like cat
except that before reading or writing anything, it changes the EOF character
from Control-D to Control-F (just because it can). This test checks that
daemon copes with an idiot client that changes its EOF character.

Don't forget that you have to type in something, and end with Control-D.

test16
------
The client just writes "stdout" to stdout and "stderr" to stderr. This test
logs the client's stderr and stdout to files. After the test, the file
"test16.stderr" will contain "stderr" and the file "test16.stdout" will
contain "stdout".

test17
------
The client just writes "stdout" to stdout and "stderr" to stderr. This test
logs the client's stderr and stdout to a single file, "test17.output". It
also logs daemon's debug messages to a file, "test17.dbg". After the test,
the file "test17.output" will contain "stdout" and "stderr" and the file
"test17.dbg" will contain all of daemon's debug messages.

test18
------
This test logs daemon's error output to a file. It also tries to
log daemon's debug output to a file but fails because that file
will already exist and be non-writable. Note that this test must
not be run as root. After the test, the file "test18.err" should
contain the following error message:

  test18: fatal: failed to start debug delivery to test18.dbg: Permission denied

test19
------
This test shows what happens when a non-root user tries to use the --user
option. Note that this test must not be run as root. It prints a usage
message starting with:

  Invalid option: --user (only works for root)

test20
------
This test shows what happens when an invalid argument is given for the --umask
option. It prints a usage message starting with:

  Invalid --umask argument: 'hello' (must be a valid octal mode)

test21
------
This test shows what happens when an invalid argument is given for the
--acceptable option. It prints a usage message starting with:

  Invalid --acceptable argument: 9 (less than 10)  

test22
------
This test shows what happens when an invalid argument is given for the
--attempts option. It prints a usage message starting with:

  Invalid --attempts argument: -1 (not between 0 and 100)

test23
------
This test also shows what happens when an invalid argument is given for the
--attempts option. It prints a usage message starting with:

  Invalid --attempts argument: 101 (not between 0 and 100)

test24
------
This test shows what happens when an invalid argument is given for the
--delay option. It prints a usage message starting with:

  Invalid --delay argument: 9 (less than 10)

test25
------
This test shows what happens when an invalid argument is given for the
--limit option. It prints a usage message starting with:

  Invalid --limit argument: -1 (less than 0)

test26
------
This test shows what happens when an invalid argument is given for the
--pty option. It prints a usage message starting with:

  Invalid --pty argument: 'hello' (Only 'noecho' is supported)

test27
------
This test shows what happens when incompatible options (--safe and --unsafe)
are given. It prints a usage message starting with:

  Incompatible options: --safe and --unsafe

test28
------
This test shows what happens when the --pty option is given without the
--foreground option. It prints a usage message starting with:

  Missing option: --foreground (required for --pty)

test29
------
This test shows what happens when the --acceptable option is given without
the --respawn option. It prints a usage message starting with:

  Missing option: --respawn (required for --acceptable)

test30
------
This test shows what happens when the --attempts option is given without the
--respawn option. It prints a usage message starting with:

  Missing option: --respawn (required for --attempts)

test31
------
This test shows what happens when the --delay option is given without the
--respawn option. It prints a usage message starting with:

  Missing option: --respawn (required for --delay)

test32
------
This test shows what happens when the --limit option is given without the
--respawn option. It prints a usage message starting with:

  Missing option: --respawn (required for --limit)

test33
------
This test shows what happens when the --stop option is given without the
--name option. It prints a usage message starting with:

  Missing option: --name (required for --stop)

test34
------
This test shows what happens when the --running option is given without the
--name option. It prints a usage message starting with:

  Missing option: --name (required for --running)

test35
------
This test shows what happens when the --name option is given in the
configuration file. It prints a usage message starting with:

  Misplaced option: --name=unimportant in config file (must be on the command line)

test36
------
This test shows what happens when the --chroot option is given in the
configuration file. It prints a usage message starting with:

  Misplaced option: --chroot=/ in config file (must be on the command line)

test37
------
This test shows what happens when the --user option is given in the
configuration file. It prints a usage message starting with:

  Misplaced option: --user=nobody in config file (must be on the command line)

test38
------
This test shows that the --pidfiles option can (now) be given without the
--name option. It echoes "hi" to daemon.err.

test39
------
This test shows what happens when --restart option is given without the
--name option.

  Missing option: --name (required for --restart)

test40
------
This test shows what happens when both the --running and --restart options
are supplied.

  Incompatible options: --running and --restart

test41
------
This test shows what happens when both the --running and --stop options
are supplied.

  Incompatible options: --running and --stop

test42
------
This test shows what happens when both the --restart and --stop options
are supplied.

  Incompatible options: --restart and --stop

test43
------
This test shows what happens when the --restart, --running and --stop
options are all supplied.

  Incompatible options: --running and --restart

test44
------
This test shows what happens when both the --config and --noconfig options
are supplied:

  Incompatible options: --config and --noconfig

test45
------
This tests parsing a ~/.daemonrc file. This is just like test1 except that
the test44 specific options are obtained from ~/.daemonrc instead of the
daemon.conf in the current directory.

The client prints the numbers from 0 to 4, sleeping for a second before
printing each one. daemon will respawn the client but since it only runs for
5 seconds, the burst/wait respawn cycle is triggered. So the client should
run twice, then wait 10 seconds, then run twice more before giving up.

test46
------
This tests the --noconfig option. This is just like test45 except that the
daemon.conf file in the current directory is not read at all so the generic
options are supplied by the ~/.daemonrc file as well.

The client prints the numbers from 0 to 4, sleeping for a second before
printing each one. daemon will respawn the client but since it only runs for
5 seconds, the burst/wait respawn cycle is triggered. So the client should
run twice, then wait 10 seconds, then run twice more before giving up.

test47
------
This tests the --pidfile option. This is just like test1 except that the
pidfile is placed in the current directory. A second after daemon is called,
the pidfile in the current directory is shown using ls(1).

The client prints the numbers from 0 to 4, sleeping for a second before
printing each one. daemon will respawn the client but since it only runs for
5 seconds, the burst/wait respawn cycle is triggered. So the client should
run twice, then wait 10 seconds, then run twice more before giving up.

test48
------
This tests the --pidfiles option. This is just like test1 except that the
pidfile is placed in the current directory. A second after daemon is called,
the pidfile in the current directory is shown using ls(1).

The client prints the numbers from 0 to 4, sleeping for a second before
printing each one. daemon will respawn the client but since it only runs for
5 seconds, the burst/wait respawn cycle is triggered. So the client should
run twice, then wait 10 seconds, then run twice more before giving up.

test49
------
This test shows what happens when the argument to the --pidfile option
includes a non-existent directory.

  Invalid --pidfile argument: '/i-am-not-a-directory/i-am-an-invalid-argument/test49.pid' (Parent directory does not exist)

test50
------
This test shows what happens when the argument to the --pidfile option
includes a directory that is not writable (don't run this as root):

  Invalid --pidfile argument: '/var/test50.pid' (Parent directory is not writable)

test51
------
This test shows what happens when the argument to the --pidfile option
is not an absolute path:

  Invalid --pidfile argument: 'test51.pid' (Must be an absolute file path)

test52
------
This test shows what happens when the argument to the --pidfiles option
is not a directory.

  Invalid --pidfiles argument: '/i-am-not-a-directory/i-am-an-invalid-argument' (Directory does not exist)

test53
------
This test shows what happens when the argument to the --pidfiles option
is a directory that is not writable (don't run this as root):

  Invalid --pidfiles argument: '/var' (Directory is not writable)

test54
------
This test shows what happens when the argument to the --pidfiles option
is not an absolute path:

  Invalid --pidfiles argument: 'var' (Must be an absolute directory path)

test55
------
This test shows what happens when the argument to the --name option has
invalid characters:

  Invalid --name argument: 'name;' (Must consist entirely of [-._a-zA-Z0-9])

test56
------
This test shows what happens when the argument to the --pidfile option has
invalid characters:

  Invalid --pidfile argument: '/name;' (Must consist entirely of [-._a-zA-Z0-9/])

test57
------
This test shows what happens when the argument to the --pidfiles option has
invalid characters:

  Invalid --pidfiles argument: '/name;' (Must consist entirely of [-._a-zA-Z0-9/])

test58
------
This tests the --restart option. This test runs test1 and, three seconds later,
restarts it.

The client prints the numbers from 0 to 2, sleeping for a second before
printing each one. It is then restarted at that point, and it the prints the
numbers from 0 to 4. daemon will respawn the client but since it only runs
for 5 seconds, the burst/wait respawn cycle is triggered. So the client
should run twice, then wait 10 seconds, then run twice more before giving
up.

test59
------
This test shows what happens when no client command is supplied on the
command line. It prints a usage message starting with:

  Invalid arguments: no command supplied

test60
------
This test shows what happens when daemon tries to keep respawning a client
that terminates as soon as it's started (i.e. /bin/false). It will respawn
quickly 5 times, then wait wait for 10 seconds. It repeats this 3 times
before finally giving up.

test61
------
This tests the --command option. It echoes "test61 extra" to daemon.err.
The "test61" comes from the configuration file. The "extra" comes from
the daemon command line in the test61 shell script.

test62
------
This tests the --command option. It echoes "test62" to daemon.err.
The "test62" comes from the configuration file. No extra arguments
are passed on the command line.

test63
------
This tests daemon's response to the --stop option. It echoes "line 1 of 2"
and "line 2 of 2" to daemon.err. The second line comes from the client's
sigterm handler.

test64
------
This tests that daemon reads configuration from files in the configuration
directory, ./daemon.conf.d/*. It uses the command option in one of these
configuration files "/bin/echo test64 used" and adds arguments from the
command line "echo extra". It echoes "test64 used echo extra" to daemon.err.

test65
------
This tests that daemon doesn't read configuration from files in the
configuration directory, ./daemon.conf.d/* whose names start with the dot
character. It doesn't see the command option in one of these configuration
files "/bin/echo test65 ignored" and so only uses the arguments from the
command line "echo extra". It echoes "extra" to daemon.err.

test66
------
This tests that daemon in safe mode doesn't read configuration from files in
the configuration directory, ./daemon.conf.d/* that are unsafe (i.e. group
writable). It doesn't see the command option in one of these configuration
files "/bin/echo test66 unsafe" and so only uses the arguments from the
command line "echo extra". It echoes "extra" to daemon.err. It will also
emit an error message about ignoring the unsafe config file.

test67
------
This tests the --signal option by running test3.client (which runs
indefinitely printing the numbers from 0 to 10, sleeping for a second before
printing each one, and then respawning indefinitely - but only if it runs
uninterupted which isn't what happens in this test).

This test is configured with a 10 second minimum client duration, 2 attempts
in a burst, a 10 second delay between attempt bursts, and a limit of 2
attempt bursts.

This test starts the daemon, lets it run for 4 seconds, then runs daemon
with "--verbose --running" to see that it is running and it then runs daemon
with "--signal term" to send the SIGTERM signal directly to the named
daemon's client process. Then it waits for another 4 seconds and repeats the
process. This will cause the named daemon to start a 10 second delay between
attempt bursts since there have been 2 client processes in a row that lasted
less than 10 seconds. The test then waits 5 seconds and does another
"--verbose --running" which shows that the named daemon is running but that
its client process isn't. It then tries "--signal term" again but this fails
because the named daemon's client process isn't running. It then waits a
further 9 seconds so that the named daemon has finished its delay and
respawned its client process again. It then does another "--verbose
--running" and another "--signal term". It then waits a further 4 seconds
and repeats the process. This causes the named daemon to abandon its client
because there have been 2 attempt bursts. The test then wait a further 4
seconds and then does a final "--verbose --running" which shows that the
named daemon is no longer running at all.

The terminal output should look something like this:

  Start test67
  daemon: debug: config_process(target = test67)
  daemon --running (burst 1) (client should be running)
  daemon:  test67 is running (pid 1839) (clientpid 1840)
  daemon --signal term

  daemon --running (burst 1) (client should be running)
  daemon:  test67 is running (pid 1839) (clientpid 1848)
  daemon --signal term

  daemon --running during delay between bursts (client should not be running)
  daemon:  test67 is running (pid 1839) (client is not running)

  daemon --signal term (should fail since client is not running during delay)
  daemon: fatal: failed to find client pid for test67: No such file or directory

  daemon --running (burst 2) (client should be running)
  daemon:  test67 is running (pid 1839) (clientpid 1860)
  daemon --signal term

  daemon --running (burst 2) (client should be running)
  daemon:  test67 is running (pid 1839) (clientpid 1869)
  daemon --signal term

  daemon --running after exit (should not be running at all)
  daemon:  test67 is not running

And the daemon debug and client output log messages should look something
like this:

  daemon: 0
  daemon: 1
  daemon: 2
  daemon: test67: client (pid 1840) killed by signal 15, respawning
  daemon: 0
  daemon: 1
  daemon: 2
  daemon: test67: client (pid 1848) killed by signal 15, respawning
  daemon: test67: terminating too quickly, waiting 10 seconds
  daemon: test67: end of 10 second respawn attempt burst delay
  daemon: 0
  daemon: 1
  daemon: 2
  daemon: test67: client (pid 1860) killed by signal 15, respawning
  daemon: 0
  daemon: 1
  daemon: 2
  daemon: test67: client (pid 1869) killed by signal 15, respawning
  daemon: test67: fatal: reached respawn attempt burst limit (2), exiting

test68
------
This tests the --list option which shows a list of named daemons whose
pidfiles are in the the default or specified diffiles directory.
It also tests that names that differ numerically are sorted correctly.

This test starts three daemons named test68_9, test68_10 and test68_11. It
waits for a second, then runs daemon with the --list option to list just the
names of the daemons, then it runs daemon with the --list and --verbose
options to include more details like the daemon pid and its client pid (like
the output of --running --verbose). It then stops all of the daemons and
then repeats the two --list commands.

The output should look something like:

  Start daemons
  daemon: debug: config_process(target = test68_11)
  daemon: debug: config_process(target = test68_10)
  daemon: debug: config_process(target = test68_9)
  daemon: debug: config_process(target = test68_1)

  List:
  test68_1
  test68_9
  test68_10
  test68_11

  List verbose:
  test68_1 is running (pid 2343) (client pid 2344)
  test68_9 is running (pid 2337) (client pid 2339)
  test68_10 is running (pid 2329) (client pid 2332)
  test68_11 is running (pid 2322) (client pid 2324)

  Stop daemons

  List:

  List verbose:
  No named daemons are running

clean
-----
The clean script deletes all temporary files created by any of the tests.

