1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/365d31607a56/ Changeset: 365d31607a56 User: carlfeberhard Date: 2013-04-26 21:17:08 Summary: Browser tests: allow for use of test admin user, test configuration API, begin tests of user API Affected #: 7 files diff -r 98cd1bcb36f129e8fed213687deccd7701ab047a -r 365d31607a569575ac666d142556403fe82d693a lib/galaxy/model/__init__.py --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -48,9 +48,17 @@ global datatypes_registry datatypes_registry = d_registry + class User( object, APIItem ): + """ + Data for a Galaxy user or admin and relations to their + histories, credentials, and roles. + """ + # attributes that will be accessed and returned when calling get_api_value( view='collection' ) api_collection_visible_keys = ( 'id', 'email' ) + # attributes that will be accessed and returned when calling get_api_value( view='element' ) api_element_visible_keys = ( 'id', 'email', 'username', 'total_disk_usage', 'nice_total_disk_usage' ) + def __init__( self, email=None, password=None ): self.email = email self.password = password @@ -61,45 +69,78 @@ # Relationships self.histories = [] self.credentials = [] + #? self.roles = [] def set_password_cleartext( self, cleartext ): - """Set 'self.password' to the digest of 'cleartext'.""" + """ + Set user password to the digest of `cleartext`. + """ self.password = new_secure_hash( text_type=cleartext ) + def check_password( self, cleartext ): - """Check if 'cleartext' matches 'self.password' when hashed.""" + """ + Check if `cleartext` matches user password when hashed. + """ return self.password == new_secure_hash( text_type=cleartext ) + def all_roles( self ): + """ + Return a unique list of Roles associated with this user or any of their groups. + """ roles = [ ura.role for ura in self.roles ] for group in [ uga.group for uga in self.groups ]: for role in [ gra.role for gra in group.roles ]: if role not in roles: roles.append( role ) return roles + def get_disk_usage( self, nice_size=False ): + """ + Return byte count of disk space used by user or a human-readable + string if `nice_size` is `True`. + """ rval = 0 if self.disk_usage is not None: rval = self.disk_usage if nice_size: rval = galaxy.datatypes.data.nice_size( rval ) return rval + def set_disk_usage( self, bytes ): + """ + Manually set the disk space used by a user to `bytes`. + """ self.disk_usage = bytes + total_disk_usage = property( get_disk_usage, set_disk_usage ) + @property def nice_total_disk_usage( self ): + """ + Return byte count of disk space used in a human-readable string. + """ return self.get_disk_usage( nice_size=True ) + def calculate_disk_usage( self ): + """ + Return byte count total of disk space used by all non-purged, non-library + HDAs in non-purged histories. + """ + # maintain a list so that we don't double count dataset_ids = [] total = 0 # this can be a huge number and can run out of memory, so we avoid the mappers db_session = object_session( self ) for history in db_session.query( History ).enable_eagerloads( False ).filter_by( user_id=self.id, purged=False ).yield_per( 1000 ): for hda in db_session.query( HistoryDatasetAssociation ).enable_eagerloads( False ).filter_by( history_id=history.id, purged=False ).yield_per( 1000 ): + #TODO: def hda.counts_toward_disk_usage(): + # return ( not self.dataset.purged and not self.dataset.library_associations ) if not hda.dataset.id in dataset_ids and not hda.dataset.purged and not hda.dataset.library_associations: dataset_ids.append( hda.dataset.id ) total += hda.dataset.get_total_size() return total + class Job( object ): """ A job represents a request to run a tool given input datasets, tool diff -r 98cd1bcb36f129e8fed213687deccd7701ab047a -r 365d31607a569575ac666d142556403fe82d693a lib/galaxy/webapps/galaxy/api/configuration.py --- a/lib/galaxy/webapps/galaxy/api/configuration.py +++ b/lib/galaxy/webapps/galaxy/api/configuration.py @@ -2,30 +2,29 @@ API operations allowing clients to determine Galaxy instance's capabilities. """ -import logging from galaxy import web from galaxy.web.base.controller import BaseAPIController +import logging log = logging.getLogger( __name__ ) - class ConfigurationController( BaseAPIController ): EXPOSED_USER_OPTIONS = [ - 'enable_unique_workflow_defaults', - 'ftp_upload_site', - 'ftp_upload_dir', - 'wiki_url', - 'support_url', - 'logo_url', - 'terms_url', - 'allow_user_dataset_purge', + 'enable_unique_workflow_defaults', + 'ftp_upload_site', + 'ftp_upload_dir', + 'wiki_url', + 'support_url', + 'logo_url', + 'terms_url', + 'allow_user_dataset_purge', ] EXPOSED_ADMIN_OPTIONS = [ - 'library_import_dir', - 'user_library_import_dir', - 'allow_library_path_paste', - 'allow_user_creation', - 'allow_user_deletion', + 'library_import_dir', + 'user_library_import_dir', + 'allow_library_path_paste', + 'allow_user_creation', + 'allow_user_deletion', ] @web.expose_api diff -r 98cd1bcb36f129e8fed213687deccd7701ab047a -r 365d31607a569575ac666d142556403fe82d693a test/casperjs/api-configuration-tests.js --- /dev/null +++ b/test/casperjs/api-configuration-tests.js @@ -0,0 +1,121 @@ +/* Utility to load a specific page and output html, page text, or a screenshot + * Optionally wait for some time, text, or dom selector + */ +try { + //...if there's a better way - please let me know, universe + var scriptDir = require( 'system' ).args[3] + // remove the script filename + .replace( /[\w|\.|\-|_]*$/, '' ) + // if given rel. path, prepend the curr dir + .replace( /^(?!\/)/, './' ), + spaceghost = require( scriptDir + 'spaceghost' ).create({ + // script options here (can be overridden by CLI) + //verbose: true, + //logLevel: debug, + scriptDir: scriptDir + }); + +} catch( error ){ + console.debug( error ); + phantom.exit( 1 ); +} +spaceghost.start(); + +// =================================================================== SET UP +var utils = require( 'utils' ); + +var email = spaceghost.user.getRandomEmail(), + password = '123456'; +if( spaceghost.fixtureData.testUser ){ + email = spaceghost.fixtureData.testUser.email; + password = spaceghost.fixtureData.testUser.password; +} +spaceghost.user.loginOrRegisterUser( email, password ); + +function hasKeys( object, keysArray ){ + if( !utils.isObject( object ) ){ return false; } + for( var i=0; i<keysArray.length; i += 1 ){ + if( !object.hasOwnProperty( keysArray[i] ) ){ + spaceghost.debug( 'key not found: ' + keysArray[i] ); + return false; + } + } + return true; +} + +function compareObjs( obj1, where ){ + for( var key in where ){ + if( where.hasOwnProperty( key ) ){ + if( !obj1.hasOwnProperty( key ) ){ return false; } + if( obj1[ key ] !== where[ key ] ){ return false; } + } + } + return true; +} + +function findObject( objectArray, where, start ){ + start = start || 0; + for( var i=start; i<objectArray.length; i += 1 ){ + if( compareObjs( objectArray[i], where ) ){ return objectArray[i]; } + } + return null; +} + +// =================================================================== TESTS +var normKeys = [ + 'enable_unique_workflow_defaults', + 'ftp_upload_site', + 'ftp_upload_dir', + 'wiki_url', + 'support_url', + 'logo_url', + 'terms_url', + 'allow_user_dataset_purge' + ], + adminKeys = normKeys.concat([ + 'library_import_dir', + 'user_library_import_dir', + 'allow_library_path_paste', + 'allow_user_creation', + 'allow_user_deletion' + ]); + + +// ------------------------------------------------------------------------------------------- INDEX +spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){ + + this.test.comment( 'index should get a (shortened) list of configuration settings ' + + 'when requested by a normal user' ); + var configIndex = this.api.configuration.index(); + this.debug( this.jsonStr( configIndex ) ); + this.test.assert( utils.isObject( configIndex ), "index returned an object" ); + this.test.assert( hasKeys( configIndex, normKeys ), 'Has the proper keys' ); + +}); +spaceghost.user.logout(); + +// ------------------------------------------------------------------------------------------- INDEX (admin) +spaceghost.tryStepsCatch( function tryAdminLogin(){ + spaceghost.user.loginAdmin(); +}); + +//}, function failedLoginRegister(){ +// this.info( 'Admin level configuration API tests not run: no admin account available' ); +spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){ + + if( spaceghost.user.userIsAdmin() ){ + this.test.comment( 'index should get a (full) list of configuration settings ' + + 'when requested by an admin user' ); + configIndex = this.api.configuration.index(); + this.debug( this.jsonStr( configIndex ) ); + this.test.assert( utils.isObject( configIndex ), "index returned an object" ); + this.test.assert( hasKeys( configIndex, adminKeys ), 'Has the proper keys' ); + + } else { + this.info( 'Admin level configuration API tests not run: no admin account available' ); + } +}); + +// =================================================================== +spaceghost.run( function(){ +}); diff -r 98cd1bcb36f129e8fed213687deccd7701ab047a -r 365d31607a569575ac666d142556403fe82d693a test/casperjs/api-user-tests.js --- /dev/null +++ b/test/casperjs/api-user-tests.js @@ -0,0 +1,105 @@ +/* Utility to load a specific page and output html, page text, or a screenshot + * Optionally wait for some time, text, or dom selector + */ +try { + //...if there's a better way - please let me know, universe + var scriptDir = require( 'system' ).args[3] + // remove the script filename + .replace( /[\w|\.|\-|_]*$/, '' ) + // if given rel. path, prepend the curr dir + .replace( /^(?!\/)/, './' ), + spaceghost = require( scriptDir + 'spaceghost' ).create({ + // script options here (can be overridden by CLI) + //verbose: true, + //logLevel: debug, + scriptDir: scriptDir + }); + +} catch( error ){ + console.debug( error ); + phantom.exit( 1 ); +} +spaceghost.start(); + +// =================================================================== SET UP +var utils = require( 'utils' ); + +var email = spaceghost.user.getRandomEmail(), + password = '123456'; +if( spaceghost.fixtureData.testUser ){ + email = spaceghost.fixtureData.testUser.email; + password = spaceghost.fixtureData.testUser.password; +} +spaceghost.user.loginOrRegisterUser( email, password ); + +function hasKeys( object, keysArray ){ + if( !utils.isObject( object ) ){ return false; } + for( var i=0; i<keysArray.length; i += 1 ){ + if( !object.hasOwnProperty( keysArray[i] ) ){ + spaceghost.debug( 'key not found: ' + keysArray[i] ); + return false; + } + } + return true; +} + +function compareObjs( obj1, where ){ + for( var key in where ){ + if( where.hasOwnProperty( key ) ){ + if( !obj1.hasOwnProperty( key ) ){ return false; } + if( obj1[ key ] !== where[ key ] ){ return false; } + } + } + return true; +} + +function findObject( objectArray, where, start ){ + start = start || 0; + for( var i=start; i<objectArray.length; i += 1 ){ + if( compareObjs( objectArray[i], where ) ){ return objectArray[i]; } + } + return null; +} + +// =================================================================== TESTS +var workflowSummaryKeys = [ + 'id', 'model_class', 'name', 'published', 'tags', 'url' + ], + workflowDetailKeys = workflowSummaryKeys.concat([ + 'inputs', 'steps' + ]); + + +spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){ + + // ------------------------------------------------------------------------------------------- INDEX + this.test.comment( 'index should get a list of users' ); + var userIndex = this.api.users.index(); + this.debug( this.jsonStr( userIndex ) ); + this.test.assert( utils.isArray( userIndex ), "index returned an array: length " + userIndex.length ); + + // need a way to import/create a user here for testing + if( userIndex.length <= 0 ){ + log.warn( 'No users available' ); + return; + } + this.test.assert( userIndex.length >= 1, 'Has at least one user' ); + + //TODO: index( deleted ) + + // ------------------------------------------------------------------------------------------- SHOW + this.test.comment( 'show should get detailed data about the user with the given id' ); + var userShow = this.api.users.show( userIndex[0].id ); + this.debug( this.jsonStr( userShow ) ); + + //TODO: show( current ) + //TODO: show( deleted ) + + // ------------------------------------------------------------------------------------------- CREATE + + // ------------------------------------------------------------------------------------------- MISC +}); + +// =================================================================== +spaceghost.run( function(){ +}); diff -r 98cd1bcb36f129e8fed213687deccd7701ab047a -r 365d31607a569575ac666d142556403fe82d693a test/casperjs/modules/api.js --- a/test/casperjs/modules/api.js +++ b/test/casperjs/modules/api.js @@ -18,10 +18,12 @@ this.encodedIdExpectedLength = 16; this.jQueryLocation = '../../static/scripts/libs/jquery/jquery.js'; + this.configuration = new ConfigurationAPI( this ); this.histories = new HistoriesAPI( this ); this.hdas = new HDAAPI( this ); this.tools = new ToolsAPI( this ); this.workflows = new WorkflowsAPI( this ); + this.users = new UsersAPI( this ); }; exports.API = API; @@ -121,6 +123,28 @@ }; +// =================================================================== CONFIGURATION +var ConfigurationAPI = function ConfigurationAPI( api ){ + this.api = api; +}; +ConfigurationAPI.prototype.toString = function toString(){ + return this.api + '.ConfigurationAPI'; +}; + +// ------------------------------------------------------------------- +ConfigurationAPI.prototype.urlTpls = { + index : 'api/configuration' +}; + +ConfigurationAPI.prototype.index = function index( deleted ){ + this.api.spaceghost.info( 'configuration.index' ); + + return this.api._ajax( this.urlTpls.index, { + data : {} + }); +}; + + // =================================================================== HISTORIES var HistoriesAPI = function HistoriesAPI( api ){ this.api = api; @@ -140,7 +164,7 @@ }; HistoriesAPI.prototype.index = function index( deleted ){ - this.api.spaceghost.info( 'history.index: ' + (( deleted )?( 'w deleted' ):( '(wo deleted)' )) ); + this.api.spaceghost.info( 'histories.index: ' + (( deleted )?( 'w deleted' ):( '(wo deleted)' )) ); deleted = deleted || false; return this.api._ajax( this.urlTpls.index, { @@ -149,7 +173,7 @@ }; HistoriesAPI.prototype.show = function show( id, deleted ){ - this.api.spaceghost.info( 'history.show: ' + [ id, (( deleted )?( 'w deleted' ):( '' )) ] ); + this.api.spaceghost.info( 'histories.show: ' + [ id, (( deleted )?( 'w deleted' ):( '' )) ] ); id = ( id === 'most_recently_used' )?( id ):( this.api.ensureId( id ) ); deleted = deleted || false; @@ -159,7 +183,7 @@ }; HistoriesAPI.prototype.create = function create( payload ){ - this.api.spaceghost.info( 'history.create: ' + this.api.spaceghost.jsonStr( payload ) ); + this.api.spaceghost.info( 'histories.create: ' + this.api.spaceghost.jsonStr( payload ) ); // py.payload <-> ajax.data payload = this.api.ensureObject( payload ); @@ -170,7 +194,7 @@ }; HistoriesAPI.prototype.delete_ = function delete_( id, purge ){ - this.api.spaceghost.info( 'history.delete: ' + [ id, (( purge )?( '(purge!)' ):( '' )) ] ); + this.api.spaceghost.info( 'histories.delete: ' + [ id, (( purge )?( '(purge!)' ):( '' )) ] ); // py.payload <-> ajax.data var payload = ( purge )?({ purge: true }):({}); @@ -182,7 +206,7 @@ HistoriesAPI.prototype.undelete = function undelete( id ){ //throw ( 'unimplemented' ); - this.api.spaceghost.info( 'history.undelete: ' + id ); + this.api.spaceghost.info( 'histories.undelete: ' + id ); return this.api._ajax( utils.format( this.urlTpls.undelete, this.api.ensureId( id ) ), { type : 'POST' @@ -190,7 +214,7 @@ }; HistoriesAPI.prototype.update = function create( id, payload ){ - this.api.spaceghost.info( 'history.update: ' + id + ',' + this.api.spaceghost.jsonStr( payload ) ); + this.api.spaceghost.info( 'histories.update: ' + id + ',' + this.api.spaceghost.jsonStr( payload ) ); // py.payload <-> ajax.data id = this.api.ensureId( id ); @@ -269,6 +293,7 @@ }); }; + // =================================================================== TOOLS var ToolsAPI = function HDAAPI( api ){ this.api = api; @@ -319,6 +344,7 @@ // }); //}; + // =================================================================== WORKFLOWS var WorkflowsAPI = function WorkflowsAPI( api ){ this.api = api; @@ -394,3 +420,88 @@ }); }; + +// =================================================================== USERS +var UsersAPI = function UsersAPI( api ){ + this.api = api; +}; +UsersAPI.prototype.toString = function toString(){ + return this.api + '.UsersAPI'; +}; + +// ------------------------------------------------------------------- +//NOTE: lots of admin only functionality in this section +UsersAPI.prototype.urlTpls = { + index : 'api/users', + show : 'api/users/%s', + create : 'api/users', + delete_ : 'api/users/%s', + undelete: 'api/users/deleted/%s/undelete', + update : 'api/users/%s' +}; + +UsersAPI.prototype.index = function index( deleted ){ + this.api.spaceghost.info( 'users.index: ' + (( deleted )?( 'w deleted' ):( '(wo deleted)' )) ); + + deleted = deleted || false; + return this.api._ajax( this.urlTpls.index, { + data : { deleted: deleted } + }); +}; + +UsersAPI.prototype.show = function show( id, deleted ){ + this.api.spaceghost.info( 'users.show: ' + [ id, (( deleted )?( 'w deleted' ):( '' )) ] ); + + id = ( id === 'current' )?( id ):( this.api.ensureId( id ) ); + deleted = deleted || false; + return this.api._ajax( utils.format( this.urlTpls.show, id ), { + data : { deleted: deleted } + }); +}; + +UsersAPI.prototype.create = function create( payload ){ + this.api.spaceghost.info( 'users.create: ' + this.api.spaceghost.jsonStr( payload ) ); + + // py.payload <-> ajax.data + payload = this.api.ensureObject( payload ); + return this.api._ajax( utils.format( this.urlTpls.create ), { + type : 'POST', + data : payload + }); +}; + +UsersAPI.prototype.delete_ = function delete_( id, purge ){ + this.api.spaceghost.info( 'users.delete: ' + [ id, (( purge )?( '(purge!)' ):( '' )) ] ); + + // py.payload <-> ajax.data + var payload = ( purge )?({ purge: true }):({}); + return this.api._ajax( utils.format( this.urlTpls.delete_, this.api.ensureId( id ) ), { + type : 'DELETE', + data : payload + }); +}; + +UsersAPI.prototype.undelete = function undelete( id ){ + //throw ( 'unimplemented' ); + this.api.spaceghost.info( 'users.undelete: ' + id ); + + return this.api._ajax( utils.format( this.urlTpls.undelete, this.api.ensureId( id ) ), { + type : 'POST' + }); +}; + +UsersAPI.prototype.update = function create( id, payload ){ + this.api.spaceghost.info( 'users.update: ' + id + ',' + this.api.spaceghost.jsonStr( payload ) ); + + // py.payload <-> ajax.data + id = this.api.ensureId( id ); + payload = this.api.ensureObject( payload ); + url = utils.format( this.urlTpls.update, id ); + + return this.api._ajax( url, { + type : 'PUT', + data : payload + }); +}; + + diff -r 98cd1bcb36f129e8fed213687deccd7701ab047a -r 365d31607a569575ac666d142556403fe82d693a test/casperjs/modules/user.js --- a/test/casperjs/modules/user.js +++ b/test/casperjs/modules/user.js @@ -134,7 +134,7 @@ this._submitLogin( email, password ); spaceghost.withMainPanel( function mainAfterLogin(){ - if( spaceghost.getCurrentUrl().search( spaceghost.data.selectors.loginPage.url_regex ) != -1 ){ + if( spaceghost.getCurrentUrl().search( spaceghost.data.selectors.loginPage.url_regex ) !== -1 ){ var messageInfo = spaceghost.getElementInfo( spaceghost.data.selectors.messages.all ); if( messageInfo && messageInfo.attributes[ 'class' ] === 'errormessage' ){ this.warning( 'Login failed: ' + messageInfo.text ); @@ -171,6 +171,7 @@ User.prototype.logout = function logout(){ var spaceghost = this.spaceghost; spaceghost.thenOpen( spaceghost.baseUrl, function(){ + this.info( 'user logging out' ); //TODO: handle already logged out spaceghost.clickLabel( spaceghost.data.labels.masthead.menus.user ); spaceghost.clickLabel( spaceghost.data.labels.masthead.userMenu.logout ); @@ -196,6 +197,63 @@ return spaceghost; }; +// ------------------------------------------------------------------- Admin +/** Gets the admin user data from spaceghost if set and checks the universe_wsgi.ini file for the email. + * @returns {Object|null} the admin data object (email, pasword, username) + * or null if no admin is set in both the universe_wsgi.ini and spaceghost. + */ +User.prototype.getAdminData = function getAdminData(){ + //TODO: this might be better inside sg + // check for the setting in sg and the universe_wsgi.ini file + var adminData = this.spaceghost.options.adminUser, + iniAdminEmails = this.spaceghost.getUniverseSetting( 'admin_users' ); + iniAdminEmails = ( iniAdminEmails )?( iniAdminEmails.split( ',' ) ):( null ); + + //TODO: seems like we only need the wsgi setting - that's the only thing we can't change + if( adminData ){ + if( iniAdminEmails.indexOf( adminData.email ) !== -1 ){ return adminData; } + + // if not set in options, but there are entries in the ini and a default admin pass: + // return the first email with the default pass + // Hopefully this is no less secure than the user/pwd in twilltestcase + } else if( iniAdminEmails.length && this.spaceghost.options.adminPassword ){ + return { email: iniAdminEmails[0], password: this.spaceghost.options.adminPassword }; + } + + return null; +}; + +/** Logs in the admin user (if available) as the current user. + * Note: logs out any other current users. + * @throws {GalaxyError} err if specified user is not admin or no admin found + * @returns {SpaceGhost} the spaceghost instance (for chaining) + */ +User.prototype.loginAdmin = function loginAdmin(){ + this.spaceghost.then( function(){ + var adminData = this.user.getAdminData(); + if( !adminData ){ + throw new this.GalaxyError( 'No admin users found' ); + } + this.info( 'logging in administrator' ); + return this.user.loginOrRegisterUser( adminData.email, adminData.password ); + }); +}; + +/** Is the currently logged in user an admin? + * @returns {Boolean} true if the currently logged in user is admin, false if not. + */ +User.prototype.userIsAdmin = function userIsAdmin(){ + // simple test of whether the Admin tab is displayed in the masthead + return this.spaceghost.jumpToTop( function(){ + if( this.visible( this.data.selectors.masthead.adminLink ) ){ + return true; + } + return false; + }); +}; + + +// ------------------------------------------------------------------- Utility /** Gets a psuedo-random (unique?) email based on the time stamp. * Helpful for testing registration. * @param {String} username email user (defaults to 'test') @@ -207,3 +265,4 @@ domain = domain || 'test.test'; return username + Date.now() + '@' + domain; }; + diff -r 98cd1bcb36f129e8fed213687deccd7701ab047a -r 365d31607a569575ac666d142556403fe82d693a test/casperjs/spaceghost.js --- a/test/casperjs/spaceghost.js +++ b/test/casperjs/spaceghost.js @@ -47,7 +47,17 @@ } utils.inherits( SpaceGhost, Casper ); -//console.debug( 'CasperError:' + CasperError ); +/** String representation + * @returns {String} + */ +SpaceGhost.prototype.toString = function(){ + var currentUrl = ''; + try { + currentUrl = this.getCurrentUrl(); + } catch( err ){} + return 'SpaceGhost(' + currentUrl + ')'; +}; + // ------------------------------------------------------------------- included libs //??: can we require underscore, etc. from the ../../static/scripts/lib? @@ -157,9 +167,14 @@ //htmlOnError : { defaultsTo: false, flag: 'error-html', help: 'output page html on a page error' } //htmlOnFail : { defaultsTo: false, flag: 'fail-html', help: 'output page html on a test failure' }, //screenOnFail : { defaultsTo: false, flag: 'fail-screen', help: 'capture a screenshot on a test failure' } - logNamespace : { defaultsTo: false, flag: 'log-namespace', help: 'filter log messages to this namespace' } + logNamespace : { defaultsTo: false, flag: 'log-namespace', help: 'filter log messages to this namespace' }, + + adminUser : { defaultsTo: null, flag: 'admin', help: 'JSON string with email and password of admin' } }; + // no switches/hardcoded options: + this.options.adminPassword = 'testuser'; + // --url parameter required (the url of the server to test with) if( !this.cli.has( 'url' ) ){ this.die( 'Test server URL is required - ' + @@ -237,6 +252,13 @@ this._setLogNamespaceFilter( this.options.logNamespace ); } + /** email and password JSON string for admin user */ + this.options.adminUser = CLI_OPTIONS.adminUser.defaultsTo; + if( this.cli.has( CLI_OPTIONS.adminUser.flag ) ){ + this.options.adminUser = JSON.parse( this.cli.get( CLI_OPTIONS.adminUser.flag ) ); + this.warning( 'Using admin user from CLI: ' + this.jsonStr( this.options.adminUser ) ); + } + }; /** Suppress the normal output from the casper object (echo, errors) @@ -1002,6 +1024,7 @@ } }; +// ------------------------------------------------------------------- debugging /** JSON formatter */ SpaceGhost.prototype.jsonStr = function( obj ){ @@ -1036,17 +1059,7 @@ return this.errors[( this.errors.length - 1 )]; }; -/** String representation - * @returns {String} - */ -SpaceGhost.prototype.toString = function(){ - var currentUrl = ''; - try { - currentUrl = this.getCurrentUrl(); - } catch( err ){} - return 'SpaceGhost(' + currentUrl + ')'; -}; - +// ------------------------------------------------------------------- file system /** Load and parse a JSON file into an object. * @param {String} filepath filepath relative to the current scriptDir * @returns {Object} the object parsed @@ -1078,6 +1091,34 @@ return fs.write( filepath, this.getHTML( selector, outer ), 'w' ); }; +/** Read and search a file for the given regex. + * @param {String} filepath filepath relative to the current scriptDir + * @param {Regex} searchFor regex to search for + * @returns {Object} search results + */ +SpaceGhost.prototype.searchFile = function searchFile( filepath, regex ){ + //precondition: filepath is relative to script dir + filepath = this.options.scriptDir + filepath; + var read = fs.read( filepath ); + return read.match( regex ); +}; + +/** Read a configuration setting from the universe_wsgi.ini file. + * @param {String} iniKey the setting key to find + * @returns {String} value from file for iniKey (or null if not found or commented out) + */ +SpaceGhost.prototype.getUniverseSetting = function getUniverseSetting( iniKey ){ + var iniFilepath = '../../universe_wsgi.ini', + regex = new RegExp( '^([#]*)\\\s*' + iniKey + '\\\s*=\\\s*(.*)$', 'm' ), + match = this.searchFile( iniFilepath, regex ); + this.debug( 'regex: ' + regex ); + // if nothing found or found and first group (the ini comment char) is not empty + if( match === null || match[1] || !match[2] ){ + return null; + } + return match[2]; +}; + // =================================================================== TEST DATA /** General use selectors, labels, and text. Kept here to allow a centralized location. @@ -1105,6 +1146,7 @@ }, masthead : { + adminLink : '#masthead a[href="/admin"]', userMenu : { userEmail : 'a #user-email', userEmail_xpath : '//a[contains(text(),"Logged in as")]/span["id=#user-email"]' 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.