Shorter paths to PID files in integration tests
[tinc] / test / integration / cmd_misc.py
1 #!/usr/bin/env python3
2
3 """Test miscellaneous commands."""
4
5 import time
6 import typing as T
7
8 from testlib import check, cmd, util
9 from testlib.log import log
10 from testlib.proc import Tinc, Script
11 from testlib.test import Test
12
13 SUBNETS_BAR = ("10.20.30.40", "fe80::")
14
15
16 def init(ctx: Test) -> Tinc:
17     """Initialize a node."""
18
19     node = ctx.node()
20     stdin = f"""
21         init {node}
22         set Port 0
23         set Address localhost
24         set DeviceType dummy
25     """
26     node.cmd(stdin=stdin)
27     return node
28
29
30 def configure_nodes(ctx: Test) -> T.Tuple[Tinc, Tinc]:
31     """Create and configure nodes."""
32
33     log.info("initialize nodes")
34     foo, bar = init(ctx), init(ctx)
35
36     log.info("configure and start nodes")
37     foo.cmd("add", "Subnet", "1.2.3.4")
38     foo.add_script(Script.TINC_UP)
39     foo.add_script(bar.script_up)
40     foo.start()
41
42     for sub in SUBNETS_BAR:
43         bar.cmd("add", "Subnet", sub)
44     bar.start()
45
46     log.info("connect nodes")
47     cmd.exchange(foo, bar)
48     foo.cmd("add", "ConnectTo", bar.name)
49     foo.cmd("retry")
50     foo[bar.script_up].wait()
51
52     return foo, bar
53
54
55 def test_version(foo: Tinc) -> None:
56     """Test command 'version'."""
57
58     log.info("test command 'version' with redundant arguments")
59     _, err = foo.cmd("version", "foo", code=1)
60     check.is_in("Too many arguments", err)
61
62     log.info("test command 'version'")
63     out, _ = foo.cmd("version")
64     check.has_prefix(out, "tinc version ")
65
66
67 def test_help(foo: Tinc) -> None:
68     """Test command 'help'."""
69
70     log.info("test command 'help'")
71     out, _ = foo.cmd("help")
72     check.is_in("Valid options are", out)
73
74     out, _ = foo.cmd("help", "foobar")
75     check.is_in("Valid options are", out)
76
77
78 def test_info(foo: Tinc, bar: Tinc) -> None:
79     """Test command 'info'."""
80
81     log.info("info invalid arguments")
82     _, err = foo.cmd("info", code=1)
83     check.is_in("Invalid number of arguments", err)
84
85     log.info("info unknown node")
86     _, err = foo.cmd("info", "foobar", code=1)
87     check.is_in("Unknown node foobar", err)
88
89     log.info("info own node")
90     out, _ = foo.cmd("info", foo.name)
91     check.is_in("can reach itself", out)
92
93     log.info("info peer node")
94     out, _ = foo.cmd("info", bar.name)
95     check.is_in(bar.name, out)
96     for sub in SUBNETS_BAR:
97         check.is_in(sub, out)
98
99     log.info("info unknown subnet")
100     for sub in "1.1.1.1", "fe82:42::":
101         _, err = foo.cmd("info", sub, code=1)
102         check.is_in("Unknown address", err)
103
104     log.info("info own valid subnet")
105     out, _ = foo.cmd("info", "1.2.3.4")
106     check.is_in("Subnet: 1.2.3.4", out)
107     check.is_in(f"Owner:  {foo}", out)
108
109     for sub in SUBNETS_BAR:
110         log.info("info peer's valid subnet %s", sub)
111         out, _ = foo.cmd("info", sub)
112         check.is_in(f"Subnet: {sub}", out)
113         check.is_in(f"Owner:  {bar}", out)
114
115
116 def test_pid(foo: Tinc) -> None:
117     """Test command 'pid'."""
118
119     log.info("test pid with too many arguments")
120     _, err = foo.cmd("pid", "foo", code=1)
121     check.is_in("Too many arguments", err)
122
123     log.info("test pid without arguments")
124     pidfile = util.read_text(foo.pid_file)
125     pid, _ = pidfile.split(maxsplit=1)
126
127     out, _ = foo.cmd("pid")
128     check.equals(pid, out.strip())
129
130
131 def test_debug(foo: Tinc) -> None:
132     """Test command 'debug'."""
133
134     for args in ("debug",), ("debug", "1", "2"):
135         _, err = foo.cmd(*args, code=1)
136         check.is_in("Invalid number of arguments", err)
137
138     _, err = foo.cmd("debug", "5")
139     check.is_in("new level 5", err)
140
141
142 def test_log(foo: Tinc) -> None:
143     """Test command 'log'."""
144
145     log.info("test with too many arguments")
146     _, err = foo.cmd("log", "foo", "bar", code=1)
147     check.is_in("Too many arguments", err)
148
149     log.info("test correct call")
150     log_client = foo.tinc("log")
151     foo.cmd("reload")
152     time.sleep(1)
153     foo.cmd("stop")
154
155     out, _ = log_client.communicate()
156     check.true(out)
157
158
159 def test_restart(foo: Tinc) -> None:
160     """Test command 'restart'."""
161
162     log.info("restart without arguments")
163     foo.cmd("restart")
164     foo[Script.TINC_UP].wait()
165
166     log.info("restart with an argument")
167     foo.cmd("restart", "-d3")
168     foo[Script.TINC_UP].wait()
169
170     # Checking the error message is unreliable since
171     # it's provided by getopt() and differs from OS to OS.
172     log.info("restart with invalid options")
173     foo.cmd("restart", "--fake-invalid-option", code=1)
174
175     log.info("restart with invalid arguments")
176     _, err = foo.cmd("restart", "bad-incorrect-argument", code=1)
177     check.is_in("unrecognized argument", err)
178
179
180 def test_shell(foo: Tinc) -> None:
181     """Test shell."""
182
183     log.info("indented comments are not ignored")
184     _, err = foo.cmd(stdin=" # ", code=1)
185     check.is_in("Unknown command", err)
186
187     log.info("comments are ignored")
188     _, err = foo.cmd(stdin="# this_will_fail unless comments are ignored")
189     assert "this_will_fail" not in err
190
191     log.info("inline comments are treated as arguments")
192     _, err = foo.cmd(stdin="version # inline comments are not ignored", code=1)
193     check.is_in("Too many arguments", err)
194
195     log.info("check exit commands")
196     for command in "exit", "quit":
197         out, _ = foo.cmd(stdin=command)
198         check.blank(out)
199
200
201 def run_tests(ctx: Test) -> None:
202     """Run tests."""
203
204     foo, bar = configure_nodes(ctx)
205     test_shell(foo)
206     test_version(foo)
207     test_help(foo)
208     test_info(foo, bar)
209     test_pid(foo)
210     test_debug(foo)
211     test_log(foo)
212     test_restart(foo)
213
214
215 with Test("run tests") as context:
216     run_tests(context)