chore: refactor python tests to use unittest (#2414)

Move every test to a method on DenoTestCase.
test.py is a single TestSuite of every TestCase.

Add a Spawn context manager for http_server,
this is explicitly used where it's needed.
Each python test file can now be run independently
without needing to manually run http_server.

Add --help and consistent flags using argparse for
each python test, including --failfast.

Use ColorTextTestRunner so that '... ok' is green.
This commit is contained in:
Andy Hayden 2019-05-30 13:40:40 -07:00 committed by Ryan Dahl
parent 1540b36ce7
commit 8fb44eba5b
17 changed files with 548 additions and 603 deletions

View file

@ -196,7 +196,7 @@ build_script:
test_script: test_script:
- python tools\lint.py - python tools\lint.py
- python tools\test_format.py - python tools\test_format.py
- ps: Exec { & python tools\test.py $env:DENO_BUILD_PATH } - ps: Exec { & python tools\test.py -v $env:DENO_BUILD_PATH }
after_test: after_test:
# Delete the the rollup cache, which is unreliable, so that it doesn't get # Delete the the rollup cache, which is unreliable, so that it doesn't get

View file

@ -73,7 +73,7 @@ script:
- ./tools/lint.py - ./tools/lint.py
- ./tools/test_format.py - ./tools/test_format.py
- ./tools/build.py -C target/release - ./tools/build.py -C target/release
- DENO_BUILD_MODE=release ./tools/test.py - DENO_BUILD_MODE=release ./tools/test.py -v
jobs: jobs:
fast_finish: true fast_finish: true

View file

@ -3,11 +3,14 @@
import sys import sys
import os import os
import benchmark import benchmark
from util import build_path, executable_suffix import unittest
from util import DenoTestCase, test_main
def strace_parse_test(): class TestBenchmark(DenoTestCase):
with open(os.path.join(sys.path[0], "testdata/strace_summary.out"), def test_strace_parse(self):
with open(
os.path.join(sys.path[0], "testdata/strace_summary.out"),
"r") as f: "r") as f:
summary = benchmark.strace_parse(f.read()) summary = benchmark.strace_parse(f.read())
# first syscall line # first syscall line
@ -21,24 +24,23 @@ def strace_parse_test():
# summary line # summary line
assert summary["total"]["calls"] == 704 assert summary["total"]["calls"] == 704
def test_max_mem_parse(self):
def max_mem_parse_test():
with open(os.path.join(sys.path[0], "testdata/time.out"), "r") as f: with open(os.path.join(sys.path[0], "testdata/time.out"), "r") as f:
data = f.read() data = f.read()
assert benchmark.find_max_mem_in_bytes(data) == 120380 * 1024 assert benchmark.find_max_mem_in_bytes(data) == 120380 * 1024
def test_binary_size(self):
def binary_size_test(build_dir): binary_size_dict = benchmark.get_binary_sizes(self.build_dir)
binary_size_dict = benchmark.get_binary_sizes(build_dir)
assert binary_size_dict["deno"] > 0 assert binary_size_dict["deno"] > 0
assert binary_size_dict["main.js"] > 0 assert binary_size_dict["main.js"] > 0
assert binary_size_dict["main.js.map"] > 0 assert binary_size_dict["main.js.map"] > 0
assert binary_size_dict["snapshot_deno.bin"] > 0 assert binary_size_dict["snapshot_deno.bin"] > 0
@unittest.skipIf("linux" not in sys.platform,
def strace_test(deno_path): "strace only supported on linux")
def test_strace(self):
new_data = {} new_data = {}
benchmark.run_strace_benchmarks(deno_path, new_data) benchmark.run_strace_benchmarks(self.deno_exe, new_data)
assert "thread_count" in new_data assert "thread_count" in new_data
assert "syscall_count" in new_data assert "syscall_count" in new_data
@ -51,26 +53,7 @@ def strace_test(deno_path):
assert s["hello"] > 1 assert s["hello"] > 1
def benchmark_test(build_dir, deno_path):
strace_parse_test()
binary_size_test(build_dir)
max_mem_parse_test()
if "linux" in sys.platform:
strace_test(deno_path)
# This test assumes tools/http_server.py is running in the background.
def main():
if len(sys.argv) == 2:
build_dir = sys.argv[1]
elif len(sys.argv) == 1:
build_dir = build_path()
else:
print "Usage: tools/benchmark_test.py [build_dir]"
sys.exit(1)
deno_exe = os.path.join(build_dir, "deno" + executable_suffix)
benchmark_test(build_dir, deno_exe)
if __name__ == '__main__': if __name__ == '__main__':
main() # FIME this doesn't appear to be the case.
# This test assumes tools/http_server.py is running in the background.
test_main()

View file

@ -2,15 +2,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. # Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import os import os
import pty
import select
import subprocess import subprocess
import sys import sys
import time import time
import unittest import unittest
import http_server from http_server import spawn
from util import build_path, root_path, executable_suffix, green_ok, red_failed from util import DenoTestCase, root_path, test_main, tty_capture
PERMISSIONS_PROMPT_TEST_TS = "tools/complex_permissions_test.ts" PERMISSIONS_PROMPT_TEST_TS = "tools/complex_permissions_test.ts"
@ -18,47 +16,8 @@ PROMPT_PATTERN = b'⚠️'
PERMISSION_DENIED_PATTERN = b'PermissionDenied: permission denied' PERMISSION_DENIED_PATTERN = b'PermissionDenied: permission denied'
# This function is copied from: @unittest.skipIf(os.name == 'nt', "Unable to test tty on Windows")
# https://gist.github.com/hayd/4f46a68fc697ba8888a7b517a414583e class BaseComplexPermissionTest(DenoTestCase):
# https://stackoverflow.com/q/52954248/1240268
def tty_capture(cmd, bytes_input, timeout=5):
"""Capture the output of cmd with bytes_input to stdin,
with stdin, stdout and stderr as TTYs."""
mo, so = pty.openpty() # provide tty to enable line-buffering
me, se = pty.openpty()
mi, si = pty.openpty()
fdmap = {mo: 'stdout', me: 'stderr', mi: 'stdin'}
timeout_exact = time.time() + timeout
p = subprocess.Popen(
cmd, bufsize=1, stdin=si, stdout=so, stderr=se, close_fds=True)
os.write(mi, bytes_input)
select_timeout = .04 #seconds
res = {'stdout': b'', 'stderr': b''}
while True:
ready, _, _ = select.select([mo, me], [], [], select_timeout)
if ready:
for fd in ready:
data = os.read(fd, 512)
if not data:
break
res[fdmap[fd]] += data
elif p.poll() is not None or time.time(
) > timeout_exact: # select timed-out
break # p exited
for fd in [si, so, se, mi, mo, me]:
os.close(fd) # can't do it sooner: it leads to errno.EIO error
p.wait()
return p.returncode, res['stdout'], res['stderr']
class ComplexPermissionTestCase(unittest.TestCase):
def __init__(self, method_name, test_type, deno_exe):
super(ComplexPermissionTestCase, self).__init__(method_name)
self.test_type = test_type
self.deno_exe = deno_exe
def _run_deno(self, flags, args): def _run_deno(self, flags, args):
"Returns (return_code, stdout, stderr)." "Returns (return_code, stdout, stderr)."
cmd = ([self.deno_exe, "run", "--no-prompt"] + flags + cmd = ([self.deno_exe, "run", "--no-prompt"] + flags +
@ -66,7 +25,9 @@ class ComplexPermissionTestCase(unittest.TestCase):
return tty_capture(cmd, b'') return tty_capture(cmd, b'')
class TestReadWritePermissions(ComplexPermissionTestCase): class TestReadPermissions(BaseComplexPermissionTest):
test_type = "read"
def test_inside_project_dir(self): def test_inside_project_dir(self):
code, _stdout, stderr = self._run_deno( code, _stdout, stderr = self._run_deno(
["--allow-" + self.test_type + "=" + root_path], ["--allow-" + self.test_type + "=" + root_path],
@ -136,7 +97,13 @@ class TestReadWritePermissions(ComplexPermissionTestCase):
os.chdir(saved_curdir) os.chdir(saved_curdir)
class TestNetFetchPermissions(ComplexPermissionTestCase): class TestWritePermissions(TestReadPermissions):
test_type = "write"
class TestNetFetchPermissions(BaseComplexPermissionTest):
test_type = "net_fetch"
def test_allow_localhost_4545(self): def test_allow_localhost_4545(self):
code, _stdout, stderr = self._run_deno( code, _stdout, stderr = self._run_deno(
["--allow-net=localhost:4545"], ["--allow-net=localhost:4545"],
@ -171,7 +138,9 @@ class TestNetFetchPermissions(ComplexPermissionTestCase):
assert not PERMISSION_DENIED_PATTERN in stderr assert not PERMISSION_DENIED_PATTERN in stderr
class TestNetDialPermissions(ComplexPermissionTestCase): class TestNetDialPermissions(BaseComplexPermissionTest):
test_type = "net_dial"
def test_allow_localhost_ip_4555(self): def test_allow_localhost_ip_4555(self):
code, _stdout, stderr = self._run_deno( code, _stdout, stderr = self._run_deno(
["--allow-net=127.0.0.1:4545"], [self.test_type, "127.0.0.1:4545"]) ["--allow-net=127.0.0.1:4545"], [self.test_type, "127.0.0.1:4545"])
@ -203,7 +172,9 @@ class TestNetDialPermissions(ComplexPermissionTestCase):
assert not PERMISSION_DENIED_PATTERN in stderr assert not PERMISSION_DENIED_PATTERN in stderr
class TestNetListenPermissions(ComplexPermissionTestCase): class TestNetListenPermissions(BaseComplexPermissionTest):
test_type = "net_listen"
def test_allow_localhost_4555(self): def test_allow_localhost_4555(self):
code, _stdout, stderr = self._run_deno( code, _stdout, stderr = self._run_deno(
["--allow-net=localhost:4555"], [self.test_type, "localhost:4555"]) ["--allow-net=localhost:4555"], [self.test_type, "localhost:4555"])
@ -235,36 +206,10 @@ class TestNetListenPermissions(ComplexPermissionTestCase):
assert not PERMISSION_DENIED_PATTERN in stderr assert not PERMISSION_DENIED_PATTERN in stderr
def complex_permissions_test(deno_exe): def complex_permissions_tests():
runner = unittest.TextTestRunner(verbosity=2) return BaseComplexPermissionTest.__subclasses__()
loader = unittest.TestLoader()
tests = (
("read", TestReadWritePermissions),
("write", TestReadWritePermissions),
("net_fetch", TestNetFetchPermissions),
("net_dial", TestNetDialPermissions),
("net_listen", TestNetListenPermissions),
)
for (test_type, test_class) in tests:
print "Complex permissions tests for \"{}\"".format(test_type)
test_names = loader.getTestCaseNames(test_class)
suite = unittest.TestSuite()
for test_name in test_names:
suite.addTest(test_class(test_name, test_type, deno_exe))
result = runner.run(suite)
if not result.wasSuccessful():
sys.exit(1)
def main():
deno_exe = os.path.join(build_path(), "deno" + executable_suffix)
http_server.spawn()
complex_permissions_test(deno_exe)
if __name__ == "__main__": if __name__ == "__main__":
main() with spawn():
test_main()

View file

@ -5,50 +5,42 @@
import os import os
import subprocess import subprocess
import sys import sys
from util import rmtree, run
from util import DenoTestCase, mkdtemp, rmtree, run, test_main
def deno_dir_test(deno_exe, deno_dir): class TestDenoDir(DenoTestCase):
assert os.path.isfile(deno_exe) def setUp(self):
self.old_deno_dir = None
old_deno_dir = None
if "DENO_DIR" in os.environ: if "DENO_DIR" in os.environ:
old_deno_dir = os.environ["DENO_DIR"] self.old_deno_dir = os.environ["DENO_DIR"]
del os.environ["DENO_DIR"] del os.environ["DENO_DIR"]
def tearDown(self):
if self.old_deno_dir is not None:
os.environ["DENO_DIR"] = self.old_deno_dir
def test_deno_dir(self):
deno_dir = mkdtemp()
if os.path.isdir(deno_dir): if os.path.isdir(deno_dir):
rmtree(deno_dir) rmtree(deno_dir)
# Run deno with no env flag # Run deno with no env flag
run_deno(deno_exe) self.run_deno()
assert not os.path.isdir(deno_dir) assert not os.path.isdir(deno_dir)
# Run deno with DENO_DIR env flag # Run deno with DENO_DIR env flag
run_deno(deno_exe, deno_dir) self.run_deno(deno_dir)
assert os.path.isdir(deno_dir) assert os.path.isdir(deno_dir)
assert os.path.isdir(os.path.join(deno_dir, "deps")) assert os.path.isdir(os.path.join(deno_dir, "deps"))
assert os.path.isdir(os.path.join(deno_dir, "gen")) assert os.path.isdir(os.path.join(deno_dir, "gen"))
rmtree(deno_dir) rmtree(deno_dir)
if old_deno_dir is not None: def run_deno(self, deno_dir=None):
os.environ["DENO_DIR"] = old_deno_dir cmd = [self.deno_exe, "run", "tests/002_hello.ts"]
def run_deno(deno_exe, deno_dir=None):
cmd = [deno_exe, "run", "tests/002_hello.ts"]
deno_dir_env = {"DENO_DIR": deno_dir} if deno_dir is not None else None deno_dir_env = {"DENO_DIR": deno_dir} if deno_dir is not None else None
run(cmd, quiet=True, env=deno_dir_env) run(cmd, quiet=True, env=deno_dir_env)
USAGE = "./tools/deno_dir_test.py target/debug/deno target/debug/.deno_dir"
def main(argv):
if len(sys.argv) != 3:
print "Usage: " + USAGE
sys.exit(1)
deno_dir_test(argv[1], argv[2])
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(main(sys.argv)) test_main()

View file

@ -2,29 +2,29 @@
# Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. # Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import os import os
import sys import sys
from util import mkdtemp, tests_path, run_output, green_ok
import shutil import shutil
from http_server import spawn
from util import DenoTestCase, mkdtemp, tests_path, run_output, test_main
def fetch_test(deno_exe):
sys.stdout.write("fetch_test...")
sys.stdout.flush()
class FetchTest(DenoTestCase):
def test_fetch(self):
deno_dir = mkdtemp() deno_dir = mkdtemp()
try: try:
t = os.path.join(tests_path, "006_url_imports.ts") t = os.path.join(tests_path, "006_url_imports.ts")
output = run_output([deno_exe, "fetch", t], output = run_output([self.deno_exe, "fetch", t],
merge_env={"DENO_DIR": deno_dir}) merge_env={"DENO_DIR": deno_dir})
assert output == "" assert output == ""
# Check that we actually did the prefetch. # Check that we actually did the prefetch.
os.path.exists( os.path.exists(
os.path.join(deno_dir, os.path.join(
deno_dir,
"deps/http/localhost_PORT4545/tests/subdir/mod2.ts")) "deps/http/localhost_PORT4545/tests/subdir/mod2.ts"))
finally: finally:
shutil.rmtree(deno_dir) shutil.rmtree(deno_dir)
print green_ok()
if __name__ == "__main__": if __name__ == "__main__":
fetch_test(sys.argv[1]) with spawn():
test_main()

View file

@ -1,47 +1,46 @@
#!/usr/bin/env python #!/usr/bin/env python
# Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. # Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import os
import sys
from util import mkdtemp, root_path, tests_path, run, green_ok
import shutil
import json import json
import os
import shutil
import sys
from util import (DenoTestCase, mkdtemp, root_path, tests_path, run, test_main)
def fmt_test(deno_exe): class FmtTest(DenoTestCase):
sys.stdout.write("fmt_test...") def test_fmt(self):
sys.stdout.flush()
d = mkdtemp() d = mkdtemp()
try: try:
fixed_filename = os.path.join(tests_path, "badly_formatted_fixed.js") fixed_filename = os.path.join(tests_path,
"badly_formatted_fixed.js")
src = os.path.join(tests_path, "badly_formatted.js") src = os.path.join(tests_path, "badly_formatted.js")
dst = os.path.join(d, "badly_formatted.js") dst = os.path.join(d, "badly_formatted.js")
shutil.copyfile(src, dst) shutil.copyfile(src, dst)
# Set DENO_DIR to the temp dir so we test an initial fetch of prettier.
# Set DENO_DIR to the temp dir to test an initial fetch of prettier.
# TODO(ry) This make the test depend on internet access which is not # TODO(ry) This make the test depend on internet access which is not
# ideal. We should have prettier in the repo already, and we could # ideal. We should have prettier in the repo already, and we could
# fetch it instead through tools/http_server.py. # fetch it instead through tools/http_server.py.
deno_dir = d deno_dir = d
# TODO(kt3k) The below line should be run([deno_exe, "fmt", dst], ...) # TODO(kt3k) Below can be run([deno_exe, "fmt", dst], ...)
# It should be updated when the below issue is addressed # once the following issue is addressed:
# https://github.com/denoland/deno_std/issues/330 # https://github.com/denoland/deno_std/issues/330
run([os.path.join(root_path, deno_exe), "fmt", "badly_formatted.js"], run([
os.path.join(root_path, self.deno_exe), "fmt",
"badly_formatted.js"
],
cwd=d, cwd=d,
merge_env={"DENO_DIR": deno_dir}) merge_env={"DENO_DIR": deno_dir})
with open(fixed_filename) as f: with open(fixed_filename) as f:
expected = f.read() expected = f.read()
with open(dst) as f: with open(dst) as f:
actual = f.read() actual = f.read()
if expected != actual: self.assertEqual(expected, actual)
print "Expected didn't match actual."
print "expected: ", json.dumps(expected)
print "actual: ", json.dumps(actual)
sys.exit(1)
finally: finally:
shutil.rmtree(d) shutil.rmtree(d)
print green_ok()
if __name__ == "__main__": if __name__ == "__main__":
fmt_test(sys.argv[1]) test_main()

View file

@ -2,13 +2,15 @@
# Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. # Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
# Many tests expect there to be an http server on port 4545 servering the deno # Many tests expect there to be an http server on port 4545 servering the deno
# root directory. # root directory.
from collections import namedtuple
from contextlib import contextmanager
import os import os
import sys
from threading import Thread
import SimpleHTTPServer import SimpleHTTPServer
import SocketServer import SocketServer
from util import root_path import sys
from time import sleep from time import sleep
from threading import Thread
from util import root_path
PORT = 4545 PORT = 4545
REDIRECT_PORT = 4546 REDIRECT_PORT = 4546
@ -87,6 +89,9 @@ class ContentTypeHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
return SimpleHTTPServer.SimpleHTTPRequestHandler.guess_type(self, path) return SimpleHTTPServer.SimpleHTTPRequestHandler.guess_type(self, path)
RunningServer = namedtuple("RunningServer", ["server", "thread"])
def server(): def server():
os.chdir(root_path) # Hopefully the main thread doesn't also chdir. os.chdir(root_path) # Hopefully the main thread doesn't also chdir.
Handler = ContentTypeHandler Handler = ContentTypeHandler
@ -98,7 +103,7 @@ def server():
SocketServer.TCPServer.allow_reuse_address = True SocketServer.TCPServer.allow_reuse_address = True
s = SocketServer.TCPServer(("", PORT), Handler) s = SocketServer.TCPServer(("", PORT), Handler)
print "Deno test server http://localhost:%d/" % PORT print "Deno test server http://localhost:%d/" % PORT
return s return RunningServer(s, start(s))
def base_redirect_server(host_port, target_port, extra_path_segment=""): def base_redirect_server(host_port, target_port, extra_path_segment=""):
@ -117,7 +122,7 @@ def base_redirect_server(host_port, target_port, extra_path_segment=""):
s = SocketServer.TCPServer(("", host_port), Handler) s = SocketServer.TCPServer(("", host_port), Handler)
print "redirect server http://localhost:%d/ -> http://localhost:%d/" % ( print "redirect server http://localhost:%d/ -> http://localhost:%d/" % (
host_port, target_port) host_port, target_port)
return s return RunningServer(s, start(s))
# redirect server # redirect server
@ -137,35 +142,30 @@ def double_redirects_server():
return base_redirect_server(DOUBLE_REDIRECTS_PORT, REDIRECT_PORT) return base_redirect_server(DOUBLE_REDIRECTS_PORT, REDIRECT_PORT)
def spawn(): def start(s):
# Main http server thread = Thread(target=s.serve_forever, kwargs={"poll_interval": 0.05})
s = server()
thread = Thread(target=s.serve_forever)
thread.daemon = True thread.daemon = True
thread.start() thread.start()
# Redirect server
rs = redirect_server()
r_thread = Thread(target=rs.serve_forever)
r_thread.daemon = True
r_thread.start()
# Another redirect server
ars = another_redirect_server()
ar_thread = Thread(target=ars.serve_forever)
ar_thread.daemon = True
ar_thread.start()
# Double redirects server
drs = double_redirects_server()
dr_thread = Thread(target=drs.serve_forever)
dr_thread.daemon = True
dr_thread.start()
sleep(1) # TODO I'm too lazy to figure out how to do this properly.
return thread return thread
def main(): @contextmanager
def spawn():
servers = (server(), redirect_server(), another_redirect_server(),
double_redirects_server())
sleep(1) # TODO I'm too lazy to figure out how to do this properly.
try: try:
thread = spawn() yield
while thread.is_alive(): finally:
for s in servers:
s.server.shutdown()
def main():
servers = (server(), redirect_server(), another_redirect_server(),
double_redirects_server())
try:
while all(s.thread.is_alive() for s in servers):
sleep(10) sleep(10)
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass

View file

@ -7,14 +7,16 @@
# exit code can be specified. # exit code can be specified.
# #
# Usage: integration_tests.py [path to deno executable] # Usage: integration_tests.py [path to deno executable]
import argparse
import os import os
import re import re
import sys import sys
import subprocess import subprocess
import http_server import unittest
import argparse
from util import root_path, tests_path, pattern_match, \ from http_server import spawn
green_ok, red_failed, rmtree, executable_suffix from util import (DenoTestCase, ColorTextTestRunner, root_path, tests_path,
pattern_match, rmtree, test_main)
def strip_ansi_codes(s): def strip_ansi_codes(s):
@ -45,38 +47,29 @@ def str2bool(v):
raise ValueError("Bad boolean value") raise ValueError("Bad boolean value")
def integration_tests(deno_exe, test_filter=None): class TestIntegrations(DenoTestCase):
assert os.path.isfile(deno_exe) @classmethod
tests = sorted([ def _test(cls, test_filename):
filename for filename in os.listdir(tests_path) # Return thunk to test for js file,
if filename.endswith(".test") # This is to 'trick' unittest so as to generate these dynamically.
]) return lambda self: self.generate(test_filename)
assert len(tests) > 0
for test_filename in tests:
if test_filter and test_filter not in test_filename:
continue
def generate(self, test_filename):
test_abs = os.path.join(tests_path, test_filename) test_abs = os.path.join(tests_path, test_filename)
test = read_test(test_abs) test = read_test(test_abs)
exit_code = int(test.get("exit_code", 0)) exit_code = int(test.get("exit_code", 0))
args = test.get("args", "").split(" ") args = test.get("args", "").split(" ")
check_stderr = str2bool(test.get("check_stderr", "false")) check_stderr = str2bool(test.get("check_stderr", "false"))
stderr = subprocess.STDOUT if check_stderr else open(os.devnull, 'w') stderr = subprocess.STDOUT if check_stderr else open(os.devnull, 'w')
stdin_input = (test.get("input", stdin_input = (test.get("input",
"").strip().decode("string_escape").replace( "").strip().decode("string_escape").replace(
"\r\n", "\n")) "\r\n", "\n"))
has_stdin_input = len(stdin_input) > 0 has_stdin_input = len(stdin_input) > 0
output_abs = os.path.join(root_path, test.get("output", "")) output_abs = os.path.join(root_path, test.get("output", ""))
with open(output_abs, 'r') as f: with open(output_abs, 'r') as f:
expected_out = f.read() expected_out = f.read()
cmd = [deno_exe] + args cmd = [self.deno_exe] + args
sys.stdout.write("tests/%s ... " % (test_filename))
sys.stdout.flush()
actual_code = 0 actual_code = 0
try: try:
if has_stdin_input: if has_stdin_input:
@ -97,23 +90,22 @@ def integration_tests(deno_exe, test_filter=None):
actual_code = e.returncode actual_code = e.returncode
actual_out = e.output actual_out = e.output
if exit_code != actual_code: self.assertEqual(exit_code, actual_code)
print "... " + red_failed()
print "Expected exit code %d but got %d" % (exit_code, actual_code)
print "Output:"
print actual_out
sys.exit(1)
actual_out = strip_ansi_codes(actual_out) actual_out = strip_ansi_codes(actual_out)
if not pattern_match(expected_out, actual_out):
# This will always throw since pattern_match failed.
self.assertEqual(expected_out, actual_out)
if pattern_match(expected_out, actual_out) != True:
print red_failed()
print "Expected output does not match actual."
print "Expected output: \n" + expected_out
print "Actual output: \n" + actual_out
sys.exit(1)
print green_ok() # Add a methods for each test file in tests_path.
for fn in sorted(
filename for filename in os.listdir(tests_path)
if filename.endswith(".test")):
t = TestIntegrations._test(fn)
tn = t.__name__ = "test_" + fn.split(".")[0]
setattr(TestIntegrations, tn, t)
def main(): def main():
@ -125,26 +117,26 @@ def main():
args = parser.parse_args() args = parser.parse_args()
target = "release" if args.release else "debug" target = "release" if args.release else "debug"
build_dir = os.environ.get("DENO_BUILD_PATH",
build_dir = None os.path.join(root_path, "target", target))
if "DENO_BUILD_PATH" in os.environ:
build_dir = os.environ["DENO_BUILD_PATH"]
else:
build_dir = os.path.join(root_path, "target", target)
deno_dir = os.path.join(build_dir, ".deno_test") deno_dir = os.path.join(build_dir, ".deno_test")
if os.path.isdir(deno_dir): if os.path.isdir(deno_dir):
rmtree(deno_dir) rmtree(deno_dir)
os.environ["DENO_DIR"] = deno_dir os.environ["DENO_DIR"] = deno_dir
deno_exe = os.path.join(build_dir, "deno" + executable_suffix) test_names = [
if args.executable: test_name for test_name in unittest.TestLoader().getTestCaseNames(
deno_exe = args.executable TestIntegrations) if not args.filter or args.filter in test_name
]
suite = unittest.TestLoader().loadTestsFromNames(
test_names, module=TestIntegrations)
http_server.spawn() with spawn():
result = ColorTextTestRunner(verbosity=2).run(suite)
integration_tests(deno_exe, args.filter) if not result.wasSuccessful():
sys.exit(1)
if __name__ == "__main__": if __name__ == "__main__":
sys.exit(main()) main()

View file

@ -1,27 +1,23 @@
#!/usr/bin/env python #!/usr/bin/env python
# Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. # Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import os import os
import pty
import select
import subprocess import subprocess
from util import build_path, executable_suffix import unittest
from sys import stdin from sys import stdin
from permission_prompt_test import tty_capture
from util import DenoTestCase, test_main, tty_capture
IS_TTY_TEST_TS = "tests/is_tty.ts" IS_TTY_TEST_TS = "tests/is_tty.ts"
def is_tty_test(deno_exe): @unittest.skipIf(os.name == 'nt', "Unable to test tty on Windows")
cmd = [deno_exe, "run", IS_TTY_TEST_TS] class TestIsTty(DenoTestCase):
def test_is_tty(self):
cmd = [self.deno_exe, "run", IS_TTY_TEST_TS]
code, stdout, _ = tty_capture(cmd, b'') code, stdout, _ = tty_capture(cmd, b'')
assert code == 0 assert code == 0
assert str(stdin.isatty()).lower() in stdout assert str(stdin.isatty()).lower() in stdout
def main():
deno_exe = os.path.join(build_path(), "deno" + executable_suffix)
is_tty_test(deno_exe)
if __name__ == "__main__": if __name__ == "__main__":
main() test_main()

View file

@ -2,14 +2,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. # Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import os import os
import pty
import select
import subprocess import subprocess
import sys import sys
import time import time
import unittest import unittest
from util import build_path, executable_suffix, green_ok, red_failed from util import DenoTestCase, test_main, tty_capture
PERMISSIONS_PROMPT_TEST_TS = "tools/permission_prompt_test.ts" PERMISSIONS_PROMPT_TEST_TS = "tools/permission_prompt_test.ts"
@ -18,47 +16,8 @@ FIRST_CHECK_FAILED_PATTERN = b'First check failed'
PERMISSION_DENIED_PATTERN = b'PermissionDenied: permission denied' PERMISSION_DENIED_PATTERN = b'PermissionDenied: permission denied'
# This function is copied from: @unittest.skipIf(os.name == 'nt', "Unable to test tty on Windows")
# https://gist.github.com/hayd/4f46a68fc697ba8888a7b517a414583e class BasePromptTest(object):
# https://stackoverflow.com/q/52954248/1240268
def tty_capture(cmd, bytes_input, timeout=5):
"""Capture the output of cmd with bytes_input to stdin,
with stdin, stdout and stderr as TTYs."""
mo, so = pty.openpty() # provide tty to enable line-buffering
me, se = pty.openpty()
mi, si = pty.openpty()
fdmap = {mo: 'stdout', me: 'stderr', mi: 'stdin'}
timeout_exact = time.time() + timeout
p = subprocess.Popen(
cmd, bufsize=1, stdin=si, stdout=so, stderr=se, close_fds=True)
os.write(mi, bytes_input)
select_timeout = .04 #seconds
res = {'stdout': b'', 'stderr': b''}
while True:
ready, _, _ = select.select([mo, me], [], [], select_timeout)
if ready:
for fd in ready:
data = os.read(fd, 512)
if not data:
break
res[fdmap[fd]] += data
elif p.poll() is not None or time.time(
) > timeout_exact: # select timed-out
break # p exited
for fd in [si, so, se, mi, mo, me]:
os.close(fd) # can't do it sooner: it leads to errno.EIO error
p.wait()
return p.returncode, res['stdout'], res['stderr']
class TestPrompt(unittest.TestCase):
def __init__(self, method_name, test_type, deno_exe):
super(TestPrompt, self).__init__(method_name)
self.test_type = test_type
self.deno_exe = deno_exe
def _run_deno(self, flags, args, bytes_input): def _run_deno(self, flags, args, bytes_input):
"Returns (return_code, stdout, stderr)." "Returns (return_code, stdout, stderr)."
cmd = [self.deno_exe, "run"] + flags + [PERMISSIONS_PROMPT_TEST_TS cmd = [self.deno_exe, "run"] + flags + [PERMISSIONS_PROMPT_TEST_TS
@ -159,27 +118,29 @@ class TestPrompt(unittest.TestCase):
assert not PERMISSION_DENIED_PATTERN in stderr assert not PERMISSION_DENIED_PATTERN in stderr
def permission_prompt_test(deno_exe): class ReadPromptTest(DenoTestCase, BasePromptTest):
runner = unittest.TextTestRunner(verbosity=2) test_type = "read"
loader = unittest.TestLoader()
test_types = ["read", "write", "env", "net", "run"]
for test_type in test_types:
print "Permissions prompt tests for \"{}\"".format(test_type)
test_names = loader.getTestCaseNames(TestPrompt)
suite = unittest.TestSuite()
for test_name in test_names:
suite.addTest(TestPrompt(test_name, test_type, deno_exe))
result = runner.run(suite)
if not result.wasSuccessful():
sys.exit(1)
def main(): class WritePromptTest(DenoTestCase, BasePromptTest):
deno_exe = os.path.join(build_path(), "deno" + executable_suffix) test_type = "write"
permission_prompt_test(deno_exe)
class EnvPromptTest(DenoTestCase, BasePromptTest):
test_type = "env"
class NetPromptTest(DenoTestCase, BasePromptTest):
test_type = "net"
class RunPromptTest(DenoTestCase, BasePromptTest):
test_type = "run"
def permission_prompt_tests():
return BasePromptTest.__subclasses__()
if __name__ == "__main__": if __name__ == "__main__":
main() test_main()

View file

@ -4,12 +4,12 @@ from subprocess import CalledProcessError, PIPE, Popen
import sys import sys
import time import time
from util import build_path, executable_suffix, green_ok from util import DenoTestCase, test_main
class Repl(object): class TestRepl(DenoTestCase):
def __init__(self, deno_exe): def __init__(self, *args, **kwargs):
self.deno_exe = deno_exe super(TestRepl, self).__init__(*args, **kwargs)
self._warm_up() self._warm_up()
def _warm_up(self): def _warm_up(self):
@ -40,26 +40,17 @@ class Repl(object):
# Ignore Windows CRLF (\r\n). # Ignore Windows CRLF (\r\n).
return out.replace('\r\n', '\n'), err.replace('\r\n', '\n'), retcode return out.replace('\r\n', '\n'), err.replace('\r\n', '\n'), retcode
def run(self):
print('repl_test.py')
test_names = [name for name in dir(self) if name.startswith("test_")]
for t in test_names:
self.__getattribute__(t)()
sys.stdout.write(".")
sys.stdout.flush()
print(' {}\n'.format(green_ok()))
def test_console_log(self): def test_console_log(self):
out, err, code = self.input("console.log('hello')", "'world'") out, err, code = self.input("console.log('hello')", "'world'")
assertEqual(out, 'hello\nundefined\nworld\n') self.assertEqual(out, 'hello\nundefined\nworld\n')
assertEqual(err, '') self.assertEqual(err, '')
assertEqual(code, 0) self.assertEqual(code, 0)
def test_exit_command(self): def test_exit_command(self):
out, err, code = self.input("exit", "'ignored'", exit=False) out, err, code = self.input("exit", "'ignored'", exit=False)
assertEqual(out, '') self.assertEqual(out, '')
assertEqual(err, '') self.assertEqual(err, '')
assertEqual(code, 0) self.assertEqual(code, 0)
def test_help_command(self): def test_help_command(self):
out, err, code = self.input("help") out, err, code = self.input("help")
@ -68,100 +59,86 @@ class Repl(object):
"help Print this help message", "help Print this help message",
"", "",
]) ])
assertEqual(out, expectedOut) self.assertEqual(out, expectedOut)
assertEqual(err, '') self.assertEqual(err, '')
assertEqual(code, 0) self.assertEqual(code, 0)
def test_function(self): def test_function(self):
out, err, code = self.input("Deno.writeFileSync") out, err, code = self.input("Deno.writeFileSync")
assertEqual(out, '[Function: writeFileSync]\n') self.assertEqual(out, '[Function: writeFileSync]\n')
assertEqual(err, '') self.assertEqual(err, '')
assertEqual(code, 0) self.assertEqual(code, 0)
def test_multiline(self): def test_multiline(self):
out, err, code = self.input("(\n1 + 2\n)") out, err, code = self.input("(\n1 + 2\n)")
assertEqual(out, '3\n') self.assertEqual(out, '3\n')
assertEqual(err, '') self.assertEqual(err, '')
assertEqual(code, 0) self.assertEqual(code, 0)
# This should print error instead of wait for input # This should print error instead of wait for input
def test_eval_unterminated(self): def test_eval_unterminated(self):
out, err, code = self.input("eval('{')") out, err, code = self.input("eval('{')")
assertEqual(out, '') self.assertEqual(out, '')
assert "Unexpected end of input" in err assert "Unexpected end of input" in err
assertEqual(code, 0) self.assertEqual(code, 0)
def test_reference_error(self): def test_reference_error(self):
out, err, code = self.input("not_a_variable") out, err, code = self.input("not_a_variable")
assertEqual(out, '') self.assertEqual(out, '')
assert "not_a_variable is not defined" in err assert "not_a_variable is not defined" in err
assertEqual(code, 0) self.assertEqual(code, 0)
# def test_set_timeout(self): # def test_set_timeout(self):
# out, err, code = self.input( # out, err, code = self.input(
# "setTimeout(() => { console.log('b'); Deno.exit(0); }, 1)", # "setTimeout(() => { console.log('b'); Deno.exit(0); }, 1)",
# "'a'", # "'a'",
# exit=False) # exit=False)
# assertEqual(out, '1\na\nb\n') # self.assertEqual(out, '1\na\nb\n')
# assertEqual(err, '') # self.assertEqual(err, '')
# assertEqual(code, 0) # self.assertEqual(code, 0)
# def test_set_timeout_interlaced(self): # def test_set_timeout_interlaced(self):
# out, err, code = self.input( # out, err, code = self.input(
# "setTimeout(() => console.log('a'), 1)", # "setTimeout(() => console.log('a'), 1)",
# "setTimeout(() => console.log('b'), 6)", # "setTimeout(() => console.log('b'), 6)",
# sleep=0.8) # sleep=0.8)
# assertEqual(out, '1\n2\na\nb\n') # self.assertEqual(out, '1\n2\na\nb\n')
# assertEqual(err, '') # self.assertEqual(err, '')
# assertEqual(code, 0) # self.assertEqual(code, 0)
# def test_async_op(self): # def test_async_op(self):
# out, err, code = self.input( # out, err, code = self.input(
# "fetch('http://localhost:4545/tests/001_hello.js')" + # "fetch('http://localhost:4545/tests/001_hello.js')" +
# ".then(res => res.text()).then(console.log)", # ".then(res => res.text()).then(console.log)",
# sleep=1) # sleep=1)
# assertEqual(out, 'Promise {}\nconsole.log("Hello World");\n\n') # self.assertEqual(out, 'Promise {}\nconsole.log("Hello World");\n\n')
# assertEqual(err, '') # self.assertEqual(err, '')
# assertEqual(code, 0) # self.assertEqual(code, 0)
def test_syntax_error(self): def test_syntax_error(self):
out, err, code = self.input("syntax error") out, err, code = self.input("syntax error")
assertEqual(out, '') self.assertEqual(out, '')
assert "Unexpected identifier" in err assert "Unexpected identifier" in err
assertEqual(code, 0) self.assertEqual(code, 0)
def test_type_error(self): def test_type_error(self):
out, err, code = self.input("console()") out, err, code = self.input("console()")
assertEqual(out, '') self.assertEqual(out, '')
assert "console is not a function" in err assert "console is not a function" in err
assertEqual(code, 0) self.assertEqual(code, 0)
def test_variable(self): def test_variable(self):
out, err, code = self.input("var a = 123;", "a") out, err, code = self.input("var a = 123;", "a")
assertEqual(out, 'undefined\n123\n') self.assertEqual(out, 'undefined\n123\n')
assertEqual(err, '') self.assertEqual(err, '')
assertEqual(code, 0) self.assertEqual(code, 0)
def test_lexical_scoped_variable(self): def test_lexical_scoped_variable(self):
out, err, code = self.input("let a = 123;", "a") out, err, code = self.input("let a = 123;", "a")
assertEqual(out, 'undefined\n123\n') self.assertEqual(out, 'undefined\n123\n')
assertEqual(err, '') self.assertEqual(err, '')
assertEqual(code, 0) self.assertEqual(code, 0)
def assertEqual(left, right):
if left != right:
raise AssertionError("{} != {}".format(repr(left), repr(right)))
def repl_tests(deno_exe):
Repl(deno_exe).run()
def main():
deno_exe = os.path.join(build_path(), "deno" + executable_suffix)
repl_tests(deno_exe)
if __name__ == "__main__": if __name__ == "__main__":
main() test_main()

View file

@ -1,14 +1,15 @@
# Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. # Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import os import os
import sys import sys
import unittest
from setup import gn_string, read_gn_args, write_gn_args from setup import gn_string, read_gn_args, write_gn_args
from shutil import rmtree from shutil import rmtree
from tempfile import mktemp from tempfile import mktemp
from util import DenoTestCase, test_main
class TestSetup(unittest.TestCase):
class TestSetup(DenoTestCase):
def test_gn_string(self): def test_gn_string(self):
assert '"abc"' == gn_string('abc') assert '"abc"' == gn_string('abc')
assert '"foo\\$bar\\"baz"' == gn_string('foo$bar"baz') assert '"foo\\$bar\\"baz"' == gn_string('foo$bar"baz')
@ -61,12 +62,5 @@ class TestSetup(unittest.TestCase):
rmtree(d) rmtree(d)
def setup_test():
suite = unittest.TestLoader().loadTestsFromTestCase(TestSetup)
result = unittest.TextTestRunner(verbosity=2).run(suite)
if not result.wasSuccessful():
sys.exit(1)
if __name__ == '__main__': if __name__ == '__main__':
setup_test() test_main()

View file

@ -3,127 +3,122 @@
# Runs the full test suite. # Runs the full test suite.
# Usage: ./tools/test.py out/Debug # Usage: ./tools/test.py out/Debug
import os import os
import subprocess
import sys import sys
import unittest import unittest
from integration_tests import integration_tests from benchmark_test import TestBenchmark
from deno_dir_test import deno_dir_test from deno_dir_test import TestDenoDir
from util import build_path, enable_ansi_colors, executable_suffix, run, rmtree from fetch_test import FetchTest
from util import run_output, tests_path, green_ok from fmt_test import FmtTest
from unit_tests import unit_tests from integration_tests import TestIntegrations
from util_test import util_test from repl_test import TestRepl
from setup_test import setup_test from setup_test import TestSetup
from benchmark_test import benchmark_test from unit_tests import JsUnitTests
from repl_test import repl_tests from util_test import TestUtil
from fetch_test import fetch_test
from fmt_test import fmt_test from is_tty_test import TestIsTty
import subprocess # NOTE: These tests are skipped on Windows
import http_server from permission_prompt_test import permission_prompt_tests
from complex_permissions_test import complex_permissions_tests
from http_server import spawn
from util import (DenoTestCase, ColorTextTestRunner, enable_ansi_colors,
executable_suffix, run, run_output, rmtree, tests_path,
test_args)
def check_exists(filename): class TestTarget(DenoTestCase):
@staticmethod
def check_exists(filename):
if not os.path.exists(filename): if not os.path.exists(filename):
print "Required target doesn't exist:", filename print "Required target doesn't exist:", filename
print "Run ./tools/build.py" print "Run ./tools/build.py"
sys.exit(1) sys.exit(1)
def test_executable_exists(self):
self.check_exists(self.deno_exe)
def test_no_color(deno_exe): def _test(self, executable):
sys.stdout.write("no_color test...") "Test executable runs and exits with code 0."
sys.stdout.flush() bin_file = os.path.join(self.build_dir, executable + executable_suffix)
t = os.path.join(tests_path, "no_color.js") self.check_exists(bin_file)
output = run_output([deno_exe, "run", t], merge_env={"NO_COLOR": "1"}) run([bin_file])
assert output.strip() == "noColor true"
t = os.path.join(tests_path, "no_color.js")
output = run_output([deno_exe, "run", t])
assert output.strip() == "noColor false"
print green_ok()
def test_libdeno(self):
self._test("libdeno_test")
def exec_path_test(deno_exe): def test_cli(self):
cmd = [deno_exe, "run", "tests/exec_path.ts"] self._test("cli_test")
output = run_output(cmd)
assert deno_exe in output.strip()
def test_core(self):
self._test("deno_core_test")
def main(argv): def test_core_http_benchmark(self):
if len(argv) == 2: self._test("deno_core_http_bench_test")
build_dir = sys.argv[1]
elif len(argv) == 1:
build_dir = build_path()
else:
print "Usage: tools/test.py [build_dir]"
sys.exit(1)
deno_dir = os.path.join(build_dir, ".deno_test")
if os.path.isdir(deno_dir):
rmtree(deno_dir)
os.environ["DENO_DIR"] = deno_dir
enable_ansi_colors()
http_server.spawn()
deno_exe = os.path.join(build_dir, "deno" + executable_suffix)
check_exists(deno_exe)
# Python/build tools testing
setup_test()
util_test()
def test_ts_library_builder(self):
run([ run([
"node", "./node_modules/.bin/ts-node", "--project", "node", "./node_modules/.bin/ts-node", "--project",
"tools/ts_library_builder/tsconfig.json", "tools/ts_library_builder/tsconfig.json",
"tools/ts_library_builder/test.ts" "tools/ts_library_builder/test.ts"
]) ])
libdeno_test = os.path.join(build_dir, "libdeno_test" + executable_suffix) def test_no_color(self):
check_exists(libdeno_test) t = os.path.join(tests_path, "no_color.js")
run([libdeno_test]) output = run_output([self.deno_exe, "run", t],
merge_env={"NO_COLOR": "1"})
assert output.strip() == "noColor true"
t = os.path.join(tests_path, "no_color.js")
output = run_output([self.deno_exe, "run", t])
assert output.strip() == "noColor false"
cli_test = os.path.join(build_dir, "cli_test" + executable_suffix) def test_exec_path(self):
check_exists(cli_test) cmd = [self.deno_exe, "run", "tests/exec_path.ts"]
run([cli_test]) output = run_output(cmd)
assert self.deno_exe in output.strip()
deno_core_test = os.path.join(build_dir,
"deno_core_test" + executable_suffix)
check_exists(deno_core_test)
run([deno_core_test])
deno_core_http_bench_test = os.path.join( def main(argv):
build_dir, "deno_core_http_bench_test" + executable_suffix) args = test_args(argv)
check_exists(deno_core_http_bench_test)
run([deno_core_http_bench_test])
unit_tests(deno_exe)
fetch_test(deno_exe)
fmt_test(deno_exe)
integration_tests(deno_exe)
# TODO We currently skip testing the prompt and IsTTY in Windows completely.
# Windows does not support the pty module used for testing the permission
# prompt.
if os.name != 'nt':
from is_tty_test import is_tty_test
from permission_prompt_test import permission_prompt_test
from complex_permissions_test import complex_permissions_test
permission_prompt_test(deno_exe)
complex_permissions_test(deno_exe)
is_tty_test(deno_exe)
repl_tests(deno_exe)
deno_dir = os.path.join(args.build_dir, ".deno_test")
if os.path.isdir(deno_dir):
rmtree(deno_dir) rmtree(deno_dir)
os.environ["DENO_DIR"] = deno_dir
deno_dir_test(deno_exe, deno_dir) enable_ansi_colors()
test_no_color(deno_exe) with spawn():
test_cases = [
TestSetup,
TestUtil,
TestTarget,
JsUnitTests,
FetchTest,
FmtTest,
TestIntegrations,
TestRepl,
TestDenoDir,
TestBenchmark,
]
# These tests are skipped, but to make the test output less noisy
# we'll avoid triggering them.
if os.name != 'nt':
test_cases.append(TestIsTty)
test_cases += permission_prompt_tests()
test_cases += complex_permissions_tests()
benchmark_test(build_dir, deno_exe) suite = unittest.TestSuite([
exec_path_test(deno_exe) unittest.TestLoader().loadTestsFromTestCase(tc)
for tc in test_cases
])
result = ColorTextTestRunner(
verbosity=args.verbosity + 1, failfast=args.failfast).run(suite)
if not result.wasSuccessful():
sys.exit(1)
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(main(sys.argv)) main(sys.argv[1:])

View file

@ -2,12 +2,16 @@
# Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. # Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import sys import sys
import subprocess import subprocess
import http_server
from http_server import spawn
from util import DenoTestCase, test_main
def unit_tests(deno_exe): class JsUnitTests(DenoTestCase):
def test_unit_test_runner(self):
cmd = [ cmd = [
deno_exe, "run", "--reload", "--allow-run", "js/unit_test_runner.ts" self.deno_exe, "run", "--reload", "--allow-run",
"js/unit_test_runner.ts"
] ]
process = subprocess.Popen( process = subprocess.Popen(
cmd, bufsize=1, universal_newlines=True, stderr=subprocess.STDOUT) cmd, bufsize=1, universal_newlines=True, stderr=subprocess.STDOUT)
@ -15,13 +19,10 @@ def unit_tests(deno_exe):
process.wait() process.wait()
errcode = process.returncode errcode = process.returncode
if errcode != 0: if errcode != 0:
sys.exit(errcode) raise AssertionError(
"js/unit_test_runner.ts exited with exit code %s" % errcode)
if __name__ == '__main__': if __name__ == '__main__':
if len(sys.argv) < 2: with spawn():
print "Usage ./tools/unit_tests.py target/debug/deno" test_main()
sys.exit(1)
http_server.spawn()
unit_tests(sys.argv[1])

View file

@ -1,12 +1,17 @@
# Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. # Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import argparse
import os import os
import re import re
import shutil import shutil
import select
import stat import stat
import sys import sys
import subprocess import subprocess
import tempfile import tempfile
import time
import unittest
# FIXME support nocolor (use "" if passed?)
RESET = "\x1b[0m" RESET = "\x1b[0m"
FG_RED = "\x1b[31m" FG_RED = "\x1b[31m"
FG_GREEN = "\x1b[32m" FG_GREEN = "\x1b[32m"
@ -85,14 +90,6 @@ def shell_quote(arg):
return quote(arg) return quote(arg)
def red_failed():
return "%sFAILED%s" % (FG_RED, RESET)
def green_ok():
return "%sok%s" % (FG_GREEN, RESET)
def symlink(target, name, target_is_dir=False): def symlink(target, name, target_is_dir=False):
if os.name == "nt": if os.name == "nt":
from ctypes import WinDLL, WinError, GetLastError from ctypes import WinDLL, WinError, GetLastError
@ -176,6 +173,8 @@ def rmtree(directory):
def build_mode(default="debug"): def build_mode(default="debug"):
if "DENO_BUILD_MODE" in os.environ: if "DENO_BUILD_MODE" in os.environ:
return os.environ["DENO_BUILD_MODE"] return os.environ["DENO_BUILD_MODE"]
elif "--release" in sys.argv:
return "release"
else: else:
return default return default
@ -191,8 +190,6 @@ def build_path():
# Returns True if the expected matches the actual output, allowing variation # Returns True if the expected matches the actual output, allowing variation
# from actual where expected has the wildcard (e.g. matches /.*/) # from actual where expected has the wildcard (e.g. matches /.*/)
def pattern_match(pattern, string, wildcard="[WILDCARD]"): def pattern_match(pattern, string, wildcard="[WILDCARD]"):
if len(pattern) == 0:
return string == 0
if pattern == wildcard: if pattern == wildcard:
return True return True
@ -374,3 +371,122 @@ def mkdtemp():
# 'TS5009: Cannot find the common subdirectory path for the input files.' # 'TS5009: Cannot find the common subdirectory path for the input files.'
temp_dir = os.environ["TEMP"] if os.name == 'nt' else None temp_dir = os.environ["TEMP"] if os.name == 'nt' else None
return tempfile.mkdtemp(dir=temp_dir) return tempfile.mkdtemp(dir=temp_dir)
class DenoTestCase(unittest.TestCase):
@property
def build_dir(self):
args = test_args()
return args.build_dir
@property
def deno_exe(self):
return os.path.join(self.build_dir, "deno" + executable_suffix)
# overload the test result class
class ColorTextTestResult(unittest.TextTestResult):
def getDescription(self, test):
name = str(test)
if name.startswith("test_"):
name = name[5:]
return name
def addSuccess(self, test):
if self.showAll:
self.stream.write(FG_GREEN)
super(ColorTextTestResult, self).addSuccess(test)
if self.showAll:
self.stream.write(RESET)
def addError(self, test, err):
if self.showAll:
self.stream.write(FG_RED)
super(ColorTextTestResult, self).addError(test, err)
if self.showAll:
self.stream.write(RESET)
def addFailure(self, test, err):
if self.showAll:
self.stream.write(FG_RED)
super(ColorTextTestResult, self).addFailure(test, err)
if self.showAll:
self.stream.write(RESET)
class ColorTextTestRunner(unittest.TextTestRunner):
resultclass = ColorTextTestResult
def test_main():
args = test_args()
# FIXME(hayd) support more of the unittest.main API.
return unittest.main(
verbosity=args.verbosity + 1,
testRunner=ColorTextTestRunner,
failfast=args.failfast,
argv=[''])
def test_args(argv=None):
if argv is None:
argv = sys.argv[1:]
parser = argparse.ArgumentParser()
parser.add_argument(
'--failfast', '-f', action='store_true', help='Stop on first failure')
parser.add_argument(
'--verbosity', '-v', action='store_true', help='Verbose output')
parser.add_argument(
'--release',
action='store_true',
help='Test against release deno_executable')
parser.add_argument('build_dir', nargs='?', help='Deno build directory')
args = parser.parse_args(argv)
if args.build_dir and args.release:
raise argparse.ArgumentError(
None, "build_dir is inferred from --release, cannot provide both")
if not args.build_dir:
args.build_dir = build_path()
if not os.path.isfile(
os.path.join(args.build_dir, "deno" + executable_suffix)):
raise argparse.ArgumentError(None,
"deno executable not found in build_dir")
return args
# This function is copied from:
# https://gist.github.com/hayd/4f46a68fc697ba8888a7b517a414583e
# https://stackoverflow.com/q/52954248/1240268
def tty_capture(cmd, bytes_input, timeout=5):
"""Capture the output of cmd with bytes_input to stdin,
with stdin, stdout and stderr as TTYs."""
# pty is not available on windows, so we import it within this function.
import pty
mo, so = pty.openpty() # provide tty to enable line-buffering
me, se = pty.openpty()
mi, si = pty.openpty()
fdmap = {mo: 'stdout', me: 'stderr', mi: 'stdin'}
timeout_exact = time.time() + timeout
p = subprocess.Popen(
cmd, bufsize=1, stdin=si, stdout=so, stderr=se, close_fds=True)
os.write(mi, bytes_input)
select_timeout = .04 #seconds
res = {'stdout': b'', 'stderr': b''}
while True:
ready, _, _ = select.select([mo, me], [], [], select_timeout)
if ready:
for fd in ready:
data = os.read(fd, 512)
if not data:
break
res[fdmap[fd]] += data
elif p.poll() is not None or time.time(
) > timeout_exact: # select timed-out
break # p exited
for fd in [si, so, se, mi, mo, me]:
os.close(fd) # can't do it sooner: it leads to errno.EIO error
p.wait()
return p.returncode, res['stdout'], res['stderr']

View file

@ -1,18 +1,19 @@
# Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. # Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import os
import sys import sys
import unittest
from util import ( from util import (
DenoTestCase,
pattern_match, pattern_match,
parse_exit_code, parse_exit_code,
shell_quote_win, shell_quote_win,
parse_wrk_output, parse_wrk_output,
root_path, root_path,
test_main,
) )
import os
class TestUtil(unittest.TestCase): class TestUtil(DenoTestCase):
def test_pattern_match(self): def test_pattern_match(self):
# yapf: disable # yapf: disable
fixtures = [("foobarbaz", "foobarbaz", True), fixtures = [("foobarbaz", "foobarbaz", True),
@ -68,12 +69,5 @@ class TestUtil(unittest.TestCase):
assert stats3['max_latency'] == 1630.0 assert stats3['max_latency'] == 1630.0
def util_test():
suite = unittest.TestLoader().loadTestsFromTestCase(TestUtil)
result = unittest.TextTestRunner(verbosity=2).run(suite)
if not result.wasSuccessful():
sys.exit(1)
if __name__ == '__main__': if __name__ == '__main__':
util_test() test_main()