go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/common/logging/fields_test.go (about) 1 // Copyright 2015 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package logging 16 17 import ( 18 "context" 19 "errors" 20 "fmt" 21 "sort" 22 "testing" 23 24 . "github.com/smartystreets/goconvey/convey" 25 ) 26 27 type stringStruct struct { 28 Value string 29 } 30 31 var _ fmt.Stringer = (*stringStruct)(nil) 32 33 func (s *stringStruct) String() string { 34 return s.Value 35 } 36 37 // TestFieldEntry tests methods associated with the FieldEntry and 38 // fieldEntrySlice types. 39 func TestFieldEntry(t *testing.T) { 40 Convey(`A FieldEntry instance: "value" => "\"Hello, World!\""`, t, func() { 41 fe := FieldEntry{"value", `"Hello, World!"`} 42 43 Convey(`Has a String() value, "value":"\"Hello, World!\"".`, func() { 44 So(fe.String(), ShouldEqual, `"value":"\"Hello, World!\""`) 45 }) 46 }) 47 48 Convey(`A FieldEntry instance: "value" => 42`, t, func() { 49 fe := FieldEntry{"value", 42} 50 51 Convey(`Has a String() value, "value":"42".`, func() { 52 So(fe.String(), ShouldEqual, `"value":42`) 53 }) 54 }) 55 56 Convey(`A FieldEntry instance: "value" => stringStruct{"My \"value\""}`, t, func() { 57 fe := FieldEntry{"value", &stringStruct{`My "value"`}} 58 59 Convey(`Has a String() value, "value":"My \"value\"".`, func() { 60 So(fe.String(), ShouldEqual, `"value":"My \"value\""`) 61 }) 62 }) 63 64 Convey(`A FieldEntry instance: "value" => error{"There was a \"failure\"}`, t, func() { 65 fe := FieldEntry{"value", errors.New(`There was a "failure"`)} 66 67 Convey(`Has a String() value, "value":"There was a \"failure\"".`, func() { 68 So(fe.String(), ShouldEqual, `"value":"There was a \"failure\""`) 69 }) 70 }) 71 72 Convey(`A FieldEntry instance: "value" => struct{a: "Hello!", b: 42}`, t, func() { 73 type myStruct struct { 74 a string 75 b int 76 } 77 fe := FieldEntry{"value", &myStruct{"Hello!", 42}} 78 79 Convey(`Has a String() value, "value":myStruct { a: "Hello!", b: 42 }".`, func() { 80 So(fe.String(), ShouldEqual, `"value":&logging.myStruct{a:"Hello!", b:42}`) 81 }) 82 }) 83 84 Convey(`A fieldEntrySlice: {foo/bar, error/z, asdf/baz}`, t, func() { 85 fes := fieldEntrySlice{ 86 &FieldEntry{"foo", "bar"}, 87 &FieldEntry{ErrorKey, errors.New("z")}, 88 &FieldEntry{"asdf", "baz"}, 89 } 90 91 Convey(`Should be sorted: [error, asdf, foo].`, func() { 92 sorted := make(fieldEntrySlice, len(fes)) 93 copy(sorted, fes) 94 sort.Sort(sorted) 95 96 So(sorted, ShouldResemble, fieldEntrySlice{fes[1], fes[2], fes[0]}) 97 }) 98 }) 99 } 100 101 func TestFields(t *testing.T) { 102 Convey(`A nil Fields`, t, func() { 103 fm := Fields(nil) 104 105 Convey(`Returns nil when Copied with an empty Fields.`, func() { 106 So(fm.Copy(Fields{}), ShouldBeNil) 107 }) 108 109 Convey(`Returns a populated Fields when Copied with a populated Fields.`, func() { 110 other := Fields{ 111 "foo": "bar", 112 "baz": "qux", 113 } 114 So(fm.Copy(other), ShouldResemble, Fields{"foo": "bar", "baz": "qux"}) 115 }) 116 117 Convey(`Returns the populated Fields when Copied with a populated Fields.`, func() { 118 other := Fields{ 119 "foo": "bar", 120 "baz": "qux", 121 } 122 So(fm.Copy(other), ShouldResemble, other) 123 }) 124 }) 125 126 Convey(`A populated Fields`, t, func() { 127 fm := NewFields(map[string]any{ 128 "foo": "bar", 129 "baz": "qux", 130 }) 131 So(fm, ShouldHaveSameTypeAs, Fields(nil)) 132 133 Convey(`Returns an augmented Fields when Copied with a populated Fields.`, func() { 134 other := Fields{ 135 ErrorKey: errors.New("err"), 136 } 137 So(fm.Copy(other), ShouldResemble, Fields{"foo": "bar", "baz": "qux", ErrorKey: errors.New("err")}) 138 }) 139 140 Convey(`Has a String representation: {"baz":"qux", "foo":"bar"}`, func() { 141 So(fm.String(), ShouldEqual, `{"baz":"qux", "foo":"bar"}`) 142 }) 143 }) 144 } 145 146 func TestContextFields(t *testing.T) { 147 Convey(`An empty Context`, t, func() { 148 c := context.Background() 149 150 Convey(`Has no Fields.`, func() { 151 So(GetFields(c), ShouldBeNil) 152 }) 153 154 Convey(`Sets {"foo": "bar", "baz": "qux"}`, func() { 155 c = SetFields(c, Fields{ 156 "foo": "bar", 157 "baz": "qux", 158 }) 159 So(GetFields(c), ShouldResemble, Fields{ 160 "foo": "bar", 161 "baz": "qux", 162 }) 163 164 Convey(`Is overridden by: {"foo": "override", "error": "failure"}`, func() { 165 c = SetFields(c, Fields{ 166 "foo": "override", 167 "error": errors.New("failure"), 168 }) 169 170 So(GetFields(c), ShouldResemble, Fields{ 171 "foo": "override", 172 "baz": "qux", 173 "error": errors.New("failure"), 174 }) 175 }) 176 }) 177 }) 178 }