[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.")
|