shell-test.py 2.64 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import os
import sys
import subprocess
import time
import tempfile

def run_command_through_shell(cmd, shellp, no_read=False) :
    shellp.stdin.write(cmd)
    shellp.stdin.flush()
    if not no_read:
        result = os.read(shellp.stdout.fileno(), 1000)
        return result.decode('utf-8')
    return None

def create_shell_process(shell_exec) :
    p = subprocess.Popen(shell_exec, universal_newlines=True, stdout=subprocess.PIPE,
                        stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
    return p


def expect(shellp, command, expected, min_time=None, max_time=None) :
    if expected and type(expected) != set:
        expected = {expected}

    print("=" * 80)
    print(f"CMD: {command}")
    t0 = time.time()
    r = run_command_through_shell(command, shellp, expected is None)
    t1 = time.time()
    print(f"RESULT: {r}")
    if expected and r not in expected:
        print(f"EXPECTED: {' OR '.join(expected)}")
        print("FAIL")
        return False
    elif min_time and (t1 - t0) < min_time:
        print(f"COMMAND FINISHED TOO FAST")
        return False
    elif max_time and (t1 - t0) > max_time:
        print(f"TIME LIMIT EXCEEDED")
        return False
    else:
        print("PASS")
        return True

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print(f"Run as f{sys.argv[0]} SHELL_EXEC")
        exit(1)

    shell_exec = os.path.abspath(sys.argv[1])
    with tempfile.TemporaryDirectory() as tmpdir:
        os.chdir(tmpdir)

        # Create a process running the shell
        p = create_shell_process(shell_exec)

        # Push the following commands through the shell and
        # check their output.
        tests = [("/bin/pwd\n", tmpdir + "\n"),
                 ("pwd\n", tmpdir + "\n"),
                 ("touch file1.txt\n", None),
                 ("ls\n", "file1.txt\n"),
                 ("sleep 5; echo 'hello'\n", "hello\n", 4, 6),
                 ("sleep 5 & echo 'hello'\n", "hello\n", 0, 1),
                 ("echo line1 > file1.txt\n", None),
                 ("cat < file1.txt\n", "line1\n"),
                 ("cat file1.txt | wc -l\n", "1\n"),
                 ("cat file1.txt | cat | cat | cat | cat | wc -l\n", "1\n"),
                 ("echo 'x' | cat | wc -l & echo 2\n", {"1\n", "2\n"})
                 ]

        all_pass = True
        for test in tests:
            all_pass = expect(p, *test) and all_pass

        # Send EOF to the shell
        p.stdin.close()
        # The shell should exit
        p.wait()

        print ("=" * 80)
        if all_pass:
            print ("PASS: All tests have passed.")
        else:
            print ("FAIL: Some tests have failed.")
        print ("=" * 80)