| # Licensed to the Apache Software Foundation (ASF) under one or more |
| # contributor license agreements. See the NOTICE file distributed with |
| # this work for additional information regarding copyright ownership. |
| # The ASF licenses this file to You under the Apache License, Version 2.0 |
| # (the "License"); you may not use this file except in compliance with |
| # the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| |
| import json |
| import unittest |
| import urllib.request, urllib.parse, urllib.error |
| #from multiprocessing.pool import ThreadPool |
| from unittest import skip |
| |
| import numpy as np |
| from mock import Mock |
| from nexustiles.model.nexusmodel import Tile, BBox |
| from nexustiles.nexustiles import NexusTileService |
| from tornado.testing import AsyncHTTPTestCase, bind_unused_port |
| import tornado.web |
| |
| from webservice.algorithms import StandardDeviationSearch |
| from webservice.nexus_tornado.request.handlers.NexusRequestHandler import NexusRequestHandler |
| |
| |
| class HttpParametersTest(AsyncHTTPTestCase): |
| def get_app(self): |
| path = StandardDeviationSearch.StandardDeviationSearchCalcHandlerImpl.path |
| algorithm = StandardDeviationSearch.StandardDeviationSearchCalcHandlerImpl |
| thread_pool = tornado.concurrent.futures.ThreadPoolExecutor(1) |
| #thread_pool = ThreadPool(processes=1) |
| return tornado.web.Application( |
| [(path, NexusRequestHandler, dict(clazz=algorithm, thread_pool=thread_pool))], |
| default_host=bind_unused_port() |
| ) |
| |
| def test_no_ds_400(self): |
| response = self.fetch(StandardDeviationSearch.StandardDeviationSearchCalcHandlerImpl.path) |
| self.assertEqual(400, response.code) |
| body = json.loads(response.body) |
| self.assertEqual("'ds' argument is required", body['error']) |
| |
| def test_no_longitude_400(self): |
| params = { |
| "ds": "dataset" |
| } |
| path = StandardDeviationSearch.StandardDeviationSearchCalcHandlerImpl.path + '?' + urllib.parse.urlencode(params) |
| response = self.fetch(path) |
| self.assertEqual(400, response.code) |
| body = json.loads(response.body) |
| self.assertEqual("'longitude' argument is required", body['error']) |
| |
| def test_no_latitude_400(self): |
| params = { |
| "ds": "dataset", |
| "longitude": "22.4" |
| } |
| path = StandardDeviationSearch.StandardDeviationSearchCalcHandlerImpl.path + '?' + urllib.parse.urlencode(params) |
| response = self.fetch(path) |
| self.assertEqual(400, response.code) |
| body = json.loads(response.body) |
| self.assertEqual("'latitude' argument is required", body['error']) |
| |
| def test_no_day_or_date_400(self): |
| params = { |
| "ds": "dataset", |
| "longitude": "22.4", |
| "latitude": "-84.32" |
| } |
| path = StandardDeviationSearch.StandardDeviationSearchCalcHandlerImpl.path + '?' + urllib.parse.urlencode(params) |
| response = self.fetch(path) |
| self.assertEqual(400, response.code) |
| body = json.loads(response.body) |
| self.assertEqual("At least one of 'day' or 'date' arguments are required but not both.", body['error']) |
| |
| def test_no_day_not_int_400(self): |
| params = { |
| "ds": "dataset", |
| "longitude": "22.4", |
| "latitude": "-84.32", |
| "day": "yayday" |
| } |
| path = StandardDeviationSearch.StandardDeviationSearchCalcHandlerImpl.path + '?' + urllib.parse.urlencode(params) |
| response = self.fetch(path) |
| self.assertEqual(400, response.code) |
| body = json.loads(response.body) |
| self.assertEqual("At least one of 'day' or 'date' arguments are required but not both.", body['error']) |
| |
| def test_day_and_date_400(self): |
| params = { |
| "ds": "dataset", |
| "longitude": "22.4", |
| "latitude": "-84.32", |
| "day": "35", |
| "date": "1992-01-01T00:00:00Z" |
| } |
| path = StandardDeviationSearch.StandardDeviationSearchCalcHandlerImpl.path + '?' + urllib.parse.urlencode(params) |
| response = self.fetch(path) |
| self.assertEqual(400, response.code) |
| body = json.loads(response.body) |
| self.assertEqual("At least one of 'day' or 'date' arguments are required but not both.", body['error']) |
| |
| def test_no_allInTile_200(self): |
| params = { |
| "ds": "dataset", |
| "longitude": "22.4", |
| "latitude": "-84.32", |
| "day": "35" |
| } |
| path = StandardDeviationSearch.StandardDeviationSearchCalcHandlerImpl.path + '?' + urllib.parse.urlencode(params) |
| response = self.fetch(path) |
| self.assertEqual(200, response.code) |
| |
| def test_allInTile_false_200(self): |
| params = { |
| "ds": "dataset", |
| "longitude": "22.4", |
| "latitude": "-84.32", |
| "date": "1992-01-01T00:00:00Z", |
| "allInTile": "false" |
| } |
| path = StandardDeviationSearch.StandardDeviationSearchCalcHandlerImpl.path + '?' + urllib.parse.urlencode(params) |
| response = self.fetch(path) |
| self.assertEqual(200, response.code) |
| |
| @skip("Integration test only. Works only if you have Solr and Cassandra running locally with data ingested") |
| def test_integration_all_in_tile(self): |
| params = { |
| "ds": "AVHRR_OI_L4_GHRSST_NCEI_CLIM", |
| "longitude": "-177.775", |
| "latitude": "-78.225", |
| "day": "1" |
| } |
| path = StandardDeviationSearch.StandardDeviationSearchCalcHandlerImpl.path + '?' + urllib.parse.urlencode(params) |
| response = self.fetch(path) |
| self.assertEqual(200, response.code) |
| print(response.body) |
| body = json.loads(response.body) |
| self.assertEqual(560, len(body['data'])) |
| |
| @skip("Integration test only. Works only if you have Solr and Cassandra running locally with data ingested") |
| def test_integration_all_in_tile_false(self): |
| params = { |
| "ds": "AVHRR_OI_L4_GHRSST_NCEI_CLIM", |
| "longitude": "-177.875", |
| "latitude": "-78.125", |
| "date": "2016-01-01T00:00:00Z", |
| "allInTile": "false" |
| } |
| path = StandardDeviationSearch.StandardDeviationSearchCalcHandlerImpl.path + '?' + urllib.parse.urlencode(params) |
| # Increase timeouts when debugging |
| # self.http_client.fetch(self.get_url(path), self.stop, connect_timeout=99999999, request_timeout=999999999) |
| # response = self.wait(timeout=9999999999) |
| response = self.fetch(path) |
| self.assertEqual(200, response.code) |
| print(response.body) |
| body = json.loads(response.body) |
| self.assertAlmostEqual(-177.875, body['data'][0]['longitude'], 3) |
| self.assertAlmostEqual(-78.125, body['data'][0]['latitude'], 3) |
| self.assertAlmostEqual(0.4956, body['data'][0]['standard_deviation'], 4) |
| |
| |
| class TestStandardDeviationSearch(unittest.TestCase): |
| def setUp(self): |
| tile = Tile() |
| tile.bbox = BBox(-1.0, 1.0, -2.0, 2.0) |
| tile.latitudes = np.ma.array([-1.0, -0.5, 0, .5, 1.0]) |
| tile.longitudes = np.ma.array([-2.0, -1.0, 0, 1.0, 2.0]) |
| tile.times = np.ma.array([0]) |
| tile.data = np.ma.arange(25.0).reshape((1, 5, 5)) |
| tile.meta_data = {"std": np.ma.arange(25.0).reshape((1, 5, 5))} |
| |
| attrs = {'find_tile_by_polygon_and_most_recent_day_of_year.return_value': [tile]} |
| self.tile_service = Mock(spec=NexusTileService, **attrs) |
| |
| def test_get_single_exact_std_dev(self): |
| result = StandardDeviationSearch.get_single_std_dev(self.tile_service, "fake dataset", 1.0, .5, 83) |
| self.assertEqual(1, len(result)) |
| self.assertEqual((1.0, 0.5, 18.0), result[0]) |
| |
| def test_get_single_close_std_dev(self): |
| result = StandardDeviationSearch.get_single_std_dev(self.tile_service, "fake dataset", 1.3, .25, 83) |
| self.assertEqual(1, len(result)) |
| self.assertEqual((1.0, 0.0, 13.0), result[0]) |
| |
| def test_get_all_std_dev(self): |
| result = StandardDeviationSearch.get_all_std_dev(self.tile_service, "fake dataset", 1.3, .25, 83) |
| self.assertEqual(25, len(result)) |
| |
| |
| @skip("Integration test only. Works only if you have Solr and Cassandra running locally with data ingested") |
| class IntegrationTestStandardDeviationSearch(unittest.TestCase): |
| def setUp(self): |
| self.tile_service = NexusTileService() |
| |
| def test_get_single_exact_std_dev(self): |
| result = StandardDeviationSearch.get_single_std_dev(self.tile_service, "AVHRR_OI_L4_GHRSST_NCEI_CLIM", -177.625, |
| -78.375, 1) |
| self.assertEqual(1, len(result)) |
| self.assertAlmostEqual(-177.625, result[0][0], 3) |
| self.assertAlmostEqual(-78.375, result[0][1], 3) |
| self.assertAlmostEqual(0.5166, result[0][2], 4) |
| |
| def test_get_single_close_std_dev(self): |
| result = StandardDeviationSearch.get_single_std_dev(self.tile_service, "AVHRR_OI_L4_GHRSST_NCEI_CLIM", -177.775, |
| -78.225, 1) |
| self.assertEqual(1, len(result)) |
| self.assertAlmostEqual(-177.875, result[0][0], 3) |
| self.assertAlmostEqual(-78.125, result[0][1], 3) |
| self.assertAlmostEqual(0.4956, result[0][2], 4) |
| |
| def test_get_all_std_dev(self): |
| result = StandardDeviationSearch.get_all_std_dev(self.tile_service, "AVHRR_OI_L4_GHRSST_NCEI_CLIM", -177.775, |
| -78.225, 1) |
| |
| self.assertEqual(560, len(result)) |