1// Copyright 2017 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
5package pprof
6
7import (
8	"context"
9	"reflect"
10	"sort"
11	"testing"
12)
13
14func labelsSorted(ctx context.Context) []label {
15	ls := []label{}
16	ForLabels(ctx, func(key, value string) bool {
17		ls = append(ls, label{key, value})
18		return true
19	})
20	sort.Sort(labelSorter(ls))
21	return ls
22}
23
24type labelSorter []label
25
26func (s labelSorter) Len() int           { return len(s) }
27func (s labelSorter) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
28func (s labelSorter) Less(i, j int) bool { return s[i].key < s[j].key }
29
30func TestContextLabels(t *testing.T) {
31	// Background context starts with no labels.
32	ctx := context.Background()
33	labels := labelsSorted(ctx)
34	if len(labels) != 0 {
35		t.Errorf("labels on background context: want [], got %v ", labels)
36	}
37
38	// Add a single label.
39	ctx = WithLabels(ctx, Labels("key", "value"))
40	// Retrieve it with Label.
41	v, ok := Label(ctx, "key")
42	if !ok || v != "value" {
43		t.Errorf(`Label(ctx, "key"): got %v, %v; want "value", ok`, v, ok)
44	}
45	gotLabels := labelsSorted(ctx)
46	wantLabels := []label{{"key", "value"}}
47	if !reflect.DeepEqual(gotLabels, wantLabels) {
48		t.Errorf("(sorted) labels on context: got %v, want %v", gotLabels, wantLabels)
49	}
50
51	// Add a label with a different key.
52	ctx = WithLabels(ctx, Labels("key2", "value2"))
53	v, ok = Label(ctx, "key2")
54	if !ok || v != "value2" {
55		t.Errorf(`Label(ctx, "key2"): got %v, %v; want "value2", ok`, v, ok)
56	}
57	gotLabels = labelsSorted(ctx)
58	wantLabels = []label{{"key", "value"}, {"key2", "value2"}}
59	if !reflect.DeepEqual(gotLabels, wantLabels) {
60		t.Errorf("(sorted) labels on context: got %v, want %v", gotLabels, wantLabels)
61	}
62
63	// Add label with first key to test label replacement.
64	ctx = WithLabels(ctx, Labels("key", "value3"))
65	v, ok = Label(ctx, "key")
66	if !ok || v != "value3" {
67		t.Errorf(`Label(ctx, "key3"): got %v, %v; want "value3", ok`, v, ok)
68	}
69	gotLabels = labelsSorted(ctx)
70	wantLabels = []label{{"key", "value3"}, {"key2", "value2"}}
71	if !reflect.DeepEqual(gotLabels, wantLabels) {
72		t.Errorf("(sorted) labels on context: got %v, want %v", gotLabels, wantLabels)
73	}
74
75	// Labels called with two labels with the same key should pick the second.
76	ctx = WithLabels(ctx, Labels("key4", "value4a", "key4", "value4b"))
77	v, ok = Label(ctx, "key4")
78	if !ok || v != "value4b" {
79		t.Errorf(`Label(ctx, "key4"): got %v, %v; want "value4b", ok`, v, ok)
80	}
81	gotLabels = labelsSorted(ctx)
82	wantLabels = []label{{"key", "value3"}, {"key2", "value2"}, {"key4", "value4b"}}
83	if !reflect.DeepEqual(gotLabels, wantLabels) {
84		t.Errorf("(sorted) labels on context: got %v, want %v", gotLabels, wantLabels)
85	}
86}
87
88func TestLabelMapStringer(t *testing.T) {
89	for _, tbl := range []struct {
90		m        labelMap
91		expected string
92	}{
93		{
94			m: labelMap{
95				// empty map
96			},
97			expected: "{}",
98		}, {
99			m: labelMap{
100				"foo": "bar",
101			},
102			expected: `{"foo":"bar"}`,
103		}, {
104			m: labelMap{
105				"foo":             "bar",
106				"key1":            "value1",
107				"key2":            "value2",
108				"key3":            "value3",
109				"key4WithNewline": "\nvalue4",
110			},
111			expected: `{"foo":"bar", "key1":"value1", "key2":"value2", "key3":"value3", "key4WithNewline":"\nvalue4"}`,
112		},
113	} {
114		if got := tbl.m.String(); tbl.expected != got {
115			t.Errorf("%#v.String() = %q; want %q", tbl.m, got, tbl.expected)
116		}
117	}
118}
119