knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/test/helpers/name.go (about) 1 /* 2 Copyright 2019 The Knative Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package helpers 18 19 import ( 20 "math/rand" 21 "strings" 22 "sync" 23 "time" 24 "unicode" 25 ) 26 27 const ( 28 letterBytes = "abcdefghijklmnopqrstuvwxyz" 29 randSuffixLen = 8 30 nameLengthLimit = 50 31 sep = '-' 32 sepS = "-" 33 testNamePrefix = "Test" 34 ) 35 36 var ( 37 nameRand *rand.Rand 38 nameMu sync.Mutex 39 ) 40 41 func init() { 42 // Properly seed the random number generator so RandomString() is actually random. 43 // Otherwise, rerunning tests will generate the same names for the test resources, causing conflicts with 44 // already existing resources. 45 seed := time.Now().UTC().UnixNano() 46 nameRand = rand.New(rand.NewSource(seed)) 47 } 48 49 type named interface { 50 Name() string 51 } 52 53 // ObjectPrefixForTest returns the name prefix for this test's random names. 54 func ObjectPrefixForTest(t named) string { 55 return MakeK8sNamePrefix(strings.TrimPrefix(t.Name(), testNamePrefix)) 56 } 57 58 // ObjectNameForTest generates a random object name based on the test name. 59 func ObjectNameForTest(t named) string { 60 prefix := ObjectPrefixForTest(t) 61 suffix := string(sep) + RandomString() 62 limit := nameLengthLimit - len(suffix) 63 if len(prefix) < limit { 64 limit = len(prefix) 65 } 66 67 return prefix[:limit] + suffix 68 } 69 70 // AppendRandomString will generate a random string that begins with prefix. 71 // This is useful if you want to make sure that your tests can run at the same 72 // time against the same environment without conflicting. 73 // This method will use "-" as the separator between the prefix and 74 // the random suffix. 75 func AppendRandomString(prefix string) string { 76 return prefix + sepS + RandomString() 77 } 78 79 // RandomString will generate a random string. 80 func RandomString() string { 81 suffix := make([]byte, randSuffixLen) 82 nameMu.Lock() 83 for i := range suffix { 84 suffix[i] = letterBytes[nameRand.Intn(len(letterBytes))] 85 } 86 nameMu.Unlock() 87 return string(suffix) 88 } 89 90 // For the same prefix more specific should come first. 91 // Note: we expect GRPC vs gRPC. 92 var knownNames = []string{"GRPC", "H2C", "HTTPS", "HTTP2", "HTTP", "REST", "TLS", "WS"} 93 94 // MakeK8sNamePrefix converts each chunk of non-alphanumeric character into a single dash 95 // and also convert camelcase tokens into dash-delimited lowercase tokens. 96 // The function will try to catch some well known abbreviations, so that we don't separate them. 97 func MakeK8sNamePrefix(s string) string { 98 var sb strings.Builder 99 sb.Grow(len(s)) // At least as many chars will be in the output. 100 newToken := false 101 outer: 102 for i := 0; i < len(s); i++ { 103 c := rune(s[i]) 104 if !unicode.IsLetter(c) && !unicode.IsNumber(c) { 105 newToken = true 106 continue 107 } 108 isUpper := unicode.IsUpper(c) 109 // We could've done it only for uppercase letters, 110 if isUpper { 111 for _, n := range knownNames { 112 if strings.HasPrefix(s[i:], n) { 113 sub := s[i : i+len(n)] 114 if sb.Len() > 0 { 115 sb.WriteRune(sep) 116 } 117 sb.WriteString(strings.ToLower(sub)) 118 i += len(n) - 1 119 continue outer 120 } 121 } 122 } 123 // Just a random uppercase word. 124 if sb.Len() > 0 && (newToken || isUpper) { 125 sb.WriteRune(sep) 126 } 127 sb.WriteRune(unicode.ToLower(c)) 128 newToken = false 129 } 130 return sb.String() 131 } 132 133 // GetBaseFuncName returns the baseFuncName parsed from the fullFuncName. 134 // eg. test/e2e.TestMain will return TestMain. 135 func GetBaseFuncName(fullFuncName string) string { 136 name := fullFuncName 137 // Possibly there is no parent package, so only remove it from the name if '/' exists 138 if strings.ContainsRune(name, '/') { 139 name = name[strings.LastIndex(name, "/")+1:] 140 } 141 name = name[strings.LastIndex(name, ".")+1:] 142 return name 143 }