Skip to content

Commit

Permalink
Rewrite integration test suite in Python
Browse files Browse the repository at this point in the history
While the previous test suite ran fine in practice, it relied on
subtle differences in behavior of many UNIX tools, and thus needed GNU
Coreutils on many operating systems to work properly, and didn't work on
"pure" Windows at all.

A simple example would be how different versions of tail handle SIGPIPE
if you pipe its output into another process: GNU tail exits on SIGPIPE
since about 2017 (too lazy to look up the exact version, but this
changed recently), while most other tails continue reading the file and
piping the output into god knows where.

Since we need Python to run the new build system (meson) anyway, let's
use it for the test suite, and get rid of all other test dependencies.

It (currently) requires only the standard library of Python 3.6 or newer.

Unlike the original test suite, this one assigns node names and port
numbers randomly to support `meson test --repeat` (because meson can run
the same test multiple times in parallel, and this breaks with the old
approach).

Also remove old integration tests based on shell scripts.
  • Loading branch information
hg committed Apr 10, 2022
1 parent 2ded4a8 commit 9a012e4
Show file tree
Hide file tree
Showing 56 changed files with 3,147 additions and 2,004 deletions.
19 changes: 19 additions & 0 deletions .pylintrc
@@ -0,0 +1,19 @@
[MASTER]
jobs=0
persistent=yes
py-version=3.6
recursive=yes
ignore=build

[BASIC]
good-names=foo, bar, baz, f, k, ex

[REPORTS]
output-format=colorized

[DESIGN]
min-public-methods=0

[SIMILARITIES]
min-similarity-lines=10

17 changes: 15 additions & 2 deletions src/sptps_test.c
Expand Up @@ -301,6 +301,19 @@ static int start_input_reader(void) {

#endif // HAVE_WINDOWS

static void print_listening_msg(int sock) {
sockaddr_t sa = {0};
socklen_t salen = sizeof(sa);
int port = 0;

if(!getsockname(sock, &sa.sa, &salen)) {
port = ntohs(sa.in.sin_port);
}

fprintf(stderr, "Listening on %d...\n", port);
fflush(stderr);
}

int main(int argc, char *argv[]) {
program_name = argv[0];
bool initiator = false;
Expand Down Expand Up @@ -481,7 +494,7 @@ int main(int argc, char *argv[]) {
return 1;
}

fprintf(stderr, "Listening...\n");
print_listening_msg(sock);

sock = accept(sock, NULL, NULL);

Expand All @@ -490,7 +503,7 @@ int main(int argc, char *argv[]) {
return 1;
}
} else {
fprintf(stderr, "Listening...\n");
print_listening_msg(sock);

char buf[65536];
struct sockaddr addr;
Expand Down
67 changes: 67 additions & 0 deletions test/integration/algorithms.py
@@ -0,0 +1,67 @@
#!/usr/bin/env python3

"""Check that legacy protocol works with different cryptographic algorithms."""

import typing as T

from testlib.test import Test
from testlib.proc import Tinc
from testlib.log import log
from testlib import cmd, check


def init(ctx: Test, digest: str, cipher: str) -> T.Tuple[Tinc, Tinc]:
"""Initialize new test nodes."""
foo, bar = ctx.node(), ctx.node()

stdin = f"""
init {foo}
set Port 0
set DeviceType dummy
set Address localhost
set ExperimentalProtocol no
set Digest {digest}
set Cipher {cipher}
"""
foo.cmd(stdin=stdin)
foo.start()

stdin = f"""
init {bar}
set Port 0
set DeviceType dummy
set Address localhost
set ExperimentalProtocol no
set Digest {digest}
set Cipher {cipher}
"""
bar.cmd(stdin=stdin)

foo.add_script(bar.script_up)
bar.add_script(foo.script_up)

cmd.exchange(foo, bar)
bar.cmd("add", "ConnectTo", foo.name)
bar.cmd("start")

return foo, bar


def test(foo: Tinc, bar: Tinc) -> None:
"""Run tests on algorithm pair."""
log.info("waiting for bar to come up")
foo[bar.script_up].wait()

log.info("waiting for foo to come up")
bar[foo.script_up].wait()

log.info("checking node reachability")
stdout, _ = foo.cmd("info", bar.name)
check.is_in("reachable", stdout)


for alg_digest in "none", "sha256", "sha512":
for alg_cipher in "none", "aes-256-cbc":
with Test("compression") as context:
node0, node1 = init(context, alg_digest, alg_cipher)
test(node0, node1)
56 changes: 0 additions & 56 deletions test/integration/algorithms.test

This file was deleted.

48 changes: 48 additions & 0 deletions test/integration/basic.py
@@ -0,0 +1,48 @@
#!/usr/bin/env python3

"""Check that basic functionality works (tincd can be started and stopped)."""

from testlib.test import Test
from testlib.proc import Tinc
from testlib.log import log
from testlib.script import Script
from testlib import check


def init(ctx: Test) -> Tinc:
"""Initialize new test nodes."""
node = ctx.node()
node.add_script(Script.TINC_UP)
stdin = f"""
init {node}
set Address localhost
set Port 0
set DeviceType dummy
"""
node.cmd(stdin=stdin)
return node


def test(ctx: Test, *flags: str) -> None:
"""Run tests with flags."""
log.info("init new node")
node = init(ctx)

log.info('starting tincd with flags "%s"', " ".join(flags))
tincd = node.tincd(*flags)

log.info("waiting for tinc-up script")
node[Script.TINC_UP].wait()

log.info("stopping tincd")
node.cmd("stop")

log.info("checking tincd exit code")
check.equals(0, tincd.wait())


with Test("foreground mode") as context:
test(context, "-D")

with Test("background mode") as context:
test(context)
26 changes: 0 additions & 26 deletions test/integration/basic.test

This file was deleted.

0 comments on commit 9a012e4

Please sign in to comment.