[test] add test cases for download_extent
Browse files- src/utilities/utilities.py +37 -0
- tests/events/geotiff/10/553/394.tif +0 -0
- tests/events/geotiff/10/553/395.tif +0 -0
- tests/events/geotiff/10/553/396.tif +0 -0
- tests/events/geotiff/10/554/394.tif +0 -0
- tests/events/geotiff/10/554/395.tif +0 -0
- tests/events/geotiff/10/554/396.tif +0 -0
- tests/events/geotiff/10/555/394.tif +0 -0
- tests/events/geotiff/10/555/395.tif +0 -0
- tests/events/geotiff/10/555/396.tif +0 -0
- tests/io/test_tms2geotiff.py +99 -0
src/utilities/utilities.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
| 1 |
"""Various utilities (logger, time benchmark, args dump, numerical and stats info)"""
|
|
|
|
|
|
|
| 2 |
|
| 3 |
|
| 4 |
def _prepare_base64_input(sb):
|
|
@@ -52,3 +54,38 @@ def base64_encode(sb: str or bytes) -> bytes:
|
|
| 52 |
|
| 53 |
sb_bytes = _prepare_base64_input(sb)
|
| 54 |
return base64.b64encode(sb_bytes)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
"""Various utilities (logger, time benchmark, args dump, numerical and stats info)"""
|
| 2 |
+
from src import app_logger
|
| 3 |
+
from src.utilities.serialize import serialize
|
| 4 |
|
| 5 |
|
| 6 |
def _prepare_base64_input(sb):
|
|
|
|
| 54 |
|
| 55 |
sb_bytes = _prepare_base64_input(sb)
|
| 56 |
return base64.b64encode(sb_bytes)
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def hash_calculate(arr: any) -> str or bytes:
|
| 60 |
+
"""
|
| 61 |
+
Return computed hash from input variable (typically a numpy array).
|
| 62 |
+
|
| 63 |
+
Args:
|
| 64 |
+
arr: input variable
|
| 65 |
+
|
| 66 |
+
Returns:
|
| 67 |
+
str or bytes: computed hash from input variable
|
| 68 |
+
"""
|
| 69 |
+
import hashlib
|
| 70 |
+
import numpy as np
|
| 71 |
+
from base64 import b64encode
|
| 72 |
+
|
| 73 |
+
if isinstance(arr, np.ndarray):
|
| 74 |
+
hash_fn = hashlib.sha256(arr.data)
|
| 75 |
+
elif isinstance(arr, dict):
|
| 76 |
+
import json
|
| 77 |
+
|
| 78 |
+
serialized = serialize(arr)
|
| 79 |
+
variable_to_hash = json.dumps(serialized, sort_keys=True).encode('utf-8')
|
| 80 |
+
hash_fn = hashlib.sha256(variable_to_hash)
|
| 81 |
+
elif isinstance(arr, str):
|
| 82 |
+
try:
|
| 83 |
+
hash_fn = hashlib.sha256(arr)
|
| 84 |
+
except TypeError:
|
| 85 |
+
app_logger.warning(f"TypeError, re-try encoding arg:{arr},type:{type(arr)}.")
|
| 86 |
+
hash_fn = hashlib.sha256(arr.encode('utf-8'))
|
| 87 |
+
elif isinstance(arr, bytes):
|
| 88 |
+
hash_fn = hashlib.sha256(arr)
|
| 89 |
+
else:
|
| 90 |
+
raise ValueError(f"variable 'arr':{arr} not yet handled.")
|
| 91 |
+
return b64encode(hash_fn.digest())
|
tests/events/geotiff/10/553/394.tif
ADDED
|
|
tests/events/geotiff/10/553/395.tif
ADDED
|
|
tests/events/geotiff/10/553/396.tif
ADDED
|
|
tests/events/geotiff/10/554/394.tif
ADDED
|
|
tests/events/geotiff/10/554/395.tif
ADDED
|
|
tests/events/geotiff/10/554/396.tif
ADDED
|
|
tests/events/geotiff/10/555/394.tif
ADDED
|
|
tests/events/geotiff/10/555/395.tif
ADDED
|
|
tests/events/geotiff/10/555/396.tif
ADDED
|
|
tests/io/test_tms2geotiff.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import unittest
|
| 2 |
+
|
| 3 |
+
import numpy as np
|
| 4 |
+
|
| 5 |
+
from src import app_logger
|
| 6 |
+
from src.io.tms2geotiff import download_extent
|
| 7 |
+
from src.utilities.utilities import hash_calculate
|
| 8 |
+
from tests import TEST_EVENTS_FOLDER
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
tile_source_url = "http://localhost:8000/geotiff/{z}/{x}/{y}.tif"
|
| 12 |
+
input_bbox = [[38.03932961278458, 15.36808069832851], [37.455509218936974, 14.632807441554068]]
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
class TestTms2geotiff(unittest.TestCase):
|
| 16 |
+
from contextlib import contextmanager
|
| 17 |
+
|
| 18 |
+
@staticmethod
|
| 19 |
+
@contextmanager
|
| 20 |
+
def http_server(host: str, port: int, directory: str):
|
| 21 |
+
"""Function http_server defined within this test class to avoid pytest error "fixture 'host' not found"."""
|
| 22 |
+
from functools import partial
|
| 23 |
+
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
|
| 24 |
+
from threading import Thread
|
| 25 |
+
|
| 26 |
+
server = ThreadingHTTPServer(
|
| 27 |
+
(host, port), partial(SimpleHTTPRequestHandler, directory=directory)
|
| 28 |
+
)
|
| 29 |
+
server_thread = Thread(target=server.serve_forever, name="http_server")
|
| 30 |
+
server_thread.start()
|
| 31 |
+
print(f"listen:: host {host}, port {port}.")
|
| 32 |
+
|
| 33 |
+
try:
|
| 34 |
+
yield
|
| 35 |
+
finally:
|
| 36 |
+
server.shutdown()
|
| 37 |
+
server_thread.join()
|
| 38 |
+
|
| 39 |
+
def test_download_extent(self):
|
| 40 |
+
listen_port = 8000
|
| 41 |
+
|
| 42 |
+
with self.http_server("localhost", listen_port, directory=TEST_EVENTS_FOLDER):
|
| 43 |
+
pt0, pt1 = input_bbox
|
| 44 |
+
zoom = 10
|
| 45 |
+
img, matrix = download_extent(
|
| 46 |
+
source=tile_source_url, lat0=pt0[0], lon0=pt0[1], lat1=pt1[0], lon1=pt1[1], zoom=zoom
|
| 47 |
+
)
|
| 48 |
+
app_logger.info("# DOWNLOAD ENDED! #")
|
| 49 |
+
np_img = np.array(img)
|
| 50 |
+
output_hash = hash_calculate(np_img)
|
| 51 |
+
assert output_hash == b'LJNhEuMMp2nRclFJfF6oM3iMVbnZnWDmZqWzrs3T4Hs='
|
| 52 |
+
|
| 53 |
+
def test_download_extent_io_error1(self):
|
| 54 |
+
|
| 55 |
+
with self.assertRaises(IOError):
|
| 56 |
+
try:
|
| 57 |
+
pt0, pt1 = input_bbox
|
| 58 |
+
zoom = 10
|
| 59 |
+
download_extent(
|
| 60 |
+
source=tile_source_url, lat0=pt0[0], lon0=pt0[1], lat1=pt1[0], lon1=pt1[1], zoom=zoom
|
| 61 |
+
)
|
| 62 |
+
except IOError as ioe1:
|
| 63 |
+
app_logger.error(f"ioe1:{ioe1}.")
|
| 64 |
+
msg0 = "HTTPConnectionPool(host='localhost', port=8000): Max retries exceeded with url: /geotiff/"
|
| 65 |
+
msg1 = "Caused by NewConnectionError"
|
| 66 |
+
msg2 = ": Failed to establish a new connection: [Errno 61] Connection refused'))"
|
| 67 |
+
assert msg0 in str(ioe1)
|
| 68 |
+
assert msg1 in str(ioe1)
|
| 69 |
+
assert msg2 in str(ioe1)
|
| 70 |
+
raise ioe1
|
| 71 |
+
|
| 72 |
+
def test_download_extent_io_error2(self):
|
| 73 |
+
listen_port = 8000
|
| 74 |
+
with self.http_server("localhost", listen_port, directory=TEST_EVENTS_FOLDER):
|
| 75 |
+
pt0, pt1 = input_bbox
|
| 76 |
+
zoom = 10
|
| 77 |
+
|
| 78 |
+
with self.assertRaises(AttributeError):
|
| 79 |
+
try:
|
| 80 |
+
download_extent(
|
| 81 |
+
source=tile_source_url + "_not_found_raster!",
|
| 82 |
+
lat0=pt0[0], lon0=pt0[1], lat1=pt1[0], lon1=pt1[1], zoom=zoom
|
| 83 |
+
)
|
| 84 |
+
except AttributeError as ae:
|
| 85 |
+
app_logger.error(f"ae:{ae}.")
|
| 86 |
+
assert str(ae) == "'NoneType' object has no attribute 'crop'"
|
| 87 |
+
raise ae
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
if __name__ == '__main__':
|
| 91 |
+
from tests import TEST_ROOT_FOLDER
|
| 92 |
+
|
| 93 |
+
main_listen_port = 8000
|
| 94 |
+
print("http_basedir_serve:", TEST_ROOT_FOLDER, "#")
|
| 95 |
+
with TestTms2geotiff.http_server("127.0.0.1", main_listen_port, directory=TEST_ROOT_FOLDER):
|
| 96 |
+
pass
|
| 97 |
+
# import time
|
| 98 |
+
# time.sleep(10)
|
| 99 |
+
print("Http server stopped.")
|