3 """Test that all tincd scripts execute in correct order and contain expected env vars."""
8 from testlib import check, path
9 from testlib.log import log
10 from testlib.proc import Tinc, Script, ScriptType, TincScript
11 from testlib.test import Test
12 from testlib.util import random_string
14 SUBNET_SERVER = ("10.0.0.1", "fec0::/64")
15 SUBNET_CLIENT = ("10.0.0.2", "fec0::/64#5")
17 "server": "net_" + random_string(8),
18 "invite": "net_" + random_string(8),
19 "client": "net_" + random_string(8),
22 # Creation time for the last notification event we've received.
23 # Used for checking that scripts are called in the correct order.
24 # dict is to avoid angering linters by using `global` to update this value.
25 last_time = {"time": -1}
28 def init(ctx: Test) -> T.Tuple[Tinc, Tinc]:
29 """Initialize new test nodes."""
30 server, client = ctx.node(), ctx.node()
37 set AddressFamily ipv4
38 add Subnet {SUBNET_SERVER[0]}
39 add Subnet {SUBNET_SERVER[1]}
41 server.cmd(stdin=stdin)
50 server.add_script(script)
55 def wait_script(script: TincScript) -> T.Dict[str, str]:
56 """Wait for script to finish and check that it was run by tincd *after* the
57 script that was used as the argument in the previous call to this function.
59 For example, to check that SUBNET_UP is called after TINC_UP:
60 wait_script(node[Script.TINC_UP])
61 wait_script(node[Script.SUBNET_UP])
67 "%s sent %d, prev %d, diff %d",
71 msg.created_at - last_time["time"],
74 if msg.created_at <= last_time["time"]:
75 raise ValueError(f"script {script} started in wrong order")
77 last_time["time"] = msg.created_at
81 def wait_tinc(server: Tinc, script: Script) -> None:
82 """Wait for TINC_UP / TINC_DOWN and check env vars."""
83 log.info("checking tinc: %s %s", server, script)
85 env = wait_script(server[script])
86 check.equals(NETNAMES["server"], env["NETNAME"])
87 check.equals(server.name, env["NAME"])
88 check.equals("dummy", env["DEVICE"])
91 def wait_subnet(server: Tinc, script: Script, node: Tinc, subnet: str) -> None:
92 """Wait for SUBNET_UP / SUBNET_DOWN and check env vars."""
93 log.info("checking subnet: %s %s %s %s", server, script, node, subnet)
95 env = wait_script(server[script])
96 check.equals(NETNAMES["server"], env["NETNAME"])
97 check.equals(server.name, env["NAME"])
98 check.equals("dummy", env["DEVICE"])
99 check.equals(node.name, env["NODE"])
102 check.equals("127.0.0.1", env["REMOTEADDRESS"])
103 check.equals(str(node.port), env["REMOTEPORT"])
106 addr, weight = subnet.split("#")
107 check.equals(addr, env["SUBNET"])
108 check.equals(weight, env["WEIGHT"])
110 check.equals(subnet, env["SUBNET"])
113 def wait_host(server: Tinc, client: Tinc, script: ScriptType) -> None:
114 """Wait for HOST_UP / HOST_DOWN and check env vars."""
115 log.info("checking host: %s %s %s", server, client, script)
117 env = wait_script(server[script])
118 check.equals(NETNAMES["server"], env["NETNAME"])
119 check.equals(server.name, env["NAME"])
120 check.equals(client.name, env["NODE"])
121 check.equals("dummy", env["DEVICE"])
122 check.equals("127.0.0.1", env["REMOTEADDRESS"])
123 check.equals(str(client.port), env["REMOTEPORT"])
126 def test_start_server(server: Tinc) -> None:
127 """Start server node and run checks on its scripts."""
128 server.cmd("-n", NETNAMES["server"], "start")
129 wait_tinc(server, Script.TINC_UP)
131 port = server.read_port()
132 server.cmd("set", "port", str(port))
134 log.info("test server subnet-up")
135 for sub in SUBNET_SERVER:
136 wait_subnet(server, Script.SUBNET_UP, server, sub)
139 def test_invite_client(server: Tinc, client: Tinc) -> str:
140 """Check that client invitation scripts work."""
141 url, _ = server.cmd("-n", NETNAMES["invite"], "invite", client.name)
145 env = wait_script(server[Script.INVITATION_CREATED])
146 check.equals(NETNAMES["invite"], env["NETNAME"])
147 check.equals(server.name, env["NAME"])
148 check.equals(client.name, env["NODE"])
149 check.equals(url, env["INVITATION_URL"])
150 assert os.path.isfile(env["INVITATION_FILE"])
155 def test_join_client(server: Tinc, client: Tinc, url: str) -> None:
156 """Test that client joining scripts work."""
157 client.cmd("-n", NETNAMES["client"], "join", url)
159 env = wait_script(server[Script.INVITATION_ACCEPTED])
160 check.equals(NETNAMES["server"], env["NETNAME"])
161 check.equals(server.name, env["NAME"])
162 check.equals(client.name, env["NODE"])
163 check.equals("dummy", env["DEVICE"])
164 check.equals("127.0.0.1", env["REMOTEADDRESS"])
167 def test_start_client(server: Tinc, client: Tinc) -> None:
168 """Start client and check its script work."""
169 client.randomize_port()
172 set Address {client.address}
173 set ListenAddress {client.address}
174 set Port {client.port}
176 add Subnet {SUBNET_CLIENT[0]}
177 add Subnet {SUBNET_CLIENT[1]}
180 client.cmd(stdin=stdin)
182 log.info("test client scripts")
183 wait_host(server, client, Script.HOST_UP)
184 wait_host(server, client, client.script_up)
186 log.info("test client subnet-up")
187 for sub in SUBNET_CLIENT:
188 wait_subnet(server, Script.SUBNET_UP, client, sub)
191 def test_stop_server(server: Tinc, client: Tinc) -> None:
192 """Stop server and check that its scripts work."""
194 wait_host(server, client, Script.HOST_DOWN)
195 wait_host(server, client, client.script_down)
197 log.info("test client subnet-down")
198 for sub in SUBNET_CLIENT:
199 wait_subnet(server, Script.SUBNET_DOWN, client, sub)
201 log.info("test server subnet-down")
202 for sub in SUBNET_SERVER:
203 wait_subnet(server, Script.SUBNET_DOWN, server, sub)
205 log.info("test tinc-down")
206 wait_tinc(server, Script.TINC_DOWN)
209 def run_tests(ctx: Test) -> None:
211 server, client = init(ctx)
213 log.info("start server")
214 test_start_server(server)
216 log.info("invite client")
217 url = test_invite_client(server, client)
219 log.info('join client via url "%s"', url)
220 test_join_client(server, client, url)
222 log.info("start client")
223 test_start_client(server, client)
225 log.info("stop server")
226 test_stop_server(server, client)
229 def run_script_interpreter_test(ctx: Test) -> None:
230 """Check that tincd scripts run with a custom script interpreter."""
236 set ScriptsInterpreter {path.PYTHON_PATH}
238 foo_up = foo.add_script(Script.TINC_UP)
246 with Test("scripts test") as context:
250 with Test("works with ScriptInterpreter") as context:
251 run_script_interpreter_test(context)