From a26c845a766b45ceabd87c17c0801d191650f0d4 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 17 Jan 2020 16:43:55 -0500 Subject: [PATCH] use a DefaultRecord for unregistered PayloadTypes instead of returning an error if we don't have a registered Record for a given PayloadType, we can have a catch-all DefaultRecord type that just preserves the original payload as a []byte --- record/record.go | 40 +++++++++++++++++++++++++--------------- record/record_test.go | 15 +++++++++++---- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/record/record.go b/record/record.go index cb645fe..5a489de 100644 --- a/record/record.go +++ b/record/record.go @@ -1,17 +1,8 @@ package record -import ( - "errors" - "reflect" -) +import "reflect" -var ( - // ErrPayloadTypeNotRegistered is returned from ConsumeEnvelope when the Envelope's - // PayloadType does not match any registered Record types. - ErrPayloadTypeNotRegistered = errors.New("payload type is not registered") - - payloadTypeRegistry = make(map[string]reflect.Type) -) +var payloadTypeRegistry = make(map[string]reflect.Type) // Record represents a data type that can be used as the payload of an Envelope. // The Record interface defines the methods used to marshal and unmarshal a Record @@ -32,14 +23,33 @@ type Record interface { UnmarshalRecord([]byte) error } +// DefaultRecord contains the payload of an Envelope whose PayloadType field +// does not match any registered Record type. The Contents field contains +// the unprocessed Envelope payload. +type DefaultRecord struct { + Contents []byte +} + +func (r *DefaultRecord) MarshalRecord() ([]byte, error) { + return r.Contents, nil +} + +func (r *DefaultRecord) UnmarshalRecord(data []byte) error { + r.Contents = make([]byte, len(data)) + copy(r.Contents, data) + return nil +} + // RegisterPayloadType associates a binary payload type identifier with a concrete // Record type. This is used to automatically unmarshal Record payloads from Envelopes // when using ConsumeEnvelope, and to automatically marshal Records and determine the // correct PayloadType when calling MakeEnvelopeWithRecord. // -// Callers must provide an instance of the record type to be registered, which must be -// a pointer type. Registration should be done in the init function of the package -// where the Record type is defined: +// To register a Record type, provide the payload type identifier and an +// empty instance of the Record type. +// +// Registration should be done in the init function of the package where the +// Record type is defined: // // package hello_record // @@ -70,7 +80,7 @@ func unmarshalRecordPayload(payloadType []byte, payloadBytes []byte) (Record, er func blankRecordForPayloadType(payloadType []byte) (Record, error) { valueType, ok := payloadTypeRegistry[string(payloadType)] if !ok { - return nil, ErrPayloadTypeNotRegistered + return &DefaultRecord{}, nil } val := reflect.New(valueType) diff --git a/record/record_test.go b/record/record_test.go index 1e2b92a..62c1036 100644 --- a/record/record_test.go +++ b/record/record_test.go @@ -21,10 +21,17 @@ func (p *testPayload) UnmarshalRecord(bytes []byte) error { } func TestUnmarshalPayload(t *testing.T) { - t.Run("fails if payload type is unregistered", func(t *testing.T) { - _, err := unmarshalRecordPayload([]byte("unknown type"), []byte{}) - if err != ErrPayloadTypeNotRegistered { - t.Error("Expected error when unmarshalling payload with unregistered payload type") + t.Run("returns DefaultRecord if payload type is unregistered", func(t *testing.T) { + rec, err := unmarshalRecordPayload([]byte("unknown type"), []byte("hello world")) + if err != nil { + t.Error(err) + } + defaultRec, ok := rec.(*DefaultRecord) + if !ok { + t.Error("expected unregistered PayloadType to be unmarshalled as DefaultRecord") + } + if !bytes.Equal(defaultRec.Contents, []byte("hello world")) { + t.Error("unexpected alteration of record") } })