931b6d406f75a01a19beb0f5f8d47ab2ef9ed19a
[tinc] / test / integration / commandline.py
1 #!/usr/bin/env python3
2
3 """Test supported and unsupported commandline flags."""
4
5 import os
6 import signal
7 import subprocess as subp
8 import time
9
10 from testlib import check, util, path
11 from testlib.log import log
12 from testlib.proc import Tinc, Script
13 from testlib.test import Test
14
15 tinc_flags = (
16     (0, ("get", "name")),
17     (0, ("-n", "foo", "get", "name")),
18     (0, ("-nfoo", "get", "name")),
19     (0, ("--net=foo", "get", "name")),
20     (0, ("--net", "foo", "get", "name")),
21     (0, ("-c", "conf", "-c", "conf")),
22     (0, ("-n", "net", "-n", "net")),
23     (0, ("--pidfile=pid", "--pidfile=pid")),
24     (1, ("-n", "foo", "get", "somethingreallyunknown")),
25     (1, ("--net",)),
26     (1, ("--net", "get", "name")),
27     (1, ("foo",)),
28     (1, ("-c", "conf", "-n", "n/e\\t")),
29 )
30
31 tincd_flags = (
32     (0, ("-D",)),
33     (0, ("--no-detach",)),
34     (0, ("-D", "-d")),
35     (0, ("-D", "-d2")),
36     (0, ("-D", "-d", "2")),
37     (0, ("-D", "-n", "foo")),
38     (0, ("-D", "-nfoo")),
39     (0, ("-D", "--net=foo")),
40     (0, ("-D", "--net", "foo")),
41     (0, ("-D", "-c", ".", "-c", ".")),
42     (0, ("-D", "-n", "net", "-n", "net")),
43     (0, ("-D", "-n", "net", "-o", "FakeOpt=42")),
44     (0, ("-D", "--logfile=log", "--logfile=log")),
45     (0, ("-D", "--pidfile=pid", "--pidfile=pid")),
46     (1, ("foo",)),
47     (1, ("--pidfile",)),
48     (1, ("--foo",)),
49     (1, ("-n", "net", "-o", "Compression=")),
50     (1, ("-c", "fakedir", "-n", "n/e\\t")),
51 )
52
53
54 def init(ctx: Test) -> Tinc:
55     """Initialize new test nodes."""
56     tinc = ctx.node()
57     stdin = f"""
58         init {tinc}
59         set Port 0
60         set Address localhost
61         set DeviceType dummy
62     """
63     tinc.cmd(stdin=stdin)
64     tinc.add_script(Script.TINC_UP)
65     return tinc
66
67
68 with Test("commandline flags") as context:
69     node = init(context)
70
71     for code, flags in tincd_flags:
72         COOKIE = util.random_string(10)
73         server = node.tincd(*flags, env={"COOKIE": COOKIE})
74
75         if not code:
76             log.info("waiting for tincd to come up")
77             env = node[Script.TINC_UP].wait().env
78             check.equals(COOKIE, env["COOKIE"])
79
80         log.info("stopping tinc")
81         node.cmd("stop", code=code)
82
83         log.info("reading tincd output")
84         stdout, stderr = server.communicate()
85
86         log.debug('got code %d, ("%s", "%s")', server.returncode, stdout, stderr)
87         check.equals(code, server.returncode)
88
89     for code, flags in tinc_flags:
90         node.cmd(*flags, code=code)
91
92
93 def test_relative_path(ctx: Test, chroot: bool) -> None:
94     """Test tincd with relative paths."""
95
96     foo = init(ctx)
97
98     conf_dir = os.path.realpath(foo.sub("."))
99     dirname = os.path.dirname(conf_dir)
100     basename = os.path.basename(conf_dir)
101     log.info("using confdir %s, dirname %s, basename %s", conf_dir, dirname, basename)
102
103     args = [
104         path.TINCD_PATH,
105         "-D",
106         "-c",
107         basename,
108         "--pidfile",
109         "pid",
110         "--logfile",
111         ".//./log",
112     ]
113
114     if chroot:
115         args.append("-R")
116
117     pidfile = os.path.join(dirname, "pid")
118     util.remove_file(pidfile)
119
120     logfile = os.path.join(dirname, "log")
121     util.remove_file(logfile)
122
123     with subp.Popen(args, stderr=subp.STDOUT, cwd=dirname) as tincd:
124         foo[Script.TINC_UP].wait(10)
125
126         log.info("pidfile and logfile must exist at expected paths")
127         check.file_exists(pidfile)
128         check.file_exists(logfile)
129
130         # chrooted tincd won't be able to reopen its log since in this
131         # test we put the log outside tinc's configuration directory.
132         if os.name != "nt" and not chroot:
133             log.info("test log file rotation")
134             time.sleep(1)
135             util.remove_file(logfile)
136             os.kill(tincd.pid, signal.SIGHUP)
137             time.sleep(1)
138
139             log.info("pidfile and logfile must still exist")
140             check.file_exists(pidfile)
141             check.file_exists(logfile)
142
143         log.info("stopping tinc through '%s'", pidfile)
144         foo.cmd("--pidfile", pidfile, "stop")
145         check.equals(0, tincd.wait())
146
147
148 with Test("relative path to tincd dir") as context:
149     test_relative_path(context, chroot=False)
150
151 if os.name != "nt" and not os.getuid():
152     with Test("relative path to tincd dir (chroot)") as context:
153         test_relative_path(context, chroot=True)