github.com/nats-io/nats-server/v2@v2.11.0-preview.2/server/util_test.go (about) 1 // Copyright 2012-2018 The NATS Authors 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package server 15 16 import ( 17 "math" 18 "math/rand" 19 "net/url" 20 "reflect" 21 "strconv" 22 "sync" 23 "testing" 24 "time" 25 ) 26 27 func TestParseSize(t *testing.T) { 28 if parseSize(nil) != -1 { 29 t.Fatal("Should error on nil byte slice") 30 } 31 n := []byte("12345678") 32 if pn := parseSize(n); pn != 12345678 { 33 t.Fatalf("Did not parse %q correctly, res=%d", n, pn) 34 } 35 36 n = []byte("12345invalid678") 37 if pn := parseSize(n); pn != -1 { 38 t.Fatalf("Should error on %q, res=%d", n, pn) 39 } 40 } 41 42 func TestParseSInt64(t *testing.T) { 43 if parseInt64(nil) != -1 { 44 t.Fatal("Should error on nil byte slice") 45 } 46 n := []byte("12345678") 47 if pn := parseInt64(n); pn != 12345678 { 48 t.Fatalf("Did not parse %q correctly, res=%d", n, pn) 49 } 50 51 n = []byte("12345invalid678") 52 if pn := parseInt64(n); pn != -1 { 53 t.Fatalf("Should error on %q, res=%d", n, pn) 54 } 55 } 56 57 func TestParseHostPort(t *testing.T) { 58 check := func(hostPort string, defaultPort int, expectedHost string, expectedPort int, expectedErr bool) { 59 h, p, err := parseHostPort(hostPort, defaultPort) 60 if expectedErr { 61 if err == nil { 62 stackFatalf(t, "Expected an error, did not get one") 63 } 64 // expected error, so we are done 65 return 66 } 67 if !expectedErr && err != nil { 68 stackFatalf(t, "Unexpected error: %v", err) 69 } 70 if expectedHost != h { 71 stackFatalf(t, "Expected host %q, got %q", expectedHost, h) 72 } 73 if expectedPort != p { 74 stackFatalf(t, "Expected port %d, got %d", expectedPort, p) 75 } 76 } 77 check("addr:1234", 5678, "addr", 1234, false) 78 check(" addr:1234 ", 5678, "addr", 1234, false) 79 check(" addr : 1234 ", 5678, "addr", 1234, false) 80 check("addr", 5678, "addr", 5678, false) 81 check(" addr ", 5678, "addr", 5678, false) 82 check("addr:-1", 5678, "addr", 5678, false) 83 check(" addr:-1 ", 5678, "addr", 5678, false) 84 check(" addr : -1 ", 5678, "addr", 5678, false) 85 check("addr:0", 5678, "addr", 5678, false) 86 check(" addr:0 ", 5678, "addr", 5678, false) 87 check(" addr : 0 ", 5678, "addr", 5678, false) 88 check("addr:addr", 0, "", 0, true) 89 check("addr:::1234", 0, "", 0, true) 90 check("", 0, "", 0, true) 91 } 92 93 func TestURLsAreEqual(t *testing.T) { 94 check := func(t *testing.T, u1Str, u2Str string, expectedSame bool) { 95 t.Helper() 96 u1, err := url.Parse(u1Str) 97 if err != nil { 98 t.Fatalf("Error parsing url %q: %v", u1Str, err) 99 } 100 u2, err := url.Parse(u2Str) 101 if err != nil { 102 t.Fatalf("Error parsing url %q: %v", u2Str, err) 103 } 104 same := urlsAreEqual(u1, u2) 105 if expectedSame && !same { 106 t.Fatalf("Expected %v and %v to be the same, they were not", u1, u2) 107 } else if !expectedSame && same { 108 t.Fatalf("Expected %v and %v to be different, they were not", u1, u2) 109 } 110 } 111 check(t, "nats://localhost:4222", "nats://localhost:4222", true) 112 check(t, "nats://ivan:pwd@localhost:4222", "nats://ivan:pwd@localhost:4222", true) 113 check(t, "nats://ivan@localhost:4222", "nats://ivan@localhost:4222", true) 114 check(t, "nats://ivan:@localhost:4222", "nats://ivan:@localhost:4222", true) 115 check(t, "nats://host1:4222", "nats://host2:4222", false) 116 } 117 118 func TestComma(t *testing.T) { 119 type testList []struct { 120 name, got, exp string 121 } 122 123 l := testList{ 124 {"0", comma(0), "0"}, 125 {"10", comma(10), "10"}, 126 {"100", comma(100), "100"}, 127 {"1,000", comma(1000), "1,000"}, 128 {"10,000", comma(10000), "10,000"}, 129 {"100,000", comma(100000), "100,000"}, 130 {"10,000,000", comma(10000000), "10,000,000"}, 131 {"10,100,000", comma(10100000), "10,100,000"}, 132 {"10,010,000", comma(10010000), "10,010,000"}, 133 {"10,001,000", comma(10001000), "10,001,000"}, 134 {"123,456,789", comma(123456789), "123,456,789"}, 135 {"maxint", comma(9.223372e+18), "9,223,372,000,000,000,000"}, 136 {"math.maxint", comma(math.MaxInt64), "9,223,372,036,854,775,807"}, 137 {"math.minint", comma(math.MinInt64), "-9,223,372,036,854,775,808"}, 138 {"minint", comma(-9.223372e+18), "-9,223,372,000,000,000,000"}, 139 {"-123,456,789", comma(-123456789), "-123,456,789"}, 140 {"-10,100,000", comma(-10100000), "-10,100,000"}, 141 {"-10,010,000", comma(-10010000), "-10,010,000"}, 142 {"-10,001,000", comma(-10001000), "-10,001,000"}, 143 {"-10,000,000", comma(-10000000), "-10,000,000"}, 144 {"-100,000", comma(-100000), "-100,000"}, 145 {"-10,000", comma(-10000), "-10,000"}, 146 {"-1,000", comma(-1000), "-1,000"}, 147 {"-100", comma(-100), "-100"}, 148 {"-10", comma(-10), "-10"}, 149 } 150 151 failed := false 152 for _, test := range l { 153 if test.got != test.exp { 154 t.Errorf("On %v, expected '%v', but got '%v'", 155 test.name, test.exp, test.got) 156 failed = true 157 } 158 } 159 if failed { 160 t.FailNow() 161 } 162 } 163 164 func TestURLRedaction(t *testing.T) { 165 redactionFromTo := []struct { 166 Full string 167 Safe string 168 }{ 169 {"nats://foo:bar@example.org", "nats://foo:xxxxx@example.org"}, 170 {"nats://foo@example.org", "nats://foo@example.org"}, 171 {"nats://example.org", "nats://example.org"}, 172 {"nats://example.org/foo?bar=1", "nats://example.org/foo?bar=1"}, 173 } 174 var err error 175 listFull := make([]*url.URL, len(redactionFromTo)) 176 listSafe := make([]*url.URL, len(redactionFromTo)) 177 for i := range redactionFromTo { 178 r := redactURLString(redactionFromTo[i].Full) 179 if r != redactionFromTo[i].Safe { 180 t.Fatalf("Redacting URL [index %d] %q, expected %q got %q", i, redactionFromTo[i].Full, redactionFromTo[i].Safe, r) 181 } 182 if listFull[i], err = url.Parse(redactionFromTo[i].Full); err != nil { 183 t.Fatalf("Redacting URL index %d parse Full failed: %v", i, err) 184 } 185 if listSafe[i], err = url.Parse(redactionFromTo[i].Safe); err != nil { 186 t.Fatalf("Redacting URL index %d parse Safe failed: %v", i, err) 187 } 188 } 189 results := redactURLList(listFull) 190 if !reflect.DeepEqual(results, listSafe) { 191 t.Fatalf("Redacting URL list did not compare equal, even after each URL did") 192 } 193 } 194 195 func TestVersionAtLeast(t *testing.T) { 196 for _, test := range []struct { 197 version string 198 major int 199 minor int 200 update int 201 result bool 202 }{ 203 {"2.0.0-beta", 1, 9, 9, true}, 204 {"2.0.0", 1, 99, 9, true}, 205 {"2.2.0", 2, 1, 9, true}, 206 {"2.2.2", 2, 2, 2, true}, 207 {"2.2.2", 2, 2, 3, false}, 208 {"2.2.2", 2, 3, 2, false}, 209 {"2.2.2", 3, 2, 2, false}, 210 {"2.22.2", 3, 0, 0, false}, 211 {"2.2.22", 2, 3, 0, false}, 212 {"bad.version", 1, 2, 3, false}, 213 } { 214 t.Run(_EMPTY_, func(t *testing.T) { 215 if res := versionAtLeast(test.version, test.major, test.minor, test.update); res != test.result { 216 t.Fatalf("For check version %q at least %d.%d.%d result should have been %v, got %v", 217 test.version, test.major, test.minor, test.update, test.result, res) 218 } 219 }) 220 } 221 } 222 223 func BenchmarkParseInt(b *testing.B) { 224 b.SetBytes(1) 225 n := "12345678" 226 for i := 0; i < b.N; i++ { 227 strconv.ParseInt(n, 10, 0) 228 } 229 } 230 231 func BenchmarkParseSize(b *testing.B) { 232 b.SetBytes(1) 233 n := []byte("12345678") 234 for i := 0; i < b.N; i++ { 235 parseSize(n) 236 } 237 } 238 239 func deferUnlock(mu *sync.Mutex) { 240 mu.Lock() 241 defer mu.Unlock() 242 // see noDeferUnlock 243 if false { 244 return 245 } 246 } 247 248 func BenchmarkDeferMutex(b *testing.B) { 249 var mu sync.Mutex 250 b.SetBytes(1) 251 for i := 0; i < b.N; i++ { 252 deferUnlock(&mu) 253 } 254 } 255 256 func noDeferUnlock(mu *sync.Mutex) { 257 mu.Lock() 258 // prevent staticcheck warning about empty critical section 259 if false { 260 return 261 } 262 mu.Unlock() 263 } 264 265 func BenchmarkNoDeferMutex(b *testing.B) { 266 var mu sync.Mutex 267 b.SetBytes(1) 268 for i := 0; i < b.N; i++ { 269 noDeferUnlock(&mu) 270 } 271 } 272 273 func createTestSub() *subscription { 274 return &subscription{ 275 subject: []byte("foo"), 276 queue: []byte("bar"), 277 sid: []byte("22"), 278 } 279 } 280 281 func BenchmarkArrayRand(b *testing.B) { 282 b.StopTimer() 283 r := rand.New(rand.NewSource(time.Now().UnixNano())) 284 // Create an array of 10 items 285 subs := []*subscription{} 286 for i := 0; i < 10; i++ { 287 subs = append(subs, createTestSub()) 288 } 289 b.StartTimer() 290 291 for i := 0; i < b.N; i++ { 292 index := r.Intn(len(subs)) 293 _ = subs[index] 294 } 295 } 296 297 func BenchmarkMapRange(b *testing.B) { 298 b.StopTimer() 299 // Create an map of 10 items 300 subs := map[int]*subscription{} 301 for i := 0; i < 10; i++ { 302 subs[i] = createTestSub() 303 } 304 b.StartTimer() 305 306 for i := 0; i < b.N; i++ { 307 for range subs { 308 break 309 } 310 } 311 }