From 6d56fcd26f202c99e9172ee0cb4d240e610363c1 Mon Sep 17 00:00:00 2001 From: Johan Brandhorst-Satzkorn Date: Fri, 8 Apr 2022 16:01:00 -0400 Subject: [PATCH] feat(subtypes): Add new transformation registration option This allows the user to register a custom transformation callback for a specific protobuf message, in cases where the transformation is sufficiently complex for it to be cumbersome to formalise the logic through protobuf options. --- .../gen/testing/attribute/attribute.pb.go | 690 +++++++++++------- .../testing/attribute/v1/attribute.proto | 10 + internal/types/subtypes/interceptor.go | 20 +- internal/types/subtypes/interceptor_test.go | 87 +++ internal/types/subtypes/transformations.go | 83 +++ 5 files changed, 609 insertions(+), 281 deletions(-) create mode 100644 internal/types/subtypes/transformations.go diff --git a/internal/gen/testing/attribute/attribute.pb.go b/internal/gen/testing/attribute/attribute.pb.go index da0a789aa..7d51194c9 100644 --- a/internal/gen/testing/attribute/attribute.pb.go +++ b/internal/gen/testing/attribute/attribute.pb.go @@ -294,6 +294,102 @@ func (x *TestNoOneOf) GetAttributes() *structpb.Struct { return nil } +type TestCustomTransformation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SomeRandomId string `protobuf:"bytes,1,opt,name=some_random_id,json=someRandomId,proto3" json:"some_random_id,omitempty"` + SecondaryId string `protobuf:"bytes,2,opt,name=secondary_id,json=secondaryId,proto3" json:"secondary_id,omitempty"` + // Types that are assignable to Attrs: + // *TestCustomTransformation_Attributes + // *TestCustomTransformation_SubResourceAttributes + Attrs isTestCustomTransformation_Attrs `protobuf_oneof:"attrs"` +} + +func (x *TestCustomTransformation) Reset() { + *x = TestCustomTransformation{} + if protoimpl.UnsafeEnabled { + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TestCustomTransformation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TestCustomTransformation) ProtoMessage() {} + +func (x *TestCustomTransformation) ProtoReflect() protoreflect.Message { + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TestCustomTransformation.ProtoReflect.Descriptor instead. +func (*TestCustomTransformation) Descriptor() ([]byte, []int) { + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{4} +} + +func (x *TestCustomTransformation) GetSomeRandomId() string { + if x != nil { + return x.SomeRandomId + } + return "" +} + +func (x *TestCustomTransformation) GetSecondaryId() string { + if x != nil { + return x.SecondaryId + } + return "" +} + +func (m *TestCustomTransformation) GetAttrs() isTestCustomTransformation_Attrs { + if m != nil { + return m.Attrs + } + return nil +} + +func (x *TestCustomTransformation) GetAttributes() *structpb.Struct { + if x, ok := x.GetAttrs().(*TestCustomTransformation_Attributes); ok { + return x.Attributes + } + return nil +} + +func (x *TestCustomTransformation) GetSubResourceAttributes() *TestSubResourceAttributes { + if x, ok := x.GetAttrs().(*TestCustomTransformation_SubResourceAttributes); ok { + return x.SubResourceAttributes + } + return nil +} + +type isTestCustomTransformation_Attrs interface { + isTestCustomTransformation_Attrs() +} + +type TestCustomTransformation_Attributes struct { + Attributes *structpb.Struct `protobuf:"bytes,10,opt,name=attributes,proto3,oneof"` +} + +type TestCustomTransformation_SubResourceAttributes struct { + SubResourceAttributes *TestSubResourceAttributes `protobuf:"bytes,20,opt,name=sub_resource_attributes,json=subResourceAttributes,proto3,oneof"` +} + +func (*TestCustomTransformation_Attributes) isTestCustomTransformation_Attrs() {} + +func (*TestCustomTransformation_SubResourceAttributes) isTestCustomTransformation_Attrs() {} + type TestListResourceRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -303,7 +399,7 @@ type TestListResourceRequest struct { func (x *TestListResourceRequest) Reset() { *x = TestListResourceRequest{} if protoimpl.UnsafeEnabled { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[4] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -316,7 +412,7 @@ func (x *TestListResourceRequest) String() string { func (*TestListResourceRequest) ProtoMessage() {} func (x *TestListResourceRequest) ProtoReflect() protoreflect.Message { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[4] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -329,7 +425,7 @@ func (x *TestListResourceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use TestListResourceRequest.ProtoReflect.Descriptor instead. func (*TestListResourceRequest) Descriptor() ([]byte, []int) { - return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{4} + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{5} } type TestListResourceResponse struct { @@ -343,7 +439,7 @@ type TestListResourceResponse struct { func (x *TestListResourceResponse) Reset() { *x = TestListResourceResponse{} if protoimpl.UnsafeEnabled { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[5] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -356,7 +452,7 @@ func (x *TestListResourceResponse) String() string { func (*TestListResourceResponse) ProtoMessage() {} func (x *TestListResourceResponse) ProtoReflect() protoreflect.Message { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[5] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -369,7 +465,7 @@ func (x *TestListResourceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use TestListResourceResponse.ProtoReflect.Descriptor instead. func (*TestListResourceResponse) Descriptor() ([]byte, []int) { - return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{5} + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{6} } func (x *TestListResourceResponse) GetItems() []*TestResource { @@ -390,7 +486,7 @@ type TestGetResourceRequest struct { func (x *TestGetResourceRequest) Reset() { *x = TestGetResourceRequest{} if protoimpl.UnsafeEnabled { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[6] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -403,7 +499,7 @@ func (x *TestGetResourceRequest) String() string { func (*TestGetResourceRequest) ProtoMessage() {} func (x *TestGetResourceRequest) ProtoReflect() protoreflect.Message { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[6] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -416,7 +512,7 @@ func (x *TestGetResourceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use TestGetResourceRequest.ProtoReflect.Descriptor instead. func (*TestGetResourceRequest) Descriptor() ([]byte, []int) { - return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{6} + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{7} } func (x *TestGetResourceRequest) GetId() string { @@ -437,7 +533,7 @@ type TestGetResourceResponse struct { func (x *TestGetResourceResponse) Reset() { *x = TestGetResourceResponse{} if protoimpl.UnsafeEnabled { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[7] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -450,7 +546,7 @@ func (x *TestGetResourceResponse) String() string { func (*TestGetResourceResponse) ProtoMessage() {} func (x *TestGetResourceResponse) ProtoReflect() protoreflect.Message { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[7] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -463,7 +559,7 @@ func (x *TestGetResourceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use TestGetResourceResponse.ProtoReflect.Descriptor instead. func (*TestGetResourceResponse) Descriptor() ([]byte, []int) { - return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{7} + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{8} } func (x *TestGetResourceResponse) GetItem() *TestResource { @@ -484,7 +580,7 @@ type TestCreateResourceRequest struct { func (x *TestCreateResourceRequest) Reset() { *x = TestCreateResourceRequest{} if protoimpl.UnsafeEnabled { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[8] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -497,7 +593,7 @@ func (x *TestCreateResourceRequest) String() string { func (*TestCreateResourceRequest) ProtoMessage() {} func (x *TestCreateResourceRequest) ProtoReflect() protoreflect.Message { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[8] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -510,7 +606,7 @@ func (x *TestCreateResourceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use TestCreateResourceRequest.ProtoReflect.Descriptor instead. func (*TestCreateResourceRequest) Descriptor() ([]byte, []int) { - return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{8} + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{9} } func (x *TestCreateResourceRequest) GetItem() *TestResource { @@ -531,7 +627,7 @@ type TestCreateResourceResponse struct { func (x *TestCreateResourceResponse) Reset() { *x = TestCreateResourceResponse{} if protoimpl.UnsafeEnabled { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[9] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -544,7 +640,7 @@ func (x *TestCreateResourceResponse) String() string { func (*TestCreateResourceResponse) ProtoMessage() {} func (x *TestCreateResourceResponse) ProtoReflect() protoreflect.Message { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[9] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -557,7 +653,7 @@ func (x *TestCreateResourceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use TestCreateResourceResponse.ProtoReflect.Descriptor instead. func (*TestCreateResourceResponse) Descriptor() ([]byte, []int) { - return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{9} + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{10} } func (x *TestCreateResourceResponse) GetItem() *TestResource { @@ -580,7 +676,7 @@ type TestUpdateResourceRequest struct { func (x *TestUpdateResourceRequest) Reset() { *x = TestUpdateResourceRequest{} if protoimpl.UnsafeEnabled { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[10] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -593,7 +689,7 @@ func (x *TestUpdateResourceRequest) String() string { func (*TestUpdateResourceRequest) ProtoMessage() {} func (x *TestUpdateResourceRequest) ProtoReflect() protoreflect.Message { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[10] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -606,7 +702,7 @@ func (x *TestUpdateResourceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use TestUpdateResourceRequest.ProtoReflect.Descriptor instead. func (*TestUpdateResourceRequest) Descriptor() ([]byte, []int) { - return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{10} + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{11} } func (x *TestUpdateResourceRequest) GetId() string { @@ -641,7 +737,7 @@ type TestUpdateResourceResponse struct { func (x *TestUpdateResourceResponse) Reset() { *x = TestUpdateResourceResponse{} if protoimpl.UnsafeEnabled { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[11] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -654,7 +750,7 @@ func (x *TestUpdateResourceResponse) String() string { func (*TestUpdateResourceResponse) ProtoMessage() {} func (x *TestUpdateResourceResponse) ProtoReflect() protoreflect.Message { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[11] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -667,7 +763,7 @@ func (x *TestUpdateResourceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use TestUpdateResourceResponse.ProtoReflect.Descriptor instead. func (*TestUpdateResourceResponse) Descriptor() ([]byte, []int) { - return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{11} + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{12} } func (x *TestUpdateResourceResponse) GetItem() *TestResource { @@ -688,7 +784,7 @@ type TestRequestNoItem struct { func (x *TestRequestNoItem) Reset() { *x = TestRequestNoItem{} if protoimpl.UnsafeEnabled { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[12] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -701,7 +797,7 @@ func (x *TestRequestNoItem) String() string { func (*TestRequestNoItem) ProtoMessage() {} func (x *TestRequestNoItem) ProtoReflect() protoreflect.Message { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[12] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -714,7 +810,7 @@ func (x *TestRequestNoItem) ProtoReflect() protoreflect.Message { // Deprecated: Use TestRequestNoItem.ProtoReflect.Descriptor instead. func (*TestRequestNoItem) Descriptor() ([]byte, []int) { - return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{12} + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{13} } func (x *TestRequestNoItem) GetName() string { @@ -735,7 +831,7 @@ type TestRequestItemNotMessage struct { func (x *TestRequestItemNotMessage) Reset() { *x = TestRequestItemNotMessage{} if protoimpl.UnsafeEnabled { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[13] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -748,7 +844,7 @@ func (x *TestRequestItemNotMessage) String() string { func (*TestRequestItemNotMessage) ProtoMessage() {} func (x *TestRequestItemNotMessage) ProtoReflect() protoreflect.Message { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[13] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -761,7 +857,7 @@ func (x *TestRequestItemNotMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use TestRequestItemNotMessage.ProtoReflect.Descriptor instead. func (*TestRequestItemNotMessage) Descriptor() ([]byte, []int) { - return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{13} + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{14} } func (x *TestRequestItemNotMessage) GetItem() string { @@ -782,7 +878,7 @@ type TestItemNoType struct { func (x *TestItemNoType) Reset() { *x = TestItemNoType{} if protoimpl.UnsafeEnabled { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[14] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -795,7 +891,7 @@ func (x *TestItemNoType) String() string { func (*TestItemNoType) ProtoMessage() {} func (x *TestItemNoType) ProtoReflect() protoreflect.Message { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[14] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -808,7 +904,7 @@ func (x *TestItemNoType) ProtoReflect() protoreflect.Message { // Deprecated: Use TestItemNoType.ProtoReflect.Descriptor instead. func (*TestItemNoType) Descriptor() ([]byte, []int) { - return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{14} + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{15} } func (x *TestItemNoType) GetId() string { @@ -829,7 +925,7 @@ type TestRequestItemNoType struct { func (x *TestRequestItemNoType) Reset() { *x = TestRequestItemNoType{} if protoimpl.UnsafeEnabled { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[15] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -842,7 +938,7 @@ func (x *TestRequestItemNoType) String() string { func (*TestRequestItemNoType) ProtoMessage() {} func (x *TestRequestItemNoType) ProtoReflect() protoreflect.Message { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[15] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -855,7 +951,7 @@ func (x *TestRequestItemNoType) ProtoReflect() protoreflect.Message { // Deprecated: Use TestRequestItemNoType.ProtoReflect.Descriptor instead. func (*TestRequestItemNoType) Descriptor() ([]byte, []int) { - return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{15} + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{16} } func (x *TestRequestItemNoType) GetItem() *TestItemNoType { @@ -880,7 +976,7 @@ type TestNoItemAttributes struct { func (x *TestNoItemAttributes) Reset() { *x = TestNoItemAttributes{} if protoimpl.UnsafeEnabled { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[16] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -893,7 +989,7 @@ func (x *TestNoItemAttributes) String() string { func (*TestNoItemAttributes) ProtoMessage() {} func (x *TestNoItemAttributes) ProtoReflect() protoreflect.Message { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[16] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -906,7 +1002,7 @@ func (x *TestNoItemAttributes) ProtoReflect() protoreflect.Message { // Deprecated: Use TestNoItemAttributes.ProtoReflect.Descriptor instead. func (*TestNoItemAttributes) Descriptor() ([]byte, []int) { - return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{16} + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{17} } func (x *TestNoItemAttributes) GetId() string { @@ -964,7 +1060,7 @@ type TestCreateNoOneOfRequest struct { func (x *TestCreateNoOneOfRequest) Reset() { *x = TestCreateNoOneOfRequest{} if protoimpl.UnsafeEnabled { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[17] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -977,7 +1073,7 @@ func (x *TestCreateNoOneOfRequest) String() string { func (*TestCreateNoOneOfRequest) ProtoMessage() {} func (x *TestCreateNoOneOfRequest) ProtoReflect() protoreflect.Message { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[17] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -990,7 +1086,7 @@ func (x *TestCreateNoOneOfRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use TestCreateNoOneOfRequest.ProtoReflect.Descriptor instead. func (*TestCreateNoOneOfRequest) Descriptor() ([]byte, []int) { - return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{17} + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{18} } func (x *TestCreateNoOneOfRequest) GetItem() *TestNoOneOf { @@ -1012,7 +1108,7 @@ type TestUpdateNoOneOfRequest struct { func (x *TestUpdateNoOneOfRequest) Reset() { *x = TestUpdateNoOneOfRequest{} if protoimpl.UnsafeEnabled { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[18] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1025,7 +1121,7 @@ func (x *TestUpdateNoOneOfRequest) String() string { func (*TestUpdateNoOneOfRequest) ProtoMessage() {} func (x *TestUpdateNoOneOfRequest) ProtoReflect() protoreflect.Message { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[18] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1038,7 +1134,7 @@ func (x *TestUpdateNoOneOfRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use TestUpdateNoOneOfRequest.ProtoReflect.Descriptor instead. func (*TestUpdateNoOneOfRequest) Descriptor() ([]byte, []int) { - return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{18} + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{19} } func (x *TestUpdateNoOneOfRequest) GetId() string { @@ -1066,7 +1162,7 @@ type TestResponseNoItem struct { func (x *TestResponseNoItem) Reset() { *x = TestResponseNoItem{} if protoimpl.UnsafeEnabled { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[19] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1079,7 +1175,7 @@ func (x *TestResponseNoItem) String() string { func (*TestResponseNoItem) ProtoMessage() {} func (x *TestResponseNoItem) ProtoReflect() protoreflect.Message { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[19] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1092,7 +1188,7 @@ func (x *TestResponseNoItem) ProtoReflect() protoreflect.Message { // Deprecated: Use TestResponseNoItem.ProtoReflect.Descriptor instead. func (*TestResponseNoItem) Descriptor() ([]byte, []int) { - return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{19} + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{20} } func (x *TestResponseNoItem) GetName() string { @@ -1113,7 +1209,7 @@ type TestResponseItemNotMessage struct { func (x *TestResponseItemNotMessage) Reset() { *x = TestResponseItemNotMessage{} if protoimpl.UnsafeEnabled { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[20] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1126,7 +1222,7 @@ func (x *TestResponseItemNotMessage) String() string { func (*TestResponseItemNotMessage) ProtoMessage() {} func (x *TestResponseItemNotMessage) ProtoReflect() protoreflect.Message { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[20] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1139,7 +1235,7 @@ func (x *TestResponseItemNotMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use TestResponseItemNotMessage.ProtoReflect.Descriptor instead. func (*TestResponseItemNotMessage) Descriptor() ([]byte, []int) { - return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{20} + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{21} } func (x *TestResponseItemNotMessage) GetItem() string { @@ -1160,7 +1256,7 @@ type TestResponseItemNoType struct { func (x *TestResponseItemNoType) Reset() { *x = TestResponseItemNoType{} if protoimpl.UnsafeEnabled { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[21] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1173,7 +1269,7 @@ func (x *TestResponseItemNoType) String() string { func (*TestResponseItemNoType) ProtoMessage() {} func (x *TestResponseItemNoType) ProtoReflect() protoreflect.Message { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[21] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1186,7 +1282,7 @@ func (x *TestResponseItemNoType) ProtoReflect() protoreflect.Message { // Deprecated: Use TestResponseItemNoType.ProtoReflect.Descriptor instead. func (*TestResponseItemNoType) Descriptor() ([]byte, []int) { - return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{21} + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{22} } func (x *TestResponseItemNoType) GetItem() *TestItemNoType { @@ -1207,7 +1303,7 @@ type TestCreateNoOneOfResponse struct { func (x *TestCreateNoOneOfResponse) Reset() { *x = TestCreateNoOneOfResponse{} if protoimpl.UnsafeEnabled { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[22] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1220,7 +1316,7 @@ func (x *TestCreateNoOneOfResponse) String() string { func (*TestCreateNoOneOfResponse) ProtoMessage() {} func (x *TestCreateNoOneOfResponse) ProtoReflect() protoreflect.Message { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[22] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1233,7 +1329,7 @@ func (x *TestCreateNoOneOfResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use TestCreateNoOneOfResponse.ProtoReflect.Descriptor instead. func (*TestCreateNoOneOfResponse) Descriptor() ([]byte, []int) { - return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{22} + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{23} } func (x *TestCreateNoOneOfResponse) GetItem() *TestNoOneOf { @@ -1254,7 +1350,7 @@ type TestUpdateNoOneOfResponse struct { func (x *TestUpdateNoOneOfResponse) Reset() { *x = TestUpdateNoOneOfResponse{} if protoimpl.UnsafeEnabled { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[23] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1267,7 +1363,7 @@ func (x *TestUpdateNoOneOfResponse) String() string { func (*TestUpdateNoOneOfResponse) ProtoMessage() {} func (x *TestUpdateNoOneOfResponse) ProtoReflect() protoreflect.Message { - mi := &file_testing_attribute_v1_attribute_proto_msgTypes[23] + mi := &file_testing_attribute_v1_attribute_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1280,7 +1376,7 @@ func (x *TestUpdateNoOneOfResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use TestUpdateNoOneOfResponse.ProtoReflect.Descriptor instead. func (*TestUpdateNoOneOfResponse) Descriptor() ([]byte, []int) { - return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{23} + return file_testing_attribute_v1_attribute_proto_rawDescGZIP(), []int{24} } func (x *TestUpdateNoOneOfResponse) GetItem() *TestNoOneOf { @@ -1340,159 +1436,176 @@ var file_testing_attribute_v1_attribute_proto_rawDesc = []byte{ 0x75, 0x74, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x22, - 0x19, 0x0a, 0x17, 0x54, 0x65, 0x73, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x54, 0x0a, 0x18, 0x54, 0x65, - 0x73, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, - 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, - 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, - 0x22, 0x28, 0x0a, 0x16, 0x54, 0x65, 0x73, 0x74, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x51, 0x0a, 0x17, 0x54, 0x65, - 0x73, 0x74, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x53, 0x0a, - 0x19, 0x54, 0x65, 0x73, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x36, 0x0a, 0x04, 0x69, 0x74, - 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, - 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x04, 0x69, 0x74, - 0x65, 0x6d, 0x22, 0x54, 0x0a, 0x1a, 0x54, 0x65, 0x73, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x36, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, - 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, - 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0xa1, 0x01, 0x0a, 0x19, 0x54, 0x65, 0x73, - 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x36, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x3c, - 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, - 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x22, 0x54, 0x0a, 0x1a, - 0x54, 0x65, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x92, 0x02, 0x0a, 0x18, 0x54, 0x65, 0x73, 0x74, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0e, + 0x73, 0x6f, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x6f, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, + 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x5f, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, + 0x61, 0x72, 0x79, 0x49, 0x64, 0x12, 0x39, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, + 0x74, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, + 0x63, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, + 0x12, 0x69, 0x0a, 0x17, 0x73, 0x75, 0x62, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x62, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x65, 0x73, 0x48, 0x00, 0x52, 0x15, 0x73, 0x75, 0x62, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x42, 0x07, 0x0a, 0x05, 0x61, + 0x74, 0x74, 0x72, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x54, 0x65, 0x73, 0x74, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, + 0x54, 0x0a, 0x18, 0x54, 0x65, 0x73, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x05, 0x69, + 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x73, + 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x05, + 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x28, 0x0a, 0x16, 0x54, 0x65, 0x73, 0x74, 0x47, 0x65, 0x74, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, + 0x51, 0x0a, 0x17, 0x54, 0x65, 0x73, 0x74, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x04, 0x69, 0x74, - 0x65, 0x6d, 0x22, 0x27, 0x0a, 0x11, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4e, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x2f, 0x0a, 0x19, 0x54, - 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x4e, 0x6f, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x20, 0x0a, 0x0e, - 0x54, 0x65, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x4e, 0x6f, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x51, - 0x0a, 0x15, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x74, 0x65, - 0x6d, 0x4e, 0x6f, 0x54, 0x79, 0x70, 0x65, 0x12, 0x38, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, - 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, - 0x74, 0x49, 0x74, 0x65, 0x6d, 0x4e, 0x6f, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x69, 0x74, 0x65, - 0x6d, 0x22, 0xf4, 0x01, 0x0a, 0x14, 0x54, 0x65, 0x73, 0x74, 0x4e, 0x6f, 0x49, 0x74, 0x65, 0x6d, - 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x46, 0x0a, 0x0a, 0x61, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x42, 0x0b, 0x9a, 0xe3, 0x29, 0x07, 0x64, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x65, 0x73, 0x12, 0x7b, 0x0a, 0x17, 0x73, 0x75, 0x62, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x14, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x53, + 0x65, 0x6d, 0x22, 0x53, 0x0a, 0x19, 0x54, 0x65, 0x73, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x36, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x54, 0x0a, 0x1a, 0x54, 0x65, 0x73, 0x74, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0xa1, 0x01, + 0x0a, 0x19, 0x54, 0x65, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x36, 0x0a, 0x04, 0x69, + 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x73, 0x74, + 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x04, 0x69, + 0x74, 0x65, 0x6d, 0x12, 0x3c, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, + 0x73, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, + 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, + 0x6b, 0x22, 0x54, 0x0a, 0x1a, 0x54, 0x65, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x36, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x27, 0x0a, 0x11, 0x54, 0x65, 0x73, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x22, 0x2f, 0x0a, 0x19, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, + 0x74, 0x65, 0x6d, 0x4e, 0x6f, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x74, 0x65, + 0x6d, 0x22, 0x20, 0x0a, 0x0e, 0x54, 0x65, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x4e, 0x6f, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x22, 0x51, 0x0a, 0x15, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x4e, 0x6f, 0x54, 0x79, 0x70, 0x65, 0x12, 0x38, 0x0a, 0x04, + 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74, 0x65, 0x73, + 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x4e, 0x6f, 0x54, 0x79, 0x70, 0x65, + 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0xf4, 0x01, 0x0a, 0x14, 0x54, 0x65, 0x73, 0x74, 0x4e, + 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x46, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x42, 0x0b, 0x9a, 0xe3, + 0x29, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x74, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x7b, 0x0a, 0x17, 0x73, 0x75, 0x62, 0x5f, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x65, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, + 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x62, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, + 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x42, 0x10, 0x9a, 0xe3, 0x29, 0x0c, 0x73, + 0x75, 0x62, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x00, 0x52, 0x15, 0x73, 0x75, 0x62, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, - 0x75, 0x74, 0x65, 0x73, 0x42, 0x10, 0x9a, 0xe3, 0x29, 0x0c, 0x73, 0x75, 0x62, 0x5f, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x00, 0x52, 0x15, 0x73, 0x75, 0x62, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x42, - 0x07, 0x0a, 0x05, 0x61, 0x74, 0x74, 0x72, 0x73, 0x22, 0x51, 0x0a, 0x18, 0x54, 0x65, 0x73, 0x74, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x4f, 0x6e, 0x65, 0x4f, 0x66, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, + 0x75, 0x74, 0x65, 0x73, 0x42, 0x07, 0x0a, 0x05, 0x61, 0x74, 0x74, 0x72, 0x73, 0x22, 0x51, 0x0a, + 0x18, 0x54, 0x65, 0x73, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x4f, 0x6e, 0x65, + 0x4f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x04, 0x69, 0x74, 0x65, + 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, + 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, + 0x65, 0x73, 0x74, 0x4e, 0x6f, 0x4f, 0x6e, 0x65, 0x4f, 0x66, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, + 0x22, 0x61, 0x0a, 0x18, 0x54, 0x65, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, + 0x4f, 0x6e, 0x65, 0x4f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x35, 0x0a, 0x04, + 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, 0x73, + 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x4e, 0x6f, 0x4f, 0x6e, 0x65, 0x4f, 0x66, 0x52, 0x04, 0x69, + 0x74, 0x65, 0x6d, 0x22, 0x28, 0x0a, 0x12, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x4e, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x30, 0x0a, + 0x1a, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x49, 0x74, 0x65, + 0x6d, 0x4e, 0x6f, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, + 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, + 0x52, 0x0a, 0x16, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x49, + 0x74, 0x65, 0x6d, 0x4e, 0x6f, 0x54, 0x79, 0x70, 0x65, 0x12, 0x38, 0x0a, 0x04, 0x69, 0x74, 0x65, + 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, + 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, + 0x65, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x4e, 0x6f, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x69, + 0x74, 0x65, 0x6d, 0x22, 0x52, 0x0a, 0x19, 0x54, 0x65, 0x73, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x4e, 0x6f, 0x4f, 0x6e, 0x65, 0x4f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x35, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, + 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, + 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x4e, 0x6f, 0x4f, 0x6e, 0x65, 0x4f, + 0x66, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x52, 0x0a, 0x19, 0x54, 0x65, 0x73, 0x74, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x4f, 0x6e, 0x65, 0x4f, 0x66, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x4e, 0x6f, - 0x4f, 0x6e, 0x65, 0x4f, 0x66, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x61, 0x0a, 0x18, 0x54, - 0x65, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x4f, 0x6e, 0x65, 0x4f, 0x66, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x35, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, - 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, - 0x74, 0x4e, 0x6f, 0x4f, 0x6e, 0x65, 0x4f, 0x66, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x28, - 0x0a, 0x12, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4e, 0x6f, - 0x49, 0x74, 0x65, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x30, 0x0a, 0x1a, 0x54, 0x65, 0x73, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x4e, 0x6f, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x52, 0x0a, 0x16, 0x54, 0x65, - 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x4e, 0x6f, - 0x54, 0x79, 0x70, 0x65, 0x12, 0x38, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x49, 0x74, - 0x65, 0x6d, 0x4e, 0x6f, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x52, - 0x0a, 0x19, 0x54, 0x65, 0x73, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x4f, 0x6e, - 0x65, 0x4f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x69, - 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, 0x73, 0x74, - 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x54, 0x65, 0x73, 0x74, 0x4e, 0x6f, 0x4f, 0x6e, 0x65, 0x4f, 0x66, 0x52, 0x04, 0x69, 0x74, - 0x65, 0x6d, 0x22, 0x52, 0x0a, 0x19, 0x54, 0x65, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x4e, 0x6f, 0x4f, 0x6e, 0x65, 0x4f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x35, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, - 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x4e, 0x6f, 0x4f, 0x6e, 0x65, 0x4f, 0x66, - 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x32, 0xc1, 0x05, 0x0a, 0x13, 0x54, 0x65, 0x73, 0x74, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x9b, - 0x01, 0x0a, 0x10, 0x54, 0x65, 0x73, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x4c, - 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x4c, 0x69, - 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x28, 0x92, 0x41, 0x0b, 0x12, 0x09, 0x54, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x69, - 0x73, 0x74, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x12, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x65, - 0x73, 0x74, 0x2d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0xaf, 0x01, 0x0a, - 0x12, 0x54, 0x65, 0x73, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x12, 0x2f, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x36, 0x92, 0x41, 0x0d, 0x12, 0x0b, 0x54, 0x65, 0x73, - 0x74, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x22, 0x12, - 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0xb4, - 0x01, 0x0a, 0x12, 0x54, 0x65, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2f, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, - 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, - 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, - 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, - 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3b, 0x92, 0x41, 0x0d, 0x12, 0x0b, 0x54, - 0x65, 0x73, 0x74, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, - 0x32, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, - 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0xa2, 0x01, 0x0a, 0x0f, 0x54, 0x65, 0x73, 0x74, 0x47, 0x65, - 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2c, 0x2e, 0x74, 0x65, 0x73, 0x74, - 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x54, 0x65, 0x73, 0x74, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, + 0x4f, 0x6e, 0x65, 0x4f, 0x66, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x32, 0xc1, 0x05, 0x0a, 0x13, + 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x9b, 0x01, 0x0a, 0x10, 0x54, 0x65, 0x73, 0x74, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, + 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x54, 0x65, 0x73, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, - 0x65, 0x73, 0x74, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x32, 0x92, 0x41, 0x0a, 0x12, 0x08, 0x54, 0x65, 0x73, - 0x74, 0x20, 0x67, 0x65, 0x74, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x12, 0x17, 0x2f, 0x76, 0x31, - 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, - 0x7b, 0x69, 0x64, 0x7d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x42, 0x50, 0x5a, 0x46, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, - 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, - 0x2f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x3b, 0x61, 0x74, 0x74, 0x72, 0x69, - 0x62, 0x75, 0x74, 0x65, 0xa2, 0xe3, 0x29, 0x04, 0x74, 0x65, 0x73, 0x74, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x73, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x28, 0x92, 0x41, 0x0b, 0x12, 0x09, 0x54, 0x65, + 0x73, 0x74, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x12, 0x12, 0x2f, + 0x76, 0x31, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x12, 0xaf, 0x01, 0x0a, 0x12, 0x54, 0x65, 0x73, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2f, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, + 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x54, 0x65, 0x73, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x74, 0x65, 0x73, 0x74, + 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x54, 0x65, 0x73, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x36, 0x92, 0x41, 0x0d, + 0x12, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x20, 0x22, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, + 0x74, 0x65, 0x6d, 0x12, 0xb4, 0x01, 0x0a, 0x12, 0x54, 0x65, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2f, 0x2e, 0x74, 0x65, 0x73, + 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x74, 0x65, + 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3b, 0x92, + 0x41, 0x0d, 0x12, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x32, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2d, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x04, + 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0xa2, 0x01, 0x0a, 0x0f, 0x54, + 0x65, 0x73, 0x74, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2c, + 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, + 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x74, + 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x32, 0x92, 0x41, 0x0a, + 0x12, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x67, 0x65, 0x74, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, + 0x12, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x42, + 0x50, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, + 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, + 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x74, 0x65, + 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x3b, + 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0xa2, 0xe3, 0x29, 0x04, 0x74, 0x65, 0x73, + 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1507,67 +1620,70 @@ func file_testing_attribute_v1_attribute_proto_rawDescGZIP() []byte { return file_testing_attribute_v1_attribute_proto_rawDescData } -var file_testing_attribute_v1_attribute_proto_msgTypes = make([]protoimpl.MessageInfo, 24) +var file_testing_attribute_v1_attribute_proto_msgTypes = make([]protoimpl.MessageInfo, 25) var file_testing_attribute_v1_attribute_proto_goTypes = []interface{}{ (*TestResource)(nil), // 0: testing.attribute.v1.TestResource (*TestSubResourceAttributes)(nil), // 1: testing.attribute.v1.TestSubResourceAttributes (*TestNoAttributes)(nil), // 2: testing.attribute.v1.TestNoAttributes (*TestNoOneOf)(nil), // 3: testing.attribute.v1.TestNoOneOf - (*TestListResourceRequest)(nil), // 4: testing.attribute.v1.TestListResourceRequest - (*TestListResourceResponse)(nil), // 5: testing.attribute.v1.TestListResourceResponse - (*TestGetResourceRequest)(nil), // 6: testing.attribute.v1.TestGetResourceRequest - (*TestGetResourceResponse)(nil), // 7: testing.attribute.v1.TestGetResourceResponse - (*TestCreateResourceRequest)(nil), // 8: testing.attribute.v1.TestCreateResourceRequest - (*TestCreateResourceResponse)(nil), // 9: testing.attribute.v1.TestCreateResourceResponse - (*TestUpdateResourceRequest)(nil), // 10: testing.attribute.v1.TestUpdateResourceRequest - (*TestUpdateResourceResponse)(nil), // 11: testing.attribute.v1.TestUpdateResourceResponse - (*TestRequestNoItem)(nil), // 12: testing.attribute.v1.TestRequestNoItem - (*TestRequestItemNotMessage)(nil), // 13: testing.attribute.v1.TestRequestItemNotMessage - (*TestItemNoType)(nil), // 14: testing.attribute.v1.TestItemNoType - (*TestRequestItemNoType)(nil), // 15: testing.attribute.v1.TestRequestItemNoType - (*TestNoItemAttributes)(nil), // 16: testing.attribute.v1.TestNoItemAttributes - (*TestCreateNoOneOfRequest)(nil), // 17: testing.attribute.v1.TestCreateNoOneOfRequest - (*TestUpdateNoOneOfRequest)(nil), // 18: testing.attribute.v1.TestUpdateNoOneOfRequest - (*TestResponseNoItem)(nil), // 19: testing.attribute.v1.TestResponseNoItem - (*TestResponseItemNotMessage)(nil), // 20: testing.attribute.v1.TestResponseItemNotMessage - (*TestResponseItemNoType)(nil), // 21: testing.attribute.v1.TestResponseItemNoType - (*TestCreateNoOneOfResponse)(nil), // 22: testing.attribute.v1.TestCreateNoOneOfResponse - (*TestUpdateNoOneOfResponse)(nil), // 23: testing.attribute.v1.TestUpdateNoOneOfResponse - (*structpb.Struct)(nil), // 24: google.protobuf.Struct - (*fieldmaskpb.FieldMask)(nil), // 25: google.protobuf.FieldMask + (*TestCustomTransformation)(nil), // 4: testing.attribute.v1.TestCustomTransformation + (*TestListResourceRequest)(nil), // 5: testing.attribute.v1.TestListResourceRequest + (*TestListResourceResponse)(nil), // 6: testing.attribute.v1.TestListResourceResponse + (*TestGetResourceRequest)(nil), // 7: testing.attribute.v1.TestGetResourceRequest + (*TestGetResourceResponse)(nil), // 8: testing.attribute.v1.TestGetResourceResponse + (*TestCreateResourceRequest)(nil), // 9: testing.attribute.v1.TestCreateResourceRequest + (*TestCreateResourceResponse)(nil), // 10: testing.attribute.v1.TestCreateResourceResponse + (*TestUpdateResourceRequest)(nil), // 11: testing.attribute.v1.TestUpdateResourceRequest + (*TestUpdateResourceResponse)(nil), // 12: testing.attribute.v1.TestUpdateResourceResponse + (*TestRequestNoItem)(nil), // 13: testing.attribute.v1.TestRequestNoItem + (*TestRequestItemNotMessage)(nil), // 14: testing.attribute.v1.TestRequestItemNotMessage + (*TestItemNoType)(nil), // 15: testing.attribute.v1.TestItemNoType + (*TestRequestItemNoType)(nil), // 16: testing.attribute.v1.TestRequestItemNoType + (*TestNoItemAttributes)(nil), // 17: testing.attribute.v1.TestNoItemAttributes + (*TestCreateNoOneOfRequest)(nil), // 18: testing.attribute.v1.TestCreateNoOneOfRequest + (*TestUpdateNoOneOfRequest)(nil), // 19: testing.attribute.v1.TestUpdateNoOneOfRequest + (*TestResponseNoItem)(nil), // 20: testing.attribute.v1.TestResponseNoItem + (*TestResponseItemNotMessage)(nil), // 21: testing.attribute.v1.TestResponseItemNotMessage + (*TestResponseItemNoType)(nil), // 22: testing.attribute.v1.TestResponseItemNoType + (*TestCreateNoOneOfResponse)(nil), // 23: testing.attribute.v1.TestCreateNoOneOfResponse + (*TestUpdateNoOneOfResponse)(nil), // 24: testing.attribute.v1.TestUpdateNoOneOfResponse + (*structpb.Struct)(nil), // 25: google.protobuf.Struct + (*fieldmaskpb.FieldMask)(nil), // 26: google.protobuf.FieldMask } var file_testing_attribute_v1_attribute_proto_depIdxs = []int32{ - 24, // 0: testing.attribute.v1.TestResource.attributes:type_name -> google.protobuf.Struct + 25, // 0: testing.attribute.v1.TestResource.attributes:type_name -> google.protobuf.Struct 1, // 1: testing.attribute.v1.TestResource.sub_resource_attributes:type_name -> testing.attribute.v1.TestSubResourceAttributes - 24, // 2: testing.attribute.v1.TestNoOneOf.attributes:type_name -> google.protobuf.Struct - 0, // 3: testing.attribute.v1.TestListResourceResponse.items:type_name -> testing.attribute.v1.TestResource - 0, // 4: testing.attribute.v1.TestGetResourceResponse.item:type_name -> testing.attribute.v1.TestResource - 0, // 5: testing.attribute.v1.TestCreateResourceRequest.item:type_name -> testing.attribute.v1.TestResource - 0, // 6: testing.attribute.v1.TestCreateResourceResponse.item:type_name -> testing.attribute.v1.TestResource - 0, // 7: testing.attribute.v1.TestUpdateResourceRequest.item:type_name -> testing.attribute.v1.TestResource - 25, // 8: testing.attribute.v1.TestUpdateResourceRequest.update_mask:type_name -> google.protobuf.FieldMask - 0, // 9: testing.attribute.v1.TestUpdateResourceResponse.item:type_name -> testing.attribute.v1.TestResource - 14, // 10: testing.attribute.v1.TestRequestItemNoType.item:type_name -> testing.attribute.v1.TestItemNoType - 24, // 11: testing.attribute.v1.TestNoItemAttributes.attributes:type_name -> google.protobuf.Struct - 1, // 12: testing.attribute.v1.TestNoItemAttributes.sub_resource_attributes:type_name -> testing.attribute.v1.TestSubResourceAttributes - 3, // 13: testing.attribute.v1.TestCreateNoOneOfRequest.item:type_name -> testing.attribute.v1.TestNoOneOf - 3, // 14: testing.attribute.v1.TestUpdateNoOneOfRequest.item:type_name -> testing.attribute.v1.TestNoOneOf - 14, // 15: testing.attribute.v1.TestResponseItemNoType.item:type_name -> testing.attribute.v1.TestItemNoType - 3, // 16: testing.attribute.v1.TestCreateNoOneOfResponse.item:type_name -> testing.attribute.v1.TestNoOneOf - 3, // 17: testing.attribute.v1.TestUpdateNoOneOfResponse.item:type_name -> testing.attribute.v1.TestNoOneOf - 4, // 18: testing.attribute.v1.TestResourceService.TestListResource:input_type -> testing.attribute.v1.TestListResourceRequest - 8, // 19: testing.attribute.v1.TestResourceService.TestCreateResource:input_type -> testing.attribute.v1.TestCreateResourceRequest - 10, // 20: testing.attribute.v1.TestResourceService.TestUpdateResource:input_type -> testing.attribute.v1.TestUpdateResourceRequest - 6, // 21: testing.attribute.v1.TestResourceService.TestGetResource:input_type -> testing.attribute.v1.TestGetResourceRequest - 5, // 22: testing.attribute.v1.TestResourceService.TestListResource:output_type -> testing.attribute.v1.TestListResourceResponse - 9, // 23: testing.attribute.v1.TestResourceService.TestCreateResource:output_type -> testing.attribute.v1.TestCreateResourceResponse - 11, // 24: testing.attribute.v1.TestResourceService.TestUpdateResource:output_type -> testing.attribute.v1.TestUpdateResourceResponse - 7, // 25: testing.attribute.v1.TestResourceService.TestGetResource:output_type -> testing.attribute.v1.TestGetResourceResponse - 22, // [22:26] is the sub-list for method output_type - 18, // [18:22] is the sub-list for method input_type - 18, // [18:18] is the sub-list for extension type_name - 18, // [18:18] is the sub-list for extension extendee - 0, // [0:18] is the sub-list for field type_name + 25, // 2: testing.attribute.v1.TestNoOneOf.attributes:type_name -> google.protobuf.Struct + 25, // 3: testing.attribute.v1.TestCustomTransformation.attributes:type_name -> google.protobuf.Struct + 1, // 4: testing.attribute.v1.TestCustomTransformation.sub_resource_attributes:type_name -> testing.attribute.v1.TestSubResourceAttributes + 0, // 5: testing.attribute.v1.TestListResourceResponse.items:type_name -> testing.attribute.v1.TestResource + 0, // 6: testing.attribute.v1.TestGetResourceResponse.item:type_name -> testing.attribute.v1.TestResource + 0, // 7: testing.attribute.v1.TestCreateResourceRequest.item:type_name -> testing.attribute.v1.TestResource + 0, // 8: testing.attribute.v1.TestCreateResourceResponse.item:type_name -> testing.attribute.v1.TestResource + 0, // 9: testing.attribute.v1.TestUpdateResourceRequest.item:type_name -> testing.attribute.v1.TestResource + 26, // 10: testing.attribute.v1.TestUpdateResourceRequest.update_mask:type_name -> google.protobuf.FieldMask + 0, // 11: testing.attribute.v1.TestUpdateResourceResponse.item:type_name -> testing.attribute.v1.TestResource + 15, // 12: testing.attribute.v1.TestRequestItemNoType.item:type_name -> testing.attribute.v1.TestItemNoType + 25, // 13: testing.attribute.v1.TestNoItemAttributes.attributes:type_name -> google.protobuf.Struct + 1, // 14: testing.attribute.v1.TestNoItemAttributes.sub_resource_attributes:type_name -> testing.attribute.v1.TestSubResourceAttributes + 3, // 15: testing.attribute.v1.TestCreateNoOneOfRequest.item:type_name -> testing.attribute.v1.TestNoOneOf + 3, // 16: testing.attribute.v1.TestUpdateNoOneOfRequest.item:type_name -> testing.attribute.v1.TestNoOneOf + 15, // 17: testing.attribute.v1.TestResponseItemNoType.item:type_name -> testing.attribute.v1.TestItemNoType + 3, // 18: testing.attribute.v1.TestCreateNoOneOfResponse.item:type_name -> testing.attribute.v1.TestNoOneOf + 3, // 19: testing.attribute.v1.TestUpdateNoOneOfResponse.item:type_name -> testing.attribute.v1.TestNoOneOf + 5, // 20: testing.attribute.v1.TestResourceService.TestListResource:input_type -> testing.attribute.v1.TestListResourceRequest + 9, // 21: testing.attribute.v1.TestResourceService.TestCreateResource:input_type -> testing.attribute.v1.TestCreateResourceRequest + 11, // 22: testing.attribute.v1.TestResourceService.TestUpdateResource:input_type -> testing.attribute.v1.TestUpdateResourceRequest + 7, // 23: testing.attribute.v1.TestResourceService.TestGetResource:input_type -> testing.attribute.v1.TestGetResourceRequest + 6, // 24: testing.attribute.v1.TestResourceService.TestListResource:output_type -> testing.attribute.v1.TestListResourceResponse + 10, // 25: testing.attribute.v1.TestResourceService.TestCreateResource:output_type -> testing.attribute.v1.TestCreateResourceResponse + 12, // 26: testing.attribute.v1.TestResourceService.TestUpdateResource:output_type -> testing.attribute.v1.TestUpdateResourceResponse + 8, // 27: testing.attribute.v1.TestResourceService.TestGetResource:output_type -> testing.attribute.v1.TestGetResourceResponse + 24, // [24:28] is the sub-list for method output_type + 20, // [20:24] is the sub-list for method input_type + 20, // [20:20] is the sub-list for extension type_name + 20, // [20:20] is the sub-list for extension extendee + 0, // [0:20] is the sub-list for field type_name } func init() { file_testing_attribute_v1_attribute_proto_init() } @@ -1625,7 +1741,7 @@ func file_testing_attribute_v1_attribute_proto_init() { } } file_testing_attribute_v1_attribute_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestListResourceRequest); i { + switch v := v.(*TestCustomTransformation); i { case 0: return &v.state case 1: @@ -1637,7 +1753,7 @@ func file_testing_attribute_v1_attribute_proto_init() { } } file_testing_attribute_v1_attribute_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestListResourceResponse); i { + switch v := v.(*TestListResourceRequest); i { case 0: return &v.state case 1: @@ -1649,7 +1765,7 @@ func file_testing_attribute_v1_attribute_proto_init() { } } file_testing_attribute_v1_attribute_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestGetResourceRequest); i { + switch v := v.(*TestListResourceResponse); i { case 0: return &v.state case 1: @@ -1661,7 +1777,7 @@ func file_testing_attribute_v1_attribute_proto_init() { } } file_testing_attribute_v1_attribute_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestGetResourceResponse); i { + switch v := v.(*TestGetResourceRequest); i { case 0: return &v.state case 1: @@ -1673,7 +1789,7 @@ func file_testing_attribute_v1_attribute_proto_init() { } } file_testing_attribute_v1_attribute_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestCreateResourceRequest); i { + switch v := v.(*TestGetResourceResponse); i { case 0: return &v.state case 1: @@ -1685,7 +1801,7 @@ func file_testing_attribute_v1_attribute_proto_init() { } } file_testing_attribute_v1_attribute_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestCreateResourceResponse); i { + switch v := v.(*TestCreateResourceRequest); i { case 0: return &v.state case 1: @@ -1697,7 +1813,7 @@ func file_testing_attribute_v1_attribute_proto_init() { } } file_testing_attribute_v1_attribute_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestUpdateResourceRequest); i { + switch v := v.(*TestCreateResourceResponse); i { case 0: return &v.state case 1: @@ -1709,7 +1825,7 @@ func file_testing_attribute_v1_attribute_proto_init() { } } file_testing_attribute_v1_attribute_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestUpdateResourceResponse); i { + switch v := v.(*TestUpdateResourceRequest); i { case 0: return &v.state case 1: @@ -1721,7 +1837,7 @@ func file_testing_attribute_v1_attribute_proto_init() { } } file_testing_attribute_v1_attribute_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestRequestNoItem); i { + switch v := v.(*TestUpdateResourceResponse); i { case 0: return &v.state case 1: @@ -1733,7 +1849,7 @@ func file_testing_attribute_v1_attribute_proto_init() { } } file_testing_attribute_v1_attribute_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestRequestItemNotMessage); i { + switch v := v.(*TestRequestNoItem); i { case 0: return &v.state case 1: @@ -1745,7 +1861,7 @@ func file_testing_attribute_v1_attribute_proto_init() { } } file_testing_attribute_v1_attribute_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestItemNoType); i { + switch v := v.(*TestRequestItemNotMessage); i { case 0: return &v.state case 1: @@ -1757,7 +1873,7 @@ func file_testing_attribute_v1_attribute_proto_init() { } } file_testing_attribute_v1_attribute_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestRequestItemNoType); i { + switch v := v.(*TestItemNoType); i { case 0: return &v.state case 1: @@ -1769,7 +1885,7 @@ func file_testing_attribute_v1_attribute_proto_init() { } } file_testing_attribute_v1_attribute_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestNoItemAttributes); i { + switch v := v.(*TestRequestItemNoType); i { case 0: return &v.state case 1: @@ -1781,7 +1897,7 @@ func file_testing_attribute_v1_attribute_proto_init() { } } file_testing_attribute_v1_attribute_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestCreateNoOneOfRequest); i { + switch v := v.(*TestNoItemAttributes); i { case 0: return &v.state case 1: @@ -1793,7 +1909,7 @@ func file_testing_attribute_v1_attribute_proto_init() { } } file_testing_attribute_v1_attribute_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestUpdateNoOneOfRequest); i { + switch v := v.(*TestCreateNoOneOfRequest); i { case 0: return &v.state case 1: @@ -1805,7 +1921,7 @@ func file_testing_attribute_v1_attribute_proto_init() { } } file_testing_attribute_v1_attribute_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestResponseNoItem); i { + switch v := v.(*TestUpdateNoOneOfRequest); i { case 0: return &v.state case 1: @@ -1817,7 +1933,7 @@ func file_testing_attribute_v1_attribute_proto_init() { } } file_testing_attribute_v1_attribute_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestResponseItemNotMessage); i { + switch v := v.(*TestResponseNoItem); i { case 0: return &v.state case 1: @@ -1829,7 +1945,7 @@ func file_testing_attribute_v1_attribute_proto_init() { } } file_testing_attribute_v1_attribute_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestResponseItemNoType); i { + switch v := v.(*TestResponseItemNotMessage); i { case 0: return &v.state case 1: @@ -1841,7 +1957,7 @@ func file_testing_attribute_v1_attribute_proto_init() { } } file_testing_attribute_v1_attribute_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestCreateNoOneOfResponse); i { + switch v := v.(*TestResponseItemNoType); i { case 0: return &v.state case 1: @@ -1853,6 +1969,18 @@ func file_testing_attribute_v1_attribute_proto_init() { } } file_testing_attribute_v1_attribute_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TestCreateNoOneOfResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_testing_attribute_v1_attribute_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TestUpdateNoOneOfResponse); i { case 0: return &v.state @@ -1869,7 +1997,11 @@ func file_testing_attribute_v1_attribute_proto_init() { (*TestResource_Attributes)(nil), (*TestResource_SubResourceAttributes)(nil), } - file_testing_attribute_v1_attribute_proto_msgTypes[16].OneofWrappers = []interface{}{ + file_testing_attribute_v1_attribute_proto_msgTypes[4].OneofWrappers = []interface{}{ + (*TestCustomTransformation_Attributes)(nil), + (*TestCustomTransformation_SubResourceAttributes)(nil), + } + file_testing_attribute_v1_attribute_proto_msgTypes[17].OneofWrappers = []interface{}{ (*TestNoItemAttributes_Attributes)(nil), (*TestNoItemAttributes_SubResourceAttributes)(nil), } @@ -1879,7 +2011,7 @@ func file_testing_attribute_v1_attribute_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_testing_attribute_v1_attribute_proto_rawDesc, NumEnums: 0, - NumMessages: 24, + NumMessages: 25, NumExtensions: 0, NumServices: 1, }, diff --git a/internal/proto/testing/attribute/v1/attribute.proto b/internal/proto/testing/attribute/v1/attribute.proto index 0d921d785..4a06544ed 100644 --- a/internal/proto/testing/attribute/v1/attribute.proto +++ b/internal/proto/testing/attribute/v1/attribute.proto @@ -40,6 +40,16 @@ message TestNoOneOf { google.protobuf.Struct attributes = 10; } +message TestCustomTransformation { + string some_random_id = 1; + string secondary_id = 2; + + oneof attrs { + google.protobuf.Struct attributes = 10; + TestSubResourceAttributes sub_resource_attributes = 20; + } +} + service TestResourceService { rpc TestListResource(TestListResourceRequest) returns (TestListResourceResponse) { option (google.api.http) = { diff --git a/internal/types/subtypes/interceptor.go b/internal/types/subtypes/interceptor.go index 77656f203..b9dc9d578 100644 --- a/internal/types/subtypes/interceptor.go +++ b/internal/types/subtypes/interceptor.go @@ -172,6 +172,14 @@ func transformResponseItemAttributes(item proto.Message) error { return convertAttributesToDefault(item, st) } +func transformRequest(msg proto.Message) error { + fqn := msg.ProtoReflect().Descriptor().FullName() + if fn, ok := globalTransformationRegistry.requestTransformationFuncs[fqn]; ok { + return fn(msg) + } + return transformRequestAttributes(msg) +} + // transformResponseAttributes will modify the response proto.Message, setting // any subtype attribute fields into the default structpb.Struct field. It looks // for some specific structure in the proto.Message to identify that it is a @@ -232,6 +240,14 @@ func transformResponseAttributes(res proto.Message) error { return nil } +func transformResponse(msg proto.Message) error { + fqn := msg.ProtoReflect().Descriptor().FullName() + if fn, ok := globalTransformationRegistry.responseTransformationFuncs[fqn]; ok { + return fn(msg) + } + return transformResponseAttributes(msg) +} + // AttributeTransformerInterceptor is a grpc server interceptor that will // transform subtype attributes for requests and responses. This will only // modify requests and responses that adhere to a specific structure and is done @@ -280,7 +296,7 @@ func AttributeTransformerInterceptor(_ context.Context) grpc.UnaryServerIntercep const op = "subtypes.AttributeTransformInterceptor" return func(interceptorCtx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { if reqMsg, ok := req.(proto.Message); ok { - if err := transformRequestAttributes(reqMsg); err != nil { + if err := transformRequest(reqMsg); err != nil { return nil, handlers.InvalidArgumentErrorf("Error in provided request.", map[string]string{"attributes": "Attribute fields do not match the expected format."}) } @@ -289,7 +305,7 @@ func AttributeTransformerInterceptor(_ context.Context) grpc.UnaryServerIntercep res, handlerErr := handler(interceptorCtx, req) if res, ok := res.(proto.Message); ok { - if err := transformResponseAttributes(res); err != nil { + if err := transformResponse(res); err != nil { return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "failed building attribute struct: %v", err) } } diff --git a/internal/types/subtypes/interceptor_test.go b/internal/types/subtypes/interceptor_test.go index 1e2c828f8..086ada728 100644 --- a/internal/types/subtypes/interceptor_test.go +++ b/internal/types/subtypes/interceptor_test.go @@ -588,3 +588,90 @@ func TestTransformResponseAttributes(t *testing.T) { }) } } + +func TestCustomTransformRequest(t *testing.T) { + RegisterRequestTransformationFunc( + &attribute.TestCustomTransformation{}, + func(m proto.Message) error { + msg, ok := m.(*attribute.TestCustomTransformation) + require.True(t, ok, "wrong message passed to request transformation callback") + if msg.SomeRandomId == "some_random_id" && msg.SecondaryId == "secondary_id" { + newAttrs := &attribute.TestSubResourceAttributes{} + err := structToProto(msg.GetAttributes(), newAttrs) + require.NoError(t, err) + msg.Attrs = &attribute.TestCustomTransformation_SubResourceAttributes{ + SubResourceAttributes: newAttrs, + } + } + return nil + }, + ) + request := &attribute.TestCustomTransformation{ + SomeRandomId: "some_random_id", + SecondaryId: "secondary_id", + Attrs: &attribute.TestCustomTransformation_Attributes{ + Attributes: func() *structpb.Struct { + attrs, _ := structpb.NewStruct(map[string]interface{}{ + "name": "test", + }) + return attrs + }(), + }, + } + expected := &attribute.TestCustomTransformation{ + SomeRandomId: "some_random_id", + SecondaryId: "secondary_id", + Attrs: &attribute.TestCustomTransformation_SubResourceAttributes{ + SubResourceAttributes: &attribute.TestSubResourceAttributes{ + Name: "test", + }, + }, + } + + err := transformRequest(request) + require.NoError(t, err) + assert.Empty(t, cmp.Diff(request, expected, protocmp.Transform())) +} + +func TestCustomTransformResponse(t *testing.T) { + RegisterResponseTransformationFunc( + &attribute.TestCustomTransformation{}, + func(m proto.Message) error { + msg, ok := m.(*attribute.TestCustomTransformation) + require.True(t, ok, "wrong message passed to response transformation callback") + if msg.SomeRandomId == "some_random_id" && msg.SecondaryId == "secondary_id" { + newAttrs, err := protoToStruct(msg.GetSubResourceAttributes()) + require.NoError(t, err) + msg.Attrs = &attribute.TestCustomTransformation_Attributes{ + Attributes: newAttrs, + } + } + return nil + }, + ) + response := &attribute.TestCustomTransformation{ + SomeRandomId: "some_random_id", + SecondaryId: "secondary_id", + Attrs: &attribute.TestCustomTransformation_SubResourceAttributes{ + SubResourceAttributes: &attribute.TestSubResourceAttributes{ + Name: "test", + }, + }, + } + expected := &attribute.TestCustomTransformation{ + SomeRandomId: "some_random_id", + SecondaryId: "secondary_id", + Attrs: &attribute.TestCustomTransformation_Attributes{ + Attributes: func() *structpb.Struct { + attrs, _ := structpb.NewStruct(map[string]interface{}{ + "name": "test", + }) + return attrs + }(), + }, + } + + err := transformResponse(response) + require.NoError(t, err) + assert.Empty(t, cmp.Diff(response, expected, protocmp.Transform())) +} diff --git a/internal/types/subtypes/transformations.go b/internal/types/subtypes/transformations.go new file mode 100644 index 000000000..364377d67 --- /dev/null +++ b/internal/types/subtypes/transformations.go @@ -0,0 +1,83 @@ +package subtypes + +import ( + "context" + "fmt" + "sync" + + "github.com/hashicorp/boundary/internal/errors" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" +) + +var globalTransformationRegistry = &transformationRegistry{ + requestTransformationFuncs: make(map[protoreflect.FullName]TransformationFunc), + responseTransformationFuncs: make(map[protoreflect.FullName]TransformationFunc), +} + +// transformationRegistry stores registered request and response +// transformation functions. +type transformationRegistry struct { + requestTransformationFuncs map[protoreflect.FullName]TransformationFunc + responseTransformationFuncs map[protoreflect.FullName]TransformationFunc + + sync.RWMutex +} + +func (r *transformationRegistry) registerRequestTransformationFunc(ctx context.Context, msg proto.Message, transformFn TransformationFunc) error { + r.Lock() + defer r.Unlock() + + fqn := msg.ProtoReflect().Descriptor().FullName() + const op = "subtypes.(transformationRegistry).RegisterRequestTransformationFunc" + if _, present := r.requestTransformationFuncs[fqn]; present { + return errors.New( + ctx, + errors.SubtypeAlreadyRegistered, + op, + fmt.Sprintf("proto type %q already has a request transformation function registered", fqn), + ) + } + r.requestTransformationFuncs[fqn] = transformFn + return nil +} + +func (r *transformationRegistry) registerResponseTransformationFunc(ctx context.Context, msg proto.Message, transformFn TransformationFunc) error { + r.Lock() + defer r.Unlock() + + fqn := msg.ProtoReflect().Descriptor().FullName() + const op = "subtypes.(transformationRegistry).RegisterResponseTransformationFunc" + if _, present := r.responseTransformationFuncs[fqn]; present { + return errors.New( + ctx, + errors.SubtypeAlreadyRegistered, + op, + fmt.Sprintf("proto type %q already has a response transformation function registered", fqn), + ) + } + r.responseTransformationFuncs[fqn] = transformFn + return nil +} + +// TransformationFunc defines the signature used to transform +// protobuf message attributes. The proto.Message is mutated in place. +type TransformationFunc func(proto.Message) error + +// RegisterRequestTransformationFunc registers a transformation function for +// the provided message. The message should be used as a request parameter to +// a service method. The provided callback is guaranteed to only be called with messages +// of the same type as the provided message. +func RegisterRequestTransformationFunc(msg proto.Message, transformFn TransformationFunc) error { + ctx := context.TODO() + return globalTransformationRegistry.registerRequestTransformationFunc(ctx, msg, transformFn) +} + +// RegisterResponseTransformationFunc registers a transformation function for +// the provided message. The message should be used as a response parameter to +// a service method. The provided callback is guaranteed to only be called with messages +// of the same type as the provided message. +func RegisterResponseTransformationFunc(msg proto.Message, transformFn TransformationFunc) error { + ctx := context.TODO() + return globalTransformationRegistry.registerResponseTransformationFunc(ctx, msg, transformFn) +}