From: Kirill Isakov Date: Thu, 26 May 2022 08:20:34 +0000 (+0600) Subject: Add tests for join/invite errors X-Git-Url: https://www.tinc-vpn.org/git/browse?p=tinc;a=commitdiff_plain;h=b4280adda649c177ad27349fad4d51c2ebd9d35d Add tests for join/invite errors --- diff --git a/src/invitation.c b/src/invitation.c index 151f701b..a95a3245 100644 --- a/src/invitation.c +++ b/src/invitation.c @@ -333,6 +333,11 @@ int cmd_invite(int argc, char *argv[]) { return 1; } + if(argc > 2) { + fprintf(stderr, "Too many arguments!\n"); + return 1; + } + // Check validity of the new node's name if(!check_id(argv[1])) { fprintf(stderr, "Invalid name for node.\n"); @@ -1243,7 +1248,7 @@ int cmd_join(int argc, char *argv[]) { if(!fgets(line, sizeof(line), stdin)) { fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno)); - return false; + return 1; } invitation = line; diff --git a/test/integration/cmd_join.py b/test/integration/cmd_join.py new file mode 100755 index 00000000..585afeed --- /dev/null +++ b/test/integration/cmd_join.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 + +"""Test invite/join error conditions.""" + +import os +import shutil + +from testlib import check, util +from testlib.log import log +from testlib.proc import Tinc +from testlib.test import Test + +FAKE_INVITE = "localhost:65535/pVOZMJGm3MqTvTu0UnhMGb2cfuqygiu79MdnERnGYdga5v8C" + + +def init(ctx: Test) -> Tinc: + """Initialize a node.""" + + node = ctx.node() + stdin = f""" + init {node} + set Port 0 + set Address localhost + set DeviceType dummy + """ + node.cmd(stdin=stdin) + return node + + +def test_invite(foo: Tinc) -> None: + """Test successful 'invite'.""" + + foo.cmd("set", "Mode", "switch") + foo.cmd("set", "Broadcast", "mst") + foo.start() + + log.info("test successful invitation") + out, _ = foo.cmd("invite", "quux") + check.is_in(f"localhost:{foo.port}/", out) + + for filename in os.listdir(foo.sub("invitations")): + content = util.read_text(foo.sub(f"invitations/{filename}")) + if filename == "ed25519_key.priv": + check.is_in("-----BEGIN ED25519 PRIVATE KEY-----", content) + else: + check.is_in("Broadcast = mst", content) + check.is_in("Mode = switch", content) + check.is_in("Address = localhost", content) + check.is_in("Name = quux", content) + check.is_in(f"NetName = {foo}", content) + check.is_in(f"ConnectTo = {foo}", content) + + +def test_invite_errors(foo: Tinc) -> None: + """Test invite error conditions.""" + + log.info("invite node with tincd stopped") + _, err = foo.cmd("invite", "foobar", code=1) + check.is_in("Could not open pid file", err) + + log.info("start node %s", foo) + foo.start() + + log.info("invite without arguments") + _, err = foo.cmd("invite", code=1) + check.is_in("Not enough arguments", err) + + log.info("invite with too many arguments") + _, err = foo.cmd("invite", "foo", "bar", code=1) + check.is_in("Too many arguments", err) + + log.info("invite with invalid name") + _, err = foo.cmd("invite", "!@#", code=1) + check.is_in("Invalid name for node", err) + + log.info("invite existing node") + _, err = foo.cmd("invite", foo.name, code=1) + check.is_in("already exists", err) + + if os.name != "nt": + invites = foo.sub("invitations") + os.chmod(invites, 0) + _, err = foo.cmd("invite", "foobar", code=1) + check.is_in("Could not read directory", err) + os.chmod(invites, 0o750) + + log.info("block creating invitations directory") + shutil.rmtree(foo.sub("invitations")) + os.chmod(foo.work_dir, 0o500) + _, err = foo.cmd("invite", "foobar", code=1) + check.is_in("Could not create directory", err) + os.chmod(foo.work_dir, 0o750) + + log.info("fully block access to configuration directory") + work_dir = foo.sub("test_no_access") + os.mkdir(work_dir, mode=0) + _, err = foo.cmd("-c", work_dir, "invite", "foobar", code=1) + check.is_in("Could not open", err) + + +def test_join_errors(foo: Tinc) -> None: + """Test join error conditions.""" + + log.info("try joining with redundant arguments") + _, err = foo.cmd("join", "bar", "quux", code=1) + check.is_in("Too many arguments", err) + + log.info("try joining with existing configuration") + _, err = foo.cmd("join", FAKE_INVITE, code=1) + check.is_in("already exists", err) + + log.info("try running without an invite URL") + work_dir = foo.sub("test_no_invite") + join = foo.tinc("-c", work_dir, "join") + _, err = join.communicate(input="") + check.equals(1, join.returncode) + check.is_in("Error while reading", err) + + log.info("try using an invalid invite") + work_dir = foo.sub("test_invalid_invite") + _, err = foo.cmd("-c", work_dir, "join", FAKE_INVITE, code=1) + check.is_in("Could not connect to", err) + + if os.name != "nt": + log.info("test working without access to configuration directory") + work_dir = foo.sub("wd_access_test") + os.mkdir(work_dir, mode=400) + _, err = foo.cmd("-c", work_dir, "join", FAKE_INVITE, code=1) + check.is_in("No permission to write", err) + + +with Test("run invite success tests") as context: + test_invite(init(context)) + +with Test("run invite error tests") as context: + test_invite_errors(init(context)) + +with Test("run join tests") as context: + test_join_errors(init(context)) diff --git a/test/integration/meson.build b/test/integration/meson.build index 392d86f8..0fd03dd6 100644 --- a/test/integration/meson.build +++ b/test/integration/meson.build @@ -2,6 +2,7 @@ tests = [ 'basic.py', 'cmd_dump.py', 'cmd_fsck.py', + 'cmd_join.py', 'cmd_keys.py', 'cmd_misc.py', 'cmd_net.py', diff --git a/test/integration/testlib/proc.py b/test/integration/testlib/proc.py index d5cbee48..ffa0a5f5 100755 --- a/test/integration/testlib/proc.py +++ b/test/integration/testlib/proc.py @@ -149,6 +149,11 @@ class Tinc: """Return path to a subdirectory within the working dir for this node.""" return os.path.join(self._work_dir, *paths) + @property + def work_dir(self): + """Node's working directory.""" + return self._work_dir + @property def script_up(self) -> str: """Name of the hosts/XXX-up script for this node."""