From 39694d1e4d9d4c60bb240ec2eb1c4ca7dfa38c96 Mon Sep 17 00:00:00 2001
From: Chaza Abdelwahab <abdelwahab@teklia.com>
Date: Fri, 30 Sep 2022 13:20:27 +0000
Subject: [PATCH] Support CachedElements on metadata endpoints

---
 arkindex_worker/worker/metadata.py          |  21 +--
 tests/test_elements_worker/test_metadata.py | 142 +++++++++++++++++++-
 2 files changed, 151 insertions(+), 12 deletions(-)

diff --git a/arkindex_worker/worker/metadata.py b/arkindex_worker/worker/metadata.py
index 7300a20a..afa2c2f1 100644
--- a/arkindex_worker/worker/metadata.py
+++ b/arkindex_worker/worker/metadata.py
@@ -7,6 +7,7 @@ from enum import Enum
 from typing import Dict, List, Optional, Union
 
 from arkindex_worker import logger
+from arkindex_worker.cache import CachedElement
 from arkindex_worker.models import Element
 
 
@@ -59,7 +60,7 @@ class MetaType(Enum):
 class MetaDataMixin(object):
     def create_metadata(
         self,
-        element: Element,
+        element: Union[Element, CachedElement],
         type: MetaType,
         name: str,
         value: str,
@@ -76,8 +77,8 @@ class MetaDataMixin(object):
         :returns: UUID of the created metadata.
         """
         assert element and isinstance(
-            element, Element
-        ), "element shouldn't be null and should be of type Element"
+            element, (Element, CachedElement)
+        ), "element shouldn't be null and should be of type Element or CachedElement"
         assert type and isinstance(
             type, MetaType
         ), "type shouldn't be null and should be of type MetaType"
@@ -110,7 +111,7 @@ class MetaDataMixin(object):
 
     def create_metadatas(
         self,
-        element: Element,
+        element: Union[Element, CachedElement],
         metadatas: List[
             Dict[
                 str, Union[MetaType, str, Union[str, Union[int, float]], Optional[str]]
@@ -129,8 +130,8 @@ class MetaDataMixin(object):
             - entity_id : Union[str, None]
         """
         assert element and isinstance(
-            element, Element
-        ), "element shouldn't be null and should be of type Element"
+            element, (Element, CachedElement)
+        ), "element shouldn't be null and should be of type Element or CachedElement"
 
         assert metadatas and isinstance(
             metadatas, list
@@ -186,7 +187,9 @@ class MetaDataMixin(object):
 
         return created_metadatas
 
-    def list_element_metadata(self, element: Element) -> List[Dict[str, str]]:
+    def list_element_metadata(
+        self, element: Union[Element, CachedElement]
+    ) -> List[Dict[str, str]]:
         """
         List all metadata linked to an element.
         This method does not support cache.
@@ -194,7 +197,7 @@ class MetaDataMixin(object):
         :param element: The element to list metadata on.
         """
         assert element and isinstance(
-            element, Element
-        ), "element shouldn't be null and should be of type Element"
+            element, (Element, CachedElement)
+        ), "element shouldn't be null and should be of type Element or CachedElement"
 
         return self.api_client.paginate("ListElementMetaData", id=element.id)
diff --git a/tests/test_elements_worker/test_metadata.py b/tests/test_elements_worker/test_metadata.py
index c6b3515f..c18e3f60 100644
--- a/tests/test_elements_worker/test_metadata.py
+++ b/tests/test_elements_worker/test_metadata.py
@@ -4,6 +4,8 @@ import json
 import pytest
 from apistar.exceptions import ErrorResponse
 
+from arkindex.mock import MockApiClient
+from arkindex_worker.cache import CachedElement
 from arkindex_worker.models import Element
 from arkindex_worker.worker import MetaType
 
@@ -18,7 +20,10 @@ def test_create_metadata_wrong_element(mock_elements_worker):
             name="Teklia",
             value="La Turbine, Grenoble 38000",
         )
-    assert str(e.value) == "element shouldn't be null and should be of type Element"
+    assert (
+        str(e.value)
+        == "element shouldn't be null and should be of type Element or CachedElement"
+    )
 
     with pytest.raises(AssertionError) as e:
         mock_elements_worker.create_metadata(
@@ -27,7 +32,10 @@ def test_create_metadata_wrong_element(mock_elements_worker):
             name="Teklia",
             value="La Turbine, Grenoble 38000",
         )
-    assert str(e.value) == "element shouldn't be null and should be of type Element"
+    assert (
+        str(e.value)
+        == "element shouldn't be null and should be of type Element or CachedElement"
+    )
 
 
 def test_create_metadata_wrong_type(mock_elements_worker):
@@ -198,6 +206,41 @@ def test_create_metadata(responses, mock_elements_worker):
     assert metadata_id == "12345678-1234-1234-1234-123456789123"
 
 
+def test_create_metadata_cached_element(responses, mock_elements_worker_with_cache):
+    elt = CachedElement.create(id="12341234-1234-1234-1234-123412341234", type="thing")
+    responses.add(
+        responses.POST,
+        "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/metadata/",
+        status=200,
+        json={"id": "12345678-1234-1234-1234-123456789123"},
+    )
+
+    metadata_id = mock_elements_worker_with_cache.create_metadata(
+        element=elt,
+        type=MetaType.Location,
+        name="Teklia",
+        value="La Turbine, Grenoble 38000",
+    )
+
+    assert len(responses.calls) == len(BASE_API_CALLS) + 1
+    assert [
+        (call.request.method, call.request.url) for call in responses.calls
+    ] == BASE_API_CALLS + [
+        (
+            "POST",
+            "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/metadata/",
+        ),
+    ]
+    assert json.loads(responses.calls[-1].request.body) == {
+        "type": "location",
+        "name": "Teklia",
+        "value": "La Turbine, Grenoble 38000",
+        "entity_id": None,
+        "worker_run_id": "56785678-5678-5678-5678-567856785678",
+    }
+    assert metadata_id == "12345678-1234-1234-1234-123456789123"
+
+
 @pytest.mark.parametrize(
     "metadatas",
     [
@@ -266,6 +309,80 @@ def test_create_metadatas(responses, mock_elements_worker, metadatas):
     ]
 
 
+@pytest.mark.parametrize(
+    "metadatas",
+    [
+        ([{"type": MetaType.Text, "name": "fake_name", "value": "fake_value"}]),
+        (
+            [
+                {
+                    "type": MetaType.Text,
+                    "name": "fake_name",
+                    "value": "fake_value",
+                    "entity_id": "fake_entity_id",
+                }
+            ]
+        ),
+    ],
+)
+def test_create_metadatas_cached_element(
+    responses, mock_elements_worker_with_cache, metadatas
+):
+    element = CachedElement.create(
+        id="12341234-1234-1234-1234-123412341234", type="thing"
+    )
+    responses.add(
+        responses.POST,
+        "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/metadata/bulk/",
+        status=201,
+        json={
+            "worker_run_id": "56785678-5678-5678-5678-567856785678",
+            "metadata_list": [
+                {
+                    "id": "fake_metadata_id",
+                    "type": metadatas[0]["type"].value,
+                    "name": metadatas[0]["name"],
+                    "value": metadatas[0]["value"],
+                    "dates": [],
+                    "entity_id": metadatas[0].get("entity_id"),
+                }
+            ],
+        },
+    )
+
+    created_metadatas = mock_elements_worker_with_cache.create_metadatas(
+        element, metadatas
+    )
+
+    assert len(responses.calls) == len(BASE_API_CALLS) + 1
+    assert [
+        (call.request.method, call.request.url) for call in responses.calls
+    ] == BASE_API_CALLS + [
+        (
+            "POST",
+            "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/metadata/bulk/",
+        ),
+    ]
+    assert json.loads(responses.calls[-1].request.body)["metadata_list"] == [
+        {
+            "type": metadatas[0]["type"].value,
+            "name": metadatas[0]["name"],
+            "value": metadatas[0]["value"],
+            "entity_id": metadatas[0].get("entity_id"),
+        }
+    ]
+    assert created_metadatas == [
+        {
+            "id": "fake_metadata_id",
+            "type": metadatas[0]["type"].value,
+            "name": metadatas[0]["name"],
+            "value": metadatas[0]["value"],
+            "dates": [],
+            "entity_id": metadatas[0].get("entity_id"),
+        }
+    ]
+
+
 @pytest.mark.parametrize(
     "wrong_element",
     [
@@ -283,7 +400,10 @@ def test_create_metadatas_wrong_element(mock_elements_worker, wrong_element):
         mock_elements_worker.create_metadatas(
             element=wrong_element, metadatas=wrong_metadatas
         )
-    assert str(e.value) == "element shouldn't be null and should be of type Element"
+    assert (
+        str(e.value)
+        == "element shouldn't be null and should be of type Element or CachedElement"
+    )
 
 
 @pytest.mark.parametrize(
@@ -417,3 +537,19 @@ def test_list_element_metadata(fake_dummy_worker):
 
     assert len(fake_dummy_worker.api_client.history) == 1
     assert len(fake_dummy_worker.api_client.responses) == 0
+
+
+def test_list_element_metadata_cached_element(mock_elements_worker_with_cache):
+    element = CachedElement.create(id="element_id", type="thing")
+    mock_elements_worker_with_cache.api_client = MockApiClient()
+    mock_elements_worker_with_cache.api_client.add_response(
+        "ListElementMetaData",
+        id="element_id",
+        response={"id": "metadata_id"},
+    )
+    assert mock_elements_worker_with_cache.list_element_metadata(element) == {
+        "id": "metadata_id"
+    }
+
+    assert len(mock_elements_worker_with_cache.api_client.history) == 1
+    assert len(mock_elements_worker_with_cache.api_client.responses) == 0
-- 
GitLab