python-tuf/tests/test_developer_tool.py
Santiago Torres 26eb5b7e35 Added relative filepath support and increased coverage
After seeing the coveralls report I realized the projects were not
relocatable. While this might be convenient for some uses, moving a
project from one place to another might not be optimal. This has been
changed now.

The only place where absolute filepaths are handled now is with flat
project layouts. However, it is possible to overwrite this filepath if
the targets folder is to be changed.
2014-06-21 19:07:34 -04:00

447 lines
15 KiB
Python
Executable file

#!/usr/bin/env python
"""
<Program Name>
test_developer_tool.py
<Authors>
Santiago Torres Arias <torresariass@gmail.com
Zane Fisher <zanefisher@gmail.com>
<Copyright>
See LICENSE for licensing inforation
<Purpose>
Unit tests for the 'developer_tool' module
"""
import os
import time
import datetime
import unittest
import logging
import tempfile
import shutil
import tuf
import tuf.log
import tuf.formats
import tuf.roledb
import tuf.keydb
import tuf.developer_tool as developer_tool
from tuf.developer_tool import METADATA_DIRECTORY_NAME
from tuf.developer_tool import TARGETS_DIRECTORY_NAME
logger = logging.getLogger("tuf.test_developer_tool")
class TestProject(unittest.TestCase):
tmp_dir = None
@classmethod
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
tuf.roledb.clear_roledb()
tuf.keydb.clear_keydb()
pass
def test_emtpy(self):
return
def test_create_new_project(self):
# test cases for the create_new_project function. In this test we will
# check input, correct file creation and format. We also check
# that a proper object is generated. We will use the normal layout for this
# test suite.
# create a local subfolder for this test.
local_tmp = tempfile.mkdtemp(dir = self.tmp_dir)
# these are the usual values we will be throwing to the function, however
# we will swap these for nulls or malformed values every now and then to
# test input
project_name = "test_suite"
metadata_directory = local_tmp
location_in_repository = '/prefix'
targets_directory = None
key = None
# create a blank project
project = developer_tool.create_new_project(project_name, metadata_directory,
location_in_repository)
self.assertTrue(isinstance(project, developer_tool.Project))
self.assertTrue(project.layout_type == 'repo-like')
self.assertTrue(project.prefix == location_in_repository)
self.assertTrue(project._project_name == project_name)
self.assertTrue(project._metadata_directory ==
os.path.join(metadata_directory,METADATA_DIRECTORY_NAME))
self.assertTrue(project._targets_directory ==
os.path.join(metadata_directory,TARGETS_DIRECTORY_NAME))
# create a blank project without a prefix
project = developer_tool.create_new_project(project_name, metadata_directory)
self.assertTrue(isinstance(project, developer_tool.Project))
self.assertTrue(project.layout_type == 'repo-like')
self.assertTrue(project.prefix == '')
self.assertTrue(project._project_name == project_name)
self.assertTrue(project._metadata_directory ==
os.path.join(metadata_directory,METADATA_DIRECTORY_NAME))
self.assertTrue(project._targets_directory ==
os.path.join(metadata_directory,TARGETS_DIRECTORY_NAME))
# create a blank project without a valid metadata directory
self.assertRaises(tuf.FormatError, developer_tool.create_new_project,
0, metadata_directory, location_in_repository)
self.assertRaises(tuf.FormatError, developer_tool.create_new_project,
project_name, 0, location_in_repository)
self.assertRaises(tuf.FormatError, developer_tool.create_new_project,
project_name, metadata_directory, 0)
# create a new project with a flat layout
targets_directory = tempfile.mkdtemp(dir = local_tmp)
metadata_directory = tempfile.mkdtemp(dir = local_tmp)
project = developer_tool.create_new_project(project_name, metadata_directory,
location_in_repository, targets_directory)
self.assertTrue(isinstance(project, developer_tool.Project))
self.assertTrue(project.layout_type == 'flat')
self.assertTrue(project.prefix == location_in_repository)
self.assertTrue(project._project_name == project_name)
self.assertTrue(project._metadata_directory == metadata_directory)
self.assertTrue(project._targets_directory == targets_directory)
# finally, check that if targets_directory is set, it is valid
self.assertRaises(tuf.FormatError, developer_tool.create_new_project,
project_name, metadata_directory, location_in_repository, 0)
# copy a key to our workspace and create a new project with it.
keystore_path = os.path.join('repository_data','keystore')
# I will use the same key as the one provided in the repository
# tool tests for the root role, but this is not a root role...
root_key_path = os.path.join(keystore_path,'root_key.pub')
project_key = developer_tool.import_rsa_publickey_from_file(root_key_path)
# test create new project with a key added by default
project = developer_tool.create_new_project(project_name, metadata_directory,
location_in_repository, targets_directory, project_key)
self.assertTrue(isinstance(project, developer_tool.Project))
self.assertTrue(project.layout_type == 'flat')
self.assertTrue(project.prefix == location_in_repository)
self.assertTrue(project._project_name == project_name)
self.assertTrue(project._metadata_directory == metadata_directory)
self.assertTrue(project._targets_directory == targets_directory)
self.assertTrue(len(project.keys) == 1)
self.assertTrue(project.keys[0] == project_key['keyid'])
# set as readonly and try to write a repo
shutil.rmtree(targets_directory)
os.chmod(local_tmp, 0o0555)
tuf.roledb.clear_roledb()
tuf.keydb.clear_keydb()
self.assertRaises(OSError, developer_tool.create_new_project ,project_name,
metadata_directory, location_in_repository, targets_directory,
project_key)
os.chmod(local_tmp, 0o0777)
shutil.rmtree(metadata_directory)
os.chmod(local_tmp, 0o0555)
tuf.roledb.clear_roledb()
tuf.keydb.clear_keydb()
self.assertRaises(OSError, developer_tool.create_new_project ,project_name,
metadata_directory, location_in_repository, targets_directory,
project_key)
os.chmod(local_tmp, 0o0777)
shutil.rmtree(local_tmp)
def test_load_project(self):
# this test case will try to load an existing project and test for the result
# then we will try to load a nonexisting project and expect a correct error
# handler
# finally, we will try to overwrite the existing prefix on the loaded project
# create a local subfolder for this test.
local_tmp = tempfile.mkdtemp(dir = self.tmp_dir)
# test inexisting project filepath
nonexistent_path = os.path.join(local_tmp, "nonexistent")
self.assertRaises(IOError, developer_tool.load_project, nonexistent_path)
# copy the pregenerated metadata
project_data_filepath = os.path.join('repository_data', 'project')
target_project_data_filepath = os.path.join(local_tmp, 'project')
shutil.copytree("repository_data/project", target_project_data_filepath)
# load a project properly...
repo_filepath = os.path.join(local_tmp, 'project', 'test-repo')
project = developer_tool.load_project(repo_filepath)
self.assertTrue(project.layout_type == "repo-like")
repo_filepath = os.path.join(local_tmp, 'project', 'test-flat')
new_targets_path = os.path.join(local_tmp, 'project', 'targets')
project = developer_tool.load_project(repo_filepath,
new_targets_location = new_targets_path)
self.assertTrue(project._targets_directory == new_targets_path)
self.assertTrue(project.layout_type == 'flat')
# load a project ovrwriting the prefix
project = developer_tool.load_project(repo_filepath, prefix='new')
self.assertTrue(project.prefix == 'new')
# load a project with a file missing
file_to_corrupt = os.path.join(repo_filepath, 'test-flat','role1.json')
with open(file_to_corrupt, 'wt') as fp:
fp.write("this is not a json file")
self.assertRaises(tuf.Error, developer_tool.load_project, repo_filepath)
def test_add_verification_keys(self):
# maybe we need to clear the roledb and keydb
# create a new project instance
project = developer_tool.Project("test_verification_keys", "somepath",
"someotherpath", "prefix")
# add invalid verification key
self.assertRaises(tuf.FormatError, project.add_verification_key, "invalid")
# add verification key
# - load it first
keystore_path = os.path.join('repository_data','keystore')
first_verification_key_path = os.path.join(keystore_path,'root_key.pub')
first_verification_key = \
developer_tool.import_rsa_publickey_from_file(first_verification_key_path)
project.add_verification_key(first_verification_key)
# add another verification key (should expect exception)
second_verification_key_path = os.path.join(keystore_path,'snapshot_key.pub')
second_verification_key = \
developer_tool.import_rsa_publickey_from_file(second_verification_key_path)
self.assertRaises(tuf.Error,
project.add_verification_key,(second_verification_key))
# add a verification key for the delegation
project.delegate("somedelegation", [], [])
project("somedelegation").add_verification_key(first_verification_key)
project("somedelegation").add_verification_key(second_verification_key)
# add another delegation of the delegation
project("somedelegation").delegate("somesubdelegation", [], [])
project("somedelegation")("somesubdelegation").add_verification_key(
first_verification_key)
project("somedelegation")("somesubdelegation").add_verification_key(
second_verification_key)
def test_write(self):
# create tmp directory
local_tmp = tempfile.mkdtemp(dir=self.tmp_dir)
# create new project inside tmp directory
project = developer_tool.create_new_project("test_write", local_tmp,
"prefix");
# create some target files inside the tmp directory
target_filepath = os.path.join(local_tmp, "targets", "test_target")
with open(target_filepath, "wt") as fp:
fp.write("testing file")
# add the targets
project.add_target(target_filepath)
# add verification keys
keystore_path = os.path.join('repository_data','keystore')
project_key_path = os.path.join(keystore_path,'root_key.pub')
project_key = \
developer_tool.import_rsa_publickey_from_file(project_key_path)
# call status (for the sake of doing it)
project.status()
project.add_verification_key(project_key)
# add another verification key (should expect exception)
delegation_key_path = os.path.join(keystore_path,'snapshot_key.pub')
delegation_key = \
developer_tool.import_rsa_publickey_from_file(delegation_key_path)
# add a subdelegation
subdelegation_key_path = os.path.join(keystore_path,'timestamp_key.pub')
subdelegation_key = \
developer_tool.import_rsa_publickey_from_file(subdelegation_key_path)
# add a delegation
project.delegate("delegation", [delegation_key], [])
project("delegation").delegate("subdelegation", [subdelegation_key], [])
# call write (except)
self.assertRaises(tuf.Error, project.write, ())
# call status (for the sake of doing it)
project.status()
# load private keys
project_private_key_path = os.path.join(keystore_path, 'root_key')
project_private_key = \
developer_tool.import_rsa_privatekey_from_file(project_private_key_path,
'password')
delegation_private_key_path = os.path.join(keystore_path, 'snapshot_key')
delegation_private_key = \
developer_tool.import_rsa_privatekey_from_file(delegation_private_key_path,
'password')
subdelegation_private_key_path = \
os.path.join(keystore_path, 'timestamp_key')
subdelegation_private_key = \
developer_tool.import_rsa_privatekey_from_file(subdelegation_private_key_path,
'password')
# test partial write
# backup everything (again)
# + backup targets:
targets_backup = project.target_files
# + backup delegations
delegations_backup = \
tuf.roledb.get_delegated_rolenames(project._project_name)
# + backup layout type
layout_type_backup = project.layout_type
# + backup keyid's
keys_backup = project.keys
delegation_keys_backup = project("delegation").keys
# + backup the prefix
prefix_backup = project.prefix
# + backup the name
name_backup = project._project_name
# set the compressions, we will be checking this part here too
project.compressions = ['gz']
project('delegation').compressions = project.compressions
# write and reload
self.assertRaises(tuf.Error, project.write)
project.write(write_partial=True)
project = developer_tool.load_project(local_tmp)
# check against backup
self.assertEquals(project.target_files, targets_backup)
new_delegations = tuf.roledb.get_delegated_rolenames(project._project_name)
self.assertEquals(new_delegations, delegations_backup)
self.assertEquals(project.layout_type, layout_type_backup)
self.assertEquals(project.keys, keys_backup)
self.assertEquals(project("delegation").keys, delegation_keys_backup)
self.assertEquals(project.prefix, prefix_backup)
self.assertEquals(project._project_name, name_backup)
roleinfo = tuf.roledb.get_roleinfo(project._project_name)
self.assertEquals(roleinfo['partial_loaded'], True)
# load_signing_keys
project("delegation").load_signing_key(delegation_private_key)
project.status()
project("delegation")("subdelegation").load_signing_key(
subdelegation_private_key)
# import pdb; pdb.set_trace()
project.status()
project.load_signing_key(project_private_key)
# backup everything
# + backup targets:
targets_backup = project.target_files
# + backup delegations
delegations_backup = \
tuf.roledb.get_delegated_rolenames(project._project_name)
# + backup layout type
layout_type_backup = project.layout_type
# + backup keyid's
keys_backup = project.keys
delegation_keys_backup = project("delegation").keys
# + backup the prefix
prefix_backup = project.prefix
# + backup the name
name_backup = project._project_name
# call status (for the sake of doing it)
project.status()
# call write
project.write()
# call load
project = developer_tool.load_project(local_tmp)
# check against backup
self.assertEquals(project.target_files, targets_backup)
new_delegations = tuf.roledb.get_delegated_rolenames(project._project_name)
self.assertEquals(new_delegations, delegations_backup)
self.assertEquals(project.layout_type, layout_type_backup)
self.assertEquals(project.keys, keys_backup)
self.assertEquals(project("delegation").keys, delegation_keys_backup)
self.assertEquals(project.prefix, prefix_backup)
self.assertEquals(project._project_name, name_backup)
if __name__ == '__main__':
unittest.main()