Skip to content

Commit 0032c60

Browse files
authored
Delete & Read Handler should be invoked using identifiers (#537)
* Delete & Read Handler should be invoked using identifiers * Allow schema merge to happen iteratively for a path * Add suggested changes * update the handler
1 parent 95881e4 commit 0032c60

File tree

13 files changed

+107
-20
lines changed

13 files changed

+107
-20
lines changed

src/rpdk/core/cli.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ def no_command(args):
104104
# some cases where it makes sense for the commands to raise SystemExit.)
105105
log.debug("Caught exit recommendation", exc_info=e)
106106
log.critical(str(e))
107+
# pylint: disable=W0707
107108
raise SystemExit(1)
108109
except DownstreamError as e:
109110
# For these operations, we don't want to swallow the exception
@@ -124,6 +125,7 @@ def no_command(args):
124125
"https://github.com/aws-cloudformation/aws-cloudformation-rpdk/issues",
125126
file=sys.stderr,
126127
)
128+
# pylint: disable=W0707
127129
raise SystemExit(2)
128130
except Exception: # pylint: disable=broad-except
129131
print("=== Unhandled exception ===", file=sys.stderr)
@@ -142,4 +144,5 @@ def no_command(args):
142144
import traceback # pylint: disable=import-outside-toplevel
143145

144146
traceback.print_exc()
147+
# pylint: disable=W0707
145148
raise SystemExit(EXIT_UNHANDLED_EXCEPTION)

src/rpdk/core/contract/resource_client.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,22 @@ def override_properties(document, overrides):
9898
return document
9999

100100

101+
def create_model_with_properties_in_path(src_model, paths):
102+
"""Creates a model with values preset in the paths.
103+
104+
This assumes properties will always have an object (dict) as a parent.
105+
The function returns the created model.
106+
"""
107+
model = {}
108+
try:
109+
for path in paths:
110+
pruned_path = path[-1]
111+
model[pruned_path] = src_model[pruned_path]
112+
except LookupError:
113+
pass
114+
return model
115+
116+
101117
class ResourceClient: # pylint: disable=too-many-instance-attributes
102118
def __init__(
103119
self,

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logging
12
from functools import wraps
23
from inspect import Parameter, signature
34
from unittest.test.testmock.support import is_instance
@@ -6,6 +7,8 @@
67

78
from rpdk.core.contract.interface import HandlerErrorCode
89

10+
LOG = logging.getLogger(__name__)
11+
912

1013
def _rebind(decorator, func, *args, **kwargs):
1114
"""Helper function to construct decorated arguments
@@ -82,6 +85,8 @@ def response_does_not_contain_write_only_properties(resource_client, response):
8285
def response_contains_resource_model_equal_current_model(
8386
response, current_resource_model
8487
):
88+
LOG.debug("This is response[resourceModel] %s", response["resourceModel"])
89+
LOG.debug("This is current_resource_model %s", current_resource_model)
8590
assert response["resourceModel"] == current_resource_model
8691

8792

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

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from rpdk.core.contract.interface import Action, HandlerErrorCode, OperationStatus
44
from rpdk.core.contract.resource_client import (
5+
create_model_with_properties_in_path,
56
prune_properties_from_model,
67
prune_properties_if_not_exist_in_path,
78
)
@@ -48,16 +49,22 @@ def test_create_failure_if_repeat_writeable_id(resource_client, current_resource
4849
@response_does_not_contain_write_only_properties
4950
@response_contains_resource_model_equal_current_model
5051
def test_read_success(resource_client, current_resource_model):
52+
primay_identifier_only_model = create_model_with_properties_in_path(
53+
current_resource_model.copy(), resource_client.primary_identifier_paths,
54+
)
5155
_status, response, _error_code = resource_client.call_and_assert(
52-
Action.READ, OperationStatus.SUCCESS, current_resource_model
56+
Action.READ, OperationStatus.SUCCESS, primay_identifier_only_model
5357
)
5458
return response
5559

5660

5761
@failed_event(error_code=HandlerErrorCode.NotFound)
5862
def test_read_failure_not_found(resource_client, current_resource_model):
63+
primay_identifier_only_model = create_model_with_properties_in_path(
64+
current_resource_model, resource_client.primary_identifier_paths,
65+
)
5966
_status, _response, error_code = resource_client.call_and_assert(
60-
Action.READ, OperationStatus.FAILED, current_resource_model
67+
Action.READ, OperationStatus.FAILED, primay_identifier_only_model
6168
)
6269
return error_code
6370

@@ -116,30 +123,36 @@ def test_update_failure_not_found(resource_client, current_resource_model):
116123

117124

118125
def test_delete_success(resource_client, current_resource_model):
126+
primay_identifier_only_model = create_model_with_properties_in_path(
127+
current_resource_model, resource_client.primary_identifier_paths,
128+
)
119129
_status, response, _error_code = resource_client.call_and_assert(
120-
Action.DELETE, OperationStatus.SUCCESS, current_resource_model
130+
Action.DELETE, OperationStatus.SUCCESS, primay_identifier_only_model
121131
)
122132
return response
123133

124134

125135
@failed_event(error_code=HandlerErrorCode.NotFound)
126136
def test_delete_failure_not_found(resource_client, current_resource_model):
137+
primay_identifier_only_model = create_model_with_properties_in_path(
138+
current_resource_model, resource_client.primary_identifier_paths,
139+
)
127140
_status, _response, error_code = resource_client.call_and_assert(
128-
Action.DELETE, OperationStatus.FAILED, current_resource_model
141+
Action.DELETE, OperationStatus.FAILED, primay_identifier_only_model
129142
)
130143
return error_code
131144

132145

133146
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
147+
pruned_input_model = prune_properties_from_model(
148+
input_model.copy(), resource_client.write_only_paths
136149
)
137150

138-
output_model = prune_properties_from_model(
139-
output_model, resource_client.read_only_paths
151+
pruned_output_model = prune_properties_if_not_exist_in_path(
152+
output_model.copy(), pruned_input_model, resource_client.read_only_paths
140153
)
141-
output_model = prune_properties_if_not_exist_in_path(
142-
output_model, input_model, resource_client.create_only_paths
154+
pruned_output_model = prune_properties_if_not_exist_in_path(
155+
pruned_output_model, pruned_input_model, resource_client.create_only_paths
143156
)
144157

145-
assert input_model == output_model
158+
assert pruned_input_model == pruned_output_model

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
# WARNING: contract tests should use fully qualified imports to avoid issues
88
# when being loaded by pytest
99
from rpdk.core.contract.interface import Action, HandlerErrorCode, OperationStatus
10+
from rpdk.core.contract.resource_client import create_model_with_properties_in_path
1011
from rpdk.core.contract.suite.contract_asserts import (
1112
failed_event,
1213
skip_not_writable_identifier,
@@ -34,7 +35,12 @@ def created_resource(resource_client):
3435
test_input_equals_output(resource_client, input_model, model)
3536
yield model, request
3637
finally:
37-
resource_client.call_and_assert(Action.DELETE, OperationStatus.SUCCESS, model)
38+
primay_identifier_only_model = create_model_with_properties_in_path(
39+
model, resource_client.primary_identifier_paths
40+
)
41+
resource_client.call_and_assert(
42+
Action.DELETE, OperationStatus.SUCCESS, primay_identifier_only_model
43+
)
3844

3945

4046
@pytest.mark.create

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
# WARNING: contract tests should use fully qualified imports to avoid issues
88
# when being loaded by pytest
99
from rpdk.core.contract.interface import Action, HandlerErrorCode, OperationStatus
10-
from rpdk.core.contract.resource_client import prune_properties_from_model
10+
from rpdk.core.contract.resource_client import (
11+
create_model_with_properties_in_path,
12+
prune_properties_from_model,
13+
)
1114
from rpdk.core.contract.suite.handler_commons import (
1215
test_create_success,
1316
test_delete_failure_not_found,
@@ -25,20 +28,23 @@
2528

2629
@pytest.fixture(scope="module")
2730
def deleted_resource(resource_client):
28-
request = input_model = model = resource_client.generate_create_example()
31+
request = input_model = pruned_model = resource_client.generate_create_example()
2932
try:
3033
_status, response, _error = resource_client.call_and_assert(
3134
Action.CREATE, OperationStatus.SUCCESS, request
3235
)
3336
model = response["resourceModel"]
3437
test_input_equals_output(resource_client, input_model, model)
38+
primay_identifier_only_model = create_model_with_properties_in_path(
39+
model, resource_client.primary_identifier_paths,
40+
)
3541
_status, response, _error = resource_client.call_and_assert(
36-
Action.DELETE, OperationStatus.SUCCESS, model
42+
Action.DELETE, OperationStatus.SUCCESS, primay_identifier_only_model
3743
)
3844
assert "resourceModel" not in response
3945
yield model, request
4046
finally:
41-
status, response = resource_client.call(Action.DELETE, model)
47+
status, response = resource_client.call(Action.DELETE, pruned_model)
4248

4349
# a failed status is allowed if the error code is NotFound
4450
if status == OperationStatus.FAILED:

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
# WARNING: contract tests should use fully qualified imports to avoid issues
77
# when being loaded by pytest
88
from rpdk.core.contract.interface import Action, OperationStatus
9+
from rpdk.core.contract.resource_client import create_model_with_properties_in_path
910
from rpdk.core.contract.suite.handler_commons import (
1011
test_input_equals_output,
1112
test_model_in_list,
@@ -34,7 +35,12 @@ def updated_resource(resource_client):
3435

3536
yield create_request, created_model, update_request, updated_model
3637
finally:
37-
resource_client.call_and_assert(Action.DELETE, OperationStatus.SUCCESS, model)
38+
primay_identifier_only_model = create_model_with_properties_in_path(
39+
model, resource_client.primary_identifier_paths
40+
)
41+
resource_client.call_and_assert(
42+
Action.DELETE, OperationStatus.SUCCESS, primay_identifier_only_model
43+
)
3844

3945

4046
@pytest.mark.update

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
# WARNING: contract tests should use fully qualified imports to avoid issues
77
# when being loaded by pytest
88
from rpdk.core.contract.interface import Action, HandlerErrorCode, OperationStatus
9+
from rpdk.core.contract.resource_client import create_model_with_properties_in_path
910
from rpdk.core.contract.suite.contract_asserts import failed_event
1011

1112

@@ -28,8 +29,11 @@ def contract_update_create_only_property(resource_client):
2829
)
2930
assert response["message"]
3031
finally:
32+
primay_identifier_only_model = create_model_with_properties_in_path(
33+
created_model, resource_client.primary_identifier_paths,
34+
)
3135
resource_client.call_and_assert(
32-
Action.DELETE, OperationStatus.SUCCESS, created_model
36+
Action.DELETE, OperationStatus.SUCCESS, primay_identifier_only_model
3337
)
3438
else:
3539
pytest.skip("No createOnly Properties. Skipping test.")

src/rpdk/core/init.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def __call__(self, value):
6868
try:
6969
choice = int(value)
7070
except ValueError:
71+
# pylint: disable=W0707
7172
raise WizardValidationError("Please enter an integer")
7273
choice -= 1
7374
if choice < 0 or choice >= self.max:
@@ -159,6 +160,7 @@ def wrapper(args):
159160
function(args)
160161
except (KeyboardInterrupt, WizardAbortError):
161162
print("\naborted")
163+
# pylint: disable=W0707
162164
raise SystemExit(1)
163165

164166
return wrapper

src/rpdk/core/jsonutils/flattener.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ def _flatten_ref_type(self, ref_path):
8888
try:
8989
ref_parts = fragment_decode(ref_path)
9090
except ValueError as e:
91+
# pylint: disable=W0707
9192
raise FlatteningError(
9293
"Invalid ref at path '{}': {}".format(ref_path, str(e))
9394
)
@@ -190,4 +191,5 @@ def _find_subschema_by_ref(self, ref_path):
190191
try:
191192
return traverse(self._full_schema, ref_path)
192193
except (LookupError, ValueError):
194+
# pylint: disable=W0707
193195
raise FlatteningError("Invalid ref: {}".format(ref_path))

0 commit comments

Comments
 (0)