diff --git a/.gitattributes b/.gitattributes index c30c7891640dabd3ca23f69759bfab0e98ba8450..87739538732cdd933c7a6db2bcfdf68e02127521 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4604,6 +4604,10 @@ SAS/MoM/MoMQueryService/CMakeLists.txt -text SAS/MoM/MoMQueryService/__init__.py -text SAS/MoM/MoMQueryService/momprojectdetailsquery.py -text SAS/MoM/MoMQueryService/momqueryservice.py -text +SAS/MoM/MoMQueryService/test/CMakeLists.txt -text +SAS/MoM/MoMQueryService/test/test_momqueryservice.py -text +SAS/MoM/MoMQueryService/test/test_momqueryservice.run -text +SAS/MoM/MoMQueryService/test/test_momqueryservice.sh -text SAS/OTB/OTB-distribution/assembly.xml -text SAS/OTB/OTB-distribution/pom.xml -text SAS/OTB/OTB/assembly.xml -text diff --git a/SAS/MoM/MoMQueryService/CMakeLists.txt b/SAS/MoM/MoMQueryService/CMakeLists.txt index 4143cbec73786ab9f97a167366e1dc18bd91fed2..cf8815b8c3eb8c5798aa39cf2fd34b229d40567a 100644 --- a/SAS/MoM/MoMQueryService/CMakeLists.txt +++ b/SAS/MoM/MoMQueryService/CMakeLists.txt @@ -12,3 +12,4 @@ set(_py_files python_install(${_py_files} DESTINATION lofar/mom/momqueryservice) +add_subdirectory(test) diff --git a/SAS/MoM/MoMQueryService/momprojectdetailsquery.py b/SAS/MoM/MoMQueryService/momprojectdetailsquery.py index b2f99eb823a875cae5525fa97954e6d6c6fee746..6251f8460a0476d8c014aa1c6601f3fee7b93839 100755 --- a/SAS/MoM/MoMQueryService/momprojectdetailsquery.py +++ b/SAS/MoM/MoMQueryService/momprojectdetailsquery.py @@ -1,26 +1,55 @@ #!/usr/bin/python import sys +import logging from lofar.messaging.RPC import RPC ''' Simple RPC client for Service momqueryservice.GetProjectDetails ''' +logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.INFO) +logger = logging.getLogger("momprojectdetailsquery") + + +def getProjectDetails(ids, busname='momqueryservice'): + '''get the project details for one or more mom ids + :param ids single or list of mom ids_string + :param string busname name of the bus on which the service listens + :rtype dict with project details''' + if isinstance(ids, int) or isinstance(ids, str): + ids = [ids] + ids = [str(x) for x in ids] + ids_string = ', '.join(ids) + + with RPC(busname, 'GetProjectDetails', timeout=10) as getProjectDetails: + res, status = getProjectDetails(ids_string) + + if status != 'OK': + logger.error("%s %s" % (status, res)) + return status + + return res + + +def main(ids, busname='momqueryservice'): + '''get the project details for one or more mom ids + and print the results + :param ids single or list of mom ids_string + :param string busname name of the bus on which the service listens + :rtype dict with project details''' + logger.info("Requesting details for: %s" % (str(ids))) + result = getProjectDetails(ids, busname) + + for id, obj in result.items(): + logger.info('Object %s' % (id)) + for k, v in obj.items(): + logger.info(' %s: %s' % (k, v)) + + if __name__ == '__main__': if len(sys.argv) <= 1: print 'Please provide one or more mom ids' sys.exit(1) ids = ','.join(sys.argv[1:]) - with RPC('momqueryservice','GetProjectDetails',timeout=10) as getProjectDetails: - res,status=getProjectDetails(ids) - - if status == 'OK': - for id,obj in res.items(): - print 'Object %s' % (id) - for k,v in obj.items(): - print ' %s: %s' % (k, v) - print - else: - print status, res - + main(ids) diff --git a/SAS/MoM/MoMQueryService/momqueryservice.py b/SAS/MoM/MoMQueryService/momqueryservice.py index b36b416e05dc647a2675ee9a1977cbbe26494045..395d419224e16015e7d00db5a2847b758304afb9 100755 --- a/SAS/MoM/MoMQueryService/momqueryservice.py +++ b/SAS/MoM/MoMQueryService/momqueryservice.py @@ -5,15 +5,17 @@ Simple Service listening on momqueryservice.GetProjectDetails which gives the project details for each requested mom object id ''' - +import sys +import logging from mysql import connector from lofar.messaging import Service -# do not commit passwd in svn -passwd='' +logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.INFO) +logger=logging.getLogger("momqueryservice") -class DBlistener: - def __init__(self): +class ProjectDetailsQueryHandler: + '''handler class for details query in mom db''' + def __init__(self, passwd): self.conn = connector.connect(host="mysql1.control.lofar", user="momreadonly", passwd=passwd, @@ -25,8 +27,15 @@ class DBlistener: # filter out everything else to prevent sql injection mom_ids = [x.strip() for x in text.split(',')] mom_ids = [x for x in mom_ids if x.isdigit()] + mom_ids_str = ', '.join(mom_ids) + + if not mom_ids_str: + logger.error("Could not find proper ids in: " + text) + raise KeyError("Could not find proper ids in: " + text) + + logger.info("Query for mom id%s: %s" % ('\'s' if len(mom_ids) > 1 else '', mom_ids_str)) - cursor = self.conn.cursor() + cursor = self.conn.cursor(dictionary=True) # TODO: make a view for this query in momdb! query = '''SELECT project.mom2id as project_mom2id, project.name as project_name, project.description as project_description, object.mom2id as object_mom2id, object.name as object_name, object.description as object_description, object.mom2objecttype as object_type, object.group_id as object_group_id @@ -34,24 +43,38 @@ class DBlistener: inner join lofar_mom3.mom2object as project on project.id = object.ownerprojectid where object.mom2id in (%s) order by project_mom2id - ''' % (','.join(mom_ids)) + ''' % (mom_ids_str) cursor.execute(query) - result={} - - rows= cursor.fetchall() + result = {} + rows = cursor.fetchall() for row in rows: - item = {'project_mom2id': int(row[0]), - 'project_name': row[1], - 'project_description': row[2], - 'object_mom2id': int(row[3]), - 'object_name': row[4], - 'object_description': row[5], - 'object_type': row[6], - 'object_group_id': int(row[7]) if row[7] else None} - result[str(row[3])] = item + object_mom2id = row['object_mom2id'] + result[str(object_mom2id)] = row + logger.info("Result for %s: %s" % (object_mom2id, str(row))) return result -with Service("momqueryservice", "GetProjectDetails", DBlistener(), startonwith=True) as getProjectDetailsService: - getProjectDetailsService.WaitForInterrupt() + +def createService(busname='momqueryservice', momreadonly_passwd=''): + '''create the GetProjectDetails on given busname + :param string busname: name of the bus on which this service listens + :param string momreadonly_passwd: the momreadonly passwd. + :rtype: lofar.messaging.Service''' + handler = ProjectDetailsQueryHandler(momreadonly_passwd) + return Service(busname, + 'GetProjectDetails', + handler, + startonwith=True, + numthreads=1) + + +def main(): + # do not commit passwd in svn + passwd = '' + + with createService('momqueryservice', passwd) as getProjectDetailsService: + getProjectDetailsService.WaitForInterrupt() + +if __name__ == '__main__': + main() diff --git a/SAS/MoM/MoMQueryService/test/CMakeLists.txt b/SAS/MoM/MoMQueryService/test/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..b337f99844032cb115fcabde61d087f445e8683a --- /dev/null +++ b/SAS/MoM/MoMQueryService/test/CMakeLists.txt @@ -0,0 +1,5 @@ +# $Id: CMakeLists.txt 32679 2015-10-26 09:31:56Z schaap $ +include(LofarCTest) + +lofar_add_test(test_momqueryservice) + diff --git a/SAS/MoM/MoMQueryService/test/test_momqueryservice.py b/SAS/MoM/MoMQueryService/test/test_momqueryservice.py new file mode 100755 index 0000000000000000000000000000000000000000..24f9158aff102f623c43f7fd1c8bd6acc0de000f --- /dev/null +++ b/SAS/MoM/MoMQueryService/test/test_momqueryservice.py @@ -0,0 +1,62 @@ +#!/usr/bin/python + +# Copyright (C) 2012-2015 ASTRON (Netherlands Institute for Radio Astronomy) +# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands +# +# This file is part of the LOFAR software suite. +# The LOFAR software suite is free software: you can redistribute it and/or +# modify it under the terms of the GNU General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# The LOFAR software suite is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. + +# $Id: $ + +import unittest +import uuid +from lofar.mom.momqueryservice import momqueryservice +from lofar.mom.momqueryservice import momprojectdetailsquery +from qpid.messaging import Connection +from qpidtoollibs import BrokerAgent + +try: + connection = Connection.establish('127.0.0.1') + broker = BrokerAgent(connection) + + busname = "momqueryservice-test-%s" % (uuid.uuid1()) + broker.addExchange('topic', busname) + + # do not commit passwd in svn + passwd = '' + + with momqueryservice.createService(busname, passwd): + + class TestLTAStorageDb(unittest.TestCase): + def testProjectDetailsQuery(self): + testid = '598612' + result = momprojectdetailsquery.getProjectDetails(testid, busname) + self.assertEquals(1, len(result.keys())) + self.assertEquals(testid, result.keys()[0]) + self.assertTrue('project_mom2id' in result[testid]) + self.assertTrue('project_name' in result[testid]) + self.assertTrue('project_description' in result[testid]) + + def testSqlInjection(self): + testid = '598612; select * from lofar_mom3.mom2object;' + result = momprojectdetailsquery.getProjectDetails(testid, busname) + print result + + self.assertTrue('errmsg' in result) + self.assertTrue('KeyError' in result['errmsg']) + + unittest.main(verbosity=2) +finally: + broker.delExchange(busname) + connection.close() diff --git a/SAS/MoM/MoMQueryService/test/test_momqueryservice.run b/SAS/MoM/MoMQueryService/test/test_momqueryservice.run new file mode 100755 index 0000000000000000000000000000000000000000..f68b2f7fa5f58a43162c09db9839d27c19eef7b2 --- /dev/null +++ b/SAS/MoM/MoMQueryService/test/test_momqueryservice.run @@ -0,0 +1,25 @@ +#!/bin/bash + +if type "coverage" > /dev/null; then + #run test using python coverage tool + + #erase previous results + coverage erase + + #setup coverage config file + printf "[report]\nexclude_lines = \n if __name__ == .__main__.\n def main\n" > .coveragerc + + coverage run --branch --include=*momqueryservice* test_momqueryservice.py + RESULT=$? + if [ $RESULT -eq 0 ]; then + echo " *** Code coverage results *** " + coverage report -m + echo " *** End coverage results *** " + fi + exit $RESULT +else + #coverage not available + echo "Please run: 'pip install coverage' to enable code coverage reporting of the unit tests" + #run plain test script + python test_momqueryservice.py +fi diff --git a/SAS/MoM/MoMQueryService/test/test_momqueryservice.sh b/SAS/MoM/MoMQueryService/test/test_momqueryservice.sh new file mode 100755 index 0000000000000000000000000000000000000000..488e7f88ef29f3efbda2cda3da7aa43560f23374 --- /dev/null +++ b/SAS/MoM/MoMQueryService/test/test_momqueryservice.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +./runctest.sh test_momqueryservice