go.temporal.io/server@v1.23.0/common/rpc/interceptor/namespace_validator_test.go (about)

     1  // The MIT License
     2  //
     3  // Copyright (c) 2020 Temporal Technologies Inc.  All rights reserved.
     4  //
     5  // Copyright (c) 2020 Uber Technologies, Inc.
     6  //
     7  // Permission is hereby granted, free of charge, to any person obtaining a copy
     8  // of this software and associated documentation files (the "Software"), to deal
     9  // in the Software without restriction, including without limitation the rights
    10  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    11  // copies of the Software, and to permit persons to whom the Software is
    12  // furnished to do so, subject to the following conditions:
    13  //
    14  // The above copyright notice and this permission notice shall be included in
    15  // all copies or substantial portions of the Software.
    16  //
    17  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    18  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    19  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    20  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    21  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    22  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    23  // THE SOFTWARE.
    24  
    25  package interceptor
    26  
    27  import (
    28  	"context"
    29  	"fmt"
    30  	"testing"
    31  
    32  	"github.com/golang/mock/gomock"
    33  	"github.com/google/uuid"
    34  	"github.com/stretchr/testify/require"
    35  	"github.com/stretchr/testify/suite"
    36  	enumspb "go.temporal.io/api/enums/v1"
    37  	"go.temporal.io/api/operatorservice/v1"
    38  	"go.temporal.io/api/serviceerror"
    39  	"go.temporal.io/api/workflowservice/v1"
    40  	"google.golang.org/grpc"
    41  
    42  	"go.temporal.io/server/api/adminservice/v1"
    43  	persistencespb "go.temporal.io/server/api/persistence/v1"
    44  	tokenspb "go.temporal.io/server/api/token/v1"
    45  	"go.temporal.io/server/common"
    46  	"go.temporal.io/server/common/dynamicconfig"
    47  	"go.temporal.io/server/common/namespace"
    48  	"go.temporal.io/server/common/persistence"
    49  )
    50  
    51  type (
    52  	namespaceValidatorSuite struct {
    53  		suite.Suite
    54  		*require.Assertions
    55  
    56  		controller   *gomock.Controller
    57  		mockRegistry *namespace.MockRegistry
    58  	}
    59  )
    60  
    61  func TestNamespaceValidatorSuite(t *testing.T) {
    62  	suite.Run(t, &namespaceValidatorSuite{})
    63  }
    64  
    65  func (s *namespaceValidatorSuite) SetupSuite() {
    66  }
    67  
    68  func (s *namespaceValidatorSuite) TearDownSuite() {
    69  }
    70  
    71  func (s *namespaceValidatorSuite) SetupTest() {
    72  	s.Assertions = require.New(s.T())
    73  
    74  	s.controller = gomock.NewController(s.T())
    75  	s.mockRegistry = namespace.NewMockRegistry(s.controller)
    76  }
    77  
    78  func (s *namespaceValidatorSuite) TearDownTest() {
    79  	s.controller.Finish()
    80  }
    81  
    82  func (s *namespaceValidatorSuite) Test_StateValidationIntercept_NamespaceNotSet() {
    83  	taskToken, _ := common.NewProtoTaskTokenSerializer().Serialize(&tokenspb.Task{
    84  		NamespaceId: "",
    85  		WorkflowId:  "wid",
    86  	})
    87  
    88  	nvi := NewNamespaceValidatorInterceptor(
    89  		s.mockRegistry,
    90  		dynamicconfig.GetBoolPropertyFn(false),
    91  		dynamicconfig.GetIntPropertyFn(100))
    92  	serverInfo := &grpc.UnaryServerInfo{
    93  		FullMethod: "/temporal/random",
    94  	}
    95  
    96  	testCases := []struct {
    97  		expectedErr error
    98  		req         interface{}
    99  	}{
   100  		{
   101  			req:         &workflowservice.StartWorkflowExecutionRequest{},
   102  			expectedErr: &serviceerror.InvalidArgument{},
   103  		},
   104  		{
   105  			req: &workflowservice.RespondWorkflowTaskCompletedRequest{
   106  				Namespace: "test-namespace", // Ignored, must be set on token.
   107  				TaskToken: nil,
   108  			},
   109  			expectedErr: &serviceerror.InvalidArgument{},
   110  		},
   111  		{
   112  			req: &workflowservice.RespondWorkflowTaskCompletedRequest{
   113  				Namespace: "test-namespace", // Ignored, must be set on token.
   114  				TaskToken: taskToken,
   115  			},
   116  			expectedErr: &serviceerror.InvalidArgument{},
   117  		},
   118  	}
   119  
   120  	for _, testCase := range testCases {
   121  		handlerCalled := false
   122  		_, err := nvi.StateValidationIntercept(context.Background(), testCase.req, serverInfo, func(ctx context.Context, req interface{}) (interface{}, error) {
   123  			handlerCalled = true
   124  			return &workflowservice.StartWorkflowExecutionResponse{}, nil
   125  		})
   126  
   127  		if testCase.expectedErr != nil {
   128  			s.IsType(testCase.expectedErr, err)
   129  			s.False(handlerCalled)
   130  		} else {
   131  			s.NoError(err)
   132  			s.True(handlerCalled)
   133  		}
   134  	}
   135  }
   136  
   137  func (s *namespaceValidatorSuite) Test_StateValidationIntercept_NamespaceNotFound() {
   138  
   139  	nvi := NewNamespaceValidatorInterceptor(
   140  		s.mockRegistry,
   141  		dynamicconfig.GetBoolPropertyFn(false),
   142  		dynamicconfig.GetIntPropertyFn(100))
   143  	serverInfo := &grpc.UnaryServerInfo{
   144  		FullMethod: "/temporal/random",
   145  	}
   146  
   147  	s.mockRegistry.EXPECT().GetNamespace(namespace.Name("not-found-namespace")).Return(nil, serviceerror.NewNamespaceNotFound("missing-namespace"))
   148  	req := &workflowservice.StartWorkflowExecutionRequest{Namespace: "not-found-namespace"}
   149  	handlerCalled := false
   150  	_, err := nvi.StateValidationIntercept(context.Background(), req, serverInfo, func(ctx context.Context, req interface{}) (interface{}, error) {
   151  		handlerCalled = true
   152  		return &workflowservice.StartWorkflowExecutionResponse{}, nil
   153  	})
   154  
   155  	s.IsType(&serviceerror.NamespaceNotFound{}, err)
   156  	s.False(handlerCalled)
   157  
   158  	s.mockRegistry.EXPECT().GetNamespaceByID(namespace.ID("not-found-namespace-id")).Return(nil, serviceerror.NewNamespaceNotFound("missing-namespace"))
   159  	taskToken, _ := common.NewProtoTaskTokenSerializer().Serialize(&tokenspb.Task{
   160  		NamespaceId: "not-found-namespace-id",
   161  	})
   162  	tokenReq := &workflowservice.RespondWorkflowTaskCompletedRequest{
   163  		Namespace: "test-namespace",
   164  		TaskToken: taskToken,
   165  	}
   166  	handlerCalled = false
   167  	_, err = nvi.StateValidationIntercept(context.Background(), tokenReq, serverInfo, func(ctx context.Context, req interface{}) (interface{}, error) {
   168  		handlerCalled = true
   169  		return &workflowservice.RespondWorkflowTaskCompletedResponse{}, nil
   170  	})
   171  
   172  	s.IsType(&serviceerror.NamespaceNotFound{}, err)
   173  	s.False(handlerCalled)
   174  }
   175  
   176  func (s *namespaceValidatorSuite) Test_StateValidationIntercept_StatusFromNamespace() {
   177  	testCases := []struct {
   178  		state            enumspb.NamespaceState
   179  		replicationState enumspb.ReplicationState
   180  		expectedErr      error
   181  		method           string
   182  		req              interface{}
   183  	}{
   184  		// StartWorkflowExecution
   185  		{
   186  			state:       enumspb.NAMESPACE_STATE_REGISTERED,
   187  			expectedErr: nil,
   188  			method:      "/temporal/StartWorkflowExecution",
   189  			req:         &workflowservice.StartWorkflowExecutionRequest{Namespace: "test-namespace"},
   190  		},
   191  		{
   192  			state:       enumspb.NAMESPACE_STATE_DEPRECATED,
   193  			expectedErr: &serviceerror.NamespaceInvalidState{},
   194  			method:      "/temporal/StartWorkflowExecution",
   195  			req:         &workflowservice.StartWorkflowExecutionRequest{Namespace: "test-namespace"},
   196  		},
   197  		{
   198  			state:       enumspb.NAMESPACE_STATE_DELETED,
   199  			expectedErr: &serviceerror.NamespaceInvalidState{},
   200  			method:      "/temporal/StartWorkflowExecution",
   201  			req:         &workflowservice.StartWorkflowExecutionRequest{Namespace: "test-namespace"},
   202  		},
   203  		{
   204  			state:            enumspb.NAMESPACE_STATE_REGISTERED,
   205  			replicationState: enumspb.REPLICATION_STATE_HANDOVER,
   206  			expectedErr:      common.ErrNamespaceHandover,
   207  			method:           "/temporal/StartWorkflowExecution",
   208  			req:              &workflowservice.StartWorkflowExecutionRequest{Namespace: "test-namespace"},
   209  		},
   210  		// DescribeNamespace
   211  		{
   212  			state:       enumspb.NAMESPACE_STATE_UNSPECIFIED,
   213  			expectedErr: errNamespaceNotSet,
   214  			method:      "/temporal/DescribeNamespace",
   215  			req:         &workflowservice.DescribeNamespaceRequest{},
   216  		},
   217  		{
   218  			state:       enumspb.NAMESPACE_STATE_UNSPECIFIED,
   219  			expectedErr: nil,
   220  			method:      "/temporal/DescribeNamespace",
   221  			req:         &workflowservice.DescribeNamespaceRequest{Id: "test-namespace-id"},
   222  		},
   223  		{
   224  			state:       enumspb.NAMESPACE_STATE_UNSPECIFIED,
   225  			expectedErr: nil,
   226  			method:      "/temporal/DescribeNamespace",
   227  			req:         &workflowservice.DescribeNamespaceRequest{Namespace: "test-namespace"},
   228  		},
   229  		// RegisterNamespace
   230  		{
   231  			state:       enumspb.NAMESPACE_STATE_UNSPECIFIED,
   232  			expectedErr: nil,
   233  			method:      "/temporal/RegisterNamespace",
   234  			req:         &workflowservice.RegisterNamespaceRequest{Namespace: "test-namespace"},
   235  		},
   236  		{
   237  			state:       enumspb.NAMESPACE_STATE_UNSPECIFIED,
   238  			expectedErr: errNamespaceNotSet,
   239  			method:      "/temporal/RegisterNamespace",
   240  			req:         &workflowservice.RegisterNamespaceRequest{},
   241  		},
   242  		// PollWorkflowTaskQueue (default)
   243  		{
   244  			state:       enumspb.NAMESPACE_STATE_REGISTERED,
   245  			expectedErr: nil,
   246  			method:      "/temporal/PollWorkflowTaskQueue",
   247  			req:         &workflowservice.PollWorkflowTaskQueueRequest{Namespace: "test-namespace"},
   248  		},
   249  		{
   250  			state:       enumspb.NAMESPACE_STATE_DEPRECATED,
   251  			expectedErr: nil,
   252  			method:      "/temporal/PollWorkflowTaskQueue",
   253  			req:         &workflowservice.PollWorkflowTaskQueueRequest{Namespace: "test-namespace"},
   254  		},
   255  		{
   256  			state:       enumspb.NAMESPACE_STATE_DELETED,
   257  			expectedErr: &serviceerror.NamespaceInvalidState{},
   258  			method:      "/temporal/PollWorkflowTaskQueue",
   259  			req:         &workflowservice.PollWorkflowTaskQueueRequest{Namespace: "test-namespace"},
   260  		},
   261  		// UpdateNamespace
   262  		{
   263  			state:       enumspb.NAMESPACE_STATE_REGISTERED,
   264  			expectedErr: nil,
   265  			method:      "/temporal/UpdateNamespace",
   266  			req:         &workflowservice.UpdateNamespaceRequest{Namespace: "test-namespace"},
   267  		},
   268  		{
   269  			state:       enumspb.NAMESPACE_STATE_DEPRECATED,
   270  			expectedErr: nil,
   271  			method:      "/temporal/UpdateNamespace",
   272  			req:         &workflowservice.UpdateNamespaceRequest{Namespace: "test-namespace"},
   273  		},
   274  		{
   275  			state:            enumspb.NAMESPACE_STATE_REGISTERED,
   276  			replicationState: enumspb.REPLICATION_STATE_HANDOVER,
   277  			expectedErr:      nil,
   278  			method:           "/temporal/UpdateNamespace",
   279  			req:              &workflowservice.UpdateNamespaceRequest{Namespace: "test-namespace"},
   280  		},
   281  		{
   282  			state:       enumspb.NAMESPACE_STATE_DELETED,
   283  			expectedErr: &serviceerror.NamespaceInvalidState{},
   284  			method:      "/temporal/UpdateNamespace",
   285  			req:         &workflowservice.UpdateNamespaceRequest{Namespace: "test-namespace"},
   286  		},
   287  	}
   288  
   289  	for i, testCase := range testCases {
   290  		s.T().Run(fmt.Sprintf("test-case-%v", i), func(t *testing.T) {
   291  			_, isDescribeNamespace := testCase.req.(*workflowservice.DescribeNamespaceRequest)
   292  			_, isRegisterNamespace := testCase.req.(*workflowservice.RegisterNamespaceRequest)
   293  			if !isDescribeNamespace && !isRegisterNamespace {
   294  				s.mockRegistry.EXPECT().GetNamespace(namespace.Name("test-namespace")).Return(namespace.FromPersistentState(
   295  					&persistence.GetNamespaceResponse{
   296  						Namespace: &persistencespb.NamespaceDetail{
   297  							Config: &persistencespb.NamespaceConfig{},
   298  							ReplicationConfig: &persistencespb.NamespaceReplicationConfig{
   299  								State: testCase.replicationState,
   300  							},
   301  							Info: &persistencespb.NamespaceInfo{
   302  								State: testCase.state,
   303  							},
   304  						},
   305  					}), nil)
   306  			}
   307  
   308  			nvi := NewNamespaceValidatorInterceptor(
   309  				s.mockRegistry,
   310  				dynamicconfig.GetBoolPropertyFn(false),
   311  				dynamicconfig.GetIntPropertyFn(100))
   312  			serverInfo := &grpc.UnaryServerInfo{
   313  				FullMethod: testCase.method,
   314  			}
   315  
   316  			handlerCalled := false
   317  			_, err := nvi.StateValidationIntercept(context.Background(), testCase.req, serverInfo, func(ctx context.Context, req interface{}) (interface{}, error) {
   318  				handlerCalled = true
   319  				return &workflowservice.StartWorkflowExecutionResponse{}, nil
   320  			})
   321  
   322  			if testCase.expectedErr != nil {
   323  				s.IsType(testCase.expectedErr, err)
   324  				s.False(handlerCalled)
   325  			} else {
   326  				s.NoError(err)
   327  				s.True(handlerCalled)
   328  			}
   329  		})
   330  	}
   331  }
   332  
   333  func (s *namespaceValidatorSuite) Test_StateValidationIntercept_StatusFromToken() {
   334  	taskToken, _ := common.NewProtoTaskTokenSerializer().Serialize(&tokenspb.Task{
   335  		NamespaceId: "test-namespace-id",
   336  	})
   337  
   338  	testCases := []struct {
   339  		state       enumspb.NamespaceState
   340  		expectedErr error
   341  		method      string
   342  		req         interface{}
   343  	}{
   344  		// RespondWorkflowTaskCompleted
   345  		{
   346  			state:       enumspb.NAMESPACE_STATE_REGISTERED,
   347  			expectedErr: nil,
   348  			method:      "/temporal/RespondWorkflowTaskCompleted",
   349  			req: &workflowservice.RespondWorkflowTaskCompletedRequest{
   350  				TaskToken: taskToken,
   351  			},
   352  		},
   353  		{
   354  			state:       enumspb.NAMESPACE_STATE_DEPRECATED,
   355  			expectedErr: nil,
   356  			method:      "/temporal/RespondWorkflowTaskCompleted",
   357  			req: &workflowservice.RespondWorkflowTaskCompletedRequest{
   358  				TaskToken: taskToken,
   359  			},
   360  		},
   361  		{
   362  			state:       enumspb.NAMESPACE_STATE_DELETED,
   363  			expectedErr: &serviceerror.NamespaceInvalidState{},
   364  			method:      "/temporal/RespondWorkflowTaskCompleted",
   365  			req: &workflowservice.RespondWorkflowTaskCompletedRequest{
   366  				TaskToken: taskToken,
   367  			},
   368  		},
   369  	}
   370  
   371  	for _, testCase := range testCases {
   372  		s.mockRegistry.EXPECT().GetNamespaceByID(namespace.ID("test-namespace-id")).Return(namespace.FromPersistentState(
   373  			&persistence.GetNamespaceResponse{
   374  				Namespace: &persistencespb.NamespaceDetail{
   375  					Config:            &persistencespb.NamespaceConfig{},
   376  					ReplicationConfig: &persistencespb.NamespaceReplicationConfig{},
   377  					Info: &persistencespb.NamespaceInfo{
   378  						State: testCase.state,
   379  					},
   380  				},
   381  			}), nil)
   382  
   383  		nvi := NewNamespaceValidatorInterceptor(
   384  			s.mockRegistry,
   385  			dynamicconfig.GetBoolPropertyFn(false),
   386  			dynamicconfig.GetIntPropertyFn(100))
   387  		serverInfo := &grpc.UnaryServerInfo{
   388  			FullMethod: testCase.method,
   389  		}
   390  
   391  		handlerCalled := false
   392  		_, err := nvi.StateValidationIntercept(context.Background(), testCase.req, serverInfo, func(ctx context.Context, req interface{}) (interface{}, error) {
   393  			handlerCalled = true
   394  			return &workflowservice.RespondWorkflowTaskCompletedResponse{}, nil
   395  		})
   396  
   397  		if testCase.expectedErr != nil {
   398  			s.IsType(testCase.expectedErr, err)
   399  			s.False(handlerCalled)
   400  		} else {
   401  			s.NoError(err)
   402  			s.True(handlerCalled)
   403  		}
   404  	}
   405  }
   406  
   407  func (s *namespaceValidatorSuite) Test_StateValidationIntercept_DescribeNamespace_Id() {
   408  	nvi := NewNamespaceValidatorInterceptor(
   409  		s.mockRegistry,
   410  		dynamicconfig.GetBoolPropertyFn(false),
   411  		dynamicconfig.GetIntPropertyFn(100))
   412  	serverInfo := &grpc.UnaryServerInfo{
   413  		FullMethod: "/temporal/random",
   414  	}
   415  
   416  	req := &workflowservice.DescribeNamespaceRequest{Id: "test-namespace-id"}
   417  	handlerCalled := false
   418  	_, err := nvi.StateValidationIntercept(context.Background(), req, serverInfo, func(ctx context.Context, req interface{}) (interface{}, error) {
   419  		handlerCalled = true
   420  		return &workflowservice.DescribeNamespaceResponse{}, nil
   421  	})
   422  
   423  	s.NoError(err)
   424  	s.True(handlerCalled)
   425  
   426  	req = &workflowservice.DescribeNamespaceRequest{}
   427  	handlerCalled = false
   428  	_, err = nvi.StateValidationIntercept(context.Background(), req, serverInfo, func(ctx context.Context, req interface{}) (interface{}, error) {
   429  		handlerCalled = true
   430  		return &workflowservice.DescribeNamespaceResponse{}, nil
   431  	})
   432  
   433  	s.IsType(&serviceerror.InvalidArgument{}, err)
   434  	s.False(handlerCalled)
   435  }
   436  
   437  func (s *namespaceValidatorSuite) Test_StateValidationIntercept_GetClusterInfo() {
   438  	nvi := NewNamespaceValidatorInterceptor(
   439  		s.mockRegistry,
   440  		dynamicconfig.GetBoolPropertyFn(false),
   441  		dynamicconfig.GetIntPropertyFn(100))
   442  	serverInfo := &grpc.UnaryServerInfo{
   443  		FullMethod: "/temporal/random",
   444  	}
   445  
   446  	// Example of API which doesn't have namespace field.
   447  	req := &workflowservice.GetClusterInfoRequest{}
   448  	handlerCalled := false
   449  	_, err := nvi.StateValidationIntercept(context.Background(), req, serverInfo, func(ctx context.Context, req interface{}) (interface{}, error) {
   450  		handlerCalled = true
   451  		return &workflowservice.GetClusterInfoResponse{}, nil
   452  	})
   453  
   454  	s.NoError(err)
   455  	s.True(handlerCalled)
   456  }
   457  
   458  func (s *namespaceValidatorSuite) Test_Intercept_RegisterNamespace() {
   459  	nvi := NewNamespaceValidatorInterceptor(
   460  		s.mockRegistry,
   461  		dynamicconfig.GetBoolPropertyFn(false),
   462  		dynamicconfig.GetIntPropertyFn(100))
   463  	serverInfo := &grpc.UnaryServerInfo{
   464  		FullMethod: "/temporal/random",
   465  	}
   466  
   467  	req := &workflowservice.RegisterNamespaceRequest{Namespace: "new-namespace"}
   468  	handlerCalled := false
   469  	_, err := nvi.StateValidationIntercept(context.Background(), req, serverInfo, func(ctx context.Context, req interface{}) (interface{}, error) {
   470  		handlerCalled = true
   471  		return &workflowservice.RegisterNamespaceResponse{}, nil
   472  	})
   473  
   474  	s.NoError(err)
   475  	s.True(handlerCalled)
   476  
   477  	req = &workflowservice.RegisterNamespaceRequest{}
   478  	handlerCalled = false
   479  	_, err = nvi.StateValidationIntercept(context.Background(), req, serverInfo, func(ctx context.Context, req interface{}) (interface{}, error) {
   480  		handlerCalled = true
   481  		return &workflowservice.RegisterNamespaceResponse{}, nil
   482  	})
   483  
   484  	s.IsType(&serviceerror.InvalidArgument{}, err)
   485  	s.False(handlerCalled)
   486  }
   487  
   488  func (s *namespaceValidatorSuite) Test_StateValidationIntercept_TokenNamespaceEnforcement() {
   489  	testCases := []struct {
   490  		tokenNamespaceID                namespace.ID
   491  		tokenNamespaceName              namespace.Name
   492  		requestNamespaceID              namespace.ID
   493  		requestNamespaceName            namespace.Name
   494  		enableTokenNamespaceEnforcement bool
   495  		expectedErr                     error
   496  	}{
   497  		{
   498  			tokenNamespaceID:                "valid-id",
   499  			tokenNamespaceName:              "valid-name",
   500  			requestNamespaceID:              "valid-id",
   501  			requestNamespaceName:            "valid-name",
   502  			enableTokenNamespaceEnforcement: true,
   503  			expectedErr:                     nil,
   504  		},
   505  		{
   506  			tokenNamespaceID:                "valid-id",
   507  			tokenNamespaceName:              "valid-name",
   508  			requestNamespaceID:              "valid-id",
   509  			requestNamespaceName:            "valid-name",
   510  			enableTokenNamespaceEnforcement: false,
   511  			expectedErr:                     nil,
   512  		},
   513  		{
   514  			tokenNamespaceID:                "valid-id",
   515  			tokenNamespaceName:              "valid-name",
   516  			requestNamespaceID:              "invalid-id",
   517  			requestNamespaceName:            "invalid-name",
   518  			enableTokenNamespaceEnforcement: true,
   519  			expectedErr:                     &serviceerror.InvalidArgument{},
   520  		},
   521  		{
   522  			tokenNamespaceID:                "valid-id",
   523  			tokenNamespaceName:              "valid-name",
   524  			requestNamespaceID:              "invalid-id",
   525  			requestNamespaceName:            "invalid-name",
   526  			enableTokenNamespaceEnforcement: false,
   527  			expectedErr:                     nil,
   528  		},
   529  	}
   530  
   531  	for _, testCase := range testCases {
   532  		taskToken, _ := common.NewProtoTaskTokenSerializer().Serialize(&tokenspb.Task{
   533  			NamespaceId: testCase.tokenNamespaceID.String(),
   534  		})
   535  		tokenNamespace := namespace.FromPersistentState(
   536  			&persistence.GetNamespaceResponse{
   537  				Namespace: &persistencespb.NamespaceDetail{
   538  					Config:            &persistencespb.NamespaceConfig{},
   539  					ReplicationConfig: &persistencespb.NamespaceReplicationConfig{},
   540  					Info: &persistencespb.NamespaceInfo{
   541  						Id:    testCase.tokenNamespaceID.String(),
   542  						Name:  testCase.tokenNamespaceName.String(),
   543  						State: enumspb.NAMESPACE_STATE_REGISTERED,
   544  					},
   545  				},
   546  			})
   547  
   548  		req := &workflowservice.RespondWorkflowTaskCompletedRequest{
   549  			Namespace: testCase.requestNamespaceName.String(),
   550  			TaskToken: taskToken,
   551  		}
   552  		queryReq := &workflowservice.RespondQueryTaskCompletedRequest{
   553  			Namespace: testCase.requestNamespaceName.String(),
   554  			TaskToken: taskToken,
   555  		}
   556  		requestNamespace := namespace.FromPersistentState(
   557  			&persistence.GetNamespaceResponse{
   558  				Namespace: &persistencespb.NamespaceDetail{
   559  					Config:            &persistencespb.NamespaceConfig{},
   560  					ReplicationConfig: &persistencespb.NamespaceReplicationConfig{},
   561  					Info: &persistencespb.NamespaceInfo{
   562  						Id:    testCase.requestNamespaceID.String(),
   563  						Name:  testCase.requestNamespaceName.String(),
   564  						State: enumspb.NAMESPACE_STATE_REGISTERED,
   565  					},
   566  				},
   567  			})
   568  
   569  		// 2 times because of RespondQueryTaskCompleted.
   570  		s.mockRegistry.EXPECT().GetNamespace(testCase.requestNamespaceName).Return(requestNamespace, nil).Times(2)
   571  		s.mockRegistry.EXPECT().GetNamespaceByID(testCase.tokenNamespaceID).Return(tokenNamespace, nil).Times(2)
   572  
   573  		nvi := NewNamespaceValidatorInterceptor(
   574  			s.mockRegistry,
   575  			dynamicconfig.GetBoolPropertyFn(testCase.enableTokenNamespaceEnforcement),
   576  			dynamicconfig.GetIntPropertyFn(100))
   577  		serverInfo := &grpc.UnaryServerInfo{
   578  			FullMethod: "/temporal/RandomMethod",
   579  		}
   580  
   581  		handlerCalled := false
   582  		_, err := nvi.StateValidationIntercept(context.Background(), req, serverInfo, func(ctx context.Context, req interface{}) (interface{}, error) {
   583  			handlerCalled = true
   584  			return &workflowservice.RespondWorkflowTaskCompletedResponse{}, nil
   585  		})
   586  		_, queryErr := nvi.StateValidationIntercept(context.Background(), queryReq, serverInfo, func(ctx context.Context, req interface{}) (interface{}, error) {
   587  			handlerCalled = true
   588  			return &workflowservice.RespondQueryTaskCompletedResponse{}, nil
   589  		})
   590  
   591  		if testCase.expectedErr != nil {
   592  			s.IsType(testCase.expectedErr, err)
   593  			s.IsType(testCase.expectedErr, queryErr)
   594  			s.False(handlerCalled)
   595  		} else {
   596  			s.NoError(err)
   597  			s.NoError(queryErr)
   598  			s.True(handlerCalled)
   599  		}
   600  	}
   601  }
   602  
   603  func (s *namespaceValidatorSuite) Test_Intercept_SearchAttributeRequests() {
   604  	// it's just a list of requests
   605  	testCases := []struct {
   606  		req          any
   607  		hasNamespace bool
   608  	}{
   609  		{
   610  			req:          &adminservice.AddSearchAttributesRequest{},
   611  			hasNamespace: false,
   612  		},
   613  		{
   614  			req:          &adminservice.RemoveSearchAttributesRequest{},
   615  			hasNamespace: false,
   616  		},
   617  		{
   618  			req:          &adminservice.GetSearchAttributesRequest{},
   619  			hasNamespace: false,
   620  		},
   621  		{
   622  			req:          &operatorservice.AddSearchAttributesRequest{},
   623  			hasNamespace: false,
   624  		},
   625  		{
   626  			req:          &operatorservice.RemoveSearchAttributesRequest{},
   627  			hasNamespace: false,
   628  		},
   629  		{
   630  			req:          &operatorservice.ListSearchAttributesRequest{},
   631  			hasNamespace: false,
   632  		},
   633  		{
   634  			req:          &adminservice.AddSearchAttributesRequest{Namespace: "test-namespace"},
   635  			hasNamespace: true,
   636  		},
   637  		{
   638  			req:          &adminservice.RemoveSearchAttributesRequest{Namespace: "test-namespace"},
   639  			hasNamespace: true,
   640  		},
   641  		{
   642  			req:          &adminservice.GetSearchAttributesRequest{Namespace: "test-namespace"},
   643  			hasNamespace: true,
   644  		},
   645  		{
   646  			req:          &operatorservice.AddSearchAttributesRequest{Namespace: "test-namespace"},
   647  			hasNamespace: true,
   648  		},
   649  		{
   650  			req:          &operatorservice.RemoveSearchAttributesRequest{Namespace: "test-namespace"},
   651  			hasNamespace: true,
   652  		},
   653  		{
   654  			req:          &operatorservice.ListSearchAttributesRequest{Namespace: "test-namespace"},
   655  			hasNamespace: true,
   656  		},
   657  	}
   658  
   659  	for _, testCase := range testCases {
   660  		if testCase.hasNamespace {
   661  			s.mockRegistry.EXPECT().GetNamespace(namespace.Name("test-namespace")).Return(nil, nil)
   662  		}
   663  
   664  		nvi := NewNamespaceValidatorInterceptor(
   665  			s.mockRegistry,
   666  			dynamicconfig.GetBoolPropertyFn(false),
   667  			dynamicconfig.GetIntPropertyFn(100),
   668  		)
   669  		serverInfo := &grpc.UnaryServerInfo{
   670  			FullMethod: "/temporal/random",
   671  		}
   672  
   673  		handlerCalled := false
   674  		_, err := nvi.StateValidationIntercept(
   675  			context.Background(),
   676  			testCase.req,
   677  			serverInfo,
   678  			func(ctx context.Context, req any) (any, error) {
   679  				handlerCalled = true
   680  				return nil, nil
   681  			},
   682  		)
   683  		s.NoError(err)
   684  		s.True(handlerCalled)
   685  	}
   686  }
   687  
   688  func (s *namespaceValidatorSuite) Test_NamespaceValidateIntercept() {
   689  	nvi := NewNamespaceValidatorInterceptor(
   690  		s.mockRegistry,
   691  		dynamicconfig.GetBoolPropertyFn(false),
   692  		dynamicconfig.GetIntPropertyFn(10))
   693  	serverInfo := &grpc.UnaryServerInfo{
   694  		FullMethod: "/temporal/random",
   695  	}
   696  	requestNamespace := namespace.FromPersistentState(
   697  		&persistence.GetNamespaceResponse{
   698  			Namespace: &persistencespb.NamespaceDetail{
   699  				Config:            &persistencespb.NamespaceConfig{},
   700  				ReplicationConfig: &persistencespb.NamespaceReplicationConfig{},
   701  				Info: &persistencespb.NamespaceInfo{
   702  					Id:    uuid.New().String(),
   703  					Name:  "namespace",
   704  					State: enumspb.NAMESPACE_STATE_REGISTERED,
   705  				},
   706  			},
   707  		})
   708  	requestNamespaceTooLong := namespace.FromPersistentState(
   709  		&persistence.GetNamespaceResponse{
   710  			Namespace: &persistencespb.NamespaceDetail{
   711  				Config:            &persistencespb.NamespaceConfig{},
   712  				ReplicationConfig: &persistencespb.NamespaceReplicationConfig{},
   713  				Info: &persistencespb.NamespaceInfo{
   714  					Id:    uuid.New().String(),
   715  					Name:  "namespaceTooLong",
   716  					State: enumspb.NAMESPACE_STATE_REGISTERED,
   717  				},
   718  			},
   719  		})
   720  	s.mockRegistry.EXPECT().GetNamespace(namespace.Name("namespace")).Return(requestNamespace, nil).AnyTimes()
   721  	s.mockRegistry.EXPECT().GetNamespace(namespace.Name("namespaceTooLong")).Return(requestNamespaceTooLong, nil).AnyTimes()
   722  
   723  	req := &workflowservice.StartWorkflowExecutionRequest{Namespace: "namespace"}
   724  	handlerCalled := false
   725  	_, err := nvi.NamespaceValidateIntercept(context.Background(), req, serverInfo, func(ctx context.Context, req interface{}) (interface{}, error) {
   726  		handlerCalled = true
   727  		return &workflowservice.StartWorkflowExecutionResponse{}, nil
   728  	})
   729  	s.True(handlerCalled)
   730  	s.NoError(err)
   731  
   732  	req = &workflowservice.StartWorkflowExecutionRequest{Namespace: "namespaceTooLong"}
   733  	handlerCalled = false
   734  	_, err = nvi.NamespaceValidateIntercept(context.Background(), req, serverInfo, func(ctx context.Context, req interface{}) (interface{}, error) {
   735  		handlerCalled = true
   736  		return &workflowservice.StartWorkflowExecutionResponse{}, nil
   737  	})
   738  	s.False(handlerCalled)
   739  	s.Error(err)
   740  }
   741  
   742  func (s *namespaceValidatorSuite) TestSetNamespace() {
   743  	namespaceRequestName := uuid.New().String()
   744  	namespaceEntryName := uuid.New().String()
   745  	namespaceEntry := namespace.FromPersistentState(
   746  		&persistence.GetNamespaceResponse{
   747  			Namespace: &persistencespb.NamespaceDetail{
   748  				Config:            &persistencespb.NamespaceConfig{},
   749  				ReplicationConfig: &persistencespb.NamespaceReplicationConfig{},
   750  				Info: &persistencespb.NamespaceInfo{
   751  					Id:    uuid.New().String(),
   752  					Name:  namespaceEntryName,
   753  					State: enumspb.NAMESPACE_STATE_REGISTERED,
   754  				},
   755  			},
   756  		})
   757  
   758  	nvi := NewNamespaceValidatorInterceptor(
   759  		s.mockRegistry,
   760  		dynamicconfig.GetBoolPropertyFn(false),
   761  		dynamicconfig.GetIntPropertyFn(10),
   762  	)
   763  
   764  	queryReq := &workflowservice.RespondQueryTaskCompletedRequest{}
   765  	nvi.setNamespace(namespaceEntry, queryReq)
   766  	s.Equal(namespaceEntryName, queryReq.Namespace)
   767  	queryReq.Namespace = namespaceRequestName
   768  	nvi.setNamespace(namespaceEntry, queryReq)
   769  	s.Equal(namespaceRequestName, queryReq.Namespace)
   770  
   771  	completeWorkflowTaskReq := &workflowservice.RespondWorkflowTaskCompletedRequest{}
   772  	nvi.setNamespace(namespaceEntry, completeWorkflowTaskReq)
   773  	s.Equal(namespaceEntryName, completeWorkflowTaskReq.Namespace)
   774  	completeWorkflowTaskReq.Namespace = namespaceRequestName
   775  	nvi.setNamespace(namespaceEntry, completeWorkflowTaskReq)
   776  	s.Equal(namespaceRequestName, completeWorkflowTaskReq.Namespace)
   777  
   778  	failWorkflowTaskReq := &workflowservice.RespondWorkflowTaskFailedRequest{}
   779  	nvi.setNamespace(namespaceEntry, failWorkflowTaskReq)
   780  	s.Equal(namespaceEntryName, failWorkflowTaskReq.Namespace)
   781  	failWorkflowTaskReq.Namespace = namespaceRequestName
   782  	nvi.setNamespace(namespaceEntry, failWorkflowTaskReq)
   783  	s.Equal(namespaceRequestName, failWorkflowTaskReq.Namespace)
   784  
   785  	heartbeatActivityTaskReq := &workflowservice.RecordActivityTaskHeartbeatRequest{}
   786  	nvi.setNamespace(namespaceEntry, heartbeatActivityTaskReq)
   787  	s.Equal(namespaceEntryName, heartbeatActivityTaskReq.Namespace)
   788  	heartbeatActivityTaskReq.Namespace = namespaceRequestName
   789  	nvi.setNamespace(namespaceEntry, heartbeatActivityTaskReq)
   790  	s.Equal(namespaceRequestName, heartbeatActivityTaskReq.Namespace)
   791  
   792  	cancelActivityTaskReq := &workflowservice.RespondActivityTaskCanceledRequest{}
   793  	nvi.setNamespace(namespaceEntry, cancelActivityTaskReq)
   794  	s.Equal(namespaceEntryName, cancelActivityTaskReq.Namespace)
   795  	cancelActivityTaskReq.Namespace = namespaceRequestName
   796  	nvi.setNamespace(namespaceEntry, cancelActivityTaskReq)
   797  	s.Equal(namespaceRequestName, cancelActivityTaskReq.Namespace)
   798  
   799  	completeActivityTaskReq := &workflowservice.RespondActivityTaskCompletedRequest{}
   800  	nvi.setNamespace(namespaceEntry, completeActivityTaskReq)
   801  	s.Equal(namespaceEntryName, completeActivityTaskReq.Namespace)
   802  	completeActivityTaskReq.Namespace = namespaceRequestName
   803  	nvi.setNamespace(namespaceEntry, completeActivityTaskReq)
   804  	s.Equal(namespaceRequestName, completeActivityTaskReq.Namespace)
   805  
   806  	failActivityTaskReq := &workflowservice.RespondActivityTaskFailedRequest{}
   807  	nvi.setNamespace(namespaceEntry, failActivityTaskReq)
   808  	s.Equal(namespaceEntryName, failActivityTaskReq.Namespace)
   809  	failActivityTaskReq.Namespace = namespaceRequestName
   810  	nvi.setNamespace(namespaceEntry, failActivityTaskReq)
   811  	s.Equal(namespaceRequestName, failActivityTaskReq.Namespace)
   812  }