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