Added even more information to the tool_test_errors dict. Separated failed and passed tests in the metadata record. Added documentation.

This commit is contained in:
Dave Bouvier
2013-03-08 14:25:06 -05:00
parent e80abf9214
commit b84b45e7d0
3 changed files with 255 additions and 66 deletions
@@ -38,7 +38,16 @@ def main():
'''Script that checks repositories to see if the tools contained within them have functional tests defined.'''
parser = OptionParser()
parser.add_option( "-i", "--info_only", action="store_true", dest="info_only", help="info about the requested action", default=False )
parser.add_option( "-v", "--verbose", action="store_true", dest="verbose", help="verbose mode, print the name, owner, and changeset revision of each repository", default=False )
parser.add_option(
"-v", "--verbose",
action="count", dest="verbosity",
default=1,
help="Control the amount of detail in the log output.")
parser.add_option(
"--verbosity", action="store", dest="verbosity",
metavar='VERBOSITY',
type="int", help="Control the amount of detail in the log output. --verbosity=1 is "
"the same as -v")
( options, args ) = parser.parse_args()
ini_file = args[0]
config_parser = ConfigParser.ConfigParser( {'here':os.getcwd()} )
@@ -56,12 +65,12 @@ def main():
if options.info_only:
print "# Displaying info only ( --info_only )"
if options.verbose:
print "# Displaying extra information ( --verbose )"
if options.verbosity:
print "# Displaying extra information ( --verbosity = %d )" % options.verbosity
check_and_flag_repositories( app, info_only=options.info_only, verbose=options.verbose )
check_and_flag_repositories( app, info_only=options.info_only, verbosity=options.verbosity )
def check_and_flag_repositories( app, info_only=False, verbose=False ):
def check_and_flag_repositories( app, info_only=False, verbosity=1 ):
'''
This method will iterate through all records in the repository_metadata table, checking each one for tool metadata,
then checking the tool metadata for tests.
@@ -97,10 +106,15 @@ def check_and_flag_repositories( app, info_only=False, verbose=False ):
and test repositories script to process. If the tested changeset revision does not have a test-data directory, this script will also mark the revision
not to be tested.
If any error is encountered, the script will update the repository_metadata.tool_test_errors attribute with the following structure:
If any error is encountered, the script will update the repository_metadata.tool_test_errors attribute following this structure:
{
"test_environment":
{
"galaxy_revision": "9001:abcd1234",
"galaxy_database_version": "114",
"tool_shed_revision": "9001:abcd1234",
"tool_shed_mercurial_version": "2.3.1",
"tool_shed_database_version": "17",
"python_version": "2.7.2",
"architecture": "x86_64",
"system": "Darwin 12.2.0"
@@ -108,8 +122,28 @@ def check_and_flag_repositories( app, info_only=False, verbose=False ):
"test_errors":
[
{
"test_id": "Something that will easily identify what the problem is",
"stdout": "The output of the test, or a more detailed description of what was tested and why it failed."
"test_id": "The test ID, generated by twill",
"tool_id": "The tool ID that was tested",
"tool_version": "The tool version that was tested",
"stderr": "The output of the test, or a more detailed description of what was tested and what the error was."
"traceback": "The traceback, if any."
},
]
"passed_tests":
[
{
"test_id": "The test ID, generated by twill",
"tool_id": "The tool ID that was tested",
"tool_version": "The tool version that was tested",
},
]
"invalid_tests":
[
{
"tool_id": "The tool ID that does not have functional tests defined.",
"tool_version": "The version of the tool."
"tool_guid": "The guid of the tool."
"reason_test_is_invalid": "A short explanation of what is invalid.
},
]
}
@@ -129,19 +163,24 @@ def check_and_flag_repositories( app, info_only=False, verbose=False ):
repository_status[ 'test_environment' ][ 'tool_shed_database_version' ] = get_database_version( app )
repository_status[ 'test_environment' ][ 'tool_shed_mercurial_version' ] = __version__.version
repository_status[ 'test_environment' ][ 'tool_shed_revision' ] = get_repository_current_revision( os.getcwd() )
repository_status[ 'test_errors' ] = []
repository_status[ 'invalid_tests' ] = []
metadata_records_to_check = app.sa_session.query( app.model.RepositoryMetadata ) \
.filter( and_( app.model.RepositoryMetadata.table.c.downloadable == True,
app.model.RepositoryMetadata.table.c.do_not_test == False,
app.model.RepositoryMetadata.table.c.tools_functionally_correct == False ) ) \
.all()
for metadata_record in metadata_records_to_check:
repository_status[ 'test_errors' ] = []
if metadata_record.tool_test_errors:
repository_status = metadata_record.tool_test_errors
name = metadata_record.repository.name
owner = metadata_record.repository.user.username
changeset_revision = str( metadata_record.changeset_revision )
repository_status[ 'invalid_tests' ] = []
if metadata_record.repository.id not in checked_repository_ids:
checked_repository_ids.append( metadata_record.repository.id )
if verbosity >= 1:
print '# Checking for functional tests in changeset revision %s of %s, owned by %s.' % \
( changeset_revision, name, owner )
# If this changeset revision has no tools, we don't need to do anything here, the install and test script has a filter for returning
# only repositories that contain tools.
if 'tools' not in metadata_record.metadata:
@@ -152,19 +191,26 @@ def check_and_flag_repositories( app, info_only=False, verbose=False ):
for tool_metadata in metadata_record.metadata[ 'tools' ]:
tool_count += 1
tool_id = tool_metadata[ 'id' ]
if verbose:
print '# Checking for functional tests in changeset revision %s of %s, tool ID %s.' % \
( changeset_revision, name, tool_id )
tool_version = tool_metadata[ 'version' ]
tool_guid = tool_metadata[ 'guid' ]
if verbosity >= 2:
print "# Checking tool ID '%s' in changeset revision %s of %s." % \
( tool_id, changeset_revision, name )
# If there are no tests, this tool should not be tested, since the tool functional tests only report failure if the test itself fails,
# not if it's missing or undefined. Filtering out those repositories at this step will reduce the number of "false negatives" the
# automated functional test framework produces.
if 'tests' not in tool_metadata or not tool_metadata[ 'tests' ]:
if verbose:
if verbosity >= 2:
print '# No functional tests defined for %s.' % tool_id
# The repository_metadata.tool_test_errors attribute should always have the following structure:
# {
# "test_environment":
# {
# "galaxy_revision": "9001:abcd1234",
# "galaxy_database_version": "114",
# "tool_shed_revision": "9001:abcd1234",
# "tool_shed_mercurial_version": "2.3.1",
# "tool_shed_database_version": "17",
# "python_version": "2.7.2",
# "architecture": "x86_64",
# "system": "Darwin 12.2.0"
@@ -172,22 +218,44 @@ def check_and_flag_repositories( app, info_only=False, verbose=False ):
# "test_errors":
# [
# {
# "test_id": "Something that will easily identify what the problem is",
# "stderr": "The output of the test, or a more detailed description of what was tested and why it failed."
# "test_id": "The test ID, generated by twill",
# "tool_id": "The tool ID that was tested",
# "tool_version": "The tool version that was tested",
# "stderr": "The output of the test, or a more detailed description of what was tested and what the outcome was."
# "traceback": "The captured traceback."
# },
# ]
# "passed_tests":
# [
# {
# "test_id": "The test ID, generated by twill",
# "tool_id": "The tool ID that was tested",
# "tool_version": "The tool version that was tested",
# "stderr": "The output of the test, or a more detailed description of what was tested and what the outcome was."
# },
# ]
# "invalid_tests":
# [
# {
# "tool_id": "The tool ID that does not have functional tests defined.",
# "tool_version": "The version of the tool."
# "tool_guid": "The guid of the tool."
# "reason_test_is_invalid": "A short explanation of what is invalid.
# },
# ]
# }
# Optionally, "stdout" and "traceback" may be included in a test_errors dict, if they are relevant.
test_id = 'Functional tests for %s' % tool_id
test_errors = dict( stderr='No functional tests defined for tool %s in changeset revision %s of repository %s owned by %s.' % \
( tool_id, changeset_revision, name, owner ) )
repository_status[ 'test_errors' ].append( test_errors )
repository_status[ 'status' ] = 'failed'
# Optionally, "traceback" may be included in a test_errors dict, if it is relevant. No script should overwrite anything other
# than the list relevant to what it is testing.
test_errors = dict( tool_id=tool_id, tool_version=tool_version, tool_guid=tool_guid )
repository_status[ 'invalid_tests' ].append( test_errors )
no_tests += 1
else:
if verbosity >= 2:
print "# Tool ID '%s' in changeset revision %s of %s has one or more valid functional tests defined." % \
( tool_id, changeset_revision, name )
has_tests += 1
if verbose:
if not repository_status[ 'test_errors' ]:
if verbosity >= 1:
if not repository_status[ 'invalid_tests' ]:
print '# All tools have functional tests in changeset revision %s of repository %s owned by %s.' % ( changeset_revision, name, owner )
else:
print '# Some tools missing functional tests in changeset revision %s of repository %s owned by %s.' % ( changeset_revision, name, owner )
@@ -211,12 +279,17 @@ def check_and_flag_repositories( app, info_only=False, verbose=False ):
if os.path.exists( work_dir ):
shutil.rmtree( work_dir )
if not has_test_data:
if verbose:
if verbosity >= 1:
print '# Test data missing in changeset revision %s of repository %s owned by %s.' % ( changeset_revision, name, owner )
# The repository_metadata.tool_test_errors attribute should always have the following structure:
# {
# "test_environment":
# {
# "galaxy_revision": "9001:abcd1234",
# "galaxy_database_version": "114",
# "tool_shed_revision": "9001:abcd1234",
# "tool_shed_mercurial_version": "2.3.1",
# "tool_shed_database_version": "17",
# "python_version": "2.7.2",
# "architecture": "x86_64",
# "system": "Darwin 12.2.0"
@@ -224,23 +297,44 @@ def check_and_flag_repositories( app, info_only=False, verbose=False ):
# "test_errors":
# [
# {
# "test_id": "Something that will easily identify what the problem is",
# "stderr": "The output of the test, or a more detailed description of what was tested and why it failed."
# "test_id": "The test ID, generated by twill",
# "tool_id": "The tool ID that was tested",
# "tool_version": "The tool version that was tested",
# "stderr": "The output of the test, or a more detailed description of what was tested and what the outcome was."
# "traceback": "The captured traceback."
# },
# ]
# "passed_tests":
# [
# {
# "test_id": "The test ID, generated by twill",
# "tool_id": "The tool ID that was tested",
# "tool_version": "The tool version that was tested",
# "stderr": "The output of the test, or a more detailed description of what was tested and what the outcome was."
# },
# ]
# "invalid_tests":
# [
# {
# "tool_id": "The tool ID that does not have functional tests defined.",
# "tool_version": "The version of the tool."
# "tool_guid": "The guid of the tool."
# "reason_test_is_invalid": "A short explanation of what is invalid.
# },
# ]
# }
# Optionally, "stdout" and "traceback" may be included in a test_errors dict, if they are relevant.
test_id = 'Find functional test data for %s' % metadata_record.repository.name
test_errors = dict( stderr='No test data found for changeset revision %s of repository %s owned by %s.' % ( changeset_revision, name, owner ) )
repository_status[ 'test_errors' ].append( test_errors )
repository_status[ 'status' ] = 'failed'
# Optionally, "traceback" may be included in a test_errors dict, if it is relevant. No script should overwrite anything other
# than the list relevant to what it is testing.
test_errors = dict( tool_id=None, tool_version=None, tool_guid=None,
reason_test_is_invalid="Repository %s is missing a test-data directory." % name )
repository_status[ 'invalid_tests' ].append( test_errors )
else:
if verbose:
if verbosity >= 1:
print '# Test data found in changeset revision %s of repository %s owned by %s.' % ( changeset_revision, name, owner )
if not info_only:
# If repository_status[ 'test_errors' ] is empty, no issues were found, and we can just update time_last_tested with the platform
# on which this script was run.
if repository_status[ 'test_errors' ]:
if repository_status[ 'invalid_tests' ]:
# If functional test definitions or test data are missing, set do_not_test = True if and only if:
# a) There are multiple downloadable revisions, and the revision being tested is not the most recent downloadable revision. In this case,
# the revision will never be updated with correct data, and re-testing it would be redundant.
@@ -250,8 +344,6 @@ def check_and_flag_repositories( app, info_only=False, verbose=False ):
if should_set_do_not_test_flag( app, metadata_record.repository, changeset_revision ):
metadata_record.do_not_test = True
metadata_record.tools_functionally_correct = False
else:
repository_status[ 'status' ] = 'passed'
metadata_record.tool_test_errors = repository_status
metadata_record.time_last_tested = datetime.utcnow()
app.sa_session.add( metadata_record )
+2 -2
View File
@@ -74,8 +74,8 @@ def get_installed_repository_info( elem, last_galaxy_test_file_dir, last_tested_
return None, repository_name, changeset_revision
return last_galaxy_test_file_dir, last_tested_repository_name, last_tested_changeset_revision
def get_test_environment():
rval = {}
def get_test_environment( current_environment={} ):
rval = current_environment
rval[ 'python_version' ] = platform.python_version()
rval[ 'architecture' ] = platform.machine()
os, hostname, os_version, uname, arch, processor = platform.uname()
@@ -60,6 +60,7 @@ import nose.core
import nose.config
import nose.loader
import nose.plugins.manager
from nose.plugins import Plugin
from base.util import parse_tool_panel_config, get_database_version, get_test_environment, get_repository_current_revision
@@ -115,9 +116,36 @@ if 'GALAXY_INSTALL_TEST_SECRET' not in os.environ:
else:
galaxy_encode_secret = os.environ[ 'GALAXY_INSTALL_TEST_SECRET' ]
class ReportResults( Plugin ):
'''Simple Nose plugin to record the IDs of all tests run, regardless of success.'''
name = "reportresults"
passed = []
def options( self, parser, env=os.environ ):
super( ReportResults, self ).options( parser, env=env )
def configure(self, options, conf):
super( ReportResults, self ).configure( options, conf )
if not self.enabled:
return
def addSuccess( self, test ):
'''Only record test IDs that correspond to tool functional tests.'''
if 'TestForTool' in test.id():
test_id = test.id()
# Rearrange the test ID to match the format that is produced in test_results.failures
test_id_parts = test_id.split( '.' )
fixed_test_id = '%s (%s)' % ( test_id_parts[ -1 ], '.'.join( test_id_parts[ :-1 ] ) )
self.passed.append( fixed_test_id )
def getTestStatus( self ):
return self.passed
def execute_uninstall_method( repository_dict ):
# Delete any configured tool functional tests from the test_toolbox.__dict__, otherwise nose will find them
# and try to re-run the tests after uninstalling the repository.
# and try to re-run the tests after uninstalling the repository, which will cause false failure reports,
# since the test data has been deleted from disk by now.
tests_to_delete = []
for key in test_toolbox.__dict__:
if key.startswith( 'TestForTool_' ):
@@ -132,7 +160,7 @@ def execute_uninstall_method( repository_dict ):
test_config.configure( sys.argv )
# Run the uninstall method. This method uses the Galaxy web interface to uninstall the previously installed
# repository and delete it from disk.
result = run_tests( test_config )
result, _ = run_tests( test_config )
success = result.wasSuccessful()
return success
@@ -191,6 +219,23 @@ def get_repositories_to_install( location, source='file', format='json' ):
else:
raise AssertonError( 'Unknown format %s.' % format )
def get_tool_info_from_test_id( test_id ):
'''
Test IDs come in the form test_tool_number (functional.test_toolbox.TestForTool_toolshed_url/repos/owner/repository_name/tool_id/tool_version)
We want the tool ID and tool version.
'''
parts = test_id.replace( ')', '' ).split( '/' )
tool_version = parts[ -1 ]
tool_id = parts[ -2 ]
return tool_id, tool_version
def get_tool_test_errors_from_api( tool_shed_url, metadata_dict ):
params = dict()
api_path = metadata_dict[ 'url' ].split( '/' )
api_url = get_api_url( base=tool_shed_url, parts=api_path )
repository_metadata = json_from_url( api_url )
return repository_metadata[ 'tool_test_errors' ]
def json_from_url( url ):
url_handle = urllib.urlopen( url )
url_contents = url_handle.read()
@@ -201,16 +246,15 @@ def register_test_result( url, metadata_id, test_results_dict, tests_passed=Fals
if tests_passed:
params[ 'tools_functionally_correct' ] = 'true'
params[ 'do_not_test' ] = 'true'
test_results_dict[ 'status' ] = 'passed'
else:
params[ 'tools_functionally_correct' ] = 'false'
params[ 'do_not_test' ] = 'true'
test_results_dict[ 'status' ] = 'failed'
params[ 'tool_test_errors' ] = test_results_dict
return update( tool_shed_api_key, '%s' % ( url_join( galaxy_tool_shed_url, 'api', 'repository_revisions', metadata_id ) ), params, return_formatted=False )
def run_tests( test_config ):
loader = nose.loader.TestLoader( config=test_config )
test_config.plugins.addPlugin( ReportResults() )
plug_loader = test_config.plugins.prepareTestLoader( loader )
if plug_loader is not None:
loader = plug_loader
@@ -221,7 +265,8 @@ def run_tests( test_config ):
plug_runner = test_config.plugins.prepareTestRunner( test_runner )
if plug_runner is not None:
test_runner = plug_runner
return test_runner.run( tests )
result = test_runner.run( tests )
return result, test_config.plugins._plugins
def main():
# ---- Configuration ------------------------------------------------------
@@ -391,10 +436,6 @@ def main():
log.info( "The embedded Galaxy application is running on %s:%s" % ( galaxy_test_host, galaxy_test_port ) )
log.info( "Repositories will be installed from the tool shed at %s" % galaxy_tool_shed_url )
success = False
repository_status = dict()
test_environment = get_test_environment()
test_environment[ 'galaxy_database_version' ] = get_database_version( app )
test_environment[ 'galaxy_revision'] = get_repository_current_revision( os.getcwd() )
try:
# Iterate through a list of repository info dicts.
log.info( "Retrieving repositories to install from the URL:\n%s\n" % str( galaxy_tool_shed_url ) )
@@ -472,7 +513,7 @@ def main():
test_config.configure( sys.argv )
# Run the configured install method as a test. This method uses the embedded Galaxy application's web interface to install the specified
# repository, with tool and repository dependencies also selected for installation.
result = run_tests( test_config )
result, _ = run_tests( test_config )
success = result.wasSuccessful()
# If the installation succeeds, configure and run functional tests for this repository. This is equivalent to
# sh run_functional_tests.sh -installed
@@ -483,14 +524,63 @@ def main():
# and the tools_functionally_correct flag to False, as well as updating tool_test_errors.
file( galaxy_shed_tools_dict, 'w' ).write( to_json_string( dict() ) )
has_test_data, shed_tools_dict = parse_tool_panel_config( galaxy_shed_tool_conf_file, from_json_string( file( galaxy_shed_tools_dict, 'r' ).read() ) )
# The repository_status dict should always have the following structure:
# {
# "test_environment":
# {
# "galaxy_revision": "9001:abcd1234",
# "galaxy_database_version": "114",
# "tool_shed_revision": "9001:abcd1234",
# "tool_shed_mercurial_version": "2.3.1",
# "tool_shed_database_version": "17",
# "python_version": "2.7.2",
# "architecture": "x86_64",
# "system": "Darwin 12.2.0"
# },
# "test_errors":
# [
# {
# "test_id": "The test ID, generated by twill",
# "tool_id": "The tool ID that was tested",
# "tool_version": "The tool version that was tested",
# "stderr": "The output of the test, or a more detailed description of what was tested and what the outcome was."
# "traceback": "The captured traceback."
# },
# ]
# "passed_tests":
# [
# {
# "test_id": "The test ID, generated by twill",
# "tool_id": "The tool ID that was tested",
# "tool_version": "The tool version that was tested",
# "stderr": "The output of the test, or a more detailed description of what was tested and what the outcome was."
# },
# ]
# "invalid_tests":
# [
# {
# "tool_id": "The tool ID that does not have functional tests defined.",
# "tool_version": "The version of the tool."
# "tool_guid": "The guid of the tool."
# "reason_test_is_invalid": "A short explanation of what is invalid.
# },
# ]
# }
repository_status = get_tool_test_errors_from_api( galaxy_tool_shed_url, repository_dict )
test_environment = get_test_environment( repository_status[ 'test_environment' ] )
test_environment[ 'galaxy_database_version' ] = get_database_version( app )
test_environment[ 'galaxy_revision'] = get_repository_current_revision( os.getcwd() )
repository_status[ 'test_environment' ] = test_environment
repository_status[ 'tests_passed' ] = []
repository_status[ 'test_errors' ] = []
if not has_test_data:
log.error( 'Test data is missing for this repository. Updating repository and skipping functional tests.' )
repository_status[ 'test_environment' ] = get_test_environment()
test_id = 'Find functional test data for %s' % repository_dict[ 'name' ]
test_errors = dict( test_id=test_id,
stdout='No test data found for changeset revision %s of repository %s owned by %s.' % \
( repository_dict[ 'changeset_revision' ], repository_dict[ 'name' ], repository_dict[ 'owner' ] ) )
repository_status[ 'test_errors' ] = [ test_errors ]
# Record the lack of test data.
test_errors = dict( tool_id=None, tool_version=None, tool_guid=None,
reason_test_is_invalid="Repository %s is missing a test-data directory." % name )
repository_status[ 'invalid_tests' ].append( test_errors )
# Record the status of this repository in the tool shed.
register_test_result( galaxy_tool_shed_url, metadata_revision_id, repository_status, tests_passed=False )
# Run the cleanup method. This removes tool functional test methods from the test_toolbox module and uninstalls the
@@ -518,12 +608,20 @@ def main():
test_config = nose.config.Config( env=os.environ, plugins=nose.plugins.manager.DefaultPluginManager() )
test_config.configure( sys.argv )
# Run the configured tests.
result = run_tests( test_config )
result, test_plugins = run_tests( test_config )
success = result.wasSuccessful()
# Record some information about the environment in which this test was run, in case a failure is specific to a certain processor
# architecture or operating system.
repository_dict[ 'test_environment' ] = test_environment
test_errors = []
for plugin in test_plugins:
if hasattr( plugin, 'getTestStatus' ):
tests_passed = plugin.getTestStatus()
break
repository_status[ 'tests_passed' ] = []
for test_id in tests_passed:
tool_id, tool_version = get_tool_info_from_test_id( test_id )
test_result = dict( test_id=test_id, tool_id=tool_id, tool_version=tool_version )
repository_status[ 'tests_passed' ].append( test_result )
if success:
# This repository's tools passed all functional tests. Update the repository_metadata table in the tool shed's database
# to reflect that. Call the register_test_result method, which executes a PUT request to the repository_revisions API
@@ -531,15 +629,16 @@ def main():
# updates the time_last_tested field to today's date.
repositories_passed.append( dict( name=name, owner=owner, changeset_revision=changeset_revision ) )
repository_status[ 'test_environment' ] = test_environment
repository_status[ 'test_errors' ] = []
register_test_result( galaxy_tool_shed_url, metadata_revision_id, repository_status, tests_passed=True )
log.debug( 'Revision %s of repository %s installed and passed functional tests.' % \
( repository_dict[ 'changeset_revision' ], repository_dict[ 'name' ] ) )
else:
# If the functional tests fail, log the output and update the failed changeset revision's metadata record in the tool shed via the API.
for failure in result.failures:
# Record the twill test identifier, so the repository owner can discover which test is failing.
test_status = dict( test_id=str( failure[0] ) )
# Record the twill test identifier and information about the tool, so the repository owner can discover which test is failing.
test_id = str( failure[0] )
tool_id, tool_version = get_tool_info_from_test_id( test_id )
test_status = dict( test_id=test_id, tool_id=tool_id, tool_version=tool_version )
log_output = failure[1].replace( '\\n', '\n' )
# Remove debug output that the reviewer or owner doesn't need.
log_output = re.sub( r'control \d+:.+', r'', log_output )
@@ -547,7 +646,7 @@ def main():
appending_to = 'output'
tmp_output = {}
output = {}
# Iterate through the functional test output and extract only the important data. Captured logging is not recorded.
# Iterate through the functional test output and extract only the important data. Captured logging and stdout are not recorded.
for line in log_output.split( '\n' ):
if line.startswith( 'Traceback' ):
appending_to = 'traceback'
@@ -567,17 +666,15 @@ def main():
if appending_to not in tmp_output:
tmp_output[ appending_to ] = []
tmp_output[ appending_to ].append( line )
for output_type in [ 'stderr', 'stdout', 'traceback' ]:
for output_type in [ 'stderr', 'traceback' ]:
if output_type in tmp_output:
test_status[ output_type ] = '\n'.join( tmp_output[ output_type ] )
test_errors.append( test_status )
if test_errors:
# Only update test_errors for this repository if it's not empty.
repository_status[ 'test_environment' ] = test_environment
repository_status[ 'test_errors' ] = test_errors
repository_status[ 'test_errors' ].append( test_status )
log.debug( to_json_string( repository_status, indent=2, sort_keys=True ) )
# Call the register_test_result method, which executes a PUT request to the repository_revisions API controller with the outcome
# status of the tests, and updates tool_test_errors with the relevant log data.
# This also sets the do_not_test and tools_functionally correct flags, and updates the time_last_tested field to today's date.
# of the tests, and updates tool_test_errors with the relevant log data.
# This also sets the do_not_test and tools_functionally correct flags to the appropriate values, and updates the time_last_tested
# field to today's date.
repositories_failed.append( dict( name=name, owner=owner, changeset_revision=changeset_revision ) )
register_test_result( galaxy_tool_shed_url, metadata_revision_id, repository_status, tests_passed=False )
log.debug( 'Revision %s of repository %s installed successfully, but did not pass functional tests.' % \