Skip to content

Commit 0823067

Browse files
authored
Assert input to the handler is equal to the output (#531)
* Assert input to the handler is equal to the output * Check if createOnly property is null/empty and remove it from input and output
1 parent 579abeb commit 0823067

File tree

6 files changed

+95
-7
lines changed

6 files changed

+95
-7
lines changed

src/rpdk/core/contract/resource_client.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,35 @@ def prune_properties(document, paths):
4141
return document
4242

4343

44+
def prune_properties_if_not_exist_in_path(output_model, input_model, paths):
45+
"""Prune given properties from a document.
46+
47+
This assumes properties will always have an object (dict) as a parent.
48+
The function returns the document after pruning the path which exists
49+
in the paths tuple but not in the input_model
50+
"""
51+
output_document = {"properties": output_model.copy()}
52+
input_document = {"properties": input_model.copy()}
53+
for path in paths:
54+
try:
55+
if not path_exists(input_document, path):
56+
_prop, resolved_path, parent = traverse(output_document, path)
57+
key = resolved_path[-1]
58+
del parent[key]
59+
except LookupError:
60+
pass
61+
return output_document["properties"]
62+
63+
64+
def path_exists(document, path):
65+
try:
66+
_prop, _resolved_path, _parent = traverse(document, path)
67+
except LookupError:
68+
return False
69+
else:
70+
return True
71+
72+
4473
def prune_properties_from_model(model, paths):
4574
"""Prune given properties from a resource model.
4675
@@ -299,7 +328,7 @@ def make_request(
299328
return {
300329
"desiredResourceState": desired_resource_state,
301330
"previousResourceState": previous_resource_state,
302-
"logicalResourceIdentifier": None,
331+
"logicalResourceIdentifier": "test",
303332
**kwargs,
304333
"region": region,
305334
"awsPartition": partition,

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import logging
22

33
from rpdk.core.contract.interface import Action, HandlerErrorCode, OperationStatus
4+
from rpdk.core.contract.resource_client import (
5+
prune_properties_from_model,
6+
prune_properties_if_not_exist_in_path,
7+
)
48
from rpdk.core.contract.suite.contract_asserts import (
59
failed_event,
610
response_contains_primary_identifier,
@@ -124,3 +128,18 @@ def test_delete_failure_not_found(resource_client, current_resource_model):
124128
Action.DELETE, OperationStatus.FAILED, current_resource_model
125129
)
126130
return error_code
131+
132+
133+
def test_input_equals_output(resource_client, input_model, output_model):
134+
input_model = prune_properties_from_model(
135+
input_model, resource_client.write_only_paths
136+
)
137+
138+
output_model = prune_properties_from_model(
139+
output_model, resource_client.read_only_paths
140+
)
141+
output_model = prune_properties_if_not_exist_in_path(
142+
output_model, input_model, resource_client.create_only_paths
143+
)
144+
145+
assert input_model == output_model

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
test_create_failure_if_repeat_writeable_id,
1616
test_create_success,
1717
test_delete_success,
18+
test_input_equals_output,
1819
test_model_in_list,
1920
test_read_success,
2021
)
@@ -24,12 +25,13 @@
2425

2526
@pytest.fixture(scope="module")
2627
def created_resource(resource_client):
27-
request = model = resource_client.generate_create_example()
28+
request = input_model = model = resource_client.generate_create_example()
2829
try:
2930
_status, response, _error = resource_client.call_and_assert(
3031
Action.CREATE, OperationStatus.SUCCESS, request
3132
)
3233
model = response["resourceModel"]
34+
test_input_equals_output(resource_client, input_model, model)
3335
yield model, request
3436
finally:
3537
resource_client.call_and_assert(Action.DELETE, OperationStatus.SUCCESS, model)
@@ -38,11 +40,14 @@ def created_resource(resource_client):
3840
@pytest.mark.create
3941
@pytest.mark.delete
4042
def contract_create_delete(resource_client):
41-
requested_model = delete_model = resource_client.generate_create_example()
43+
requested_model = (
44+
delete_model
45+
) = input_model = resource_client.generate_create_example()
4246
try:
4347
response = test_create_success(resource_client, requested_model)
4448
# check response here
4549
delete_model = response["resourceModel"]
50+
test_input_equals_output(resource_client, input_model, delete_model)
4651
finally:
4752
test_delete_success(resource_client, delete_model)
4853

src/rpdk/core/contract/suite/handler_delete.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from rpdk.core.contract.suite.handler_commons import (
1212
test_create_success,
1313
test_delete_failure_not_found,
14+
test_input_equals_output,
1415
test_model_in_list,
1516
test_read_failure_not_found,
1617
test_update_failure_not_found,
@@ -24,12 +25,13 @@
2425

2526
@pytest.fixture(scope="module")
2627
def deleted_resource(resource_client):
27-
request = model = resource_client.generate_create_example()
28+
request = input_model = model = resource_client.generate_create_example()
2829
try:
2930
_status, response, _error = resource_client.call_and_assert(
3031
Action.CREATE, OperationStatus.SUCCESS, request
3132
)
3233
model = response["resourceModel"]
34+
test_input_equals_output(resource_client, input_model, model)
3335
_status, response, _error = resource_client.call_and_assert(
3436
Action.DELETE, OperationStatus.SUCCESS, model
3537
)

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,31 @@
77
# when being loaded by pytest
88
from rpdk.core.contract.interface import Action, OperationStatus
99
from rpdk.core.contract.suite.handler_commons import (
10+
test_input_equals_output,
1011
test_model_in_list,
1112
test_read_success,
1213
)
1314

1415

1516
@pytest.fixture(scope="module")
1617
def updated_resource(resource_client):
17-
create_request = model = resource_client.generate_create_example()
18+
create_request = input_model = model = resource_client.generate_create_example()
1819
try:
1920
_status, response, _error = resource_client.call_and_assert(
2021
Action.CREATE, OperationStatus.SUCCESS, create_request
2122
)
2223
created_model = model = response["resourceModel"]
23-
update_request = resource_client.generate_update_example(created_model)
24+
test_input_equals_output(resource_client, input_model, created_model)
25+
26+
updated_input_model = update_request = resource_client.generate_update_example(
27+
created_model
28+
)
2429
_status, response, _error = resource_client.call_and_assert(
2530
Action.UPDATE, OperationStatus.SUCCESS, update_request, created_model
2631
)
2732
updated_model = response["resourceModel"]
33+
test_input_equals_output(resource_client, updated_input_model, updated_model)
34+
2835
yield create_request, created_model, update_request, updated_model
2936
finally:
3037
resource_client.call_and_assert(Action.DELETE, OperationStatus.SUCCESS, model)

tests/contract/test_resource_client.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
override_properties,
1515
prune_properties,
1616
prune_properties_from_model,
17+
prune_properties_if_not_exist_in_path,
1718
)
1819
from rpdk.core.test import (
1920
DEFAULT_ENDPOINT,
@@ -161,6 +162,31 @@ def test_prune_properties_from_model():
161162
assert document == {"one": "two", "array": ["first"]}
162163

163164

165+
def test_prune_properties_if_not_exist_in_path():
166+
previous_model = {
167+
"spam": "eggs",
168+
"one": "two",
169+
"array": ["first", "second"],
170+
}
171+
model = {
172+
"foo": "bar",
173+
"spam": "eggs",
174+
"one": "two",
175+
"array": ["first", "second"],
176+
}
177+
model = prune_properties_if_not_exist_in_path(
178+
model,
179+
previous_model,
180+
[
181+
("properties", "foo"),
182+
("properties", "spam"),
183+
("properties", "array", "1"),
184+
("properties", "invalid"),
185+
],
186+
)
187+
assert model == previous_model
188+
189+
164190
def test_init_sam_cli_client():
165191
patch_sesh = patch(
166192
"rpdk.core.contract.resource_client.create_sdk_session", autospec=True
@@ -210,7 +236,7 @@ def test_make_request():
210236
assert request == {
211237
"desiredResourceState": desired_resource_state,
212238
"previousResourceState": previous_resource_state,
213-
"logicalResourceIdentifier": None,
239+
"logicalResourceIdentifier": "test",
214240
"clientRequestToken": token,
215241
"region": "us-west-2",
216242
"awsPartition": "aws",

0 commit comments

Comments
 (0)