Skip to content

Commit 8a62ac2

Browse files
authored
Add unit tests for serializer (#1380)
* Add unit tests for serializer
1 parent a9f6e50 commit 8a62ac2

File tree

2 files changed

+204
-2
lines changed

2 files changed

+204
-2
lines changed

internal/common/serializer/history_serializer.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ func DeserializeBatchEvents(data *shared.DataBlob) ([]*shared.HistoryEvent, erro
107107
return nil, nil
108108
}
109109
var events []*shared.HistoryEvent
110-
if data != nil && len(data.Data) == 0 {
110+
if len(data.Data) == 0 {
111111
return events, nil
112112
}
113113
err := deserialize(data, &events)
@@ -171,7 +171,6 @@ func deserialize(data *shared.DataBlob, target interface{}) error {
171171
err = thriftrwDecode(data.Data, target)
172172
case shared.EncodingTypeJSON: // For backward-compatibility
173173
err = json.Unmarshal(data.Data, target)
174-
175174
}
176175

177176
if err != nil {
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
// Copyright (c) 2017-2021 Uber Technologies Inc.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
// THE SOFTWARE.
20+
21+
package serializer
22+
23+
import (
24+
"reflect"
25+
"testing"
26+
27+
"github.com/stretchr/testify/assert"
28+
"github.com/stretchr/testify/require"
29+
30+
"go.uber.org/cadence/.gen/go/shared"
31+
"go.uber.org/cadence/internal/common"
32+
)
33+
34+
func TestSerializationRoundup(t *testing.T) {
35+
for _, encoding := range []shared.EncodingType{shared.EncodingTypeJSON, shared.EncodingTypeThriftRW} {
36+
t.Run(encoding.String(), func(t *testing.T) {
37+
38+
events := []*shared.HistoryEvent{
39+
{
40+
EventId: common.Int64Ptr(1),
41+
Timestamp: common.Int64Ptr(1),
42+
EventType: common.EventTypePtr(shared.EventTypeActivityTaskCompleted),
43+
Version: common.Int64Ptr(1),
44+
ActivityTaskCompletedEventAttributes: &shared.ActivityTaskCompletedEventAttributes{
45+
Result: []byte("result"),
46+
},
47+
},
48+
}
49+
50+
serialized, err := SerializeBatchEvents(events, encoding)
51+
require.NoError(t, err)
52+
53+
deserialized, err := DeserializeBatchEvents(serialized)
54+
require.NoError(t, err)
55+
56+
assert.Equal(t, events, deserialized)
57+
})
58+
}
59+
}
60+
61+
func TestDeserializeBlobDataToHistoryEvents(t *testing.T) {
62+
events := []*shared.HistoryEvent{
63+
{
64+
EventId: common.Int64Ptr(1),
65+
Timestamp: common.Int64Ptr(1),
66+
EventType: common.EventTypePtr(shared.EventTypeDecisionTaskStarted),
67+
Version: common.Int64Ptr(1),
68+
DecisionTaskStartedEventAttributes: &shared.DecisionTaskStartedEventAttributes{
69+
ScheduledEventId: common.Int64Ptr(1),
70+
},
71+
},
72+
{
73+
EventId: common.Int64Ptr(1),
74+
Timestamp: common.Int64Ptr(1),
75+
EventType: common.EventTypePtr(shared.EventTypeActivityTaskCompleted),
76+
Version: common.Int64Ptr(1),
77+
ActivityTaskCompletedEventAttributes: &shared.ActivityTaskCompletedEventAttributes{
78+
Result: []byte("result"),
79+
},
80+
},
81+
}
82+
83+
serialized, err := SerializeBatchEvents(events, shared.EncodingTypeThriftRW)
84+
require.NoError(t, err)
85+
86+
deserialized, err := DeserializeBlobDataToHistoryEvents([]*shared.DataBlob{serialized}, shared.HistoryEventFilterTypeCloseEvent)
87+
require.NoError(t, err)
88+
89+
assert.Equal(t, events[1], deserialized.Events[0])
90+
}
91+
92+
func TestDeserializeBlobDataToHistoryEvents_failure(t *testing.T) {
93+
for _, tc := range []struct {
94+
name string
95+
serialized *shared.DataBlob
96+
expectedErrString string
97+
}{
98+
{
99+
name: "empty blob",
100+
serialized: &shared.DataBlob{},
101+
expectedErrString: "corrupted history event batch, empty events",
102+
},
103+
{
104+
name: "corrupted blob",
105+
serialized: &shared.DataBlob{Data: []byte("corrupted"), EncodingType: shared.EncodingTypeThriftRW.Ptr()},
106+
expectedErrString: "BadRequestError{Message: Invalid binary encoding version.}",
107+
},
108+
} {
109+
t.Run(tc.name, func(t *testing.T) {
110+
_, err := DeserializeBlobDataToHistoryEvents([]*shared.DataBlob{tc.serialized}, shared.HistoryEventFilterTypeCloseEvent)
111+
assert.ErrorContains(t, err, tc.expectedErrString)
112+
})
113+
}
114+
}
115+
116+
func TestThriftEncodingRoundtrip(t *testing.T) {
117+
for _, tc := range []struct {
118+
input interface{}
119+
}{
120+
{
121+
input: &shared.HistoryEvent{
122+
EventId: common.Int64Ptr(1),
123+
EventType: shared.EventTypeDecisionTaskStarted.Ptr(),
124+
},
125+
},
126+
{
127+
input: &shared.Memo{
128+
Fields: map[string][]byte{"key": []byte("value")},
129+
},
130+
},
131+
{
132+
input: &shared.ResetPoints{
133+
Points: []*shared.ResetPointInfo{
134+
{
135+
BinaryChecksum: common.StringPtr("checksum"),
136+
},
137+
},
138+
},
139+
},
140+
{
141+
input: &shared.BadBinaries{
142+
Binaries: map[string]*shared.BadBinaryInfo{
143+
"key": {
144+
Reason: common.StringPtr("reason"),
145+
},
146+
},
147+
},
148+
},
149+
{
150+
input: &shared.VersionHistories{
151+
CurrentVersionHistoryIndex: common.Int32Ptr(1),
152+
},
153+
},
154+
{
155+
input: nil,
156+
},
157+
} {
158+
name := "nil"
159+
if tc.input != nil {
160+
name = reflect.TypeOf(tc.input).String()
161+
}
162+
t.Run(name, func(t *testing.T) {
163+
serialized, err := thriftrwEncode(tc.input)
164+
require.NoError(t, err)
165+
166+
var deserialized interface{}
167+
if tc.input != nil {
168+
deserialized = createEmptyPointer(tc.input)
169+
err = thriftrwDecode(serialized, deserialized)
170+
require.NoError(t, err)
171+
}
172+
173+
assert.Equal(t, tc.input, deserialized)
174+
})
175+
}
176+
}
177+
178+
func TestSerialization_corner_cases(t *testing.T) {
179+
t.Run("nil", func(t *testing.T) {
180+
res, err := serialize(nil, shared.EncodingTypeThriftRW)
181+
assert.Nil(t, res)
182+
assert.NoError(t, err)
183+
})
184+
t.Run("unsupported encoding", func(t *testing.T) {
185+
_, err := SerializeBatchEvents(nil, -1)
186+
assert.ErrorContains(t, err, "unknown or unsupported encoding type")
187+
})
188+
t.Run("serialization error", func(t *testing.T) {
189+
res, err := Encode(nil)
190+
assert.Nil(t, res)
191+
assert.ErrorIs(t, err, MsgPayloadNotThriftEncoded)
192+
})
193+
}
194+
195+
func createEmptyPointer(input interface{}) interface{} {
196+
inputType := reflect.TypeOf(input)
197+
if inputType.Kind() != reflect.Ptr {
198+
panic("input must be a pointer to a struct")
199+
}
200+
elemType := inputType.Elem()
201+
newInstance := reflect.New(elemType)
202+
return newInstance.Interface()
203+
}

0 commit comments

Comments
 (0)