Merge pull request #1104 from MVrachev/silence-log-with-temp-files

Log subproceses stdout and stderr in temp files
This commit is contained in:
Joshua Lock 2020-10-01 12:40:23 +01:00 committed by GitHub
commit fb2eaa5f23
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 338 additions and 489 deletions

View file

@ -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:

View file

@ -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):

View file

@ -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)

View file

@ -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,

View file

@ -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

View file

@ -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()

View file

@ -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

View file

@ -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):

View file

@ -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

View file

@ -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.

View file

@ -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:

View file

@ -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))

View file

@ -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)

View file

@ -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:

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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.

View file

@ -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()