From bebdab3cb53fc7e23ebba220ba7b3d150bbf07ce Mon Sep 17 00:00:00 2001 From: Kon Date: Thu, 21 Feb 2013 03:36:58 -0500 Subject: [PATCH] test_system_setup.py is complete. Few minor stylistic changes were made to download.py and signercli.py. --- tuf/download.py | 2 +- tuf/repo/signercli.py | 20 +-- tuf/tests/system_test/test_system_setup.py | 200 ++++++++++++++++++++- 3 files changed, 205 insertions(+), 17 deletions(-) diff --git a/tuf/download.py b/tuf/download.py index 9df64ca2..9d840bbc 100755 --- a/tuf/download.py +++ b/tuf/download.py @@ -175,7 +175,7 @@ def download_url_to_tempfileobj(url, required_hashes=None, required_length=None) # might put back-slashes in place of forward-slashes. This converts it to the # common format. url = url.replace('\\','/') - logger.info('Downloading '+url) + logger.info('Downloading: '+url) connection = _open_connection(url) temp_file = tuf.util.TempFile() diff --git a/tuf/repo/signercli.py b/tuf/repo/signercli.py index 5c928c78..89a81411 100755 --- a/tuf/repo/signercli.py +++ b/tuf/repo/signercli.py @@ -1226,43 +1226,43 @@ def parse_options(): # Add the options supported by 'signercli' to the option parser. option_parser.add_option('--genrsakey', action='store', type='string', - help='Generate an RSA key and save it to ' + help='Generate an RSA key and save it to '\ 'the keystore.') option_parser.add_option('--listkeys', action='store', type='string', - help='List the key IDs of the signing ' + help='List the key IDs of the signing '\ 'keys located in the keystore.') option_parser.add_option('--changepass', action='store', type='string', - help='Change the password for one of ' + help='Change the password for one of '\ 'the signing keys.') option_parser.add_option('--dumpkey', action='store', type='string', - help='Dump the contents of an encrypted ' + help='Dump the contents of an encrypted '\ 'key file.') option_parser.add_option('--makeroot', action='store', type='string', - help='Create the Root metadata file ' + help='Create the Root metadata file '\ '(root.txt).') option_parser.add_option('--maketargets', action='store', type='string', - help='Create the Targets metadata file ' + help='Create the Targets metadata file '\ '(targets.txt).') option_parser.add_option('--makerelease', action='store', type='string', - help='Create the Release metadata file ' + help='Create the Release metadata file '\ '(release.txt).') option_parser.add_option('--maketimestamp', action='store', type='string', - help='Create the Timestamp metadata file ' + help='Create the Timestamp metadata file '\ '(timestamp.txt).') option_parser.add_option('--sign', action='store', type='string', help='Sign a metadata file.') option_parser.add_option('--makedelegation', action='store', type='string', - help='Create a delegated role by creating ' - 'its metadata file and updating the parent ' + help='Create a delegated role by creating '\ + 'its metadata file and updating the parent '\ 'role\'s metadata file.') (options, remaining_arguments) = option_parser.parse_args() diff --git a/tuf/tests/system_test/test_system_setup.py b/tuf/tests/system_test/test_system_setup.py index 18082e67..15a160f4 100644 --- a/tuf/tests/system_test/test_system_setup.py +++ b/tuf/tests/system_test/test_system_setup.py @@ -1,6 +1,6 @@ """ - repository_setup.py + test_system_setup.py Konstantin Andrianov @@ -12,13 +12,15 @@ See LICENSE for licensing information. - Setup a repository structure. + Provide automatic setup and clean-up functionality. This module is based on + python's unittest. In fact the main class TestCase inherits from + unittest.TestCase. simple server --> repository_dir | -------------------------- | | - repository_file1path repository_file2path + filename1 filename2 This modules uses unittest module to provide easy setup and tear down capability. @@ -37,12 +39,73 @@ import shutil import random import urllib2 +import logging import tempfile import unittest import subprocess +import tuf.repo.signerlib as signerlib + +# Disable/Enable logging. Comment-out to Enable logging. +logging.getLogger('tuf') +logging.disable(logging.CRITICAL) + class TestCase(unittest.TestCase): + """ + + TUF: + Indicates whether or not TUF structure should be implemented. + + + repository_dir: + Repository directory, where updates are located. + + filename#: + Name of the update, which is located in the repository directory. + + server_process: + A subprocess object. + + url: + URL pointing to the repository directory ('repository_dir'). + + + TUF related instance variables. Refer to the diagram in tuf_setUp(). + + tuf_repository_dir: + A tuf repository that contains all tuf related directories, such as + metadata, targets, and keystore. (Read docs on how to handle keys!) + + tuf_metadata_dir: + Metadata directory that contains metadata files and is located in the + tuf repository directory ('tuf_repository_dir'). + + tuf_keystore_dir: + Contains all tuf keys, i.e. keys that are used to sign metadata roles. + It's located in the tuf repository directory ('tuf_repository_dir'). + + tuf_targets_dir: + All target files (updates) are stored in tuf targets directory. + It's populated using the content 'repository_dir' (devel's repository). + It's located in the tuf repository directory ('tuf_repository_dir'). + + tuf_client_dir: + Client side tuf directory. It contains current and previous metadata + files. + + tuf_client_metadata_dir: + Contains current and previous versions of metadata files. + + Note: metadata files are root.txt, targets.txt, release.txt and + timestamp.txt. There could be more metadata files such us mirrors.txt. + The metadata files are signed by their corresponding roles i.e. root, + targets etc. + + """ + + TUF = True + def setUp(self): unittest.TestCase.setUp(self) @@ -50,8 +113,8 @@ def setUp(self): self.repository_dir = tempfile.mkdtemp(dir=os.getcwd()) repository_file1 = tempfile.mkstemp(dir=self.repository_dir) repository_file2 = tempfile.mkstemp(dir=self.repository_dir) - self.repository_file1path = os.path.basename(repository_file1[1]) - self.repository_file2path = os.path.basename(repository_file2[1]) + self.filename1 = os.path.basename(repository_file1[1]) + self.filename2 = os.path.basename(repository_file2[1]) fileobj = open(repository_file1[1], 'wb') fileobj.write('System Test File 1') fileobj.close() @@ -71,17 +134,24 @@ def setUp(self): # time.sleep(.1) + if self.TUF is True: + self.tuf_setUp() + def tearDown(self): unittest.TestCase.tearDown(self) if self.server_process.returncode is None: + print 'Server terminated.' self.server_process.kill() # Removing repository directory. shutil.rmtree(self.repository_dir) + if self.TUF is True: + self.tuf_tearDown() + @staticmethod @@ -102,11 +172,129 @@ def client_download(self, filename): + def tuf_setUp(self): + """ + + Setup TUF directory structure and populated it with TUF metadata and + congfiguration files. + + tuf_repository_dir + | + -------------------------------------------- + | | | + keystore metadata targets + | | | + key.key files role.txt files targets (updates) + ... ... ... + + + tuf_client_dir + | + metadata + | + --------------------------- + | | + current previous + | | + role.txt files role.txt files + ... ... + + """ + + passwd = 'test' + threshold = 1 + + # Setup TUF directory structure. + self.tuf_repository_dir = tempfile.mkdtemp(suffix='tuf_r', dir=os.getcwd()) + self.tuf_client_dir = tempfile.mkdtemp(suffix='tuf_c', dir=os.getcwd()) + self.tuf_keystore_dir = os.path.join(self.tuf_repository_dir, 'keystore') + self.tuf_metadata_dir = os.path.join(self.tuf_repository_dir, 'metadata') + os.mkdir(self.tuf_keystore_dir) + os.mkdir(self.tuf_metadata_dir) + self.tuf_targets_dir = os.path.join(self.tuf_repository_dir, 'targets') + shutil.copytree(self.repository_dir, self.tuf_targets_dir) + + # Generate at least one rsa key. + key = signerlib.generate_and_save_rsa_key(self.tuf_keystore_dir, passwd) + + # Set some role info. + info = {'keyids': [key['keyid']], 'threshold': threshold} + + # Setup keystore. 'role_info' dictionary looks like this: + # {'keyids : [keyid1, ...] , 'threshold' : 2} + # In our case 'role_info[keyids]' will only have on entry since only one + # is being used. + role_info = {} + role_list = ['root', 'targets', 'release', 'timestamp'] + for role in role_list: + role_info[role] = info + + # At this point there is enough information to create TUF configuration + # and metadata files. + + # Build the configuration file. + conf_filepath = signerlib.build_config_file(self.repository_dir, 365, role_info) + + # Generate the 'root.txt' metadata file. + keyid = [key['keyid']] + signerlib.build_root_file(conf_filepath, keyid, self.tuf_metadata_dir) + + # Generate the 'targets.txt' metadata file. + signerlib.build_targets_file(self.tuf_targets_dir, keyid, self.tuf_metadata_dir) + + # Generate the 'release.txt' metadata file. + signerlib.build_release_file(keyid, self.tuf_metadata_dir) + + # Generate the 'timestamp.txt' metadata file. + signerlib.build_timestamp_file(keyid, self.tuf_metadata_dir) + + # Setting up client's TUF directory structure. + # 'tuf.client.updater.py' expects the 'current' and 'previous' + # directories to exist under client's 'metadata' directory. + self.tuf_client_metadata_dir = os.path.join(self.tuf_client_dir, 'metadata') + os.mkdir(self.tuf_client_metadata_dir) + + # Move the metadata to the client's 'current' and 'previous' directories. + self.client_current = os.path.join(self.tuf_client_metadata_dir, 'current') + self.client_previous = os.path.join(self.tuf_client_metadata_dir, 'previous') + shutil.copytree(self.tuf_metadata_dir, self.client_current) + shutil.copytree(self.tuf_metadata_dir, self.client_previous) + + + + def tuf_tearDown(self): + """ + + The clean-up method, removes all TUF directories created using + tuf_setUp(). + """ + shutil.rmtree(self.tuf_repository_dir) + shutil.rmtree(self.tuf_client_dir) + + + # Quick internal test to see if everything runs smoothly. def test_client_download(self): - data = self.client_download(self.repository_file1path) + data = self.client_download(self.filename1) self.assertEquals(data, 'System Test File 1') + # Verify that all necessary paths exist. + for role in ['root', 'targets', 'release', 'timestamp']: + # Repository side. + role_file = os.path.join(self.tuf_metadata_dir, role+'.txt') + self.assertTrue(os.path.isfile(role_file)) + + # Client side. + role_file = os.path.join(self.client_current, role+'.txt') + self.assertTrue(os.path.isfile(role_file)) + + target1 = os.path.join(self.tuf_targets_dir, self.filename1) + target2 = os.path.join(self.tuf_targets_dir, self.filename2) + self.assertTrue(os.path.isfile(target1)) + self.assertTrue(os.path.isfile(target2)) + + + if __name__=='__main__':