#!/usr/bin/env python """ test_interpose_updater.py Pankhuri Goyal August 2014. See LICENSE for licensing information. Unit test for 'tuf.interposition.updater.py'. """ from __future__ import print_function from __future__ import absolute_import from __future__ import division from __future__ import unicode_literals import os import sys import tempfile import subprocess import random import shutil import logging import time import copy import json import tuf import tuf.util import tuf.conf import tuf.log import tuf.interposition.updater as updater import tuf.interposition.configuration as configuration import tuf.unittest_toolbox as unittest_toolbox if sys.version_info >= (2, 7): import unittest else: import unittest2 as unittest logger = logging.getLogger('tuf.test_interpose_updater') class TestUpdaterController(unittest_toolbox.Modified_TestCase): @classmethod def setUpClass(cls): # This method is called before tests in 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. cls.temporary_directory = tempfile.mkdtemp(dir=os.getcwd()) # Launch a SimpleHTTPServer (serves files in the current directory). # Test cases will request metadata and target files that have been # pre-generated in 'tuf/tests/repository_data', which will be served # by the SimpleHTTPServer launched here. The test cases of # 'test_updater.py' 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, stderr=subprocess.PIPE) 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 time.sleep(1) @classmethod def tearDownClass(cls): # Remove the temporary directory after all the tests are done. shutil.rmtree(cls.temporary_directory) # Kill the SimpleHTTPServer Process if cls.server_process is None: message = '\tServer process ' + str(cls.server_process.pid) + \ ' terminated.' logger.info(message) cls.server_process.kill() def setUp(self): # We are inheriting from custom class. unittest_toolbox.Modified_TestCase.setUp(self) # Copy the original repository files provided in the test folder so that # any modifications made to repository files are restricted to the copies. # The 'repository_data' directory is expected to exist in 'tuf.tests/'. original_repository_files = os.path.join(os.getcwd(), 'repository_data') temporary_repository_root = \ self.make_temp_directory(directory=self.temporary_directory) # The original repository, keystore, and client directories will be copied # for each test case. original_repository = os.path.join(original_repository_files, 'repository') original_keystore = os.path.join(original_repository_files, 'keystore') original_client = os.path.join(original_repository_files, 'client') # Save references to the often-needed client repository directories. # Test cases need these references to access metadata and target files. self.repository_directory = \ os.path.join(temporary_repository_root, 'repository') self.keystore_directory = \ os.path.join(temporary_repository_root, 'keystore') self.client_directory = os.path.join(temporary_repository_root, 'client') self.client_metadata = os.path.join(self.client_directory, 'metadata') self.client_metadata_current = os.path.join(self.client_metadata, 'current') self.client_metadata_previous = \ os.path.join(self.client_metadata, 'previous') # Copy the original 'repository', 'client', and 'keystore' directories # to the temporary repository the test cases can use. shutil.copytree(original_repository, self.repository_directory) shutil.copytree(original_client, self.client_directory) shutil.copytree(original_keystore, self.keystore_directory) # 'path/to/tmp/repository' -> 'localhost:8001/tmp/repository'. repository_basepath = self.repository_directory[len(os.getcwd()):] # Test Set 1 - port = self.SERVER_PORT url_prefix = 'http://localhost:' + str(port) + repository_basepath # Setting 'tuf.conf.repository_directory' with the temporary client # directory copied from the original repository files. tuf.conf.repository_directory = self.client_directory self.repository_mirrors = {'mirror': {'url_prefix': url_prefix, 'metadata_path': 'metadata', 'targets_path': 'targets', 'confined_target_dirs': ['']} } self.target_filepath = [{".*/targets":"/file1.txt"}] self.good_configuration = configuration.Configuration('localhost', 8001, self.client_directory, self.repository_mirrors, self.target_filepath, None) self.test1_configuration = configuration.Configuration('localhost', port, self.client_directory, self.repository_mirrors, 'targets', None) self.test2_configuration = configuration.Configuration('localhost', 8002, self.client_directory, self.repository_mirrors, 'targets', None) test_server_port=random.randint(30000, 45000) self.test3_configuration = configuration.Configuration('localhost', test_server_port, self.client_directory, self.repository_mirrors, 'targets', None) url_prefix_test = \ 'http://localhost:' + str(test_server_port) + repository_basepath self.repository_mirrors = {'mirror': {'url_prefix': url_prefix_test, 'metadata_path': 'metadata', 'targets_path': 'targets', 'confined_target_dirs': ['']} } self.test4_configuration = configuration.Configuration('localhost', 8004, self.client_directory, self.repository_mirrors, 'targets', None) def tearDown(self): # We are inheriting from custom class. unittest_toolbox.Modified_TestCase.tearDown(self) # Unit Tests def test_add(self): updater_controller = updater.UpdaterController() # Given good configuration, the UpdaterController.add() should work. updater_controller.add(self.good_configuration) # Instead of configuration, if some number is given. self.assertRaises(tuf.InvalidConfigurationError, updater_controller.add, 8) # Hostname already exists, should raise exception. self.assertRaises(tuf.FormatError, updater_controller.add, self.good_configuration) # Hostname already exists as a mirror, should raise an exception. self.assertRaises(tuf.FormatError, updater_controller.add, self.test1_configuration) # Repository mirror already exists as another mirror. self.assertRaises(tuf.FormatError, updater_controller.add, self.test2_configuration) # Remove the old updater. updater_controller.remove(self.good_configuration) # Add a new updater for this test. updater_controller.add(self.test3_configuration) # Repository mirror already exists as an updater. self.assertRaises(tuf.FormatError, updater_controller.add, self.test4_configuration) # Remove the updater once the testing is completed. updater_controller.remove(self.test3_configuration) def test_refresh(self): updater_controller = updater.UpdaterController() # To check refresh() method, add a configuration for test. updater_controller.add(self.good_configuration) updater_controller.refresh(self.good_configuration) # Check for invalid configuration error. self.assertRaises(tuf.InvalidConfigurationError, updater_controller.refresh, 8) # Check if the updater not added in the updater list is refreshed, gives an # error or not. self.assertRaises(tuf.NotFoundError, updater_controller.refresh, self.test1_configuration) # Giving the same port number and network location as good_configuration. self.test4_configuration.port = 8001 self.test4_configuration.network_location = 'localhost:8001' # Check if the mirror not added is refreshed, gives an error or not. self.assertRaises(tuf.NotFoundError, updater_controller.refresh, self.test4_configuration) # Make an object of tuf.interposition.updater.Updater of good configuration # for testing. good_updater = updater.Updater(self.good_configuration) good_updater.refresh() self.good_configuration.repository_mirrors['mirror']['url_prefix'] = \ 'http://localhost:99999999' # To check if a bad url_prefix of a mirror raises an exception or not. self.assertRaises(tuf.NoWorkingMirrorError, good_updater.refresh) def test_get(self): updater_controller = updater.UpdaterController() updater_controller.add(self.good_configuration) url = 'http://localhost:8001' updater_controller.get(url) wrong_url = 'http://localhost:9999' updater_controller.get(wrong_url) good_updater = updater.Updater(self.good_configuration) self.assertRaises(tuf.URLMatchesNoPatternError, good_updater.get_target_filepath, url) def test_remove(self): updater_controller = updater.UpdaterController() # To check remove() method, add a configuration for test. updater_controller.add(self.good_configuration) # Check for invalid configuration error. self.assertRaises(tuf.InvalidConfigurationError, updater_controller.remove, 8) self.assertRaises(tuf.NotFoundError, updater_controller.remove, self.test1_configuration) # Giving the same port number and network location as good_configuration. self.test4_configuration.port = 8001 self.test4_configuration.network_location = 'localhost:8001' self.assertRaises(tuf.NotFoundError, updater_controller.remove, self.test4_configuration) class TestUpdater(unittest_toolbox.Modified_TestCase): @classmethod def setUpClass(cls): # This method is called before tests in 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. cls.temporary_directory = tempfile.mkdtemp(dir=os.getcwd()) # Launch a SimpleHTTPServer (serves files in the current directory). # Test cases will request metadata and target files that have been # pre-generated in 'tuf/tests/repository_data', which will be served # by the SimpleHTTPServer launched here. The test cases of # 'test_updater.py' 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, stderr=subprocess.PIPE) 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 time.sleep(1) @classmethod def tearDownClass(cls): # Remove the temporary directory after all the tests are done. shutil.rmtree(cls.temporary_directory) # Kill the SimpleHTTPServer Process if cls.server_process is None: message = '\tServer process ' + str(cls.server_process.pid) + \ ' terminated.' logger.info(message) cls.server_process.kill() def setUp(self): # We are inheriting from custom class. unittest_toolbox.Modified_TestCase.setUp(self) # Copy the original repository files provided in the test folder so that # any modifications made to repository files are restricted to the copies. # The 'repository_data' directory is expected to exist in 'tuf.tests/'. original_repository_files = os.path.join(os.getcwd(), 'repository_data') temporary_repository_root = \ self.make_temp_directory(directory=self.temporary_directory) # The original repository, keystore, and client directories will be copied # for each test case. original_repository = os.path.join(original_repository_files, 'repository') original_keystore = os.path.join(original_repository_files, 'keystore') original_client = os.path.join(original_repository_files, 'client') # Save references to the often-needed client repository directories. # Test cases need these references to access metadata and target files. self.repository_directory = \ os.path.join(temporary_repository_root, 'repository') self.keystore_directory = \ os.path.join(temporary_repository_root, 'keystore') self.client_directory = os.path.join(temporary_repository_root, 'client') self.client_metadata = os.path.join(self.client_directory, 'metadata') self.client_metadata_current = os.path.join(self.client_metadata, 'current') self.client_metadata_previous = \ os.path.join(self.client_metadata, 'previous') # Copy the original 'repository', 'client', and 'keystore' directories # to the temporary repository the test cases can use. shutil.copytree(original_repository, self.repository_directory) shutil.copytree(original_client, self.client_directory) shutil.copytree(original_keystore, self.keystore_directory) # 'path/to/tmp/repository' -> 'localhost:8001/tmp/repository'. repository_basepath = self.repository_directory[len(os.getcwd()):] # Test Set 1 - port = self.SERVER_PORT url_prefix = 'http://localhost:' + str(port) + repository_basepath # Setting 'tuf.conf.repository_directory' with the temporary client # directory copied from the original repository files. tuf.conf.repository_directory = self.client_directory self.repository_mirrors = {'mirror': {'url_prefix': url_prefix, 'metadata_path': 'metadata', 'targets_path': 'targets', 'confined_target_dirs': ['']} } self.target_paths = [{".*/targets":"/file1.txt"}] self.good_configuration = configuration.Configuration('localhost', 8001, self.client_directory, self.repository_mirrors, self.target_paths, None) def tearDown(self): # We are inheriting from custom class. unittest_toolbox.Modified_TestCase.tearDown(self) # Unit Tests def test_download_target(self): myUpdater = updater.Updater(self.good_configuration) target_filepath = 'file.txt' self.assertRaises(tuf.UnknownTargetError, myUpdater.download_target, target_filepath) self.assertRaises(tuf.FormatError, myUpdater.download_target, 8) target_filepath = 'file1.txt' myUpdater.download_target(target_filepath) def test_get_target_filepath(self): myUpdater = updater.Updater(self.good_configuration) self.assertRaises(AttributeError, myUpdater.get_target_filepath, 8) test_source_url = 'http://localhost:9999' self.assertRaises(tuf.URLMatchesNoPatternError, myUpdater.get_target_filepath, test_source_url) test_source_url = 'http://localhost:8001/targets/file.txt' myUpdater.get_target_filepath(test_source_url) def test_open(self): myUpdater = updater.Updater(self.good_configuration) self.assertRaises(AttributeError, myUpdater.open, 8) url = 'http://localhost:8001/targets/file1.txt' myUpdater.open(url, 'interposition.json') def test_retrieve(self): myUpdater = updater.Updater(self.good_configuration) self.assertRaises(AttributeError, myUpdater.retrieve, 8) test_source_url = 'http://localhost:8001/targets/file1.txt' myUpdater.retrieve(test_source_url, 'interposition.json') #self.assertRaises(tuf.NoWorkingMirrorError, myUpdater.retrieve, test_source_url) test_source_url = 'http://6767:localhost' self.assertRaises(tuf.URLMatchesNoPatternError, myUpdater.retrieve, test_source_url) test_source_url = 'http://localhost:8001/targets/file1.txt' myUpdater.retrieve(test_source_url) if __name__ == '__main__': unittest.main()