Fix modref's iteraction with store merging
[official-gcc.git] / libgo / go / expvar / expvar_test.go
blobba95a36066c390135b05bd1ba555069a0efad122
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.
5 package expvar
7 import (
8 "bytes"
9 "crypto/sha1"
10 "encoding/json"
11 "fmt"
12 "net"
13 "net/http/httptest"
14 "reflect"
15 "runtime"
16 "strconv"
17 "sync"
18 "sync/atomic"
19 "testing"
22 // RemoveAll removes all exported variables.
23 // This is for tests only.
24 func RemoveAll() {
25 varKeysMu.Lock()
26 defer varKeysMu.Unlock()
27 for _, k := range varKeys {
28 vars.Delete(k)
30 varKeys = nil
33 func TestNil(t *testing.T) {
34 RemoveAll()
35 val := Get("missing")
36 if val != nil {
37 t.Errorf("got %v, want nil", val)
41 func TestInt(t *testing.T) {
42 RemoveAll()
43 reqs := NewInt("requests")
44 if i := reqs.Value(); i != 0 {
45 t.Errorf("reqs.Value() = %v, want 0", i)
47 if reqs != Get("requests").(*Int) {
48 t.Errorf("Get() failed.")
51 reqs.Add(1)
52 reqs.Add(3)
53 if i := reqs.Value(); i != 4 {
54 t.Errorf("reqs.Value() = %v, want 4", i)
57 if s := reqs.String(); s != "4" {
58 t.Errorf("reqs.String() = %q, want \"4\"", s)
61 reqs.Set(-2)
62 if i := reqs.Value(); i != -2 {
63 t.Errorf("reqs.Value() = %v, want -2", i)
67 func BenchmarkIntAdd(b *testing.B) {
68 var v Int
70 b.RunParallel(func(pb *testing.PB) {
71 for pb.Next() {
72 v.Add(1)
77 func BenchmarkIntSet(b *testing.B) {
78 var v Int
80 b.RunParallel(func(pb *testing.PB) {
81 for pb.Next() {
82 v.Set(1)
87 func TestFloat(t *testing.T) {
88 RemoveAll()
89 reqs := NewFloat("requests-float")
90 if reqs.f != 0.0 {
91 t.Errorf("reqs.f = %v, want 0", reqs.f)
93 if reqs != Get("requests-float").(*Float) {
94 t.Errorf("Get() failed.")
97 reqs.Add(1.5)
98 reqs.Add(1.25)
99 if v := reqs.Value(); v != 2.75 {
100 t.Errorf("reqs.Value() = %v, want 2.75", v)
103 if s := reqs.String(); s != "2.75" {
104 t.Errorf("reqs.String() = %q, want \"4.64\"", s)
107 reqs.Add(-2)
108 if v := reqs.Value(); v != 0.75 {
109 t.Errorf("reqs.Value() = %v, want 0.75", v)
113 func BenchmarkFloatAdd(b *testing.B) {
114 var f Float
116 b.RunParallel(func(pb *testing.PB) {
117 for pb.Next() {
118 f.Add(1.0)
123 func BenchmarkFloatSet(b *testing.B) {
124 var f Float
126 b.RunParallel(func(pb *testing.PB) {
127 for pb.Next() {
128 f.Set(1.0)
133 func TestString(t *testing.T) {
134 RemoveAll()
135 name := NewString("my-name")
136 if s := name.Value(); s != "" {
137 t.Errorf(`NewString("my-name").Value() = %q, want ""`, s)
140 name.Set("Mike")
141 if s, want := name.String(), `"Mike"`; s != want {
142 t.Errorf(`after name.Set("Mike"), name.String() = %q, want %q`, s, want)
144 if s, want := name.Value(), "Mike"; s != want {
145 t.Errorf(`after name.Set("Mike"), name.Value() = %q, want %q`, s, want)
148 // Make sure we produce safe JSON output.
149 name.Set("<")
150 if s, want := name.String(), "\"\\u003c\""; s != want {
151 t.Errorf(`after name.Set("<"), name.String() = %q, want %q`, s, want)
155 func BenchmarkStringSet(b *testing.B) {
156 var s String
158 b.RunParallel(func(pb *testing.PB) {
159 for pb.Next() {
160 s.Set("red")
165 func TestMapInit(t *testing.T) {
166 RemoveAll()
167 colors := NewMap("bike-shed-colors")
168 colors.Add("red", 1)
169 colors.Add("blue", 1)
170 colors.Add("chartreuse", 1)
172 n := 0
173 colors.Do(func(KeyValue) { n++ })
174 if n != 3 {
175 t.Errorf("after three Add calls with distinct keys, Do should invoke f 3 times; got %v", n)
178 colors.Init()
180 n = 0
181 colors.Do(func(KeyValue) { n++ })
182 if n != 0 {
183 t.Errorf("after Init, Do should invoke f 0 times; got %v", n)
187 func TestMapDelete(t *testing.T) {
188 RemoveAll()
189 colors := NewMap("bike-shed-colors")
191 colors.Add("red", 1)
192 colors.Add("red", 2)
193 colors.Add("blue", 4)
195 n := 0
196 colors.Do(func(KeyValue) { n++ })
197 if n != 2 {
198 t.Errorf("after two Add calls with distinct keys, Do should invoke f 2 times; got %v", n)
201 colors.Delete("red")
202 n = 0
203 colors.Do(func(KeyValue) { n++ })
204 if n != 1 {
205 t.Errorf("removed red, Do should invoke f 1 times; got %v", n)
208 colors.Delete("notfound")
209 n = 0
210 colors.Do(func(KeyValue) { n++ })
211 if n != 1 {
212 t.Errorf("attempted to remove notfound, Do should invoke f 1 times; got %v", n)
215 colors.Delete("blue")
216 colors.Delete("blue")
217 n = 0
218 colors.Do(func(KeyValue) { n++ })
219 if n != 0 {
220 t.Errorf("all keys removed, Do should invoke f 0 times; got %v", n)
224 func TestMapCounter(t *testing.T) {
225 RemoveAll()
226 colors := NewMap("bike-shed-colors")
228 colors.Add("red", 1)
229 colors.Add("red", 2)
230 colors.Add("blue", 4)
231 colors.AddFloat(`green "midori"`, 4.125)
232 if x := colors.Get("red").(*Int).Value(); x != 3 {
233 t.Errorf("colors.m[\"red\"] = %v, want 3", x)
235 if x := colors.Get("blue").(*Int).Value(); x != 4 {
236 t.Errorf("colors.m[\"blue\"] = %v, want 4", x)
238 if x := colors.Get(`green "midori"`).(*Float).Value(); x != 4.125 {
239 t.Errorf("colors.m[`green \"midori\"] = %v, want 4.125", x)
242 // colors.String() should be '{"red":3, "blue":4}',
243 // though the order of red and blue could vary.
244 s := colors.String()
245 var j any
246 err := json.Unmarshal([]byte(s), &j)
247 if err != nil {
248 t.Errorf("colors.String() isn't valid JSON: %v", err)
250 m, ok := j.(map[string]any)
251 if !ok {
252 t.Error("colors.String() didn't produce a map.")
254 red := m["red"]
255 x, ok := red.(float64)
256 if !ok {
257 t.Error("red.Kind() is not a number.")
259 if x != 3 {
260 t.Errorf("red = %v, want 3", x)
264 func BenchmarkMapSet(b *testing.B) {
265 m := new(Map).Init()
267 v := new(Int)
269 b.RunParallel(func(pb *testing.PB) {
270 for pb.Next() {
271 m.Set("red", v)
276 func BenchmarkMapSetDifferent(b *testing.B) {
277 procKeys := make([][]string, runtime.GOMAXPROCS(0))
278 for i := range procKeys {
279 keys := make([]string, 4)
280 for j := range keys {
281 keys[j] = fmt.Sprint(i, j)
283 procKeys[i] = keys
286 m := new(Map).Init()
287 v := new(Int)
288 b.ResetTimer()
290 var n int32
291 b.RunParallel(func(pb *testing.PB) {
292 i := int(atomic.AddInt32(&n, 1)-1) % len(procKeys)
293 keys := procKeys[i]
295 for pb.Next() {
296 for _, k := range keys {
297 m.Set(k, v)
303 // BenchmarkMapSetDifferentRandom simulates such a case where the concerned
304 // keys of Map.Set are generated dynamically and as a result insertion is
305 // out of order and the number of the keys may be large.
306 func BenchmarkMapSetDifferentRandom(b *testing.B) {
307 keys := make([]string, 100)
308 for i := range keys {
309 keys[i] = fmt.Sprintf("%x", sha1.Sum([]byte(fmt.Sprint(i))))
312 v := new(Int)
313 b.ResetTimer()
315 for i := 0; i < b.N; i++ {
316 m := new(Map).Init()
317 for _, k := range keys {
318 m.Set(k, v)
323 func BenchmarkMapSetString(b *testing.B) {
324 m := new(Map).Init()
326 v := new(String)
327 v.Set("Hello, ï €!")
329 b.RunParallel(func(pb *testing.PB) {
330 for pb.Next() {
331 m.Set("red", v)
336 func BenchmarkMapAddSame(b *testing.B) {
337 b.RunParallel(func(pb *testing.PB) {
338 for pb.Next() {
339 m := new(Map).Init()
340 m.Add("red", 1)
341 m.Add("red", 1)
342 m.Add("red", 1)
343 m.Add("red", 1)
348 func BenchmarkMapAddDifferent(b *testing.B) {
349 procKeys := make([][]string, runtime.GOMAXPROCS(0))
350 for i := range procKeys {
351 keys := make([]string, 4)
352 for j := range keys {
353 keys[j] = fmt.Sprint(i, j)
355 procKeys[i] = keys
358 b.ResetTimer()
360 var n int32
361 b.RunParallel(func(pb *testing.PB) {
362 i := int(atomic.AddInt32(&n, 1)-1) % len(procKeys)
363 keys := procKeys[i]
365 for pb.Next() {
366 m := new(Map).Init()
367 for _, k := range keys {
368 m.Add(k, 1)
374 // BenchmarkMapAddDifferentRandom simulates such a case where that the concerned
375 // keys of Map.Add are generated dynamically and as a result insertion is out of
376 // order and the number of the keys may be large.
377 func BenchmarkMapAddDifferentRandom(b *testing.B) {
378 keys := make([]string, 100)
379 for i := range keys {
380 keys[i] = fmt.Sprintf("%x", sha1.Sum([]byte(fmt.Sprint(i))))
383 b.ResetTimer()
385 for i := 0; i < b.N; i++ {
386 m := new(Map).Init()
387 for _, k := range keys {
388 m.Add(k, 1)
393 func BenchmarkMapAddSameSteadyState(b *testing.B) {
394 m := new(Map).Init()
395 b.RunParallel(func(pb *testing.PB) {
396 for pb.Next() {
397 m.Add("red", 1)
402 func BenchmarkMapAddDifferentSteadyState(b *testing.B) {
403 procKeys := make([][]string, runtime.GOMAXPROCS(0))
404 for i := range procKeys {
405 keys := make([]string, 4)
406 for j := range keys {
407 keys[j] = fmt.Sprint(i, j)
409 procKeys[i] = keys
412 m := new(Map).Init()
413 b.ResetTimer()
415 var n int32
416 b.RunParallel(func(pb *testing.PB) {
417 i := int(atomic.AddInt32(&n, 1)-1) % len(procKeys)
418 keys := procKeys[i]
420 for pb.Next() {
421 for _, k := range keys {
422 m.Add(k, 1)
428 func TestFunc(t *testing.T) {
429 RemoveAll()
430 var x any = []string{"a", "b"}
431 f := Func(func() any { return x })
432 if s, exp := f.String(), `["a","b"]`; s != exp {
433 t.Errorf(`f.String() = %q, want %q`, s, exp)
435 if v := f.Value(); !reflect.DeepEqual(v, x) {
436 t.Errorf(`f.Value() = %q, want %q`, v, x)
439 x = 17
440 if s, exp := f.String(), `17`; s != exp {
441 t.Errorf(`f.String() = %q, want %q`, s, exp)
445 func TestHandler(t *testing.T) {
446 RemoveAll()
447 m := NewMap("map1")
448 m.Add("a", 1)
449 m.Add("z", 2)
450 m2 := NewMap("map2")
451 for i := 0; i < 9; i++ {
452 m2.Add(strconv.Itoa(i), int64(i))
454 rr := httptest.NewRecorder()
455 rr.Body = new(bytes.Buffer)
456 expvarHandler(rr, nil)
457 want := `{
458 "map1": {"a": 1, "z": 2},
459 "map2": {"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8}
462 if got := rr.Body.String(); got != want {
463 t.Errorf("HTTP handler wrote:\n%s\nWant:\n%s", got, want)
467 func BenchmarkRealworldExpvarUsage(b *testing.B) {
468 var (
469 bytesSent Int
470 bytesRead Int
473 // The benchmark creates GOMAXPROCS client/server pairs.
474 // Each pair creates 4 goroutines: client reader/writer and server reader/writer.
475 // The benchmark stresses concurrent reading and writing to the same connection.
476 // Such pattern is used in net/http and net/rpc.
478 b.StopTimer()
480 P := runtime.GOMAXPROCS(0)
481 N := b.N / P
482 W := 1000
484 // Setup P client/server connections.
485 clients := make([]net.Conn, P)
486 servers := make([]net.Conn, P)
487 ln, err := net.Listen("tcp", "127.0.0.1:0")
488 if err != nil {
489 b.Fatalf("Listen failed: %v", err)
491 defer ln.Close()
492 done := make(chan bool, 1)
493 go func() {
494 for p := 0; p < P; p++ {
495 s, err := ln.Accept()
496 if err != nil {
497 b.Errorf("Accept failed: %v", err)
498 done <- false
499 return
501 servers[p] = s
503 done <- true
505 for p := 0; p < P; p++ {
506 c, err := net.Dial("tcp", ln.Addr().String())
507 if err != nil {
508 <-done
509 b.Fatalf("Dial failed: %v", err)
511 clients[p] = c
513 if !<-done {
514 b.FailNow()
517 b.StartTimer()
519 var wg sync.WaitGroup
520 wg.Add(4 * P)
521 for p := 0; p < P; p++ {
522 // Client writer.
523 go func(c net.Conn) {
524 defer wg.Done()
525 var buf [1]byte
526 for i := 0; i < N; i++ {
527 v := byte(i)
528 for w := 0; w < W; w++ {
529 v *= v
531 buf[0] = v
532 n, err := c.Write(buf[:])
533 if err != nil {
534 b.Errorf("Write failed: %v", err)
535 return
538 bytesSent.Add(int64(n))
540 }(clients[p])
542 // Pipe between server reader and server writer.
543 pipe := make(chan byte, 128)
545 // Server reader.
546 go func(s net.Conn) {
547 defer wg.Done()
548 var buf [1]byte
549 for i := 0; i < N; i++ {
550 n, err := s.Read(buf[:])
552 if err != nil {
553 b.Errorf("Read failed: %v", err)
554 return
557 bytesRead.Add(int64(n))
558 pipe <- buf[0]
560 }(servers[p])
562 // Server writer.
563 go func(s net.Conn) {
564 defer wg.Done()
565 var buf [1]byte
566 for i := 0; i < N; i++ {
567 v := <-pipe
568 for w := 0; w < W; w++ {
569 v *= v
571 buf[0] = v
572 n, err := s.Write(buf[:])
573 if err != nil {
574 b.Errorf("Write failed: %v", err)
575 return
578 bytesSent.Add(int64(n))
580 s.Close()
581 }(servers[p])
583 // Client reader.
584 go func(c net.Conn) {
585 defer wg.Done()
586 var buf [1]byte
587 for i := 0; i < N; i++ {
588 n, err := c.Read(buf[:])
590 if err != nil {
591 b.Errorf("Read failed: %v", err)
592 return
595 bytesRead.Add(int64(n))
597 c.Close()
598 }(clients[p])
600 wg.Wait()