1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/changeset/447448028a2f/ changeset: 447448028a2f user: greg date: 2012-11-13 19:49:09 summary: Add the framework components to enable creating a functional test framework for the tool shed. affected #: 9 files diff -r 3419a45c1f01790b3108d1726253fcb46feedbf4 -r 447448028a2f7326fc452ee32055de5c58e822f6 run_tool_shed_functional_tests.sh --- /dev/null +++ b/run_tool_shed_functional_tests.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +# A good place to look for nose info: http://somethingaboutorange.com/mrl/projects/nose/ +#rm -f ./test/tool_shed/run_functional_tests.log + +if [ ! $1 ]; then + python ./test/tool_shed/functional_tests.py -v --with-nosehtml --html-report-file ./test/tool_shed/run_functional_tests.html ./test/tool_shed/functional +elif [ $1 = 'help' ]; then + echo "'run_tool_shed_functional_tests.sh' for running all the test scripts in the ./test/tool_shed/functional directory" + echo "'run_tool_shed_functional_tests.sh testscriptname' for running one test script named testscriptname in the .test/tool_shed/functional directory" +else + python ./test/tool_shed/functional_tests.py -v --with-nosehtml --html-report-file ./test/tool_shed/run_functional_tests.html $1 +fi + +echo "'sh run_tool_shed_functional_tests.sh help' for help" diff -r 3419a45c1f01790b3108d1726253fcb46feedbf4 -r 447448028a2f7326fc452ee32055de5c58e822f6 test/tool_shed/__init__.py --- /dev/null +++ b/test/tool_shed/__init__.py @@ -0,0 +1,1 @@ +"""Tool shed functional Tests""" \ No newline at end of file diff -r 3419a45c1f01790b3108d1726253fcb46feedbf4 -r 447448028a2f7326fc452ee32055de5c58e822f6 test/tool_shed/base/test_db_util.py --- /dev/null +++ b/test/tool_shed/base/test_db_util.py @@ -0,0 +1,39 @@ +import galaxy.webapps.community.model as model +from galaxy.model.orm import * +from galaxy.webapps.community.model.mapping import context as sa_session +from base.twilltestcase import * +import sys + +def delete_obj( obj ): + sa_session.delete( obj ) + sa_session.flush() +def delete_user_roles( user ): + for ura in user.roles: + sa_session.delete( ura ) + sa_session.flush() +def flush( obj ): + sa_session.add( obj ) + sa_session.flush() +def get_default_user_permissions_by_role( role ): + return sa_session.query( model.DefaultUserPermissions ) \ + .filter( model.DefaultUserPermissions.table.c.role_id == role.id ) \ + .all() +def get_default_user_permissions_by_user( user ): + return sa_session.query( model.DefaultUserPermissions ) \ + .filter( model.DefaultUserPermissions.table.c.user_id==user.id ) \ + .all() +def get_private_role( user ): + for role in user.all_roles(): + if role.name == user.email and role.description == 'Private Role for %s' % user.email: + return role + raise AssertionError( "Private role not found for user '%s'" % user.email ) +def get_user( email ): + return sa_session.query( model.User ) \ + .filter( model.User.table.c.email==email ) \ + .first() +def mark_obj_deleted( obj ): + obj.deleted = True + sa_session.add( obj ) + sa_session.flush() +def refresh( obj ): + sa_session.refresh( obj ) diff -r 3419a45c1f01790b3108d1726253fcb46feedbf4 -r 447448028a2f7326fc452ee32055de5c58e822f6 test/tool_shed/base/twilltestcase.py --- /dev/null +++ b/test/tool_shed/base/twilltestcase.py @@ -0,0 +1,20 @@ +from base.twilltestcase import * + +class ShedTwillTestCase( TwillTestCase ): + def setUp( self ): + # Security helper + self.security = security.SecurityHelper( id_secret='changethisinproductiontoo' ) + self.history_id = None + self.host = os.environ.get( 'TOOL_SHED_TEST_HOST' ) + self.port = os.environ.get( 'TOOL_SHED_TEST_PORT' ) + self.url = "http://%s:%s" % ( self.host, self.port ) + self.file_dir = os.environ.get( 'TOOL_SHED_TEST_FILE_DIR', None ) + self.tool_shed_test_file = None + self.shed_tools_dict = {} + self.keepOutdir = os.environ.get( 'TOOL_SHED_TEST_SAVE', '' ) + if self.keepOutdir > '': + try: + os.makedirs( self.keepOutdir ) + except: + pass + self.home() diff -r 3419a45c1f01790b3108d1726253fcb46feedbf4 -r 447448028a2f7326fc452ee32055de5c58e822f6 test/tool_shed/functional/test_0000_create_repository.py --- /dev/null +++ b/test/tool_shed/functional/test_0000_create_repository.py @@ -0,0 +1,44 @@ +import tempfile, time, re, tempfile, os, shutil +import galaxy.webapps.community.model +from galaxy.util import parse_xml, string_as_bool +from galaxy.util.shed_util import clean_tool_shed_url +from galaxy.model.orm import * +from tool_shed.base.twilltestcase import * +from tool_shed.base.test_db_util import * + +admin_user = None +admin_user_private_role = None +admin_email = 'test@bx.psu.edu' +admin_username = 'admin-user' + +class TestCreateRepository( ShedTwillTestCase ): + + def test_0000_initiate_users( self ): + """Create necessary users and login as an admin user.""" + self.logout() + self.login( email=admin_email, username=admin_username ) + admin_user = get_user( admin_email ) + assert admin_user is not None, 'Problem retrieving user with email %s from the database' % admin_email + admin_user_private_role = get_private_role( admin_user ) + def test_0005_create_category( self ): + """Create a category""" + self.visit_url( '/admin/manage_categories?operation=create' ) + try: + tc.fv( "1", "name", "Text Manipulation" ) + tc.fv( "1", "description", "Tools for manipulating text" ) + tc.submit( "create_category_button" ) + except Exception, e: + errmsg = "Problem creating a category: %s" % str( e ) + raise AssertionError( e ) + def test_0010_create_filter_repository( self ): + """Create a repository""" + self.visit_url( '/repository/create_repository' ) + try: + tc.fv( "1", "name", "filter" ) + tc.fv( "1", "description", "Galaxy's filter tool" ) + tc.fv( "1", "long_description", "Long description of Galaxy's filter tool" ) + tc.fv( "1", "category_id", "Text Manipulation" ) + tc.submit( "create_repository_button" ) + except Exception, e: + errmsg = "Problem creating a repository: %s" % str( e ) + raise AssertionError( e ) diff -r 3419a45c1f01790b3108d1726253fcb46feedbf4 -r 447448028a2f7326fc452ee32055de5c58e822f6 test/tool_shed/functional_tests.py --- /dev/null +++ b/test/tool_shed/functional_tests.py @@ -0,0 +1,274 @@ +#!/usr/bin/env python + +import os, sys, shutil, tempfile, re + +# Assume we are run from the galaxy root directory, add lib to the python path +cwd = os.getcwd() +tool_shed_home_directory = os.path.join( cwd, 'test', 'tool_shed' ) +default_tool_shed_test_file_dir = os.path.join( tool_shed_home_directory, 'test_data' ) +new_path = [ os.path.join( cwd, "lib" ) ] +new_path.extend( sys.path[1:] ) +sys.path = new_path + +from galaxy import eggs + +eggs.require( "nose" ) +eggs.require( "NoseHTML" ) +eggs.require( "NoseTestDiff" ) +eggs.require( "twill==0.9" ) +eggs.require( "Paste" ) +eggs.require( "PasteDeploy" ) +eggs.require( "Cheetah" ) + +# This should not be required, but it is under certain conditions, thanks to this bug: http://code.google.com/p/python-nose/issues/detail?id=284 +eggs.require( "pysqlite" ) + +import atexit, logging, os, os.path, sys, tempfile +import twill, unittest, time +import sys, threading, random +import httplib, socket +from paste import httpserver +import galaxy.webapps.community.app +from galaxy.webapps.community.app import UniverseApplication +from galaxy.webapps.community import buildapp + +import nose.core +import nose.config +import nose.loader +import nose.plugins.manager + +log = logging.getLogger( "tool_shed_functional_tests.py" ) + +default_tool_shed_test_host = "localhost" +default_tool_shed_test_port_min = 8000 +default_tool_shed_test_port_max = 9999 +default_tool_shed_locales = 'en' + +def run_tests( test_config ): + loader = nose.loader.TestLoader( config=test_config ) + plug_loader = test_config.plugins.prepareTestLoader( loader ) + if plug_loader is not None: + loader = plug_loader + tests = loader.loadTestsFromNames( test_config.testNames ) + test_runner = nose.core.TextTestRunner( stream=test_config.stream, + verbosity=test_config.verbosity, + config=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 ) + +def main(): + # ---- Configuration ------------------------------------------------------ + tool_shed_test_host = os.environ.get( 'TOOL_SHED_TEST_HOST', default_tool_shed_test_host ) + tool_shed_test_port = os.environ.get( 'TOOL_SHED_TEST_PORT', None ) + tool_shed_test_save = os.environ.get( 'TOOL_SHED_TEST_SAVE', None ) + tool_path = os.environ.get( 'TOOL_SHED_TEST_TOOL_PATH', 'tools' ) + start_server = 'TOOL_SHED_TEST_EXTERNAL' not in os.environ + if 'HTTP_ACCEPT_LANGUAGE' not in os.environ: + os.environ[ 'HTTP_ACCEPT_LANGUAGE' ] = default_tool_shed_locales + tool_shed_test_file_dir = os.environ.get( 'TOOL_SHED_TEST_FILE_DIR', default_tool_shed_test_file_dir ) + if not os.path.isabs( tool_shed_test_file_dir ): + tool_shed_test_file_dir = tool_shed_test_file_dir + ignore_files = () + if os.path.exists( 'tool_data_table_conf.test.xml' ): + tool_data_table_config_path = 'tool_data_table_conf.test.xml' + else: + tool_data_table_config_path = 'tool_data_table_conf.xml' + shed_tool_data_table_config = 'shed_tool_data_table_conf.xml' + tool_dependency_dir = os.environ.get( 'TOOL_SHED_TOOL_DEPENDENCY_DIR', None ) + use_distributed_object_store = os.environ.get( 'TOOL_SHED_USE_DISTRIBUTED_OBJECT_STORE', False ) + + if start_server: + psu_production = False + tool_shed_test_proxy_port = None + if 'TOOL_SHED_TEST_PSU_PRODUCTION' in os.environ: + if not tool_shed_test_port: + raise Exception( 'Set TOOL_SHED_TEST_PORT to the port to which the proxy server will proxy' ) + tool_shed_test_proxy_port = os.environ.get( 'TOOL_SHED_TEST_PROXY_PORT', None ) + if not tool_shed_test_proxy_port: + raise Exception( 'Set TOOL_SHED_TEST_PROXY_PORT to the port on which the proxy server is listening' ) + base_file_path = os.environ.get( 'TOOL_SHED_TEST_BASE_FILE_PATH', None ) + if not base_file_path: + raise Exception( 'Set TOOL_SHED_TEST_BASE_FILE_PATH to the directory which will contain the dataset files directory' ) + base_new_file_path = os.environ.get( 'TOOL_SHED_TEST_BASE_NEW_FILE_PATH', None ) + if not base_new_file_path: + raise Exception( 'Set TOOL_SHED_TEST_BASE_NEW_FILE_PATH to the directory which will contain the temporary directory' ) + database_connection = os.environ.get( 'TOOL_SHED_TEST_DBURI', None ) + if not database_connection: + raise Exception( 'Set TOOL_SHED_TEST_DBURI to the URI of the database to be used for tests' ) + nginx_upload_store = os.environ.get( 'TOOL_SHED_TEST_NGINX_UPLOAD_STORE', None ) + if not nginx_upload_store: + raise Exception( 'Set TOOL_SHED_TEST_NGINX_UPLOAD_STORE to the path where the nginx upload module places uploaded files' ) + file_path = tempfile.mkdtemp( dir=base_file_path ) + new_file_path = tempfile.mkdtemp( dir=base_new_file_path ) + kwargs = dict( database_engine_option_pool_size = '10', + database_engine_option_max_overflow = '20', + database_engine_option_strategy = 'threadlocal', + static_enabled = 'False', + debug = 'False' ) + psu_production = True + else: + if 'TOOL_SHED_TEST_DBPATH' in os.environ: + db_path = os.environ[ 'TOOL_SHED_TEST_DBPATH' ] + else: + tempdir = tempfile.mkdtemp() + db_path = os.path.join( tempdir, 'database' ) + file_path = os.path.join( db_path, 'files' ) + new_file_path = os.path.join( db_path, 'tmp' ) + if 'TOOL_SHED_TEST_DBURI' in os.environ: + database_connection = os.environ[ 'TOOL_SHED_TEST_DBURI' ] + else: + database_connection = 'sqlite:///' + os.path.join( db_path, 'universe.sqlite' ) + kwargs = {} + for dir in file_path, new_file_path: + try: + os.makedirs( dir ) + except OSError: + pass + + print "Database connection:", database_connection + + # ---- Build Application -------------------------------------------------- + app = None + if start_server: + global_conf = { '__file__' : 'community_wsgi.ini.sample' } + if psu_production: + global_conf = None + if not database_connection.startswith( 'sqlite://' ): + kwargs[ 'database_engine_option_max_overflow' ] = '20' + if tool_dependency_dir is not None: + kwargs[ 'tool_dependency_dir' ] = tool_dependency_dir + if use_distributed_object_store: + kwargs[ 'object_store' ] = 'distributed' + kwargs[ 'distributed_object_store_config_file' ] = 'distributed_object_store_conf.xml.sample' + + app = UniverseApplication( job_queue_workers = 5, + id_secret = 'changethisinproductiontoo', + template_path = 'templates', + database_connection = database_connection, + database_engine_option_pool_size = '10', + file_path = file_path, + new_file_path = new_file_path, + tool_path=tool_path, + datatype_converters_config_file = 'datatype_converters_conf.xml.sample', + tool_parse_help = False, + tool_data_table_config_path = tool_data_table_config_path, + shed_tool_data_table_config = shed_tool_data_table_config, + log_destination = "stdout", + use_heartbeat = False, + allow_user_creation = True, + allow_user_deletion = True, + admin_users = 'test@bx.psu.edu', + global_conf = global_conf, + running_functional_tests = True, + hgweb_config_dir = new_file_path, + **kwargs ) + log.info( "Embedded Universe application started" ) + + # ---- Run webserver ------------------------------------------------------ + server = None + if start_server: + webapp = buildapp.app_factory( dict( database_file=database_connection ), + use_translogger=False, + static_enabled=False, + app=app ) + if tool_shed_test_port is not None: + server = httpserver.serve( webapp, host=tool_shed_test_host, port=tool_shed_test_port, start_loop=False ) + else: + random.seed() + for i in range( 0, 9 ): + try: + tool_shed_test_port = str( random.randint( default_tool_shed_test_port_min, default_tool_shed_test_port_max ) ) + log.debug( "Attempting to serve app on randomly chosen port: %s" % tool_shed_test_port ) + server = httpserver.serve( webapp, host=tool_shed_test_host, port=tool_shed_test_port, start_loop=False ) + break + except socket.error, e: + if e[0] == 98: + continue + raise + else: + raise Exception( "Unable to open a port between %s and %s to start Galaxy server" % ( default_tool_shed_test_port_min, default_tool_shed_test_port_max ) ) + if tool_shed_test_proxy_port: + os.environ[ 'TOOL_SHED_TEST_PORT' ] = tool_shed_test_proxy_port + else: + os.environ[ 'TOOL_SHED_TEST_PORT' ] = tool_shed_test_port + t = threading.Thread( target=server.serve_forever ) + t.start() + # Test if the server is up + for i in range( 10 ): + # Directly test the app, not the proxy. + conn = httplib.HTTPConnection( tool_shed_test_host, tool_shed_test_port ) + conn.request( "GET", "/" ) + if conn.getresponse().status == 200: + break + time.sleep( 0.1 ) + else: + raise Exception( "Test HTTP server did not return '200 OK' after 10 tries" ) + # Test if the proxy server is up. + if psu_production: + # Directly test the app, not the proxy. + conn = httplib.HTTPConnection( tool_shed_test_host, tool_shed_test_proxy_port ) + conn.request( "GET", "/" ) + if not conn.getresponse().status == 200: + raise Exception( "Test HTTP proxy server did not return '200 OK'" ) + log.info( "Embedded web server started" ) + # We don't add the tests to the path until everything is up and running + new_path = [ os.path.join( cwd, 'test' ) ] + new_path.extend( sys.path[1:] ) + sys.path = new_path + # ---- Find tests --------------------------------------------------------- + if tool_shed_test_proxy_port: + log.info( "Functional tests will be run against %s:%s" % ( tool_shed_test_host, tool_shed_test_proxy_port ) ) + else: + log.info( "Functional tests will be run against %s:%s" % ( tool_shed_test_host, tool_shed_test_port ) ) + success = False + try: + # What requires these? Handy for (eg) functional tests to save outputs? + if tool_shed_test_save: + os.environ[ 'TOOL_SHED_TEST_SAVE' ] = tool_shed_test_save + # Pass in through script set env, will leave a copy of ALL test validate files. + os.environ[ 'TOOL_SHED_TEST_HOST' ] = tool_shed_test_host + if tool_shed_test_file_dir: + os.environ[ 'TOOL_SHED_TEST_FILE_DIR' ] = tool_shed_test_file_dir + test_config = nose.config.Config( env=os.environ, ignoreFiles=ignore_files, plugins=nose.plugins.manager.DefaultPluginManager() ) + test_config.configure( sys.argv ) + # Run the tests. + result = run_tests( test_config ) + success = result.wasSuccessful() + except: + log.exception( "Failure running tests" ) + + log.info( "Shutting down" ) + # ---- Tear down ----------------------------------------------------------- + if server: + log.info( "Shutting down embedded web server" ) + server.server_close() + server = None + log.info( "Embedded web server stopped" ) + if app: + log.info( "Shutting down app" ) + app.shutdown() + app = None + log.info( "Embedded Universe application stopped" ) + try: + if os.path.exists( tempdir ) and 'TOOL_SHED_TEST_NO_CLEANUP' not in os.environ: + log.info( "Cleaning up temporary files in %s" % tempdir ) + shutil.rmtree( tempdir ) + except: + pass + if psu_production and 'TOOL_SHED_TEST_NO_CLEANUP' not in os.environ: + for dir in ( file_path, new_file_path ): + try: + if os.path.exists( dir ): + log.info( 'Cleaning up temporary files in %s' % dir ) + shutil.rmtree( dir ) + except: + pass + if success: + return 0 + else: + return 1 + +if __name__ == "__main__": + sys.exit( main() ) diff -r 3419a45c1f01790b3108d1726253fcb46feedbf4 -r 447448028a2f7326fc452ee32055de5c58e822f6 test/tool_shed/test_data/filtering_1.1.0.tar Binary file test/tool_shed/test_data/filtering_1.1.0.tar has changed Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.