Add tests for some device & address variables
[tinc] / test / integration / device.py
1 #!/usr/bin/env python3
2
3 """Test device configuration variables."""
4
5 import os
6 import platform
7 import typing as T
8
9 from testlib import check
10 from testlib.feature import Feature
11 from testlib.log import log
12 from testlib.proc import Script
13 from testlib.test import Test
14
15 system = platform.system()
16
17
18 def unknown_device_types(
19     features: T.Container[Feature],
20 ) -> T.Generator[str, T.Any, None]:
21     """Get devices unsupported by current OS."""
22
23     yield "foobar"
24
25     if Feature.UML not in features:
26         yield "uml"
27
28     if Feature.TUNEMU not in features:
29         yield "tunemu"
30
31     if system != "Darwin":
32         if not system.endswith("BSD"):
33             yield "tunnohead"
34             yield "tunifhead"
35
36         yield "utun"
37
38     if system == "Windows":
39         yield "tun"
40         yield "tap"
41
42
43 def test_unknown_types(ctx: Test) -> None:
44     """Test unknown device types."""
45
46     foo = ctx.node(init=True)
47
48     for dev_type in unknown_device_types(foo.features):
49         log.info("testing unknown device type %s", dev_type)
50         _, err = foo.cmd("start", "-o", f"DeviceType={dev_type}", code=1)
51         check.is_in(f"Unknown device type {dev_type}", err)
52
53
54 def test_device_standby(ctx: Test) -> None:
55     """Test DeviceStandby."""
56
57     foo, bar, baz = ctx.node(init=True), ctx.node(), ctx.node()
58
59     log.info("configure %s", foo)
60     foo.cmd("set", "DeviceStandby", "yes")
61     foo.add_script(Script.TINC_UP)
62     foo.add_script(Script.TINC_DOWN)
63
64     log.info("starting tincd must not call tinc-up")
65     foo.cmd("start")
66     assert not foo[Script.TINC_UP].wait(timeout=1)
67
68     log.info("invite %s", bar)
69     url, _ = foo.cmd("invite", bar.name)
70     bar.cmd("join", url.strip())
71     bar.cmd("set", "DeviceType", "dummy")
72     bar.cmd("set", "Port", "0")
73
74     log.info("invite %s", baz)
75     url, _ = foo.cmd("invite", baz.name)
76     baz.cmd("join", url.strip())
77     baz.cmd("set", "DeviceType", "dummy")
78     baz.cmd("set", "Port", "0")
79
80     log.info("starting first client must call tinc-up")
81     bar.start()
82     foo[Script.TINC_UP].wait()
83
84     log.info("starting second client must not call tinc-up")
85     baz.start()
86     assert not foo[Script.TINC_UP].wait(timeout=1)
87
88     log.info("stopping next-to-last client must not call tinc-down")
89     bar.add_script(Script.TINC_DOWN)
90     bar.cmd("stop")
91     bar[Script.TINC_DOWN].wait()
92     assert not foo[Script.TINC_DOWN].wait(timeout=1)
93
94     log.info("stopping last client must call tinc-down")
95     baz.cmd("stop")
96     foo[Script.TINC_DOWN].wait()
97
98     log.info("stopping tincd must not call tinc-down")
99     foo.cmd("stop")
100     assert not foo[Script.TINC_DOWN].wait(timeout=1)
101
102
103 # Device types are not checked on Windows.
104 # /dev/net/tun is not available in Docker containers.
105 if system != "Windows" and (system != "Linux" or os.path.exists("/dev/net/tun")):
106     with Test("unknown device types") as context:
107         test_unknown_types(context)
108
109 if system != "Windows":
110     with Test("test DeviceStandby = yes") as context:
111         test_device_standby(context)