question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

contract_create_list_success fails when there are writeOnlyProperties

See original GitHub issue

(I could also be misunderstanding the contract, see later. Related: the contract could probably use some extra documentation)

I currently have the following schema and list handler:

{
...
    "properties": {
        "KeyName": { ... },
        "PublicKey": { ... },
        "Fingerprint": { ... }
    },
    "required": [
        "KeyName",
        "PublicKey"
    ],
    "additionalIdentifiers": [
        [
            "/properties/Fingerprint"
        ]
    ],
    "readOnlyProperties": [
        "/properties/Fingerprint"
    ],
    "writeOnlyProperties": [
        "/properties/PublicKey"
    ],
    "createOnlyProperties": [
        "/properties/PublicKey",
        "/properties/KeyName"
    ],
    "primaryIdentifier": [
        "/properties/KeyName"
    ],
    "additionalProperties": false,
...
}
@resource.handler(Action.LIST)
def list_handler(
    session: Optional[SessionProxy],
    request: ResourceHandlerRequest,
    callback_context: MutableMapping[str, Any],
) -> ProgressEvent:
    ec2 = session.client("ec2")  # type: botostubs.EC2
    keypairs = ec2.describe_key_pairs()["KeyPairs"]

    return ProgressEvent(
        status=OperationStatus.SUCCESS,
        resourceModels=[_create_model(x) for x in keypairs],
    )


def _create_model(o: Mapping) -> ResourceModel:
    return ResourceModel(
        KeyName=o["KeyName"],
        Fingerprint=o["KeyFingerprint"],
        # There is no way to get the PublicKey from the EC2 api.
        # That's why it's defined as a writeOnlyProperty in the resource spec:
        PublicKey=None,
    )

If I run cfn test (both with the version from pypi as with the current master branch, commit 06d5fa9dbd9e42016e8b3f8c4fda09be062646b4) I always get a failure of the contract_create_list_success test:

======================================================================= FAILURES =======================================================================
_____________________________________________________________ contract_create_list_success _____________________________________________________________

created_resource = ({'Fingerprint': '51:9a:ab:e6:9d:1c:f4:b9:c7:59:35:f5:0c:4c:06:8e', 'KeyName': '-', 'PublicKey': 'ssh-rsa AAAAB3NzaC1y...x0MGuK7VLppPvoozQVIi3zmGFcfjgou/WhkwUQy0GOo7RSeEQl20zluqn/7/uwkqapM3utXl1AFYxce7eA12whV2G0ByJLVZEKs40tNX Ben@Cloudar'})
resource_client = <rpdk.core.contract.resource_client.ResourceClient object at 0x10476f750>

    @pytest.mark.create
    @pytest.mark.list
    def contract_create_list_success(created_resource, resource_client):
        created_model, _request = created_resource
        models = test_list_success(resource_client, created_model)
>       assert created_model in models
E       AssertionError: assert {'Fingerprint': '51:9a:ab:e6:9d:1c:f4:b9:c7:59:35:f5:0c:4c:06:8e', 'KeyName': '-', 'PublicKey': 'ssh-rsa AAAAB3NzaC1yc...ux0MGuK7VLppPvoozQVIi3zmGFcfjgou/WhkwUQy0GOo7RSeEQl20zluqn/7/uwkqapM3utXl1AFYxce7eA12whV2G0ByJLVZEKs40tNX Ben@Cloudar'} in [{'Fingerprint': '51:9a:ab:e6:9d:1c:f4:b9:c7:59:35:f5:0c:4c:06:8e', 'KeyName': '-', 'PublicKey': None}]

/Users/ben/.local/share/virtualenvs/cloudformation-samples-riS8wOWn/lib/python3.7/site-packages/rpdk/core/contract/suite/handler_create.py:64: AssertionError

I would expect the test / contract to ignore all writeOnlyProperties when doing the list command.

(this is the part where I may be misunderstanding the contract, because:)

If I get the PublicKey (= a writeOnlyProperty) from the model, I can make the test succeed, but that feels wrong. I can’t always guarantee that this property has not been changed outside of CloudFormation (in this example I could do that by looking at the Fingerprint, but for other resources I might not have that kind of relationship available).

@resource.handler(Action.LIST)
def list_handler(
    session: Optional[SessionProxy],
    request: ResourceHandlerRequest,
    callback_context: MutableMapping[str, Any],
) -> ProgressEvent:
    model = request.desiredResourceState
    ec2 = session.client("ec2")  # type: botostubs.EC2
    keypairs = ec2.describe_key_pairs()["KeyPairs"]

    return ProgressEvent(
        status=OperationStatus.SUCCESS,
        resourceModels=[_create_model(x, model) for x in keypairs],
    )


def _create_model(o: Mapping, model: ResourceModel) -> ResourceModel:

    if model.KeyName == o["KeyName"]:
        public_key = model.PublicKey
    else:
        public_key = None
    return ResourceModel(
        KeyName=o["KeyName"],
        Fingerprint=o["KeyFingerprint"],
        # There is no way to get the PublicKey from the EC2 api.
        # That's why it's defined as a writeOnlyProperty in the resource spec:
        PublicKey=public_key,
    )

is this a bug in the test, or am I not understanding the expected behaviour (related: is there more documentation about the contract than the source code of the tests)?

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:5 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
jotompkicommented, Dec 16, 2019

Yes @ikben we are addressing some issues with writeOnly properties in the above PR. However, In the above test contract_create_list_success, the returned model from a successful create is taken and we ensure that the same model is returned in the list call. I suspect that the issue might be related to some sort of mismatch between the model returned by your create handler and the ones returned by the list handler. Does your model from create return writeOnlyProperties?

Also agree we need to add some more documentation around the contract of these handlers

1reaction
rjlohancommented, Dec 16, 2019

Yeah we are working on fixing the handling of writeOnlyProperties in the contract tests. @jotompki posted a PR against the schema to start with: https://github.com/aws-cloudformation/aws-cloudformation-resource-schema/pull/64

Read more comments on GitHub >

github_iconTop Results From Across the Web

Readonly properties changing on update causing contract ...
Motivation for Change When running contract tests for a resource that has a read-only property that is modified automatically during an ...
Read more >
WCF DataContract with readonly properties - Stack Overflow
The service fails to load due to a problem with serialization. Is there a way to make readonly properties on a WCF DataContract?...
Read more >
TypeError: "x" is read-only - JavaScript - MDN Web Docs
The JavaScript strict mode-only exception "is read-only" occurs when a global variable or object property that was assigned to is a read-only property....
Read more >
PHP 8.1: readonly properties - Stitcher.io
In cases where all properties of you class are readonly (which often happens with DTOs or VOs), you can mark the class itself...
Read more >
Is guaranteeing immutability a justification for exposing a field ...
There isn't much advantage gained over a property without a public setter, ... and it's a compiler error anyway to pass a readonly...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found