Skip to content

Commit 99f08ac

Browse files
Narek MkhitaryanNarek Mkhitaryan
authored andcommitted
added project_custom_field tests
1 parent b0b77e5 commit 99f08ac

File tree

6 files changed

+268
-3
lines changed

6 files changed

+268
-3
lines changed

src/superannotate/lib/core/serviceproviders.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ def list_workflow_roles(self, project_id: int, workflow_id: int):
105105
def list_project_custom_field_templates(self):
106106
raise NotImplementedError
107107

108+
def create_project_custom_field_template(self, data: dict):
109+
raise NotImplementedError
110+
111+
def delete_project_custom_field_template(self, pk: int):
112+
raise NotImplementedError
113+
108114
@abstractmethod
109115
def list_project_custom_entities(self, project_id: int):
110116
raise NotImplementedError

src/superannotate/lib/core/usecases/projects.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,11 @@ def execute(self):
227227
raise AppException("Invalid custom field value provided.")
228228
patch_data = {custom_field_id: self._value}
229229
# TODO add error handling
230-
self._service_provider.work_management.set_project_custom_field_value(
230+
res = self._service_provider.work_management.set_project_custom_field_value(
231231
project_id=self._project.id, data=patch_data
232232
)
233+
if res.error:
234+
raise AppException(res.error)
233235

234236

235237
class CreateProjectUseCase(BaseUseCase):

src/superannotate/lib/infrastructure/controller.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ def list_projects(
318318
include: List[str] = None,
319319
**filters: Unpack[ProjectFilters],
320320
) -> List[ProjectEntity]:
321-
if "custom_fields" in include:
321+
if include and "custom_fields" in include:
322322
body_query = self._build_body_query(filters)
323323
response = self.service_provider.work_management.list_projects(
324324
body_query=body_query

src/superannotate/lib/infrastructure/services/work_management.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class WorkManagementService(BaseWorkManagementService):
1818
URL_CREATE_ROLE = "roles"
1919
URL_CREATE_STATUS = "statuses"
2020
URL_CUSTOM_FIELD_TEMPLATES = "customfieldtemplates"
21+
URL_CUSTOM_FIELD_TEMPLATE_DELETE = "customfieldtemplates/{template_id}"
2122
URL_PROJECT_CUSTOM_ENTITIES = "customentities/{project_id}"
2223
LIST_PROJECTS = "customentities/search"
2324

@@ -116,6 +117,37 @@ def list_project_custom_field_templates(self):
116117
},
117118
)
118119

120+
def create_project_custom_field_template(self, data: dict):
121+
return self.client.request(
122+
url=self.URL_CUSTOM_FIELD_TEMPLATES,
123+
method="post",
124+
data=data,
125+
headers={
126+
"x-sa-entity-context": base64.b64encode(
127+
f'{{"team_id":{self.client.team_id}}}'.encode("utf-8")
128+
).decode()
129+
},
130+
params={
131+
"entity": "Project",
132+
"parentEntity": "Team",
133+
},
134+
)
135+
136+
def delete_project_custom_field_template(self, pk: int):
137+
return self.client.request(
138+
url=self.URL_CUSTOM_FIELD_TEMPLATE_DELETE.format(template_id=pk),
139+
method="delete",
140+
headers={
141+
"x-sa-entity-context": base64.b64encode(
142+
f'{{"team_id":{self.client.team_id}}}'.encode("utf-8")
143+
).decode()
144+
},
145+
params={
146+
"entity": "Project",
147+
"parentEntity": "Team",
148+
},
149+
)
150+
119151
def list_project_custom_entities(self, project_id: int):
120152
return self.client.request(
121153
url=self.URL_PROJECT_CUSTOM_ENTITIES.format(project_id=project_id),

src/superannotate/lib/infrastructure/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ def get_role_id(self, project: entities.ProjectEntity, role_name: str) -> int:
129129
raise AppException("Invalid assignments role provided.")
130130

131131
def get_role_name(self, project: entities.ProjectEntity, role_id: int) -> str:
132-
self._sync(project, "roles")
132+
self._sync_project_data(project, "roles")
133133
mapping = self._role_id_name_map.get(project.id, {})
134134
if role_id in mapping:
135135
return mapping[role_id]
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
import time
2+
from typing import Any
3+
from typing import Dict
4+
5+
from lib.core.entities.work_managament import ProjectCustomFieldType
6+
from src.superannotate import SAClient
7+
from tests.integration.base import BaseTestCase
8+
9+
sa = SAClient()
10+
11+
12+
class TestProjectCustomFields(BaseTestCase):
13+
PROJECT_NAME = "TestProjectCustomFields"
14+
PROJECT_TYPE = "Vector"
15+
PROJECT_DESCRIPTION = "DESCRIPTION"
16+
CUSTOM_FIELD_PAYLOADS = [
17+
{
18+
"name": "SDK_test_text",
19+
"access": {},
20+
"component_id": ProjectCustomFieldType.Text.value,
21+
},
22+
{
23+
"name": "SDK_test_date_picker",
24+
"access": {},
25+
"component_id": ProjectCustomFieldType.DATE_PICKER.value,
26+
},
27+
{
28+
"name": "SDK_test_numeric",
29+
"access": {},
30+
"component_payload": {
31+
"configs": {"min": None, "max": None, "step": None, "suffix": None}
32+
},
33+
"component_id": ProjectCustomFieldType.NUMERIC.value,
34+
},
35+
{
36+
"name": "SDK_test_single_select",
37+
"access": {},
38+
"component_id": ProjectCustomFieldType.SINGLE_SELECT.value,
39+
"component_payload": {
40+
"options": [{"value": "option1"}, {"value": "option2"}]
41+
},
42+
},
43+
{
44+
"name": "SDK_test_multy_select",
45+
"access": {},
46+
"component_id": ProjectCustomFieldType.MULTI_SELECT.value,
47+
"component_payload": {
48+
"options": [{"value": "option1"}, {"value": "option2"}]
49+
},
50+
},
51+
]
52+
FIELD_VALUE_MAP = {
53+
"SDK_test_text": "test_text_value",
54+
"SDK_test_date_picker": float(int(time.time())),
55+
"SDK_test_numeric": 123,
56+
"SDK_test_single_select": "option1",
57+
"SDK_test_multy_select": ["option1", "option2"],
58+
}
59+
60+
@classmethod
61+
def setUpClass(cls, *args, **kwargs) -> None:
62+
# setup custom fields for test
63+
cls.tearDownClass()
64+
for data in cls.CUSTOM_FIELD_PAYLOADS:
65+
req = sa.controller.service_provider.work_management.create_project_custom_field_template(
66+
data
67+
)
68+
assert req.status_code == 201
69+
70+
@classmethod
71+
def tearDownClass(cls) -> None:
72+
# cleanup test custom fields
73+
bed_custom_fields_name_id_map = {
74+
i["name"]: i["id"]
75+
for i in sa.controller.service_provider.work_management.list_project_custom_field_templates().data[
76+
"data"
77+
]
78+
}
79+
for data in cls.CUSTOM_FIELD_PAYLOADS:
80+
if data["name"] in bed_custom_fields_name_id_map.keys():
81+
req = sa.controller.service_provider.work_management.delete_project_custom_field_template(
82+
bed_custom_fields_name_id_map[data["name"]]
83+
)
84+
assert req.status_code == 200
85+
86+
def _set_custom_field_values(self, field_value_map: Dict[str, Any] = None) -> None:
87+
if not field_value_map:
88+
field_value_map = self.FIELD_VALUE_MAP
89+
for k, v in field_value_map.items():
90+
sa.set_project_custom_field(self.PROJECT_NAME, k, v)
91+
92+
def test_get_project_metadata_without_custom_fields(self):
93+
project_metadata = sa.get_project_metadata(
94+
self.PROJECT_NAME, include_custom_fields=False
95+
)
96+
assert project_metadata["custom_fields"] == {}
97+
98+
def test_set_project_custom_field(self):
99+
# project metadata before set custom field values
100+
project_metadata = sa.get_project_metadata(
101+
self.PROJECT_NAME, include_custom_fields=True
102+
)
103+
for data in self.CUSTOM_FIELD_PAYLOADS:
104+
assert data["name"] in project_metadata["custom_fields"].keys()
105+
assert not project_metadata["custom_fields"][data["name"]]
106+
107+
# project metadata after set custom field values
108+
self._set_custom_field_values()
109+
110+
project_metadata = sa.get_project_metadata(
111+
self.PROJECT_NAME, include_custom_fields=True
112+
)
113+
for data in self.CUSTOM_FIELD_PAYLOADS:
114+
assert data["name"] in project_metadata["custom_fields"].keys()
115+
assert (
116+
project_metadata["custom_fields"][data["name"]]
117+
== self.FIELD_VALUE_MAP[data["name"]]
118+
)
119+
120+
def test_list_projects_by_native_fields(self):
121+
projects = sa.list_projects(include=["custom_fields"], name=self.PROJECT_NAME)
122+
assert len(projects) == 1
123+
assert projects[0]["name"] == self.PROJECT_NAME
124+
for data in self.CUSTOM_FIELD_PAYLOADS:
125+
assert data["name"] in projects[0]["custom_fields"].keys()
126+
assert not projects[0]["custom_fields"][data["name"]]
127+
128+
assert not sa.list_projects(
129+
include=["custom_fields"], name__in=["invalid_name_1", "invalid_name_2"]
130+
)
131+
assert (
132+
len(
133+
sa.list_projects(
134+
include=["custom_fields"], name__contains="TestProjectCustomFie"
135+
)
136+
)
137+
== 1
138+
)
139+
assert (
140+
len(
141+
sa.list_projects(
142+
include=["custom_fields"],
143+
name__in=[self.PROJECT_NAME, "other_name"],
144+
)
145+
)
146+
== 1
147+
)
148+
assert not sa.list_projects(
149+
include=["custom_fields"],
150+
name__in=[self.PROJECT_NAME, "other_name"],
151+
status="Completed",
152+
)
153+
assert (
154+
len(
155+
sa.list_projects(
156+
include=["custom_fields"],
157+
name__in=[self.PROJECT_NAME, "other_name"],
158+
status__in=["NotStarted"],
159+
)
160+
)
161+
== 1
162+
)
163+
164+
def test_list_projects_by_custom_fields(self):
165+
# project metadata after set custom field values
166+
self._set_custom_field_values()
167+
projects = sa.list_projects(
168+
include=["custom_fields"], custom_field__SDK_test_numeric=123
169+
)
170+
assert len(projects) == 1
171+
assert projects[0]["name"] == self.PROJECT_NAME
172+
for data in self.CUSTOM_FIELD_PAYLOADS:
173+
assert data["name"] in projects[0]["custom_fields"].keys()
174+
assert (
175+
projects[0]["custom_fields"][data["name"]]
176+
== self.FIELD_VALUE_MAP[data["name"]]
177+
)
178+
179+
assert not sa.list_projects(
180+
include=["custom_fields"], custom_field__SDK_test_numeric=1
181+
)
182+
for p in sa.list_projects(
183+
include=["custom_fields"], custom_field__SDK_test_numeric__ne=123
184+
):
185+
assert not p["name"] == self.PROJECT_NAME
186+
assert (
187+
len(
188+
sa.list_projects(
189+
include=["custom_fields"],
190+
custom_field__SDK_test_multy_select__in=["option1", "option2"],
191+
)
192+
)
193+
== 1
194+
)
195+
assert (
196+
len(
197+
sa.list_projects(
198+
include=["custom_fields"],
199+
custom_field__SDK_test_single_select="option1",
200+
)
201+
)
202+
== 1
203+
)
204+
assert (
205+
len(
206+
sa.list_projects(
207+
include=["custom_fields"],
208+
custom_field__SDK_test_multy_select__contains="option2",
209+
)
210+
)
211+
== 1
212+
)
213+
assert not sa.list_projects(
214+
include=["custom_fields"],
215+
custom_field__SDK_test_multy_select__contains="invalid_option",
216+
)
217+
assert (
218+
len(
219+
sa.list_projects(
220+
include=["custom_fields"],
221+
custom_field__SDK_test_text__contains="test_text_v",
222+
)
223+
)
224+
== 1
225+
)

0 commit comments

Comments
 (0)