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  }