mirror of
https://github.com/theupdateframework/python-tuf
synced 2026-05-24 10:08:28 +00:00
Merge pull request #1104 from MVrachev/silence-log-with-temp-files
Log subproceses stdout and stderr in temp files
This commit is contained in:
commit
fb2eaa5f23
20 changed files with 338 additions and 489 deletions
|
|
@ -48,20 +48,11 @@
|
|||
keyfile = os.path.join('ssl_certs', 'ssl_cert.key')
|
||||
certfile = os.path.join('ssl_certs', 'ssl_cert.crt')
|
||||
|
||||
def _generate_random_port():
|
||||
return random.randint(30000, 45000)
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
try:
|
||||
PORT = int(sys.argv[1])
|
||||
if PORT < 30000 or PORT > 45000:
|
||||
raise ValueError
|
||||
|
||||
except ValueError:
|
||||
PORT = _generate_random_port()
|
||||
PORT = int(sys.argv[1])
|
||||
|
||||
else:
|
||||
PORT = _generate_random_port()
|
||||
PORT = random.randint(30000, 45000)
|
||||
|
||||
if len(sys.argv) > 2:
|
||||
|
||||
|
|
|
|||
|
|
@ -41,20 +41,11 @@
|
|||
|
||||
PORT = 0
|
||||
|
||||
def _port_gen():
|
||||
return random.randint(30000, 45000)
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
try:
|
||||
PORT = int(sys.argv[1])
|
||||
if PORT < 30000 or PORT > 45000:
|
||||
raise ValueError
|
||||
|
||||
except ValueError:
|
||||
PORT = _port_gen()
|
||||
PORT = int(sys.argv[1])
|
||||
|
||||
else:
|
||||
PORT = _port_gen()
|
||||
PORT = random.randint(30000, 45000)
|
||||
|
||||
|
||||
class QuietHTTPRequestHandler(SimpleHTTPRequestHandler):
|
||||
|
|
|
|||
|
|
@ -85,12 +85,6 @@ def do_GET(self):
|
|||
|
||||
|
||||
|
||||
def get_random_port():
|
||||
port = random.randint(30000, 45000)
|
||||
return port
|
||||
|
||||
|
||||
|
||||
def run(port, test_mode):
|
||||
server_address = ('localhost', port)
|
||||
httpd = HTTPServer_Test(server_address, Handler, test_mode)
|
||||
|
|
|
|||
|
|
@ -38,10 +38,8 @@
|
|||
|
||||
import os
|
||||
import tempfile
|
||||
import random
|
||||
import shutil
|
||||
import json
|
||||
import subprocess
|
||||
import logging
|
||||
import unittest
|
||||
import sys
|
||||
|
|
@ -66,8 +64,6 @@ class TestArbitraryPackageAttack(unittest_toolbox.Modified_TestCase):
|
|||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# setUpClass() is called before any of the test cases are executed.
|
||||
|
||||
# Create a temporary directory to store the repository, metadata, and target
|
||||
# files. 'temporary_directory' must be deleted in TearDownModule() so that
|
||||
# temporary files are always removed, even when exceptions occur.
|
||||
|
|
@ -80,32 +76,19 @@ def setUpClass(cls):
|
|||
# the pre-generated metadata files have a specific structure, such
|
||||
# as a delegated role 'targets/role1', three target files, five key files,
|
||||
# etc.
|
||||
cls.SERVER_PORT = random.randint(30000, 45000)
|
||||
command = ['python', 'simple_server.py', str(cls.SERVER_PORT)]
|
||||
cls.server_process = subprocess.Popen(command)
|
||||
logger.info('Server process started.')
|
||||
logger.info('Server process id: ' + str(cls.server_process.pid))
|
||||
logger.info('Serving on port: ' + str(cls.SERVER_PORT))
|
||||
cls.url = 'http://localhost:' + str(cls.SERVER_PORT) + os.path.sep
|
||||
|
||||
utils.wait_for_server('localhost', cls.SERVER_PORT)
|
||||
cls.server_process_handler = utils.TestServerProcess(log=logger)
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
# tearDownModule() is called after all the test cases have run.
|
||||
# http://docs.python.org/2/library/unittest.html#class-and-module-fixtures
|
||||
# Kills the server subprocess and closes the temp file used for logging.
|
||||
cls.server_process_handler.clean()
|
||||
|
||||
# Remove the temporary repository directory, which should contain all the
|
||||
# metadata, targets, and key files generated of all the test cases.
|
||||
shutil.rmtree(cls.temporary_directory)
|
||||
|
||||
# Kill the SimpleHTTPServer process.
|
||||
if cls.server_process.returncode is None:
|
||||
logger.info('Server process ' + str(cls.server_process.pid) + ' terminated.')
|
||||
cls.server_process.kill()
|
||||
cls.server_process.wait()
|
||||
|
||||
|
||||
|
||||
|
|
@ -141,8 +124,8 @@ def setUp(self):
|
|||
# Set the url prefix required by the 'tuf/client/updater.py' updater.
|
||||
# 'path/to/tmp/repository' -> 'localhost:8001/tmp/repository'.
|
||||
repository_basepath = self.repository_directory[len(os.getcwd()):]
|
||||
url_prefix = \
|
||||
'http://localhost:' + str(self.SERVER_PORT) + repository_basepath
|
||||
url_prefix = 'http://localhost:' \
|
||||
+ str(self.server_process_handler.port) + repository_basepath
|
||||
|
||||
# Setting 'tuf.settings.repository_directory' with the temporary client
|
||||
# directory copied from the original repository files.
|
||||
|
|
@ -158,6 +141,7 @@ def setUp(self):
|
|||
self.repository_mirrors)
|
||||
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
# Modified_TestCase.tearDown() automatically deletes temporary files and
|
||||
# directories that may have been created during each test case.
|
||||
|
|
@ -166,6 +150,11 @@ def tearDown(self):
|
|||
tuf.roledb.clear_roledb(clear_all=True)
|
||||
tuf.keydb.clear_keydb(clear_all=True)
|
||||
|
||||
# Logs stdout and stderr from the sever subprocess.
|
||||
self.server_process_handler.flush_log()
|
||||
|
||||
|
||||
|
||||
def test_without_tuf(self):
|
||||
# Verify that a target file replaced with a malicious version is downloaded
|
||||
# by a non-TUF client (i.e., a non-TUF client that does not verify hashes,
|
||||
|
|
|
|||
|
|
@ -55,13 +55,11 @@ class TestProject(unittest.TestCase):
|
|||
def setUpClass(cls):
|
||||
cls.tmp_dir = tempfile.mkdtemp(dir = os.getcwd())
|
||||
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
shutil.rmtree(cls.tmp_dir)
|
||||
|
||||
def setUp(self):
|
||||
# called before every test case
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
# called after every test case
|
||||
|
|
|
|||
|
|
@ -36,8 +36,6 @@
|
|||
import hashlib
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
|
|
@ -73,15 +71,11 @@ def setUp(self):
|
|||
self.target_data_length = len(self.target_data)
|
||||
|
||||
# Launch a SimpleHTTPServer (serves files in the current dir).
|
||||
self.PORT = random.randint(30000, 45000)
|
||||
self.server_proc = popen_python(['simple_server.py', str(self.PORT)])
|
||||
logger.info('\n\tServer process started.')
|
||||
logger.info('\tServer process id: ' + str(self.server_proc.pid))
|
||||
logger.info('\tServing on port: ' + str(self.PORT))
|
||||
junk, rel_target_filepath = os.path.split(target_filepath)
|
||||
self.url = 'http://localhost:'+str(self.PORT)+'/'+rel_target_filepath
|
||||
self.server_process_handler = utils.TestServerProcess(log=logger)
|
||||
|
||||
utils.wait_for_server('localhost', self.PORT)
|
||||
rel_target_filepath = os.path.basename(target_filepath)
|
||||
self.url = 'http://localhost:' \
|
||||
+ str(self.server_process_handler.port) + '/' + rel_target_filepath
|
||||
|
||||
# Computing hash of target file data.
|
||||
m = hashlib.md5()
|
||||
|
|
@ -93,11 +87,11 @@ def setUp(self):
|
|||
# Stop server process and perform clean up.
|
||||
def tearDown(self):
|
||||
unittest_toolbox.Modified_TestCase.tearDown(self)
|
||||
if self.server_proc.returncode is None:
|
||||
logger.info('\tServer process '+str(self.server_proc.pid)+' terminated.')
|
||||
self.server_proc.kill()
|
||||
# Drop return values of communicate()
|
||||
self.server_proc.communicate()
|
||||
|
||||
# Logs stdout and stderr from the server subprocess and then it
|
||||
# kills it and closes the temp file used for logging.
|
||||
self.server_process_handler.clean()
|
||||
|
||||
self.target_fileobj.close()
|
||||
|
||||
|
||||
|
|
@ -176,14 +170,17 @@ def test_download_url_to_tempfileobj_and_urls(self):
|
|||
download_file,
|
||||
self.random_string(), self.target_data_length)
|
||||
|
||||
url = 'http://localhost:' \
|
||||
+ str(self.server_process_handler.port) + '/' + self.random_string()
|
||||
self.assertRaises(requests.exceptions.HTTPError,
|
||||
download_file,
|
||||
'http://localhost:' + str(self.PORT) + '/' + self.random_string(),
|
||||
url,
|
||||
self.target_data_length)
|
||||
|
||||
url1 = 'http://localhost:' \
|
||||
+ str(self.server_process_handler.port + 1) + '/' + self.random_string()
|
||||
self.assertRaises(requests.exceptions.ConnectionError,
|
||||
download_file,
|
||||
'http://localhost:' + str(self.PORT+1) + '/' + self.random_string(),
|
||||
url1,
|
||||
self.target_data_length)
|
||||
|
||||
# Specify an unsupported URI scheme.
|
||||
|
|
@ -258,27 +255,30 @@ def test_https_connection(self):
|
|||
# 3: run with an HTTPS certificate with an unexpected hostname
|
||||
# 4: run with an HTTPS certificate that is expired
|
||||
# Be sure to offset from the port used in setUp to avoid collision.
|
||||
port1 = str(self.PORT + 1)
|
||||
port2 = str(self.PORT + 2)
|
||||
port3 = str(self.PORT + 3)
|
||||
port4 = str(self.PORT + 4)
|
||||
good_https_server_proc = popen_python(
|
||||
['simple_https_server.py', port1, good_cert_fname])
|
||||
good2_https_server_proc = popen_python(
|
||||
['simple_https_server.py', port2, good2_cert_fname])
|
||||
bad_https_server_proc = popen_python(
|
||||
['simple_https_server.py', port3, bad_cert_fname])
|
||||
expd_https_server_proc = popen_python(
|
||||
['simple_https_server.py', port4, expired_cert_fname])
|
||||
|
||||
for port in range(self.PORT + 1, self.PORT + 5):
|
||||
utils.wait_for_server('localhost', port)
|
||||
port1 = self.server_process_handler.port + 1
|
||||
port2 = self.server_process_handler.port + 2
|
||||
port3 = self.server_process_handler.port + 3
|
||||
port4 = self.server_process_handler.port + 4
|
||||
|
||||
relative_target_fpath = os.path.basename(target_filepath)
|
||||
good_https_url = 'https://localhost:' + port1 + '/' + relative_target_fpath
|
||||
good2_https_url = good_https_url.replace(':' + port1, ':' + port2)
|
||||
bad_https_url = good_https_url.replace(':' + port1, ':' + port3)
|
||||
expired_https_url = good_https_url.replace(':' + port1, ':' + port4)
|
||||
good_https_server_handler = utils.TestServerProcess(log=logger,
|
||||
server='simple_https_server.py', port=port1,
|
||||
extra_cmd_args=[good_cert_fname])
|
||||
good2_https_server_handler = utils.TestServerProcess(log=logger,
|
||||
server='simple_https_server.py', port=port2,
|
||||
extra_cmd_args=[good2_cert_fname])
|
||||
bad_https_server_handler = utils.TestServerProcess(log=logger,
|
||||
server='simple_https_server.py', port=port3,
|
||||
extra_cmd_args=[bad_cert_fname])
|
||||
expd_https_server_handler = utils.TestServerProcess(log=logger,
|
||||
server='simple_https_server.py', port=port4,
|
||||
extra_cmd_args=[expired_cert_fname])
|
||||
|
||||
suffix = '/' + os.path.basename(target_filepath)
|
||||
good_https_url = 'https://localhost:' + str(port1) + suffix
|
||||
good2_https_url = 'https://localhost:' + str(port2) + suffix
|
||||
bad_https_url = 'https://localhost:' + str(port3) + suffix
|
||||
expired_https_url = 'https://localhost:' + str(port4) + suffix
|
||||
|
||||
# Download the target file using an HTTPS connection.
|
||||
|
||||
|
|
@ -354,36 +354,15 @@ def test_https_connection(self):
|
|||
download.unsafe_download(good2_https_url, target_data_length).close()
|
||||
|
||||
finally:
|
||||
for proc in [
|
||||
good_https_server_proc,
|
||||
good2_https_server_proc,
|
||||
bad_https_server_proc,
|
||||
expd_https_server_proc]:
|
||||
if proc.returncode is None:
|
||||
logger.info('Terminating server process ' + str(proc.pid))
|
||||
proc.kill()
|
||||
# drop return values
|
||||
proc.communicate()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# TODO: Move this to a common test module (tests/common.py?)
|
||||
# and strip it test_proxy_use.py and test_download.py.
|
||||
def popen_python(command_arg_list):
|
||||
"""
|
||||
Run subprocess.Popen() to produce a process running a Python interpreter.
|
||||
Uses the same Python interpreter that the current process is using, via
|
||||
sys.executable.
|
||||
"""
|
||||
assert sys.executable, 'Test cannot function: unable to determine ' \
|
||||
'current Python interpreter via sys.executable.'
|
||||
|
||||
return subprocess.Popen(
|
||||
[sys.executable] + command_arg_list, stderr=subprocess.PIPE)
|
||||
|
||||
for proc_handler in [
|
||||
good_https_server_handler,
|
||||
good2_https_server_handler,
|
||||
bad_https_server_handler,
|
||||
expd_https_server_handler]:
|
||||
|
||||
# Logs stdout and stderr from the server subprocess and then it
|
||||
# kills it and closes the temp file used for logging.
|
||||
proc_handler.clean()
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -41,10 +41,8 @@
|
|||
|
||||
import os
|
||||
import tempfile
|
||||
import random
|
||||
import shutil
|
||||
import json
|
||||
import subprocess
|
||||
import logging
|
||||
import unittest
|
||||
import sys
|
||||
|
|
@ -68,8 +66,6 @@ class TestEndlessDataAttack(unittest_toolbox.Modified_TestCase):
|
|||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# setUpClass() is called before any of the test cases are executed.
|
||||
|
||||
# Create a temporary directory to store the repository, metadata, and target
|
||||
# files. 'temporary_directory' must be deleted in TearDownModule() so that
|
||||
# temporary files are always removed, even when exceptions occur.
|
||||
|
|
@ -82,32 +78,19 @@ def setUpClass(cls):
|
|||
# the pre-generated metadata files have a specific structure, such
|
||||
# as a delegated role 'targets/role1', three target files, five key files,
|
||||
# etc.
|
||||
cls.SERVER_PORT = random.randint(30000, 45000)
|
||||
command = ['python', 'simple_server.py', str(cls.SERVER_PORT)]
|
||||
cls.server_process = subprocess.Popen(command)
|
||||
logger.info('Server process started.')
|
||||
logger.info('Server process id: '+str(cls.server_process.pid))
|
||||
logger.info('Serving on port: '+str(cls.SERVER_PORT))
|
||||
cls.url = 'http://localhost:'+str(cls.SERVER_PORT) + os.path.sep
|
||||
|
||||
utils.wait_for_server('localhost', cls.SERVER_PORT)
|
||||
cls.server_process_handler = utils.TestServerProcess(log=logger)
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
# tearDownModule() is called after all the test cases have run.
|
||||
# http://docs.python.org/2/library/unittest.html#class-and-module-fixtures
|
||||
# Kills the server subprocess and closes the temp file used for logging.
|
||||
cls.server_process_handler.clean()
|
||||
|
||||
# Remove the temporary repository directory, which should contain all the
|
||||
# metadata, targets, and key files generated of all the test cases.
|
||||
shutil.rmtree(cls.temporary_directory)
|
||||
|
||||
# Kill the SimpleHTTPServer process.
|
||||
if cls.server_process.returncode is None:
|
||||
logger.info('Server process '+str(cls.server_process.pid)+' terminated.')
|
||||
cls.server_process.kill()
|
||||
cls.server_process.wait()
|
||||
|
||||
|
||||
|
||||
|
|
@ -143,8 +126,8 @@ def setUp(self):
|
|||
# Set the url prefix required by the 'tuf/client/updater.py' updater.
|
||||
# 'path/to/tmp/repository' -> 'localhost:8001/tmp/repository'.
|
||||
repository_basepath = self.repository_directory[len(os.getcwd()):]
|
||||
url_prefix = \
|
||||
'http://localhost:' + str(self.SERVER_PORT) + repository_basepath
|
||||
url_prefix = 'http://localhost:' \
|
||||
+ str(self.server_process_handler.port) + repository_basepath
|
||||
|
||||
# Setting 'tuf.settings.repository_directory' with the temporary client
|
||||
# directory copied from the original repository files.
|
||||
|
|
@ -167,6 +150,10 @@ def tearDown(self):
|
|||
tuf.roledb.clear_roledb(clear_all=True)
|
||||
tuf.keydb.clear_keydb(clear_all=True)
|
||||
|
||||
# Logs stdout and stderr from the sever subprocess.
|
||||
self.server_process_handler.flush_log()
|
||||
|
||||
|
||||
|
||||
def test_without_tuf(self):
|
||||
# Verify that a target file replaced with a larger malicious version (to
|
||||
|
|
|
|||
|
|
@ -44,10 +44,8 @@
|
|||
|
||||
import os
|
||||
import tempfile
|
||||
import random
|
||||
import shutil
|
||||
import json
|
||||
import subprocess
|
||||
import logging
|
||||
import unittest
|
||||
import sys
|
||||
|
|
@ -72,8 +70,6 @@ class TestExtraneousDependenciesAttack(unittest_toolbox.Modified_TestCase):
|
|||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# setUpClass() is called before any of the test cases are executed.
|
||||
|
||||
# Create a temporary directory to store the repository, metadata, and target
|
||||
# files. 'temporary_directory' must be deleted in TearDownModule() so that
|
||||
# temporary files are always removed, even when exceptions occur.
|
||||
|
|
@ -86,32 +82,19 @@ def setUpClass(cls):
|
|||
# the pre-generated metadata files have a specific structure, such
|
||||
# as a delegated role 'targets/role1', three target files, five key files,
|
||||
# etc.
|
||||
cls.SERVER_PORT = random.randint(30000, 45000)
|
||||
command = ['python', 'simple_server.py', str(cls.SERVER_PORT)]
|
||||
cls.server_process = subprocess.Popen(command)
|
||||
logger.info('Server process started.')
|
||||
logger.info('Server process id: '+str(cls.server_process.pid))
|
||||
logger.info('Serving on port: '+str(cls.SERVER_PORT))
|
||||
cls.url = 'http://localhost:'+str(cls.SERVER_PORT) + os.path.sep
|
||||
|
||||
utils.wait_for_server('localhost', cls.SERVER_PORT)
|
||||
cls.server_process_handler = utils.TestServerProcess(log=logger)
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
# tearDownModule() is called after all the test cases have run.
|
||||
# http://docs.python.org/2/library/unittest.html#class-and-module-fixtures
|
||||
# Kills the server subprocess and closes the temp file used for logging.
|
||||
cls.server_process_handler.clean()
|
||||
|
||||
# Remove the temporary repository directory, which should contain all the
|
||||
# metadata, targets, and key files generated of all the test cases.
|
||||
shutil.rmtree(cls.temporary_directory)
|
||||
|
||||
# Kill the SimpleHTTPServer process.
|
||||
if cls.server_process.returncode is None:
|
||||
logger.info('Server process '+str(cls.server_process.pid)+' terminated.')
|
||||
cls.server_process.kill()
|
||||
cls.server_process.wait()
|
||||
|
||||
|
||||
|
||||
|
|
@ -150,8 +133,8 @@ def setUp(self):
|
|||
# Set the url prefix required by the 'tuf/client/updater.py' updater.
|
||||
# 'path/to/tmp/repository' -> 'localhost:8001/tmp/repository'.
|
||||
repository_basepath = self.repository_directory[len(os.getcwd()):]
|
||||
url_prefix = \
|
||||
'http://localhost:' + str(self.SERVER_PORT) + repository_basepath
|
||||
url_prefix = 'http://localhost:' \
|
||||
+ str(self.server_process_handler.port) + repository_basepath
|
||||
|
||||
# Setting 'tuf.settings.repository_directory' with the temporary client
|
||||
# directory copied from the original repository files.
|
||||
|
|
@ -174,7 +157,8 @@ def tearDown(self):
|
|||
tuf.roledb.clear_roledb(clear_all=True)
|
||||
tuf.keydb.clear_keydb(clear_all=True)
|
||||
|
||||
|
||||
# Logs stdout and stderr from the sever subprocess.
|
||||
self.server_process_handler.flush_log()
|
||||
|
||||
|
||||
def test_with_tuf(self):
|
||||
|
|
|
|||
|
|
@ -45,12 +45,10 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import random
|
||||
import time
|
||||
import tempfile
|
||||
import shutil
|
||||
import json
|
||||
import subprocess
|
||||
import logging
|
||||
import unittest
|
||||
import sys
|
||||
|
|
@ -80,8 +78,6 @@ class TestIndefiniteFreezeAttack(unittest_toolbox.Modified_TestCase):
|
|||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# setUpClass() is called before any of the test cases are executed.
|
||||
|
||||
# Create a temporary directory to store the repository, metadata, and target
|
||||
# files. 'temporary_directory' must be deleted in TearDownModule() so that
|
||||
# temporary files are always removed, even when exceptions occur.
|
||||
|
|
@ -94,32 +90,19 @@ def setUpClass(cls):
|
|||
# the pre-generated metadata files have a specific structure, such
|
||||
# as a delegated role 'targets/role1', three target files, five key files,
|
||||
# etc.
|
||||
cls.SERVER_PORT = random.randint(30000, 45000)
|
||||
command = ['python', 'simple_server.py', str(cls.SERVER_PORT)]
|
||||
cls.server_process = subprocess.Popen(command)
|
||||
logger.info('Server process started.')
|
||||
logger.info('Server process id: '+str(cls.server_process.pid))
|
||||
logger.info('Serving on port: '+str(cls.SERVER_PORT))
|
||||
cls.url = 'http://localhost:'+str(cls.SERVER_PORT) + os.path.sep
|
||||
|
||||
utils.wait_for_server('localhost', cls.SERVER_PORT)
|
||||
cls.server_process_handler = utils.TestServerProcess(log=logger)
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
# tearDownModule() is called after all the test cases have run.
|
||||
# http://docs.python.org/2/library/unittest.html#class-and-module-fixtures
|
||||
# Kills the server subprocess and closes the temp file used for logging.
|
||||
cls.server_process_handler.clean()
|
||||
|
||||
# Remove the temporary repository directory, which should contain all the
|
||||
# metadata, targets, and key files generated of all the test cases.
|
||||
shutil.rmtree(cls.temporary_directory)
|
||||
|
||||
# Kill the SimpleHTTPServer process.
|
||||
if cls.server_process.returncode is None:
|
||||
logger.info('Server process '+str(cls.server_process.pid)+' terminated.')
|
||||
cls.server_process.kill()
|
||||
cls.server_process.wait()
|
||||
|
||||
|
||||
|
||||
|
|
@ -157,8 +140,8 @@ def setUp(self):
|
|||
# Set the url prefix required by the 'tuf/client/updater.py' updater.
|
||||
# 'path/to/tmp/repository' -> 'localhost:8001/tmp/repository'.
|
||||
repository_basepath = self.repository_directory[len(os.getcwd()):]
|
||||
url_prefix = \
|
||||
'http://localhost:' + str(self.SERVER_PORT) + repository_basepath
|
||||
url_prefix = 'http://localhost:' \
|
||||
+ str(self.server_process_handler.port) + repository_basepath
|
||||
|
||||
# Setting 'tuf.settings.repository_directory' with the temporary client
|
||||
# directory copied from the original repository files.
|
||||
|
|
@ -181,6 +164,9 @@ def tearDown(self):
|
|||
tuf.roledb.clear_roledb(clear_all=True)
|
||||
tuf.keydb.clear_keydb(clear_all=True)
|
||||
|
||||
# Logs stdout and stderr from the sever subprocess.
|
||||
self.server_process_handler.flush_log()
|
||||
|
||||
|
||||
def test_without_tuf(self):
|
||||
# Without TUF, Test 1 and Test 2 are functionally equivalent, so we skip
|
||||
|
|
|
|||
|
|
@ -41,8 +41,6 @@
|
|||
import shutil
|
||||
import tempfile
|
||||
import logging
|
||||
import random
|
||||
import subprocess
|
||||
import unittest
|
||||
import sys
|
||||
|
||||
|
|
@ -67,8 +65,6 @@ class TestKeyRevocation(unittest_toolbox.Modified_TestCase):
|
|||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# setUpClass() is called before tests in an individual class are executed.
|
||||
|
||||
# Create a temporary directory to store the repository, metadata, and target
|
||||
# files. 'temporary_directory' must be deleted in TearDownModule() so that
|
||||
# temporary files are always removed, even when exceptions occur.
|
||||
|
|
@ -81,32 +77,19 @@ def setUpClass(cls):
|
|||
# 'test_key_revocation.py' assume the pre-generated metadata files have a
|
||||
# specific structure, such as a delegated role, three target files, five
|
||||
# key files, etc.
|
||||
cls.SERVER_PORT = random.randint(30000, 45000)
|
||||
command = ['python', 'simple_server.py', str(cls.SERVER_PORT)]
|
||||
cls.server_process = subprocess.Popen(command)
|
||||
logger.info('\n\tServer process started.')
|
||||
logger.info('\tServer process id: '+str(cls.server_process.pid))
|
||||
logger.info('\tServing on port: '+str(cls.SERVER_PORT))
|
||||
cls.url = 'http://localhost:'+str(cls.SERVER_PORT) + os.path.sep
|
||||
|
||||
utils.wait_for_server('localhost', cls.SERVER_PORT)
|
||||
cls.server_process_handler = utils.TestServerProcess(log=logger)
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
# tearDownModule() is called after all the tests have run.
|
||||
# http://docs.python.org/2/library/unittest.html#class-and-module-fixtures
|
||||
# Kills the server subprocess and closes the temp file used for logging.
|
||||
cls.server_process_handler.clean()
|
||||
|
||||
# Remove the temporary repository directory, which should contain all the
|
||||
# metadata, targets, and key files generated for the test cases.
|
||||
shutil.rmtree(cls.temporary_directory)
|
||||
|
||||
# Kill the SimpleHTTPServer process.
|
||||
if cls.server_process.returncode is None:
|
||||
logger.info('\tServer process '+str(cls.server_process.pid)+' terminated.')
|
||||
cls.server_process.kill()
|
||||
cls.server_process.wait()
|
||||
|
||||
|
||||
|
||||
|
|
@ -149,8 +132,8 @@ def setUp(self):
|
|||
|
||||
# 'path/to/tmp/repository' -> 'localhost:8001/tmp/repository'.
|
||||
repository_basepath = self.repository_directory[len(os.getcwd()):]
|
||||
url_prefix = \
|
||||
'http://localhost:' + str(self.SERVER_PORT) + repository_basepath
|
||||
url_prefix = 'http://localhost:' \
|
||||
+ str(self.server_process_handler.port) + repository_basepath
|
||||
|
||||
# Setting 'tuf.settings.repository_directory' with the temporary client
|
||||
# directory copied from the original repository files.
|
||||
|
|
@ -179,6 +162,8 @@ def tearDown(self):
|
|||
tuf.roledb.clear_roledb(clear_all=True)
|
||||
tuf.keydb.clear_keydb(clear_all=True)
|
||||
|
||||
# Logs stdout and stderr from the sever subprocess.
|
||||
self.server_process_handler.flush_log()
|
||||
|
||||
|
||||
# UNIT TESTS.
|
||||
|
|
|
|||
|
|
@ -40,9 +40,7 @@
|
|||
|
||||
import os
|
||||
import tempfile
|
||||
import random
|
||||
import shutil
|
||||
import subprocess
|
||||
import logging
|
||||
import unittest
|
||||
import sys
|
||||
|
|
@ -71,8 +69,6 @@ class TestMixAndMatchAttack(unittest_toolbox.Modified_TestCase):
|
|||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# setUpClass() is called before any of the test cases are executed.
|
||||
|
||||
# Create a temporary directory to store the repository, metadata, and
|
||||
# target files. 'temporary_directory' must be deleted in TearDownModule()
|
||||
# so that temporary files are always removed, even when exceptions occur.
|
||||
|
|
@ -85,33 +81,19 @@ def setUpClass(cls):
|
|||
# the pre-generated metadata files have a specific structure, such
|
||||
# as a delegated role 'targets/role1', three target files, five key files,
|
||||
# etc.
|
||||
cls.SERVER_PORT = random.randint(30000, 45000)
|
||||
command = ['python', 'simple_server.py', str(cls.SERVER_PORT)]
|
||||
cls.server_process = subprocess.Popen(command)
|
||||
logger.info('Server process started.')
|
||||
logger.info('Server process id: '+str(cls.server_process.pid))
|
||||
logger.info('Serving on port: '+str(cls.SERVER_PORT))
|
||||
cls.url = 'http://localhost:'+str(cls.SERVER_PORT) + os.path.sep
|
||||
|
||||
utils.wait_for_server('localhost', cls.SERVER_PORT)
|
||||
cls.server_process_handler = utils.TestServerProcess(log=logger)
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
# tearDownModule() is called after all the test cases have run.
|
||||
# http://docs.python.org/2/library/unittest.html#class-and-module-fixtures
|
||||
# Kills the server subprocess and closes the temp file used for logging.
|
||||
cls.server_process_handler.clean()
|
||||
|
||||
# Remove the temporary repository directory, which should contain all the
|
||||
# metadata, targets, and key files generated of all the test cases.
|
||||
shutil.rmtree(cls.temporary_directory)
|
||||
|
||||
# Kill the SimpleHTTPServer process.
|
||||
if cls.server_process.returncode is None:
|
||||
logger.info('Server process '+str(cls.server_process.pid)+' terminated.')
|
||||
cls.server_process.kill()
|
||||
cls.server_process.wait()
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -150,8 +132,8 @@ def setUp(self):
|
|||
# Set the url prefix required by the 'tuf/client/updater.py' updater.
|
||||
# 'path/to/tmp/repository' -> 'localhost:8001/tmp/repository'.
|
||||
repository_basepath = self.repository_directory[len(os.getcwd()):]
|
||||
url_prefix = \
|
||||
'http://localhost:' + str(self.SERVER_PORT) + repository_basepath
|
||||
url_prefix = 'http://localhost:' \
|
||||
+ str(self.server_process_handler.port) + repository_basepath
|
||||
|
||||
# Setting 'tuf.settings.repository_directory' with the temporary client
|
||||
# directory copied from the original repository files.
|
||||
|
|
@ -174,6 +156,9 @@ def tearDown(self):
|
|||
tuf.roledb.clear_roledb(clear_all=True)
|
||||
tuf.keydb.clear_keydb(clear_all=True)
|
||||
|
||||
# Logs stdout and stderr from the sever subprocess.
|
||||
self.server_process_handler.flush_log()
|
||||
|
||||
|
||||
def test_with_tuf(self):
|
||||
# Scenario:
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@
|
|||
import os
|
||||
import tempfile
|
||||
import random
|
||||
import subprocess
|
||||
import logging
|
||||
import shutil
|
||||
import unittest
|
||||
|
|
@ -133,28 +132,19 @@ def setUp(self):
|
|||
# has been changed when executing a subprocess.
|
||||
SIMPLE_SERVER_PATH = os.path.join(os.getcwd(), 'simple_server.py')
|
||||
|
||||
command = ['python', SIMPLE_SERVER_PATH, str(self.SERVER_PORT)]
|
||||
command2 = ['python', SIMPLE_SERVER_PATH, str(self.SERVER_PORT2)]
|
||||
|
||||
self.server_process = subprocess.Popen(command,
|
||||
cwd=self.repository_directory)
|
||||
# Creates a subprocess running server and uses temp file for logging.
|
||||
self.server_process_handler = utils.TestServerProcess(log=logger,
|
||||
port=self.SERVER_PORT, server=SIMPLE_SERVER_PATH,
|
||||
popen_cwd=self.repository_directory)
|
||||
|
||||
logger.debug('Server process started.')
|
||||
logger.debug('Server process id: ' + str(self.server_process.pid))
|
||||
logger.debug('Serving on port: ' + str(self.SERVER_PORT))
|
||||
|
||||
self.server_process2 = subprocess.Popen(command2,
|
||||
cwd=self.repository_directory2)
|
||||
|
||||
# Creates a subprocess running server and uses temp file for logging.
|
||||
self.server_process_handler2 = utils.TestServerProcess(log=logger,
|
||||
port=self.SERVER_PORT2, server=SIMPLE_SERVER_PATH,
|
||||
popen_cwd=self.repository_directory2)
|
||||
|
||||
logger.debug('Server process 2 started.')
|
||||
logger.debug('Server 2 process id: ' + str(self.server_process2.pid))
|
||||
logger.debug('Serving 2 on port: ' + str(self.SERVER_PORT2))
|
||||
self.url = 'http://localhost:' + str(self.SERVER_PORT) + os.path.sep
|
||||
self.url2 = 'http://localhost:' + str(self.SERVER_PORT2) + os.path.sep
|
||||
|
||||
utils.wait_for_server('localhost', self.SERVER_PORT)
|
||||
utils.wait_for_server('localhost', self.SERVER_PORT2)
|
||||
|
||||
url_prefix = 'http://localhost:' + str(self.SERVER_PORT)
|
||||
url_prefix2 = 'http://localhost:' + str(self.SERVER_PORT2)
|
||||
|
|
@ -182,16 +172,10 @@ def tearDown(self):
|
|||
# directories that may have been created during each test case.
|
||||
unittest_toolbox.Modified_TestCase.tearDown(self)
|
||||
|
||||
# Kill the SimpleHTTPServer process.
|
||||
if self.server_process.returncode is None:
|
||||
logger.info('Server process ' + str(self.server_process.pid) + ' terminated.')
|
||||
self.server_process.kill()
|
||||
self.server_process.wait()
|
||||
|
||||
if self.server_process2.returncode is None:
|
||||
logger.info('Server 2 process ' + str(self.server_process2.pid) + ' terminated.')
|
||||
self.server_process2.kill()
|
||||
self.server_process2.wait()
|
||||
# Logs stdout and stderr from the server subprocesses and then it
|
||||
# kills them and closes the temp files used for logging.
|
||||
self.server_process_handler.clean()
|
||||
self.server_process_handler2.clean()
|
||||
|
||||
# updater.Updater() populates the roledb with the name "test_repository1"
|
||||
tuf.roledb.clear_roledb(clear_all=True)
|
||||
|
|
@ -200,7 +184,6 @@ def tearDown(self):
|
|||
shutil.rmtree(self.temporary_directory)
|
||||
|
||||
|
||||
|
||||
def test_update(self):
|
||||
self.assertEqual('test_repository1', str(self.repository_updater))
|
||||
self.assertEqual('test_repository2', str(self.repository_updater2))
|
||||
|
|
|
|||
|
|
@ -37,10 +37,8 @@
|
|||
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
import sys
|
||||
|
||||
import tuf
|
||||
import tuf.download as download
|
||||
|
|
@ -78,25 +76,23 @@ def setUpClass(cls):
|
|||
" (proxy_server.py is Python2 only)")
|
||||
|
||||
# Launch a simple HTTP server (serves files in the current dir).
|
||||
cls.http_port = random.randint(30000, 45000)
|
||||
cls.http_server_proc = popen_python(
|
||||
['simple_server.py', str(cls.http_port)])
|
||||
cls.http_server_handler = utils.TestServerProcess(log=logger)
|
||||
|
||||
# Launch an HTTPS server (serves files in the current dir).
|
||||
cls.https_port = cls.http_port + 1
|
||||
cls.https_server_proc = popen_python(
|
||||
['simple_https_server.py', str(cls.https_port)])
|
||||
|
||||
cls.https_server_handler = utils.TestServerProcess(log=logger,
|
||||
server='simple_https_server.py',
|
||||
port=cls.http_server_handler.port + 1)
|
||||
|
||||
# Launch an HTTP proxy server derived from inaz2/proxy2.
|
||||
# This one is able to handle HTTP CONNECT requests, and so can pass HTTPS
|
||||
# requests on to the target server.
|
||||
cls.http_proxy_port = cls.http_port + 2
|
||||
cls.http_proxy_proc = popen_python(
|
||||
['proxy_server.py', str(cls.http_proxy_port)])
|
||||
cls.http_proxy_handler = utils.TestServerProcess(log=logger,
|
||||
server='proxy_server.py',
|
||||
port=cls.http_server_handler.port + 2)
|
||||
|
||||
# Note that the HTTP proxy server's address uses http://, regardless of the
|
||||
# type of connection used with the target server.
|
||||
cls.http_proxy_addr = 'http://127.0.0.1:' + str(cls.http_proxy_port)
|
||||
cls.http_proxy_addr = 'http://127.0.0.1:' + str(cls.http_proxy_handler.port)
|
||||
|
||||
|
||||
# Launch an HTTPS proxy server, also derived from inaz2/proxy2.
|
||||
|
|
@ -111,18 +107,15 @@ def setUpClass(cls):
|
|||
# 3rd arg: (optional) certificate file for telling the proxy what target
|
||||
# server certs to accept in its HTTPS connection to the target server.
|
||||
# This is only relevant if the proxy is in intercept mode.
|
||||
cls.https_proxy_port = cls.http_port + 3
|
||||
cls.https_proxy_proc = popen_python(
|
||||
['proxy_server.py', str(cls.https_proxy_port), 'intercept',
|
||||
os.path.join('ssl_certs', 'ssl_cert.crt')])
|
||||
good_cert_fpath = os.path.join('ssl_certs', 'ssl_cert.crt')
|
||||
cls.https_proxy_handler = utils.TestServerProcess(log=logger,
|
||||
server='proxy_server.py',
|
||||
port=cls.http_server_handler.port + 3,
|
||||
extra_cmd_args=['intercept', good_cert_fpath])
|
||||
|
||||
# Note that the HTTPS proxy server's address uses https://, regardless of
|
||||
# the type of connection used with the target server.
|
||||
cls.https_proxy_addr = 'https://localhost:' + str(cls.https_proxy_port)
|
||||
|
||||
utils.wait_for_server('localhost', cls.http_port)
|
||||
utils.wait_for_server('localhost', cls.https_port)
|
||||
utils.wait_for_server('localhost', cls.http_proxy_port)
|
||||
utils.wait_for_server('localhost', cls.https_proxy_port)
|
||||
cls.https_proxy_addr = 'https://localhost:' + str(cls.https_proxy_handler.port)
|
||||
|
||||
|
||||
|
||||
|
|
@ -135,17 +128,15 @@ def tearDownClass(cls):
|
|||
"""
|
||||
unittest_toolbox.Modified_TestCase.tearDownClass()
|
||||
|
||||
for proc in [
|
||||
cls.http_server_proc,
|
||||
cls.https_server_proc,
|
||||
cls.http_proxy_proc,
|
||||
cls.https_proxy_proc,
|
||||
for proc_handler in [
|
||||
cls.http_server_handler,
|
||||
cls.https_server_handler,
|
||||
cls.http_proxy_handler,
|
||||
cls.https_proxy_handler,
|
||||
]:
|
||||
if proc.returncode is None:
|
||||
logger.info('\tTerminating process ' + str(proc.pid) + ' in cleanup.')
|
||||
proc.kill()
|
||||
# Drop return values of communicate()
|
||||
proc.communicate()
|
||||
|
||||
# Kill the SimpleHTTPServer process.
|
||||
proc_handler.clean()
|
||||
|
||||
|
||||
|
||||
|
|
@ -163,16 +154,16 @@ def setUp(self):
|
|||
# and its url on the server.
|
||||
current_dir = os.getcwd()
|
||||
target_filepath = self.make_temp_data_file(directory=current_dir)
|
||||
rel_target_filepath = os.path.basename(target_filepath)
|
||||
|
||||
with open(target_filepath, 'r') as target_file_object:
|
||||
self.target_data_length = len(target_file_object.read())
|
||||
|
||||
suffix = '/' + os.path.basename(target_filepath)
|
||||
self.url = \
|
||||
'http://localhost:' + str(self.http_port) + '/' + rel_target_filepath
|
||||
'http://localhost:' + str(self.http_server_handler.port) + suffix
|
||||
|
||||
self.url_https = \
|
||||
'https://localhost:' + str(self.https_port) + '/' + rel_target_filepath
|
||||
'https://localhost:' + str(self.https_server_handler.port) + suffix
|
||||
|
||||
|
||||
|
||||
|
|
@ -187,6 +178,15 @@ def tearDown(self):
|
|||
|
||||
self.restore_all_modified_env_values()
|
||||
|
||||
for proc_handler in [
|
||||
self.http_server_handler,
|
||||
self.https_server_handler,
|
||||
self.http_proxy_handler,
|
||||
self.https_proxy_handler,
|
||||
]:
|
||||
|
||||
# Logs stdout and stderr from the sever subprocess.
|
||||
proc_handler.flush_log()
|
||||
|
||||
|
||||
|
||||
|
|
@ -352,32 +352,12 @@ def restore_env_value(self, key):
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
def restore_all_modified_env_values(self):
|
||||
for key in self.old_env_values:
|
||||
self.restore_env_value(key)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# TODO: Move this to a common test module (tests/common.py?)
|
||||
# and strip it test_proxy_use.py and test_download.py.
|
||||
def popen_python(command_arg_list):
|
||||
"""
|
||||
Run subprocess.Popen() to produce a process running a Python interpreter.
|
||||
Uses the same Python interpreter that the current process is using, via
|
||||
sys.executable.
|
||||
"""
|
||||
assert sys.executable, 'Test cannot function: unable to determine ' \
|
||||
'current Python interpreter via sys.executable.'
|
||||
|
||||
return subprocess.Popen(
|
||||
[sys.executable] + command_arg_list, stderr=subprocess.PIPE)
|
||||
|
||||
|
||||
|
||||
# Run unit test.
|
||||
if __name__ == '__main__':
|
||||
utils.configure_test_logging(sys.argv)
|
||||
|
|
|
|||
|
|
@ -40,10 +40,8 @@
|
|||
|
||||
import os
|
||||
import tempfile
|
||||
import random
|
||||
import datetime
|
||||
import shutil
|
||||
import subprocess
|
||||
import logging
|
||||
import unittest
|
||||
import sys
|
||||
|
|
@ -71,8 +69,6 @@ class TestReplayAttack(unittest_toolbox.Modified_TestCase):
|
|||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# setUpClass() is called before any of the test cases are executed.
|
||||
|
||||
# Create a temporary directory to store the repository, metadata, and target
|
||||
# files. 'temporary_directory' must be deleted in TearDownModule() so that
|
||||
# temporary files are always removed, even when exceptions occur.
|
||||
|
|
@ -85,32 +81,19 @@ def setUpClass(cls):
|
|||
# the pre-generated metadata files have a specific structure, such
|
||||
# as a delegated role 'targets/role1', three target files, five key files,
|
||||
# etc.
|
||||
cls.SERVER_PORT = random.randint(30000, 45000)
|
||||
command = ['python', 'simple_server.py', str(cls.SERVER_PORT)]
|
||||
cls.server_process = subprocess.Popen(command)
|
||||
logger.info('Server process started.')
|
||||
logger.info('Server process id: '+str(cls.server_process.pid))
|
||||
logger.info('Serving on port: '+str(cls.SERVER_PORT))
|
||||
cls.url = 'http://localhost:'+str(cls.SERVER_PORT) + os.path.sep
|
||||
|
||||
utils.wait_for_server('localhost', cls.SERVER_PORT)
|
||||
cls.server_process_handler = utils.TestServerProcess(log=logger)
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
# tearDownModule() is called after all the test cases have run.
|
||||
# http://docs.python.org/2/library/unittest.html#class-and-module-fixtures
|
||||
# Kills the server subprocess and closes the temp file used for logging.
|
||||
cls.server_process_handler.clean()
|
||||
|
||||
# Remove the temporary repository directory, which should contain all the
|
||||
# metadata, targets, and key files generated of all the test cases.
|
||||
shutil.rmtree(cls.temporary_directory)
|
||||
|
||||
# Kill the SimpleHTTPServer process.
|
||||
if cls.server_process.returncode is None:
|
||||
logger.info('Server process '+str(cls.server_process.pid)+' terminated.')
|
||||
cls.server_process.kill()
|
||||
cls.server_process.wait()
|
||||
|
||||
|
||||
|
||||
|
|
@ -149,8 +132,8 @@ def setUp(self):
|
|||
# Set the url prefix required by the 'tuf/client/updater.py' updater.
|
||||
# 'path/to/tmp/repository' -> 'localhost:8001/tmp/repository'.
|
||||
repository_basepath = self.repository_directory[len(os.getcwd()):]
|
||||
url_prefix = \
|
||||
'http://localhost:' + str(self.SERVER_PORT) + repository_basepath
|
||||
url_prefix = 'http://localhost:' \
|
||||
+ str(self.server_process_handler.port) + repository_basepath
|
||||
|
||||
# Setting 'tuf.settings.repository_directory' with the temporary client
|
||||
# directory copied from the original repository files.
|
||||
|
|
@ -173,6 +156,10 @@ def tearDown(self):
|
|||
tuf.roledb.clear_roledb(clear_all=True)
|
||||
tuf.keydb.clear_keydb(clear_all=True)
|
||||
|
||||
# Logs stdout and stderr from the sever subprocess.
|
||||
self.server_process_handler.flush_log()
|
||||
|
||||
|
||||
|
||||
def test_without_tuf(self):
|
||||
# Scenario:
|
||||
|
|
|
|||
|
|
@ -70,9 +70,6 @@
|
|||
class TestRepositoryToolFunctions(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
|
||||
# setUpClass() is called before tests in an individual class are executed.
|
||||
|
||||
# Create a temporary directory to store the repository, metadata, and target
|
||||
# files. 'temporary_directory' must be deleted in TearDownClass() so that
|
||||
# temporary files are always removed, even when exceptions occur.
|
||||
|
|
@ -84,10 +81,6 @@ def setUpClass(cls):
|
|||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
|
||||
# tearDownModule() is called after all the tests have run.
|
||||
# http://docs.python.org/2/library/unittest.html#class-and-module-fixtures
|
||||
|
||||
# Remove the temporary repository directory, which should contain all the
|
||||
# metadata, targets, and key files generated for the test cases.
|
||||
tuf.roledb.clear_roledb(clear_all=True)
|
||||
|
|
|
|||
|
|
@ -58,9 +58,6 @@
|
|||
class TestRepository(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
|
||||
# setUpClass() is called before tests in an individual class are executed.
|
||||
|
||||
# Create a temporary directory to store the repository, metadata, and target
|
||||
# files. 'temporary_directory' must be deleted in TearDownClass() so that
|
||||
# temporary files are always removed, even when exceptions occur.
|
||||
|
|
@ -69,10 +66,6 @@ def setUpClass(cls):
|
|||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
|
||||
# tearDownModule() is called after all the tests have run.
|
||||
# http://docs.python.org/2/library/unittest.html#class-and-module-fixtures
|
||||
|
||||
# Remove the temporary repository directory, which should contain all the
|
||||
# metadata, targets, and key files generated for the test cases.
|
||||
shutil.rmtree(cls.temporary_directory)
|
||||
|
|
@ -1160,9 +1153,6 @@ def test_init(self):
|
|||
class TestTargets(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
|
||||
# setUpClass() is called before tests in an individual class are executed.
|
||||
|
||||
# Create a temporary directory to store the repository, metadata, and target
|
||||
# files. 'temporary_directory' must be deleted in TearDownClass() so that
|
||||
# temporary files are always removed, even when exceptions occur.
|
||||
|
|
@ -1172,10 +1162,6 @@ def setUpClass(cls):
|
|||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
|
||||
# tearDownModule() is called after all the tests have run.
|
||||
# http://docs.python.org/2/library/unittest.html#class-and-module-fixtures
|
||||
|
||||
# Remove the temporary repository directory, which should contain all the
|
||||
# metadata, targets, and key files generated for the test cases.
|
||||
shutil.rmtree(cls.temporary_directory)
|
||||
|
|
@ -1922,9 +1908,6 @@ def test_check_path(self):
|
|||
class TestRepositoryToolFunctions(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
|
||||
# setUpClass() is called before tests in an individual class are executed.
|
||||
|
||||
# Create a temporary directory to store the repository, metadata, and target
|
||||
# files. 'temporary_directory' must be deleted in TearDownClass() so that
|
||||
# temporary files are always removed, even when exceptions occur.
|
||||
|
|
@ -1934,10 +1917,6 @@ def setUpClass(cls):
|
|||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
|
||||
# tearDownModule() is called after all the tests have run.
|
||||
# http://docs.python.org/2/library/unittest.html#class-and-module-fixtures
|
||||
|
||||
# Remove the temporary repository directory, which should contain all the
|
||||
# metadata, targets, and key files generated for the test cases.
|
||||
shutil.rmtree(cls.temporary_directory)
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@
|
|||
import random
|
||||
import time
|
||||
import shutil
|
||||
import subprocess
|
||||
import logging
|
||||
import unittest
|
||||
import sys
|
||||
|
|
@ -73,8 +72,6 @@ class TestSlowRetrievalAttack(unittest_toolbox.Modified_TestCase):
|
|||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# setUpClass() is called before any of the test cases are executed.
|
||||
|
||||
# Create a temporary directory to store the repository, metadata, and target
|
||||
# files. 'temporary_directory' must be deleted in TearDownModule() so that
|
||||
# temporary files are always removed, even when exceptions occur.
|
||||
|
|
@ -85,9 +82,6 @@ def setUpClass(cls):
|
|||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
# tearDownModule() is called after all the test cases have run.
|
||||
# http://docs.python.org/2/library/unittest.html#class-and-module-fixtures
|
||||
|
||||
# Remove the temporary repository directory, which should contain all the
|
||||
# metadata, targets, and key files generated of all the test cases.
|
||||
shutil.rmtree(cls.temporary_directory)
|
||||
|
|
@ -102,12 +96,11 @@ def _start_slow_server(self, mode):
|
|||
# the pre-generated metadata files have a specific structure, such
|
||||
# as a delegated role 'targets/role1', three target files, five key files,
|
||||
# etc.
|
||||
command = ['python', 'slow_retrieval_server.py', str(self.SERVER_PORT), mode]
|
||||
server_process = subprocess.Popen(command)
|
||||
self.server_process_handler = utils.TestServerProcess(log=logger,
|
||||
server='slow_retrieval_server.py', port=self.SERVER_PORT,
|
||||
timeout=0, extra_cmd_args=[mode])
|
||||
|
||||
logger.info('Slow Retrieval Server process started.')
|
||||
logger.info('Server process id: '+str(server_process.pid))
|
||||
logger.info('Serving on port: '+str(self.SERVER_PORT))
|
||||
url = 'http://localhost:'+str(self.SERVER_PORT) + os.path.sep
|
||||
|
||||
# NOTE: Following error is raised if a delay is not long enough:
|
||||
# <urlopen error [Errno 111] Connection refused>
|
||||
|
|
@ -117,17 +110,12 @@ def _start_slow_server(self, mode):
|
|||
# increasing this to 3s, sadly.
|
||||
time.sleep(3)
|
||||
|
||||
return server_process
|
||||
|
||||
|
||||
|
||||
def _stop_slow_server(self, server_process):
|
||||
# Kill the SimpleHTTPServer process.
|
||||
if server_process.returncode is None:
|
||||
logger.info('Server process '+str(server_process.pid)+' terminated.')
|
||||
server_process.kill()
|
||||
server_process.wait()
|
||||
|
||||
def _stop_slow_server(self):
|
||||
# Logs stdout and stderr from the server subprocess and then it
|
||||
# kills it and closes the temp file used for logging.
|
||||
self.server_process_handler.clean()
|
||||
|
||||
|
||||
def setUp(self):
|
||||
|
|
@ -247,12 +235,14 @@ def tearDown(self):
|
|||
tuf.keydb.clear_keydb(clear_all=True)
|
||||
|
||||
|
||||
|
||||
|
||||
def test_with_tuf_mode_1(self):
|
||||
# Simulate a slow retrieval attack.
|
||||
# 'mode_1': When download begins,the server blocks the download for a long
|
||||
# time by doing nothing before it sends the first byte of data.
|
||||
|
||||
server_process = self._start_slow_server('mode_1')
|
||||
self._start_slow_server('mode_1')
|
||||
|
||||
# Verify that the TUF client detects replayed metadata and refuses to
|
||||
# continue the update process.
|
||||
|
|
@ -276,7 +266,7 @@ def test_with_tuf_mode_1(self):
|
|||
self.fail('TUF did not prevent a slow retrieval attack.')
|
||||
|
||||
finally:
|
||||
self._stop_slow_server(server_process)
|
||||
self._stop_slow_server()
|
||||
|
||||
|
||||
|
||||
|
|
@ -292,7 +282,7 @@ def test_with_tuf_mode_2(self):
|
|||
# 'mode_2': During the download process, the server blocks the download
|
||||
# by sending just several characters every few seconds.
|
||||
|
||||
server_process = self._start_slow_server('mode_2')
|
||||
self._start_slow_server('mode_2')
|
||||
client_filepath = os.path.join(self.client_directory, 'file1.txt')
|
||||
original_average_download_speed = tuf.settings.MIN_AVERAGE_DOWNLOAD_SPEED
|
||||
tuf.settings.MIN_AVERAGE_DOWNLOAD_SPEED = 3
|
||||
|
|
@ -320,7 +310,7 @@ def test_with_tuf_mode_2(self):
|
|||
self.fail('TUF did not prevent a slow retrieval attack.')
|
||||
|
||||
finally:
|
||||
self._stop_slow_server(server_process)
|
||||
self._stop_slow_server()
|
||||
tuf.settings.MIN_AVERAGE_DOWNLOAD_SPEED = original_average_download_speed
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -55,8 +55,6 @@
|
|||
import copy
|
||||
import tempfile
|
||||
import logging
|
||||
import random
|
||||
import subprocess
|
||||
import errno
|
||||
import sys
|
||||
import unittest
|
||||
|
|
@ -85,8 +83,6 @@ class TestUpdater(unittest_toolbox.Modified_TestCase):
|
|||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# setUpClass() is called before tests in an individual class are executed.
|
||||
|
||||
# Create a temporary directory to store the repository, metadata, and target
|
||||
# files. 'temporary_directory' must be deleted in TearDownModule() so that
|
||||
# temporary files are always removed, even when exceptions occur.
|
||||
|
|
@ -104,28 +100,15 @@ def setUpClass(cls):
|
|||
# assume the pre-generated metadata files have a specific structure, such
|
||||
# as a delegated role 'targets/role1', three target files, five key files,
|
||||
# etc.
|
||||
cls.SERVER_PORT = random.randint(30000, 45000)
|
||||
command = ['python', cls.SIMPLE_SERVER_PATH, str(cls.SERVER_PORT)]
|
||||
cls.server_process = subprocess.Popen(command)
|
||||
logger.info('\n\tServer process started.')
|
||||
logger.info('\tServer process id: '+str(cls.server_process.pid))
|
||||
logger.info('\tServing on port: '+str(cls.SERVER_PORT))
|
||||
cls.url = 'http://localhost:'+str(cls.SERVER_PORT) + os.path.sep
|
||||
|
||||
utils.wait_for_server('localhost', cls.SERVER_PORT)
|
||||
cls.server_process_handler = utils.TestServerProcess(log=logger,
|
||||
server=cls.SIMPLE_SERVER_PATH)
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
# tearDownModule() is called after all the tests have run.
|
||||
# http://docs.python.org/2/library/unittest.html#class-and-module-fixtures
|
||||
|
||||
# Kill the SimpleHTTPServer process.
|
||||
if cls.server_process.returncode is None:
|
||||
logger.info('\tServer process ' + str(cls.server_process.pid) + ' terminated.')
|
||||
cls.server_process.kill()
|
||||
cls.server_process.wait()
|
||||
# Kills the server subprocess and closes the temp file used for logging.
|
||||
cls.server_process_handler.clean()
|
||||
|
||||
# Remove the temporary repository directory, which should contain all the
|
||||
# metadata, targets, and key files generated for the test cases
|
||||
|
|
@ -178,8 +161,8 @@ def setUp(self):
|
|||
|
||||
# 'path/to/tmp/repository' -> 'localhost:8001/tmp/repository'.
|
||||
repository_basepath = self.repository_directory[len(os.getcwd()):]
|
||||
url_prefix = \
|
||||
'http://localhost:' + str(self.SERVER_PORT) + repository_basepath
|
||||
url_prefix = 'http://localhost:' \
|
||||
+ str(self.server_process_handler.port) + repository_basepath
|
||||
|
||||
# Setting 'tuf.settings.repository_directory' with the temporary client
|
||||
# directory copied from the original repository files.
|
||||
|
|
@ -208,7 +191,8 @@ def tearDown(self):
|
|||
tuf.roledb.clear_roledb(clear_all=True)
|
||||
tuf.keydb.clear_keydb(clear_all=True)
|
||||
|
||||
|
||||
# Logs stdout and stderr from the sever subprocess.
|
||||
self.server_process_handler.flush_log()
|
||||
|
||||
|
||||
# UNIT TESTS.
|
||||
|
|
@ -1091,16 +1075,15 @@ def test_6_get_one_valid_targetinfo(self):
|
|||
# Unlike some of the other tests, start up a fresh server here.
|
||||
# The SimpleHTTPServer started in the setupclass has a tendency to
|
||||
# timeout in Windows after a few tests.
|
||||
SERVER_PORT = random.randint(30000, 45000)
|
||||
command = ['python', self.SIMPLE_SERVER_PATH, str(SERVER_PORT)]
|
||||
server_process = subprocess.Popen(command)
|
||||
|
||||
utils.wait_for_server('localhost', SERVER_PORT)
|
||||
# Creates a subprocess running server and uses temp file for logging.
|
||||
server_process_handler = utils.TestServerProcess(log=logger,
|
||||
server=self.SIMPLE_SERVER_PATH)
|
||||
|
||||
# 'path/to/tmp/repository' -> 'localhost:8001/tmp/repository'.
|
||||
repository_basepath = self.repository_directory[len(os.getcwd()):]
|
||||
url_prefix = \
|
||||
'http://localhost:' + str(SERVER_PORT) + repository_basepath
|
||||
url_prefix = 'http://localhost:' \
|
||||
+ str(self.server_process_handler.port) + repository_basepath
|
||||
|
||||
self.repository_mirrors = {'mirror1': {'url_prefix': url_prefix,
|
||||
'metadata_path': 'metadata', 'targets_path': 'targets',
|
||||
|
|
@ -1218,8 +1201,8 @@ def test_6_get_one_valid_targetinfo(self):
|
|||
self.repository_updater.get_one_valid_targetinfo,
|
||||
'/foo/foo1.1.tar.gz')
|
||||
|
||||
server_process.kill()
|
||||
server_process.wait()
|
||||
# Kills the server subprocess and closes the temp file used for logging.
|
||||
server_process_handler.clean()
|
||||
|
||||
|
||||
|
||||
|
|
@ -1387,15 +1370,15 @@ def test_7_updated_targets(self):
|
|||
# Unlike some of the other tests, start up a fresh server here.
|
||||
# The SimpleHTTPServer started in the setupclass has a tendency to
|
||||
# timeout in Windows after a few tests.
|
||||
SERVER_PORT = random.randint(30000, 45000)
|
||||
command = ['python', self.SIMPLE_SERVER_PATH, str(SERVER_PORT)]
|
||||
server_process = subprocess.Popen(command)
|
||||
utils.wait_for_server('localhost', SERVER_PORT)
|
||||
|
||||
# Creates a subprocess running server and uses temp file for logging.
|
||||
server_process_handler = utils.TestServerProcess(log=logger,
|
||||
server=self.SIMPLE_SERVER_PATH)
|
||||
|
||||
# 'path/to/tmp/repository' -> 'localhost:8001/tmp/repository'.
|
||||
repository_basepath = self.repository_directory[len(os.getcwd()):]
|
||||
url_prefix = \
|
||||
'http://localhost:' + str(SERVER_PORT) + repository_basepath
|
||||
url_prefix = 'http://localhost:' \
|
||||
+ str(self.server_process_handler.port) + repository_basepath
|
||||
|
||||
# Setting 'tuf.settings.repository_directory' with the temporary client
|
||||
# directory copied from the original repository files.
|
||||
|
|
@ -1501,8 +1484,8 @@ def test_7_updated_targets(self):
|
|||
self.repository_updater.updated_targets(all_targets, destination_directory)
|
||||
self.assertEqual(len(updated_targets), 1)
|
||||
|
||||
server_process.kill()
|
||||
server_process.wait()
|
||||
# Kills the server subprocess and closes the temp file used for logging.
|
||||
server_process_handler.clean()
|
||||
|
||||
|
||||
|
||||
|
|
@ -1512,15 +1495,15 @@ def test_8_remove_obsolete_targets(self):
|
|||
# Unlike some of the other tests, start up a fresh server here.
|
||||
# The SimpleHTTPServer started in the setupclass has a tendency to
|
||||
# timeout in Windows after a few tests.
|
||||
SERVER_PORT = random.randint(30000, 45000)
|
||||
command = ['python', self.SIMPLE_SERVER_PATH, str(SERVER_PORT)]
|
||||
server_process = subprocess.Popen(command)
|
||||
utils.wait_for_server('localhost', SERVER_PORT)
|
||||
|
||||
# Creates a subprocess running server and uses temp file for logging.
|
||||
server_process_handler = utils.TestServerProcess(log=logger,
|
||||
server=self.SIMPLE_SERVER_PATH)
|
||||
|
||||
# 'path/to/tmp/repository' -> 'localhost:8001/tmp/repository'.
|
||||
repository_basepath = self.repository_directory[len(os.getcwd()):]
|
||||
url_prefix = \
|
||||
'http://localhost:' + str(SERVER_PORT) + repository_basepath
|
||||
url_prefix = 'http://localhost:' \
|
||||
+ str(self.server_process_handler.port) + repository_basepath
|
||||
|
||||
# Setting 'tuf.settings.repository_directory' with the temporary client
|
||||
# directory copied from the original repository files.
|
||||
|
|
@ -1603,8 +1586,8 @@ def test_8_remove_obsolete_targets(self):
|
|||
del self.repository_updater.metadata['previous']['targets']
|
||||
self.repository_updater.remove_obsolete_targets(destination_directory)
|
||||
|
||||
server_process.kill()
|
||||
server_process.wait()
|
||||
# Kills the server subprocess and closes the temp file used for logging.
|
||||
server_process_handler.clean()
|
||||
|
||||
|
||||
|
||||
|
|
@ -1872,30 +1855,25 @@ def setUp(self):
|
|||
# the pre-generated metadata files have a specific structure, such
|
||||
# as a delegated role 'targets/role1', three target files, five key files,
|
||||
# etc.
|
||||
|
||||
# The ports are harcoded because the urls to the repositories are harcoded
|
||||
# in map.json.
|
||||
self.SERVER_PORT = 30001
|
||||
self.SERVER_PORT2 = 30002
|
||||
|
||||
command = ['python', self.SIMPLE_SERVER_PATH, str(self.SERVER_PORT)]
|
||||
command2 = ['python', self.SIMPLE_SERVER_PATH, str(self.SERVER_PORT2)]
|
||||
|
||||
self.server_process = subprocess.Popen(command,
|
||||
cwd=self.repository_directory)
|
||||
# Creates a subprocess running server and uses temp file for logging.
|
||||
self.server_process_handler = utils.TestServerProcess(log=logger,
|
||||
server=self.SIMPLE_SERVER_PATH, port=self.SERVER_PORT,
|
||||
popen_cwd=self.repository_directory)
|
||||
|
||||
logger.debug('Server process started.')
|
||||
logger.debug('Server process id: ' + str(self.server_process.pid))
|
||||
logger.debug('Serving on port: ' + str(self.SERVER_PORT))
|
||||
|
||||
self.server_process2 = subprocess.Popen(command2,
|
||||
cwd=self.repository_directory2)
|
||||
# Creates a subprocess running server and uses temp file for logging.
|
||||
self.server_process_handler2 = utils.TestServerProcess(log=logger,
|
||||
server=self.SIMPLE_SERVER_PATH, port=self.SERVER_PORT2,
|
||||
popen_cwd=self.repository_directory2)
|
||||
|
||||
logger.debug('Server process 2 started.')
|
||||
logger.debug('Server 2 process id: ' + str(self.server_process2.pid))
|
||||
logger.debug('Serving 2 on port: ' + str(self.SERVER_PORT2))
|
||||
self.url = 'http://localhost:' + str(self.SERVER_PORT) + os.path.sep
|
||||
self.url2 = 'http://localhost:' + str(self.SERVER_PORT2) + os.path.sep
|
||||
|
||||
utils.wait_for_server('localhost', self.SERVER_PORT)
|
||||
utils.wait_for_server('localhost', self.SERVER_PORT2)
|
||||
|
||||
url_prefix = 'http://localhost:' + str(self.SERVER_PORT)
|
||||
url_prefix2 = 'http://localhost:' + str(self.SERVER_PORT2)
|
||||
|
|
@ -1931,16 +1909,10 @@ def tearDown(self):
|
|||
# directories that may have been created during each test case.
|
||||
unittest_toolbox.Modified_TestCase.tearDown(self)
|
||||
|
||||
# Kill the SimpleHTTPServer process.
|
||||
if self.server_process.returncode is None:
|
||||
logger.info('Server process ' + str(self.server_process.pid) + ' terminated.')
|
||||
self.server_process.kill()
|
||||
self.server_process.wait()
|
||||
|
||||
if self.server_process2.returncode is None:
|
||||
logger.info('Server 2 process ' + str(self.server_process2.pid) + ' terminated.')
|
||||
self.server_process2.kill()
|
||||
self.server_process2.wait()
|
||||
# Logs stdout and stderr from the server subprocesses and then it
|
||||
# kills them and closes the temp files used for logging.
|
||||
self.server_process_handler.clean()
|
||||
self.server_process_handler2.clean()
|
||||
|
||||
# updater.Updater() populates the roledb with the name "test_repository1"
|
||||
tuf.roledb.clear_roledb(clear_all=True)
|
||||
|
|
|
|||
|
|
@ -45,8 +45,6 @@
|
|||
import shutil
|
||||
import tempfile
|
||||
import logging
|
||||
import random
|
||||
import subprocess
|
||||
import unittest
|
||||
import filecmp
|
||||
import sys
|
||||
|
|
@ -74,8 +72,6 @@ class TestUpdater(unittest_toolbox.Modified_TestCase):
|
|||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# setUpClass() is called before tests in an individual class are executed.
|
||||
|
||||
# Create a temporary directory to store the repository, metadata, and target
|
||||
# files. 'temporary_directory' must be deleted in TearDownModule() so that
|
||||
# temporary files are always removed, even when exceptions occur.
|
||||
|
|
@ -88,32 +84,20 @@ def setUpClass(cls):
|
|||
# assume the pre-generated metadata files have a specific structure, such
|
||||
# as a delegated role 'targets/role1', three target files, five key files,
|
||||
# etc.
|
||||
cls.SERVER_PORT = random.randint(30000, 45000)
|
||||
command = ['python', 'simple_server.py', str(cls.SERVER_PORT)]
|
||||
cls.server_process = subprocess.Popen(command)
|
||||
logger.info('\n\tServer process started.')
|
||||
logger.info('\tServer process id: '+str(cls.server_process.pid))
|
||||
logger.info('\tServing on port: '+str(cls.SERVER_PORT))
|
||||
cls.url = 'http://localhost:'+str(cls.SERVER_PORT) + os.path.sep
|
||||
|
||||
utils.wait_for_server('localhost', cls.SERVER_PORT)
|
||||
cls.server_process_handler = utils.TestServerProcess(log=logger)
|
||||
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
# tearDownModule() is called after all the tests have run.
|
||||
# http://docs.python.org/2/library/unittest.html#class-and-module-fixtures
|
||||
# Kills the server subprocess and closes the temp file used for logging.
|
||||
cls.server_process_handler.clean()
|
||||
|
||||
# Remove the temporary repository directory, which should contain all the
|
||||
# metadata, targets, and key files generated for the test cases.
|
||||
shutil.rmtree(cls.temporary_directory)
|
||||
|
||||
# Kill the SimpleHTTPServer process.
|
||||
if cls.server_process.returncode is None:
|
||||
logger.info('\tServer process ' + str(cls.server_process.pid) + ' terminated.')
|
||||
cls.server_process.kill()
|
||||
|
||||
|
||||
|
||||
|
|
@ -156,8 +140,8 @@ def setUp(self):
|
|||
|
||||
# 'path/to/tmp/repository' -> 'localhost:8001/tmp/repository'.
|
||||
repository_basepath = self.repository_directory[len(os.getcwd()):]
|
||||
url_prefix = \
|
||||
'http://localhost:' + str(self.SERVER_PORT) + repository_basepath
|
||||
url_prefix = 'http://localhost:' \
|
||||
+ str(self.server_process_handler.port) + repository_basepath
|
||||
|
||||
# Setting 'tuf.settings.repository_directory' with the temporary client
|
||||
# directory copied from the original repository files.
|
||||
|
|
@ -186,7 +170,8 @@ def tearDown(self):
|
|||
tuf.roledb.clear_roledb(clear_all=True)
|
||||
tuf.keydb.clear_keydb(clear_all=True)
|
||||
|
||||
|
||||
# Logs stdout and stderr from the sever subprocess.
|
||||
self.server_process_handler.flush_log()
|
||||
|
||||
|
||||
# UNIT TESTS.
|
||||
|
|
|
|||
115
tests/utils.py
115
tests/utils.py
|
|
@ -25,6 +25,9 @@
|
|||
import logging
|
||||
import socket
|
||||
import time
|
||||
import subprocess
|
||||
import tempfile
|
||||
import random
|
||||
|
||||
import tuf.log
|
||||
|
||||
|
|
@ -49,7 +52,7 @@ def __str__(self):
|
|||
# but the current blocking connect() seems to work fast on Linux and seems
|
||||
# to at least work on Windows (ECONNREFUSED unfortunately has a 2 second
|
||||
# timeout on Windows)
|
||||
def wait_for_server(host, port, timeout=10):
|
||||
def wait_for_server(host, server, port, timeout=10):
|
||||
start = time.time()
|
||||
remaining_timeout = timeout
|
||||
succeeded = False
|
||||
|
|
@ -74,7 +77,8 @@ def wait_for_server(host, port, timeout=10):
|
|||
remaining_timeout = timeout - (time.time() - start)
|
||||
|
||||
if not succeeded:
|
||||
raise TimeoutError
|
||||
raise TimeoutError("Could not connect to the " + server \
|
||||
+ " on port " + str(port) + " !")
|
||||
|
||||
|
||||
def configure_test_logging(argv):
|
||||
|
|
@ -97,3 +101,110 @@ def configure_test_logging(argv):
|
|||
|
||||
logging.basicConfig(level=loglevel)
|
||||
tuf.log.set_log_level(loglevel)
|
||||
|
||||
|
||||
class TestServerProcess():
|
||||
"""
|
||||
<Purpose>
|
||||
Creates a child process with the subprocess.Popen object and
|
||||
TempFile object used for logging.
|
||||
|
||||
<Arguments>
|
||||
log:
|
||||
Logger which will be used for logging.
|
||||
|
||||
server:
|
||||
Path to the server to run in the subprocess.
|
||||
Default is "simpler_server.py".
|
||||
|
||||
port:
|
||||
The port used to access the server. If none is provided,
|
||||
then one will be generated.
|
||||
Default is None.
|
||||
|
||||
timeout:
|
||||
Time in seconds in which the server should start or otherwise
|
||||
TimeoutError error will be raised.
|
||||
If 0 is given, no check if the server has started will be done.
|
||||
Default is 10.
|
||||
|
||||
popen_cwd:
|
||||
Current working directory used when instancing a
|
||||
subprocess.Popen object.
|
||||
Default is "."
|
||||
|
||||
extra_cmd_args:
|
||||
List of additional arguments for the command
|
||||
which will start the subprocess.
|
||||
More precisely "python -u <path_to_server> <port> <extra_cmd_args>".
|
||||
Default is empty list.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, log, server='simple_server.py',
|
||||
port=None, timeout=10, popen_cwd=".",
|
||||
extra_cmd_args=[]):
|
||||
|
||||
# Create temporary log file used for logging stdout and stderr
|
||||
# of the subprocess. In the mode "r+"" stands for reading and writing
|
||||
# and "t" stands for text mode.
|
||||
self.__temp_log_file = tempfile.TemporaryFile(mode='r+t')
|
||||
|
||||
self.server = server
|
||||
self.port = port or random.randint(30000, 45000)
|
||||
self.__logger = log
|
||||
|
||||
# The "-u" option forces stdin, stdout and stderr to be unbuffered.
|
||||
command = ['python', '-u', server, str(self.port)] + extra_cmd_args
|
||||
|
||||
# We are reusing one server subprocess in multiple unit tests, but we are
|
||||
# collecting the logs per test.
|
||||
self.__server_process = subprocess.Popen(command,
|
||||
stdout=self.__temp_log_file, stderr=subprocess.STDOUT, cwd=popen_cwd)
|
||||
|
||||
self.__logger.info('Server process with process id ' \
|
||||
+ str(self.__server_process.pid) + " serving on port " \
|
||||
+ str(self.port) + ' started.')
|
||||
|
||||
if timeout > 0:
|
||||
try:
|
||||
wait_for_server('localhost', self.server, self.port, timeout)
|
||||
except Exception as e:
|
||||
# Make sure that errors from the server side will be logged.
|
||||
self.flush_log()
|
||||
raise e
|
||||
|
||||
|
||||
|
||||
def flush_log(self):
|
||||
"""Logs contents from TempFile, truncates buffer"""
|
||||
|
||||
# Seek is needed to move the pointer to the beginning of the file, because
|
||||
# the subprocess could have read and/or write and thus moved the pointer.
|
||||
self.__temp_log_file.seek(0)
|
||||
log_message = self.__temp_log_file.read()
|
||||
|
||||
if len(log_message) > 0:
|
||||
title = "Test server (" + self.server + ") output:"
|
||||
message = [title] + log_message.splitlines()
|
||||
self.__logger.info('\n| '.join(message))
|
||||
|
||||
# Make sure the file is empty before the next test logs new information.
|
||||
self.__temp_log_file.truncate(0)
|
||||
|
||||
|
||||
|
||||
def clean(self):
|
||||
"""Kills the subprocess and closes the TempFile.
|
||||
Calls flush_log to check for logged information, but not yet flushed."""
|
||||
|
||||
# If there is anything logged, flush it before closing the resourses.
|
||||
self.flush_log()
|
||||
|
||||
self.__temp_log_file.close()
|
||||
|
||||
if self.__server_process.returncode is None:
|
||||
self.__logger.info('Server process ' + str(self.__server_process.pid) +
|
||||
' terminated.')
|
||||
self.__server_process.kill()
|
||||
self.__server_process.wait()
|
||||
|
|
|
|||
Loading…
Reference in a new issue