go.temporal.io/server/tests/namespace_test.go

458 LOC · 0 covered · 458 uncovered · 0 ranges · 0 concepts · 0 introducers · 0 tests

1 package tests
2
3 import (
4 "errors"
5 "fmt"
6 "strconv"
7 "testing"
8 "time"
9
10 "github.com/google/uuid"
11 commonpb "go.temporal.io/api/common/v1"
12 enumspb "go.temporal.io/api/enums/v1"
13 "go.temporal.io/api/operatorservice/v1"
14 "go.temporal.io/api/serviceerror"
15 taskqueuepb "go.temporal.io/api/taskqueue/v1"
16 "go.temporal.io/api/workflowservice/v1"
17 "go.temporal.io/server/chasm"
18 "go.temporal.io/server/common"
19 "go.temporal.io/server/common/dynamicconfig"
20 "go.temporal.io/server/common/persistence"
21 "go.temporal.io/server/common/testing/parallelsuite"
22 "go.temporal.io/server/common/testing/testvars"
23 "go.temporal.io/server/tests/testcore"
24 "google.golang.org/protobuf/types/known/durationpb"
25 )
26
27 type (
28 namespaceTestSuite struct {
29 parallelsuite.Suite[*namespaceTestSuite]
30 }
31 )
32
33 func TestNamespaceSuite(t *testing.T) {
34 parallelsuite.RunLegacySequential(t, &namespaceTestSuite{}) //nolint:staticcheck // SA1019: namespace deletion tests use dedicated worker-service clusters.
35 }
36
37 func (s *namespaceTestSuite) newTestEnv(opts ...testcore.TestOption) *testcore.TestEnv {
38 baseOpts := []testcore.TestOption{
39 testcore.WithWorkerService("namespace deletion tests require the system worker service"),
40 testcore.WithDynamicConfig(dynamicconfig.TransferProcessorUpdateAckInterval, 1*time.Second),
41 testcore.WithDynamicConfig(dynamicconfig.VisibilityProcessorUpdateAckInterval, 1*time.Second),
42 }
43 return testcore.NewEnv(s.T(), append(baseOpts, opts...)...)
44 }
45
46 func (s *namespaceTestSuite) Test_NamespaceDelete_Empty() {
47 env := s.newTestEnv()
48
49 retention := 24 * time.Hour
50 _, err := env.FrontendClient().RegisterNamespace(s.Context(), &workflowservice.RegisterNamespaceRequest{
51 Namespace: "ns_name_san_diego",
52 Description: "Namespace to delete",
53 WorkflowExecutionRetentionPeriod: durationpb.New(retention),
54 HistoryArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
55 VisibilityArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
56 })
57 s.NoError(err)
58
59 descResp, err := env.FrontendClient().DescribeNamespace(s.Context(), &workflowservice.DescribeNamespaceRequest{
60 Namespace: "ns_name_san_diego",
61 })
62 s.NoError(err)
63 nsID := descResp.GetNamespaceInfo().GetId()
64
65 delResp, err := env.OperatorClient().DeleteNamespace(s.Context(), &operatorservice.DeleteNamespaceRequest{
66 Namespace: "ns_name_san_diego",
67 })
68 s.NoError(err)
69 s.Equal("ns_name_san_diego-deleted-"+nsID[:5], delResp.GetDeletedNamespace())
70
71 descResp2, err := env.FrontendClient().DescribeNamespace(s.Context(), &workflowservice.DescribeNamespaceRequest{
72 Id: nsID,
73 })
74 s.NoError(err)
75 s.Equal(enumspb.NAMESPACE_STATE_DELETED, descResp2.GetNamespaceInfo().GetState())
76 s.Eventually(func() bool {
77 _, err := env.FrontendClient().DescribeNamespace(s.Context(), &workflowservice.DescribeNamespaceRequest{
78 Id: nsID,
79 })
80 var notFound *serviceerror.NamespaceNotFound
81 if !errors.As(err, &notFound) {
82 return false
83 }
84
85 return true
86 }, 20*time.Second, time.Second)
87 }
88
89 func (s *namespaceTestSuite) Test_NamespaceDelete_OverrideDelay() {
90 env := s.newTestEnv(testcore.WithDynamicConfig(dynamicconfig.DeleteNamespaceNamespaceDeleteDelay, time.Hour))
91
92 retention := 24 * time.Hour
93 _, err := env.FrontendClient().RegisterNamespace(s.Context(), &workflowservice.RegisterNamespaceRequest{
94 Namespace: "ns_name_san_diego",
95 Description: "Namespace to delete",
96 WorkflowExecutionRetentionPeriod: durationpb.New(retention),
97 HistoryArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
98 VisibilityArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
99 })
100 s.NoError(err)
101
102 descResp, err := env.FrontendClient().DescribeNamespace(s.Context(), &workflowservice.DescribeNamespaceRequest{
103 Namespace: "ns_name_san_diego",
104 })
105 s.NoError(err)
106 nsID := descResp.GetNamespaceInfo().GetId()
107
108 delResp, err := env.OperatorClient().DeleteNamespace(s.Context(), &operatorservice.DeleteNamespaceRequest{
109 Namespace: "ns_name_san_diego",
110 NamespaceDeleteDelay: durationpb.New(0),
111 })
112 s.NoError(err)
113 s.Equal("ns_name_san_diego-deleted-"+nsID[:5], delResp.GetDeletedNamespace())
114
115 descResp2, err := env.FrontendClient().DescribeNamespace(s.Context(), &workflowservice.DescribeNamespaceRequest{
116 Id: nsID,
117 })
118 s.NoError(err)
119 s.Equal(enumspb.NAMESPACE_STATE_DELETED, descResp2.GetNamespaceInfo().GetState())
120 s.Eventually(func() bool {
121 _, err := env.FrontendClient().DescribeNamespace(s.Context(), &workflowservice.DescribeNamespaceRequest{
122 Id: nsID,
123 })
124 var notFound *serviceerror.NamespaceNotFound
125 if !errors.As(err, &notFound) {
126 return false
127 }
128
129 return true
130 }, 20*time.Second, time.Second)
131 }
132
133 func (s *namespaceTestSuite) Test_NamespaceDelete_Empty_WithID() {
134 env := s.newTestEnv()
135
136 retention := 24 * time.Hour
137 _, err := env.FrontendClient().RegisterNamespace(s.Context(), &workflowservice.RegisterNamespaceRequest{
138 Namespace: "ns_name_san_diego",
139 Description: "Namespace to delete",
140 WorkflowExecutionRetentionPeriod: durationpb.New(retention),
141 HistoryArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
142 VisibilityArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
143 })
144 s.NoError(err)
145
146 descResp, err := env.FrontendClient().DescribeNamespace(s.Context(), &workflowservice.DescribeNamespaceRequest{
147 Namespace: "ns_name_san_diego",
148 })
149 s.NoError(err)
150 nsID := descResp.GetNamespaceInfo().GetId()
151
152 delResp, err := env.OperatorClient().DeleteNamespace(s.Context(), &operatorservice.DeleteNamespaceRequest{
153 NamespaceId: nsID,
154 })
155 s.NoError(err)
156 s.Equal("ns_name_san_diego-deleted-"+nsID[:5], delResp.GetDeletedNamespace())
157
158 descResp2, err := env.FrontendClient().DescribeNamespace(s.Context(), &workflowservice.DescribeNamespaceRequest{
159 Id: nsID,
160 })
161 s.NoError(err)
162 s.Equal(enumspb.NAMESPACE_STATE_DELETED, descResp2.GetNamespaceInfo().GetState())
163 s.Eventually(func() bool {
164 _, err := env.FrontendClient().DescribeNamespace(s.Context(), &workflowservice.DescribeNamespaceRequest{
165 Id: nsID,
166 })
167 var notFound *serviceerror.NamespaceNotFound
168 if !errors.As(err, &notFound) {
169 return false
170 }
171
172 return true
173 }, 20*time.Second, time.Second)
174 }
175
176 func (s *namespaceTestSuite) Test_NamespaceDelete_WithNameAndID() {
177 env := s.newTestEnv()
178
179 retention := 24 * time.Hour
180 _, err := env.FrontendClient().RegisterNamespace(s.Context(), &workflowservice.RegisterNamespaceRequest{
181 Namespace: "ns_name_san_diego",
182 Description: "Namespace to delete",
183 WorkflowExecutionRetentionPeriod: durationpb.New(retention),
184 HistoryArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
185 VisibilityArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
186 })
187 s.NoError(err)
188
189 descResp, err := env.FrontendClient().DescribeNamespace(s.Context(), &workflowservice.DescribeNamespaceRequest{
190 Namespace: "ns_name_san_diego",
191 })
192 s.NoError(err)
193 nsID := descResp.GetNamespaceInfo().GetId()
194
195 _, err = env.OperatorClient().DeleteNamespace(s.Context(), &operatorservice.DeleteNamespaceRequest{
196 Namespace: "ns_name_san_diego",
197 NamespaceId: nsID,
198 })
199 s.EqualError(err, "Only one of namespace name or Id should be set on request.")
200 }
201
202 func (s *namespaceTestSuite) Test_NamespaceDelete_WithWorkflows() {
203 env := s.newTestEnv()
204
205 retention := 24 * time.Hour
206 _, err := env.FrontendClient().RegisterNamespace(s.Context(), &workflowservice.RegisterNamespaceRequest{
207 Namespace: "ns_name_seattle",
208 Description: "Namespace to delete",
209 WorkflowExecutionRetentionPeriod: durationpb.New(retention),
210 HistoryArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
211 VisibilityArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
212 })
213 s.NoError(err)
214
215 descResp, err := env.FrontendClient().DescribeNamespace(s.Context(), &workflowservice.DescribeNamespaceRequest{
216 Namespace: "ns_name_seattle",
217 })
218 s.NoError(err)
219 nsID := descResp.GetNamespaceInfo().GetId()
220
221 // Start few workflow executions.
222 var executions []*commonpb.WorkflowExecution
223 for i := range 100 {
224 wid := "wf_id_" + strconv.Itoa(i)
225 resp, err := env.FrontendClient().StartWorkflowExecution(s.Context(), &workflowservice.StartWorkflowExecutionRequest{
226 RequestId: uuid.NewString(),
227 Namespace: "ns_name_seattle",
228 WorkflowId: wid,
229 WorkflowType: &commonpb.WorkflowType{Name: "workflowTypeName"},
230 TaskQueue: &taskqueuepb.TaskQueue{Name: "taskQueueName", Kind: enumspb.TASK_QUEUE_KIND_NORMAL},
231 })
232 s.NoError(err)
233 executions = append(executions, &commonpb.WorkflowExecution{
234 WorkflowId: wid,
235 RunId: resp.GetRunId(),
236 })
237 }
238
239 // Terminate some workflow executions.
240 for _, execution := range executions[:30] {
241 _, err = env.FrontendClient().TerminateWorkflowExecution(s.Context(), &workflowservice.TerminateWorkflowExecutionRequest{
242 Namespace: "ns_name_seattle",
243 WorkflowExecution: execution,
244 })
245 s.NoError(err)
246 }
247
248 delResp, err := env.OperatorClient().DeleteNamespace(s.Context(), &operatorservice.DeleteNamespaceRequest{
249 Namespace: "ns_name_seattle",
250 })
251 s.NoError(err)
252 s.Equal("ns_name_seattle-deleted-"+nsID[:5], delResp.GetDeletedNamespace())
253
254 descResp2, err := env.FrontendClient().DescribeNamespace(s.Context(), &workflowservice.DescribeNamespaceRequest{
255 Id: nsID,
256 })
257 s.NoError(err)
258 s.Equal(enumspb.NAMESPACE_STATE_DELETED, descResp2.GetNamespaceInfo().GetState())
259
260 s.Eventually(func() bool {
261 _, err := env.FrontendClient().DescribeNamespace(s.Context(), &workflowservice.DescribeNamespaceRequest{
262 Id: nsID,
263 })
264 var notFound *serviceerror.NamespaceNotFound
265 if !errors.As(err, &notFound) {
266 return false // namespace still exists
267 }
268
269 for _, execution := range executions {
270 _, err = env.FrontendClient().DescribeWorkflowExecution(s.Context(), &workflowservice.DescribeWorkflowExecutionRequest{
271 Namespace: "ns_name_seattle",
272 Execution: &commonpb.WorkflowExecution{
273 WorkflowId: execution.GetWorkflowId(),
274 },
275 })
276 if !errors.As(err, &notFound) {
277 return false // should never happen
278 }
279 }
280 return true
281 }, 20*time.Second, time.Second)
282 }
283
284 func (s *namespaceTestSuite) Test_NamespaceDelete_WithMissingWorkflows() {
285 env := s.newTestEnv()
286
287 retention := 24 * time.Hour
288 _, err := env.FrontendClient().RegisterNamespace(s.Context(), &workflowservice.RegisterNamespaceRequest{
289 Namespace: "ns_name_los_angeles",
290 Description: "Namespace to delete",
291 WorkflowExecutionRetentionPeriod: durationpb.New(retention),
292 HistoryArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
293 VisibilityArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
294 })
295 s.NoError(err)
296
297 descResp, err := env.FrontendClient().DescribeNamespace(s.Context(), &workflowservice.DescribeNamespaceRequest{
298 Namespace: "ns_name_los_angeles",
299 })
300 s.NoError(err)
301 nsID := descResp.GetNamespaceInfo().GetId()
302
303 // Start few workflow executions.
304
305 var executions []*commonpb.WorkflowExecution
306 for i := range 10 {
307 wid := "wf_id_" + strconv.Itoa(i)
308 resp, err := env.FrontendClient().StartWorkflowExecution(s.Context(), &workflowservice.StartWorkflowExecutionRequest{
309 RequestId: uuid.NewString(),
310 Namespace: "ns_name_los_angeles",
311 WorkflowId: wid,
312 WorkflowType: &commonpb.WorkflowType{Name: "workflowTypeName"},
313 TaskQueue: &taskqueuepb.TaskQueue{Name: "taskQueueName", Kind: enumspb.TASK_QUEUE_KIND_NORMAL},
314 })
315 s.NoError(err)
316 executions = append(executions, &commonpb.WorkflowExecution{
317 WorkflowId: wid,
318 RunId: resp.GetRunId(),
319 })
320 }
321
322 // Delete some workflow executions from DB but not from visibility.
323 // Every subsequent delete (from deleteexecutions.Workflow) from ES will take at least 1s due to bulk processor.
324 for _, execution := range executions[0:5] {
325 shardID := common.WorkflowIDToHistoryShard(
326 nsID,
327 execution.GetWorkflowId(),
328 env.GetTestClusterConfig().HistoryConfig.NumHistoryShards,
329 )
330
331 err = env.GetTestCluster().ExecutionManager().DeleteWorkflowExecution(s.Context(), &persistence.DeleteWorkflowExecutionRequest{
332 ShardID: shardID,
333 NamespaceID: nsID,
334 WorkflowID: execution.GetWorkflowId(),
335 RunID: execution.GetRunId(),
336 ArchetypeID: chasm.WorkflowArchetypeID,
337 })
338 s.NoError(err)
339 }
340
341 delResp, err := env.OperatorClient().DeleteNamespace(s.Context(), &operatorservice.DeleteNamespaceRequest{
342 Namespace: "ns_name_los_angeles",
343 })
344 s.NoError(err)
345 s.Equal("ns_name_los_angeles-deleted-"+nsID[:5], delResp.GetDeletedNamespace())
346
347 descResp2, err := env.FrontendClient().DescribeNamespace(s.Context(), &workflowservice.DescribeNamespaceRequest{
348 Id: nsID,
349 })
350 s.NoError(err)
351 s.Equal(enumspb.NAMESPACE_STATE_DELETED, descResp2.GetNamespaceInfo().GetState())
352
353 s.Eventually(func() bool {
354 _, err := env.FrontendClient().DescribeNamespace(s.Context(), &workflowservice.DescribeNamespaceRequest{
355 Id: nsID,
356 })
357 var notFound *serviceerror.NamespaceNotFound
358 if !errors.As(err, &notFound) {
359 return false // namespace still exists
360 }
361
362 for _, execution := range executions {
363 _, err = env.FrontendClient().DescribeWorkflowExecution(s.Context(), &workflowservice.DescribeWorkflowExecutionRequest{
364 Namespace: "ns_name_los_angeles",
365 Execution: &commonpb.WorkflowExecution{
366 WorkflowId: execution.GetWorkflowId(),
367 },
368 })
369 if !errors.As(err, &notFound) {
370 return false // should never happen
371 }
372 }
373 return true
374 }, 20*time.Second, time.Second)
375 }
376
377 func (s *namespaceTestSuite) Test_NamespaceDelete_CrossNamespaceChild() {
378 // TODO (alex): create 2 namespaces, start workflow in first namespace and start child in second namespace.
379 // Delete second namespace and verify that parent received child termination signal.
380 }
381
382 func (s *namespaceTestSuite) Test_NamespaceDelete_Protected() {
383 tv := testvars.New(s.T())
384 env := s.newTestEnv(testcore.WithDynamicConfig(dynamicconfig.ProtectedNamespaces, []string{tv.NamespaceName().String()}))
385
386 _, err := env.FrontendClient().RegisterNamespace(s.Context(), &workflowservice.RegisterNamespaceRequest{
387 Namespace: tv.NamespaceName().String(),
388 Description: tv.Any().String(),
389 WorkflowExecutionRetentionPeriod: tv.Any().InfiniteTimeout(),
390 HistoryArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
391 VisibilityArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
392 })
393 s.NoError(err)
394
395 delResp, err := env.OperatorClient().DeleteNamespace(s.Context(), &operatorservice.DeleteNamespaceRequest{
396 Namespace: tv.NamespaceName().String(),
397 })
398 s.Error(err)
399 s.Nil(delResp)
400
401 var failedPreconditionErr *serviceerror.FailedPrecondition
402 s.ErrorAs(err, &failedPreconditionErr)
403 s.Equal(fmt.Sprintf("namespace %s is protected from deletion", tv.NamespaceName().String()), failedPreconditionErr.Message)
404 }
405
406 func (s *namespaceTestSuite) Test_DescribeNamespace_WeakConsistency() {
407 env := s.newTestEnv()
408
409 nsName := "ns_weak_" + uuid.NewString()
410 _, err := env.FrontendClient().RegisterNamespace(s.Context(), &workflowservice.RegisterNamespaceRequest{
411 Namespace: nsName,
412 Description: "weak consistency test",
413 WorkflowExecutionRetentionPeriod: durationpb.New(24 * time.Hour),
414 HistoryArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
415 VisibilityArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
416 })
417 s.NoError(err)
418
419 var nsNotFound *serviceerror.NamespaceNotFound
420
421 // Cache is populated by the periodic refresh, so the weak path should eventually succeed.
422 var weakResp *workflowservice.DescribeNamespaceResponse
423 s.Eventually(func() bool {
424 weakResp, err = env.FrontendClient().DescribeNamespace(s.Context(), &workflowservice.DescribeNamespaceRequest{
425 Namespace: nsName,
426 WeakConsistency: true,
427 })
428 // fail the test if error is not nil or NamespaceNotFound
429 if err != nil && !errors.As(err, &nsNotFound) {
430 s.Failf("unexpected error", "Expected NamespaceNotFound error, got: %v", err)
431 }
432 return err == nil
433 }, 5*testcore.NamespaceCacheRefreshInterval, 100*time.Millisecond) //nolint:forbidigo
434
435 strongResp, err := env.FrontendClient().DescribeNamespace(s.Context(), &workflowservice.DescribeNamespaceRequest{
436 Namespace: nsName,
437 })
438 s.NoError(err)
439 s.Equal(strongResp.GetNamespaceInfo().GetId(), weakResp.GetNamespaceInfo().GetId())
440 s.Equal(strongResp.GetNamespaceInfo().GetName(), weakResp.GetNamespaceInfo().GetName())
441 s.Equal(strongResp.GetIsGlobalNamespace(), weakResp.GetIsGlobalNamespace())
442
443 // Lookup by ID should also work via the weak path.
444 nsID := strongResp.GetNamespaceInfo().GetId()
445 weakByIDResp, err := env.FrontendClient().DescribeNamespace(s.Context(), &workflowservice.DescribeNamespaceRequest{
446 Id: nsID,
447 WeakConsistency: true,
448 })
449 s.NoError(err)
450 s.Equal(nsName, weakByIDResp.GetNamespaceInfo().GetName())
451
452 // Non-existent namespace should return NamespaceNotFound.
453 _, err = env.FrontendClient().DescribeNamespace(s.Context(), &workflowservice.DescribeNamespaceRequest{
454 Namespace: "ns_does_not_exist_" + uuid.NewString(),
455 WeakConsistency: true,
456 })
457 s.ErrorAs(err, &nsNotFound)
458 }