From 790abc85cb3ffc798861bcc2d188fb226be1cd07 Mon Sep 17 00:00:00 2001 From: Peter Hamilton Date: Fri, 5 Apr 2019 12:04:34 -0400 Subject: [PATCH] Update the GetAttributeList payloads to support KMIP 2.0 This change updates the GetAttributeList payloads to support KMIP 2.0 features, including swapping out Attribute Names for the Attribute Reference structure in the response payload. Unit tests have been added to cover these changes. --- .../messages/payloads/get_attribute_list.py | 83 ++++- .../payloads/test_get_attribute_list.py | 306 ++++++++++++++++-- 2 files changed, 346 insertions(+), 43 deletions(-) diff --git a/kmip/core/messages/payloads/get_attribute_list.py b/kmip/core/messages/payloads/get_attribute_list.py index c1eff8e..aed190a 100644 --- a/kmip/core/messages/payloads/get_attribute_list.py +++ b/kmip/core/messages/payloads/get_attribute_list.py @@ -17,6 +17,7 @@ import six from kmip.core import enums from kmip.core import exceptions +from kmip.core import objects from kmip.core import primitives from kmip.core import utils @@ -284,16 +285,50 @@ class GetAttributeListResponsePayload(primitives.Struct): ) names = list() - while self.is_tag_next(enums.Tags.ATTRIBUTE_NAME, local_buffer): - name = primitives.TextString(tag=enums.Tags.ATTRIBUTE_NAME) - name.read(local_buffer, kmip_version=kmip_version) - names.append(name) - if len(names) == 0: - raise exceptions.InvalidKmipEncoding( - "The GetAttributeList response payload encoding is missing " - "the attribute names." - ) - self._attribute_names = names + if kmip_version < enums.KMIPVersion.KMIP_2_0: + while self.is_tag_next(enums.Tags.ATTRIBUTE_NAME, local_buffer): + name = primitives.TextString(tag=enums.Tags.ATTRIBUTE_NAME) + name.read(local_buffer, kmip_version=kmip_version) + names.append(name) + if len(names) == 0: + raise exceptions.InvalidKmipEncoding( + "The GetAttributeList response payload encoding is " + "missing the attribute names." + ) + self._attribute_names = names + else: + while self.is_tag_next( + enums.Tags.ATTRIBUTE_REFERENCE, + local_buffer + ): + if self.is_type_next(enums.Types.STRUCTURE, local_buffer): + reference = objects.AttributeReference() + reference.read(local_buffer, kmip_version=kmip_version) + names.append( + primitives.TextString( + value=reference.attribute_name, + tag=enums.Tags.ATTRIBUTE_NAME + ) + ) + elif self.is_type_next(enums.Types.ENUMERATION, local_buffer): + reference = primitives.Enumeration( + enums.Tags, + tag=enums.Tags.ATTRIBUTE_REFERENCE + ) + reference.read(local_buffer, kmip_version=kmip_version) + name = enums.convert_attribute_tag_to_name(reference.value) + names.append( + primitives.TextString( + value=name, + tag=enums.Tags.ATTRIBUTE_NAME + ) + ) + else: + raise exceptions.InvalidKmipEncoding( + "The GetAttributeList response payload encoding " + "contains an invalid AttributeReference type." + ) + self._attribute_names = names self.is_oversized(local_buffer) @@ -328,8 +363,32 @@ class GetAttributeListResponsePayload(primitives.Struct): ) if self._attribute_names: - for attribute_name in self._attribute_names: - attribute_name.write(local_buffer, kmip_version=kmip_version) + if kmip_version < enums.KMIPVersion.KMIP_2_0: + for attribute_name in self._attribute_names: + attribute_name.write( + local_buffer, + kmip_version=kmip_version + ) + else: + # NOTE (ph) This approach simplifies backwards compatible + # issues but limits easy support for Attribute + # Reference structures going forward, specifically + # limiting the use of VendorIdentification for + # custom attributes. If custom attributes need to + # be retrieved using the GetAttributeList operation + # for KMIP 2.0 applications this code will need to + # change. + for attribute_name in self._attribute_names: + t = enums.convert_attribute_name_to_tag( + attribute_name.value + ) + e = primitives.Enumeration( + enums.Tags, + value=t, + tag=enums.Tags.ATTRIBUTE_REFERENCE + ) + e.write(local_buffer, kmip_version=kmip_version) + else: raise exceptions.InvalidField( "The GetAttributeList response payload is missing the " diff --git a/kmip/tests/unit/core/messages/payloads/test_get_attribute_list.py b/kmip/tests/unit/core/messages/payloads/test_get_attribute_list.py index 6f68f14..658358a 100644 --- a/kmip/tests/unit/core/messages/payloads/test_get_attribute_list.py +++ b/kmip/tests/unit/core/messages/payloads/test_get_attribute_list.py @@ -33,12 +33,20 @@ class TestGetAttributeListRequestPayload(testtools.TestCase): # Encodings taken from Sections 3.1.4 of the KMIP 1.1 testing # documentation. + # + # This encoding matches the following set of values: + # Request Payload + # Unique Identifier - b4faee10-aa2a-4446-8ad4-0881f3422959 self.full_encoding = utils.BytearrayStream( - b'\x42\x00\x79\x01\x00\x00\x00\x30\x42\x00\x94\x07\x00\x00\x00\x24' + b'\x42\x00\x79\x01\x00\x00\x00\x30' + b'\x42\x00\x94\x07\x00\x00\x00\x24' b'\x62\x34\x66\x61\x65\x65\x31\x30\x2D\x61\x61\x32\x61\x2D\x34\x34' b'\x34\x36\x2D\x38\x61\x64\x34\x2D\x30\x38\x38\x31\x66\x33\x34\x32' b'\x32\x39\x35\x39\x00\x00\x00\x00' ) + + # This encoding matches the following set of values: + # Request Payload self.empty_encoding = utils.BytearrayStream( b'\x42\x00\x79\x01\x00\x00\x00\x00' ) @@ -318,59 +326,190 @@ class TestGetAttributeListResponsePayload(testtools.TestCase): # Encodings taken from Sections 3.1.4 of the KMIP 1.1 testing # documentation. + # + # This encoding matches the following set of values: + # Response Payload + # Unique Identifier - b4faee10-aa2a-4446-8ad4-0881f3422959 + # Attribute Name - Cryptographic Length + # Attribute Name - Cryptographic Algorithm + # Attribute Name - State + # Attribute Name - Digest + # Attribute Name - Lease Time + # Attribute Name - Initial Date + # Attribute Name - Unique Identifier + # Attribute Name - Name + # Attribute Name - Cryptographic Usage Mask + # Attribute Name - Object Type + # Attribute Name - Contact Information + # Attribute Name - Last Change Date self.full_encoding = utils.BytearrayStream( - b'\x42\x00\x7C\x01\x00\x00\x01\x60\x42\x00\x94\x07\x00\x00\x00\x24' + b'\x42\x00\x7C\x01\x00\x00\x01\x60' + b'\x42\x00\x94\x07\x00\x00\x00\x24' b'\x62\x34\x66\x61\x65\x65\x31\x30\x2D\x61\x61\x32\x61\x2D\x34\x34' b'\x34\x36\x2D\x38\x61\x64\x34\x2D\x30\x38\x38\x31\x66\x33\x34\x32' - b'\x32\x39\x35\x39\x00\x00\x00\x00\x42\x00\x0A\x07\x00\x00\x00\x14' + b'\x32\x39\x35\x39\x00\x00\x00\x00' + b'\x42\x00\x0A\x07\x00\x00\x00\x14' b'\x43\x72\x79\x70\x74\x6F\x67\x72\x61\x70\x68\x69\x63\x20\x4C\x65' - b'\x6E\x67\x74\x68\x00\x00\x00\x00\x42\x00\x0A\x07\x00\x00\x00\x17' + b'\x6E\x67\x74\x68\x00\x00\x00\x00' + b'\x42\x00\x0A\x07\x00\x00\x00\x17' b'\x43\x72\x79\x70\x74\x6F\x67\x72\x61\x70\x68\x69\x63\x20\x41\x6C' - b'\x67\x6F\x72\x69\x74\x68\x6D\x00\x42\x00\x0A\x07\x00\x00\x00\x05' - b'\x53\x74\x61\x74\x65\x00\x00\x00\x42\x00\x0A\x07\x00\x00\x00\x06' - b'\x44\x69\x67\x65\x73\x74\x00\x00\x42\x00\x0A\x07\x00\x00\x00\x0A' + b'\x67\x6F\x72\x69\x74\x68\x6D\x00' + b'\x42\x00\x0A\x07\x00\x00\x00\x05\x53\x74\x61\x74\x65\x00\x00\x00' + b'\x42\x00\x0A\x07\x00\x00\x00\x06\x44\x69\x67\x65\x73\x74\x00\x00' + b'\x42\x00\x0A\x07\x00\x00\x00\x0A' b'\x4C\x65\x61\x73\x65\x20\x54\x69\x6D\x65\x00\x00\x00\x00\x00\x00' - b'\x42\x00\x0A\x07\x00\x00\x00\x0C\x49\x6E\x69\x74\x69\x61\x6C\x20' - b'\x44\x61\x74\x65\x00\x00\x00\x00\x42\x00\x0A\x07\x00\x00\x00\x11' + b'\x42\x00\x0A\x07\x00\x00\x00\x0C' + b'\x49\x6E\x69\x74\x69\x61\x6C\x20\x44\x61\x74\x65\x00\x00\x00\x00' + b'\x42\x00\x0A\x07\x00\x00\x00\x11' b'\x55\x6E\x69\x71\x75\x65\x20\x49\x64\x65\x6E\x74\x69\x66\x69\x65' - b'\x72\x00\x00\x00\x00\x00\x00\x00\x42\x00\x0A\x07\x00\x00\x00\x04' - b'\x4E\x61\x6D\x65\x00\x00\x00\x00\x42\x00\x0A\x07\x00\x00\x00\x18' + b'\x72\x00\x00\x00\x00\x00\x00\x00' + b'\x42\x00\x0A\x07\x00\x00\x00\x04\x4E\x61\x6D\x65\x00\x00\x00\x00' + b'\x42\x00\x0A\x07\x00\x00\x00\x18' b'\x43\x72\x79\x70\x74\x6F\x67\x72\x61\x70\x68\x69\x63\x20\x55\x73' - b'\x61\x67\x65\x20\x4D\x61\x73\x6B\x42\x00\x0A\x07\x00\x00\x00\x0B' + b'\x61\x67\x65\x20\x4D\x61\x73\x6B' + b'\x42\x00\x0A\x07\x00\x00\x00\x0B' b'\x4F\x62\x6A\x65\x63\x74\x20\x54\x79\x70\x65\x00\x00\x00\x00\x00' - b'\x42\x00\x0A\x07\x00\x00\x00\x13\x43\x6F\x6E\x74\x61\x63\x74\x20' - b'\x49\x6E\x66\x6F\x72\x6D\x61\x74\x69\x6F\x6E\x00\x00\x00\x00\x00' - b'\x42\x00\x0A\x07\x00\x00\x00\x10\x4C\x61\x73\x74\x20\x43\x68\x61' - b'\x6E\x67\x65\x20\x44\x61\x74\x65' + b'\x42\x00\x0A\x07\x00\x00\x00\x13' + b'\x43\x6F\x6E\x74\x61\x63\x74\x20\x49\x6E\x66\x6F\x72\x6D\x61\x74' + b'\x69\x6F\x6E\x00\x00\x00\x00\x00' + b'\x42\x00\x0A\x07\x00\x00\x00\x10' + b'\x4C\x61\x73\x74\x20\x43\x68\x61\x6E\x67\x65\x20\x44\x61\x74\x65' ) + + # Encodings taken from Sections 3.1.4 of the KMIP 1.1 testing + # documentation. + # + # This encoding matches the following set of values: + # Response Payload + # Attribute Name - Cryptographic Length + # Attribute Name - Cryptographic Algorithm + # Attribute Name - State + # Attribute Name - Digest + # Attribute Name - Lease Time + # Attribute Name - Initial Date + # Attribute Name - Unique Identifier + # Attribute Name - Name + # Attribute Name - Cryptographic Usage Mask + # Attribute Name - Object Type + # Attribute Name - Contact Information + # Attribute Name - Last Change Date self.encoding_sans_unique_identifier = utils.BytearrayStream( - b'\x42\x00\x7C\x01\x00\x00\x01\x30\x42\x00\x0A\x07\x00\x00\x00\x14' + b'\x42\x00\x7C\x01\x00\x00\x01\x30' + b'\x42\x00\x0A\x07\x00\x00\x00\x14' b'\x43\x72\x79\x70\x74\x6F\x67\x72\x61\x70\x68\x69\x63\x20\x4C\x65' - b'\x6E\x67\x74\x68\x00\x00\x00\x00\x42\x00\x0A\x07\x00\x00\x00\x17' + b'\x6E\x67\x74\x68\x00\x00\x00\x00' + b'\x42\x00\x0A\x07\x00\x00\x00\x17' b'\x43\x72\x79\x70\x74\x6F\x67\x72\x61\x70\x68\x69\x63\x20\x41\x6C' - b'\x67\x6F\x72\x69\x74\x68\x6D\x00\x42\x00\x0A\x07\x00\x00\x00\x05' - b'\x53\x74\x61\x74\x65\x00\x00\x00\x42\x00\x0A\x07\x00\x00\x00\x06' - b'\x44\x69\x67\x65\x73\x74\x00\x00\x42\x00\x0A\x07\x00\x00\x00\x0A' + b'\x67\x6F\x72\x69\x74\x68\x6D\x00' + b'\x42\x00\x0A\x07\x00\x00\x00\x05\x53\x74\x61\x74\x65\x00\x00\x00' + b'\x42\x00\x0A\x07\x00\x00\x00\x06\x44\x69\x67\x65\x73\x74\x00\x00' + b'\x42\x00\x0A\x07\x00\x00\x00\x0A' b'\x4C\x65\x61\x73\x65\x20\x54\x69\x6D\x65\x00\x00\x00\x00\x00\x00' - b'\x42\x00\x0A\x07\x00\x00\x00\x0C\x49\x6E\x69\x74\x69\x61\x6C\x20' - b'\x44\x61\x74\x65\x00\x00\x00\x00\x42\x00\x0A\x07\x00\x00\x00\x11' + b'\x42\x00\x0A\x07\x00\x00\x00\x0C' + b'\x49\x6E\x69\x74\x69\x61\x6C\x20\x44\x61\x74\x65\x00\x00\x00\x00' + b'\x42\x00\x0A\x07\x00\x00\x00\x11' b'\x55\x6E\x69\x71\x75\x65\x20\x49\x64\x65\x6E\x74\x69\x66\x69\x65' - b'\x72\x00\x00\x00\x00\x00\x00\x00\x42\x00\x0A\x07\x00\x00\x00\x04' - b'\x4E\x61\x6D\x65\x00\x00\x00\x00\x42\x00\x0A\x07\x00\x00\x00\x18' + b'\x72\x00\x00\x00\x00\x00\x00\x00' + b'\x42\x00\x0A\x07\x00\x00\x00\x04\x4E\x61\x6D\x65\x00\x00\x00\x00' + b'\x42\x00\x0A\x07\x00\x00\x00\x18' b'\x43\x72\x79\x70\x74\x6F\x67\x72\x61\x70\x68\x69\x63\x20\x55\x73' - b'\x61\x67\x65\x20\x4D\x61\x73\x6B\x42\x00\x0A\x07\x00\x00\x00\x0B' + b'\x61\x67\x65\x20\x4D\x61\x73\x6B' + b'\x42\x00\x0A\x07\x00\x00\x00\x0B' b'\x4F\x62\x6A\x65\x63\x74\x20\x54\x79\x70\x65\x00\x00\x00\x00\x00' - b'\x42\x00\x0A\x07\x00\x00\x00\x13\x43\x6F\x6E\x74\x61\x63\x74\x20' - b'\x49\x6E\x66\x6F\x72\x6D\x61\x74\x69\x6F\x6E\x00\x00\x00\x00\x00' - b'\x42\x00\x0A\x07\x00\x00\x00\x10\x4C\x61\x73\x74\x20\x43\x68\x61' - b'\x6E\x67\x65\x20\x44\x61\x74\x65' + b'\x42\x00\x0A\x07\x00\x00\x00\x13' + b'\x43\x6F\x6E\x74\x61\x63\x74\x20\x49\x6E\x66\x6F\x72\x6D\x61\x74' + b'\x69\x6F\x6E\x00\x00\x00\x00\x00' + b'\x42\x00\x0A\x07\x00\x00\x00\x10' + b'\x4C\x61\x73\x74\x20\x43\x68\x61\x6E\x67\x65\x20\x44\x61\x74\x65' ) + + # Encodings taken from Sections 3.1.4 of the KMIP 1.1 testing + # documentation. + # + # This encoding matches the following set of values: + # Response Payload + # Unique Identifier - b4faee10-aa2a-4446-8ad4-0881f3422959 self.encoding_sans_attribute_names = utils.BytearrayStream( - b'\x42\x00\x7C\x01\x00\x00\x00\x30\x42\x00\x94\x07\x00\x00\x00\x24' + b'\x42\x00\x7C\x01\x00\x00\x00\x30' + b'\x42\x00\x94\x07\x00\x00\x00\x24' b'\x62\x34\x66\x61\x65\x65\x31\x30\x2D\x61\x61\x32\x61\x2D\x34\x34' b'\x34\x36\x2D\x38\x61\x64\x34\x2D\x30\x38\x38\x31\x66\x33\x34\x32' b'\x32\x39\x35\x39\x00\x00\x00\x00' ) + + # Encodings adapted from Sections 3.1.2 of the KMIP 1.1 testing + # documentation. Manually converted to the KMIP 2.0 format. + # + # This encoding matches the following set of values: + # Response Payload + # Unique Identifier - 1703250b-4d40-4de2-93a0-c494a1d4ae40 + # Attribute Reference - Object Group + # Attribute Reference - Application Specific Information + # Attribute Reference - Contact Information + self.full_encoding_with_reference_enums = utils.BytearrayStream( + b'\x42\x00\x7C\x01\x00\x00\x00\x60' + b'\x42\x00\x94\x07\x00\x00\x00\x24' + b'\x31\x37\x30\x33\x32\x35\x30\x62\x2D\x34\x64\x34\x30\x2D\x34\x64' + b'\x65\x32\x2D\x39\x33\x61\x30\x2D\x63\x34\x39\x34\x61\x31\x64\x34' + b'\x61\x65\x34\x30\x00\x00\x00\x00' + b'\x42\x01\x3B\x05\x00\x00\x00\x04\x00\x42\x00\x56\x00\x00\x00\x00' + b'\x42\x01\x3B\x05\x00\x00\x00\x04\x00\x42\x00\x04\x00\x00\x00\x00' + b'\x42\x01\x3B\x05\x00\x00\x00\x04\x00\x42\x00\x22\x00\x00\x00\x00' + ) + + # Encodings adapted from Sections 3.1.2 of the KMIP 1.1 testing + # documentation. Manually converted to the KMIP 2.0 format. + # + # This encoding matches the following set of values: + # Response Payload + # Unique Identifier - 1703250b-4d40-4de2-93a0-c494a1d4ae40 + # Attribute Reference + # Vendor Identification - + # Attribute Name - Object Group + # Attribute Reference + # Vendor Identification - + # Attribute Name - Application Specific Information + # Attribute Reference + # Vendor Identification - + # Attribute Name - Contact Information + self.full_encoding_with_reference_structs = utils.BytearrayStream( + b'\x42\x00\x7C\x01\x00\x00\x00\xD0' + b'\x42\x00\x94\x07\x00\x00\x00\x24' + b'\x31\x37\x30\x33\x32\x35\x30\x62\x2D\x34\x64\x34\x30\x2D\x34\x64' + b'\x65\x32\x2D\x39\x33\x61\x30\x2D\x63\x34\x39\x34\x61\x31\x64\x34' + b'\x61\x65\x34\x30\x00\x00\x00\x00' + b'\x42\x01\x3B\x01\x00\x00\x00\x20' + b'\x42\x00\x9D\x07\x00\x00\x00\x00' + b'\x42\x00\x0A\x07\x00\x00\x00\x0C' + b'\x4F\x62\x6A\x65\x63\x74\x20\x47\x72\x6F\x75\x70\x00\x00\x00\x00' + b'\x42\x01\x3B\x01\x00\x00\x00\x30' + b'\x42\x00\x9D\x07\x00\x00\x00\x00' + b'\x42\x00\x0A\x07\x00\x00\x00\x20' + b'\x41\x70\x70\x6C\x69\x63\x61\x74\x69\x6F\x6E\x20\x53\x70\x65\x63' + b'\x69\x66\x69\x63\x20\x49\x6E\x66\x6F\x72\x6D\x61\x74\x69\x6F\x6E' + b'\x42\x01\x3B\x01\x00\x00\x00\x28' + b'\x42\x00\x9D\x07\x00\x00\x00\x00' + b'\x42\x00\x0A\x07\x00\x00\x00\x13' + b'\x43\x6F\x6E\x74\x61\x63\x74\x20\x49\x6E\x66\x6F\x72\x6D\x61\x74' + b'\x69\x6F\x6E\x00\x00\x00\x00\x00' + ) + + # Encodings adapted from Sections 3.1.2 of the KMIP 1.1 testing + # documentation. Manually converted to the KMIP 2.0 format. + # + # This encoding matches the following set of values: + # Response Payload + # Unique Identifier - 1703250b-4d40-4de2-93a0-c494a1d4ae40 + # Attribute Reference - Object Group --> "encoded" as a ByteString + self.invalid_attribute_reference_encoding = utils.BytearrayStream( + b'\x42\x00\x7C\x01\x00\x00\x00\x40' + b'\x42\x00\x94\x07\x00\x00\x00\x24' + b'\x31\x37\x30\x33\x32\x35\x30\x62\x2D\x34\x64\x34\x30\x2D\x34\x64' + b'\x65\x32\x2D\x39\x33\x61\x30\x2D\x63\x34\x39\x34\x61\x31\x64\x34' + b'\x61\x65\x34\x30\x00\x00\x00\x00' + b'\x42\x01\x3B\x08\x00\x00\x00\x04\x00\x42\x00\x56\x00\x00\x00\x00' + ) + self.empty_encoding = utils.BytearrayStream( b'\x42\x00\x7C\x01\x00\x00\x00\x00' ) @@ -583,6 +722,85 @@ class TestGetAttributeListResponsePayload(testtools.TestCase): payload._attribute_names ) + def test_read_kmip_2_0_enums(self): + """ + Test that a GetAttributeList response payload can be read from a data + stream encoded with the KMIP 2.0 format using AttributeReference + enumerations. + """ + payload = payloads.GetAttributeListResponsePayload() + + self.assertEqual(None, payload.unique_identifier) + self.assertEqual(list(), payload.attribute_names) + + payload.read( + self.full_encoding_with_reference_enums, + kmip_version=enums.KMIPVersion.KMIP_2_0 + ) + + self.assertEqual( + "1703250b-4d40-4de2-93a0-c494a1d4ae40", + payload.unique_identifier + ) + self.assertEqual(3, len(payload.attribute_names)) + self.assertEqual( + [ + "Object Group", + "Application Specific Information", + "Contact Information" + ], + payload.attribute_names + ) + + def test_read_kmip_2_0_structs(self): + """ + Test that a GetAttributeList response payload can be read from a data + stream encoded with the KMIP 2.0 format using AttributeReference + structures. + """ + payload = payloads.GetAttributeListResponsePayload() + + self.assertEqual(None, payload.unique_identifier) + self.assertEqual(list(), payload.attribute_names) + + payload.read( + self.full_encoding_with_reference_structs, + kmip_version=enums.KMIPVersion.KMIP_2_0 + ) + + self.assertEqual( + "1703250b-4d40-4de2-93a0-c494a1d4ae40", + payload.unique_identifier + ) + self.assertEqual(3, len(payload.attribute_names)) + self.assertEqual( + [ + "Object Group", + "Application Specific Information", + "Contact Information" + ], + payload.attribute_names + ) + + def test_read_kmip_2_0_invalid_attribute_reference(self): + """ + Test that an InvalidKmipEncoding error is raised during the decoding + of a GetAttributeList response payload when the wrong type is found + for the AttributeReference structure. + """ + payload = payloads.GetAttributeListResponsePayload() + + args = (self.invalid_attribute_reference_encoding, ) + kwargs = {"kmip_version": enums.KMIPVersion.KMIP_2_0} + self.assertRaisesRegex( + exceptions.InvalidKmipEncoding, + "The GetAttributeList response payload encoding contains an " + "invalid AttributeReference type.", + payload.read, + *args, + **kwargs + ) + def test_read_with_no_unique_identifier(self): """ Test that an InvalidKmipEncoding error is raised when a @@ -638,6 +856,32 @@ class TestGetAttributeListResponsePayload(testtools.TestCase): self.assertEqual(len(self.full_encoding), len(stream)) self.assertEqual(str(self.full_encoding), str(stream)) + def test_write_kmip_2_0_enums(self): + """ + Test that a GetAttributeList response payload can be written to a data + stream encoded in the KMIP 2.0 format using AttributeReference + enumerations. + """ + payload = payloads.GetAttributeListResponsePayload( + "1703250b-4d40-4de2-93a0-c494a1d4ae40", + [ + "Object Group", + "Application Specific Information", + "Contact Information" + ] + ) + stream = utils.BytearrayStream() + payload.write(stream, kmip_version=enums.KMIPVersion.KMIP_2_0) + + self.assertEqual( + len(self.full_encoding_with_reference_enums), + len(stream) + ) + self.assertEqual( + str(self.full_encoding_with_reference_enums), + str(stream) + ) + def test_write_with_no_unique_identifier(self): """ Test that an InvalidField error is raised when a GetAttributeList