diff --git a/awips/NotificationMessage.py b/awips/NotificationMessage.py index 9d0b7ce..e860ea5 100644 --- a/awips/NotificationMessage.py +++ b/awips/NotificationMessage.py @@ -1,7 +1,7 @@ ## # This software was developed and / or modified by Raytheon Company, # pursuant to Contract DG133W-05-CQ-1067 with the US Government. -# +# # U.S. EXPORT CONTROLLED TECHNICAL DATA # This software product contains export-restricted data whose # export/transfer/disclosure is restricted by U.S. law. Dissemination @@ -13,7 +13,7 @@ # Mail Stop B8 # Omaha, NE 68106 # 402.291.0100 -# +# # See the AWIPS II Master Rights File ("Master Rights File.pdf") for # further licensing information. ## @@ -47,6 +47,8 @@ from dynamicserialize import DynamicSerializationManager # 01/07/11 5645 cjeanbap Added audio file to Status Message. # 05/27/11 3050 cjeanbap Added if-statement to check Priority # value +# 07/27/15 4654 skorolev Added filters +# 11/11/15 5120 rferrel Cannot serialize empty filters. # class NotificationMessage: @@ -58,13 +60,14 @@ class NotificationMessage: 4: 'EVENTB', 5: 'VERBOSE'} - def __init__(self, host='localhost', port=61999, message='', priority='PROBLEM', category="LOCAL", source="ANNOUNCER", audioFile="NONE"): + def __init__(self, host='localhost', port=61999, message='', priority='PROBLEM', category="LOCAL", source="ANNOUNCER", audioFile="NONE", filters=None): self.host = host self.port = port self.message = message self.audioFile = audioFile self.source = source self.category = category + self.filters = filters priorityInt = None @@ -113,9 +116,9 @@ class NotificationMessage: # of the message to AlertViz # 9581 is global distribution thru ThriftClient to Edex # 61999 is local distribution - if (self.port == 61999): + if (int(self.port) == 61999): # use stomp.py - conn = stomp.Connection(host_and_ports=[(self.host, self.port)]) + conn = stomp.Connection(host_and_ports=[(self.host, 61999)]) timeout = threading.Timer(5.0, self.connection_timeout, [conn]) try: @@ -132,6 +135,8 @@ class NotificationMessage: sm.set("category", self.category) sm.set("sourceKey", self.source) sm.set("audioFile", self.audioFile) + if self.filters is not None and len(self.filters) > 0: + sm.set("filters", self.filters) msg = ET.SubElement(sm, "message") msg.text = self.message details = ET.SubElement(sm, "details") @@ -144,7 +149,7 @@ class NotificationMessage: conn.stop() else: # use ThriftClient - alertVizRequest = createRequest(self.message, self.priority, self.source, self.category, self.audioFile) + alertVizRequest = createRequest(self.message, self.priority, self.source, self.category, self.audioFile, self.filters) thriftClient = ThriftClient.ThriftClient(self.host, self.port, "/services") serverResponse = None @@ -159,7 +164,7 @@ class NotificationMessage: else: print("Response: " + str(serverResponse)) -def createRequest(message, priority, source, category, audioFile): +def createRequest(message, priority, source, category, audioFile, filters): obj = AlertVizRequest() obj.setMachine(socket.gethostname()) @@ -171,7 +176,7 @@ def createRequest(message, priority, source, category, audioFile): obj.setAudioFile(audioFile) else: obj.setAudioFile('\0') - + obj.setFilters(filters) return obj if __name__ == '__main__': diff --git a/awips/dataaccess/CombinedTimeQuery.py b/awips/dataaccess/CombinedTimeQuery.py new file mode 100644 index 0000000..8810e0e --- /dev/null +++ b/awips/dataaccess/CombinedTimeQuery.py @@ -0,0 +1,99 @@ +# # +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +# # + +# +# Method for performing a DAF time query where all parameter/level/location +# combinations must be available at the same time. +# +# +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 06/22/16 #5591 bsteffen Initial Creation. +# + +from awips.dataaccess import DataAccessLayer + +def getAvailableTimes(request, refTimeOnly=False): + return __getAvailableTimesForEachParameter(request, refTimeOnly) + +def __getAvailableTimesForEachParameter(request, refTimeOnly=False): + parameters = request.getParameters() + if parameters: + times = None + for parameter in parameters: + specificRequest = __cloneRequest(request) + specificRequest.setParameters(parameter) + specificTimes = __getAvailableTimesForEachLevel(specificRequest, refTimeOnly) + if times is None: + times = specificTimes + else: + times.intersection_update(specificTimes) + if not times: + break + return times + else: + return __getAvailableTimesForEachLevel(request, refTimeOnly) + +def __getAvailableTimesForEachLevel(request, refTimeOnly=False): + levels = request.getLevels() + if levels: + times = None + for level in levels: + specificRequest = __cloneRequest(request) + specificRequest.setLevels(level) + specificTimes = __getAvailableTimesForEachLocation(specificRequest, refTimeOnly) + if times is None: + times = specificTimes + else: + times.intersection_update(specificTimes) + if not times: + break + return times + else: + return __getAvailableTimesForEachLocation(request, refTimeOnly) + +def __getAvailableTimesForEachLocation(request, refTimeOnly=False): + locations = request.getLocationNames() + if locations: + times = None + for location in locations: + specificRequest = __cloneRequest(request) + specificRequest.setLocationNames(location) + specificTimes = DataAccessLayer.getAvailableTimes(specificRequest, refTimeOnly) + if times is None: + times = set(specificTimes) + else: + times.intersection_update(specificTimes) + if not times: + break + return times + else: + return DataAccessLayer.getAvailableTimes(request, refTimeOnly) + +def __cloneRequest(request): + return DataAccessLayer.newDataRequest(datatype = request.getDatatype(), + parameters = request.getParameters(), + levels = request.getLevels(), + locationNames = request.getLocationNames(), + envelope = request.getEnvelope(), + **request.getIdentifiers()) diff --git a/awips/dataaccess/DataAccessLayer.py b/awips/dataaccess/DataAccessLayer.py index 7344ff5..38e933e 100644 --- a/awips/dataaccess/DataAccessLayer.py +++ b/awips/dataaccess/DataAccessLayer.py @@ -30,12 +30,17 @@ # 12/10/12 njensen Initial Creation. # Feb 14, 2013 1614 bsteffen refactor data access framework # to use single request. -# 04/10/13 1871 mnash move getLatLonCoords to JGridData and add default args -# 05/29/13 2023 dgilling Hook up ThriftClientRouter. -# 03/03/14 2673 bsteffen Add ability to query only ref times. -# 07/22/14 3185 njensen Added optional/default args to newDataRequest -# 07/30/14 3185 njensen Renamed valid identifiers to optional -# Apr 26, 2015 4259 njensen Updated for new JEP API +# 04/10/13 1871 mnash move getLatLonCoords to JGridData and add default args +# 05/29/13 2023 dgilling Hook up ThriftClientRouter. +# 03/03/14 2673 bsteffen Add ability to query only ref times. +# 07/22/14 3185 njensen Added optional/default args to newDataRequest +# 07/30/14 3185 njensen Renamed valid identifiers to optional +# Apr 26, 2015 4259 njensen Updated for new JEP API +# Apr 13, 2016 5379 tgurney Add getIdentifierValues() +# Jun 01, 2016 5587 tgurney Add new signatures for +# getRequiredIdentifiers() and +# getOptionalIdentifiers() +# 10/07/16 ---- mjames@ucar Added getForecastRun # # # @@ -43,6 +48,7 @@ import sys import subprocess +import warnings THRIFT_HOST = "edex" USING_NATIVE_THRIFT = False @@ -58,17 +64,17 @@ else: router = ThriftClientRouter.ThriftClientRouter(THRIFT_HOST) USING_NATIVE_THRIFT = True -def getForecastCycle(cycle, times): +def getForecastRun(cycle, times): """ :param cycle: Forecast cycle reference time :param times: All available times/cycles :return: DataTime array for a single forecast run """ - forecast_run = [] - for time in times: - if time.getRefTime() == cycle.getRefTime(): - forecast_run.append(time) - return forecast_run + fcstRun = [] + for t in times: + if str(t)[:19] == str(cycle): + fcstRun.append(t) + return fcstRun def getAvailableTimes(request, refTimeOnly=False): """ @@ -81,6 +87,7 @@ def getAvailableTimes(request, refTimeOnly=False): """ return router.getAvailableTimes(request, refTimeOnly) + def getGridData(request, times=[]): """ Gets the grid data that matches the request at the specified times. Each @@ -94,6 +101,7 @@ def getGridData(request, times=[]): """ return router.getGridData(request, times) + def getGeometryData(request, times=[]): """ Gets the geometry data that matches the request at the specified times. @@ -107,6 +115,7 @@ def getGeometryData(request, times=[]): """ return router.getGeometryData(request, times) + def getAvailableLocationNames(request): """ Gets the available location names that match the request without actually @@ -118,6 +127,7 @@ def getAvailableLocationNames(request): """ return router.getAvailableLocationNames(request) + def getAvailableParameters(request): """ Gets the available parameters names that match the request without actually @@ -129,6 +139,7 @@ def getAvailableParameters(request): """ return router.getAvailableParameters(request) + def getAvailableLevels(request): """ Gets the available levels that match the request without actually @@ -140,26 +151,46 @@ def getAvailableLevels(request): """ return router.getAvailableLevels(request) -def getRequiredIdentifiers(datatype): + +def getRequiredIdentifiers(request): """ - Gets the required identifiers for this datatype. These identifiers + Gets the required identifiers for this request. These identifiers must be set on a request for the request of this datatype to succeed. - :param datatype: the datatype to find required identifiers for + :param request: the request to find required identifiers :returns: a list of strings of required identifiers """ - return router.getRequiredIdentifiers(datatype) + if str(request) == request: + warnings.warn("Use getRequiredIdentifiers(IDataRequest) instead", + DeprecationWarning) + return router.getRequiredIdentifiers(request) -def getOptionalIdentifiers(datatype): + +def getOptionalIdentifiers(request): """ - Gets the optional identifiers for this datatype. + Gets the optional identifiers for this request. - :param datatype: the datatype to find optional identifiers for + :param request: the reuqest to find optional identifiers for :returns: a list of strings of optional identifiers """ - return router.getOptionalIdentifiers(datatype) + if str(request) == request: + warnings.warn("Use getOptionalIdentifiers(IDataRequest) instead", + DeprecationWarning) + return router.getOptionalIdentifiers(request) + + +def getIdentifierValues(request, identifierKey): + """ + Gets the allowed values for a particular identifier on this datatype. + + :param request: the request to find identifier values for + :praram identifierKey: the identifier to find values for + + :returns: a list of strings of allowed values for the specified identifier + """ + return router.getIdentifierValues(request, identifierKey) def newDataRequest(datatype=None, **kwargs): """ diff --git a/awips/dataaccess/PyGeometryData.py b/awips/dataaccess/PyGeometryData.py index 6debd3d..8cbe95c 100644 --- a/awips/dataaccess/PyGeometryData.py +++ b/awips/dataaccess/PyGeometryData.py @@ -28,10 +28,11 @@ # Date Ticket# Engineer Description # ------------ ---------- ----------- -------------------------- # 06/03/13 dgilling Initial Creation. -# 01/06/14 #2537 bsteffen Share geometry WKT. -# 03/19/14 #2882 dgilling Raise an exception when getNumber() +# 01/06/14 2537 bsteffen Share geometry WKT. +# 03/19/14 2882 dgilling Raise an exception when getNumber() # is called for data that is not a # numeric Type. +# 06/09/16 5574 mapeters Handle 'SHORT' type in getNumber(). # # @@ -61,7 +62,7 @@ class PyGeometryData(IGeometryData, PyData.PyData): def getNumber(self, param): value = self.__dataMap[param][0] t = self.getType(param) - if t == 'INT': + if t == 'INT' or t == 'SHORT': return int(value) elif t == 'LONG': return int(value) diff --git a/awips/dataaccess/PyGridData.py b/awips/dataaccess/PyGridData.py index 2275710..87fffac 100644 --- a/awips/dataaccess/PyGridData.py +++ b/awips/dataaccess/PyGridData.py @@ -28,6 +28,7 @@ # Date Ticket# Engineer Description # ------------ ---------- ----------- -------------------------- # 06/03/13 #2023 dgilling Initial Creation. +# 11/10/16 #5900 bsteffen Correct grid shape # # @@ -51,7 +52,7 @@ class PyGridData(IGridData, PyData.PyData): ny = ny self.__parameter = gridDataRecord.getParameter() self.__unit = gridDataRecord.getUnit() - self.__gridData = numpy.reshape(numpy.array(gridDataRecord.getGridData()), (nx, ny)) + self.__gridData = numpy.reshape(numpy.array(gridDataRecord.getGridData()), (ny, nx)) self.__latLonGrid = latLonGrid def getParameter(self): diff --git a/awips/dataaccess/ThriftClientRouter.py b/awips/dataaccess/ThriftClientRouter.py index 327d469..c1f8126 100644 --- a/awips/dataaccess/ThriftClientRouter.py +++ b/awips/dataaccess/ThriftClientRouter.py @@ -23,17 +23,22 @@ # # # -# SOFTWARE HISTORY +# SOFTWARE HISTORY # # Date Ticket# Engineer Description # ------------ ---------- ----------- -------------------------- -# 05/21/13 #2023 dgilling Initial Creation. -# 01/06/14 #2537 bsteffen Share geometry WKT. -# 03/03/14 #2673 bsteffen Add ability to query only ref times. -# 07/22/14 #3185 njensen Added optional/default args to newDataRequest -# 07/23/14 #3185 njensen Added new methods -# 07/30/14 #3185 njensen Renamed valid identifiers to optional -# 06/30/15 #4569 nabowle Use hex WKB for geometries. +# 05/21/13 2023 dgilling Initial Creation. +# 01/06/14 2537 bsteffen Share geometry WKT. +# 03/03/14 2673 bsteffen Add ability to query only ref times. +# 07/22/14 3185 njensen Added optional/default args to newDataRequest +# 07/23/14 3185 njensen Added new methods +# 07/30/14 3185 njensen Renamed valid identifiers to optional +# 06/30/15 4569 nabowle Use hex WKB for geometries. +# 04/13/15 5379 tgurney Add getIdentifierValues() +# 06/01/16 5587 tgurney Add new signatures for +# getRequiredIdentifiers() and +# getOptionalIdentifiers() +# 11/10/16 5900 bsteffen Correct grid shape # @@ -49,6 +54,7 @@ from dynamicserialize.dstypes.com.raytheon.uf.common.dataaccess.request import G from dynamicserialize.dstypes.com.raytheon.uf.common.dataaccess.request import GetAvailableLevelsRequest from dynamicserialize.dstypes.com.raytheon.uf.common.dataaccess.request import GetRequiredIdentifiersRequest from dynamicserialize.dstypes.com.raytheon.uf.common.dataaccess.request import GetOptionalIdentifiersRequest +from dynamicserialize.dstypes.com.raytheon.uf.common.dataaccess.request import GetIdentifierValuesRequest from dynamicserialize.dstypes.com.raytheon.uf.common.dataaccess.request import GetSupportedDatatypesRequest from awips import ThriftClient @@ -87,8 +93,8 @@ class ThriftClientRouter(object): for location in locNames: nx = response.getSiteNxValues()[location] ny = response.getSiteNyValues()[location] - latData = numpy.reshape(numpy.array(response.getSiteLatGrids()[location]), (nx, ny)) - lonData = numpy.reshape(numpy.array(response.getSiteLonGrids()[location]), (nx, ny)) + latData = numpy.reshape(numpy.array(response.getSiteLatGrids()[location]), (ny, nx)) + lonData = numpy.reshape(numpy.array(response.getSiteLonGrids()[location]), (ny, nx)) locSpecificData[location] = (nx, ny, (lonData, latData)) retVal = [] @@ -143,18 +149,31 @@ class ThriftClientRouter(object): response = self._client.sendRequest(levelReq) return response - def getRequiredIdentifiers(self, datatype): + def getRequiredIdentifiers(self, request): + if str(request) == request: + # Handle old version getRequiredIdentifiers(str) + request = self.newDataRequest(request) idReq = GetRequiredIdentifiersRequest() - idReq.setDatatype(datatype) + idReq.setRequest(request) response = self._client.sendRequest(idReq) return response - def getOptionalIdentifiers(self, datatype): + def getOptionalIdentifiers(self, request): + if str(request) == request: + # Handle old version getOptionalIdentifiers(str) + request = self.newDataRequest(request) idReq = GetOptionalIdentifiersRequest() - idReq.setDatatype(datatype) + idReq.setRequest(request) response = self._client.sendRequest(idReq) return response + def getIdentifierValues(self, request, identifierKey): + idValReq = GetIdentifierValuesRequest() + idValReq.setIdentifierKey(identifierKey) + idValReq.setRequestParameters(request) + response = self._client.sendRequest(idValReq) + return response + def newDataRequest(self, datatype, parameters=[], levels=[], locationNames = [], envelope=None, **kwargs): req = DefaultDataRequest() if datatype: diff --git a/awips/test/dafTests/__init__.py b/awips/test/dafTests/__init__.py new file mode 100644 index 0000000..6041dc1 --- /dev/null +++ b/awips/test/dafTests/__init__.py @@ -0,0 +1,36 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + + +# +# __init__.py for awips.test.dafTests package +# +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 02/09/2016 4795 mapeters Initial creation. +# 04/12/2016 5548 tgurney Cleanup +# +# +# + +__all__ = [] diff --git a/awips/test/dafTests/baseBufrMosTestCase.py b/awips/test/dafTests/baseBufrMosTestCase.py new file mode 100644 index 0000000..652d838 --- /dev/null +++ b/awips/test/dafTests/baseBufrMosTestCase.py @@ -0,0 +1,59 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from awips.dataaccess import DataAccessLayer as DAL + +import baseDafTestCase + +# +# Base TestCase for BufrMos* tests. +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# +# +# + + +class BufrMosTestCase(baseDafTestCase.DafTestCase): + """Base class for testing DAF support of bufrmos data""" + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + self.runParametersTest(req) + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + self.runLocationsTest(req) + + def testGetAvailableTimes(self): + req = DAL.newDataRequest(self.datatype) + req.setLocationNames("KOMA") + self.runTimesTest(req) + + def testGetGeometryData(self): + req = DAL.newDataRequest(self.datatype) + req.setLocationNames("KOMA") + req.setParameters("temperature", "dewpoint") + self.runGeometryDataTest(req) diff --git a/awips/test/dafTests/baseDafTestCase.py b/awips/test/dafTests/baseDafTestCase.py new file mode 100644 index 0000000..f857ac1 --- /dev/null +++ b/awips/test/dafTests/baseDafTestCase.py @@ -0,0 +1,218 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function + +from awips.dataaccess import DataAccessLayer as DAL +from awips.ThriftClient import ThriftRequestException + +import os +import unittest + +# +# Base TestCase for DAF tests. This class provides helper methods and +# tests common to all DAF test cases. +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/13/16 5379 tgurney Add identifier values tests +# 04/18/16 5548 tgurney More cleanup, plus new tests +# 04/26/16 5587 tgurney Move identifier values tests +# to subclasses +# 06/01/16 5587 tgurney Add testGet*Identifiers +# 06/07/16 5574 tgurney Make geometry/grid data tests +# return the retrieved data +# 06/10/16 5548 tgurney Make testDatatypeIsSupported +# case-insensitive +# 10/05/16 5926 dgilling Better checks in runGeometryDataTest. +# 11/08/16 5985 tgurney Do not check data times on +# time-agnostic data +# +# + + +class DafTestCase(unittest.TestCase): + + sampleDataLimit = 5 + """ + Maximum number of levels, locations, times, and geometry/grid data to + display + """ + + numTimesToLimit = 3 + """ + When limiting geometry/grid data requests with times, only retrieve data + for this many times + """ + + datatype = None + """Name of the datatype""" + + @classmethod + def setUp(cls): + host = os.environ.get('DAF_TEST_HOST') + if host is None: + host = 'localhost' + DAL.changeEDEXHost(host) + + @staticmethod + def getTimesIfSupported(req): + """Return available times for req. If req refers to a time-agnostic + datatype, return an empty list instead. + """ + times = [] + try: + times = DAL.getAvailableTimes(req) + except ThriftRequestException as e: + if not 'TimeAgnosticDataException' in str(e): + raise + return times + + def testDatatypeIsSupported(self): + allSupported = (item.lower() for item in DAL.getSupportedDatatypes()) + self.assertIn(self.datatype.lower(), allSupported) + + def testGetRequiredIdentifiers(self): + req = DAL.newDataRequest(self.datatype) + required = DAL.getRequiredIdentifiers(req) + self.assertIsNotNone(required) + print("Required identifiers:", required) + + def testGetOptionalIdentifiers(self): + req = DAL.newDataRequest(self.datatype) + optional = DAL.getOptionalIdentifiers(req) + self.assertIsNotNone(optional) + print("Optional identifiers:", optional) + + def runGetIdValuesTest(self, identifiers): + for id in identifiers: + req = DAL.newDataRequest(self.datatype) + idValues = DAL.getIdentifierValues(req, id) + self.assertTrue(hasattr(idValues, '__iter__')) + + def runInvalidIdValuesTest(self): + badString = 'id from ' + self.datatype + '; select 1;' + with self.assertRaises(ThriftRequestException) as cm: + req = DAL.newDataRequest(self.datatype) + idValues = DAL.getIdentifierValues(req, badString) + + def runNonexistentIdValuesTest(self): + with self.assertRaises(ThriftRequestException) as cm: + req = DAL.newDataRequest(self.datatype) + idValues = DAL.getIdentifierValues(req, 'idthatdoesnotexist') + + def runParametersTest(self, req): + params = DAL.getAvailableParameters(req) + self.assertIsNotNone(params) + print(params) + + def runLevelsTest(self, req): + levels = DAL.getAvailableLevels(req) + self.assertIsNotNone(levels) + print("Number of levels: " + str(len(levels))) + strLevels = [str(t) for t in levels[:self.sampleDataLimit]] + print("Sample levels:\n" + str(strLevels)) + + def runLocationsTest(self, req): + locs = DAL.getAvailableLocationNames(req) + self.assertIsNotNone(locs) + print("Number of location names: " + str(len(locs))) + print("Sample location names:\n" + str(locs[:self.sampleDataLimit])) + + def runTimesTest(self, req): + times = DAL.getAvailableTimes(req) + self.assertIsNotNone(times) + print("Number of times: " + str(len(times))) + strTimes = [str(t) for t in times[:self.sampleDataLimit]] + print("Sample times:\n" + str(strTimes)) + + def runTimeAgnosticTest(self, req): + with self.assertRaises(ThriftRequestException) as cm: + times = DAL.getAvailableTimes(req) + self.assertIn('TimeAgnosticDataException', str(cm.exception)) + + def runGeometryDataTest(self, req, checkDataTimes=True): + """ + Test that we are able to successfully retrieve geometry data for the + given request. + """ + times = DafTestCase.getTimesIfSupported(req) + geomData = DAL.getGeometryData(req, times[:self.numTimesToLimit]) + self.assertIsNotNone(geomData) + if times: + self.assertNotEqual(len(geomData), 0) + print("Number of geometry records: " + str(len(geomData))) + print("Sample geometry data:") + for record in geomData[:self.sampleDataLimit]: + if checkDataTimes and times: + self.assertIn(record.getDataTime(), times[:self.numTimesToLimit]) + print("geometry=" + str(record.getGeometry()), end="") + for p in req.getParameters(): + print(" " + p + "=" + record.getString(p), end="") + print() + return geomData + + def runGeometryDataTestWithTimeRange(self, req, timeRange): + """ + Test that we are able to successfully retrieve geometry data for the + given request. + """ + geomData = DAL.getGeometryData(req, timeRange) + self.assertIsNotNone(geomData) + print("Number of geometry records: " + str(len(geomData))) + print("Sample geometry data:") + for record in geomData[:self.sampleDataLimit]: + self.assertGreaterEqual(record.getDataTime().getRefTime().getTime(), timeRange.getStartInMillis()) + self.assertLessEqual(record.getDataTime().getRefTime().getTime(), timeRange.getEndInMillis()) + print("geometry=" + str(record.getGeometry()), end="") + for p in req.getParameters(): + print(" " + p + "=" + record.getString(p), end="") + print() + return geomData + + def runGridDataTest(self, req, testSameShape=True): + """ + Test that we are able to successfully retrieve grid data for the given + request. + + Args: + testSameShape: whether or not to verify that all the retrieved data + have the same shape (most data don't change shape) + """ + times = DafTestCase.getTimesIfSupported(req) + gridData = DAL.getGridData(req, times[:self.numTimesToLimit]) + self.assertIsNotNone(gridData) + print("Number of grid records: " + str(len(gridData))) + if len(gridData) > 0: + print("Sample grid data shape:\n" + str(gridData[0].getRawData().shape) + "\n") + print("Sample grid data:\n" + str(gridData[0].getRawData()) + "\n") + print("Sample lat-lon data:\n" + str(gridData[0].getLatLonCoords()) + "\n") + + if testSameShape: + correctGridShape = gridData[0].getLatLonCoords()[0].shape + for record in gridData: + rawData = record.getRawData() + self.assertIsNotNone(rawData) + self.assertEqual(rawData.shape, correctGridShape) + return gridData diff --git a/awips/test/dafTests/testAcars.py b/awips/test/dafTests/testAcars.py new file mode 100644 index 0000000..9ab9167 --- /dev/null +++ b/awips/test/dafTests/testAcars.py @@ -0,0 +1,61 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from awips.dataaccess import DataAccessLayer as DAL + +import baseDafTestCase +import unittest + +# +# Test DAF support for ACARS data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# +# + + +class AcarsTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for ACARS data""" + + datatype = "acars" + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + self.runParametersTest(req) + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + self.runLocationsTest(req) + + def testGetAvailableTimes(self): + req = DAL.newDataRequest(self.datatype) + self.runTimesTest(req) + + def testGetGeometryData(self): + req = DAL.newDataRequest(self.datatype) + req.setParameters("flightLevel", "tailNumber") + self.runGeometryDataTest(req) diff --git a/awips/test/dafTests/testAirep.py b/awips/test/dafTests/testAirep.py new file mode 100644 index 0000000..32cd903 --- /dev/null +++ b/awips/test/dafTests/testAirep.py @@ -0,0 +1,165 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from awips.dataaccess import DataAccessLayer as DAL + +from dynamicserialize.dstypes.com.raytheon.uf.common.dataquery.requests import RequestConstraint +import baseDafTestCase +import unittest + +# +# Test DAF support for airep data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# 06/09/16 5587 bsteffen Add getIdentifierValues tests +# 06/13/16 5574 tgurney Add advanced query tests +# +# + + +class AirepTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for airep data""" + + datatype = "airep" + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + self.runParametersTest(req) + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + self.runLocationsTest(req) + + def testGetAvailableTimes(self): + req = DAL.newDataRequest(self.datatype) + self.runTimesTest(req) + + def testGetGeometryData(self): + req = DAL.newDataRequest(self.datatype) + req.setParameters("flightLevel", "reportType") + self.runGeometryDataTest(req) + + def testGetIdentifierValues(self): + req = DAL.newDataRequest(self.datatype) + optionalIds = set(DAL.getOptionalIdentifiers(req)) + self.runGetIdValuesTest(optionalIds) + + def testGetInvalidIdentifierValuesThrowsException(self): + self.runInvalidIdValuesTest() + + def testGetNonexistentIdentifierValuesThrowsException(self): + self.runNonexistentIdValuesTest() + + def _runConstraintTest(self, key, operator, value): + req = DAL.newDataRequest(self.datatype) + constraint = RequestConstraint.new(operator, value) + req.setParameters("flightLevel", "reportType") + req.addIdentifier(key, constraint) + return self.runGeometryDataTest(req) + + def testGetDataWithEqualsString(self): + geometryData = self._runConstraintTest('reportType', '=', 'AIREP') + for record in geometryData: + self.assertEqual(record.getString('reportType'), 'AIREP') + + def testGetDataWithEqualsUnicode(self): + geometryData = self._runConstraintTest('reportType', '=', u'AIREP') + for record in geometryData: + self.assertEqual(record.getString('reportType'), 'AIREP') + + # No numeric tests since no numeric identifiers are available. + + def testGetDataWithEqualsNone(self): + geometryData = self._runConstraintTest('reportType', '=', None) + for record in geometryData: + self.assertEqual(record.getType('reportType'), 'NULL') + + def testGetDataWithNotEquals(self): + geometryData = self._runConstraintTest('reportType', '!=', 'AIREP') + for record in geometryData: + self.assertNotEqual(record.getString('reportType'), 'AIREP') + + def testGetDataWithNotEqualsNone(self): + geometryData = self._runConstraintTest('reportType', '!=', None) + for record in geometryData: + self.assertNotEqual(record.getType('reportType'), 'NULL') + + def testGetDataWithGreaterThan(self): + geometryData = self._runConstraintTest('reportType', '>', 'AIREP') + for record in geometryData: + self.assertGreater(record.getString('reportType'), 'AIREP') + + def testGetDataWithLessThan(self): + geometryData = self._runConstraintTest('reportType', '<', 'AIREP') + for record in geometryData: + self.assertLess(record.getString('reportType'), 'AIREP') + + def testGetDataWithGreaterThanEquals(self): + geometryData = self._runConstraintTest('reportType', '>=', 'AIREP') + for record in geometryData: + self.assertGreaterEqual(record.getString('reportType'), 'AIREP') + + def testGetDataWithLessThanEquals(self): + geometryData = self._runConstraintTest('reportType', '<=', 'AIREP') + for record in geometryData: + self.assertLessEqual(record.getString('reportType'), 'AIREP') + + def testGetDataWithInTuple(self): + collection = ('AIREP', 'AMDAR') + geometryData = self._runConstraintTest('reportType', 'in', collection) + for record in geometryData: + self.assertIn(record.getString('reportType'), collection) + + def testGetDataWithInList(self): + collection = ['AIREP', 'AMDAR'] + geometryData = self._runConstraintTest('reportType', 'in', collection) + for record in geometryData: + self.assertIn(record.getString('reportType'), collection) + + def testGetDataWithInGenerator(self): + collection = ('AIREP', 'AMDAR') + generator = (item for item in collection) + geometryData = self._runConstraintTest('reportType', 'in', generator) + for record in geometryData: + self.assertIn(record.getString('reportType'), collection) + + def testGetDataWithInvalidConstraintTypeThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('reportType', 'junk', 'AIREP') + + def testGetDataWithInvalidConstraintValueThrowsException(self): + with self.assertRaises(TypeError): + self._runConstraintTest('reportType', '=', {}) + + def testGetDataWithEmptyInConstraintThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('reportType', 'in', []) + + def testGetDataWithNestedInConstraintThrowsException(self): + collection = ('AIREP', 'AMDAR', ()) + with self.assertRaises(TypeError): + self._runConstraintTest('reportType', 'in', collection) diff --git a/awips/test/dafTests/testBinLightning.py b/awips/test/dafTests/testBinLightning.py new file mode 100644 index 0000000..134d059 --- /dev/null +++ b/awips/test/dafTests/testBinLightning.py @@ -0,0 +1,192 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from awips.dataaccess import DataAccessLayer as DAL +from awips.ThriftClient import ThriftRequestException +from dynamicserialize.dstypes.com.raytheon.uf.common.dataquery.requests import RequestConstraint + + +import baseDafTestCase +import unittest + +# +# Test DAF support for binlightning data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# 04/21/16 5551 tgurney Add tests to verify #5551 +# 04/25/16 5587 tgurney Enable skipped test added in +# #5551 +# 04/26/16 5587 tgurney Move identifier values tests +# out of base class +# 06/01/16 5587 tgurney Update testGetIdentifierValues +# 06/03/16 5574 tgurney Add advanced query tests +# 06/13/16 5574 tgurney Typo +# 11/08/16 5985 tgurney Do not check data times +# +# + + +class BinLightningTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for binlightning data""" + + datatype = "binlightning" + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + self.runParametersTest(req) + + def testGetAvailableTimes(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier("source", "NLDN") + self.runTimesTest(req) + + def testGetGeometryDataSingleSourceSingleParameter(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier("source", "NLDN") + req.setParameters('intensity') + self.runGeometryDataTest(req, checkDataTimes=False) + + def testGetGeometryDataInvalidParamRaisesIncompatibleRequestException(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier("source", "NLDN") + req.setParameters('blahblahblah') + with self.assertRaises(ThriftRequestException) as cm: + self.runGeometryDataTest(req) + self.assertIn('IncompatibleRequestException', str(cm.exception)) + + def testGetGeometryDataSingleSourceAllParameters(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier("source", "NLDN") + req.setParameters(*DAL.getAvailableParameters(req)) + self.runGeometryDataTest(req, checkDataTimes=False) + + def testGetIdentifierValues(self): + req = DAL.newDataRequest(self.datatype) + optionalIds = set(DAL.getOptionalIdentifiers(req)) + requiredIds = set(DAL.getRequiredIdentifiers(req)) + self.runGetIdValuesTest(optionalIds | requiredIds) + + def testGetInvalidIdentifierValuesThrowsException(self): + self.runInvalidIdValuesTest() + + def testGetNonexistentIdentifierValuesThrowsException(self): + self.runNonexistentIdValuesTest() + + def _runConstraintTest(self, key, operator, value): + req = DAL.newDataRequest(self.datatype) + constraint = RequestConstraint.new(operator, value) + req.addIdentifier(key, constraint) + req.setParameters('intensity') + return self.runGeometryDataTest(req, checkDataTimes=False) + + def testGetDataWithEqualsString(self): + geomData = self._runConstraintTest('source', '=', 'NLDN') + for record in geomData: + self.assertEqual(record.getAttribute('source'), 'NLDN') + + def testGetDataWithEqualsUnicode(self): + geomData = self._runConstraintTest('source', '=', u'NLDN') + for record in geomData: + self.assertEqual(record.getAttribute('source'), 'NLDN') + + def testGetDataWithEqualsInt(self): + geomData = self._runConstraintTest('source', '=', 1000) + for record in geomData: + self.assertEqual(record.getAttribute('source'), 1000) + + def testGetDataWithEqualsLong(self): + geomData = self._runConstraintTest('source', '=', 1000L) + for record in geomData: + self.assertEqual(record.getAttribute('source'), 1000) + + def testGetDataWithEqualsFloat(self): + geomData = self._runConstraintTest('source', '=', 1.0) + for record in geomData: + self.assertEqual(round(record.getAttribute('source'), 1), 1.0) + + def testGetDataWithEqualsNone(self): + geomData = self._runConstraintTest('source', '=', None) + for record in geomData: + self.assertIsNone(record.getAttribute('source')) + + def testGetDataWithNotEquals(self): + geomData = self._runConstraintTest('source', '!=', 'NLDN') + for record in geomData: + self.assertNotEqual(record.getAttribute('source'), 'NLDN') + + def testGetDataWithNotEqualsNone(self): + geomData = self._runConstraintTest('source', '!=', None) + for record in geomData: + self.assertIsNotNone(record.getAttribute('source')) + + def testGetDataWithGreaterThan(self): + geomData = self._runConstraintTest('source', '>', 'NLDN') + for record in geomData: + self.assertGreater(record.getAttribute('source'), 'NLDN') + + def testGetDataWithLessThan(self): + geomData = self._runConstraintTest('source', '<', 'NLDN') + for record in geomData: + self.assertLess(record.getAttribute('source'), 'NLDN') + + def testGetDataWithGreaterThanEquals(self): + geomData = self._runConstraintTest('source', '>=', 'NLDN') + for record in geomData: + self.assertGreaterEqual(record.getAttribute('source'), 'NLDN') + + def testGetDataWithLessThanEquals(self): + geomData = self._runConstraintTest('source', '<=', 'NLDN') + for record in geomData: + self.assertLessEqual(record.getAttribute('source'), 'NLDN') + + def testGetDataWithInTuple(self): + geomData = self._runConstraintTest('source', 'in', ('NLDN', 'ENTLN')) + for record in geomData: + self.assertIn(record.getAttribute('source'), ('NLDN', 'ENTLN')) + + def testGetDataWithInList(self): + geomData = self._runConstraintTest('source', 'in', ['NLDN', 'ENTLN']) + for record in geomData: + self.assertIn(record.getAttribute('source'), ('NLDN', 'ENTLN')) + + def testGetDataWithInGenerator(self): + generator = (item for item in ('NLDN', 'ENTLN')) + geomData = self._runConstraintTest('source', 'in', generator) + for record in geomData: + self.assertIn(record.getAttribute('source'), ('NLDN', 'ENTLN')) + + def testGetDataWithInvalidConstraintTypeThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('source', 'junk', 'NLDN') + + def testGetDataWithInvalidConstraintValueThrowsException(self): + with self.assertRaises(TypeError): + self._runConstraintTest('source', '=', {}) + + def testGetDataWithEmptyInConstraintThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('source', 'in', []) diff --git a/awips/test/dafTests/testBufrMosAvn.py b/awips/test/dafTests/testBufrMosAvn.py new file mode 100644 index 0000000..38409bd --- /dev/null +++ b/awips/test/dafTests/testBufrMosAvn.py @@ -0,0 +1,45 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function + +import baseBufrMosTestCase +import unittest + +# +# Test DAF support for bufrmosAVN data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# +# + + +class BufrMosAvnTestCase(baseBufrMosTestCase.BufrMosTestCase): + """Test DAF support for bufrmosAVN data""" + + datatype = "bufrmosAVN" + + # All tests inherited from superclass diff --git a/awips/test/dafTests/testBufrMosEta.py b/awips/test/dafTests/testBufrMosEta.py new file mode 100644 index 0000000..9c7c8d3 --- /dev/null +++ b/awips/test/dafTests/testBufrMosEta.py @@ -0,0 +1,45 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function + +import baseBufrMosTestCase +import unittest + +# +# Test DAF support for bufrmosETA data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# +# + + +class BufrMosEtaTestCase(baseBufrMosTestCase.BufrMosTestCase): + """Test DAF support for bufrmosETA data""" + + datatype = "bufrmosETA" + + # All tests inherited from superclass diff --git a/awips/test/dafTests/testBufrMosGfs.py b/awips/test/dafTests/testBufrMosGfs.py new file mode 100644 index 0000000..1b5819c --- /dev/null +++ b/awips/test/dafTests/testBufrMosGfs.py @@ -0,0 +1,45 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function + +import baseBufrMosTestCase +import unittest + +# +# Test DAF support for bufrmosGFS data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# +# + + +class BufrMosGfsTestCase(baseBufrMosTestCase.BufrMosTestCase): + """Test DAF support for bufrmosGFS data""" + + datatype = "bufrmosGFS" + + # All tests inherited from superclass diff --git a/awips/test/dafTests/testBufrMosHpc.py b/awips/test/dafTests/testBufrMosHpc.py new file mode 100644 index 0000000..e1ab295 --- /dev/null +++ b/awips/test/dafTests/testBufrMosHpc.py @@ -0,0 +1,52 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from awips.dataaccess import DataAccessLayer as DAL + +import baseBufrMosTestCase +import unittest + +# +# Test DAF support for bufrmosHPC data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# +# + + +class BufrMosHpcTestCase(baseBufrMosTestCase.BufrMosTestCase): + """Test DAF support for bufrmosHPC data""" + + datatype = "bufrmosHPC" + + # Most tests inherited from superclass + + def testGetGeometryData(self): + req = DAL.newDataRequest(self.datatype) + req.setLocationNames("KOMA") + req.setParameters("forecastHr", "maxTemp24Hour") + self.runGeometryDataTest(req) diff --git a/awips/test/dafTests/testBufrMosLamp.py b/awips/test/dafTests/testBufrMosLamp.py new file mode 100644 index 0000000..a3dc723 --- /dev/null +++ b/awips/test/dafTests/testBufrMosLamp.py @@ -0,0 +1,45 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function + +import baseBufrMosTestCase +import unittest + +# +# Test DAF support for bufrmosLAMP data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# +# + + +class BufrMosLampTestCase(baseBufrMosTestCase.BufrMosTestCase): + """Test DAF support for bufrmosLAMP data""" + + datatype = "bufrmosLAMP" + + # All tests inherited from superclass diff --git a/awips/test/dafTests/testBufrMosMrf.py b/awips/test/dafTests/testBufrMosMrf.py new file mode 100644 index 0000000..27d1b0f --- /dev/null +++ b/awips/test/dafTests/testBufrMosMrf.py @@ -0,0 +1,52 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from awips.dataaccess import DataAccessLayer as DAL + +import baseBufrMosTestCase +import unittest + +# +# Test DAF support for bufrmosMRF data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# +# + + +class BufrMosMrfTestCase(baseBufrMosTestCase.BufrMosTestCase): + """Test DAF support for bufrmosMRF data""" + + datatype = "bufrmosMRF" + + # Most tests inherited from superclass + + def testGetGeometryData(self): + req = DAL.newDataRequest(self.datatype) + req.setLocationNames("KOMA") + req.setParameters("forecastHr", "maxTempDay") + self.runGeometryDataTest(req) diff --git a/awips/test/dafTests/testBufrUa.py b/awips/test/dafTests/testBufrUa.py new file mode 100644 index 0000000..46c7c4f --- /dev/null +++ b/awips/test/dafTests/testBufrUa.py @@ -0,0 +1,205 @@ +# # +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +# # + +from __future__ import print_function +from awips.dataaccess import DataAccessLayer as DAL + +from dynamicserialize.dstypes.com.raytheon.uf.common.dataquery.requests import RequestConstraint +import baseDafTestCase +import unittest + +# +# Test DAF support for bufrua data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# 06/09/16 5587 bsteffen Add getIdentifierValues tests +# 06/13/16 5574 tgurney Add advanced query tests +# +# + + +class BufrUaTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for bufrua data""" + + datatype = "bufrua" + + location = "72558" + """stationid corresponding to KOAX""" + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + self.runParametersTest(req) + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier("reportType", "2020") + self.runLocationsTest(req) + + def testGetAvailableTimes(self): + req = DAL.newDataRequest(self.datatype) + req.setLocationNames(self.location) + req.addIdentifier("reportType", "2020") + self.runTimesTest(req) + + def testGetGeometryData(self): + req = DAL.newDataRequest(self.datatype) + req.setLocationNames(self.location) + req.addIdentifier("reportType", "2020") + req.setParameters("sfcPressure", "staName", "rptType", "tdMan") + + print("Testing getGeometryData()") + + geomData = DAL.getGeometryData(req) + self.assertIsNotNone(geomData) + print("Number of geometry records: " + str(len(geomData))) + print("Sample geometry data:") + for record in geomData[:self.sampleDataLimit]: + print("level=", record.getLevel(), end="") + # One dimensional parameters are reported on the 0.0UNKNOWN level. + # 2D parameters are reported on MB levels from pressure. + if record.getLevel() == "0.0UNKNOWN": + print(" sfcPressure=" + record.getString("sfcPressure") + record.getUnit("sfcPressure"), end="") + print(" staName=" + record.getString("staName"), end="") + print(" rptType=" + record.getString("rptType") + record.getUnit("rptType"), end="") + else: + print(" tdMan=" + str(record.getNumber("tdMan")) + record.getUnit("tdMan"), end="") + print(" geometry=", record.getGeometry()) + + print("getGeometryData() complete\n\n") + + def testGetIdentifierValues(self): + req = DAL.newDataRequest(self.datatype) + optionalIds = set(DAL.getOptionalIdentifiers(req)) + self.runGetIdValuesTest(optionalIds) + + def testGetInvalidIdentifierValuesThrowsException(self): + self.runInvalidIdValuesTest() + + def testGetNonexistentIdentifierValuesThrowsException(self): + self.runNonexistentIdValuesTest() + + def _runConstraintTest(self, key, operator, value): + req = DAL.newDataRequest(self.datatype) + constraint = RequestConstraint.new(operator, value) + req.addIdentifier(key, constraint) + # As an identifier it is "reportType" but as a parameter it is + # "rptType"... this is weird... + req.setParameters("staName", "rptType") + return self.runGeometryDataTest(req) + + def testGetDataWithEqualsString(self): + geometryData = self._runConstraintTest('reportType', '=', '2022') + for record in geometryData: + self.assertEqual(record.getString('rptType'), '2022') + + def testGetDataWithEqualsUnicode(self): + geometryData = self._runConstraintTest('reportType', '=', u'2022') + for record in geometryData: + self.assertEqual(record.getString('rptType'), '2022') + + def testGetDataWithEqualsInt(self): + geometryData = self._runConstraintTest('reportType', '=', 2022) + for record in geometryData: + self.assertEqual(record.getString('rptType'), '2022') + + def testGetDataWithEqualsLong(self): + geometryData = self._runConstraintTest('reportType', '=', 2022L) + for record in geometryData: + self.assertEqual(record.getString('rptType'), '2022') + + # No float test because no float identifiers are available + + + def testGetDataWithEqualsNone(self): + geometryData = self._runConstraintTest('reportType', '=', None) + for record in geometryData: + self.assertEqual(record.getType('rptType'), 'NULL') + + def testGetDataWithNotEquals(self): + geometryData = self._runConstraintTest('reportType', '!=', 2022) + for record in geometryData: + self.assertNotEqual(record.getString('rptType'), '2022') + + def testGetDataWithNotEqualsNone(self): + geometryData = self._runConstraintTest('reportType', '!=', None) + for record in geometryData: + self.assertNotEqual(record.getType('rptType'), 'NULL') + + def testGetDataWithGreaterThan(self): + geometryData = self._runConstraintTest('reportType', '>', 2022) + for record in geometryData: + self.assertGreater(record.getString('rptType'), '2022') + + def testGetDataWithLessThan(self): + geometryData = self._runConstraintTest('reportType', '<', 2022) + for record in geometryData: + self.assertLess(record.getString('rptType'), '2022') + + def testGetDataWithGreaterThanEquals(self): + geometryData = self._runConstraintTest('reportType', '>=', 2022) + for record in geometryData: + self.assertGreaterEqual(record.getString('rptType'), '2022') + + def testGetDataWithLessThanEquals(self): + geometryData = self._runConstraintTest('reportType', '<=', 2022) + for record in geometryData: + self.assertLessEqual(record.getString('rptType'), '2022') + + def testGetDataWithInTuple(self): + collection = ('2022', '2032') + geometryData = self._runConstraintTest('reportType', 'in', collection) + for record in geometryData: + self.assertIn(record.getString('rptType'), collection) + + def testGetDataWithInList(self): + collection = ['2022', '2032'] + geometryData = self._runConstraintTest('reportType', 'in', collection) + for record in geometryData: + self.assertIn(record.getString('rptType'), collection) + + def testGetDataWithInGenerator(self): + collection = ('2022', '2032') + generator = (item for item in collection) + geometryData = self._runConstraintTest('reportType', 'in', generator) + for record in geometryData: + self.assertIn(record.getString('rptType'), collection) + + def testGetDataWithInvalidConstraintTypeThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('reportType', 'junk', '2022') + + def testGetDataWithInvalidConstraintValueThrowsException(self): + with self.assertRaises(TypeError): + self._runConstraintTest('reportType', '=', {}) + + def testGetDataWithEmptyInConstraintThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('rptType', 'in', []) + + def testGetDataWithNestedInConstraintThrowsException(self): + collection = ('2022', '2032', ()) + with self.assertRaises(TypeError): + self._runConstraintTest('rptType', 'in', collection) diff --git a/awips/test/dafTests/testClimate.py b/awips/test/dafTests/testClimate.py new file mode 100644 index 0000000..61dc4a7 --- /dev/null +++ b/awips/test/dafTests/testClimate.py @@ -0,0 +1,413 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +import datetime +from dynamicserialize.dstypes.com.raytheon.uf.common.dataquery.requests import RequestConstraint +from dynamicserialize.dstypes.com.raytheon.uf.common.time import TimeRange +from awips.dataaccess import DataAccessLayer as DAL +from awips.ThriftClient import ThriftRequestException + +import baseDafTestCase +import unittest + +# +# Test DAF support for climate data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# 04/26/16 5587 tgurney Add identifier values tests +# 06/09/16 5574 mapeters Add advanced query tests, Short parameter test +# 06/13/16 5574 tgurney Fix checks for None +# 06/21/16 5548 tgurney Skip tests that cause errors +# 10/06/16 5926 dgilling Add additional time and location tests. +# +# + + +class ClimateTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for climate data""" + + datatype = 'climate' + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_asos_monthly') + self.runParametersTest(req) + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_asos_monthly') + self.runLocationsTest(req) + + def testGetAvailableLocationsForRptTable(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.rpt') + self.runLocationsTest(req) + + def testGetAvailableLocationsForStationId(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.day_climate_norm') + self.runLocationsTest(req) + + def testGetAvailableLocationsForInformId(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_mon_season_yr') + self.runLocationsTest(req) + + def testGetAvailableLocationsWithConstraints(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_asos_monthly') + req.addIdentifier('maxtemp_mon', RequestConstraint.new('>', 95)) + self.runLocationsTest(req) + + def testGetAvailableLocationsWithInvalidTable(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.boolean_values') + with self.assertRaises(ThriftRequestException) as cm: + DAL.getAvailableLocationNames(req) + self.assertIn('IncompatibleRequestException', str(cm.exception)) + + def testGetAvailableTimes(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_asos_monthly') + req.setParameters('maxtemp_mon', 'min_sea_press') + self.runTimesTest(req) + + def testGetAvailableTimesWithLocationNamesForYearMonth(self): + """ + Test retrieval of times for a climo table that uses year and + month columns to build DataTimes. + """ + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_asos_monthly') + req.setLocationNames('KOMA', 'KABR', 'KDMO') + req.setParameters('maxtemp_mon', 'min_sea_press') + self.runTimesTest(req) + + def testGetAvailableTimesWithLocationNamesForYearDayOfYear(self): + """ + Test retrieval of times for a climo table that uses year and + day_of_year columns to build DataTimes. + """ + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_asos_daily') + req.setLocationNames('KOMA', 'KABR', 'KDMO') + req.setParameters('maxtemp_cal', 'min_press') + self.runTimesTest(req) + + def testGetAvailableTimesWithLocationNamesForPeriod(self): + """ + Test retrieval of times for a climo table that uses + period_start and period_end columns to build DataTimes. + """ + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_mon_season_yr') + req.setLocationNames('KOMA', 'KABR', 'KDMO') + req.setParameters('max_temp', 'precip_total') + self.runTimesTest(req) + + def testGetAvailableTimesWithLocationNamesForDate(self): + """ + Test retrieval of times for a climo table that uses a date + column to build DataTimes. + """ + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.daily_climate') + req.setLocationNames('KOMA', 'KABR', 'KDMO') + req.setParameters('max_temp', 'precip', 'avg_wind_speed') + self.runTimesTest(req) + + def testGetAvailableTimesWithConstraint(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_asos_monthly') + req.addIdentifier('maxtemp_mon', RequestConstraint.new('<', 75)) + req.setParameters('maxtemp_mon', 'min_sea_press') + self.runTimesTest(req) + + def testGetGeometryData(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_asos_monthly') + req.setLocationNames('KFNB') + req.setParameters('maxtemp_mon', 'min_sea_press') + self.runGeometryDataTest(req) + + def testGetGeometryDataForYearAndDayOfYearTable(self): + """ + Test retrieval of data for a climo table that uses year and + day_of_year columns to build DataTimes. + """ + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_asos_daily') + req.setLocationNames('KFNB') + req.setParameters('maxtemp_cal', 'min_press') + self.runGeometryDataTest(req) + + def testGetGeometryDataForPeriodTable(self): + """ + Test retrieval of data for a climo table that uses a period_start and + period_end columns to build DataTimes. + """ + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_mon_season_yr') + req.setLocationNames('KFNB') + req.setParameters('max_temp', 'precip_total') + self.runGeometryDataTest(req) + + def testGetGeometryDataForDateTable(self): + """ + Test retrieval of data for a climo table that uses a date column to + build DataTimes. + """ + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.daily_climate') + req.setLocationNames('KFNB') + req.setParameters('max_temp', 'precip', 'avg_wind_speed') + self.runGeometryDataTest(req) + + def testGetGeometryDataWithShortParameter(self): + """ + Test that a parameter that is stored in Java as a Short is correctly + retrieved as a number. + """ + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'cli_asos_monthly') + req.setParameters('month') + geometryData = self.runGeometryDataTest(req) + for record in geometryData: + self.assertIsNotNone(record.getNumber('month')) + + def testGetTableIdentifierValues(self): + self.runGetIdValuesTest(['table']) + + def testGetColumnIdValuesWithTable(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_asos_monthly') + idValues = DAL.getIdentifierValues(req, 'year') + self.assertTrue(hasattr(idValues, '__iter__')) + + def testGetColumnIdValuesWithoutTableThrowsException(self): + req = DAL.newDataRequest(self.datatype) + with self.assertRaises(ThriftRequestException): + idValues = DAL.getIdentifierValues(req, 'year') + + @unittest.skip('avoid EDEX error') + def testGetColumnIdValuesWithNonexistentTableThrowsException(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'nonexistentjunk') + with self.assertRaises(ThriftRequestException): + idValues = DAL.getIdentifierValues(req, 'year') + + @unittest.skip('avoid EDEX error') + def testGetNonexistentColumnIdValuesThrowsException(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_asos_monthly') + with self.assertRaises(ThriftRequestException): + idValues = DAL.getIdentifierValues(req, 'nonexistentjunk') + + def testGetInvalidIdentifierValuesThrowsException(self): + self.runInvalidIdValuesTest() + + def testGetNonexistentIdentifierValuesThrowsException(self): + self.runNonexistentIdValuesTest() + + def _runConstraintTest(self, key, operator, value): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'cli_asos_monthly') + constraint = RequestConstraint.new(operator, value) + req.addIdentifier(key, constraint) + req.setParameters('station_code', 'avg_daily_max') + return self.runGeometryDataTest(req) + + def testGetDataWithEqualsString(self): + geometryData = self._runConstraintTest('station_code', '=', 'KOMA') + for record in geometryData: + self.assertEqual(record.getString('station_code'), 'KOMA') + + def testGetDataWithEqualsUnicode(self): + geometryData = self._runConstraintTest('station_code', '=', u'KOMA') + for record in geometryData: + self.assertEqual(record.getString('station_code'), 'KOMA') + + def testGetDataWithEqualsInt(self): + geometryData = self._runConstraintTest('avg_daily_max', '=', 70) + for record in geometryData: + self.assertEqual(record.getNumber('avg_daily_max'), 70) + + def testGetDataWithEqualsLong(self): + geometryData = self._runConstraintTest('avg_daily_max', '=', 70L) + for record in geometryData: + self.assertEqual(record.getNumber('avg_daily_max'), 70) + + def testGetDataWithEqualsFloat(self): + geometryData = self._runConstraintTest('avg_daily_max', '=', 69.2) + for record in geometryData: + self.assertEqual(round(record.getNumber('avg_daily_max'), 1), 69.2) + + def testGetDataWithEqualsNone(self): + geometryData = self._runConstraintTest('station_code', '=', None) + self.assertEqual(len(geometryData), 0) + + def testGetDataWithNotEquals(self): + geometryData = self._runConstraintTest('station_code', '!=', 'KOMA') + for record in geometryData: + self.assertNotEqual(record.getString('station_code'), 'KOMA') + + def testGetDataWithNotEqualsNone(self): + geometryData = self._runConstraintTest('station_code', '!=', None) + for record in geometryData: + self.assertNotEqual(record.getType('station_code'), 'NULL') + + def testGetDataWithGreaterThan(self): + geometryData = self._runConstraintTest('avg_daily_max', '>', 70) + for record in geometryData: + self.assertGreater(record.getNumber('avg_daily_max'), 70) + + def testGetDataWithLessThan(self): + geometryData = self._runConstraintTest('avg_daily_max', '<', 70) + for record in geometryData: + self.assertLess(record.getNumber('avg_daily_max'), 70) + + def testGetDataWithGreaterThanEquals(self): + geometryData = self._runConstraintTest('avg_daily_max', '>=', 70) + for record in geometryData: + self.assertGreaterEqual(record.getNumber('avg_daily_max'), 70) + + def testGetDataWithLessThanEquals(self): + geometryData = self._runConstraintTest('avg_daily_max', '<=', 70) + for record in geometryData: + self.assertLessEqual(record.getNumber('avg_daily_max'), 70) + + def testGetDataWithInTuple(self): + collection = ('KOMA', 'KABR') + geometryData = self._runConstraintTest('station_code', 'in', collection) + for record in geometryData: + self.assertIn(record.getString('station_code'), collection) + + def testGetDataWithInList(self): + collection = ['KOMA', 'KABR'] + geometryData = self._runConstraintTest('station_code', 'in', collection) + for record in geometryData: + self.assertIn(record.getString('station_code'), collection) + + def testGetDataWithInGenerator(self): + collection = ('KOMA', 'KABR') + generator = (item for item in collection) + geometryData = self._runConstraintTest('station_code', 'in', generator) + for record in geometryData: + self.assertIn(record.getString('station_code'), collection) + + def testGetDataWithInvalidConstraintTypeThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('station_code', 'junk', 'KOMA') + + def testGetDataWithInvalidConstraintValueThrowsException(self): + with self.assertRaises(TypeError): + self._runConstraintTest('station_code', '=', {}) + + def testGetDataWithEmptyInConstraintThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('station_code', 'in', []) + + def testGetDataWithTimeRangeWithYearAndMonth1(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_asos_monthly') + req.setLocationNames('KFNB') + req.setParameters('maxtemp_mon', 'min_sea_press') + startTime = datetime.datetime(2009, 1, 1) + endTime = datetime.datetime(2009, 12, 31) + tr = TimeRange(startTime, endTime) + self.runGeometryDataTestWithTimeRange(req, tr) + + def testGetDataWithTimeRangeWithYearAndMonth2(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_asos_monthly') + req.setLocationNames('KFNB') + req.setParameters('maxtemp_mon', 'min_sea_press') + startTime = datetime.datetime(2008, 1, 1) + endTime = datetime.datetime(2009, 3, 31) + tr = TimeRange(startTime, endTime) + self.runGeometryDataTestWithTimeRange(req, tr) + + def testGetDataWithTimeRangeWithYearAndMonth3(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_asos_monthly') + req.setLocationNames('KFNB') + req.setParameters('maxtemp_mon', 'min_sea_press') + startTime = datetime.datetime(2007, 7, 1) + endTime = datetime.datetime(2009, 3, 31) + tr = TimeRange(startTime, endTime) + self.runGeometryDataTestWithTimeRange(req, tr) + + def testGetDataWithTimeRangeWithYearAndDayOfYear1(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_asos_daily') + req.setLocationNames('KFNB') + req.setParameters('maxtemp_cal', 'min_press') + startTime = datetime.datetime(2009, 1, 1) + endTime = datetime.datetime(2009, 7, 31) + tr = TimeRange(startTime, endTime) + self.runGeometryDataTestWithTimeRange(req, tr) + + def testGetDataWithTimeRangeWithYearAndDayOfYear2(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_asos_daily') + req.setLocationNames('KFNB') + req.setParameters('maxtemp_cal', 'min_press') + startTime = datetime.datetime(2008, 7, 1) + endTime = datetime.datetime(2009, 3, 31) + tr = TimeRange(startTime, endTime) + self.runGeometryDataTestWithTimeRange(req, tr) + + def testGetDataWithTimeRangeWithYearAndDayOfYear3(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_asos_daily') + req.setLocationNames('KFNB') + req.setParameters('maxtemp_cal', 'min_press') + startTime = datetime.datetime(2007, 7, 1) + endTime = datetime.datetime(2009, 3, 31) + tr = TimeRange(startTime, endTime) + self.runGeometryDataTestWithTimeRange(req, tr) + + def testGetDataWithTimeRangeWithPeriodTable(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.cli_mon_season_yr') + req.setLocationNames('KFNB') + req.setParameters('max_temp', 'precip_total') + startTime = datetime.datetime(2007, 7, 1) + endTime = datetime.datetime(2009, 3, 31) + tr = TimeRange(startTime, endTime) + self.runGeometryDataTestWithTimeRange(req, tr) + + def testGetDataWithTimeRangeWithForDateTable(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.daily_climate') + req.setLocationNames('KFNB') + req.setParameters('max_temp', 'precip', 'avg_wind_speed') + startTime = datetime.datetime(2007, 7, 1) + endTime = datetime.datetime(2009, 3, 31) + tr = TimeRange(startTime, endTime) + self.runGeometryDataTestWithTimeRange(req, tr) + diff --git a/awips/test/dafTests/testCombinedTimeQuery.py b/awips/test/dafTests/testCombinedTimeQuery.py new file mode 100644 index 0000000..b3527db --- /dev/null +++ b/awips/test/dafTests/testCombinedTimeQuery.py @@ -0,0 +1,67 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from awips.dataaccess import DataAccessLayer as DAL + +from awips.dataaccess import CombinedTimeQuery as CTQ + +import unittest +import os + +# +# Test the CombinedTimedQuery module +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 06/24/16 5591 bsteffen Initial Creation. +# 11/08/16 5895 tgurney Change grid model +# +# +# + +class CombinedTimeQueryTestCase(unittest.TestCase): + + @classmethod + def setUp(cls): + host = os.environ.get('DAF_TEST_HOST') + if host is None: + host = 'localhost' + DAL.changeEDEXHost(host) + + def testSuccessfulQuery(self): + req = DAL.newDataRequest('grid') + req.setLocationNames('RUC130') + req.setParameters('T','GH') + req.setLevels('300MB', '500MB','700MB') + times = CTQ.getAvailableTimes(req); + self.assertNotEqual(len(times), 0) + + def testNonIntersectingQuery(self): + """ + Test that when a parameter is only available on one of the levels that no times are returned. + """ + req = DAL.newDataRequest('grid') + req.setLocationNames('RUC130') + req.setParameters('T','GH', 'LgSP1hr') + req.setLevels('300MB', '500MB','700MB','0.0SFC') + times = CTQ.getAvailableTimes(req); + self.assertEqual(len(times), 0) diff --git a/awips/test/dafTests/testCommonObsSpatial.py b/awips/test/dafTests/testCommonObsSpatial.py new file mode 100644 index 0000000..822783c --- /dev/null +++ b/awips/test/dafTests/testCommonObsSpatial.py @@ -0,0 +1,179 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from shapely.geometry import box +from awips.dataaccess import DataAccessLayer as DAL + +from dynamicserialize.dstypes.com.raytheon.uf.common.dataquery.requests import RequestConstraint +import baseDafTestCase +import unittest + +# +# Test DAF support for common_obs_spatial data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# 05/26/16 5587 njensen Added testGetIdentifierValues() +# 06/01/16 5587 tgurney Move testIdentifiers() to +# superclass +# 06/13/16 5574 tgurney Add advanced query tests +# 06/21/16 5548 tgurney Skip tests that cause errors +# + + +class CommonObsSpatialTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for common_obs_spatial data""" + + datatype = "common_obs_spatial" + + envelope = box(-97.0, 41.0, -96.0, 42.0) + """Default request area (box around KOAX)""" + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + self.runParametersTest(req) + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier("country", ["US", "CN"]) + self.runLocationsTest(req) + + def testGetIdentifierValues(self): + self.runGetIdValuesTest(['country']) + + @unittest.skip('avoid EDEX error') + def testGetInvalidIdentifierValuesThrowsException(self): + self.runInvalidIdValuesTest() + + @unittest.skip('avoid EDEX error') + def testGetNonexistentIdentifierValuesThrowsException(self): + self.runNonexistentIdValuesTest() + + def testGetGeometryData(self): + req = DAL.newDataRequest(self.datatype) + req.setEnvelope(self.envelope) + req.setParameters("name", "stationid") + self.runGeometryDataTest(req) + + def testRequestingTimesThrowsTimeAgnosticDataException(self): + req = DAL.newDataRequest(self.datatype) + self.runTimeAgnosticTest(req) + + def _runConstraintTest(self, key, operator, value): + req = DAL.newDataRequest(self.datatype) + constraint = RequestConstraint.new(operator, value) + req.addIdentifier(key, constraint) + req.setParameters('catalogtype', 'elevation', 'state') + return self.runGeometryDataTest(req) + + def testGetDataWithEqualsString(self): + geometryData = self._runConstraintTest('state', '=', 'NE') + for record in geometryData: + self.assertEqual(record.getString('state'), 'NE') + + def testGetDataWithEqualsUnicode(self): + geometryData = self._runConstraintTest('state', '=', u'NE') + for record in geometryData: + self.assertEqual(record.getString('state'), 'NE') + + def testGetDataWithEqualsInt(self): + geometryData = self._runConstraintTest('catalogtype', '=', 32) + for record in geometryData: + self.assertEqual(record.getNumber('catalogtype'), 32) + + def testGetDataWithEqualsLong(self): + geometryData = self._runConstraintTest('elevation', '=', 0L) + for record in geometryData: + self.assertEqual(record.getNumber('elevation'), 0) + + # No float test since there are no float identifiers available. Attempting + # to filter a non-float identifier on a float value raises an exception. + + def testGetDataWithEqualsNone(self): + geometryData = self._runConstraintTest('state', '=', None) + for record in geometryData: + self.assertEqual(record.getType('state'), 'NULL') + + def testGetDataWithNotEquals(self): + geometryData = self._runConstraintTest('state', '!=', 'NE') + for record in geometryData: + self.assertNotEqual(record.getString('state'), 'NE') + + def testGetDataWithNotEqualsNone(self): + geometryData = self._runConstraintTest('state', '!=', None) + for record in geometryData: + self.assertNotEqual(record.getType('state'), 'NULL') + + def testGetDataWithGreaterThan(self): + geometryData = self._runConstraintTest('elevation', '>', 500) + for record in geometryData: + self.assertGreater(record.getNumber('elevation'), 500) + + def testGetDataWithLessThan(self): + geometryData = self._runConstraintTest('elevation', '<', 100) + for record in geometryData: + self.assertLess(record.getNumber('elevation'), 100) + + def testGetDataWithGreaterThanEquals(self): + geometryData = self._runConstraintTest('elevation', '>=', 500) + for record in geometryData: + self.assertGreaterEqual(record.getNumber('elevation'), 500) + + def testGetDataWithLessThanEquals(self): + geometryData = self._runConstraintTest('elevation', '<=', 100) + for record in geometryData: + self.assertLessEqual(record.getNumber('elevation'), 100) + + def testGetDataWithInTuple(self): + collection = ('NE', 'TX') + geometryData = self._runConstraintTest('state', 'in', collection) + for record in geometryData: + self.assertIn(record.getString('state'), collection) + + def testGetDataWithInList(self): + collection = ['NE', 'TX'] + geometryData = self._runConstraintTest('state', 'in', collection) + for record in geometryData: + self.assertIn(record.getString('state'), collection) + + def testGetDataWithInGenerator(self): + collection = ('NE', 'TX') + generator = (item for item in collection) + geometryData = self._runConstraintTest('state', 'in', generator) + for record in geometryData: + self.assertIn(record.getString('state'), collection) + + def testGetDataWithInvalidConstraintTypeThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('state', 'junk', 'NE') + + def testGetDataWithInvalidConstraintValueThrowsException(self): + with self.assertRaises(TypeError): + self._runConstraintTest('state', '=', {}) + + def testGetDataWithEmptyInConstraintThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('state', 'in', []) diff --git a/awips/test/dafTests/testFfmp.py b/awips/test/dafTests/testFfmp.py new file mode 100644 index 0000000..600c76d --- /dev/null +++ b/awips/test/dafTests/testFfmp.py @@ -0,0 +1,98 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from awips.dataaccess import DataAccessLayer as DAL + +import baseDafTestCase +import unittest + +# +# Test DAF support for ffmp data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# 04/18/16 5587 tgurney Add test for sane handling of +# zero records returned +# 06/20/16 5587 tgurney Add identifier values tests +# 11/08/16 5985 tgurney Do not check data times +# +# + + +class FfmpTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for ffmp data""" + + datatype = "ffmp" + + @staticmethod + def addIdentifiers(req): + req.addIdentifier("wfo", "OAX") + req.addIdentifier("siteKey", "hpe") + req.addIdentifier("dataKey", "hpe") + req.addIdentifier("huc", "ALL") + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + self.runParametersTest(req) + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + self.addIdentifiers(req) + self.runLocationsTest(req) + + def testGetAvailableTimes(self): + req = DAL.newDataRequest(self.datatype) + self.addIdentifiers(req) + self.runTimesTest(req) + + def testGetGeometryData(self): + req = DAL.newDataRequest(self.datatype) + self.addIdentifiers(req) + req.setParameters("PRTM") + self.runGeometryDataTest(req, checkDataTimes=False) + + def testGetGeometryDataEmptyResult(self): + req = DAL.newDataRequest(self.datatype) + self.addIdentifiers(req) + req.setParameters("blah blah blah") # force 0 records returned + result = self.runGeometryDataTest(req, checkDataTimes=False) + self.assertEqual(len(result), 0) + + def testGetIdentifierValues(self): + req = DAL.newDataRequest(self.datatype) + optionalIds = set(DAL.getOptionalIdentifiers(req)) + requiredIds = set(DAL.getRequiredIdentifiers(req)) + ids = requiredIds | optionalIds + # These two not yet supported + ids.remove('huc') + ids.remove('accumHrs') + self.runGetIdValuesTest(ids) + + def testGetInvalidIdentifierValuesThrowsException(self): + self.runInvalidIdValuesTest() + + def testGetNonexistentIdentifierValuesThrowsException(self): + self.runNonexistentIdValuesTest() diff --git a/awips/test/dafTests/testGfe.py b/awips/test/dafTests/testGfe.py new file mode 100644 index 0000000..f5d5a7d --- /dev/null +++ b/awips/test/dafTests/testGfe.py @@ -0,0 +1,196 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from dynamicserialize.dstypes.com.raytheon.uf.common.dataquery.requests import RequestConstraint +from awips.dataaccess import DataAccessLayer as DAL + +import baseDafTestCase +import unittest + +# +# Test DAF support for GFE data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# 05/23/16 5637 bsteffen Test vectors +# 05/31/16 5587 tgurney Add getIdentifierValues tests +# 06/01/16 5587 tgurney Update testGetIdentifierValues +# 06/17/16 5574 mapeters Add advanced query tests +# 11/07/16 5991 bsteffen Improve vector tests +# +# + + +class GfeTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for GFE data""" + + datatype = 'gfe' + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + self.runParametersTest(req) + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('modelName', 'Fcst') + self.runLocationsTest(req) + + def testGetAvailableTimes(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('modelName', 'Fcst') + req.addIdentifier('siteId', 'OAX') + self.runTimesTest(req) + + def testGetGridData(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('modelName', 'Fcst') + req.addIdentifier('siteId', 'OAX') + req.setParameters('T') + self.runGridDataTest(req) + + def testGetVectorGridData(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('modelName', 'Fcst') + req.addIdentifier('siteId', 'OAX') + req.setParameters('Wind') + times = DAL.getAvailableTimes(req) + if not(times): + raise unittest.SkipTest('No Wind Data available for testing') + gridData = DAL.getGridData(req, [times[0]]) + rawWind = None + rawDir = None + for grid in gridData: + if grid.getParameter() == 'Wind': + self.assertEqual(grid.getUnit(),'kts') + rawWind = grid.getRawData() + elif grid.getParameter() == 'WindDirection': + self.assertEqual(grid.getUnit(),'deg') + rawDir = grid.getRawData() + self.assertIsNotNone(rawWind, 'Wind Magnitude grid is not present') + self.assertIsNotNone(rawDir, 'Wind Direction grid is not present') + # rawWind and rawDir are numpy.ndarrays so comparison will result in boolean ndarrays. + self.assertTrue((rawWind >= 0).all(), 'Wind Speed should not contain negative values') + self.assertTrue((rawDir >= 0).all(), 'Wind Direction should not contain negative values') + self.assertTrue((rawDir <= 360).all(), 'Wind Direction should be less than or equal to 360') + self.assertFalse((rawDir == rawWind).all(), 'Wind Direction should be different from Wind Speed') + + def testGetIdentifierValues(self): + req = DAL.newDataRequest(self.datatype) + optionalIds = set(DAL.getOptionalIdentifiers(req)) + requiredIds = set(DAL.getRequiredIdentifiers(req)) + self.runGetIdValuesTest(optionalIds | requiredIds) + + def testGetInvalidIdentifierValuesThrowsException(self): + self.runInvalidIdValuesTest() + + def testGetNonexistentIdentifierValuesThrowsException(self): + self.runNonexistentIdValuesTest() + + def _runConstraintTest(self, key, operator, value): + req = DAL.newDataRequest(self.datatype) + constraint = RequestConstraint.new(operator, value) + req.addIdentifier(key, constraint) + req.setLocationNames('OAX') + req.setParameters('T') + return self.runGridDataTest(req) + + def testGetDataWithEqualsString(self): + geometryData = self._runConstraintTest('modelName', '=', 'Fcst') + for record in geometryData: + self.assertEqual(record.getAttribute('modelName'), 'Fcst') + + def testGetDataWithEqualsUnicode(self): + geometryData = self._runConstraintTest('modelName', '=', u'Fcst') + for record in geometryData: + self.assertEqual(record.getAttribute('modelName'), 'Fcst') + + # No numeric tests since no numeric identifiers are available. + + def testGetDataWithEqualsNone(self): + geometryData = self._runConstraintTest('modelName', '=', None) + for record in geometryData: + self.assertIsNone(record.getAttribute('modelName')) + + def testGetDataWithNotEquals(self): + geometryData = self._runConstraintTest('modelName', '!=', 'Fcst') + for record in geometryData: + self.assertNotEqual(record.getAttribute('modelName'), 'Fcst') + + def testGetDataWithNotEqualsNone(self): + geometryData = self._runConstraintTest('modelName', '!=', None) + for record in geometryData: + self.assertIsNotNone(record.getAttribute('modelName')) + + def testGetDataWithGreaterThan(self): + geometryData = self._runConstraintTest('modelName', '>', 'Fcst') + for record in geometryData: + self.assertGreater(record.getAttribute('modelName'), 'Fcst') + + def testGetDataWithLessThan(self): + geometryData = self._runConstraintTest('modelName', '<', 'Fcst') + for record in geometryData: + self.assertLess(record.getAttribute('modelName'), 'Fcst') + + def testGetDataWithGreaterThanEquals(self): + geometryData = self._runConstraintTest('modelName', '>=', 'Fcst') + for record in geometryData: + self.assertGreaterEqual(record.getAttribute('modelName'), 'Fcst') + + def testGetDataWithLessThanEquals(self): + geometryData = self._runConstraintTest('modelName', '<=', 'Fcst') + for record in geometryData: + self.assertLessEqual(record.getAttribute('modelName'), 'Fcst') + + def testGetDataWithInTuple(self): + collection = ('Fcst', 'SAT') + geometryData = self._runConstraintTest('modelName', 'in', collection) + for record in geometryData: + self.assertIn(record.getAttribute('modelName'), collection) + + def testGetDataWithInList(self): + collection = ['Fcst', 'SAT'] + geometryData = self._runConstraintTest('modelName', 'in', collection) + for record in geometryData: + self.assertIn(record.getAttribute('modelName'), collection) + + def testGetDataWithInGenerator(self): + collection = ('Fcst', 'SAT') + generator = (item for item in collection) + geometryData = self._runConstraintTest('modelName', 'in', generator) + for record in geometryData: + self.assertIn(record.getAttribute('modelName'), collection) + + def testGetDataWithInvalidConstraintTypeThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('modelName', 'junk', 'Fcst') + + def testGetDataWithInvalidConstraintValueThrowsException(self): + with self.assertRaises(TypeError): + self._runConstraintTest('modelName', '=', {}) + + def testGetDataWithEmptyInConstraintThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('modelName', 'in', []) diff --git a/awips/test/dafTests/testGrid.py b/awips/test/dafTests/testGrid.py new file mode 100644 index 0000000..a216420 --- /dev/null +++ b/awips/test/dafTests/testGrid.py @@ -0,0 +1,123 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from shapely.geometry import box, Point +from awips.dataaccess import DataAccessLayer as DAL + +import baseDafTestCase +import unittest + +# +# Test DAF support for grid data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# 06/09/16 5587 tgurney Typo in id values test +# 10/13/16 5942 bsteffen Test envelopes +# 11/08/16 5985 tgurney Skip certain tests when no +# data is available +# + + +class GridTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for grid data""" + + datatype = "grid" + + model = "GFS160" + + envelope = box(-97.0, 41.0, -96.0, 42.0) + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier("info.datasetId", self.model) + self.runParametersTest(req) + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier("info.datasetId", self.model) + self.runLocationsTest(req) + + def testGetAvailableLevels(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier("info.datasetId", self.model) + self.runLevelsTest(req) + + def testGetAvailableTimes(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier("info.datasetId", self.model) + req.setLevels("2FHAG") + self.runTimesTest(req) + + def testGetGridData(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier("info.datasetId", self.model) + req.setLevels("2FHAG") + req.setParameters("T") + self.runGridDataTest(req) + + def testGetIdentifierValues(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier("info.datasetId", 'ENSEMBLE') + req.setLevels("2FHAG") + req.setParameters("T") + idValues = DAL.getIdentifierValues(req, 'info.ensembleId') + self.assertTrue(hasattr(idValues, '__iter__')) + if idValues: + self.assertIn('ctl1', idValues) + self.assertIn('p1', idValues) + self.assertIn('n1', idValues) + else: + raise unittest.SkipTest("no data available") + + def testGetInvalidIdentifierValuesThrowsException(self): + self.runInvalidIdValuesTest() + + def testGetNonexistentIdentifierValuesThrowsException(self): + self.runNonexistentIdValuesTest() + + + def testGetDataWithEnvelope(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('info.datasetId', self.model) + req.setLevels('2FHAG') + req.setParameters('T') + req.setEnvelope(self.envelope) + gridData = self.runGridDataTest(req) + if not gridData: + raise unittest.SkipTest('no data available') + lons, lats = gridData[0].getLatLonCoords() + lons = lons.reshape(-1) + lats = lats.reshape(-1) + + # Ensure all points are within one degree of the original box + # to allow slight margin of error for reprojection distortion. + testEnv = box(self.envelope.bounds[0] - 1, self.envelope.bounds[1] - 1, + self.envelope.bounds[2] + 1, self.envelope.bounds[3] + 1 ) + + for i in range(len(lons)): + self.assertTrue(testEnv.contains(Point(lons[i], lats[i]))) + diff --git a/awips/test/dafTests/testHydro.py b/awips/test/dafTests/testHydro.py new file mode 100644 index 0000000..0d8bef4 --- /dev/null +++ b/awips/test/dafTests/testHydro.py @@ -0,0 +1,261 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +import datetime +from awips.dataaccess import DataAccessLayer as DAL +from awips.ThriftClient import ThriftRequestException + +from dynamicserialize.dstypes.com.raytheon.uf.common.dataquery.requests import RequestConstraint +from dynamicserialize.dstypes.com.raytheon.uf.common.time import TimeRange +import baseDafTestCase +import unittest + +# +# Test DAF support for hydro data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# 04/21/16 5596 tgurney Add tests to verify #5596 +# 04/26/16 5587 tgurney Add identifier values tests +# 06/09/16 5574 tgurney Add advanced query tests +# 06/13/16 5574 tgurney Fix checks for None +# 06/21/16 5548 tgurney Skip tests that cause errors +# 10/06/16 5926 dgilling Add additional location tests. +# +# + + +class HydroTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for hydro data""" + + datatype = 'hydro' + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'height') + self.runParametersTest(req) + + def testGetAvailableParametersFullyQualifiedTable(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'public.height') + self.runParametersTest(req) + + def testGetAvailableParamsNoTableThrowsInvalidIdentifiersException(self): + req = DAL.newDataRequest(self.datatype) + with self.assertRaises(ThriftRequestException) as cm: + self.runParametersTest(req) + self.assertIn('InvalidIdentifiersException', str(cm.exception)) + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'height') + self.runLocationsTest(req) + + def testGetAvailableLocationsWithConstraint(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'height') + req.addIdentifier('value', RequestConstraint.new('>', 5.0)) + self.runLocationsTest(req) + + def testGetAvailableLocationsWithInvalidTable(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'city') + with self.assertRaises(ThriftRequestException) as cm: + DAL.getAvailableLocationNames(req) + self.assertIn('IncompatibleRequestException', str(cm.exception)) + + def testGetAvailableTimes(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'height') + req.setParameters('lid', 'quality_code') + self.runTimesTest(req) + + def testGetGeometryDataWithoutLocationSpecified(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'height') + req.setParameters('lid', 'quality_code') + self.runGeometryDataTest(req) + + def testGetGeometryDataWithLocationSpecified(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'fcstheight') + locs = DAL.getAvailableLocationNames(req) + if locs: + req.setLocationNames(locs[0]) + req.setParameters('probability', 'value') + data = self.runGeometryDataTest(req) + self.assertNotEqual(len(data), 0) + + def testGetTableIdentifierValues(self): + self.runGetIdValuesTest(['table']) + + def testGetColumnIdValuesWithTable(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'height') + idValues = DAL.getIdentifierValues(req, 'lid') + self.assertTrue(hasattr(idValues, '__iter__')) + + @unittest.skip('avoid EDEX error') + def testGetColumnIdValuesWithNonexistentTableThrowsException(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'nonexistentjunk') + with self.assertRaises(ThriftRequestException): + idValues = DAL.getIdentifierValues(req, 'lid') + + def testGetColumnIdValuesWithoutTableThrowsException(self): + req = DAL.newDataRequest(self.datatype) + with self.assertRaises(ThriftRequestException): + idValues = DAL.getIdentifierValues(req, 'lid') + + @unittest.skip('avoid EDEX error') + def testGetNonexistentColumnIdValuesThrowsException(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'height') + with self.assertRaises(ThriftRequestException): + idValues = DAL.getIdentifierValues(req, 'nonexistentjunk') + + def testGetInvalidIdentifierValuesThrowsException(self): + self.runInvalidIdValuesTest() + + def testGetNonexistentIdentifierValuesThrowsException(self): + self.runNonexistentIdValuesTest() + + def _runConstraintTest(self, key, operator, value): + req = DAL.newDataRequest(self.datatype) + constraint = RequestConstraint.new(operator, value) + req.addIdentifier(key, constraint) + req.addIdentifier('table', 'height') + req.addIdentifier('ts', 'RG') + req.setParameters('value', 'lid', 'quality_code') + return self.runGeometryDataTest(req) + + def testGetDataWithEqualsString(self): + geometryData = self._runConstraintTest('value', '=', '3') + for record in geometryData: + self.assertEqual(record.getNumber('value'), 3) + + def testGetDataWithEqualsUnicode(self): + geometryData = self._runConstraintTest('value', '=', u'3') + for record in geometryData: + self.assertEqual(record.getNumber('value'), 3) + + def testGetDataWithEqualsInt(self): + geometryData = self._runConstraintTest('value', '=', 3) + for record in geometryData: + self.assertEqual(record.getNumber('value'), 3) + + def testGetDataWithEqualsLong(self): + geometryData = self._runConstraintTest('value', '=', 3L) + for record in geometryData: + self.assertEqual(record.getNumber('value'), 3L) + + def testGetDataWithEqualsFloat(self): + geometryData = self._runConstraintTest('value', '=', 3.0) + for record in geometryData: + self.assertEqual(round(record.getNumber('value'), 1), 3.0) + + def testGetDataWithEqualsNone(self): + geometryData = self._runConstraintTest('value', '=', None) + self.assertEqual(len(geometryData), 0) + + def testGetDataWithNotEquals(self): + geometryData = self._runConstraintTest('value', '!=', 3) + for record in geometryData: + self.assertNotEqual(record.getNumber('value'), '3') + + def testGetDataWithNotEqualsNone(self): + geometryData = self._runConstraintTest('value', '!=', None) + self.assertNotEqual(len(geometryData), 0) + for record in geometryData: + self.assertNotEqual(record.getType('value'), 'NULL') + + def testGetDataWithGreaterThan(self): + geometryData = self._runConstraintTest('value', '>', 3) + for record in geometryData: + self.assertGreater(record.getNumber('value'), 3) + + def testGetDataWithLessThan(self): + geometryData = self._runConstraintTest('value', '<', 3) + for record in geometryData: + self.assertLess(record.getNumber('value'), 3) + + def testGetDataWithGreaterThanEquals(self): + geometryData = self._runConstraintTest('value', '>=', 3) + for record in geometryData: + self.assertGreaterEqual(record.getNumber('value'), 3) + + def testGetDataWithLessThanEquals(self): + geometryData = self._runConstraintTest('value', '<=', 3) + for record in geometryData: + self.assertLessEqual(record.getNumber('value'), 3) + + def testGetDataWithInTuple(self): + collection = (3, 4) + geometryData = self._runConstraintTest('value', 'in', collection) + for record in geometryData: + self.assertIn(record.getNumber('value'), collection) + + def testGetDataWithInList(self): + collection = [3, 4] + geometryData = self._runConstraintTest('value', 'in', collection) + for record in geometryData: + self.assertIn(record.getNumber('value'), collection) + + def testGetDataWithInGenerator(self): + collection = (3, 4) + generator = (item for item in collection) + geometryData = self._runConstraintTest('value', 'in', generator) + for record in geometryData: + self.assertIn(record.getNumber('value'), collection) + + def testGetDataWithTimeRange(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'height') + req.addIdentifier('ts', 'RG') + req.setParameters('value', 'lid', 'quality_code') + times = DAL.getAvailableTimes(req) + limitTimes = times[-self.numTimesToLimit:] + startTime = datetime.datetime.utcfromtimestamp(limitTimes[0].getRefTime().getTime()/1000) + endTime = datetime.datetime.utcnow() + tr = TimeRange(startTime, endTime) + self.runGeometryDataTestWithTimeRange(req, tr) + + def testGetDataWithInvalidConstraintTypeThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('value', 'junk', 3) + + def testGetDataWithInvalidConstraintValueThrowsException(self): + with self.assertRaises(TypeError): + self._runConstraintTest('value', '=', {}) + + def testGetDataWithEmptyInConstraintThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('value', 'in', []) + + def testGetDataWithNestedInConstraintThrowsException(self): + collection = ('3', '4', ()) + with self.assertRaises(TypeError): + self._runConstraintTest('value', 'in', collection) diff --git a/awips/test/dafTests/testLdadMesonet.py b/awips/test/dafTests/testLdadMesonet.py new file mode 100644 index 0000000..3e0c3d0 --- /dev/null +++ b/awips/test/dafTests/testLdadMesonet.py @@ -0,0 +1,77 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from shapely.geometry import Polygon +from awips.dataaccess import DataAccessLayer as DAL + +import baseDafTestCase +import unittest + +# +# Test DAF support for ldadmesonet data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# +# + + +class LdadMesonetTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for ldadmesonet data""" + + datatype = "ldadmesonet" + + envelope = None + + @classmethod + def getReqEnvelope(cls): + # Restrict the output to only records with latitude and + # longitude between -30 and 30. + if not cls.envelope: + vertices = [(-30, -30), (-30, 30), (30, 30), (30, -30)] + polygon = Polygon(vertices) + cls.envelope = polygon.envelope + return cls.envelope + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + self.runParametersTest(req) + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + req.setEnvelope(self.getReqEnvelope()) + self.runLocationsTest(req) + + def testGetAvailableTimes(self): + req = DAL.newDataRequest(self.datatype) + req.setEnvelope(self.getReqEnvelope()) + self.runTimesTest(req) + + def testGetGeometryData(self): + req = DAL.newDataRequest(self.datatype) + req.setParameters("highLevelCloud", "pressure") + req.setEnvelope(self.getReqEnvelope()) + self.runGeometryDataTest(req) diff --git a/awips/test/dafTests/testMaps.py b/awips/test/dafTests/testMaps.py new file mode 100644 index 0000000..6b08442 --- /dev/null +++ b/awips/test/dafTests/testMaps.py @@ -0,0 +1,227 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from dynamicserialize.dstypes.com.raytheon.uf.common.dataquery.requests import RequestConstraint +from awips.dataaccess import DataAccessLayer as DAL +from awips.ThriftClient import ThriftRequestException + +import baseDafTestCase +import unittest + +# +# Test DAF support for maps data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# 04/26/16 5587 tgurney Add identifier values tests +# 06/13/16 5574 mapeters Add advanced query tests +# 06/21/16 5548 tgurney Skip tests that cause errors +# +# + + +class MapsTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for maps data""" + + datatype = 'maps' + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'mapdata.county') + req.addIdentifier('geomField', 'the_geom') + self.runParametersTest(req) + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'mapdata.county') + req.addIdentifier('geomField', 'the_geom') + req.addIdentifier('locationField', 'cwa') + self.runLocationsTest(req) + + def testGetGeometryData(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'mapdata.county') + req.addIdentifier('geomField', 'the_geom') + req.addIdentifier('inLocation', 'true') + req.addIdentifier('locationField', 'cwa') + req.setLocationNames('OAX') + req.addIdentifier('cwa', 'OAX') + req.setParameters('countyname', 'state', 'fips') + self.runGeometryDataTest(req) + + def testRequestingTimesThrowsTimeAgnosticDataException(self): + req = DAL.newDataRequest(self.datatype) + self.runTimeAgnosticTest(req) + + def testGetTableIdentifierValues(self): + self.runGetIdValuesTest(['table']) + + def testGetGeomFieldIdentifierValues(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'mapdata.county') + idValues = DAL.getIdentifierValues(req, 'geomField') + for idValue in idValues: + self.assertTrue(idValue.startswith('the_geom')) + + def testGetGeomFieldIdValuesWithoutTableThrowsException(self): + with self.assertRaises(ThriftRequestException): + self.runGetIdValuesTest(['geomField']) + + def testGetColumnIdValuesWithTable(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'mapdata.county') + req.addIdentifier('geomField', 'the_geom') + idValues = DAL.getIdentifierValues(req, 'state') + self.assertIn('NE', idValues) + + def testGetColumnIdValuesWithoutTableThrowsException(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('geomField', 'the_geom') + with self.assertRaises(ThriftRequestException): + idValues = DAL.getIdentifierValues(req, 'state') + + @unittest.skip('avoid EDEX error') + def testGetColumnIdValuesWithNonexistentTableThrowsException(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'mapdata.nonexistentjunk') + req.addIdentifier('geomField', 'the_geom') + with self.assertRaises(ThriftRequestException): + idValues = DAL.getIdentifierValues(req, 'state') + + @unittest.skip('avoid EDEX error') + def testGetNonexistentColumnIdValuesThrowsException(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'mapdata.county') + req.addIdentifier('geomField', 'the_geom') + with self.assertRaises(ThriftRequestException): + idValues = DAL.getIdentifierValues(req, 'nonexistentjunk') + + def testGetInvalidIdentifierValuesThrowsException(self): + self.runInvalidIdValuesTest() + + def testGetNonexistentIdentifierValuesThrowsException(self): + self.runNonexistentIdValuesTest() + + def _runConstraintTest(self, key, operator, value): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('table', 'mapdata.ffmp_basins') + req.addIdentifier('geomField', 'the_geom') + req.addIdentifier('cwa', 'OAX') + constraint = RequestConstraint.new(operator, value) + req.addIdentifier(key, constraint) + req.setParameters('state', 'reservoir', 'area_sq_mi') + return self.runGeometryDataTest(req) + + def testGetDataWithEqualsString(self): + geometryData = self._runConstraintTest('state', '=', 'NE') + for record in geometryData: + self.assertEqual(record.getString('state'), 'NE') + + def testGetDataWithEqualsUnicode(self): + geometryData = self._runConstraintTest('state', '=', u'NE') + for record in geometryData: + self.assertEqual(record.getString('state'), 'NE') + + def testGetDataWithEqualsInt(self): + geometryData = self._runConstraintTest('reservoir', '=', 1) + for record in geometryData: + self.assertEqual(record.getNumber('reservoir'), 1) + + def testGetDataWithEqualsLong(self): + geometryData = self._runConstraintTest('reservoir', '=', 1L) + for record in geometryData: + self.assertEqual(record.getNumber('reservoir'), 1) + + def testGetDataWithEqualsFloat(self): + geometryData = self._runConstraintTest('area_sq_mi', '=', 5.00) + for record in geometryData: + self.assertEqual(round(record.getNumber('area_sq_mi'), 2), 5.00) + + def testGetDataWithEqualsNone(self): + geometryData = self._runConstraintTest('state', '=', None) + for record in geometryData: + self.assertEqual(record.getType('state'), 'NULL') + + def testGetDataWithNotEquals(self): + geometryData = self._runConstraintTest('state', '!=', 'NE') + for record in geometryData: + self.assertNotEqual(record.getString('state'), 'NE') + + def testGetDataWithNotEqualsNone(self): + geometryData = self._runConstraintTest('state', '!=', None) + for record in geometryData: + self.assertNotEqual(record.getType('state'), 'NULL') + + def testGetDataWithGreaterThan(self): + geometryData = self._runConstraintTest('area_sq_mi', '>', 5) + for record in geometryData: + self.assertGreater(record.getNumber('area_sq_mi'), 5) + + def testGetDataWithLessThan(self): + geometryData = self._runConstraintTest('area_sq_mi', '<', 5) + for record in geometryData: + self.assertLess(record.getNumber('area_sq_mi'), 5) + + def testGetDataWithGreaterThanEquals(self): + geometryData = self._runConstraintTest('area_sq_mi', '>=', 5) + for record in geometryData: + self.assertGreaterEqual(record.getNumber('area_sq_mi'), 5) + + def testGetDataWithLessThanEquals(self): + geometryData = self._runConstraintTest('area_sq_mi', '<=', 5) + for record in geometryData: + self.assertLessEqual(record.getNumber('area_sq_mi'), 5) + + def testGetDataWithInTuple(self): + collection = ('NE', 'TX') + geometryData = self._runConstraintTest('state', 'in', collection) + for record in geometryData: + self.assertIn(record.getString('state'), collection) + + def testGetDataWithInList(self): + collection = ['NE', 'TX'] + geometryData = self._runConstraintTest('state', 'in', collection) + for record in geometryData: + self.assertIn(record.getString('state'), collection) + + def testGetDataWithInGenerator(self): + collection = ('NE', 'TX') + generator = (item for item in collection) + geometryData = self._runConstraintTest('state', 'in', generator) + for record in geometryData: + self.assertIn(record.getString('state'), collection) + + def testGetDataWithInvalidConstraintTypeThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('state', 'junk', 'NE') + + def testGetDataWithInvalidConstraintValueThrowsException(self): + with self.assertRaises(TypeError): + self._runConstraintTest('state', '=', {}) + + def testGetDataWithEmptyInConstraintThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('state', 'in', []) diff --git a/awips/test/dafTests/testModelSounding.py b/awips/test/dafTests/testModelSounding.py new file mode 100644 index 0000000..152abe7 --- /dev/null +++ b/awips/test/dafTests/testModelSounding.py @@ -0,0 +1,209 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from awips.dataaccess import DataAccessLayer as DAL +from dynamicserialize.dstypes.com.raytheon.uf.common.dataquery.requests import RequestConstraint + +import baseDafTestCase +import unittest + +# +# Test DAF support for modelsounding data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# 06/09/16 5587 bsteffen Add getIdentifierValues tests +# 06/13/16 5574 tgurney Add advanced query tests +# 11/10/16 5985 tgurney Mark expected failures prior +# to 17.3.1 +# +# + + +class ModelSoundingTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for modelsounding data""" + + datatype = "modelsounding" + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + + self.runParametersTest(req) + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier("reportType", "ETA") + + self.runLocationsTest(req) + + def testGetAvailableTimes(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier("reportType", "ETA") + req.setLocationNames("KOMA") + + self.runTimesTest(req) + + @unittest.expectedFailure + def testGetGeometryData(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier("reportType", "ETA") + req.setLocationNames("KOMA") + req.setParameters("temperature", "pressure", "specHum", "sfcPress", "temp2", "q2") + + print("Testing getGeometryData()") + + geomData = DAL.getGeometryData(req) + print("Number of geometry records: " + str(len(geomData))) + print("Sample geometry data:") + for record in geomData[:self.sampleDataLimit]: + print("level=" + record.getLevel(), end="") + # One dimensional parameters are reported on the 0.0UNKNOWN level. + # 2D parameters are reported on MB levels from pressure. + if record.getLevel() == "0.0UNKNOWN": + print(" sfcPress=" + record.getString("sfcPress") + record.getUnit("sfcPress"), end="") + print(" temp2=" + record.getString("temp2") + record.getUnit("temp2"), end="") + print(" q2=" + record.getString("q2") + record.getUnit("q2"), end="") + + else: + print(" pressure=" + record.getString("pressure") + record.getUnit("pressure"), end="") + print(" temperature=" + record.getString("temperature") + record.getUnit("temperature"), end="") + print(" specHum=" + record.getString("specHum") + record.getUnit("specHum"), end="") + print(" geometry=" + str(record.getGeometry())) + + print("getGeometryData() complete\n\n") + + def testGetIdentifierValues(self): + req = DAL.newDataRequest(self.datatype) + optionalIds = set(DAL.getOptionalIdentifiers(req)) + self.runGetIdValuesTest(optionalIds) + + def testGetInvalidIdentifierValuesThrowsException(self): + self.runInvalidIdValuesTest() + + def testGetNonexistentIdentifierValuesThrowsException(self): + self.runNonexistentIdValuesTest() + + def _runConstraintTest(self, key, operator, value): + req = DAL.newDataRequest(self.datatype) + constraint = RequestConstraint.new(operator, value) + req.setParameters('dataURI') + req.setLocationNames('KOMA', 'KORD', 'KOFK', 'KLNK') + req.addIdentifier(key, constraint) + return self.runGeometryDataTest(req) + + # We can filter on reportType but it is not possible to retrieve the value + # of reportType directly. We can look inside the dataURI instead. + # + # For cases like '<=' and '>' the best we can do is send the request and + # see if it throws back an exception. + # + # Can also eyeball the number of returned records. + + @unittest.expectedFailure + def testGetDataWithEqualsString(self): + geometryData = self._runConstraintTest('reportType', '=', 'ETA') + for record in geometryData: + self.assertIn('/ETA/', record.getString('dataURI')) + + @unittest.expectedFailure + def testGetDataWithEqualsUnicode(self): + geometryData = self._runConstraintTest('reportType', '=', u'ETA') + for record in geometryData: + self.assertIn('/ETA/', record.getString('dataURI')) + + # No numeric tests since no numeric identifiers are available. + + @unittest.expectedFailure + def testGetDataWithEqualsNone(self): + geometryData = self._runConstraintTest('reportType', '=', None) + + @unittest.expectedFailure + def testGetDataWithNotEquals(self): + geometryData = self._runConstraintTest('reportType', '!=', 'ETA') + for record in geometryData: + self.assertNotIn('/ETA/', record.getString('dataURI')) + + @unittest.expectedFailure + def testGetDataWithNotEqualsNone(self): + geometryData = self._runConstraintTest('reportType', '!=', None) + + @unittest.expectedFailure + def testGetDataWithGreaterThan(self): + geometryData = self._runConstraintTest('reportType', '>', 'ETA') + + @unittest.expectedFailure + def testGetDataWithLessThan(self): + geometryData = self._runConstraintTest('reportType', '<', 'ETA') + + @unittest.expectedFailure + def testGetDataWithGreaterThanEquals(self): + geometryData = self._runConstraintTest('reportType', '>=', 'ETA') + + @unittest.expectedFailure + def testGetDataWithLessThanEquals(self): + geometryData = self._runConstraintTest('reportType', '<=', 'ETA') + + @unittest.expectedFailure + def testGetDataWithInTuple(self): + collection = ('ETA', 'GFS') + geometryData = self._runConstraintTest('reportType', 'in', collection) + for record in geometryData: + dataURI = record.getString('dataURI') + self.assertTrue('/ETA/' in dataURI or '/GFS/' in dataURI) + + @unittest.expectedFailure + def testGetDataWithInList(self): + collection = ['ETA', 'GFS'] + geometryData = self._runConstraintTest('reportType', 'in', collection) + for record in geometryData: + dataURI = record.getString('dataURI') + self.assertTrue('/ETA/' in dataURI or '/GFS/' in dataURI) + + @unittest.expectedFailure + def testGetDataWithInGenerator(self): + collection = ('ETA', 'GFS') + generator = (item for item in collection) + geometryData = self._runConstraintTest('reportType', 'in', generator) + for record in geometryData: + dataURI = record.getString('dataURI') + self.assertTrue('/ETA/' in dataURI or '/GFS/' in dataURI) + + def testGetDataWithInvalidConstraintTypeThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('reportType', 'junk', 'ETA') + + def testGetDataWithInvalidConstraintValueThrowsException(self): + with self.assertRaises(TypeError): + self._runConstraintTest('reportType', '=', {}) + + def testGetDataWithEmptyInConstraintThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('reportType', 'in', []) + + def testGetDataWithNestedInConstraintThrowsException(self): + collection = ('ETA', 'GFS', ()) + with self.assertRaises(TypeError): + self._runConstraintTest('reportType', 'in', collection) diff --git a/awips/test/dafTests/testObs.py b/awips/test/dafTests/testObs.py new file mode 100644 index 0000000..3bc593b --- /dev/null +++ b/awips/test/dafTests/testObs.py @@ -0,0 +1,168 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from awips.dataaccess import DataAccessLayer as DAL +from dynamicserialize.dstypes.com.raytheon.uf.common.dataquery.requests import RequestConstraint + +import baseDafTestCase +import unittest + +# +# Test DAF support for obs data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# 06/09/16 5587 bsteffen Add getIdentifierValues tests +# 06/13/16 5574 tgurney Add advanced query tests +# +# + + +class ObsTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for obs data""" + + datatype = "obs" + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + self.runParametersTest(req) + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + self.runLocationsTest(req) + + def testGetAvailableTimes(self): + req = DAL.newDataRequest(self.datatype) + req.setLocationNames("KOMA") + self.runTimesTest(req) + + def testGetGeometryData(self): + req = DAL.newDataRequest(self.datatype) + req.setLocationNames("KOMA") + req.setParameters("temperature", "seaLevelPress", "dewpoint") + self.runGeometryDataTest(req) + + def testGetIdentifierValues(self): + req = DAL.newDataRequest(self.datatype) + optionalIds = set(DAL.getOptionalIdentifiers(req)) + self.runGetIdValuesTest(optionalIds) + + def testGetInvalidIdentifierValuesThrowsException(self): + self.runInvalidIdValuesTest() + + def testGetNonexistentIdentifierValuesThrowsException(self): + self.runNonexistentIdValuesTest() + + def _runConstraintTest(self, key, operator, value): + req = DAL.newDataRequest(self.datatype) + constraint = RequestConstraint.new(operator, value) + req.setParameters("temperature", "reportType") + req.setLocationNames("KOMA") + req.addIdentifier(key, constraint) + return self.runGeometryDataTest(req) + + def testGetDataWithEqualsString(self): + geometryData = self._runConstraintTest('reportType', '=', 'METAR') + for record in geometryData: + self.assertEqual(record.getString('reportType'), 'METAR') + + def testGetDataWithEqualsUnicode(self): + geometryData = self._runConstraintTest('reportType', '=', u'METAR') + for record in geometryData: + self.assertEqual(record.getString('reportType'), 'METAR') + + # No numeric tests since no numeric identifiers are available. + + def testGetDataWithEqualsNone(self): + geometryData = self._runConstraintTest('reportType', '=', None) + for record in geometryData: + self.assertEqual(record.getType('reportType'), 'NULL') + + def testGetDataWithNotEquals(self): + geometryData = self._runConstraintTest('reportType', '!=', 'METAR') + for record in geometryData: + self.assertNotEqual(record.getString('reportType'), 'METAR') + + def testGetDataWithNotEqualsNone(self): + geometryData = self._runConstraintTest('reportType', '!=', None) + for record in geometryData: + self.assertNotEqual(record.getType('reportType'), 'NULL') + + def testGetDataWithGreaterThan(self): + geometryData = self._runConstraintTest('reportType', '>', 'METAR') + for record in geometryData: + self.assertGreater(record.getString('reportType'), 'METAR') + + def testGetDataWithLessThan(self): + geometryData = self._runConstraintTest('reportType', '<', 'METAR') + for record in geometryData: + self.assertLess(record.getString('reportType'), 'METAR') + + def testGetDataWithGreaterThanEquals(self): + geometryData = self._runConstraintTest('reportType', '>=', 'METAR') + for record in geometryData: + self.assertGreaterEqual(record.getString('reportType'), 'METAR') + + def testGetDataWithLessThanEquals(self): + geometryData = self._runConstraintTest('reportType', '<=', 'METAR') + for record in geometryData: + self.assertLessEqual(record.getString('reportType'), 'METAR') + + def testGetDataWithInTuple(self): + collection = ('METAR', 'SPECI') + geometryData = self._runConstraintTest('reportType', 'in', collection) + for record in geometryData: + self.assertIn(record.getString('reportType'), collection) + + def testGetDataWithInList(self): + collection = ['METAR', 'SPECI'] + geometryData = self._runConstraintTest('reportType', 'in', collection) + for record in geometryData: + self.assertIn(record.getString('reportType'), collection) + + def testGetDataWithInGenerator(self): + collection = ('METAR', 'SPECI') + generator = (item for item in collection) + geometryData = self._runConstraintTest('reportType', 'in', generator) + for record in geometryData: + self.assertIn(record.getString('reportType'), collection) + + def testGetDataWithInvalidConstraintTypeThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('reportType', 'junk', 'METAR') + + def testGetDataWithInvalidConstraintValueThrowsException(self): + with self.assertRaises(TypeError): + self._runConstraintTest('reportType', '=', {}) + + def testGetDataWithEmptyInConstraintThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('reportType', 'in', []) + + def testGetDataWithNestedInConstraintThrowsException(self): + collection = ('METAR', 'SPECI', ()) + with self.assertRaises(TypeError): + self._runConstraintTest('reportType', 'in', collection) diff --git a/awips/test/dafTests/testPirep.py b/awips/test/dafTests/testPirep.py new file mode 100644 index 0000000..876a378 --- /dev/null +++ b/awips/test/dafTests/testPirep.py @@ -0,0 +1,83 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from awips.dataaccess import DataAccessLayer as DAL + +import baseDafTestCase +import unittest + +# +# Test DAF support for pirep data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# +# + + +class PirepTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for pirep data""" + + datatype = "pirep" + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + self.runParametersTest(req) + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + self.runLocationsTest(req) + + def testGetAvailableTimes(self): + req = DAL.newDataRequest(self.datatype) + req.setLocationNames('OMA') + self.runTimesTest(req) + + def testGetGeometryData(self): + req = DAL.newDataRequest(self.datatype) + req.setLocationNames('OMA') + req.setParameters("temperature", "windSpeed", "hazardType", "turbType") + + print("Testing getGeometryData()") + + geomData = DAL.getGeometryData(req) + self.assertIsNotNone(geomData) + print("Number of geometry records: " + str(len(geomData))) + print("Sample geometry data:") + for record in geomData[:self.sampleDataLimit]: + print("level=", record.getLevel(), end="") + # One dimensional parameters are reported on the 0.0UNKNOWN level. + # 2D parameters are reported on MB levels from pressure. + if record.getLevel() == "0.0UNKNOWN": + print(" temperature=" + record.getString("temperature") + record.getUnit("temperature"), end="") + print(" windSpeed=" + record.getString("windSpeed") + record.getUnit("windSpeed"), end="") + else: + print(" hazardType=" + record.getString("hazardType"), end="") + print(" turbType=" + record.getString("turbType"), end="") + print(" geometry=", record.getGeometry()) + + print("getGeometryData() complete\n") + diff --git a/awips/test/dafTests/testPracticeWarning.py b/awips/test/dafTests/testPracticeWarning.py new file mode 100644 index 0000000..90dee74 --- /dev/null +++ b/awips/test/dafTests/testPracticeWarning.py @@ -0,0 +1,49 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from awips.dataaccess import DataAccessLayer as DAL + +import baseDafTestCase +import testWarning + +import unittest + +# +# Test DAF support for practicewarning data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# 06/10/16 5548 tgurney Inherit all tests from +# warning +# + + +class PracticeWarningTestCase(testWarning.WarningTestCase): + """Test DAF support for practicewarning data""" + + datatype = "practicewarning" + + # All tests taken from testWarning diff --git a/awips/test/dafTests/testProfiler.py b/awips/test/dafTests/testProfiler.py new file mode 100644 index 0000000..a05f6d9 --- /dev/null +++ b/awips/test/dafTests/testProfiler.py @@ -0,0 +1,80 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from awips.dataaccess import DataAccessLayer as DAL + +import baseDafTestCase +import unittest + +# +# Test DAF support for profiler data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# +# + + +class ProfilerTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for profiler data""" + + datatype = "profiler" + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + self.runParametersTest(req) + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + self.runLocationsTest(req) + + def testGetAvailableTimes(self): + req = DAL.newDataRequest(self.datatype) + self.runTimesTest(req) + + def testGetGeometryData(self): + req = DAL.newDataRequest(self.datatype) + req.setParameters("temperature", "pressure", "uComponent", "vComponent") + + print("Testing getGeometryData()") + + geomData = DAL.getGeometryData(req) + self.assertIsNotNone(geomData) + print("Number of geometry records: " + str(len(geomData))) + print("Sample geometry data:") + for record in geomData[:self.sampleDataLimit]: + print("level:", record.getLevel(), end="") + # One dimensional parameters are reported on the 0.0UNKNOWN level. + # 2D parameters are reported on MB levels from pressure. + if record.getLevel() == "0.0UNKNOWN": + print(" temperature=" + record.getString("temperature") + record.getUnit("temperature"), end="") + print(" pressure=" + record.getString("pressure") + record.getUnit("pressure"), end="") + else: + print(" uComponent=" + record.getString("uComponent") + record.getUnit("uComponent"), end="") + print(" vComponent=" + record.getString("vComponent") + record.getUnit("vComponent"), end="") + print(" geometry:", record.getGeometry()) + + print("getGeometryData() complete\n\n") diff --git a/awips/test/dafTests/testRadar.py b/awips/test/dafTests/testRadar.py new file mode 100644 index 0000000..8adaf5f --- /dev/null +++ b/awips/test/dafTests/testRadar.py @@ -0,0 +1,197 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from dynamicserialize.dstypes.com.raytheon.uf.common.dataquery.requests import RequestConstraint +from shapely.geometry import box +from awips.dataaccess import DataAccessLayer as DAL +from awips.ThriftClient import ThriftRequestException + +import baseDafTestCase +import unittest + +# +# Test DAF support for radar data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# 04/26/16 5587 tgurney Move identifier values tests +# out of base class +# 06/01/16 5587 tgurney Update testGetIdentifierValues +# 06/08/16 5574 mapeters Add advanced query tests +# 06/13/16 5574 tgurney Fix checks for None +# 06/14/16 5548 tgurney Undo previous change (broke +# test) +# +# + + +class RadarTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for radar data""" + + datatype = 'radar' + + envelope = box(-97.0, 41.0, -96.0, 42.0) + """Request area (box around KOAX)""" + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + self.runParametersTest(req) + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + self.runLocationsTest(req) + + def testGetAvailableLevels(self): + req = DAL.newDataRequest(self.datatype) + self.runLevelsTest(req) + + def testGetAvailableLevelsWithInvalidLevelIdentifierThrowsException(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier('level.one.field', 'invalidLevelField') + with self.assertRaises(ThriftRequestException) as cm: + self.runLevelsTest(req) + self.assertIn('IncompatibleRequestException', str(cm.exception)) + + def testGetAvailableTimes(self): + req = DAL.newDataRequest(self.datatype) + req.setEnvelope(self.envelope) + self.runTimesTest(req) + + def testGetGridData(self): + req = DAL.newDataRequest(self.datatype) + req.setEnvelope(self.envelope) + req.setLocationNames('koax') + req.setParameters('94') + # Don't test shapes since they may differ. + self.runGridDataTest(req, testSameShape=False) + + def testGetIdentifierValues(self): + req = DAL.newDataRequest(self.datatype) + optionalIds = set(DAL.getOptionalIdentifiers(req)) + requiredIds = set(DAL.getRequiredIdentifiers(req)) + self.runGetIdValuesTest(optionalIds | requiredIds) + + def testGetInvalidIdentifierValuesThrowsException(self): + self.runInvalidIdValuesTest() + + def testGetNonexistentIdentifierValuesThrowsException(self): + self.runNonexistentIdValuesTest() + + def _runConstraintTest(self, key, operator, value): + req = DAL.newDataRequest(self.datatype) + constraint = RequestConstraint.new(operator, value) + req.addIdentifier(key, constraint) + req.setParameters('94') + # Don't test shapes since they may differ. + return self.runGridDataTest(req, testSameShape=False) + + def testGetDataWithEqualsString(self): + gridData = self._runConstraintTest('icao', '=', 'koax') + for record in gridData: + self.assertEqual(record.getAttribute('icao'), 'koax') + + def testGetDataWithEqualsUnicode(self): + gridData = self._runConstraintTest('icao', '=', u'koax') + for record in gridData: + self.assertEqual(record.getAttribute('icao'), 'koax') + + def testGetDataWithEqualsInt(self): + gridData = self._runConstraintTest('icao', '=', 1000) + for record in gridData: + self.assertEqual(record.getAttribute('icao'), 1000) + + def testGetDataWithEqualsLong(self): + gridData = self._runConstraintTest('icao', '=', 1000L) + for record in gridData: + self.assertEqual(record.getAttribute('icao'), 1000) + + def testGetDataWithEqualsFloat(self): + gridData = self._runConstraintTest('icao', '=', 1.0) + for record in gridData: + self.assertEqual(round(record.getAttribute('icao'), 1), 1.0) + + def testGetDataWithEqualsNone(self): + gridData = self._runConstraintTest('icao', '=', None) + for record in gridData: + self.assertIsNone(record.getAttribute('icao')) + + def testGetDataWithNotEquals(self): + gridData = self._runConstraintTest('icao', '!=', 'koax') + for record in gridData: + self.assertNotEqual(record.getAttribute('icao'), 'koax') + + def testGetDataWithNotEqualsNone(self): + gridData = self._runConstraintTest('icao', '!=', None) + for record in gridData: + self.assertIsNotNone(record.getAttribute('icao')) + + def testGetDataWithGreaterThan(self): + gridData = self._runConstraintTest('icao', '>', 'koax') + for record in gridData: + self.assertGreater(record.getAttribute('icao'), 'koax') + + def testGetDataWithLessThan(self): + gridData = self._runConstraintTest('icao', '<', 'koax') + for record in gridData: + self.assertLess(record.getAttribute('icao'), 'koax') + + def testGetDataWithGreaterThanEquals(self): + gridData = self._runConstraintTest('icao', '>=', 'koax') + for record in gridData: + self.assertGreaterEqual(record.getAttribute('icao'), 'koax') + + def testGetDataWithLessThanEquals(self): + gridData = self._runConstraintTest('icao', '<=', 'koax') + for record in gridData: + self.assertLessEqual(record.getAttribute('icao'), 'koax') + + def testGetDataWithInTuple(self): + gridData = self._runConstraintTest('icao', 'in', ('koax', 'tpbi')) + for record in gridData: + self.assertIn(record.getAttribute('icao'), ('koax', 'tpbi')) + + def testGetDataWithInList(self): + gridData = self._runConstraintTest('icao', 'in', ['koax', 'tpbi']) + for record in gridData: + self.assertIn(record.getAttribute('icao'), ('koax', 'tpbi')) + + def testGetDataWithInGenerator(self): + generator = (item for item in ('koax', 'tpbi')) + gridData = self._runConstraintTest('icao', 'in', generator) + for record in gridData: + self.assertIn(record.getAttribute('icao'), ('koax', 'tpbi')) + + def testGetDataWithInvalidConstraintTypeThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('icao', 'junk', 'koax') + + def testGetDataWithInvalidConstraintValueThrowsException(self): + with self.assertRaises(TypeError): + self._runConstraintTest('icao', '=', {}) + + def testGetDataWithEmptyInConstraintThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('icao', 'in', []) diff --git a/awips/test/dafTests/testRadarSpatial.py b/awips/test/dafTests/testRadarSpatial.py new file mode 100644 index 0000000..9c0d13d --- /dev/null +++ b/awips/test/dafTests/testRadarSpatial.py @@ -0,0 +1,175 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from shapely.geometry import box +from awips.dataaccess import DataAccessLayer as DAL + +from dynamicserialize.dstypes.com.raytheon.uf.common.dataquery.requests import RequestConstraint +import baseDafTestCase +import unittest + +# +# Test DAF support for radar_spatial data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# 05/26/16 5587 njensen Added testGetIdentifierValues() +# 06/01/16 5587 tgurney Move testIdentifiers() to +# superclass +# 06/13/16 5574 tgurney Add advanced query tests +# +# + + +class RadarSpatialTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for radar_spatial data""" + + datatype = "radar_spatial" + + envelope = box(-97.0, 41.0, -96.0, 42.0) + """ + Default request area (box around KOAX) + """ + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + req.setEnvelope(self.envelope) + self.runLocationsTest(req) + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + self.runParametersTest(req) + + def testGetIdentifierValues(self): + self.runGetIdValuesTest(['wfo_id']) + + def testGetGeometryData(self): + req = DAL.newDataRequest(self.datatype) + req.setLocationNames("TORD", "TMDW") + req.setParameters("wfo_id", "name", "elevmeter") + self.runGeometryDataTest(req) + + def testRequestingTimesThrowsTimeAgnosticDataException(self): + req = DAL.newDataRequest(self.datatype) + self.runTimeAgnosticTest(req) + + def _runConstraintTest(self, key, operator, value): + req = DAL.newDataRequest(self.datatype) + constraint = RequestConstraint.new(operator, value) + req.addIdentifier(key, constraint) + req.setParameters('elevmeter', 'eqp_elv', 'wfo_id', 'immutablex') + return self.runGeometryDataTest(req) + + def testGetDataWithEqualsString(self): + geometryData = self._runConstraintTest('wfo_id', '=', 'OAX') + for record in geometryData: + self.assertEqual(record.getString('wfo_id'), 'OAX') + + def testGetDataWithEqualsUnicode(self): + geometryData = self._runConstraintTest('wfo_id', '=', u'OAX') + for record in geometryData: + self.assertEqual(record.getString('wfo_id'), 'OAX') + + def testGetDataWithEqualsInt(self): + geometryData = self._runConstraintTest('immutablex', '=', 57) + for record in geometryData: + self.assertEqual(record.getNumber('immutablex'), 57) + + def testGetDataWithEqualsLong(self): + geometryData = self._runConstraintTest('immutablex', '=', 57L) + for record in geometryData: + self.assertEqual(record.getNumber('immutablex'), 57) + + def testGetDataWithEqualsFloat(self): + geometryData = self._runConstraintTest('immutablex', '=', 57.0) + for record in geometryData: + self.assertEqual(round(record.getNumber('immutablex'), 1), 57.0) + + def testGetDataWithEqualsNone(self): + geometryData = self._runConstraintTest('wfo_id', '=', None) + for record in geometryData: + self.assertEqual(record.getType('wfo_id'), 'NULL') + + def testGetDataWithNotEquals(self): + geometryData = self._runConstraintTest('wfo_id', '!=', 'OAX') + for record in geometryData: + self.assertNotEquals(record.getString('wfo_id'), 'OAX') + + def testGetDataWithNotEqualsNone(self): + geometryData = self._runConstraintTest('wfo_id', '!=', None) + for record in geometryData: + self.assertNotEqual(record.getType('wfo_id'), 'NULL') + + def testGetDataWithGreaterThan(self): + geometryData = self._runConstraintTest('elevmeter', '>', 1000) + for record in geometryData: + self.assertGreater(record.getNumber('elevmeter'), 1000) + + def testGetDataWithLessThan(self): + geometryData = self._runConstraintTest('elevmeter', '<', 1000) + for record in geometryData: + self.assertLess(record.getNumber('elevmeter'), 1000) + + def testGetDataWithGreaterThanEquals(self): + geometryData = self._runConstraintTest('eqp_elv', '>=', 1295) + for record in geometryData: + self.assertGreaterEqual(record.getNumber('eqp_elv'), 1295) + + def testGetDataWithLessThanEquals(self): + geometryData = self._runConstraintTest('eqp_elv', '<=', 138) + for record in geometryData: + self.assertLessEqual(record.getNumber('eqp_elv'), 138) + + def testGetDataWithInTuple(self): + collection = ('OAX', 'GID') + geometryData = self._runConstraintTest('wfo_id', 'in', collection) + for record in geometryData: + self.assertIn(record.getString('wfo_id'), collection) + + def testGetDataWithInList(self): + collection = ['OAX', 'GID'] + geometryData = self._runConstraintTest('wfo_id', 'in', collection) + for record in geometryData: + self.assertIn(record.getString('wfo_id'), collection) + + def testGetDataWithInGenerator(self): + collection = ('OAX', 'GID') + generator = (item for item in collection) + geometryData = self._runConstraintTest('wfo_id', 'in', generator) + for record in geometryData: + self.assertIn(record.getString('wfo_id'), collection) + + def testGetDataWithInvalidConstraintTypeThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('wfo_id', 'junk', 'OAX') + + def testGetDataWithInvalidConstraintValueThrowsException(self): + with self.assertRaises(TypeError): + self._runConstraintTest('wfo_id', '=', {}) + + def testGetDataWithEmptyInConstraintThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('wfo_id', 'in', []) diff --git a/awips/test/dafTests/testSatellite.py b/awips/test/dafTests/testSatellite.py new file mode 100644 index 0000000..0bee61b --- /dev/null +++ b/awips/test/dafTests/testSatellite.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from awips.dataaccess import DataAccessLayer as DAL +from dynamicserialize.dstypes.com.raytheon.uf.common.dataquery.requests import RequestConstraint + +import baseDafTestCase +import unittest + +# +# Test DAF support for satellite data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# 04/26/16 5587 tgurney Move identifier values tests +# out of base class +# 06/01/16 5587 tgurney Update testGetIdentifierValues +# 06/07/16 5574 tgurney Add advanced query tests +# 06/13/16 5574 tgurney Typo +# +# + + +class SatelliteTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for satellite data""" + + datatype = "satellite" + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + self.runParametersTest(req) + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + self.runLocationsTest(req) + + def testGetAvailableTimes(self): + req = DAL.newDataRequest(self.datatype) + req.setLocationNames("West CONUS") + self.runTimesTest(req) + + def testGetGridData(self): + req = DAL.newDataRequest(self.datatype) + req.setParameters("Imager 11 micron IR") + req.setLocationNames("West CONUS") + self.runGridDataTest(req) + + def testGetIdentifierValues(self): + req = DAL.newDataRequest(self.datatype) + optionalIds = set(DAL.getOptionalIdentifiers(req)) + requiredIds = set(DAL.getRequiredIdentifiers(req)) + self.runGetIdValuesTest(optionalIds | requiredIds) + + def testGetInvalidIdentifierValuesThrowsException(self): + self.runInvalidIdValuesTest() + + def testGetNonexistentIdentifierValuesThrowsException(self): + self.runNonexistentIdValuesTest() + + def _runConstraintTest(self, key, operator, value): + req = DAL.newDataRequest(self.datatype) + constraint = RequestConstraint.new(operator, value) + req.addIdentifier(key, constraint) + req.setParameters("Imager 11 micron IR") + req.setLocationNames("West CONUS") + return self.runGridDataTest(req) + + def testGetDataWithEqualsString(self): + gridData = self._runConstraintTest('creatingEntity', '=', 'Composite') + for record in gridData: + self.assertEqual(record.getAttribute('creatingEntity'), 'Composite') + + def testGetDataWithEqualsUnicode(self): + gridData = self._runConstraintTest('creatingEntity', '=', u'Composite') + for record in gridData: + self.assertEqual(record.getAttribute('creatingEntity'), 'Composite') + + def testGetDataWithEqualsInt(self): + gridData = self._runConstraintTest('creatingEntity', '=', 1000) + for record in gridData: + self.assertEqual(record.getAttribute('creatingEntity'), 1000) + + def testGetDataWithEqualsLong(self): + gridData = self._runConstraintTest('creatingEntity', '=', 1000L) + for record in gridData: + self.assertEqual(record.getAttribute('creatingEntity'), 1000) + + def testGetDataWithEqualsFloat(self): + gridData = self._runConstraintTest('creatingEntity', '=', 1.0) + for record in gridData: + self.assertEqual(round(record.getAttribute('creatingEntity'), 1), 1.0) + + def testGetDataWithEqualsNone(self): + gridData = self._runConstraintTest('creatingEntity', '=', None) + for record in gridData: + self.assertIsNone(record.getAttribute('creatingEntity')) + + def testGetDataWithNotEquals(self): + gridData = self._runConstraintTest('creatingEntity', '!=', 'Composite') + for record in gridData: + self.assertNotEqual(record.getAttribute('creatingEntity'), 'Composite') + + def testGetDataWithNotEqualsNone(self): + gridData = self._runConstraintTest('creatingEntity', '!=', None) + for record in gridData: + self.assertIsNotNone(record.getAttribute('creatingEntity')) + + def testGetDataWithGreaterThan(self): + gridData = self._runConstraintTest('creatingEntity', '>', 'Composite') + for record in gridData: + self.assertGreater(record.getAttribute('creatingEntity'), 'Composite') + + def testGetDataWithLessThan(self): + gridData = self._runConstraintTest('creatingEntity', '<', 'Composite') + for record in gridData: + self.assertLess(record.getAttribute('creatingEntity'), 'Composite') + + def testGetDataWithGreaterThanEquals(self): + gridData = self._runConstraintTest('creatingEntity', '>=', 'Composite') + for record in gridData: + self.assertGreaterEqual(record.getAttribute('creatingEntity'), 'Composite') + + def testGetDataWithLessThanEquals(self): + gridData = self._runConstraintTest('creatingEntity', '<=', 'Composite') + for record in gridData: + self.assertLessEqual(record.getAttribute('creatingEntity'), 'Composite') + + def testGetDataWithInTuple(self): + collection = ('Composite', 'Miscellaneous') + gridData = self._runConstraintTest('creatingEntity', 'in', collection) + for record in gridData: + self.assertIn(record.getAttribute('creatingEntity'), collection) + + def testGetDataWithInList(self): + collection = ('Composite', 'Miscellaneous') + gridData = self._runConstraintTest('creatingEntity', 'in', collection) + for record in gridData: + self.assertIn(record.getAttribute('creatingEntity'), collection) + + def testGetDataWithInGenerator(self): + collection = ('Composite', 'Miscellaneous') + generator = (item for item in collection) + gridData = self._runConstraintTest('creatingEntity', 'in', generator) + for record in gridData: + self.assertIn(record.getAttribute('creatingEntity'), collection) + + def testGetDataWithInvalidConstraintTypeThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('creatingEntity', 'junk', 'Composite') + + def testGetDataWithInvalidConstraintValueThrowsException(self): + with self.assertRaises(TypeError): + self._runConstraintTest('creatingEntity', '=', {}) + + def testGetDataWithEmptyInConstraintThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('creatingEntity', 'in', []) + + def testGetDataWithNestedInConstraintThrowsException(self): + collection = ('Composite', 'Miscellaneous', ()) + with self.assertRaises(TypeError): + self._runConstraintTest('creatingEntity', 'in', collection) diff --git a/awips/test/dafTests/testSfcObs.py b/awips/test/dafTests/testSfcObs.py new file mode 100644 index 0000000..8967b35 --- /dev/null +++ b/awips/test/dafTests/testSfcObs.py @@ -0,0 +1,177 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from awips.dataaccess import DataAccessLayer as DAL + +from dynamicserialize.dstypes.com.raytheon.uf.common.dataquery.requests import RequestConstraint +import baseDafTestCase +import unittest + +# +# Test DAF support for sfcobs data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# 06/09/16 5587 bsteffen Add getIdentifierValues tests +# 06/13/16 5574 tgurney Add advanced query tests +# +# + + +class SfcObsTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for sfcobs data""" + + datatype = "sfcobs" + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + self.runParametersTest(req) + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + self.runLocationsTest(req) + + def testGetAvailableTimes(self): + req = DAL.newDataRequest(self.datatype) + req.setLocationNames("14547") + self.runTimesTest(req) + + def testGetGeometryData(self): + req = DAL.newDataRequest(self.datatype) + req.setLocationNames("14547") + req.setParameters("temperature", "seaLevelPress", "dewpoint") + self.runGeometryDataTest(req) + + def testGetIdentifierValues(self): + req = DAL.newDataRequest(self.datatype) + optionalIds = set(DAL.getOptionalIdentifiers(req)) + self.runGetIdValuesTest(optionalIds) + + def testGetInvalidIdentifierValuesThrowsException(self): + self.runInvalidIdValuesTest() + + def testGetNonexistentIdentifierValuesThrowsException(self): + self.runNonexistentIdValuesTest() + + def _runConstraintTest(self, key, operator, value): + req = DAL.newDataRequest(self.datatype) + constraint = RequestConstraint.new(operator, value) + req.addIdentifier(key, constraint) + req.setParameters("temperature", "reportType") + return self.runGeometryDataTest(req) + + def testGetDataWithEqualsString(self): + geometryData = self._runConstraintTest('reportType', '=', '1004') + for record in geometryData: + self.assertEqual(record.getString('reportType'), '1004') + + def testGetDataWithEqualsUnicode(self): + geometryData = self._runConstraintTest('reportType', '=', u'1004') + for record in geometryData: + self.assertEqual(record.getString('reportType'), '1004') + + def testGetDataWithEqualsInt(self): + geometryData = self._runConstraintTest('reportType', '=', 1004) + for record in geometryData: + self.assertEqual(record.getString('reportType'), '1004') + + def testGetDataWithEqualsLong(self): + geometryData = self._runConstraintTest('reportType', '=', 1004L) + for record in geometryData: + self.assertEqual(record.getString('reportType'), '1004') + + # No float test because no float identifiers are available + + def testGetDataWithEqualsNone(self): + geometryData = self._runConstraintTest('reportType', '=', None) + for record in geometryData: + self.assertEqual(record.getType('reportType'), 'NULL') + + def testGetDataWithNotEquals(self): + geometryData = self._runConstraintTest('reportType', '!=', 1004) + for record in geometryData: + self.assertNotEqual(record.getString('reportType'), '1004') + + def testGetDataWithNotEqualsNone(self): + geometryData = self._runConstraintTest('reportType', '!=', None) + for record in geometryData: + self.assertNotEqual(record.getType('reportType'), 'NULL') + + def testGetDataWithGreaterThan(self): + geometryData = self._runConstraintTest('reportType', '>', 1004) + for record in geometryData: + self.assertGreater(record.getString('reportType'), '1004') + + def testGetDataWithLessThan(self): + geometryData = self._runConstraintTest('reportType', '<', 1004) + for record in geometryData: + self.assertLess(record.getString('reportType'), '1004') + + def testGetDataWithGreaterThanEquals(self): + geometryData = self._runConstraintTest('reportType', '>=', 1004) + for record in geometryData: + self.assertGreaterEqual(record.getString('reportType'), '1004') + + def testGetDataWithLessThanEquals(self): + geometryData = self._runConstraintTest('reportType', '<=', 1004) + for record in geometryData: + self.assertLessEqual(record.getString('reportType'), '1004') + + def testGetDataWithInTuple(self): + collection = ('1004', '1005') + geometryData = self._runConstraintTest('reportType', 'in', collection) + for record in geometryData: + self.assertIn(record.getString('reportType'), collection) + + def testGetDataWithInList(self): + collection = ['1004', '1005'] + geometryData = self._runConstraintTest('reportType', 'in', collection) + for record in geometryData: + self.assertIn(record.getString('reportType'), collection) + + def testGetDataWithInGenerator(self): + collection = ('1004', '1005') + generator = (item for item in collection) + geometryData = self._runConstraintTest('reportType', 'in', generator) + for record in geometryData: + self.assertIn(record.getString('reportType'), collection) + + def testGetDataWithInvalidConstraintTypeThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('reportType', 'junk', '1004') + + def testGetDataWithInvalidConstraintValueThrowsException(self): + with self.assertRaises(TypeError): + self._runConstraintTest('reportType', '=', {}) + + def testGetDataWithEmptyInConstraintThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('reportType', 'in', []) + + def testGetDataWithNestedInConstraintThrowsException(self): + collection = ('1004', '1005', ()) + with self.assertRaises(TypeError): + self._runConstraintTest('reportType', 'in', collection) diff --git a/awips/test/dafTests/testTopo.py b/awips/test/dafTests/testTopo.py new file mode 100644 index 0000000..1ed4131 --- /dev/null +++ b/awips/test/dafTests/testTopo.py @@ -0,0 +1,96 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from awips.dataaccess import DataAccessLayer as DAL +from awips.ThriftClient import ThriftRequestException + +import baseDafTestCase +import shapely.geometry +import unittest + +# +# Test DAF support for topo data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# 05/26/16 5587 tgurney Add test for +# getIdentifierValues() +# 06/01/16 5587 tgurney Update testGetIdentifierValues +# +# + + +class TopoTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for topo data""" + + datatype = "topo" + + def testGetGridData(self): + print("defaultTopo") + req = DAL.newDataRequest(self.datatype) + req.addIdentifier("group", "/") + req.addIdentifier("dataset", "full") + poly = shapely.geometry.LinearRing(((-70, 40), (-71, 40), (-71, 42), (-70, 42))) + req.setEnvelope(poly) + gridData = DAL.getGridData(req) + self.assertIsNotNone(gridData) + print("Number of grid records: " + str(len(gridData))) + print("Sample grid data shape:\n" + str(gridData[0].getRawData().shape) + "\n") + print("Sample grid data:\n" + str(gridData[0].getRawData()) + "\n") + + for topoFile in ["gmted2010", "gtopo30"]: + print("\n" + topoFile) + req.addIdentifier("topoFile", topoFile) + gridData = DAL.getGridData(req) + self.assertIsNotNone(gridData) + print("Number of grid records: " + str(len(gridData))) + print("Sample grid data shape:\n" + str(gridData[0].getRawData().shape) + "\n") + print("Sample grid data:\n" + str(gridData[0].getRawData()) + "\n") + + + def testRequestingTooMuchDataThrowsResponseTooLargeException(self): + req = DAL.newDataRequest(self.datatype) + req.addIdentifier("group", "/") + req.addIdentifier("dataset", "full") + points = ((-180, 90), (180, 90), (180, -90), (-180, -90)) + poly = shapely.geometry.LinearRing(points) + req.setEnvelope(poly) + + with self.assertRaises(ThriftRequestException) as cm: + DAL.getGridData(req) + self.assertIn('ResponseTooLargeException', str(cm.exception)) + + def testGetIdentifierValues(self): + req = DAL.newDataRequest(self.datatype) + optionalIds = set(DAL.getOptionalIdentifiers(req)) + requiredIds = set(DAL.getRequiredIdentifiers(req)) + self.runGetIdValuesTest(optionalIds | requiredIds) + + def testGetInvalidIdentifierValuesThrowsException(self): + self.runInvalidIdValuesTest() + + def testGetNonexistentIdentifierValuesThrowsException(self): + self.runNonexistentIdValuesTest() diff --git a/awips/test/dafTests/testWarning.py b/awips/test/dafTests/testWarning.py new file mode 100644 index 0000000..0cdba36 --- /dev/null +++ b/awips/test/dafTests/testWarning.py @@ -0,0 +1,228 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +from __future__ import print_function +from awips.dataaccess import DataAccessLayer as DAL + +from dynamicserialize.dstypes.com.raytheon.uf.common.dataquery.requests import RequestConstraint +import baseDafTestCase +import unittest + +# +# Test DAF support for warning data +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 01/19/16 4795 mapeters Initial Creation. +# 04/11/16 5548 tgurney Cleanup +# 04/18/16 5548 tgurney More cleanup +# 04/26/16 5587 tgurney Add identifier values tests +# 06/08/16 5574 tgurney Add advanced query tests +# 06/10/16 5548 tgurney Clean up references to name +# of data type +# 06/13/16 5574 tgurney Fix checks for None +# 06/21/16 5548 tgurney Skip tests that cause errors +# +# + + +class WarningTestCase(baseDafTestCase.DafTestCase): + """Test DAF support for warning data""" + + datatype = "warning" + + def _getLocationNames(self): + req = DAL.newDataRequest() + req.setDatatype(self.datatype) + return DAL.getAvailableLocationNames(req) + + def _getAllRecords(self): + req = DAL.newDataRequest() + req.setDatatype(self.datatype) + req.setParameters('id') + return DAL.getGeometryData(req) + + def testGetAvailableParameters(self): + req = DAL.newDataRequest(self.datatype) + self.runParametersTest(req) + + def testGetAvailableLocations(self): + req = DAL.newDataRequest(self.datatype) + self.runLocationsTest(req) + + def testGetAvailableTimes(self): + req = DAL.newDataRequest(self.datatype) + req.setParameters("etn", "wmoid") + self.runTimesTest(req) + + def testGetGeometryData(self): + req = DAL.newDataRequest(self.datatype) + req.setParameters("etn", "wmoid") + self.runGeometryDataTest(req) + + def testFilterOnLocationName(self): + allRecordsCount = len(self._getAllRecords()) + allLocationNames = self._getLocationNames() + if allRecordsCount == 0: + errmsg = "No {0} data exists on {1}. Try again with {0} data." + raise unittest.SkipTest(errmsg.format(self.datatype, DAL.THRIFT_HOST)) + if len(allLocationNames) != 1: + testCount = 3 # number of different location names to test + for locationName in allLocationNames[:testCount]: + req = DAL.newDataRequest() + req.setDatatype(self.datatype) + req.setParameters('id') + req.setLocationNames(locationName) + geomData = DAL.getGeometryData(req) + self.assertLess(len(geomData), allRecordsCount) + for geom in geomData: + self.assertEqual(geom.getLocationName(), locationName) + + def testFilterOnNonexistentLocationReturnsEmpty(self): + req = DAL.newDataRequest() + req.setDatatype(self.datatype) + req.setParameters('id') + req.setLocationNames('ZZZZ') + self.assertEqual(len(DAL.getGeometryData(req)), 0) + + def testFilterOnInvalidLocationThrowsIncompatibleRequestException(self): + req = DAL.newDataRequest() + req.setDatatype(self.datatype) + req.setParameters('id') + req.setLocationNames(') and 0=1') + with self.assertRaises(Exception) as cm: + DAL.getGeometryData(req) + self.assertIn('IncompatibleRequestException', str(cm.exception)) + + def testGetColumnIdentifierValues(self): + self.runGetIdValuesTest(['act']) + + @unittest.skip('avoid EDEX error') + def testGetInvalidIdentifierValuesThrowsException(self): + self.runInvalidIdValuesTest() + + @unittest.skip('avoid EDEX error') + def testGetNonexistentIdentifierValuesThrowsException(self): + self.runNonexistentIdValuesTest() + + def _runConstraintTest(self, key, operator, value): + req = DAL.newDataRequest(self.datatype) + constraint = RequestConstraint.new(operator, value) + req.addIdentifier(key, constraint) + req.setParameters("etn", "wmoid", "sig") + return self.runGeometryDataTest(req) + + def testGetDataWithEqualsString(self): + geometryData = self._runConstraintTest('sig', '=', 'Y') + for record in geometryData: + self.assertEqual(record.getString('sig'), 'Y') + + def testGetDataWithEqualsUnicode(self): + geometryData = self._runConstraintTest('sig', '=', u'Y') + for record in geometryData: + self.assertEqual(record.getString('sig'), 'Y') + + def testGetDataWithEqualsInt(self): + geometryData = self._runConstraintTest('etn', '=', 1000) + for record in geometryData: + self.assertEqual(record.getString('etn'), '1000') + + def testGetDataWithEqualsLong(self): + geometryData = self._runConstraintTest('etn', '=', 1000L) + for record in geometryData: + self.assertEqual(record.getString('etn'), '1000') + + def testGetDataWithEqualsFloat(self): + geometryData = self._runConstraintTest('etn', '=', 1.0) + for record in geometryData: + self.assertEqual(round(float(record.getString('etn')), 1), 1.0) + + def testGetDataWithEqualsNone(self): + geometryData = self._runConstraintTest('sig', '=', None) + for record in geometryData: + self.assertEqual(record.getType('sig'), 'NULL') + + def testGetDataWithNotEquals(self): + geometryData = self._runConstraintTest('sig', '!=', 'Y') + for record in geometryData: + self.assertNotEqual(record.getString('sig'), 'Y') + + def testGetDataWithNotEqualsNone(self): + geometryData = self._runConstraintTest('sig', '!=', None) + for record in geometryData: + self.assertNotEqual(record.getType('sig'), 'NULL') + + def testGetDataWithGreaterThan(self): + geometryData = self._runConstraintTest('sig', '>', 'Y') + for record in geometryData: + self.assertGreater(record.getString('sig'), 'Y') + + def testGetDataWithLessThan(self): + geometryData = self._runConstraintTest('sig', '<', 'Y') + for record in geometryData: + self.assertLess(record.getString('sig'), 'Y') + + def testGetDataWithGreaterThanEquals(self): + geometryData = self._runConstraintTest('sig', '>=', 'Y') + for record in geometryData: + self.assertGreaterEqual(record.getString('sig'), 'Y') + + def testGetDataWithLessThanEquals(self): + geometryData = self._runConstraintTest('sig', '<=', 'Y') + for record in geometryData: + self.assertLessEqual(record.getString('sig'), 'Y') + + def testGetDataWithInTuple(self): + collection = ('Y', 'A') + geometryData = self._runConstraintTest('sig', 'in', collection) + for record in geometryData: + self.assertIn(record.getString('sig'), collection) + + def testGetDataWithInList(self): + collection = ['Y', 'A'] + geometryData = self._runConstraintTest('sig', 'in', collection) + for record in geometryData: + self.assertIn(record.getString('sig'), collection) + + def testGetDataWithInGenerator(self): + collection = ('Y', 'A') + generator = (item for item in collection) + geometryData = self._runConstraintTest('sig', 'in', generator) + for record in geometryData: + self.assertIn(record.getString('sig'), collection) + + def testGetDataWithInvalidConstraintTypeThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('sig', 'junk', 'Y') + + def testGetDataWithInvalidConstraintValueThrowsException(self): + with self.assertRaises(TypeError): + self._runConstraintTest('sig', '=', {}) + + def testGetDataWithEmptyInConstraintThrowsException(self): + with self.assertRaises(ValueError): + self._runConstraintTest('sig', 'in', []) + + def testGetDataWithNestedInConstraintThrowsException(self): + collection = ('Y', 'A', ()) + with self.assertRaises(TypeError): + self._runConstraintTest('sig', 'in', collection) diff --git a/docs/source/about.rst b/docs/source/about.rst index a8bbaca..771d137 100644 --- a/docs/source/about.rst +++ b/docs/source/about.rst @@ -64,7 +64,7 @@ installations. Package Version RPM Name ====================== ============== ============================== Python 2.7.10 awips2-python -**awips** **0.9.7** **awips2-python-awips** +**awips** **0.9.8** **awips2-python-awips** cartopy 0.14.2 awips2-python-cartopy cherrypy 3.1.2 awips2-python-cherrypy cycler 0.10.0 awips2-python-cycler diff --git a/docs/source/conf.py b/docs/source/conf.py index ecb05c7..92cd1da 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -65,7 +65,7 @@ author = 'Unidata' # built documents. # # The short X.Y version. -version = '0.9.7' +version = '0.9.8' # The full version, including alpha/beta/rc tags. # The language for content autogenerated by Sphinx. Refer to documentation diff --git a/dynamicserialize/DynamicSerializationManager.py b/dynamicserialize/DynamicSerializationManager.py index dbfd0bf..c3ec70c 100644 --- a/dynamicserialize/DynamicSerializationManager.py +++ b/dynamicserialize/DynamicSerializationManager.py @@ -66,4 +66,4 @@ class DynamicSerializationManager: return self.transport.getvalue() def _serialize(self, ctx, obj): - ctx.serializeMessage(obj) \ No newline at end of file + ctx.serializeMessage(obj) diff --git a/dynamicserialize/adapters/CommutativeTimestampAdapter.py b/dynamicserialize/adapters/CommutativeTimestampAdapter.py new file mode 100644 index 0000000..9b52c15 --- /dev/null +++ b/dynamicserialize/adapters/CommutativeTimestampAdapter.py @@ -0,0 +1,46 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + + +# +# Adapter for CommutativeTimestamp +# +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 9/21/2015 4486 rjpeter Initial creation. +# Jun 23, 2016 5696 rjpeter Handle CommutativeTimestamp. +# +# + +from dynamicserialize.dstypes.com.raytheon.uf.common.time import CommutativeTimestamp + + +ClassAdapter = 'com.raytheon.uf.common.time.CommutativeTimestamp' + +def serialize(context, date): + context.writeI64(date.getTime()) + +def deserialize(context): + result = CommutativeTimestamp() + result.setTime(context.readI64()) + return result diff --git a/dynamicserialize/adapters/__init__.py b/dynamicserialize/adapters/__init__.py index ccf34c2..758ce0e 100644 --- a/dynamicserialize/adapters/__init__.py +++ b/dynamicserialize/adapters/__init__.py @@ -1,19 +1,19 @@ ## # This software was developed and / or modified by Raytheon Company, # pursuant to Contract DG133W-05-CQ-1067 with the US Government. -# +# # U.S. EXPORT CONTROLLED TECHNICAL DATA # This software product contains export-restricted data whose # export/transfer/disclosure is restricted by U.S. law. Dissemination # to non-U.S. persons whether in the United States or abroad requires # an export license or other authorization. -# +# # Contractor Name: Raytheon Company # Contractor Address: 6825 Pine Street, Suite 340 # Mail Stop B8 # Omaha, NE 68106 # 402.291.0100 -# +# # See the AWIPS II Master Rights File ("Master Rights File.pdf") for # further licensing information. ## @@ -21,10 +21,10 @@ # # __init__.py for Dynamic Serialize adapters. -# -# +# +# # SOFTWARE HISTORY -# +# # Date Ticket# Engineer Description # ------------ ---------- ----------- -------------------------- # 08/31/10 njensen Initial Creation. @@ -33,6 +33,7 @@ # 02/06/14 #2672 bsteffen Added JTSEnvelopeAdapter # 06/22/2015 #4573 randerso Added JobProgressAdapter # 09/21/2015 #4486 rjpeter Added FormattedDateAdapter +# 06/23/2016 #5696 rjpeter Added CommutativeTimestampAdapter # __all__ = [ @@ -52,6 +53,7 @@ __all__ = [ 'ParmIDAdapter', 'DatabaseIDAdapter', 'TimestampAdapter', + 'CommutativeTimestampAdapter', 'EnumSetAdapter', 'FloatBufferAdapter', 'ByteBufferAdapter', @@ -60,12 +62,12 @@ __all__ = [ 'JTSEnvelopeAdapter', 'JobProgressAdapter', ] - + classAdapterRegistry = {} - + def getAdapterRegistry(): - import sys + import sys for x in __all__: exec('import dynamicserialize.adapters.' + x ) m = sys.modules['dynamicserialize.adapters.' + x] @@ -80,7 +82,7 @@ def getAdapterRegistry(): else: raise LookupError('Adapter class ' + x + ' has no ClassAdapter field ' + \ 'and cannot be registered.') - + getAdapterRegistry() diff --git a/dynamicserialize/dstypes/com/raytheon/uf/common/__init__.py b/dynamicserialize/dstypes/com/raytheon/uf/common/__init__.py index f155bf4..dfd5b4a 100644 --- a/dynamicserialize/dstypes/com/raytheon/uf/common/__init__.py +++ b/dynamicserialize/dstypes/com/raytheon/uf/common/__init__.py @@ -26,6 +26,7 @@ __all__ = [ 'auth', 'dataaccess', 'dataplugin', + 'dataquery', 'datastorage', 'localization', 'management', diff --git a/dynamicserialize/dstypes/com/raytheon/uf/common/activetable/ActiveTableKey.py b/dynamicserialize/dstypes/com/raytheon/uf/common/activetable/ActiveTableKey.py index 0828fe8..2d81715 100644 --- a/dynamicserialize/dstypes/com/raytheon/uf/common/activetable/ActiveTableKey.py +++ b/dynamicserialize/dstypes/com/raytheon/uf/common/activetable/ActiveTableKey.py @@ -24,6 +24,7 @@ # ------------ ---------- ----------- -------------------------- # 05/22/2015 4522 randerso Initial creation # 03/17/2016 5426 randerso Add issueYear to primary key +# 08/03/2016 19213 ryu Add pil to primary key # ## class ActiveTableKey(object): @@ -35,6 +36,7 @@ class ActiveTableKey(object): self.etn = None self.ugcZone = None self.issueYear = None + self.pil = None def getOfficeid(self): return self.officeid @@ -71,3 +73,9 @@ class ActiveTableKey(object): def setIssueYear(self, issueYear): self.issueYear = issueYear + + def getPil(self): + return self.pil + + def setPil(self, pil): + self.pil = pil diff --git a/dynamicserialize/dstypes/com/raytheon/uf/common/activetable/ActiveTableMode.py b/dynamicserialize/dstypes/com/raytheon/uf/common/activetable/ActiveTableMode.py index 8fbaddb..188405d 100644 --- a/dynamicserialize/dstypes/com/raytheon/uf/common/activetable/ActiveTableMode.py +++ b/dynamicserialize/dstypes/com/raytheon/uf/common/activetable/ActiveTableMode.py @@ -19,10 +19,11 @@ ## # File generated against equivalent DynamicSerialize Java class +# Jul 27, 2016 #5769 randerso Fixed __str__ method class ActiveTableMode(object): def __init__(self): self.value = None def __str__(self): - return repr(self.value) \ No newline at end of file + return str(self.value) diff --git a/dynamicserialize/dstypes/com/raytheon/uf/common/activetable/ActiveTableRecord.py b/dynamicserialize/dstypes/com/raytheon/uf/common/activetable/ActiveTableRecord.py index 9a9684d..3bbd122 100644 --- a/dynamicserialize/dstypes/com/raytheon/uf/common/activetable/ActiveTableRecord.py +++ b/dynamicserialize/dstypes/com/raytheon/uf/common/activetable/ActiveTableRecord.py @@ -24,6 +24,7 @@ # ------------ ---------- ----------- -------------------------- # 05/22/2015 4522 randerso Initial creation (hand generated) # 03/17/2016 5426 randerso Add issueYear to primary key +# 06/27/2016 5707 nabowle Remove geometry # ## @@ -46,7 +47,6 @@ class ActiveTableRecord(with_metaclass(abc.ABCMeta, object)): self.issueTime = None self.purgeTime = None self.ufn = None - self.geometry = None self.forecaster = None self.motdir = None self.motspd = None @@ -177,12 +177,6 @@ class ActiveTableRecord(with_metaclass(abc.ABCMeta, object)): def setUfn(self, ufn): self.ufn = ufn - def getGeometry(self): - return self.geometry - - def setGeometry(self, geometry): - self.geometry = geometry - def getForecaster(self): return self.forecaster diff --git a/dynamicserialize/dstypes/com/raytheon/uf/common/dataaccess/request/AbstractIdentifierRequest.py b/dynamicserialize/dstypes/com/raytheon/uf/common/dataaccess/request/AbstractIdentifierRequest.py index eeca6ca..1dafab2 100644 --- a/dynamicserialize/dstypes/com/raytheon/uf/common/dataaccess/request/AbstractIdentifierRequest.py +++ b/dynamicserialize/dstypes/com/raytheon/uf/common/dataaccess/request/AbstractIdentifierRequest.py @@ -26,6 +26,8 @@ # Date Ticket# Engineer Description # ------------ ---------- ----------- -------------------------- # 07/23/14 #3185 njensen Initial Creation. +# Jun 01, 2016 5587 tgurney Change self.datatype to +# self.request # # @@ -34,11 +36,11 @@ from six import with_metaclass class AbstractIdentifierRequest(with_metaclass(abc.ABCMeta, object)): def __init__(self): - self.datatype = None + self.request = None - def getDatatype(self): - return self.datatype + def getRequest(self): + return self.request - def setDatatype(self, datatype): - self.datatype = datatype + def setRequest(self, request): + self.request = request diff --git a/dynamicserialize/dstypes/com/raytheon/uf/common/dataaccess/request/GetIdentifierValuesRequest.py b/dynamicserialize/dstypes/com/raytheon/uf/common/dataaccess/request/GetIdentifierValuesRequest.py new file mode 100644 index 0000000..0669307 --- /dev/null +++ b/dynamicserialize/dstypes/com/raytheon/uf/common/dataaccess/request/GetIdentifierValuesRequest.py @@ -0,0 +1,45 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +# File auto-generated against equivalent DynamicSerialize Java class +# and then modified post-generation to make it subclass +# AbstractDataAccessRequest. +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 04/15/2016 5379 tgurney Initial creation +# +# + +from dynamicserialize.dstypes.com.raytheon.uf.common.dataaccess.request import AbstractDataAccessRequest + +class GetIdentifierValuesRequest(AbstractDataAccessRequest): + + def __init__(self): + super(GetIdentifierValuesRequest, self).__init__() + self.identifierKey = None + + def getIdentifierKey(self): + return self.identifierKey + + def setIdentifierKey(self, identifierKey): + self.identifierKey = identifierKey diff --git a/dynamicserialize/dstypes/com/raytheon/uf/common/dataaccess/request/__init__.py b/dynamicserialize/dstypes/com/raytheon/uf/common/dataaccess/request/__init__.py index f85be8b..ec9f8ec 100644 --- a/dynamicserialize/dstypes/com/raytheon/uf/common/dataaccess/request/__init__.py +++ b/dynamicserialize/dstypes/com/raytheon/uf/common/dataaccess/request/__init__.py @@ -31,7 +31,8 @@ __all__ = [ 'GetGridDataRequest', 'GetRequiredIdentifiersRequest', 'GetSupportedDatatypesRequest', - 'GetOptionalIdentifiersRequest' + 'GetOptionalIdentifiersRequest', + 'GetIdentifierValuesRequest' ] from .AbstractDataAccessRequest import AbstractDataAccessRequest @@ -45,4 +46,4 @@ from .GetGridDataRequest import GetGridDataRequest from .GetRequiredIdentifiersRequest import GetRequiredIdentifiersRequest from .GetSupportedDatatypesRequest import GetSupportedDatatypesRequest from .GetOptionalIdentifiersRequest import GetOptionalIdentifiersRequest - +from .GetIdentifierValuesRequest import GetIdentifierValuesRequest diff --git a/dynamicserialize/dstypes/com/raytheon/uf/common/dataquery/__init__.py b/dynamicserialize/dstypes/com/raytheon/uf/common/dataquery/__init__.py new file mode 100644 index 0000000..10183a3 --- /dev/null +++ b/dynamicserialize/dstypes/com/raytheon/uf/common/dataquery/__init__.py @@ -0,0 +1,27 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +# File auto-generated by PythonFileGenerator + +__all__ = [ + 'requests' + ] + + diff --git a/dynamicserialize/dstypes/com/raytheon/uf/common/dataquery/requests/RequestConstraint.py b/dynamicserialize/dstypes/com/raytheon/uf/common/dataquery/requests/RequestConstraint.py new file mode 100644 index 0000000..d2e282f --- /dev/null +++ b/dynamicserialize/dstypes/com/raytheon/uf/common/dataquery/requests/RequestConstraint.py @@ -0,0 +1,124 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# Jun 01, 2016 5574 tgurney Initial creation +# +# + +class RequestConstraint(object): + + def __init__(self): + self.constraintValue = None + self.constraintType = None + + def getConstraintValue(self): + return self.constraintValue + + def setConstraintValue(self, constraintValue): + self.constraintValue = constraintValue + + def getConstraintType(self): + return self.constraintType + + def setConstraintType(self, constraintType): + self.constraintType = constraintType + + # DAF-specific stuff begins here ########################################## + + CONSTRAINT_MAP = {'=': 'EQUALS', + '!=': 'NOT_EQUALS', + '>': 'GREATER_THAN', + '>=': 'GREATER_THAN_EQUALS', + '<': 'LESS_THAN', + '<=': 'LESS_THAN_EQUALS', + 'IN': 'IN', + #'NOT IN': 'NOT_IN' + } + + @staticmethod + def _stringify(value): + if type(value) in {str, int, long, bool, float, unicode}: + return str(value) + else: + # Collections are not allowed; they are handled separately. + # Arbitrary objects are not allowed because the string + # representation may not be sufficient to reconstruct the object. + raise TypeError('Constraint values of type ' + repr(type(value)) + + 'are not allowed') + + @classmethod + def _construct_in(cls, constraintType, constraintValue): + """Build a new "IN" constraint from an iterable.""" + try: + iterator = iter(constraintValue) + except TypeError: + raise TypeError("value for IN constraint must be an iterable") + stringValue = ', '.join(cls._stringify(item) for item in iterator) + if len(stringValue) == 0: + raise ValueError('cannot use IN with empty collection') + obj = cls() + obj.setConstraintType(constraintType) + obj.setConstraintValue(stringValue) + return obj + + @classmethod + def _construct_eq_not_eq(cls, constraintType, constraintValue): + """Build a new = or != constraint. Handle None specially by making an + "is null" or "is not null" instead. + """ + obj = cls() + if constraintValue is None: + if constraintType == 'EQUALS': + obj.setConstraintType('ISNULL') + elif constraintType == 'NOT_EQUALS': + obj.setConstraintType('ISNOTNULL') + else: + obj = cls._construct(constraintType, constraintValue) + return obj + + @classmethod + def _construct(cls, constraintType, constraintValue): + """Build a new constraint.""" + stringValue = cls._stringify(constraintValue) + obj = cls() + obj.setConstraintType(constraintType) + obj.setConstraintValue(stringValue) + return obj + + @classmethod + def new(cls, operator, constraintValue): + """Build a new RequestConstraint.""" + try: + constraintType = cls.CONSTRAINT_MAP[operator.upper()] + except KeyError, AttributeError: + errmsg = '{} is not a valid operator. Valid operators are: {}' + validOperators = list(sorted(cls.CONSTRAINT_MAP.keys())) + raise ValueError(errmsg.format(operator, validOperators)) + if constraintType == 'IN': + return cls._construct_in(constraintType, constraintValue) + elif constraintType in {'EQUALS', 'NOT_EQUALS'}: + return cls._construct_eq_not_eq(constraintType, constraintValue) + else: + return cls._construct(constraintType, constraintValue) diff --git a/dynamicserialize/dstypes/com/raytheon/uf/common/dataquery/requests/__init__.py b/dynamicserialize/dstypes/com/raytheon/uf/common/dataquery/requests/__init__.py new file mode 100644 index 0000000..b66872c --- /dev/null +++ b/dynamicserialize/dstypes/com/raytheon/uf/common/dataquery/requests/__init__.py @@ -0,0 +1,28 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## + +# File auto-generated by PythonFileGenerator + +__all__ = [ + 'RequestConstraint' + ] + +from RequestConstraint import RequestConstraint + diff --git a/dynamicserialize/dstypes/com/raytheon/uf/common/pypies/request/CopyRequest.py b/dynamicserialize/dstypes/com/raytheon/uf/common/pypies/request/CopyRequest.py index f89c669..ecb92ab 100644 --- a/dynamicserialize/dstypes/com/raytheon/uf/common/pypies/request/CopyRequest.py +++ b/dynamicserialize/dstypes/com/raytheon/uf/common/pypies/request/CopyRequest.py @@ -26,7 +26,6 @@ class CopyRequest(object): self.repack = None self.repackCompression = None self.outputDir = None - self.timestampCheck = None self.minMillisSinceLastChange = None self.maxMillisSinceLastChange = None self.filename = None @@ -49,12 +48,6 @@ class CopyRequest(object): def setOutputDir(self, outputDir): self.outputDir = outputDir - def getTimestampCheck(self): - return self.timestampCheck - - def setTimestampCheck(self, timestampCheck): - self.timestampCheck = timestampCheck - def getMinMillisSinceLastChange(self): return self.minMillisSinceLastChange diff --git a/dynamicserialize/dstypes/com/raytheon/uf/common/pypies/request/DeleteOrphansRequest.py b/dynamicserialize/dstypes/com/raytheon/uf/common/pypies/request/DeleteOrphansRequest.py index 13f2e5e..bad350c 100644 --- a/dynamicserialize/dstypes/com/raytheon/uf/common/pypies/request/DeleteOrphansRequest.py +++ b/dynamicserialize/dstypes/com/raytheon/uf/common/pypies/request/DeleteOrphansRequest.py @@ -19,21 +19,29 @@ ## # File auto-generated against equivalent DynamicSerialize Java class +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# Jul 27, 2015 1574 nabowle Generated +# Feb 23, 2016 5389 nabowle Regenerated class DeleteOrphansRequest(object): def __init__(self): + self.oldestDateMap = None self.filename = None - self.oldestDate = None - def getOldestDate(self): - return self.oldestDate + def getOldestDateMap(self): + return self.oldestDateMap - def setOldestDate(self, oldestDate): - self.oldestDate = oldestDate + def setOldestDateMap(self, oldestDateMap): + self.oldestDateMap = oldestDateMap def getFilename(self): return self.filename def setFilename(self, filename): self.filename = filename + diff --git a/dynamicserialize/dstypes/com/raytheon/uf/common/time/CommutativeTimestamp.py b/dynamicserialize/dstypes/com/raytheon/uf/common/time/CommutativeTimestamp.py new file mode 100644 index 0000000..c11e3ac --- /dev/null +++ b/dynamicserialize/dstypes/com/raytheon/uf/common/time/CommutativeTimestamp.py @@ -0,0 +1,37 @@ +## +# This software was developed and / or modified by Raytheon Company, +# pursuant to Contract DG133W-05-CQ-1067 with the US Government. +# +# U.S. EXPORT CONTROLLED TECHNICAL DATA +# This software product contains export-restricted data whose +# export/transfer/disclosure is restricted by U.S. law. Dissemination +# to non-U.S. persons whether in the United States or abroad requires +# an export license or other authorization. +# +# Contractor Name: Raytheon Company +# Contractor Address: 6825 Pine Street, Suite 340 +# Mail Stop B8 +# Omaha, NE 68106 +# 402.291.0100 +# +# See the AWIPS II Master Rights File ("Master Rights File.pdf") for +# further licensing information. +## +# ---------------------------------------------------------------------------- +# +# SOFTWARE HISTORY +# +# Date Ticket# Engineer Description +# ------------ ---------- ----------- -------------------------- +# 06/23/2016 #5696 rjpeter Initial creation. +# +## + +from time import gmtime, strftime +from dynamicserialize.dstypes.java.sql import Timestamp + +class CommutativeTimestamp(Timestamp): + + def __init__(self, timeInMillis=None): + super(CommutativeTimestamp, self).__init__(timeInMillis) + diff --git a/dynamicserialize/dstypes/com/raytheon/uf/common/time/FormattedDate.py b/dynamicserialize/dstypes/com/raytheon/uf/common/time/FormattedDate.py index aa082e2..25ba789 100644 --- a/dynamicserialize/dstypes/com/raytheon/uf/common/time/FormattedDate.py +++ b/dynamicserialize/dstypes/com/raytheon/uf/common/time/FormattedDate.py @@ -24,16 +24,13 @@ # Date Ticket# Engineer Description # ------------ ---------- ----------- -------------------------- # 09/21/2015 4486 rjpeter Initial creation. -# +# 06/23/2016 #5696 rjpeter Extend CommutativeTimestamp ## -from time import gmtime, strftime -from dynamicserialize.dstypes.java.util import Date +from CommutativeTimestamp import CommutativeTimestamp -class FormattedDate(Date): +# TODO: Remove after 16.4.1 no longer in field +class FormattedDate(CommutativeTimestamp): def __init__(self, timeInMillis=None): super(FormattedDate, self).__init__(timeInMillis) - - def __repr__(self): - return strftime("%Y-%m-%d %H:%M:%S.", gmtime(self.time/1000.0)) + '{:03d}'.format(self.time%1000) diff --git a/dynamicserialize/dstypes/com/raytheon/uf/common/time/__init__.py b/dynamicserialize/dstypes/com/raytheon/uf/common/time/__init__.py index 534b6c4..2921b6f 100644 --- a/dynamicserialize/dstypes/com/raytheon/uf/common/time/__init__.py +++ b/dynamicserialize/dstypes/com/raytheon/uf/common/time/__init__.py @@ -23,10 +23,11 @@ __all__ = [ 'DataTime', 'TimeRange', - 'FormattedDate' + 'FormattedDate', + 'CommutativeTimestamp' ] from .DataTime import DataTime from .TimeRange import TimeRange from .FormattedDate import FormattedDate - +from .CommutativeTimestamp import CommutativeTimestamp diff --git a/dynamicserialize/dstypes/gov/noaa/nws/ncep/common/dataplugin/pgen/request/RetrieveActivityMapRequest.py b/dynamicserialize/dstypes/gov/noaa/nws/ncep/common/dataplugin/pgen/request/RetrieveActivityMapRequest.py index 0c34127..1139684 100644 --- a/dynamicserialize/dstypes/gov/noaa/nws/ncep/common/dataplugin/pgen/request/RetrieveActivityMapRequest.py +++ b/dynamicserialize/dstypes/gov/noaa/nws/ncep/common/dataplugin/pgen/request/RetrieveActivityMapRequest.py @@ -1,8 +1,8 @@ # File auto-generated against equivalent DynamicSerialize Java class -# +# # SOFTWARE HISTORY -# + # Date Ticket# Engineer Description # ------------ ---------- ----------- -------------------------- # May 05, 2016 root Generated diff --git a/dynamicserialize/dstypes/gov/noaa/nws/ncep/common/dataplugin/pgen/response/ActivityMapData.py b/dynamicserialize/dstypes/gov/noaa/nws/ncep/common/dataplugin/pgen/response/ActivityMapData.py index 97b9a3c..1fd4902 100644 --- a/dynamicserialize/dstypes/gov/noaa/nws/ncep/common/dataplugin/pgen/response/ActivityMapData.py +++ b/dynamicserialize/dstypes/gov/noaa/nws/ncep/common/dataplugin/pgen/response/ActivityMapData.py @@ -1,8 +1,8 @@ # File auto-generated against equivalent DynamicSerialize Java class -# +# # SOFTWARE HISTORY -# +# # Date Ticket# Engineer Description # ------------ ---------- ----------- -------------------------- # May 06, 2016 root Generated diff --git a/dynamicserialize/dstypes/gov/noaa/nws/ncep/common/dataplugin/pgen/response/RetrieveActivityMapResponse.py b/dynamicserialize/dstypes/gov/noaa/nws/ncep/common/dataplugin/pgen/response/RetrieveActivityMapResponse.py index f9111ee..bb72063 100644 --- a/dynamicserialize/dstypes/gov/noaa/nws/ncep/common/dataplugin/pgen/response/RetrieveActivityMapResponse.py +++ b/dynamicserialize/dstypes/gov/noaa/nws/ncep/common/dataplugin/pgen/response/RetrieveActivityMapResponse.py @@ -1,8 +1,8 @@ # File auto-generated against equivalent DynamicSerialize Java class -# +# # SOFTWARE HISTORY -# +# # Date Ticket# Engineer Description # ------------ ---------- ----------- -------------------------- # May 06, 2016 root Generated diff --git a/dynamicserialize/dstypes/java/sql/Timestamp.py b/dynamicserialize/dstypes/java/sql/Timestamp.py index 0bf23bf..2426b8f 100644 --- a/dynamicserialize/dstypes/java/sql/Timestamp.py +++ b/dynamicserialize/dstypes/java/sql/Timestamp.py @@ -20,20 +20,24 @@ # File auto-generated against equivalent DynamicSerialize Java class # and then modified post-generation to add additional features to better -# match Java implementation. +# match Java implementation. Unlike real timestamp, does not support nanos precision. # # SOFTWARE HISTORY # # Date Ticket# Engineer Description # ------------ ---------- ----------- -------------------------- # ??/??/?? xxxxxxxx Initial Creation. -# 06/24/15 4480 dgilling implement based on Date class. +# 06/24/15 4480 dgilling implement based on Date class. +# Jun 23, 2016 5696 rjpeter Make String version match java. # from dynamicserialize.dstypes.java.util import Date - +from time import gmtime, strftime class Timestamp(Date): def __init__(self, time=None): super(Timestamp, self).__init__(time) + + def __repr__(self): + return strftime("%Y-%m-%d %H:%M:%S.", gmtime(self.time/1000.0)) + '{:03d}'.format(self.time%1000) diff --git a/setup.py b/setup.py index d03dad6..3c1fb1c 100644 --- a/setup.py +++ b/setup.py @@ -3,12 +3,12 @@ from setuptools import find_packages setup( name='python-awips', - version='0.9.7', + version='0.9.8', description='A framework for requesting AWIPS meteorological datasets from an EDEX server', packages=find_packages(exclude='data'), license='Open Source', - url='http://www.unidata.ucar.edu/software/awips2', - download_url='https://github.com/Unidata/python-awips/tarball/0.9.7', + url='http://python-awips.readthedocs.io', + download_url='https://github.com/Unidata/python-awips/tarball/0.9.8', author='Unidata', author_email='mjames@ucar.edu', requires=['argparse','shapely','numpy','six']