go.temporal.io/server@v1.23.0/common/api/metadata_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 api 26 27 import ( 28 "reflect" 29 "regexp" 30 "testing" 31 32 "github.com/stretchr/testify/assert" 33 "github.com/stretchr/testify/require" 34 "go.temporal.io/api/operatorservice/v1" 35 "go.temporal.io/api/workflowservice/v1" 36 "golang.org/x/exp/maps" 37 ) 38 39 var publicMethodRgx = regexp.MustCompile("^[A-Z]") 40 41 func TestWorkflowServiceMetadata(t *testing.T) { 42 tp := reflect.TypeOf((*workflowservice.WorkflowServiceServer)(nil)).Elem() 43 checkService(t, tp, workflowServiceMetadata) 44 } 45 46 func TestOperatorServiceMetadata(t *testing.T) { 47 tp := reflect.TypeOf((*operatorservice.OperatorServiceServer)(nil)).Elem() 48 checkService(t, tp, operatorServiceMetadata) 49 } 50 51 func checkService(t *testing.T, tp reflect.Type, m map[string]MethodMetadata) { 52 methods := getMethodNames(tp) 53 require.ElementsMatch(t, methods, maps.Keys(m), 54 "If you're adding a new method to Workflow/OperatorService, please add metadata for it in metadata.go") 55 56 for _, method := range methods { 57 refMethod, ok := tp.MethodByName(method) 58 require.True(t, ok) 59 60 checkNamespace := false 61 hasNamespace := false 62 namespaceIsString := false 63 64 if refMethod.Type.NumIn() >= 2 { 65 // not streaming 66 checkNamespace = true 67 requestType := refMethod.Type.In(1).Elem() 68 var nsField reflect.StructField 69 nsField, hasNamespace = requestType.FieldByName("Namespace") 70 if hasNamespace { 71 namespaceIsString = nsField.Type == reflect.TypeOf("string") 72 } 73 } 74 75 md := m[method] 76 switch md.Scope { 77 case ScopeNamespace: 78 if checkNamespace { 79 assert.Truef(t, namespaceIsString, "%s with ScopeNamespace should have a Namespace field that is a string", method) 80 } 81 case ScopeCluster: 82 if checkNamespace { 83 assert.Falsef(t, hasNamespace, "%s with ScopeCluster should not have a Namespace field", method) 84 } 85 default: 86 t.Error("unknown Scope for", method) 87 } 88 89 switch md.Access { 90 case AccessReadOnly, AccessWrite, AccessAdmin: 91 default: 92 t.Error("unknown Access for", method) 93 } 94 } 95 } 96 97 func TestGetMethodMetadata(t *testing.T) { 98 md := GetMethodMetadata("/temporal.api.workflowservice.v1.WorkflowService/RespondActivityTaskCompleted") 99 assert.Equal(t, ScopeNamespace, md.Scope) 100 assert.Equal(t, AccessWrite, md.Access) 101 102 // all AdminService is cluster/admin 103 md = GetMethodMetadata("/temporal.server.api.adminservice.v1.AdminService/CloseShard") 104 assert.Equal(t, ScopeCluster, md.Scope) 105 assert.Equal(t, AccessAdmin, md.Access) 106 107 md = GetMethodMetadata("/OtherService/Method1") 108 assert.Equal(t, ScopeUnknown, md.Scope) 109 assert.Equal(t, AccessUnknown, md.Access) 110 } 111 112 func getMethodNames(tp reflect.Type) []string { 113 var out []string 114 for i := 0; i < tp.NumMethod(); i++ { 115 name := tp.Method(i).Name 116 // Don't collect unimplemented methods. This weeds out the 117 // `mustEmbedUnimplementedFooBarBaz` required by the GRPC v2 gateway 118 if publicMethodRgx.MatchString(name) { 119 out = append(out, name) 120 } 121 } 122 return out 123 }