go.temporal.io/server/chasm/ref_test.go
195 LOC · 0 covered · 195 uncovered · 0 ranges · 0 concepts · 0 introducers · 0 tests
1
package chasm
2
3
import (
4
"math/rand"
5
"reflect"
6
"testing"
7
8
"github.com/stretchr/testify/require"
9
"github.com/stretchr/testify/suite"
10
persistencespb "go.temporal.io/server/api/persistence/v1"
11
"go.temporal.io/server/common/log"
12
"go.temporal.io/server/common/primitives"
13
"go.temporal.io/server/common/testing/protorequire"
14
"go.uber.org/mock/gomock"
15
)
16
17
type componentRefSuite struct {
18
suite.Suite
19
*require.Assertions
20
protorequire.ProtoAssertions
21
22
controller *gomock.Controller
23
24
registry *Registry
25
}
26
27
func TestComponentRefSuite(t *testing.T) {
28
suite.Run(t, new(componentRefSuite))
29
}
30
31
func (s *componentRefSuite) SetupTest() {
32
// Do this in SetupSubTest() as well, if we have sub tests in this suite.
33
s.Assertions = require.New(s.T())
34
s.ProtoAssertions = protorequire.New(s.T())
35
36
s.controller = gomock.NewController(s.T())
37
38
s.registry = NewRegistry(log.NewTestLogger())
39
err := s.registry.Register(newTestLibrary(s.controller))
40
s.NoError(err)
41
}
42
43
func (s *componentRefSuite) TestArchetypeID() {
44
executionKey := ExecutionKey{
45
NamespaceID: primitives.NewUUID().String(),
46
BusinessID: primitives.NewUUID().String(),
47
RunID: primitives.NewUUID().String(),
48
}
49
ref := NewComponentRef[*TestComponent](executionKey)
50
51
archetypeID, err := ref.ArchetypeID(s.registry)
52
s.NoError(err)
53
54
rc, ok := s.registry.componentOf(reflect.TypeFor[*TestComponent]())
55
s.True(ok)
56
57
s.Equal(rc.componentID, archetypeID)
58
}
59
60
func (s *componentRefSuite) TestNewComponentRefByArchetypeID() {
61
executionKey := ExecutionKey{
62
NamespaceID: primitives.NewUUID().String(),
63
BusinessID: primitives.NewUUID().String(),
64
RunID: primitives.NewUUID().String(),
65
}
66
expectArchetypeID := WorkflowArchetypeID
67
ref := NewComponentRefByArchetypeID(executionKey, expectArchetypeID)
68
69
s.Equal(executionKey, ref.ExecutionKey)
70
71
archetypeID, err := ref.ArchetypeID(s.registry)
72
s.NoError(err)
73
s.Equal(expectArchetypeID, archetypeID)
74
}
75
76
func (s *componentRefSuite) TestSerializeDeserialize() {
77
_, err := DeserializeComponentRef(nil)
78
s.ErrorIs(err, ErrInvalidComponentRef)
79
_, err = DeserializeComponentRef([]byte{})
80
s.ErrorIs(err, ErrInvalidComponentRef)
81
82
executionKey := ExecutionKey{
83
NamespaceID: primitives.NewUUID().String(),
84
BusinessID: primitives.NewUUID().String(),
85
RunID: primitives.NewUUID().String(),
86
}
87
ref := ComponentRef{
88
ExecutionKey: executionKey,
89
executionGoType: reflect.TypeFor[*TestComponent](),
90
executionLastUpdateVT: &persistencespb.VersionedTransition{
91
NamespaceFailoverVersion: rand.Int63(),
92
TransitionCount: rand.Int63(),
93
},
94
componentPath: []string{primitives.NewUUID().String(), primitives.NewUUID().String()},
95
componentInitialVT: &persistencespb.VersionedTransition{
96
NamespaceFailoverVersion: rand.Int63(),
97
TransitionCount: rand.Int63(),
98
},
99
}
100
101
serializedRef, err := ref.Serialize(s.registry)
102
s.NoError(err)
103
104
deserializedRef, err := DeserializeComponentRef(serializedRef)
105
s.NoError(err)
106
107
s.ProtoEqual(ref.executionLastUpdateVT, deserializedRef.executionLastUpdateVT)
108
s.ProtoEqual(ref.componentInitialVT, deserializedRef.componentInitialVT)
109
110
rootRc, ok := s.registry.ComponentFor(&TestComponent{})
111
s.True(ok)
112
s.Equal(rootRc.componentID, deserializedRef.archetypeID)
113
114
s.Equal(ref.ExecutionKey, deserializedRef.ExecutionKey)
115
s.Equal(ref.componentPath, deserializedRef.componentPath)
116
}
117
118
func (s *componentRefSuite) TestForConsistencyLevel() {
119
newRef := func() ComponentRef {
120
return ComponentRef{
121
ExecutionKey: ExecutionKey{
122
NamespaceID: primitives.NewUUID().String(),
123
BusinessID: primitives.NewUUID().String(),
124
RunID: primitives.NewUUID().String(),
125
},
126
archetypeID: WorkflowArchetypeID,
127
executionGoType: reflect.TypeFor[*TestComponent](),
128
executionLastUpdateVT: &persistencespb.VersionedTransition{
129
NamespaceFailoverVersion: rand.Int63(),
130
TransitionCount: rand.Int63(),
131
},
132
componentPath: []string{primitives.NewUUID().String()},
133
componentInitialVT: &persistencespb.VersionedTransition{
134
NamespaceFailoverVersion: rand.Int63(),
135
TransitionCount: rand.Int63(),
136
},
137
}
138
}
139
140
testCases := []struct {
141
name string
142
level RefConsistencyLevel
143
// verify asserts the level-specific expectations on the original (orig) and adjusted refs.
144
verify func(orig, adjusted ComponentRef)
145
}{
146
{
147
name: "ExecutionLastUpdate keeps everything",
148
level: RefConsistencyLevelExecutionLastUpdate,
149
verify: func(orig, adjusted ComponentRef) {
150
// Staleness keyed off the execution's last-update transition; nothing relaxed.
151
s.ProtoEqual(orig.executionLastUpdateVT, adjusted.executionLastUpdateVT)
152
s.ProtoEqual(orig.componentInitialVT, adjusted.componentInitialVT)
153
s.Equal(orig.RunID, adjusted.RunID)
154
},
155
},
156
{
157
name: "ComponentCreation keys staleness off the component creation VT",
158
level: RefConsistencyLevelComponentCreation,
159
verify: func(orig, adjusted ComponentRef) {
160
// The staleness check (Node.IsStale keys off executionLastUpdateVT) now uses the
161
// component's creation transition, so a behind mutable state is still reloaded.
162
s.ProtoEqual(orig.componentInitialVT, adjusted.executionLastUpdateVT)
163
// The creation transition is preserved for the component-identity check, run ID kept.
164
s.ProtoEqual(orig.componentInitialVT, adjusted.componentInitialVT)
165
s.Equal(orig.RunID, adjusted.RunID)
166
},
167
},
168
{
169
name: "CurrentRun drops both VTs and the run ID",
170
level: RefConsistencyLevelCurrentRun,
171
verify: func(orig, adjusted ComponentRef) {
172
s.Nil(adjusted.executionLastUpdateVT)
173
s.Nil(adjusted.componentInitialVT)
174
s.Empty(adjusted.RunID)
175
},
176
},
177
}
178
179
for _, tc := range testCases {
180
s.Run(tc.name, func() {
181
ref := newRef()
182
adjusted, err := ref.forConsistencyLevel(tc.level)
183
s.NoError(err)
184
tc.verify(ref, adjusted)
185
186
// Invariants for every level: path/archetype identity is preserved, and the receiver
187
// is never mutated (value semantics).
188
s.Equal(ref.componentPath, adjusted.componentPath)
189
s.Equal(ref.archetypeID, adjusted.archetypeID)
190
s.NotNil(ref.executionLastUpdateVT)
191
s.NotNil(ref.componentInitialVT)
192
s.NotEmpty(ref.RunID)
193
})
194
}
195
}