mirror of
https://github.com/hanzoai/tasks.git
synced 2026-10-04 02:04:03 +00:00
## What Used the `depguard` linter to prevent importing the package and modified all uses of it. Also fixed a bug in the membership code where we were not updating the next page token: https://github.com/temporalio/temporal/pull/8541/files#diff-985dd64ffa4c6bfe0248b982dc47439b725862baa3e1f2c559b7ff522bf21969R350 ## Why? From the package README in GitHub: > This package now leverages the github.com/google/uuid package (which is based off an earlier version of this package). Also, there's no point in having two uuid implementations in the codebase. ## Test Added the invalid import and confirmed it works: ``` ../service/frontend/admin_handler_test.go:13:2: import 'github.com/pborman/uuid' is not allowed from list 'main': Importing github.com/pborman/uuid is disallowed; use github.com/google/uuid instead (depguard) _ "github.com/pborman/uuid" ```
2361 lines
81 KiB
Go
2361 lines
81 KiB
Go
package persistencetests
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/require"
|
|
enumspb "go.temporal.io/api/enums/v1"
|
|
namespacepb "go.temporal.io/api/namespace/v1"
|
|
"go.temporal.io/api/serviceerror"
|
|
persistencespb "go.temporal.io/server/api/persistence/v1"
|
|
"go.temporal.io/server/common/cluster"
|
|
"go.temporal.io/server/common/debug"
|
|
p "go.temporal.io/server/common/persistence"
|
|
"go.temporal.io/server/common/persistence/cassandra"
|
|
"go.temporal.io/server/common/persistence/sql"
|
|
"go.temporal.io/server/common/primitives/timestamp"
|
|
"go.temporal.io/server/common/testing/protorequire"
|
|
"google.golang.org/protobuf/types/known/timestamppb"
|
|
)
|
|
|
|
type (
|
|
// MetadataPersistenceSuiteV2 is test of the V2 version of metadata persistence
|
|
MetadataPersistenceSuiteV2 struct {
|
|
*TestBase
|
|
// override suite.Suite.Assertions with require.Assertions; this means that s.NotNil(nil) will stop the test,
|
|
// not merely log an error
|
|
*require.Assertions
|
|
protorequire.ProtoAssertions
|
|
|
|
ctx context.Context
|
|
cancel context.CancelFunc
|
|
}
|
|
)
|
|
|
|
// SetupSuite implementation
|
|
func (m *MetadataPersistenceSuiteV2) SetupSuite() {
|
|
}
|
|
|
|
// SetupTest implementation
|
|
func (m *MetadataPersistenceSuiteV2) SetupTest() {
|
|
// Have to define our overridden assertions in the test setup. If we did it earlier, s.T() will return nil
|
|
m.Assertions = require.New(m.T())
|
|
m.ProtoAssertions = protorequire.New(m.T())
|
|
m.ctx, m.cancel = context.WithTimeout(context.Background(), 30*time.Second*debug.TimeoutMultiplier)
|
|
|
|
// cleanup the namespace created
|
|
var token []byte
|
|
pageSize := 10
|
|
ListLoop:
|
|
for {
|
|
resp, err := m.ListNamespaces(pageSize, token)
|
|
m.NoError(err)
|
|
token = resp.NextPageToken
|
|
for _, n := range resp.Namespaces {
|
|
m.NoError(m.DeleteNamespace(n.Namespace.Info.Id, ""))
|
|
}
|
|
if len(token) == 0 {
|
|
break ListLoop
|
|
}
|
|
}
|
|
}
|
|
|
|
// TearDownTest implementation
|
|
func (m *MetadataPersistenceSuiteV2) TearDownTest() {
|
|
m.cancel()
|
|
}
|
|
|
|
// TearDownSuite implementation
|
|
func (m *MetadataPersistenceSuiteV2) TearDownSuite() {
|
|
m.TearDownWorkflowStore()
|
|
}
|
|
|
|
// Partial namespace creation is only relevant for Cassandra, the following tests will only run when the underlying cluster is cassandra
|
|
func (m *MetadataPersistenceSuiteV2) createPartialNamespace(id string, name string) {
|
|
// only add the namespace to namespaces_by_id table and not namespaces table
|
|
const constNamespacePartition = 0
|
|
const templateCreateNamespaceQuery = `INSERT INTO namespaces_by_id (` +
|
|
`id, name) ` +
|
|
`VALUES(?, ?) IF NOT EXISTS`
|
|
query := m.DefaultTestCluster.(*cassandra.TestCluster).GetSession().Query(templateCreateNamespaceQuery, id, name).WithContext(context.Background())
|
|
err := query.Exec()
|
|
m.NoError(err)
|
|
|
|
}
|
|
|
|
func (m *MetadataPersistenceSuiteV2) truncatePartialNamespace() {
|
|
query := m.DefaultTestCluster.(*cassandra.TestCluster).GetSession().Query("TRUNCATE namespaces_by_id").WithContext(context.Background())
|
|
err := query.Exec()
|
|
m.NoError(err)
|
|
|
|
query = m.DefaultTestCluster.(*cassandra.TestCluster).GetSession().Query("TRUNCATE namespaces").WithContext(context.Background())
|
|
err = query.Exec()
|
|
m.NoError(err)
|
|
}
|
|
|
|
func (m *MetadataPersistenceSuiteV2) TestCreateWithPartialNamespaceSameNameSameID() {
|
|
// This is only relevant for cassandra
|
|
switch m.DefaultTestCluster.(type) {
|
|
case *cassandra.TestCluster:
|
|
default:
|
|
return
|
|
}
|
|
id := uuid.NewString()
|
|
name := "create-partial-namespace-test-name"
|
|
m.createPartialNamespace(id, name)
|
|
|
|
state := enumspb.NAMESPACE_STATE_REGISTERED
|
|
description := "create-namespace-test-description"
|
|
owner := "create-namespace-test-owner"
|
|
data := map[string]string{"k1": "v1"}
|
|
retention := int32(10)
|
|
historyArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
historyArchivalURI := "test://history/uri"
|
|
visibilityArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
visibilityArchivalURI := "test://visibility/uri"
|
|
badBinaries := &namespacepb.BadBinaries{Binaries: map[string]*namespacepb.BadBinaryInfo{}}
|
|
isGlobalNamespace := false
|
|
configVersion := int64(0)
|
|
failoverVersion := int64(0)
|
|
|
|
resp0, err0 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id,
|
|
Name: name,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
Data: data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention),
|
|
HistoryArchivalState: historyArchivalState,
|
|
HistoryArchivalUri: historyArchivalURI,
|
|
VisibilityArchivalState: visibilityArchivalState,
|
|
VisibilityArchivalUri: visibilityArchivalURI,
|
|
BadBinaries: badBinaries,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.NoError(err0)
|
|
m.NotNil(resp0)
|
|
m.EqualValues(id, resp0.ID)
|
|
|
|
// for namespace which do not have replication config set, will default to
|
|
// use current cluster as active, with current cluster as all clusters
|
|
resp1, err1 := m.GetNamespace(id, "")
|
|
m.NoError(err1)
|
|
m.NotNil(resp1)
|
|
m.EqualValues(id, resp1.Namespace.Info.Id)
|
|
m.Equal(name, resp1.Namespace.Info.Name)
|
|
m.Equal(state, resp1.Namespace.Info.State)
|
|
m.Equal(description, resp1.Namespace.Info.Description)
|
|
m.Equal(owner, resp1.Namespace.Info.Owner)
|
|
m.Equal(data, resp1.Namespace.Info.Data)
|
|
m.EqualValues(time.Duration(retention)*time.Hour*24, resp1.Namespace.Config.Retention.AsDuration())
|
|
m.Equal(historyArchivalState, resp1.Namespace.Config.HistoryArchivalState)
|
|
m.Equal(historyArchivalURI, resp1.Namespace.Config.HistoryArchivalUri)
|
|
m.Equal(visibilityArchivalState, resp1.Namespace.Config.VisibilityArchivalState)
|
|
m.Equal(visibilityArchivalURI, resp1.Namespace.Config.VisibilityArchivalUri)
|
|
m.ProtoEqual(badBinaries, resp1.Namespace.Config.BadBinaries)
|
|
m.Equal(cluster.TestCurrentClusterName, resp1.Namespace.ReplicationConfig.ActiveClusterName)
|
|
m.Equal(1, len(resp1.Namespace.ReplicationConfig.Clusters))
|
|
m.Equal(isGlobalNamespace, resp1.IsGlobalNamespace)
|
|
m.Equal(configVersion, resp1.Namespace.ConfigVersion)
|
|
m.Equal(failoverVersion, resp1.Namespace.FailoverVersion)
|
|
m.True(resp1.Namespace.ReplicationConfig.Clusters[0] == cluster.TestCurrentClusterName)
|
|
m.Equal(p.InitialFailoverNotificationVersion, resp1.Namespace.FailoverNotificationVersion)
|
|
m.truncatePartialNamespace()
|
|
}
|
|
|
|
func (m *MetadataPersistenceSuiteV2) TestCreateWithPartialNamespaceSameNameDifferentID() {
|
|
// This is only relevant for cassandra
|
|
switch m.DefaultTestCluster.(type) {
|
|
case *cassandra.TestCluster:
|
|
default:
|
|
return
|
|
}
|
|
|
|
id := uuid.NewString()
|
|
partialID := uuid.NewString()
|
|
name := "create-partial-namespace-test-name"
|
|
m.createPartialNamespace(partialID, name)
|
|
state := enumspb.NAMESPACE_STATE_REGISTERED
|
|
description := "create-namespace-test-description"
|
|
owner := "create-namespace-test-owner"
|
|
data := map[string]string{"k1": "v1"}
|
|
retention := int32(10)
|
|
historyArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
historyArchivalURI := "test://history/uri"
|
|
visibilityArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
visibilityArchivalURI := "test://visibility/uri"
|
|
badBinaries := &namespacepb.BadBinaries{Binaries: map[string]*namespacepb.BadBinaryInfo{}}
|
|
isGlobalNamespace := false
|
|
configVersion := int64(0)
|
|
failoverVersion := int64(0)
|
|
|
|
resp0, err0 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id,
|
|
Name: name,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
Data: data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention),
|
|
HistoryArchivalState: historyArchivalState,
|
|
HistoryArchivalUri: historyArchivalURI,
|
|
VisibilityArchivalState: visibilityArchivalState,
|
|
VisibilityArchivalUri: visibilityArchivalURI,
|
|
BadBinaries: badBinaries,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.NoError(err0)
|
|
m.NotNil(resp0)
|
|
m.EqualValues(id, resp0.ID)
|
|
|
|
// for namespace which do not have replication config set, will default to
|
|
// use current cluster as active, with current cluster as all clusters
|
|
resp1, err1 := m.GetNamespace(id, "")
|
|
m.NoError(err1)
|
|
m.NotNil(resp1)
|
|
m.EqualValues(id, resp1.Namespace.Info.Id)
|
|
m.Equal(name, resp1.Namespace.Info.Name)
|
|
m.Equal(state, resp1.Namespace.Info.State)
|
|
m.Equal(description, resp1.Namespace.Info.Description)
|
|
m.Equal(owner, resp1.Namespace.Info.Owner)
|
|
m.Equal(data, resp1.Namespace.Info.Data)
|
|
m.EqualValues(time.Duration(retention)*time.Hour*24, resp1.Namespace.Config.Retention.AsDuration())
|
|
m.Equal(historyArchivalState, resp1.Namespace.Config.HistoryArchivalState)
|
|
m.Equal(historyArchivalURI, resp1.Namespace.Config.HistoryArchivalUri)
|
|
m.Equal(visibilityArchivalState, resp1.Namespace.Config.VisibilityArchivalState)
|
|
m.Equal(visibilityArchivalURI, resp1.Namespace.Config.VisibilityArchivalUri)
|
|
m.ProtoEqual(badBinaries, resp1.Namespace.Config.BadBinaries)
|
|
m.Equal(cluster.TestCurrentClusterName, resp1.Namespace.ReplicationConfig.ActiveClusterName)
|
|
m.Equal(1, len(resp1.Namespace.ReplicationConfig.Clusters))
|
|
m.Equal(isGlobalNamespace, resp1.IsGlobalNamespace)
|
|
m.Equal(configVersion, resp1.Namespace.ConfigVersion)
|
|
m.Equal(failoverVersion, resp1.Namespace.FailoverVersion)
|
|
m.True(resp1.Namespace.ReplicationConfig.Clusters[0] == cluster.TestCurrentClusterName)
|
|
m.Equal(p.InitialFailoverNotificationVersion, resp1.Namespace.FailoverNotificationVersion)
|
|
m.truncatePartialNamespace()
|
|
}
|
|
|
|
func (m *MetadataPersistenceSuiteV2) TestCreateWithPartialNamespaceDifferentNameSameID() {
|
|
// This is only relevant for cassandra
|
|
switch m.DefaultTestCluster.(type) {
|
|
case *cassandra.TestCluster:
|
|
default:
|
|
return
|
|
}
|
|
id := uuid.NewString()
|
|
name := "create-namespace-test-name-for-partial-test"
|
|
partialName := "create-partial-namespace-test-name"
|
|
m.createPartialNamespace(id, partialName)
|
|
state := enumspb.NAMESPACE_STATE_REGISTERED
|
|
description := "create-namespace-test-description"
|
|
owner := "create-namespace-test-owner"
|
|
data := map[string]string{"k1": "v1"}
|
|
retention := int32(10)
|
|
historyArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
historyArchivalURI := "test://history/uri"
|
|
visibilityArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
visibilityArchivalURI := "test://visibility/uri"
|
|
badBinaries := &namespacepb.BadBinaries{Binaries: map[string]*namespacepb.BadBinaryInfo{}}
|
|
isGlobalNamespace := false
|
|
configVersion := int64(0)
|
|
failoverVersion := int64(0)
|
|
|
|
resp0, err0 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id,
|
|
Name: name,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
Data: data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention),
|
|
HistoryArchivalState: historyArchivalState,
|
|
HistoryArchivalUri: historyArchivalURI,
|
|
VisibilityArchivalState: visibilityArchivalState,
|
|
VisibilityArchivalUri: visibilityArchivalURI,
|
|
BadBinaries: badBinaries,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.Error(err0)
|
|
m.IsType(&serviceerror.NamespaceAlreadyExists{}, err0)
|
|
m.Nil(resp0)
|
|
m.truncatePartialNamespace()
|
|
}
|
|
|
|
// TestCreateNamespace test
|
|
func (m *MetadataPersistenceSuiteV2) TestCreateNamespace() {
|
|
id := uuid.NewString()
|
|
name := "create-namespace-test-name-for-partial-test"
|
|
state := enumspb.NAMESPACE_STATE_REGISTERED
|
|
description := "create-namespace-test-description"
|
|
owner := "create-namespace-test-owner"
|
|
data := map[string]string{"k1": "v1"}
|
|
retention := int32(10)
|
|
historyArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
historyArchivalURI := "test://history/uri"
|
|
visibilityArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
visibilityArchivalURI := "test://visibility/uri"
|
|
badBinaries := &namespacepb.BadBinaries{Binaries: map[string]*namespacepb.BadBinaryInfo{}}
|
|
isGlobalNamespace := false
|
|
configVersion := int64(0)
|
|
failoverVersion := int64(0)
|
|
|
|
resp0, err0 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id,
|
|
Name: name,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
Data: data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention),
|
|
HistoryArchivalState: historyArchivalState,
|
|
HistoryArchivalUri: historyArchivalURI,
|
|
VisibilityArchivalState: visibilityArchivalState,
|
|
VisibilityArchivalUri: visibilityArchivalURI,
|
|
BadBinaries: badBinaries,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.NoError(err0)
|
|
m.NotNil(resp0)
|
|
m.EqualValues(id, resp0.ID)
|
|
|
|
// for namespace which do not have replication config set, will default to
|
|
// use current cluster as active, with current cluster as all clusters
|
|
resp1, err1 := m.GetNamespace(id, "")
|
|
m.NoError(err1)
|
|
m.NotNil(resp1)
|
|
m.EqualValues(id, resp1.Namespace.Info.Id)
|
|
m.Equal(name, resp1.Namespace.Info.Name)
|
|
m.Equal(state, resp1.Namespace.Info.State)
|
|
m.Equal(description, resp1.Namespace.Info.Description)
|
|
m.Equal(owner, resp1.Namespace.Info.Owner)
|
|
m.Equal(data, resp1.Namespace.Info.Data)
|
|
m.EqualValues(time.Duration(retention)*time.Hour*24, resp1.Namespace.Config.Retention.AsDuration())
|
|
m.Equal(historyArchivalState, resp1.Namespace.Config.HistoryArchivalState)
|
|
m.Equal(historyArchivalURI, resp1.Namespace.Config.HistoryArchivalUri)
|
|
m.Equal(visibilityArchivalState, resp1.Namespace.Config.VisibilityArchivalState)
|
|
m.Equal(visibilityArchivalURI, resp1.Namespace.Config.VisibilityArchivalUri)
|
|
m.ProtoEqual(badBinaries, resp1.Namespace.Config.BadBinaries)
|
|
m.Equal(cluster.TestCurrentClusterName, resp1.Namespace.ReplicationConfig.ActiveClusterName)
|
|
m.Equal(1, len(resp1.Namespace.ReplicationConfig.Clusters))
|
|
m.Equal(isGlobalNamespace, resp1.IsGlobalNamespace)
|
|
m.Equal(configVersion, resp1.Namespace.ConfigVersion)
|
|
m.Equal(failoverVersion, resp1.Namespace.FailoverVersion)
|
|
m.True(resp1.Namespace.ReplicationConfig.Clusters[0] == cluster.TestCurrentClusterName)
|
|
m.Equal(p.InitialFailoverNotificationVersion, resp1.Namespace.FailoverNotificationVersion)
|
|
|
|
resp2, err2 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: uuid.NewString(),
|
|
Name: name,
|
|
State: state,
|
|
Description: "fail",
|
|
Owner: "fail",
|
|
Data: map[string]string{},
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(100),
|
|
HistoryArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
|
|
HistoryArchivalUri: "",
|
|
VisibilityArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
|
|
VisibilityArchivalUri: "",
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.Error(err2)
|
|
m.IsType(&serviceerror.NamespaceAlreadyExists{}, err2)
|
|
m.Nil(resp2)
|
|
}
|
|
|
|
// TestGetNamespace test
|
|
func (m *MetadataPersistenceSuiteV2) TestGetNamespace() {
|
|
id := uuid.NewString()
|
|
name := "get-namespace-test-name"
|
|
state := enumspb.NAMESPACE_STATE_REGISTERED
|
|
description := "get-namespace-test-description"
|
|
owner := "get-namespace-test-owner"
|
|
data := map[string]string{"k1": "v1"}
|
|
retention := int32(10)
|
|
historyArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
historyArchivalURI := "test://history/uri"
|
|
visibilityArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
visibilityArchivalURI := "test://visibility/uri"
|
|
|
|
clusterActive := "some random active cluster name"
|
|
clusterStandby := "some random standby cluster name"
|
|
configVersion := int64(11)
|
|
failoverVersion := int64(59)
|
|
isGlobalNamespace := true
|
|
clusters := []string{clusterActive, clusterStandby}
|
|
|
|
resp0, err0 := m.GetNamespace("", "does-not-exist")
|
|
m.Nil(resp0)
|
|
m.Error(err0)
|
|
m.IsType(&serviceerror.NamespaceNotFound{}, err0)
|
|
testBinaries := &namespacepb.BadBinaries{
|
|
Binaries: map[string]*namespacepb.BadBinaryInfo{
|
|
"abc": {
|
|
Reason: "test-reason",
|
|
Operator: "test-operator",
|
|
CreateTime: timestamppb.New(time.Date(2020, 8, 22, 0, 0, 0, 0, time.UTC)),
|
|
},
|
|
},
|
|
}
|
|
|
|
resp1, err1 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id,
|
|
Name: name,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
Data: data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention),
|
|
HistoryArchivalState: historyArchivalState,
|
|
HistoryArchivalUri: historyArchivalURI,
|
|
VisibilityArchivalState: visibilityArchivalState,
|
|
VisibilityArchivalUri: visibilityArchivalURI,
|
|
BadBinaries: testBinaries,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive,
|
|
Clusters: clusters,
|
|
},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.NoError(err1)
|
|
m.NotNil(resp1)
|
|
m.EqualValues(id, resp1.ID)
|
|
|
|
resp2, err2 := m.GetNamespace(id, "")
|
|
m.NoError(err2)
|
|
m.NotNil(resp2)
|
|
m.EqualValues(id, resp2.Namespace.Info.Id)
|
|
m.Equal(name, resp2.Namespace.Info.Name)
|
|
m.Equal(state, resp2.Namespace.Info.State)
|
|
m.Equal(description, resp2.Namespace.Info.Description)
|
|
m.Equal(owner, resp2.Namespace.Info.Owner)
|
|
m.Equal(data, resp2.Namespace.Info.Data)
|
|
m.EqualValues(time.Duration(retention)*time.Hour*24, resp2.Namespace.Config.Retention.AsDuration())
|
|
m.Equal(historyArchivalState, resp2.Namespace.Config.HistoryArchivalState)
|
|
m.Equal(historyArchivalURI, resp2.Namespace.Config.HistoryArchivalUri)
|
|
m.Equal(visibilityArchivalState, resp2.Namespace.Config.VisibilityArchivalState)
|
|
m.Equal(visibilityArchivalURI, resp2.Namespace.Config.VisibilityArchivalUri)
|
|
m.ProtoEqual(testBinaries, resp2.Namespace.Config.BadBinaries)
|
|
m.Equal(clusterActive, resp2.Namespace.ReplicationConfig.ActiveClusterName)
|
|
m.Equal(len(clusters), len(resp2.Namespace.ReplicationConfig.Clusters))
|
|
for index := range clusters {
|
|
m.Equal(clusters[index], resp2.Namespace.ReplicationConfig.Clusters[index])
|
|
}
|
|
m.Equal(isGlobalNamespace, resp2.IsGlobalNamespace)
|
|
m.Equal(configVersion, resp2.Namespace.ConfigVersion)
|
|
m.Equal(failoverVersion, resp2.Namespace.FailoverVersion)
|
|
m.Equal(p.InitialFailoverNotificationVersion, resp2.Namespace.FailoverNotificationVersion)
|
|
|
|
resp3, err3 := m.GetNamespace("", name)
|
|
m.NoError(err3)
|
|
m.NotNil(resp3)
|
|
m.EqualValues(id, resp3.Namespace.Info.Id)
|
|
m.Equal(name, resp3.Namespace.Info.Name)
|
|
m.Equal(state, resp3.Namespace.Info.State)
|
|
m.Equal(description, resp3.Namespace.Info.Description)
|
|
m.Equal(owner, resp3.Namespace.Info.Owner)
|
|
m.Equal(data, resp3.Namespace.Info.Data)
|
|
m.EqualValues(time.Duration(retention)*time.Hour*24, resp3.Namespace.Config.Retention.AsDuration())
|
|
m.Equal(historyArchivalState, resp3.Namespace.Config.HistoryArchivalState)
|
|
m.Equal(historyArchivalURI, resp3.Namespace.Config.HistoryArchivalUri)
|
|
m.Equal(visibilityArchivalState, resp3.Namespace.Config.VisibilityArchivalState)
|
|
m.Equal(visibilityArchivalURI, resp3.Namespace.Config.VisibilityArchivalUri)
|
|
m.Equal(clusterActive, resp3.Namespace.ReplicationConfig.ActiveClusterName)
|
|
m.Equal(len(clusters), len(resp3.Namespace.ReplicationConfig.Clusters))
|
|
for index := range clusters {
|
|
m.Equal(clusters[index], resp3.Namespace.ReplicationConfig.Clusters[index])
|
|
}
|
|
m.Equal(isGlobalNamespace, resp3.IsGlobalNamespace)
|
|
m.Equal(configVersion, resp3.Namespace.ConfigVersion)
|
|
m.Equal(failoverVersion, resp3.Namespace.FailoverVersion)
|
|
m.Equal(p.InitialFailoverNotificationVersion, resp3.Namespace.FailoverNotificationVersion)
|
|
|
|
resp4, err4 := m.GetNamespace(id, name)
|
|
m.Error(err4)
|
|
m.IsType(&serviceerror.InvalidArgument{}, err4)
|
|
m.Nil(resp4)
|
|
|
|
resp5, err5 := m.GetNamespace("", "")
|
|
m.Nil(resp5)
|
|
m.IsType(&serviceerror.InvalidArgument{}, err5)
|
|
}
|
|
|
|
// TestConcurrentCreateNamespace test
|
|
func (m *MetadataPersistenceSuiteV2) TestConcurrentCreateNamespace() {
|
|
id := uuid.NewString()
|
|
|
|
name := "concurrent-create-namespace-test-name"
|
|
state := enumspb.NAMESPACE_STATE_REGISTERED
|
|
description := "concurrent-create-namespace-test-description"
|
|
owner := "create-namespace-test-owner"
|
|
retention := int32(10)
|
|
historyArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
historyArchivalURI := "test://history/uri"
|
|
visibilityArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
visibilityArchivalURI := "test://visibility/uri"
|
|
|
|
clusterActive := "some random active cluster name"
|
|
clusterStandby := "some random standby cluster name"
|
|
configVersion := int64(10)
|
|
failoverVersion := int64(59)
|
|
isGlobalNamespace := true
|
|
clusters := []string{clusterActive, clusterStandby}
|
|
|
|
testBinaries := &namespacepb.BadBinaries{
|
|
Binaries: map[string]*namespacepb.BadBinaryInfo{
|
|
"abc": {
|
|
Reason: "test-reason",
|
|
Operator: "test-operator",
|
|
CreateTime: timestamppb.New(time.Date(2020, 8, 22, 0, 0, 0, 0, time.UTC)),
|
|
},
|
|
},
|
|
}
|
|
concurrency := 16
|
|
successCount := int32(0)
|
|
var wg sync.WaitGroup
|
|
for i := 1; i <= concurrency; i++ {
|
|
newValue := fmt.Sprintf("v-%v", i)
|
|
wg.Add(1)
|
|
go func(data map[string]string) {
|
|
_, err1 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id,
|
|
Name: name,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
Data: data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention),
|
|
HistoryArchivalState: historyArchivalState,
|
|
HistoryArchivalUri: historyArchivalURI,
|
|
VisibilityArchivalState: visibilityArchivalState,
|
|
VisibilityArchivalUri: visibilityArchivalURI,
|
|
BadBinaries: testBinaries,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive,
|
|
Clusters: clusters,
|
|
},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
if err1 == nil {
|
|
atomic.AddInt32(&successCount, 1)
|
|
}
|
|
wg.Done()
|
|
}(map[string]string{"k0": newValue})
|
|
}
|
|
wg.Wait()
|
|
m.Equal(int32(1), successCount)
|
|
|
|
resp, err3 := m.GetNamespace("", name)
|
|
m.NoError(err3)
|
|
m.NotNil(resp)
|
|
m.Equal(name, resp.Namespace.Info.Name)
|
|
m.Equal(state, resp.Namespace.Info.State)
|
|
m.Equal(description, resp.Namespace.Info.Description)
|
|
m.Equal(owner, resp.Namespace.Info.Owner)
|
|
m.EqualValues(time.Duration(retention)*time.Hour*24, resp.Namespace.Config.Retention.AsDuration())
|
|
m.Equal(historyArchivalState, resp.Namespace.Config.HistoryArchivalState)
|
|
m.Equal(historyArchivalURI, resp.Namespace.Config.HistoryArchivalUri)
|
|
m.Equal(visibilityArchivalState, resp.Namespace.Config.VisibilityArchivalState)
|
|
m.Equal(visibilityArchivalURI, resp.Namespace.Config.VisibilityArchivalUri)
|
|
m.ProtoEqual(testBinaries, resp.Namespace.Config.BadBinaries)
|
|
m.Equal(clusterActive, resp.Namespace.ReplicationConfig.ActiveClusterName)
|
|
m.Equal(len(clusters), len(resp.Namespace.ReplicationConfig.Clusters))
|
|
for index := range clusters {
|
|
m.Equal(clusters[index], resp.Namespace.ReplicationConfig.Clusters[index])
|
|
}
|
|
m.Equal(isGlobalNamespace, resp.IsGlobalNamespace)
|
|
m.Equal(configVersion, resp.Namespace.ConfigVersion)
|
|
m.Equal(failoverVersion, resp.Namespace.FailoverVersion)
|
|
|
|
// check namespace data
|
|
ss := strings.Split(resp.Namespace.Info.Data["k0"], "-")
|
|
m.Equal(2, len(ss))
|
|
vi, err := strconv.Atoi(ss[1])
|
|
m.NoError(err)
|
|
m.Equal(true, vi > 0 && vi <= concurrency)
|
|
}
|
|
|
|
// TestConcurrentUpdateNamespace test
|
|
func (m *MetadataPersistenceSuiteV2) TestConcurrentUpdateNamespace() {
|
|
id := uuid.NewString()
|
|
name := "concurrent-update-namespace-test-name"
|
|
state := enumspb.NAMESPACE_STATE_REGISTERED
|
|
description := "update-namespace-test-description"
|
|
owner := "update-namespace-test-owner"
|
|
data := map[string]string{"k1": "v1"}
|
|
retention := int32(10)
|
|
historyArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
historyArchivalURI := "test://history/uri"
|
|
visibilityArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
visibilityArchivalURI := "test://visibility/uri"
|
|
badBinaries := &namespacepb.BadBinaries{Binaries: map[string]*namespacepb.BadBinaryInfo{}}
|
|
|
|
clusterActive := "some random active cluster name"
|
|
clusterStandby := "some random standby cluster name"
|
|
configVersion := int64(10)
|
|
failoverVersion := int64(59)
|
|
isGlobalNamespace := true
|
|
clusters := []string{clusterActive, clusterStandby}
|
|
|
|
resp1, err1 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id,
|
|
Name: name,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
Data: data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention),
|
|
HistoryArchivalState: historyArchivalState,
|
|
HistoryArchivalUri: historyArchivalURI,
|
|
VisibilityArchivalState: visibilityArchivalState,
|
|
VisibilityArchivalUri: visibilityArchivalURI,
|
|
BadBinaries: badBinaries,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive,
|
|
Clusters: clusters,
|
|
},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.NoError(err1)
|
|
m.EqualValues(id, resp1.ID)
|
|
|
|
resp2, err2 := m.GetNamespace(id, "")
|
|
m.NoError(err2)
|
|
m.ProtoEqual(badBinaries, resp2.Namespace.Config.BadBinaries)
|
|
metadata, err := m.MetadataManager.GetMetadata(m.ctx)
|
|
m.NoError(err)
|
|
notificationVersion := metadata.NotificationVersion
|
|
|
|
testBinaries := &namespacepb.BadBinaries{
|
|
Binaries: map[string]*namespacepb.BadBinaryInfo{
|
|
"abc": {
|
|
Reason: "test-reason",
|
|
Operator: "test-operator",
|
|
CreateTime: timestamppb.New(time.Date(2020, 8, 22, 0, 0, 0, 0, time.UTC)),
|
|
},
|
|
},
|
|
}
|
|
concurrency := 16
|
|
successCount := int32(0)
|
|
var wg sync.WaitGroup
|
|
for i := 1; i <= concurrency; i++ {
|
|
newValue := fmt.Sprintf("v-%v", i)
|
|
wg.Add(1)
|
|
go func(updatedData map[string]string) {
|
|
err3 := m.UpdateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: resp2.Namespace.Info.Id,
|
|
Name: resp2.Namespace.Info.Name,
|
|
State: resp2.Namespace.Info.State,
|
|
Description: resp2.Namespace.Info.Description,
|
|
Owner: resp2.Namespace.Info.Owner,
|
|
Data: updatedData,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: resp2.Namespace.Config.Retention,
|
|
HistoryArchivalState: resp2.Namespace.Config.HistoryArchivalState,
|
|
HistoryArchivalUri: resp2.Namespace.Config.HistoryArchivalUri,
|
|
VisibilityArchivalState: resp2.Namespace.Config.VisibilityArchivalState,
|
|
VisibilityArchivalUri: resp2.Namespace.Config.VisibilityArchivalUri,
|
|
BadBinaries: testBinaries,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: resp2.Namespace.ReplicationConfig.ActiveClusterName,
|
|
Clusters: resp2.Namespace.ReplicationConfig.Clusters,
|
|
},
|
|
resp2.Namespace.ConfigVersion,
|
|
resp2.Namespace.FailoverVersion,
|
|
resp2.Namespace.FailoverNotificationVersion,
|
|
time.Time{},
|
|
notificationVersion,
|
|
isGlobalNamespace,
|
|
)
|
|
if err3 == nil {
|
|
atomic.AddInt32(&successCount, 1)
|
|
}
|
|
wg.Done()
|
|
}(map[string]string{"k0": newValue})
|
|
}
|
|
wg.Wait()
|
|
m.Equal(int32(1), successCount)
|
|
|
|
resp3, err3 := m.GetNamespace("", name)
|
|
m.NoError(err3)
|
|
m.NotNil(resp3)
|
|
m.EqualValues(id, resp3.Namespace.Info.Id)
|
|
m.Equal(name, resp3.Namespace.Info.Name)
|
|
m.Equal(state, resp3.Namespace.Info.State)
|
|
m.Equal(isGlobalNamespace, resp3.IsGlobalNamespace)
|
|
m.Equal(description, resp3.Namespace.Info.Description)
|
|
m.Equal(owner, resp3.Namespace.Info.Owner)
|
|
|
|
m.EqualValues(time.Duration(retention)*time.Hour*24, resp3.Namespace.Config.Retention.AsDuration())
|
|
m.Equal(historyArchivalState, resp3.Namespace.Config.HistoryArchivalState)
|
|
m.Equal(historyArchivalURI, resp3.Namespace.Config.HistoryArchivalUri)
|
|
m.Equal(visibilityArchivalState, resp3.Namespace.Config.VisibilityArchivalState)
|
|
m.Equal(visibilityArchivalURI, resp3.Namespace.Config.VisibilityArchivalUri)
|
|
m.ProtoEqual(testBinaries, resp3.Namespace.Config.BadBinaries)
|
|
m.Equal(clusterActive, resp3.Namespace.ReplicationConfig.ActiveClusterName)
|
|
m.Equal(len(clusters), len(resp3.Namespace.ReplicationConfig.Clusters))
|
|
for index := range clusters {
|
|
m.Equal(clusters[index], resp3.Namespace.ReplicationConfig.Clusters[index])
|
|
}
|
|
m.Equal(isGlobalNamespace, resp3.IsGlobalNamespace)
|
|
m.Equal(configVersion, resp3.Namespace.ConfigVersion)
|
|
m.Equal(failoverVersion, resp3.Namespace.FailoverVersion)
|
|
|
|
// check namespace data
|
|
ss := strings.Split(resp3.Namespace.Info.Data["k0"], "-")
|
|
m.Equal(2, len(ss))
|
|
vi, err := strconv.Atoi(ss[1])
|
|
m.NoError(err)
|
|
m.Equal(true, vi > 0 && vi <= concurrency)
|
|
}
|
|
|
|
// TestUpdateNamespace test
|
|
func (m *MetadataPersistenceSuiteV2) TestUpdateNamespace() {
|
|
id := uuid.NewString()
|
|
name := "update-namespace-test-name"
|
|
state := enumspb.NAMESPACE_STATE_REGISTERED
|
|
description := "update-namespace-test-description"
|
|
owner := "update-namespace-test-owner"
|
|
data := map[string]string{"k1": "v1"}
|
|
retention := int32(10)
|
|
historyArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
historyArchivalURI := "test://history/uri"
|
|
visibilityArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
visibilityArchivalURI := "test://visibility/uri"
|
|
|
|
clusterActive := "some random active cluster name"
|
|
clusterStandby := "some random standby cluster name"
|
|
configVersion := int64(10)
|
|
failoverVersion := int64(59)
|
|
failoverEndTime := time.Now().UTC()
|
|
isGlobalNamespace := true
|
|
clusters := []string{clusterActive, clusterStandby}
|
|
|
|
resp1, err1 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id,
|
|
Name: name,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
Data: data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention),
|
|
HistoryArchivalState: historyArchivalState,
|
|
HistoryArchivalUri: historyArchivalURI,
|
|
VisibilityArchivalState: visibilityArchivalState,
|
|
VisibilityArchivalUri: visibilityArchivalURI,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive,
|
|
Clusters: clusters,
|
|
},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.NoError(err1)
|
|
m.EqualValues(id, resp1.ID)
|
|
|
|
resp2, err2 := m.GetNamespace(id, "")
|
|
m.NoError(err2)
|
|
metadata, err := m.MetadataManager.GetMetadata(m.ctx)
|
|
m.NoError(err)
|
|
notificationVersion := metadata.NotificationVersion
|
|
|
|
updatedState := enumspb.NAMESPACE_STATE_DEPRECATED
|
|
updatedDescription := "description-updated"
|
|
updatedOwner := "owner-updated"
|
|
// This will overriding the previous key-value pair
|
|
updatedData := map[string]string{"k1": "v2"}
|
|
updatedRetention := timestamp.DurationFromDays(20)
|
|
updatedHistoryArchivalState := enumspb.ARCHIVAL_STATE_DISABLED
|
|
updatedHistoryArchivalURI := ""
|
|
updatedVisibilityArchivalState := enumspb.ARCHIVAL_STATE_DISABLED
|
|
updatedVisibilityArchivalURI := ""
|
|
|
|
updateClusterActive := "other random active cluster name"
|
|
updateClusterStandby := "other random standby cluster name"
|
|
updateConfigVersion := int64(12)
|
|
updateFailoverVersion := int64(28)
|
|
updateFailoverNotificationVersion := int64(14)
|
|
updateClusters := []string{updateClusterActive, updateClusterStandby}
|
|
|
|
testBinaries := &namespacepb.BadBinaries{
|
|
Binaries: map[string]*namespacepb.BadBinaryInfo{
|
|
"abc": {
|
|
Reason: "test-reason",
|
|
Operator: "test-operator",
|
|
CreateTime: timestamppb.New(time.Date(2020, 8, 22, 0, 0, 0, 0, time.UTC)),
|
|
},
|
|
},
|
|
}
|
|
|
|
err3 := m.UpdateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: resp2.Namespace.Info.Id,
|
|
Name: resp2.Namespace.Info.Name,
|
|
State: updatedState,
|
|
Description: updatedDescription,
|
|
Owner: updatedOwner,
|
|
Data: updatedData,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: updatedRetention,
|
|
HistoryArchivalState: updatedHistoryArchivalState,
|
|
HistoryArchivalUri: updatedHistoryArchivalURI,
|
|
VisibilityArchivalState: updatedVisibilityArchivalState,
|
|
VisibilityArchivalUri: updatedVisibilityArchivalURI,
|
|
BadBinaries: testBinaries,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: updateClusterActive,
|
|
Clusters: updateClusters,
|
|
},
|
|
updateConfigVersion,
|
|
updateFailoverVersion,
|
|
updateFailoverNotificationVersion,
|
|
failoverEndTime,
|
|
notificationVersion,
|
|
isGlobalNamespace,
|
|
)
|
|
m.NoError(err3)
|
|
|
|
resp4, err4 := m.GetNamespace("", name)
|
|
m.NoError(err4)
|
|
m.NotNil(resp4)
|
|
m.EqualValues(id, resp4.Namespace.Info.Id)
|
|
m.Equal(name, resp4.Namespace.Info.Name)
|
|
m.Equal(isGlobalNamespace, resp4.IsGlobalNamespace)
|
|
m.Equal(updatedState, resp4.Namespace.Info.State)
|
|
m.Equal(updatedDescription, resp4.Namespace.Info.Description)
|
|
m.Equal(updatedOwner, resp4.Namespace.Info.Owner)
|
|
m.Equal(updatedData, resp4.Namespace.Info.Data)
|
|
m.ProtoEqual(updatedRetention, resp4.Namespace.Config.Retention)
|
|
m.Equal(updatedHistoryArchivalState, resp4.Namespace.Config.HistoryArchivalState)
|
|
m.Equal(updatedHistoryArchivalURI, resp4.Namespace.Config.HistoryArchivalUri)
|
|
m.Equal(updatedVisibilityArchivalState, resp4.Namespace.Config.VisibilityArchivalState)
|
|
m.Equal(updatedVisibilityArchivalURI, resp4.Namespace.Config.VisibilityArchivalUri)
|
|
m.ProtoEqual(testBinaries, resp4.Namespace.Config.BadBinaries)
|
|
m.Equal(updateClusterActive, resp4.Namespace.ReplicationConfig.ActiveClusterName)
|
|
m.Equal(len(updateClusters), len(resp4.Namespace.ReplicationConfig.Clusters))
|
|
for index := range clusters {
|
|
m.Equal(updateClusters[index], resp4.Namespace.ReplicationConfig.Clusters[index])
|
|
}
|
|
m.Equal(updateConfigVersion, resp4.Namespace.ConfigVersion)
|
|
m.Equal(updateFailoverVersion, resp4.Namespace.FailoverVersion)
|
|
m.Equal(updateFailoverNotificationVersion, resp4.Namespace.FailoverNotificationVersion)
|
|
m.Equal(notificationVersion, resp4.NotificationVersion)
|
|
m.EqualTimes(failoverEndTime, resp4.Namespace.FailoverEndTime.AsTime())
|
|
|
|
resp5, err5 := m.GetNamespace(id, "")
|
|
m.NoError(err5)
|
|
m.NotNil(resp5)
|
|
m.EqualValues(id, resp5.Namespace.Info.Id)
|
|
m.Equal(name, resp5.Namespace.Info.Name)
|
|
m.Equal(isGlobalNamespace, resp5.IsGlobalNamespace)
|
|
m.Equal(updatedState, resp5.Namespace.Info.State)
|
|
m.Equal(updatedDescription, resp5.Namespace.Info.Description)
|
|
m.Equal(updatedOwner, resp5.Namespace.Info.Owner)
|
|
m.Equal(updatedData, resp5.Namespace.Info.Data)
|
|
m.ProtoEqual(updatedRetention, resp5.Namespace.Config.Retention)
|
|
m.Equal(updatedHistoryArchivalState, resp5.Namespace.Config.HistoryArchivalState)
|
|
m.Equal(updatedHistoryArchivalURI, resp5.Namespace.Config.HistoryArchivalUri)
|
|
m.Equal(updatedVisibilityArchivalState, resp5.Namespace.Config.VisibilityArchivalState)
|
|
m.Equal(updatedVisibilityArchivalURI, resp5.Namespace.Config.VisibilityArchivalUri)
|
|
m.Equal(updateClusterActive, resp5.Namespace.ReplicationConfig.ActiveClusterName)
|
|
m.Equal(len(updateClusters), len(resp5.Namespace.ReplicationConfig.Clusters))
|
|
for index := range clusters {
|
|
m.Equal(updateClusters[index], resp5.Namespace.ReplicationConfig.Clusters[index])
|
|
}
|
|
m.Equal(updateConfigVersion, resp5.Namespace.ConfigVersion)
|
|
m.Equal(updateFailoverVersion, resp5.Namespace.FailoverVersion)
|
|
m.Equal(updateFailoverNotificationVersion, resp5.Namespace.FailoverNotificationVersion)
|
|
m.Equal(notificationVersion, resp5.NotificationVersion)
|
|
m.EqualTimes(failoverEndTime, resp4.Namespace.FailoverEndTime.AsTime())
|
|
|
|
notificationVersion++
|
|
err6 := m.UpdateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: resp2.Namespace.Info.Id,
|
|
Name: resp2.Namespace.Info.Name,
|
|
State: updatedState,
|
|
Description: updatedDescription,
|
|
Owner: updatedOwner,
|
|
Data: updatedData,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: updatedRetention,
|
|
HistoryArchivalState: updatedHistoryArchivalState,
|
|
HistoryArchivalUri: updatedHistoryArchivalURI,
|
|
VisibilityArchivalState: updatedVisibilityArchivalState,
|
|
VisibilityArchivalUri: updatedVisibilityArchivalURI,
|
|
BadBinaries: testBinaries,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: updateClusterActive,
|
|
Clusters: updateClusters,
|
|
},
|
|
updateConfigVersion,
|
|
updateFailoverVersion,
|
|
updateFailoverNotificationVersion,
|
|
time.Time{},
|
|
notificationVersion,
|
|
isGlobalNamespace,
|
|
)
|
|
m.NoError(err6)
|
|
|
|
resp6, err6 := m.GetNamespace(id, "")
|
|
m.NoError(err6)
|
|
m.NotNil(resp6)
|
|
m.EqualValues(id, resp6.Namespace.Info.Id)
|
|
m.Equal(name, resp6.Namespace.Info.Name)
|
|
m.Equal(isGlobalNamespace, resp6.IsGlobalNamespace)
|
|
m.Equal(updatedState, resp6.Namespace.Info.State)
|
|
m.Equal(updatedDescription, resp6.Namespace.Info.Description)
|
|
m.Equal(updatedOwner, resp6.Namespace.Info.Owner)
|
|
m.Equal(updatedData, resp6.Namespace.Info.Data)
|
|
m.ProtoEqual(updatedRetention, resp6.Namespace.Config.Retention)
|
|
m.Equal(updatedHistoryArchivalState, resp6.Namespace.Config.HistoryArchivalState)
|
|
m.Equal(updatedHistoryArchivalURI, resp6.Namespace.Config.HistoryArchivalUri)
|
|
m.Equal(updatedVisibilityArchivalState, resp6.Namespace.Config.VisibilityArchivalState)
|
|
m.Equal(updatedVisibilityArchivalURI, resp6.Namespace.Config.VisibilityArchivalUri)
|
|
m.ProtoEqual(testBinaries, resp6.Namespace.Config.BadBinaries)
|
|
m.Equal(updateClusterActive, resp6.Namespace.ReplicationConfig.ActiveClusterName)
|
|
m.Equal(len(updateClusters), len(resp6.Namespace.ReplicationConfig.Clusters))
|
|
for index := range clusters {
|
|
m.Equal(updateClusters[index], resp4.Namespace.ReplicationConfig.Clusters[index])
|
|
}
|
|
m.Equal(updateConfigVersion, resp6.Namespace.ConfigVersion)
|
|
m.Equal(updateFailoverVersion, resp6.Namespace.FailoverVersion)
|
|
m.Equal(updateFailoverNotificationVersion, resp6.Namespace.FailoverNotificationVersion)
|
|
m.Equal(notificationVersion, resp6.NotificationVersion)
|
|
m.EqualTimes(time.Unix(0, 0).UTC(), resp6.Namespace.FailoverEndTime.AsTime())
|
|
}
|
|
|
|
func (m *MetadataPersistenceSuiteV2) TestRenameNamespace() {
|
|
id := uuid.NewString()
|
|
name := "rename-namespace-test-name"
|
|
newName := "rename-namespace-test-new-name"
|
|
newNewName := "rename-namespace-test-new-new-name"
|
|
state := enumspb.NAMESPACE_STATE_REGISTERED
|
|
description := "rename-namespace-test-description"
|
|
owner := "rename-namespace-test-owner"
|
|
data := map[string]string{"k1": "v1"}
|
|
retention := int32(10)
|
|
historyArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
historyArchivalURI := "test://history/uri"
|
|
visibilityArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
visibilityArchivalURI := "test://visibility/uri"
|
|
|
|
clusterActive := "some random active cluster name"
|
|
clusterStandby := "some random standby cluster name"
|
|
configVersion := int64(10)
|
|
failoverVersion := int64(59)
|
|
isGlobalNamespace := true
|
|
clusters := []string{clusterActive, clusterStandby}
|
|
|
|
resp1, err1 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id,
|
|
Name: name,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
Data: data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention),
|
|
HistoryArchivalState: historyArchivalState,
|
|
HistoryArchivalUri: historyArchivalURI,
|
|
VisibilityArchivalState: visibilityArchivalState,
|
|
VisibilityArchivalUri: visibilityArchivalURI,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive,
|
|
Clusters: clusters,
|
|
},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.NoError(err1)
|
|
m.EqualValues(id, resp1.ID)
|
|
|
|
_, err2 := m.GetNamespace(id, "")
|
|
m.NoError(err2)
|
|
|
|
err3 := m.MetadataManager.RenameNamespace(m.ctx, &p.RenameNamespaceRequest{
|
|
PreviousName: name,
|
|
NewName: newName,
|
|
})
|
|
m.NoError(err3)
|
|
|
|
resp4, err4 := m.GetNamespace("", newName)
|
|
m.NoError(err4)
|
|
m.NotNil(resp4)
|
|
m.EqualValues(id, resp4.Namespace.Info.Id)
|
|
m.Equal(newName, resp4.Namespace.Info.Name)
|
|
m.Equal(isGlobalNamespace, resp4.IsGlobalNamespace)
|
|
|
|
resp5, err5 := m.GetNamespace(id, "")
|
|
m.NoError(err5)
|
|
m.NotNil(resp5)
|
|
m.EqualValues(id, resp5.Namespace.Info.Id)
|
|
m.Equal(newName, resp5.Namespace.Info.Name)
|
|
m.Equal(isGlobalNamespace, resp5.IsGlobalNamespace)
|
|
|
|
err6 := m.MetadataManager.RenameNamespace(m.ctx, &p.RenameNamespaceRequest{
|
|
PreviousName: newName,
|
|
NewName: newNewName,
|
|
})
|
|
m.NoError(err6)
|
|
|
|
resp6, err6 := m.GetNamespace(id, "")
|
|
m.NoError(err6)
|
|
m.NotNil(resp6)
|
|
m.EqualValues(id, resp6.Namespace.Info.Id)
|
|
m.Equal(newNewName, resp6.Namespace.Info.Name)
|
|
m.Equal(isGlobalNamespace, resp6.IsGlobalNamespace)
|
|
}
|
|
|
|
// TestDeleteNamespace test
|
|
func (m *MetadataPersistenceSuiteV2) TestDeleteNamespace() {
|
|
id := uuid.NewString()
|
|
name := "delete-namespace-test-name"
|
|
state := enumspb.NAMESPACE_STATE_REGISTERED
|
|
description := "delete-namespace-test-description"
|
|
owner := "delete-namespace-test-owner"
|
|
data := map[string]string{"k1": "v1"}
|
|
retention := timestamp.DurationFromDays(10)
|
|
historyArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
historyArchivalURI := "test://history/uri"
|
|
visibilityArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
visibilityArchivalURI := "test://visibility/uri"
|
|
|
|
clusterActive := "some random active cluster name"
|
|
clusterStandby := "some random standby cluster name"
|
|
configVersion := int64(10)
|
|
failoverVersion := int64(59)
|
|
isGlobalNamespace := true
|
|
clusters := []string{clusterActive, clusterStandby}
|
|
|
|
resp1, err1 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id,
|
|
Name: name,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
Data: data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: retention,
|
|
HistoryArchivalState: historyArchivalState,
|
|
HistoryArchivalUri: historyArchivalURI,
|
|
VisibilityArchivalState: visibilityArchivalState,
|
|
VisibilityArchivalUri: visibilityArchivalURI,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive,
|
|
Clusters: clusters,
|
|
},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.NoError(err1)
|
|
m.EqualValues(id, resp1.ID)
|
|
|
|
resp2, err2 := m.GetNamespace("", name)
|
|
m.NoError(err2)
|
|
m.NotNil(resp2)
|
|
|
|
err3 := m.DeleteNamespace("", name)
|
|
m.NoError(err3)
|
|
|
|
// May need to loop here to avoid potential inconsistent read-after-write in cassandra
|
|
m.Eventually(
|
|
func() bool {
|
|
resp, err := m.GetNamespace("", name)
|
|
if errors.As(err, new(*serviceerror.NamespaceNotFound)) {
|
|
m.Nil(resp)
|
|
return true
|
|
}
|
|
return false
|
|
},
|
|
10*time.Second,
|
|
100*time.Millisecond,
|
|
)
|
|
|
|
resp5, err5 := m.GetNamespace(id, "")
|
|
m.Error(err5)
|
|
m.IsType(&serviceerror.NamespaceNotFound{}, err5)
|
|
m.Nil(resp5)
|
|
|
|
id = uuid.NewString()
|
|
resp6, err6 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id,
|
|
Name: name,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
Data: data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: retention,
|
|
HistoryArchivalState: historyArchivalState,
|
|
HistoryArchivalUri: historyArchivalURI,
|
|
VisibilityArchivalState: visibilityArchivalState,
|
|
VisibilityArchivalUri: visibilityArchivalURI,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive,
|
|
Clusters: clusters,
|
|
},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.NoError(err6)
|
|
m.EqualValues(id, resp6.ID)
|
|
|
|
err7 := m.DeleteNamespace(id, "")
|
|
m.NoError(err7)
|
|
|
|
resp8, err8 := m.GetNamespace("", name)
|
|
m.Error(err8)
|
|
m.IsType(&serviceerror.NamespaceNotFound{}, err8)
|
|
m.Nil(resp8)
|
|
|
|
resp9, err9 := m.GetNamespace(id, "")
|
|
m.Error(err9)
|
|
m.IsType(&serviceerror.NamespaceNotFound{}, err9)
|
|
m.Nil(resp9)
|
|
}
|
|
|
|
// TestListNamespaces test
|
|
func (m *MetadataPersistenceSuiteV2) TestListNamespaces() {
|
|
clusterActive1 := "some random active cluster name"
|
|
clusterStandby1 := "some random standby cluster name"
|
|
clusters1 := []string{clusterActive1, clusterStandby1}
|
|
|
|
clusterActive2 := "other random active cluster name"
|
|
clusterStandby2 := "other random standby cluster name"
|
|
clusters2 := []string{clusterActive2, clusterStandby2}
|
|
|
|
testBinaries1 := &namespacepb.BadBinaries{
|
|
Binaries: map[string]*namespacepb.BadBinaryInfo{
|
|
"abc": {
|
|
Reason: "test-reason1",
|
|
Operator: "test-operator1",
|
|
CreateTime: timestamppb.New(time.Date(2020, 8, 22, 0, 0, 0, 0, time.UTC)),
|
|
},
|
|
},
|
|
}
|
|
testBinaries2 := &namespacepb.BadBinaries{
|
|
Binaries: map[string]*namespacepb.BadBinaryInfo{
|
|
"efg": {
|
|
Reason: "test-reason2",
|
|
Operator: "test-operator2",
|
|
CreateTime: timestamppb.New(time.Date(2020, 8, 22, 0, 0, 0, 0, time.UTC)),
|
|
},
|
|
},
|
|
}
|
|
|
|
inputNamespaces := []*p.GetNamespaceResponse{
|
|
{
|
|
Namespace: &persistencespb.NamespaceDetail{
|
|
Info: &persistencespb.NamespaceInfo{
|
|
Id: uuid.NewString(),
|
|
Name: "list-namespace-test-name-1",
|
|
State: enumspb.NAMESPACE_STATE_REGISTERED,
|
|
Description: "list-namespace-test-description-1",
|
|
Owner: "list-namespace-test-owner-1",
|
|
Data: map[string]string{"k1": "v1"},
|
|
},
|
|
Config: &persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(109),
|
|
HistoryArchivalState: enumspb.ARCHIVAL_STATE_ENABLED,
|
|
HistoryArchivalUri: "test://history/uri",
|
|
VisibilityArchivalState: enumspb.ARCHIVAL_STATE_ENABLED,
|
|
VisibilityArchivalUri: "test://visibility/uri",
|
|
BadBinaries: testBinaries1,
|
|
},
|
|
ReplicationConfig: &persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive1,
|
|
Clusters: clusters1,
|
|
},
|
|
|
|
ConfigVersion: 133,
|
|
FailoverVersion: 266,
|
|
},
|
|
IsGlobalNamespace: true,
|
|
},
|
|
{
|
|
Namespace: &persistencespb.NamespaceDetail{
|
|
Info: &persistencespb.NamespaceInfo{
|
|
Id: uuid.NewString(),
|
|
Name: "list-namespace-test-name-2",
|
|
State: enumspb.NAMESPACE_STATE_REGISTERED,
|
|
Description: "list-namespace-test-description-2",
|
|
Owner: "list-namespace-test-owner-2",
|
|
Data: map[string]string{"k1": "v2"},
|
|
},
|
|
Config: &persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(326),
|
|
HistoryArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
|
|
HistoryArchivalUri: "",
|
|
VisibilityArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
|
|
VisibilityArchivalUri: "",
|
|
BadBinaries: testBinaries2,
|
|
},
|
|
ReplicationConfig: &persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive2,
|
|
Clusters: clusters2,
|
|
},
|
|
ConfigVersion: 400,
|
|
FailoverVersion: 667,
|
|
},
|
|
IsGlobalNamespace: false,
|
|
},
|
|
}
|
|
for _, namespace := range inputNamespaces {
|
|
_, err := m.CreateNamespace(
|
|
namespace.Namespace.Info,
|
|
namespace.Namespace.Config,
|
|
namespace.Namespace.ReplicationConfig,
|
|
namespace.IsGlobalNamespace,
|
|
namespace.Namespace.ConfigVersion,
|
|
namespace.Namespace.FailoverVersion,
|
|
)
|
|
m.NoError(err)
|
|
}
|
|
|
|
var token []byte
|
|
const pageSize = 1
|
|
pageCount := 0
|
|
outputNamespaces := make(map[string]*p.GetNamespaceResponse)
|
|
for {
|
|
resp, err := m.ListNamespaces(pageSize, token)
|
|
m.NoError(err)
|
|
token = resp.NextPageToken
|
|
for _, namespace := range resp.Namespaces {
|
|
outputNamespaces[namespace.Namespace.Info.Id] = namespace
|
|
// global notification version is already tested, so here we make it 0
|
|
// so we can test == easily
|
|
namespace.NotificationVersion = 0
|
|
}
|
|
// Some persistence backends return an unavoidable empty final page.
|
|
if len(resp.Namespaces) > 0 {
|
|
pageCount++
|
|
}
|
|
if len(token) == 0 {
|
|
break
|
|
}
|
|
}
|
|
|
|
// There should be 2 non-empty pages.
|
|
m.Equal(pageCount, 2)
|
|
m.Equal(len(inputNamespaces), len(outputNamespaces))
|
|
for _, namespace := range inputNamespaces {
|
|
m.DeepEqual(namespace, outputNamespaces[namespace.Namespace.Info.Id])
|
|
}
|
|
}
|
|
|
|
func (m *MetadataPersistenceSuiteV2) TestListNamespaces_DeletedNamespace() {
|
|
inputNamespaces := []*p.GetNamespaceResponse{
|
|
{
|
|
Namespace: &persistencespb.NamespaceDetail{
|
|
Info: &persistencespb.NamespaceInfo{
|
|
Id: uuid.NewString(),
|
|
Name: "list-namespace-test-name-1",
|
|
State: enumspb.NAMESPACE_STATE_REGISTERED,
|
|
},
|
|
Config: &persistencespb.NamespaceConfig{},
|
|
ReplicationConfig: &persistencespb.NamespaceReplicationConfig{},
|
|
},
|
|
},
|
|
{
|
|
Namespace: &persistencespb.NamespaceDetail{
|
|
Info: &persistencespb.NamespaceInfo{
|
|
Id: uuid.NewString(),
|
|
Name: "list-namespace-test-name-2",
|
|
State: enumspb.NAMESPACE_STATE_DELETED,
|
|
},
|
|
Config: &persistencespb.NamespaceConfig{},
|
|
ReplicationConfig: &persistencespb.NamespaceReplicationConfig{},
|
|
},
|
|
},
|
|
{
|
|
Namespace: &persistencespb.NamespaceDetail{
|
|
Info: &persistencespb.NamespaceInfo{
|
|
Id: uuid.NewString(),
|
|
Name: "list-namespace-test-name-3",
|
|
State: enumspb.NAMESPACE_STATE_REGISTERED,
|
|
},
|
|
Config: &persistencespb.NamespaceConfig{},
|
|
ReplicationConfig: &persistencespb.NamespaceReplicationConfig{},
|
|
},
|
|
},
|
|
{
|
|
Namespace: &persistencespb.NamespaceDetail{
|
|
Info: &persistencespb.NamespaceInfo{
|
|
Id: uuid.NewString(),
|
|
Name: "list-namespace-test-name-4",
|
|
State: enumspb.NAMESPACE_STATE_DELETED,
|
|
},
|
|
Config: &persistencespb.NamespaceConfig{},
|
|
ReplicationConfig: &persistencespb.NamespaceReplicationConfig{},
|
|
},
|
|
},
|
|
}
|
|
for _, namespace := range inputNamespaces {
|
|
_, err := m.CreateNamespace(
|
|
namespace.Namespace.Info,
|
|
namespace.Namespace.Config,
|
|
namespace.Namespace.ReplicationConfig,
|
|
namespace.IsGlobalNamespace,
|
|
namespace.Namespace.ConfigVersion,
|
|
namespace.Namespace.FailoverVersion,
|
|
)
|
|
m.NoError(err)
|
|
}
|
|
|
|
var token []byte
|
|
var listNamespacesPageSize2 []*p.GetNamespaceResponse
|
|
pageCount := 0
|
|
for {
|
|
resp, err := m.ListNamespaces(2, token)
|
|
m.NoError(err)
|
|
token = resp.NextPageToken
|
|
listNamespacesPageSize2 = append(listNamespacesPageSize2, resp.Namespaces...)
|
|
// Some persistence backends return an unavoidable empty final page.
|
|
if len(resp.Namespaces) > 0 {
|
|
pageCount++
|
|
}
|
|
if len(token) == 0 {
|
|
break
|
|
}
|
|
}
|
|
|
|
// There should be 1 non-empty page.
|
|
m.Equal(1, pageCount)
|
|
m.Len(listNamespacesPageSize2, 2)
|
|
for _, namespace := range listNamespacesPageSize2 {
|
|
m.NotEqual(namespace.Namespace.Info.State, enumspb.NAMESPACE_STATE_DELETED)
|
|
}
|
|
|
|
pageCount = 0
|
|
var listNamespacesPageSize1 []*p.GetNamespaceResponse
|
|
for {
|
|
resp, err := m.ListNamespaces(1, token)
|
|
m.NoError(err)
|
|
token = resp.NextPageToken
|
|
listNamespacesPageSize1 = append(listNamespacesPageSize1, resp.Namespaces...)
|
|
// Some persistence backends return an unavoidable empty final page.
|
|
if len(resp.Namespaces) > 0 {
|
|
pageCount++
|
|
}
|
|
if len(token) == 0 {
|
|
break
|
|
}
|
|
}
|
|
|
|
// There should be 2 non-empty pages.
|
|
m.Equal(2, pageCount)
|
|
m.Len(listNamespacesPageSize1, 2)
|
|
for _, namespace := range listNamespacesPageSize1 {
|
|
m.NotEqual(namespace.Namespace.Info.State, enumspb.NAMESPACE_STATE_DELETED)
|
|
}
|
|
}
|
|
|
|
// CreateNamespace helper method
|
|
func (m *MetadataPersistenceSuiteV2) CreateNamespace(info *persistencespb.NamespaceInfo, config *persistencespb.NamespaceConfig,
|
|
replicationConfig *persistencespb.NamespaceReplicationConfig, isGlobalnamespace bool, configVersion int64, failoverVersion int64) (*p.CreateNamespaceResponse, error) {
|
|
return m.MetadataManager.CreateNamespace(m.ctx, &p.CreateNamespaceRequest{
|
|
Namespace: &persistencespb.NamespaceDetail{
|
|
Info: info,
|
|
Config: config,
|
|
ReplicationConfig: replicationConfig,
|
|
|
|
ConfigVersion: configVersion,
|
|
FailoverVersion: failoverVersion,
|
|
}, IsGlobalNamespace: isGlobalnamespace,
|
|
})
|
|
}
|
|
|
|
// GetNamespace helper method
|
|
func (m *MetadataPersistenceSuiteV2) GetNamespace(id string, name string) (*p.GetNamespaceResponse, error) {
|
|
return m.MetadataManager.GetNamespace(m.ctx, &p.GetNamespaceRequest{
|
|
ID: id,
|
|
Name: name,
|
|
})
|
|
}
|
|
|
|
// UpdateNamespace helper method
|
|
func (m *MetadataPersistenceSuiteV2) UpdateNamespace(
|
|
info *persistencespb.NamespaceInfo,
|
|
config *persistencespb.NamespaceConfig,
|
|
replicationConfig *persistencespb.NamespaceReplicationConfig,
|
|
configVersion int64,
|
|
failoverVersion int64,
|
|
failoverNotificationVersion int64,
|
|
failoverEndTime time.Time,
|
|
notificationVersion int64,
|
|
isGlobalNamespace bool,
|
|
) error {
|
|
return m.MetadataManager.UpdateNamespace(m.ctx, &p.UpdateNamespaceRequest{
|
|
Namespace: &persistencespb.NamespaceDetail{
|
|
Info: info,
|
|
Config: config,
|
|
ReplicationConfig: replicationConfig,
|
|
ConfigVersion: configVersion,
|
|
FailoverVersion: failoverVersion,
|
|
FailoverEndTime: timestamppb.New(failoverEndTime),
|
|
FailoverNotificationVersion: failoverNotificationVersion,
|
|
},
|
|
NotificationVersion: notificationVersion,
|
|
IsGlobalNamespace: isGlobalNamespace,
|
|
})
|
|
}
|
|
|
|
// DeleteNamespace helper method
|
|
func (m *MetadataPersistenceSuiteV2) DeleteNamespace(id string, name string) error {
|
|
if len(id) > 0 {
|
|
return m.MetadataManager.DeleteNamespace(m.ctx, &p.DeleteNamespaceRequest{ID: id})
|
|
}
|
|
return m.MetadataManager.DeleteNamespaceByName(m.ctx, &p.DeleteNamespaceByNameRequest{Name: name})
|
|
}
|
|
|
|
// ListNamespaces helper method
|
|
func (m *MetadataPersistenceSuiteV2) ListNamespaces(pageSize int, pageToken []byte) (*p.ListNamespacesResponse, error) {
|
|
return m.MetadataManager.ListNamespaces(m.ctx, &p.ListNamespacesRequest{
|
|
PageSize: pageSize,
|
|
NextPageToken: pageToken,
|
|
})
|
|
}
|
|
|
|
// TestCASFailureUpdateNamespace tests CAS failure when trying to update a namespace
|
|
func (m *MetadataPersistenceSuiteV2) TestCASFailureUpdateNamespace() {
|
|
id := uuid.NewString()
|
|
name := "cas-update-namespace-test-name"
|
|
state := enumspb.NAMESPACE_STATE_REGISTERED
|
|
description := "cas-update-namespace-test-description"
|
|
owner := "cas-update-namespace-test-owner"
|
|
data := map[string]string{"k1": "v1"}
|
|
retention := int32(10)
|
|
historyArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
historyArchivalURI := "test://history/uri"
|
|
visibilityArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
visibilityArchivalURI := "test://visibility/uri"
|
|
badBinaries := &namespacepb.BadBinaries{Binaries: map[string]*namespacepb.BadBinaryInfo{}}
|
|
|
|
clusterActive := "some random active cluster name"
|
|
clusterStandby := "some random standby cluster name"
|
|
configVersion := int64(10)
|
|
failoverVersion := int64(59)
|
|
isGlobalNamespace := true
|
|
clusters := []string{clusterActive, clusterStandby}
|
|
|
|
resp1, err1 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id,
|
|
Name: name,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
Data: data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention),
|
|
HistoryArchivalState: historyArchivalState,
|
|
HistoryArchivalUri: historyArchivalURI,
|
|
VisibilityArchivalState: visibilityArchivalState,
|
|
VisibilityArchivalUri: visibilityArchivalURI,
|
|
BadBinaries: badBinaries,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive,
|
|
Clusters: clusters,
|
|
},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.NoError(err1)
|
|
m.EqualValues(id, resp1.ID)
|
|
|
|
resp2, err2 := m.GetNamespace(id, "")
|
|
m.NoError(err2)
|
|
metadata, err := m.MetadataManager.GetMetadata(m.ctx)
|
|
m.NoError(err)
|
|
notificationVersion := metadata.NotificationVersion
|
|
|
|
updatedDescription := "description-updated"
|
|
|
|
// Try to update with wrong notification version (stale version)
|
|
err3 := m.UpdateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: resp2.Namespace.Info.Id,
|
|
Name: resp2.Namespace.Info.Name,
|
|
State: resp2.Namespace.Info.State,
|
|
Description: updatedDescription,
|
|
Owner: resp2.Namespace.Info.Owner,
|
|
Data: resp2.Namespace.Info.Data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: resp2.Namespace.Config.Retention,
|
|
HistoryArchivalState: resp2.Namespace.Config.HistoryArchivalState,
|
|
HistoryArchivalUri: resp2.Namespace.Config.HistoryArchivalUri,
|
|
VisibilityArchivalState: resp2.Namespace.Config.VisibilityArchivalState,
|
|
VisibilityArchivalUri: resp2.Namespace.Config.VisibilityArchivalUri,
|
|
BadBinaries: badBinaries,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: resp2.Namespace.ReplicationConfig.ActiveClusterName,
|
|
Clusters: resp2.Namespace.ReplicationConfig.Clusters,
|
|
},
|
|
resp2.Namespace.ConfigVersion,
|
|
resp2.Namespace.FailoverVersion,
|
|
resp2.Namespace.FailoverNotificationVersion,
|
|
time.Time{},
|
|
notificationVersion-1, // Use stale notification version to trigger CAS failure
|
|
isGlobalNamespace,
|
|
)
|
|
m.ErrorAs(err3, new(*serviceerror.Unavailable))
|
|
|
|
// Verify that the namespace was not updated
|
|
resp4, err4 := m.GetNamespace(id, "")
|
|
m.NoError(err4)
|
|
m.Equal(description, resp4.Namespace.Info.Description) // Should still have old description
|
|
}
|
|
|
|
// TestRenameNamespaceWithNameConflict tests name conflict when trying to rename a namespace
|
|
func (m *MetadataPersistenceSuiteV2) TestRenameNamespaceWithNameConflict() {
|
|
id1 := uuid.NewString()
|
|
name1 := "rename-conflict-namespace-1"
|
|
id2 := uuid.NewString()
|
|
name2 := "rename-conflict-namespace-2"
|
|
state := enumspb.NAMESPACE_STATE_REGISTERED
|
|
description := "rename-conflict-test-description"
|
|
owner := "rename-conflict-test-owner"
|
|
data := map[string]string{"k1": "v1"}
|
|
retention := int32(10)
|
|
historyArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
historyArchivalURI := "test://history/uri"
|
|
visibilityArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
visibilityArchivalURI := "test://visibility/uri"
|
|
|
|
clusterActive := "some random active cluster name"
|
|
clusterStandby := "some random standby cluster name"
|
|
configVersion := int64(10)
|
|
failoverVersion := int64(59)
|
|
isGlobalNamespace := true
|
|
clusters := []string{clusterActive, clusterStandby}
|
|
|
|
// Create first namespace
|
|
resp1, err1 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id1,
|
|
Name: name1,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
Data: data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention),
|
|
HistoryArchivalState: historyArchivalState,
|
|
HistoryArchivalUri: historyArchivalURI,
|
|
VisibilityArchivalState: visibilityArchivalState,
|
|
VisibilityArchivalUri: visibilityArchivalURI,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive,
|
|
Clusters: clusters,
|
|
},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.NoError(err1)
|
|
m.EqualValues(id1, resp1.ID)
|
|
|
|
// Create second namespace
|
|
resp2, err2 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id2,
|
|
Name: name2,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
Data: data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention),
|
|
HistoryArchivalState: historyArchivalState,
|
|
HistoryArchivalUri: historyArchivalURI,
|
|
VisibilityArchivalState: visibilityArchivalState,
|
|
VisibilityArchivalUri: visibilityArchivalURI,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive,
|
|
Clusters: clusters,
|
|
},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.NoError(err2)
|
|
m.EqualValues(id2, resp2.ID)
|
|
|
|
// Try to rename namespace1 to the same name as namespace2 (should fail)
|
|
err3 := m.MetadataManager.RenameNamespace(m.ctx, &p.RenameNamespaceRequest{
|
|
PreviousName: name1,
|
|
NewName: name2,
|
|
})
|
|
// The error should be a conflict/unavailable error due to CAS failure
|
|
m.ErrorAs(err3, new(*serviceerror.Unavailable))
|
|
|
|
// Verify that we can still query namespace2 by name, proving the rename didn't affect it
|
|
resp5, err5 := m.GetNamespace("", name2)
|
|
m.NoError(err5)
|
|
m.Equal(name2, resp5.Namespace.Info.Name)
|
|
m.Equal(id2, resp5.Namespace.Info.Id)
|
|
|
|
// Verify that namespace1 can still be queried by its original name
|
|
resp6, err6 := m.GetNamespace("", name1)
|
|
m.NoError(err6)
|
|
m.Equal(name1, resp6.Namespace.Info.Name)
|
|
m.Equal(id1, resp6.Namespace.Info.Id)
|
|
}
|
|
|
|
// TestGetMetadataVersionIncrement tests that GetMetadata correctly increments the version after a namespace is created
|
|
func (m *MetadataPersistenceSuiteV2) TestGetMetadataVersionIncrement() {
|
|
// Get initial metadata version
|
|
metadata1, err1 := m.MetadataManager.GetMetadata(m.ctx)
|
|
m.NoError(err1)
|
|
initialVersion := metadata1.NotificationVersion
|
|
|
|
// Create a namespace
|
|
id := uuid.NewString()
|
|
name := "metadata-version-test-namespace"
|
|
state := enumspb.NAMESPACE_STATE_REGISTERED
|
|
description := "metadata-version-test-description"
|
|
owner := "metadata-version-test-owner"
|
|
data := map[string]string{"k1": "v1"}
|
|
retention := int32(10)
|
|
historyArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
historyArchivalURI := "test://history/uri"
|
|
visibilityArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
visibilityArchivalURI := "test://visibility/uri"
|
|
|
|
clusterActive := "some random active cluster name"
|
|
clusterStandby := "some random standby cluster name"
|
|
configVersion := int64(10)
|
|
failoverVersion := int64(59)
|
|
isGlobalNamespace := true
|
|
clusters := []string{clusterActive, clusterStandby}
|
|
|
|
resp1, err2 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id,
|
|
Name: name,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
Data: data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention),
|
|
HistoryArchivalState: historyArchivalState,
|
|
HistoryArchivalUri: historyArchivalURI,
|
|
VisibilityArchivalState: visibilityArchivalState,
|
|
VisibilityArchivalUri: visibilityArchivalURI,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive,
|
|
Clusters: clusters,
|
|
},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.NoError(err2)
|
|
m.NotNil(resp1)
|
|
|
|
// Get metadata version after creation
|
|
metadata2, err3 := m.MetadataManager.GetMetadata(m.ctx)
|
|
m.NoError(err3)
|
|
afterCreationVersion := metadata2.NotificationVersion
|
|
|
|
// Verify that the version was incremented
|
|
m.Equal(initialVersion+1, afterCreationVersion, "NotificationVersion should be incremented by exactly 1")
|
|
}
|
|
|
|
// TestCreateNamespaceWithDuplicateName tests creating a namespace with a name that already exists
|
|
func (m *MetadataPersistenceSuiteV2) TestCreateNamespaceWithDuplicateName() {
|
|
id1 := uuid.NewString()
|
|
name := "duplicate-name-test-namespace"
|
|
state := enumspb.NAMESPACE_STATE_REGISTERED
|
|
description := "duplicate-name-test-description"
|
|
owner := "duplicate-name-test-owner"
|
|
data := map[string]string{"k1": "v1"}
|
|
retention := int32(10)
|
|
historyArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
historyArchivalURI := "test://history/uri"
|
|
visibilityArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
visibilityArchivalURI := "test://visibility/uri"
|
|
|
|
clusterActive := "some random active cluster name"
|
|
clusterStandby := "some random standby cluster name"
|
|
configVersion := int64(10)
|
|
failoverVersion := int64(59)
|
|
isGlobalNamespace := true
|
|
clusters := []string{clusterActive, clusterStandby}
|
|
|
|
// Create first namespace
|
|
resp1, err1 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id1,
|
|
Name: name,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
Data: data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention),
|
|
HistoryArchivalState: historyArchivalState,
|
|
HistoryArchivalUri: historyArchivalURI,
|
|
VisibilityArchivalState: visibilityArchivalState,
|
|
VisibilityArchivalUri: visibilityArchivalURI,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive,
|
|
Clusters: clusters,
|
|
},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.NoError(err1)
|
|
m.NotNil(resp1)
|
|
|
|
// Verify the namespace was created
|
|
getResp1, err2 := m.GetNamespace(id1, "")
|
|
m.NoError(err2)
|
|
m.NotNil(getResp1)
|
|
m.Equal(name, getResp1.Namespace.Info.Name)
|
|
|
|
// Try to create another namespace with the same name but different ID
|
|
id2 := uuid.NewString()
|
|
_, err3 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id2,
|
|
Name: name, // Same name as the first namespace
|
|
State: state,
|
|
Description: "different description",
|
|
Owner: "different owner",
|
|
Data: map[string]string{"k2": "v2"},
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention * 2),
|
|
HistoryArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
|
|
HistoryArchivalUri: "",
|
|
VisibilityArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
|
|
VisibilityArchivalUri: "",
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive,
|
|
Clusters: clusters,
|
|
},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.ErrorAs(err3, new(*serviceerror.NamespaceAlreadyExists))
|
|
|
|
// Verify that the original namespace still exists and was not modified
|
|
getResp2, err4 := m.GetNamespace(id1, "")
|
|
m.NoError(err4)
|
|
m.NotNil(getResp2)
|
|
m.Equal(name, getResp2.Namespace.Info.Name)
|
|
m.Equal(description, getResp2.Namespace.Info.Description)
|
|
m.Equal(owner, getResp2.Namespace.Info.Owner)
|
|
|
|
// Verify that the second namespace ID does not exist
|
|
_, err5 := m.GetNamespace(id2, "")
|
|
m.ErrorAs(err5, new(*serviceerror.NamespaceNotFound))
|
|
}
|
|
|
|
// TestCreateNamespaceWithDuplicateID tests creating a namespace with an ID that already exists
|
|
func (m *MetadataPersistenceSuiteV2) TestCreateNamespaceWithDuplicateID() {
|
|
id := uuid.NewString()
|
|
name1 := "duplicate-id-test-namespace-1"
|
|
name2 := "duplicate-id-test-namespace-2"
|
|
state := enumspb.NAMESPACE_STATE_REGISTERED
|
|
description := "duplicate-id-test-description"
|
|
owner := "duplicate-id-test-owner"
|
|
data := map[string]string{"k1": "v1"}
|
|
retention := int32(10)
|
|
historyArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
historyArchivalURI := "test://history/uri"
|
|
visibilityArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
visibilityArchivalURI := "test://visibility/uri"
|
|
|
|
clusterActive := "some random active cluster name"
|
|
clusterStandby := "some random standby cluster name"
|
|
configVersion := int64(10)
|
|
failoverVersion := int64(59)
|
|
isGlobalNamespace := true
|
|
clusters := []string{clusterActive, clusterStandby}
|
|
|
|
// Create first namespace
|
|
resp1, err1 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id,
|
|
Name: name1,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
Data: data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention),
|
|
HistoryArchivalState: historyArchivalState,
|
|
HistoryArchivalUri: historyArchivalURI,
|
|
VisibilityArchivalState: visibilityArchivalState,
|
|
VisibilityArchivalUri: visibilityArchivalURI,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive,
|
|
Clusters: clusters,
|
|
},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.NoError(err1)
|
|
m.NotNil(resp1)
|
|
|
|
// Verify the namespace was created
|
|
getResp1, err2 := m.GetNamespace(id, "")
|
|
m.NoError(err2)
|
|
m.NotNil(getResp1)
|
|
m.Equal(name1, getResp1.Namespace.Info.Name)
|
|
m.Equal(id, getResp1.Namespace.Info.Id)
|
|
|
|
// Try to create another namespace with the same ID but different name
|
|
_, err3 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id, // Same ID as the first namespace
|
|
Name: name2,
|
|
State: state,
|
|
Description: "different description",
|
|
Owner: "different owner",
|
|
Data: map[string]string{"k2": "v2"},
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention * 2),
|
|
HistoryArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
|
|
HistoryArchivalUri: "",
|
|
VisibilityArchivalState: enumspb.ARCHIVAL_STATE_DISABLED,
|
|
VisibilityArchivalUri: "",
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive,
|
|
Clusters: clusters,
|
|
},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.ErrorAs(err3, new(*serviceerror.NamespaceAlreadyExists))
|
|
|
|
// Verify that the original namespace still exists and was not modified
|
|
getResp2, err4 := m.GetNamespace(id, "")
|
|
m.NoError(err4)
|
|
m.NotNil(getResp2)
|
|
m.Equal(name1, getResp2.Namespace.Info.Name) // Should still have the original name
|
|
m.Equal(description, getResp2.Namespace.Info.Description)
|
|
m.Equal(owner, getResp2.Namespace.Info.Owner)
|
|
m.Equal(id, getResp2.Namespace.Info.Id)
|
|
|
|
// Verify that the second name doesn't exist in the system
|
|
_, err5 := m.GetNamespace("", name2)
|
|
m.ErrorAs(err5, new(*serviceerror.NamespaceNotFound))
|
|
}
|
|
|
|
// TestInitializeSystemNamespaces tests the initialization of system namespaces
|
|
func (m *MetadataPersistenceSuiteV2) TestInitializeSystemNamespaces() {
|
|
clusterName := "test-cluster"
|
|
|
|
// First initialization should succeed
|
|
err1 := m.MetadataManager.InitializeSystemNamespaces(m.ctx, clusterName)
|
|
m.NoError(err1)
|
|
|
|
// Verify the system namespace was created with correct properties
|
|
resp, err2 := m.GetNamespace("", "temporal-system")
|
|
m.NoError(err2)
|
|
m.NotNil(resp)
|
|
m.Equal("temporal-system", resp.Namespace.Info.Name)
|
|
m.Equal("32049b68-7872-4094-8e63-d0dd59896a83", resp.Namespace.Info.Id)
|
|
m.Equal(enumspb.NAMESPACE_STATE_REGISTERED, resp.Namespace.Info.State)
|
|
m.Equal("Temporal internal system namespace", resp.Namespace.Info.Description)
|
|
m.Equal("[email protected]", resp.Namespace.Info.Owner)
|
|
m.Equal(clusterName, resp.Namespace.ReplicationConfig.ActiveClusterName)
|
|
m.Equal([]string{clusterName}, resp.Namespace.ReplicationConfig.Clusters)
|
|
m.False(resp.IsGlobalNamespace)
|
|
|
|
// Second initialization should be idempotent
|
|
err3 := m.MetadataManager.InitializeSystemNamespaces(m.ctx, clusterName)
|
|
m.NoError(err3, "InitializeSystemNamespaces should be idempotent")
|
|
}
|
|
|
|
// TestDeleteNamespaceIdempotency tests that delete operations are idempotent
|
|
func (m *MetadataPersistenceSuiteV2) TestDeleteNamespaceIdempotency() {
|
|
id := uuid.NewString()
|
|
name := "delete-idempotent-test-namespace"
|
|
state := enumspb.NAMESPACE_STATE_REGISTERED
|
|
description := "delete-idempotent-test-description"
|
|
owner := "delete-idempotent-test-owner"
|
|
retention := int32(10)
|
|
|
|
clusterActive := "some random active cluster name"
|
|
configVersion := int64(10)
|
|
failoverVersion := int64(59)
|
|
isGlobalNamespace := false
|
|
|
|
// Create namespace
|
|
resp1, err1 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id,
|
|
Name: name,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention),
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive,
|
|
Clusters: []string{clusterActive},
|
|
},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.NoError(err1)
|
|
m.NotNil(resp1)
|
|
|
|
// Verify it exists
|
|
resp2, err2 := m.GetNamespace(id, "")
|
|
m.NoError(err2)
|
|
m.NotNil(resp2)
|
|
m.Equal(name, resp2.Namespace.Info.Name)
|
|
|
|
// Delete by ID - first delete should succeed
|
|
err3 := m.DeleteNamespace(id, "")
|
|
m.NoError(err3)
|
|
|
|
// May need to loop here to avoid potential inconsistent read-after-write in cassandra
|
|
m.Eventually(
|
|
func() bool {
|
|
resp, err := m.GetNamespace(id, "")
|
|
if errors.As(err, new(*serviceerror.NamespaceNotFound)) {
|
|
m.Nil(resp)
|
|
return true
|
|
}
|
|
return false
|
|
},
|
|
10*time.Second,
|
|
100*time.Millisecond,
|
|
)
|
|
|
|
// Delete again - This should NOT error (deleting a non-existent namespace is a no-op)
|
|
err5 := m.DeleteNamespace(id, "")
|
|
m.NoError(err5, "Delete should be idempotent")
|
|
|
|
// Delete by name should also be idempotent
|
|
err6 := m.DeleteNamespace("", name)
|
|
m.NoError(err6, "Delete by name should be idempotent")
|
|
}
|
|
|
|
// TestUpdateNamespaceNotFound tests updating a non-existent namespace
|
|
func (m *MetadataPersistenceSuiteV2) TestUpdateNamespaceNotFound() {
|
|
nonExistentID := uuid.NewString()
|
|
name := "non-existent-namespace"
|
|
state := enumspb.NAMESPACE_STATE_REGISTERED
|
|
description := "test-description"
|
|
owner := "test-owner"
|
|
data := map[string]string{"k1": "v1"}
|
|
retention := int32(10)
|
|
|
|
clusterActive := "some random active cluster name"
|
|
configVersion := int64(10)
|
|
failoverVersion := int64(59)
|
|
isGlobalNamespace := false
|
|
|
|
// Get current notification version
|
|
metadata, err := m.MetadataManager.GetMetadata(m.ctx)
|
|
m.NoError(err)
|
|
notificationVersion := metadata.NotificationVersion
|
|
|
|
// Try to update a non-existent namespace
|
|
_ = m.UpdateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: nonExistentID,
|
|
Name: name,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
Data: data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention),
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive,
|
|
Clusters: []string{clusterActive},
|
|
},
|
|
configVersion,
|
|
failoverVersion,
|
|
0,
|
|
time.Time{},
|
|
notificationVersion,
|
|
isGlobalNamespace,
|
|
)
|
|
|
|
// Update operations may silently succeed on non-existent namespaces (no-op)
|
|
// or may fail depending on implementation. For now, we just verify the operation completes.
|
|
// The key test is that after the update, the namespace still doesn't exist.
|
|
_, err3 := m.GetNamespace(nonExistentID, "")
|
|
m.ErrorAs(err3, new(*serviceerror.NamespaceNotFound))
|
|
}
|
|
|
|
// TestRenameNamespaceNotFound tests renaming a non-existent namespace
|
|
func (m *MetadataPersistenceSuiteV2) TestRenameNamespaceNotFound() {
|
|
nonExistentName := "non-existent-namespace-" + uuid.NewString()
|
|
newName := "new-name-for-non-existent"
|
|
|
|
err := m.MetadataManager.RenameNamespace(m.ctx, &p.RenameNamespaceRequest{
|
|
PreviousName: nonExistentName,
|
|
NewName: newName,
|
|
})
|
|
m.ErrorAs(err, new(*serviceerror.NamespaceNotFound))
|
|
}
|
|
|
|
// TestRenameNamespaceCassandra tests Cassandra-specific RenameNamespace behavior
|
|
// This test verifies the two-step non-atomic rename operation in Cassandra
|
|
func (m *MetadataPersistenceSuiteV2) TestRenameNamespaceCassandra() {
|
|
// This test is for Cassandra
|
|
switch m.DefaultTestCluster.(type) {
|
|
case *sql.TestCluster:
|
|
m.T().Skip()
|
|
default:
|
|
}
|
|
|
|
id := uuid.NewString()
|
|
name := "cassandra-rename-test-name"
|
|
newName := "cassandra-rename-test-new-name"
|
|
state := enumspb.NAMESPACE_STATE_REGISTERED
|
|
description := "cassandra-rename-test-description"
|
|
owner := "cassandra-rename-test-owner"
|
|
data := map[string]string{"k1": "v1"}
|
|
retention := int32(10)
|
|
historyArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
historyArchivalURI := "test://history/uri"
|
|
visibilityArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
visibilityArchivalURI := "test://visibility/uri"
|
|
|
|
clusterActive := "some random active cluster name"
|
|
clusterStandby := "some random standby cluster name"
|
|
configVersion := int64(10)
|
|
failoverVersion := int64(59)
|
|
isGlobalNamespace := true
|
|
clusters := []string{clusterActive, clusterStandby}
|
|
|
|
// Create namespace
|
|
resp1, err1 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id,
|
|
Name: name,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
Data: data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention),
|
|
HistoryArchivalState: historyArchivalState,
|
|
HistoryArchivalUri: historyArchivalURI,
|
|
VisibilityArchivalState: visibilityArchivalState,
|
|
VisibilityArchivalUri: visibilityArchivalURI,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive,
|
|
Clusters: clusters,
|
|
},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.NoError(err1)
|
|
m.EqualValues(id, resp1.ID)
|
|
|
|
// Verify namespace exists with original name
|
|
resp2, err2 := m.GetNamespace(id, "")
|
|
m.NoError(err2)
|
|
m.Equal(name, resp2.Namespace.Info.Name)
|
|
|
|
// Test 1: Rename to a new name
|
|
err3 := m.MetadataManager.RenameNamespace(m.ctx, &p.RenameNamespaceRequest{
|
|
PreviousName: name,
|
|
NewName: newName,
|
|
})
|
|
m.NoError(err3)
|
|
|
|
// Verify namespace can be retrieved by new name
|
|
resp4, err4 := m.GetNamespace("", newName)
|
|
m.NoError(err4)
|
|
m.NotNil(resp4)
|
|
m.EqualValues(id, resp4.Namespace.Info.Id)
|
|
m.Equal(newName, resp4.Namespace.Info.Name)
|
|
m.Equal(description, resp4.Namespace.Info.Description)
|
|
m.Equal(owner, resp4.Namespace.Info.Owner)
|
|
m.Equal(data, resp4.Namespace.Info.Data)
|
|
|
|
// Verify namespace can be retrieved by ID and has new name
|
|
resp5, err5 := m.GetNamespace(id, "")
|
|
m.NoError(err5)
|
|
m.Equal(newName, resp5.Namespace.Info.Name)
|
|
|
|
// Verify old name no longer exists (may need eventual consistency check for Cassandra)
|
|
m.Eventually(
|
|
func() bool {
|
|
_, err := m.GetNamespace("", name)
|
|
return errors.As(err, new(*serviceerror.NamespaceNotFound))
|
|
},
|
|
10*time.Second,
|
|
100*time.Millisecond,
|
|
)
|
|
|
|
// Fetch metadata version before renaming
|
|
metadataBeforeRename, err9 := m.MetadataManager.GetMetadata(m.ctx)
|
|
m.NoError(err9)
|
|
|
|
// Test 2: Rename to the same name
|
|
// In Cassandra, this will fail because it tries to INSERT a row that already exists
|
|
// with IF NOT EXISTS, which is expected behavior for Cassandra's two-step process
|
|
err6 := m.MetadataManager.RenameNamespace(m.ctx, &p.RenameNamespaceRequest{
|
|
PreviousName: newName,
|
|
NewName: newName,
|
|
})
|
|
m.ErrorAs(err6, new(*serviceerror.Unavailable), "Renaming to the same name fails in Cassandra due to IF NOT EXISTS")
|
|
|
|
// Test 3: Verify namespace still exists with same name (unchanged)
|
|
resp7, err7 := m.GetNamespace(id, "")
|
|
m.NoError(err7)
|
|
m.Equal(newName, resp7.Namespace.Info.Name)
|
|
|
|
// Test 4: Verify namespace can still be fetched by ID
|
|
resp8, err8 := m.GetNamespace(id, "")
|
|
m.NoError(err8)
|
|
m.Equal(newName, resp8.Namespace.Info.Name)
|
|
|
|
// Test 5: Verify metadata version was not incremented
|
|
metadataAfterRename, err10 := m.MetadataManager.GetMetadata(m.ctx)
|
|
m.NoError(err10)
|
|
m.Equal(metadataBeforeRename.NotificationVersion, metadataAfterRename.NotificationVersion, "Notification version should not have been incremented")
|
|
}
|
|
|
|
// TestRenameNamespaceSQL tests SQL RenameNamespace behavior
|
|
// This test verifies the atomic transaction-based rename operation in SQL databases
|
|
func (m *MetadataPersistenceSuiteV2) TestRenameNamespaceSQL() {
|
|
// This test is for SQL databases
|
|
switch m.DefaultTestCluster.(type) {
|
|
case *sql.TestCluster:
|
|
default:
|
|
m.T().Skip()
|
|
}
|
|
|
|
id := uuid.NewString()
|
|
name := "sql-rename-test-name"
|
|
newName := "sql-rename-test-new-name"
|
|
state := enumspb.NAMESPACE_STATE_REGISTERED
|
|
description := "sql-rename-test-description"
|
|
owner := "sql-rename-test-owner"
|
|
data := map[string]string{"k1": "v1"}
|
|
retention := int32(10)
|
|
historyArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
historyArchivalURI := "test://history/uri"
|
|
visibilityArchivalState := enumspb.ARCHIVAL_STATE_ENABLED
|
|
visibilityArchivalURI := "test://visibility/uri"
|
|
|
|
clusterActive := "some random active cluster name"
|
|
clusterStandby := "some random standby cluster name"
|
|
configVersion := int64(10)
|
|
failoverVersion := int64(59)
|
|
isGlobalNamespace := true
|
|
clusters := []string{clusterActive, clusterStandby}
|
|
|
|
// Create namespace
|
|
resp1, err1 := m.CreateNamespace(
|
|
&persistencespb.NamespaceInfo{
|
|
Id: id,
|
|
Name: name,
|
|
State: state,
|
|
Description: description,
|
|
Owner: owner,
|
|
Data: data,
|
|
},
|
|
&persistencespb.NamespaceConfig{
|
|
Retention: timestamp.DurationFromDays(retention),
|
|
HistoryArchivalState: historyArchivalState,
|
|
HistoryArchivalUri: historyArchivalURI,
|
|
VisibilityArchivalState: visibilityArchivalState,
|
|
VisibilityArchivalUri: visibilityArchivalURI,
|
|
},
|
|
&persistencespb.NamespaceReplicationConfig{
|
|
ActiveClusterName: clusterActive,
|
|
Clusters: clusters,
|
|
},
|
|
isGlobalNamespace,
|
|
configVersion,
|
|
failoverVersion,
|
|
)
|
|
m.NoError(err1)
|
|
m.EqualValues(id, resp1.ID)
|
|
|
|
// Verify namespace exists with original name
|
|
resp2, err2 := m.GetNamespace(id, "")
|
|
m.NoError(err2)
|
|
m.Equal(name, resp2.Namespace.Info.Name)
|
|
|
|
// Test 1: Rename to a new name
|
|
err3 := m.MetadataManager.RenameNamespace(m.ctx, &p.RenameNamespaceRequest{
|
|
PreviousName: name,
|
|
NewName: newName,
|
|
})
|
|
m.NoError(err3)
|
|
|
|
// Verify namespace can be retrieved by new name
|
|
resp4, err4 := m.GetNamespace("", newName)
|
|
m.NoError(err4)
|
|
m.NotNil(resp4)
|
|
m.EqualValues(id, resp4.Namespace.Info.Id)
|
|
m.Equal(newName, resp4.Namespace.Info.Name)
|
|
m.Equal(description, resp4.Namespace.Info.Description)
|
|
m.Equal(owner, resp4.Namespace.Info.Owner)
|
|
m.Equal(data, resp4.Namespace.Info.Data)
|
|
|
|
// Verify namespace can be retrieved by ID and has new name
|
|
resp5, err5 := m.GetNamespace(id, "")
|
|
m.NoError(err5)
|
|
m.Equal(newName, resp5.Namespace.Info.Name)
|
|
|
|
// Verify old name no longer exists
|
|
_, err6 := m.GetNamespace("", name)
|
|
m.ErrorAs(err6, new(*serviceerror.NamespaceNotFound), "Old name should not exist after rename")
|
|
|
|
// Fetch metadata version before renaming
|
|
metadataBeforeRename, err9 := m.MetadataManager.GetMetadata(m.ctx)
|
|
m.NoError(err9)
|
|
|
|
// Test 2: Rename to the same name (idempotent operation)
|
|
err7 := m.MetadataManager.RenameNamespace(m.ctx, &p.RenameNamespaceRequest{
|
|
PreviousName: newName,
|
|
NewName: newName,
|
|
})
|
|
m.NoError(err7, "Renaming to the same name should succeed")
|
|
|
|
// Verify namespace still exists with same name and data is unchanged
|
|
resp8, err8 := m.GetNamespace(id, "")
|
|
m.NoError(err8)
|
|
m.Equal(newName, resp8.Namespace.Info.Name)
|
|
m.Equal(description, resp8.Namespace.Info.Description)
|
|
m.Equal(owner, resp8.Namespace.Info.Owner)
|
|
m.Equal(data, resp8.Namespace.Info.Data)
|
|
|
|
// Test 3: Verify atomicity - query by both ID and name should be consistent
|
|
resp9, err9 := m.GetNamespace("", newName)
|
|
m.NoError(err9)
|
|
m.Equal(resp9.Namespace.Info.Id, resp8.Namespace.Info.Id)
|
|
m.Equal(resp9.Namespace.Info.Name, resp8.Namespace.Info.Name)
|
|
m.Equal(resp9.Namespace.Info.Description, resp8.Namespace.Info.Description)
|
|
|
|
// Test 4: Verify metadata version was incremented
|
|
metadataAfterRename, err11 := m.MetadataManager.GetMetadata(m.ctx)
|
|
m.NoError(err11)
|
|
m.Greater(metadataAfterRename.NotificationVersion, metadataBeforeRename.NotificationVersion, "Notification version should have been incremented")
|
|
}
|