Skip to content

Commit 63ace82

Browse files
authored
Improving logging for Ctv1 (#996)
* Improving logging for Ctv1
1 parent ea960f2 commit 63ace82

File tree

5 files changed

+136
-12
lines changed

5 files changed

+136
-12
lines changed

src/rpdk/core/contract/resource_client.py

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -281,12 +281,20 @@ def has_only_writable_identifiers(self):
281281
)
282282

283283
def assert_write_only_property_does_not_exist(self, resource_model):
284+
285+
error_list = []
284286
if self.write_only_paths:
285-
assert not any(
286-
self.key_error_safe_traverse(resource_model, write_only_property)
287-
for write_only_property in self.write_only_paths
288-
), "The model MUST NOT return properties defined as \
289-
writeOnlyProperties in the resource schema"
287+
for write_only_property in self.write_only_paths:
288+
val = self.key_error_safe_traverse(resource_model, write_only_property)
289+
if val:
290+
error_list.append(write_only_property[1])
291+
assertion_error_message = (
292+
"The model MUST NOT return properties defined as "
293+
"writeOnlyProperties in the resource schema "
294+
"\n Write only properties in resource model : %s \n Output Resource Model : %s \n"
295+
% (error_list, resource_model)
296+
)
297+
assert not any(error_list), assertion_error_message
290298

291299
def get_metadata(self):
292300
try:
@@ -450,7 +458,8 @@ def compare_model(self, inputs, outputs, path=()):
450458
"All properties specified in the request MUST "
451459
"be present in the model returned, and they MUST"
452460
" match exactly, with the exception of properties"
453-
" defined as writeOnlyProperties in the resource schema"
461+
" defined as writeOnlyProperties in the resource schema \n Request Model : %s \n Returned Model : %s \n"
462+
% (inputs, outputs)
454463
)
455464
try:
456465
if isinstance(inputs, dict):
@@ -476,6 +485,16 @@ def compare_model(self, inputs, outputs, path=()):
476485
new_path,
477486
)
478487
else:
488+
if inputs[key] != outputs[key]:
489+
assertion_error_message = (
490+
"%s Value for property %s in Request Model(%s) and Response Model(%s) does not match"
491+
% (
492+
assertion_error_message,
493+
key,
494+
inputs[key],
495+
outputs[key],
496+
)
497+
)
479498
assert inputs[key] == outputs[key], assertion_error_message
480499
else:
481500
assert inputs == outputs, assertion_error_message
@@ -628,6 +647,22 @@ def is_primary_identifier_equal(
628647
match the primaryIdentifier passed into the request"
629648
) from e
630649

650+
@staticmethod
651+
def get_primary_identifier(primary_identifier_path, model):
652+
try:
653+
pid_list = []
654+
for primary_identifier in primary_identifier_path:
655+
data = traverse(model, fragment_list(primary_identifier, "properties"))[
656+
0
657+
]
658+
pid_list.append(data)
659+
return pid_list
660+
except KeyError as e:
661+
raise AssertionError(
662+
"The primaryIdentifier returned in every progress event must\
663+
match the primaryIdentifier passed into the request \n"
664+
) from e
665+
631666
def _make_payload(
632667
self,
633668
action,

src/rpdk/core/contract/suite/resource/handler_commons.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,33 @@ def test_model_in_list(resource_client, current_resource_model):
102102
)
103103

104104

105+
def error_test_model_in_list(resource_client, current_resource_model, message):
106+
resource_models = get_resource_model_list(resource_client, current_resource_model)
107+
assertion_error_message = message
108+
for resource_model in resource_models:
109+
resource_model_primary_identifier = resource_client.get_primary_identifier(
110+
resource_client.primary_identifier_paths, resource_model
111+
)
112+
current_model_primary_identifier = resource_client.get_primary_identifier(
113+
resource_client.primary_identifier_paths, current_resource_model
114+
)
115+
if resource_model_primary_identifier != current_model_primary_identifier:
116+
assertion_error_message = (
117+
"%s \n Resource Model primary identifier %s does not match with "
118+
"Current Resource Model primary identifier %s \n Resource Model : %s"
119+
" \n Currrent Model : %s "
120+
% (
121+
message,
122+
resource_model_primary_identifier[0],
123+
current_model_primary_identifier[0],
124+
resource_model,
125+
current_resource_model,
126+
)
127+
)
128+
return assertion_error_message
129+
return assertion_error_message
130+
131+
105132
@response_contains_primary_identifier
106133
@response_contains_unchanged_primary_identifier
107134
@response_contains_resource_model_equal_updated_model

src/rpdk/core/contract/suite/resource/handler_create.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
skip_not_writable_identifier,
1414
)
1515
from rpdk.core.contract.suite.resource.handler_commons import (
16+
error_test_model_in_list,
1617
test_create_failure_if_repeat_writeable_id,
1718
test_create_success,
1819
test_delete_success,
@@ -75,7 +76,9 @@ def contract_create_read(created_resource, resource_client):
7576
@pytest.mark.read
7677
def contract_create_list(created_resource, resource_client):
7778
_input_model, created_model, _request = created_resource
78-
assert test_model_in_list(resource_client, created_model)
79+
assert test_model_in_list(resource_client, created_model), error_test_model_in_list(
80+
resource_client, created_model, ""
81+
)
7982
test_read_success(resource_client, created_model)
8083

8184

src/rpdk/core/contract/suite/resource/handler_update.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
skip_not_tag_updatable,
1212
)
1313
from rpdk.core.contract.suite.resource.handler_commons import (
14+
error_test_model_in_list,
1415
test_input_equals_output,
1516
test_model_in_list,
1617
test_read_success,
@@ -55,10 +56,26 @@ def contract_update_read(updated_resource, resource_client):
5556
updated_model,
5657
updated_input_model,
5758
) = updated_resource
59+
create_primary_identifiers = resource_client.get_primary_identifier(
60+
resource_client.primary_identifier_paths, _created_model
61+
)
62+
update_primary_identifiers = resource_client.get_primary_identifier(
63+
resource_client.primary_identifier_paths, updated_model
64+
)
65+
assertion_error_message = (
66+
"The primaryIdentifier returned must match "
67+
"the primaryIdentifier passed into the request "
68+
"Create Model primary identifier %s does not match with Update Model primary identifier %s \n Create Model : %s \n Update Model : %s "
69+
% (
70+
create_primary_identifiers,
71+
update_primary_identifiers,
72+
_created_model,
73+
updated_model,
74+
)
75+
)
5876
assert resource_client.is_primary_identifier_equal(
5977
resource_client.primary_identifier_paths, _created_model, updated_model
60-
), "The primaryIdentifier returned must match\
61-
the primaryIdentifier passed into the request"
78+
), assertion_error_message
6279
read_response = test_read_success(resource_client, updated_model)
6380
test_input_equals_output(
6481
resource_client, updated_input_model, read_response["resourceModel"]
@@ -81,9 +98,11 @@ def contract_update_list(updated_resource, resource_client):
8198
resource_client.primary_identifier_paths, _created_model, updated_model
8299
), "The primaryIdentifier returned must match\
83100
the primaryIdentifier passed into the request"
84-
assert test_model_in_list(
85-
resource_client, updated_model
86-
), "A list handler MUST always return an updated model"
101+
assert test_model_in_list(resource_client, updated_model), error_test_model_in_list(
102+
resource_client,
103+
updated_model,
104+
"A list handler MUST always return an updated model",
105+
)
87106

88107

89108
@pytest.mark.update

tests/contract/test_resource_client.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import pytest
99

10+
import rpdk.core.contract.resource_client as rclient
1011
from rpdk.core.boto_helpers import LOWER_CAMEL_CRED_KEYS
1112
from rpdk.core.contract.interface import Action, HandlerErrorCode, OperationStatus
1213
from rpdk.core.contract.resource_client import (
@@ -17,6 +18,7 @@
1718
prune_properties_if_not_exist_in_path,
1819
prune_properties_which_dont_exist_in_path,
1920
)
21+
from rpdk.core.contract.suite.resource.handler_commons import error_test_model_in_list
2022
from rpdk.core.exceptions import InvalidProjectError
2123
from rpdk.core.test import (
2224
DEFAULT_ENDPOINT,
@@ -149,6 +151,8 @@
149151

150152
EMPTY_SCHEMA = {"handlers": {"create": [], "delete": [], "read": []}}
151153

154+
RESOURCE_MODEL_LIST = [{"Id": "abc123", "b": "2"}]
155+
152156

153157
@pytest.fixture
154158
def resource_client():
@@ -390,6 +394,42 @@ def resource_client_inputs_property_transform():
390394
return client
391395

392396

397+
def test_error_test_model_in_list(resource_client):
398+
patch_resource_model_list = patch(
399+
"rpdk.core.contract.suite.resource.handler_commons.get_resource_model_list",
400+
autospec=True,
401+
return_value=RESOURCE_MODEL_LIST,
402+
)
403+
resource_client.primary_identifier_paths = {("properties", "Id")}
404+
current_resource_model = {"Id": "xyz456", "b": "2"}
405+
with patch_resource_model_list:
406+
assertion_error_message = error_test_model_in_list(
407+
resource_client, current_resource_model, ""
408+
)
409+
assert (
410+
"abc123 does not match with Current Resource Model primary identifier xyz456"
411+
in assertion_error_message
412+
)
413+
414+
415+
def test_get_primary_identifier_success():
416+
primary_identifier_path = {("properties", "a")}
417+
model = {"a": 1, "b": 3, "c": 4}
418+
plist = rclient.ResourceClient.get_primary_identifier(
419+
primary_identifier_path, model
420+
)
421+
assert plist[0] == 1
422+
423+
424+
def test_get_primary_identifier_fail():
425+
primary_identifier_path = {("properties", "a")}
426+
model = {"b": 3, "c": 4}
427+
try:
428+
rclient.ResourceClient.get_primary_identifier(primary_identifier_path, model)
429+
except AssertionError:
430+
logging.debug("This test expects Assertion Exception to be thrown")
431+
432+
393433
def test_prune_properties():
394434
document = {
395435
"foo": "bar",

0 commit comments

Comments
 (0)