-
Notifications
You must be signed in to change notification settings - Fork 2
/
store_test.go
207 lines (181 loc) · 5.41 KB
/
store_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
package stream
import (
"context"
"testing"
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
"github.com/google/go-cmp/cmp"
)
func TestGetStateNotFoundIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
// Arrange.
name := createLocalTable(t)
defer deleteLocalTable(t, name)
s, err := NewStore(name, "Average", WithRegion(region), WithClient(testClient))
if err != nil {
t.Fatalf("failed to create store: %v", err)
}
as := &AverageState{}
// Act.
_, err = s.Get("id", as)
// Assert.
if err == nil {
t.Error("expected ErrStateNotFound, got nil")
}
if diff := cmp.Diff(ErrStateNotFound.Error(), err.Error()); diff != "" {
t.Error(diff)
}
}
func TestPutStateIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
// Arrange.
name := createLocalTable(t)
defer deleteLocalTable(t, name)
s, err := NewStore(name, "Average", WithRegion(region), WithClient(testClient))
if err != nil {
t.Fatalf("failed to create store: %v", err)
}
as := &AverageState{}
// Act.
err = s.Put("id", 0, as, nil, nil)
// Assert.
if err != nil {
t.Errorf("unexpected error writing initial state: %v", err)
}
}
func TestPutStateWithHistoryIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
// Arrange.
name := createLocalTable(t)
defer deleteLocalTable(t, name)
s, err := NewStore(name, "Average", WithRegion(region), WithClient(testClient), WithPersistStateHistory(true))
if err != nil {
t.Fatalf("failed to create store: %v", err)
}
as := &AverageState{}
// Act.
err = s.Put("id", 0, as, nil, nil)
if err != nil {
t.Errorf("unexpected error writing initial state: %v", err)
}
err = s.Put("id", 1, as, nil, nil)
if err != nil {
t.Errorf("unexpected error writing updated state: %v", err)
}
}
func TestPutStateCannotOverwriteIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
// Arrange.
name := createLocalTable(t)
defer deleteLocalTable(t, name)
s, err := NewStore(name, "Average", WithRegion(region), WithClient(testClient))
if err != nil {
t.Fatalf("failed to create store: %v", err)
}
as := &AverageState{}
err = s.Put("id", 0, as, nil, nil)
if err != nil {
t.Errorf("unexpected error writing initial state: %v", err)
}
// Act.
err = s.Put("id", 0, as, nil, nil)
if err != ErrOptimisticConcurrency {
t.Errorf("expected error overwriting an existing version number, but got: %v", err)
}
}
// AliasedAverageState is used to test the JSON encoding. We need to use a
// different (or aliased) type to AverageState as attributevalue.Encoder.Encode
// uses a cache internally when looking up the attribute name to use, in order
// to prevent repeated calls the reflect.TypeOf. This has the unfortunate
// side-effect of causing this test fail as the other tests run first and the
// cache gets populated with the raw field names rather than the one specified
// in the json struct tag. It has the other unfortunate side-effect of deleting
// HOURS from life trying to understand why this test would fail with
// AverageState but not another identical type!
type AliasedAverageState struct {
AverageState
}
func (s *AliasedAverageState) Process(event InboundEvent) (outbound []OutboundEvent, err error) {
return s.AverageState.Process(event)
}
func TestJSONCodecIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
// Arrange.
name := createLocalTable(t)
defer deleteLocalTable(t, name)
s, err := NewStore(name, "Average", WithRegion(region), WithClient(testClient), WithCodecTag("json"))
if err != nil {
t.Fatalf("failed to create store: %v", err)
}
as := AliasedAverageState{AverageState: AverageState{Sum: 1}}
if err != nil {
t.Errorf("failed to encode: %v", err)
}
// Act.
err = s.Put("id", 0, &as, nil, nil)
// Assert.
if err != nil {
t.Errorf("unexpected error writing initial state: %v", err)
}
// Ensure state was marshalled using JSON struct tags
out, err := s.Client.GetItem(context.Background(), &dynamodb.GetItemInput{
TableName: &name,
Key: map[string]types.AttributeValue{
"_pk": &types.AttributeValueMemberS{Value: "Average/id"},
"_sk": &types.AttributeValueMemberS{Value: "STATE"},
},
})
if err != nil {
t.Errorf("unexpected error getting item: %v", err)
}
if _, ok := out.Item["sum"]; !ok {
t.Errorf("unexpected attribute name %q, but it wasn't found: %v", "sum", out.Item)
}
}
func TestGetStateIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
// Arrange.
name := createLocalTable(t)
defer deleteLocalTable(t, name)
s, err := NewStore(name, "Average", WithRegion(region), WithClient(testClient))
if err != nil {
t.Fatalf("failed to create store: %v", err)
}
initial := &AverageState{
Sum: 1,
Count: 1,
Value: 1,
}
err = s.Put("id", 0, initial, nil, nil)
if err != nil {
t.Fatalf("unexpected error writing initial state: %v", err)
}
// Act.
retrieved := &AverageState{}
sequence, err := s.Get("id", retrieved)
if err != nil {
t.Errorf("unexpected error getting state from DB: %v", err)
}
// Assert.
if sequence != 1 {
t.Errorf("expected incremented sequence, got %d", sequence)
}
if initial.Sum != retrieved.Sum {
t.Errorf("expected sums to match, but got %d and %d", initial.Sum, retrieved.Sum)
}
if diff := cmp.Diff(initial, retrieved); diff != "" {
t.Error(diff)
}
}