2016-08-05 Vladimir Makarov <vmakarov@redhat.com>
[official-gcc.git] / libgo / go / expvar / expvar_test.go
blob7b1c9dfc4f872476b5ee7dfb76d909dc26172c53
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 "encoding/json"
10 "math"
11 "net"
12 "net/http/httptest"
13 "runtime"
14 "strconv"
15 "sync"
16 "sync/atomic"
17 "testing"
20 // RemoveAll removes all exported variables.
21 // This is for tests only.
22 func RemoveAll() {
23 mutex.Lock()
24 defer mutex.Unlock()
25 vars = make(map[string]Var)
26 varKeys = nil
29 func TestNil(t *testing.T) {
30 RemoveAll()
31 val := Get("missing")
32 if val != nil {
33 t.Errorf("got %v, want nil", val)
37 func TestInt(t *testing.T) {
38 RemoveAll()
39 reqs := NewInt("requests")
40 if reqs.i != 0 {
41 t.Errorf("reqs.i = %v, want 0", reqs.i)
43 if reqs != Get("requests").(*Int) {
44 t.Errorf("Get() failed.")
47 reqs.Add(1)
48 reqs.Add(3)
49 if reqs.i != 4 {
50 t.Errorf("reqs.i = %v, want 4", reqs.i)
53 if s := reqs.String(); s != "4" {
54 t.Errorf("reqs.String() = %q, want \"4\"", s)
57 reqs.Set(-2)
58 if reqs.i != -2 {
59 t.Errorf("reqs.i = %v, want -2", reqs.i)
63 func BenchmarkIntAdd(b *testing.B) {
64 var v Int
66 b.RunParallel(func(pb *testing.PB) {
67 for pb.Next() {
68 v.Add(1)
73 func BenchmarkIntSet(b *testing.B) {
74 var v Int
76 b.RunParallel(func(pb *testing.PB) {
77 for pb.Next() {
78 v.Set(1)
83 func (v *Float) val() float64 {
84 return math.Float64frombits(atomic.LoadUint64(&v.f))
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.val(); v != 2.75 {
100 t.Errorf("reqs.val() = %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.val(); v != 0.75 {
109 t.Errorf("reqs.val() = %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 name.s != "" {
137 t.Errorf("name.s = %q, want \"\"", name.s)
140 name.Set("Mike")
141 if name.s != "Mike" {
142 t.Errorf("name.s = %q, want \"Mike\"", name.s)
145 if s, want := name.String(), `"Mike"`; s != want {
146 t.Errorf("from %q, name.String() = %q, want %q", name.s, s, want)
149 // Make sure we produce safe JSON output.
150 name.Set(`<`)
151 if s, want := name.String(), "\"\\u003c\""; s != want {
152 t.Errorf("from %q, name.String() = %q, want %q", name.s, s, want)
156 func BenchmarkStringSet(b *testing.B) {
157 var s String
159 b.RunParallel(func(pb *testing.PB) {
160 for pb.Next() {
161 s.Set("red")
166 func TestMapCounter(t *testing.T) {
167 RemoveAll()
168 colors := NewMap("bike-shed-colors")
170 colors.Add("red", 1)
171 colors.Add("red", 2)
172 colors.Add("blue", 4)
173 colors.AddFloat(`green "midori"`, 4.125)
174 if x := colors.m["red"].(*Int).i; x != 3 {
175 t.Errorf("colors.m[\"red\"] = %v, want 3", x)
177 if x := colors.m["blue"].(*Int).i; x != 4 {
178 t.Errorf("colors.m[\"blue\"] = %v, want 4", x)
180 if x := colors.m[`green "midori"`].(*Float).val(); x != 4.125 {
181 t.Errorf("colors.m[`green \"midori\"] = %v, want 4.125", x)
184 // colors.String() should be '{"red":3, "blue":4}',
185 // though the order of red and blue could vary.
186 s := colors.String()
187 var j interface{}
188 err := json.Unmarshal([]byte(s), &j)
189 if err != nil {
190 t.Errorf("colors.String() isn't valid JSON: %v", err)
192 m, ok := j.(map[string]interface{})
193 if !ok {
194 t.Error("colors.String() didn't produce a map.")
196 red := m["red"]
197 x, ok := red.(float64)
198 if !ok {
199 t.Error("red.Kind() is not a number.")
201 if x != 3 {
202 t.Errorf("red = %v, want 3", x)
206 func BenchmarkMapSet(b *testing.B) {
207 m := new(Map).Init()
209 v := new(Int)
211 b.RunParallel(func(pb *testing.PB) {
212 for pb.Next() {
213 m.Set("red", v)
218 func BenchmarkMapAddSame(b *testing.B) {
219 for i := 0; i < b.N; i++ {
220 m := new(Map).Init()
221 m.Add("red", 1)
222 m.Add("red", 1)
223 m.Add("red", 1)
224 m.Add("red", 1)
228 func BenchmarkMapAddDifferent(b *testing.B) {
229 for i := 0; i < b.N; i++ {
230 m := new(Map).Init()
231 m.Add("red", 1)
232 m.Add("blue", 1)
233 m.Add("green", 1)
234 m.Add("yellow", 1)
238 func TestFunc(t *testing.T) {
239 RemoveAll()
240 var x interface{} = []string{"a", "b"}
241 f := Func(func() interface{} { return x })
242 if s, exp := f.String(), `["a","b"]`; s != exp {
243 t.Errorf(`f.String() = %q, want %q`, s, exp)
246 x = 17
247 if s, exp := f.String(), `17`; s != exp {
248 t.Errorf(`f.String() = %q, want %q`, s, exp)
252 func TestHandler(t *testing.T) {
253 RemoveAll()
254 m := NewMap("map1")
255 m.Add("a", 1)
256 m.Add("z", 2)
257 m2 := NewMap("map2")
258 for i := 0; i < 9; i++ {
259 m2.Add(strconv.Itoa(i), int64(i))
261 rr := httptest.NewRecorder()
262 rr.Body = new(bytes.Buffer)
263 expvarHandler(rr, nil)
264 want := `{
265 "map1": {"a": 1, "z": 2},
266 "map2": {"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8}
269 if got := rr.Body.String(); got != want {
270 t.Errorf("HTTP handler wrote:\n%s\nWant:\n%s", got, want)
274 func BenchmarkRealworldExpvarUsage(b *testing.B) {
275 var (
276 bytesSent Int
277 bytesRead Int
280 // The benchmark creates GOMAXPROCS client/server pairs.
281 // Each pair creates 4 goroutines: client reader/writer and server reader/writer.
282 // The benchmark stresses concurrent reading and writing to the same connection.
283 // Such pattern is used in net/http and net/rpc.
285 b.StopTimer()
287 P := runtime.GOMAXPROCS(0)
288 N := b.N / P
289 W := 1000
291 // Setup P client/server connections.
292 clients := make([]net.Conn, P)
293 servers := make([]net.Conn, P)
294 ln, err := net.Listen("tcp", "127.0.0.1:0")
295 if err != nil {
296 b.Fatalf("Listen failed: %v", err)
298 defer ln.Close()
299 done := make(chan bool)
300 go func() {
301 for p := 0; p < P; p++ {
302 s, err := ln.Accept()
303 if err != nil {
304 b.Errorf("Accept failed: %v", err)
305 return
307 servers[p] = s
309 done <- true
311 for p := 0; p < P; p++ {
312 c, err := net.Dial("tcp", ln.Addr().String())
313 if err != nil {
314 b.Fatalf("Dial failed: %v", err)
316 clients[p] = c
318 <-done
320 b.StartTimer()
322 var wg sync.WaitGroup
323 wg.Add(4 * P)
324 for p := 0; p < P; p++ {
325 // Client writer.
326 go func(c net.Conn) {
327 defer wg.Done()
328 var buf [1]byte
329 for i := 0; i < N; i++ {
330 v := byte(i)
331 for w := 0; w < W; w++ {
332 v *= v
334 buf[0] = v
335 n, err := c.Write(buf[:])
336 if err != nil {
337 b.Errorf("Write failed: %v", err)
338 return
341 bytesSent.Add(int64(n))
343 }(clients[p])
345 // Pipe between server reader and server writer.
346 pipe := make(chan byte, 128)
348 // Server reader.
349 go func(s net.Conn) {
350 defer wg.Done()
351 var buf [1]byte
352 for i := 0; i < N; i++ {
353 n, err := s.Read(buf[:])
355 if err != nil {
356 b.Errorf("Read failed: %v", err)
357 return
360 bytesRead.Add(int64(n))
361 pipe <- buf[0]
363 }(servers[p])
365 // Server writer.
366 go func(s net.Conn) {
367 defer wg.Done()
368 var buf [1]byte
369 for i := 0; i < N; i++ {
370 v := <-pipe
371 for w := 0; w < W; w++ {
372 v *= v
374 buf[0] = v
375 n, err := s.Write(buf[:])
376 if err != nil {
377 b.Errorf("Write failed: %v", err)
378 return
381 bytesSent.Add(int64(n))
383 s.Close()
384 }(servers[p])
386 // Client reader.
387 go func(c net.Conn) {
388 defer wg.Done()
389 var buf [1]byte
390 for i := 0; i < N; i++ {
391 n, err := c.Read(buf[:])
393 if err != nil {
394 b.Errorf("Read failed: %v", err)
395 return
398 bytesRead.Add(int64(n))
400 c.Close()
401 }(clients[p])
403 wg.Wait()