"""A TestCase that initializes the library with standard API methods.""" from collections.abc import Iterable import contextlib import copy import json import os from typing import Any, Optional from googleapiclient import discovery import unittest import ee from ee import _cloud_api_utils from ee import _state # Cached algorithms list _algorithms_cache: Optional[dict[str, Any]] = None def GetAlgorithms() -> dict[str, Any]: """Returns a static version of the ListAlgorithms call. After ApiTestCase.setUp is called, ee.data.getAlgorithms() is patched to use this data. This function may be called explicitly if the test data is needed at a time before the test case has started executing. """ global _algorithms_cache if _algorithms_cache is not None: return _algorithms_cache algorithms_path = os.path.join( os.path.dirname(os.path.realpath(__file__)), "tests/algorithms.json") with open(algorithms_path, encoding='utf-8') as algorithms_file: algorithms = json.load(algorithms_file) _algorithms_cache = _cloud_api_utils.convert_algorithms(algorithms) return _algorithms_cache class ApiTestCase(unittest.TestCase): """A TestCase that initializes the library with standard API methods.""" last_download_call: Optional[Any] last_thumb_call: Optional[Any] last_table_call: Optional[Any] last_mapid_call: Optional[Any] def setUp(self): super().setUp() # Store the state of ee.data before it is overwritten. We need to restore to # this state in tearDown to prevent state leakage between tests. self.old_get_algorithms = ee.data.getAlgorithms self.old_compute_value = ee.data.computeValue self.old_get_map_id = ee.data.getMapId self.old_get_download_id = ee.data.getDownloadId self.old_get_thumb_id = ee.data.getThumbId self.old_get_table_download_id = ee.data.getTableDownloadId # pylint: disable-next=protected-access self.old_fetch_data_catalog_stac = ee.deprecation._FetchDataCatalogStac self.InitializeApi() def tearDown(self): super().tearDown() ee.data.getAlgorithms = self.old_get_algorithms ee.data.computeValue = self.old_compute_value ee.data.getMapId = self.old_get_map_id ee.data.getDownloadId = self.old_get_download_id ee.data.getThumbId = self.old_get_thumb_id ee.data.getTableDownloadId = self.old_get_table_download_id _state.reset_state() # pylint: disable-next=protected-access ee.deprecation._FetchDataCatalogStac = self.old_fetch_data_catalog_stac def InitializeApi(self): """Initializes the library with standard API methods. This is normally invoked during setUp(), but subclasses may invoke it manually instead if they prefer. """ self.last_download_call = None self.last_thumb_call = None self.last_table_call = None self.last_mapid_call = None ee.Reset() ee.data._install_cloud_api_resource = lambda: None # pylint: disable=protected-access ee.data.getAlgorithms = GetAlgorithms ee.data.computeValue = lambda x: {'value': 'fakeValue'} ee.data.getMapId = self._MockMapId ee.data.getDownloadId = self._MockDownloadUrl ee.data.getThumbId = self._MockThumbUrl ee.data.getTableDownloadId = self._MockTableDownload # pylint: disable-next=protected-access ee.deprecation._FetchDataCatalogStac = self._MockFetchDataCatalogStac ee.Initialize(None, '', project='my-project') # We are mocking the url here so the unit tests are happy. def _MockMapId(self, params: dict[str, Any]) -> dict[str, str]: self.last_mapid_call = {'url': '/mapid', 'data': params} return {'mapid': 'fakeMapId', 'token': 'fakeToken'} def _MockDownloadUrl(self, params: dict[str, Any]) -> dict[str, str]: self.last_download_call = {'url': '/download', 'data': params} return {'docid': '1', 'token': '2'} def _MockThumbUrl( self, params: dict[str, Any], # pylint: disable-next=invalid-name thumbType: Optional[str] = None, ) -> dict[str, str]: del thumbType # Unused. # Hang on to the call arguments. self.last_thumb_call = {'url': '/thumb', 'data': params} return {'thumbid': '3', 'token': '4'} def _MockTableDownload(self, params: dict[str, Any]) -> dict[str, str]: self.last_table_call = {'url': '/table', 'data': params} return {'docid': '5', 'token': '6'} def _MockFetchDataCatalogStac(self) -> dict[str, Any]: return {} def _GenerateCloudApiResource(mock_http: Any, raw: Any) -> discovery.Resource: """Returns a Cloud API resource for testing.""" discovery_doc_path = os.path.join( os.path.dirname(os.path.realpath(__file__)), "tests/cloud_api_discovery_document.json") with open(discovery_doc_path) as discovery_doc_file: discovery_doc_str = discovery_doc_file.read() return _cloud_api_utils.build_cloud_resource_from_document( json.loads(discovery_doc_str), http_transport=mock_http, headers_supplier=ee.data._make_request_headers, # pylint: disable=protected-access response_inspector=ee.data._handle_profiling_response, # pylint: disable=protected-access raw=raw, ) @contextlib.contextmanager # pytype: disable=wrong-arg-types def UsingCloudApi( cloud_api_resource: Optional[Any] = None, cloud_api_resource_raw: Optional[Any] = None, mock_http: Optional[Any] = None, ) -> Iterable[Any]: # pytype: disable=wrong-arg-types """Returns a context manager under which the Cloud API is enabled.""" # pylint: disable=protected-access old_state = copy.copy(_state._state) # pylint: enable=protected-access try: if cloud_api_resource is None: cloud_api_resource = _GenerateCloudApiResource(mock_http, False) if cloud_api_resource_raw is None: cloud_api_resource_raw = _GenerateCloudApiResource(mock_http, True) state = _state.get_state() state.cloud_api_resource = cloud_api_resource state.cloud_api_resource_raw = cloud_api_resource_raw state.initialized = True yield finally: # pylint: disable=protected-access _state._state = old_state # pylint: enable=protected-access # A sample of encoded EE API JSON, used by SerializerTest and DeserializerTest. ENCODED_JSON_SAMPLE = { 'type': 'CompoundValue', 'scope': [ ['0', { 'type': 'Invocation', 'functionName': 'Date', 'arguments': { 'value': 1234567890000 } }], ['1', { 'type': 'LineString', 'coordinates': [[1, 2], [3, 4]], 'crs': { 'type': 'name', 'properties': { 'name': 'SR-ORG:6974' } } }], ['2', { 'evenOdd': True, 'type': 'Polygon', 'coordinates': [ [[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[5, 6], [7, 6], [7, 8], [5, 8]], [[1, 1], [2, 1], [2, 2], [1, 2]] ] }], ['3', { 'type': 'Bytes', 'value': 'aGVsbG8=' }], ['4', { 'type': 'Invocation', 'functionName': 'String.cat', 'arguments': { 'string1': 'x', 'string2': 'y' } }], ['5', { 'type': 'Dictionary', 'value': { 'foo': 'bar', 'baz': {'type': 'ValueRef', 'value': '4'} } }], ['6', { 'type': 'Function', 'argumentNames': ['x', 'y'], 'body': {'type': 'ArgumentRef', 'value': 'y'} }], ['7', [ None, True, 5, 7, 3.4, 112233445566778899, 'hello', {'type': 'ValueRef', 'value': '0'}, {'type': 'ValueRef', 'value': '1'}, {'type': 'ValueRef', 'value': '2'}, {'type': 'ValueRef', 'value': '3'}, {'type': 'ValueRef', 'value': '5'}, {'type': 'ValueRef', 'value': '4'}, {'type': 'ValueRef', 'value': '6'} ]] ], 'value': {'type': 'ValueRef', 'value': '7'} } # A sample of encoded EE API JSON for the Cloud API, used by SerializerTest. ENCODED_CLOUD_API_JSON_SAMPLE = { 'values': { '0': { 'arrayValue': { 'values': [ {'constantValue': None}, {'constantValue': True}, {'constantValue': 5}, {'constantValue': 7}, {'constantValue': 3.4}, {'integerValue': '112233445566778899'}, {'constantValue': 'hello'}, {'functionInvocationValue': { 'functionName': 'Date', 'arguments': {'value': {'constantValue': 1234567890000}} }}, {'functionInvocationValue': { 'functionName': 'GeometryConstructors.LineString', 'arguments': { 'crs': {'functionInvocationValue': { 'functionName': 'Projection', 'arguments': { 'crs': {'constantValue': 'SR-ORG:6974'}} }}, 'coordinates': {'arrayValue': {'values': [ {'valueReference': '1'}, {'constantValue': [3, 4]} ]}} }}}, {'functionInvocationValue': { 'functionName': 'GeometryConstructors.Polygon', 'arguments': { 'coordinates': {'arrayValue': {'values': [ {'arrayValue': {'values': [ {'valueReference': '2'}, {'constantValue': [10, 0]}, {'constantValue': [10, 10]}, {'constantValue': [0, 10]}, {'valueReference': '2'}]}}, {'constantValue': [[5, 6], [7, 6], [7, 8], [5, 8]]}, {'arrayValue': {'values': [ {'constantValue': [1, 1]}, {'constantValue': [2, 1]}, {'constantValue': [2, 2]}, {'valueReference': '1'}]}} ]}}, 'evenOdd': {'constantValue': True}}}}, {'bytesValue': 'aGVsbG8='}, {'dictionaryValue': { 'values': { 'baz': {'valueReference': '3'}, 'foo': {'constantValue': 'bar'}, } }}, {'valueReference': '3'}, {'functionDefinitionValue': { 'argumentNames': ['x', 'y'], 'body': '4'} } ]}}, '1': {'constantValue': [1, 2]}, '2': {'constantValue': [0, 0]}, '3': {'functionInvocationValue': { 'functionName': 'String.cat', 'arguments': { 'string1': {'constantValue': 'x'}, 'string2': {'constantValue': 'y'} }}}, '4': {'argumentReference': 'y'}, }, 'result': '0' } ENCODED_CLOUD_API_JSON_SAMPLE_PRETTY = { 'arrayValue': { 'values': [ {'constantValue': None}, {'constantValue': True}, {'constantValue': 5}, {'constantValue': 7}, {'constantValue': 3.4}, {'integerValue': '112233445566778899'}, {'constantValue': 'hello'}, {'functionInvocationValue': { 'functionName': 'Date', 'arguments': {'value': {'constantValue': 1234567890000}} }}, {'functionInvocationValue': { 'functionName': 'GeometryConstructors.LineString', 'arguments': { 'crs': {'functionInvocationValue': { 'functionName': 'Projection', 'arguments': { 'crs': {'constantValue': 'SR-ORG:6974'}} }}, 'coordinates': {'constantValue': [[1, 2], [3, 4]]} }}}, {'functionInvocationValue': { 'functionName': 'GeometryConstructors.Polygon', 'arguments': { 'coordinates': { 'constantValue': [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[5, 6], [7, 6], [7, 8], [5, 8]], [[1, 1], [2, 1], [2, 2], [1, 2]]]}, 'evenOdd': {'constantValue': True}}}}, {'bytesValue': 'aGVsbG8='}, {'dictionaryValue': { 'values': { 'baz': {'functionInvocationValue': { 'functionName': 'String.cat', 'arguments': { 'string1': {'constantValue': 'x'}, 'string2': {'constantValue': 'y'} }}}, 'foo': {'constantValue': 'bar'}, }}}, {'functionInvocationValue': { 'functionName': 'String.cat', 'arguments': { 'string1': {'constantValue': 'x'}, 'string2': {'constantValue': 'y'} }}}, {'functionDefinitionValue': { 'argumentNames': ['x', 'y'], 'body': {'argumentReference': 'y'}} } ]}}