github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/expvar/expvar_test.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package expvar 6 7 import ( 8 "bytes" 9 "encoding/json" 10 "fmt" 11 "net" 12 "net/http/httptest" 13 "reflect" 14 "runtime" 15 "strconv" 16 "sync" 17 "sync/atomic" 18 "testing" 19 ) 20 21 // RemoveAll removes all exported variables. 22 // This is for tests only. 23 func RemoveAll() { 24 varKeysMu.Lock() 25 defer varKeysMu.Unlock() 26 for _, k := range varKeys { 27 vars.Delete(k) 28 } 29 varKeys = nil 30 } 31 32 func TestNil(t *testing.T) { 33 RemoveAll() 34 val := Get("missing") 35 if val != nil { 36 t.Errorf("got %v, want nil", val) 37 } 38 } 39 40 func TestInt(t *testing.T) { 41 RemoveAll() 42 reqs := NewInt("requests") 43 if i := reqs.Value(); i != 0 { 44 t.Errorf("reqs.Value() = %v, want 0", i) 45 } 46 if reqs != Get("requests").(*Int) { 47 t.Errorf("Get() failed.") 48 } 49 50 reqs.Add(1) 51 reqs.Add(3) 52 if i := reqs.Value(); i != 4 { 53 t.Errorf("reqs.Value() = %v, want 4", i) 54 } 55 56 if s := reqs.String(); s != "4" { 57 t.Errorf("reqs.String() = %q, want \"4\"", s) 58 } 59 60 reqs.Set(-2) 61 if i := reqs.Value(); i != -2 { 62 t.Errorf("reqs.Value() = %v, want -2", i) 63 } 64 } 65 66 func BenchmarkIntAdd(b *testing.B) { 67 var v Int 68 69 b.RunParallel(func(pb *testing.PB) { 70 for pb.Next() { 71 v.Add(1) 72 } 73 }) 74 } 75 76 func BenchmarkIntSet(b *testing.B) { 77 var v Int 78 79 b.RunParallel(func(pb *testing.PB) { 80 for pb.Next() { 81 v.Set(1) 82 } 83 }) 84 } 85 86 func TestFloat(t *testing.T) { 87 RemoveAll() 88 reqs := NewFloat("requests-float") 89 if reqs.f != 0.0 { 90 t.Errorf("reqs.f = %v, want 0", reqs.f) 91 } 92 if reqs != Get("requests-float").(*Float) { 93 t.Errorf("Get() failed.") 94 } 95 96 reqs.Add(1.5) 97 reqs.Add(1.25) 98 if v := reqs.Value(); v != 2.75 { 99 t.Errorf("reqs.Value() = %v, want 2.75", v) 100 } 101 102 if s := reqs.String(); s != "2.75" { 103 t.Errorf("reqs.String() = %q, want \"4.64\"", s) 104 } 105 106 reqs.Add(-2) 107 if v := reqs.Value(); v != 0.75 { 108 t.Errorf("reqs.Value() = %v, want 0.75", v) 109 } 110 } 111 112 func BenchmarkFloatAdd(b *testing.B) { 113 var f Float 114 115 b.RunParallel(func(pb *testing.PB) { 116 for pb.Next() { 117 f.Add(1.0) 118 } 119 }) 120 } 121 122 func BenchmarkFloatSet(b *testing.B) { 123 var f Float 124 125 b.RunParallel(func(pb *testing.PB) { 126 for pb.Next() { 127 f.Set(1.0) 128 } 129 }) 130 } 131 132 func TestString(t *testing.T) { 133 RemoveAll() 134 name := NewString("my-name") 135 if s := name.Value(); s != "" { 136 t.Errorf(`NewString("my-name").Value() = %q, want ""`, s) 137 } 138 139 name.Set("Mike") 140 if s, want := name.String(), `"Mike"`; s != want { 141 t.Errorf(`after name.Set("Mike"), name.String() = %q, want %q`, s, want) 142 } 143 if s, want := name.Value(), "Mike"; s != want { 144 t.Errorf(`after name.Set("Mike"), name.Value() = %q, want %q`, s, want) 145 } 146 147 // Make sure we produce safe JSON output. 148 name.Set("<") 149 if s, want := name.String(), "\"\\u003c\""; s != want { 150 t.Errorf(`after name.Set("<"), name.String() = %q, want %q`, s, want) 151 } 152 } 153 154 func BenchmarkStringSet(b *testing.B) { 155 var s String 156 157 b.RunParallel(func(pb *testing.PB) { 158 for pb.Next() { 159 s.Set("red") 160 } 161 }) 162 } 163 164 func TestMapInit(t *testing.T) { 165 RemoveAll() 166 colors := NewMap("bike-shed-colors") 167 colors.Add("red", 1) 168 colors.Add("blue", 1) 169 colors.Add("chartreuse", 1) 170 171 n := 0 172 colors.Do(func(KeyValue) { n++ }) 173 if n != 3 { 174 t.Errorf("after three Add calls with distinct keys, Do should invoke f 3 times; got %v", n) 175 } 176 177 colors.Init() 178 179 n = 0 180 colors.Do(func(KeyValue) { n++ }) 181 if n != 0 { 182 t.Errorf("after Init, Do should invoke f 0 times; got %v", n) 183 } 184 } 185 186 func TestMapDelete(t *testing.T) { 187 RemoveAll() 188 colors := NewMap("bike-shed-colors") 189 190 colors.Add("red", 1) 191 colors.Add("red", 2) 192 colors.Add("blue", 4) 193 194 n := 0 195 colors.Do(func(KeyValue) { n++ }) 196 if n != 2 { 197 t.Errorf("after two Add calls with distinct keys, Do should invoke f 2 times; got %v", n) 198 } 199 200 colors.Delete("red") 201 n = 0 202 colors.Do(func(KeyValue) { n++ }) 203 if n != 1 { 204 t.Errorf("removed red, Do should invoke f 1 times; got %v", n) 205 } 206 207 colors.Delete("notfound") 208 n = 0 209 colors.Do(func(KeyValue) { n++ }) 210 if n != 1 { 211 t.Errorf("attempted to remove notfound, Do should invoke f 1 times; got %v", n) 212 } 213 214 colors.Delete("blue") 215 colors.Delete("blue") 216 n = 0 217 colors.Do(func(KeyValue) { n++ }) 218 if n != 0 { 219 t.Errorf("all keys removed, Do should invoke f 0 times; got %v", n) 220 } 221 } 222 223 func TestMapCounter(t *testing.T) { 224 RemoveAll() 225 colors := NewMap("bike-shed-colors") 226 227 colors.Add("red", 1) 228 colors.Add("red", 2) 229 colors.Add("blue", 4) 230 colors.AddFloat(`green "midori"`, 4.125) 231 if x := colors.Get("red").(*Int).Value(); x != 3 { 232 t.Errorf("colors.m[\"red\"] = %v, want 3", x) 233 } 234 if x := colors.Get("blue").(*Int).Value(); x != 4 { 235 t.Errorf("colors.m[\"blue\"] = %v, want 4", x) 236 } 237 if x := colors.Get(`green "midori"`).(*Float).Value(); x != 4.125 { 238 t.Errorf("colors.m[`green \"midori\"] = %v, want 4.125", x) 239 } 240 241 // colors.String() should be '{"red":3, "blue":4}', 242 // though the order of red and blue could vary. 243 s := colors.String() 244 var j interface{} 245 err := json.Unmarshal([]byte(s), &j) 246 if err != nil { 247 t.Errorf("colors.String() isn't valid JSON: %v", err) 248 } 249 m, ok := j.(map[string]interface{}) 250 if !ok { 251 t.Error("colors.String() didn't produce a map.") 252 } 253 red := m["red"] 254 x, ok := red.(float64) 255 if !ok { 256 t.Error("red.Kind() is not a number.") 257 } 258 if x != 3 { 259 t.Errorf("red = %v, want 3", x) 260 } 261 } 262 263 func BenchmarkMapSet(b *testing.B) { 264 m := new(Map).Init() 265 266 v := new(Int) 267 268 b.RunParallel(func(pb *testing.PB) { 269 for pb.Next() { 270 m.Set("red", v) 271 } 272 }) 273 } 274 275 func BenchmarkMapSetDifferent(b *testing.B) { 276 procKeys := make([][]string, runtime.GOMAXPROCS(0)) 277 for i := range procKeys { 278 keys := make([]string, 4) 279 for j := range keys { 280 keys[j] = fmt.Sprint(i, j) 281 } 282 procKeys[i] = keys 283 } 284 285 m := new(Map).Init() 286 v := new(Int) 287 b.ResetTimer() 288 289 var n int32 290 b.RunParallel(func(pb *testing.PB) { 291 i := int(atomic.AddInt32(&n, 1)-1) % len(procKeys) 292 keys := procKeys[i] 293 294 for pb.Next() { 295 for _, k := range keys { 296 m.Set(k, v) 297 } 298 } 299 }) 300 } 301 302 func BenchmarkMapSetString(b *testing.B) { 303 m := new(Map).Init() 304 305 v := new(String) 306 v.Set("Hello, !") 307 308 b.RunParallel(func(pb *testing.PB) { 309 for pb.Next() { 310 m.Set("red", v) 311 } 312 }) 313 } 314 315 func BenchmarkMapAddSame(b *testing.B) { 316 b.RunParallel(func(pb *testing.PB) { 317 for pb.Next() { 318 m := new(Map).Init() 319 m.Add("red", 1) 320 m.Add("red", 1) 321 m.Add("red", 1) 322 m.Add("red", 1) 323 } 324 }) 325 } 326 327 func BenchmarkMapAddDifferent(b *testing.B) { 328 procKeys := make([][]string, runtime.GOMAXPROCS(0)) 329 for i := range procKeys { 330 keys := make([]string, 4) 331 for j := range keys { 332 keys[j] = fmt.Sprint(i, j) 333 } 334 procKeys[i] = keys 335 } 336 337 b.ResetTimer() 338 339 var n int32 340 b.RunParallel(func(pb *testing.PB) { 341 i := int(atomic.AddInt32(&n, 1)-1) % len(procKeys) 342 keys := procKeys[i] 343 344 for pb.Next() { 345 m := new(Map).Init() 346 for _, k := range keys { 347 m.Add(k, 1) 348 } 349 } 350 }) 351 } 352 353 func BenchmarkMapAddSameSteadyState(b *testing.B) { 354 m := new(Map).Init() 355 b.RunParallel(func(pb *testing.PB) { 356 for pb.Next() { 357 m.Add("red", 1) 358 } 359 }) 360 } 361 362 func BenchmarkMapAddDifferentSteadyState(b *testing.B) { 363 procKeys := make([][]string, runtime.GOMAXPROCS(0)) 364 for i := range procKeys { 365 keys := make([]string, 4) 366 for j := range keys { 367 keys[j] = fmt.Sprint(i, j) 368 } 369 procKeys[i] = keys 370 } 371 372 m := new(Map).Init() 373 b.ResetTimer() 374 375 var n int32 376 b.RunParallel(func(pb *testing.PB) { 377 i := int(atomic.AddInt32(&n, 1)-1) % len(procKeys) 378 keys := procKeys[i] 379 380 for pb.Next() { 381 for _, k := range keys { 382 m.Add(k, 1) 383 } 384 } 385 }) 386 } 387 388 func TestFunc(t *testing.T) { 389 RemoveAll() 390 var x interface{} = []string{"a", "b"} 391 f := Func(func() interface{} { return x }) 392 if s, exp := f.String(), `["a","b"]`; s != exp { 393 t.Errorf(`f.String() = %q, want %q`, s, exp) 394 } 395 if v := f.Value(); !reflect.DeepEqual(v, x) { 396 t.Errorf(`f.Value() = %q, want %q`, v, x) 397 } 398 399 x = 17 400 if s, exp := f.String(), `17`; s != exp { 401 t.Errorf(`f.String() = %q, want %q`, s, exp) 402 } 403 } 404 405 func TestHandler(t *testing.T) { 406 RemoveAll() 407 m := NewMap("map1") 408 m.Add("a", 1) 409 m.Add("z", 2) 410 m2 := NewMap("map2") 411 for i := 0; i < 9; i++ { 412 m2.Add(strconv.Itoa(i), int64(i)) 413 } 414 rr := httptest.NewRecorder() 415 rr.Body = new(bytes.Buffer) 416 expvarHandler(rr, nil) 417 want := `{ 418 "map1": {"a": 1, "z": 2}, 419 "map2": {"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8} 420 } 421 ` 422 if got := rr.Body.String(); got != want { 423 t.Errorf("HTTP handler wrote:\n%s\nWant:\n%s", got, want) 424 } 425 } 426 427 func BenchmarkRealworldExpvarUsage(b *testing.B) { 428 var ( 429 bytesSent Int 430 bytesRead Int 431 ) 432 433 // The benchmark creates GOMAXPROCS client/server pairs. 434 // Each pair creates 4 goroutines: client reader/writer and server reader/writer. 435 // The benchmark stresses concurrent reading and writing to the same connection. 436 // Such pattern is used in net/http and net/rpc. 437 438 b.StopTimer() 439 440 P := runtime.GOMAXPROCS(0) 441 N := b.N / P 442 W := 1000 443 444 // Setup P client/server connections. 445 clients := make([]net.Conn, P) 446 servers := make([]net.Conn, P) 447 ln, err := net.Listen("tcp", "127.0.0.1:0") 448 if err != nil { 449 b.Fatalf("Listen failed: %v", err) 450 } 451 defer ln.Close() 452 done := make(chan bool) 453 go func() { 454 for p := 0; p < P; p++ { 455 s, err := ln.Accept() 456 if err != nil { 457 b.Errorf("Accept failed: %v", err) 458 return 459 } 460 servers[p] = s 461 } 462 done <- true 463 }() 464 for p := 0; p < P; p++ { 465 c, err := net.Dial("tcp", ln.Addr().String()) 466 if err != nil { 467 b.Fatalf("Dial failed: %v", err) 468 } 469 clients[p] = c 470 } 471 <-done 472 473 b.StartTimer() 474 475 var wg sync.WaitGroup 476 wg.Add(4 * P) 477 for p := 0; p < P; p++ { 478 // Client writer. 479 go func(c net.Conn) { 480 defer wg.Done() 481 var buf [1]byte 482 for i := 0; i < N; i++ { 483 v := byte(i) 484 for w := 0; w < W; w++ { 485 v *= v 486 } 487 buf[0] = v 488 n, err := c.Write(buf[:]) 489 if err != nil { 490 b.Errorf("Write failed: %v", err) 491 return 492 } 493 494 bytesSent.Add(int64(n)) 495 } 496 }(clients[p]) 497 498 // Pipe between server reader and server writer. 499 pipe := make(chan byte, 128) 500 501 // Server reader. 502 go func(s net.Conn) { 503 defer wg.Done() 504 var buf [1]byte 505 for i := 0; i < N; i++ { 506 n, err := s.Read(buf[:]) 507 508 if err != nil { 509 b.Errorf("Read failed: %v", err) 510 return 511 } 512 513 bytesRead.Add(int64(n)) 514 pipe <- buf[0] 515 } 516 }(servers[p]) 517 518 // Server writer. 519 go func(s net.Conn) { 520 defer wg.Done() 521 var buf [1]byte 522 for i := 0; i < N; i++ { 523 v := <-pipe 524 for w := 0; w < W; w++ { 525 v *= v 526 } 527 buf[0] = v 528 n, err := s.Write(buf[:]) 529 if err != nil { 530 b.Errorf("Write failed: %v", err) 531 return 532 } 533 534 bytesSent.Add(int64(n)) 535 } 536 s.Close() 537 }(servers[p]) 538 539 // Client reader. 540 go func(c net.Conn) { 541 defer wg.Done() 542 var buf [1]byte 543 for i := 0; i < N; i++ { 544 n, err := c.Read(buf[:]) 545 546 if err != nil { 547 b.Errorf("Read failed: %v", err) 548 return 549 } 550 551 bytesRead.Add(int64(n)) 552 } 553 c.Close() 554 }(clients[p]) 555 } 556 wg.Wait() 557 }