...

Source file src/edge-infra.dev/pkg/lib/fog/fog_test.go

Documentation: edge-infra.dev/pkg/lib/fog

     1  package fog
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"strings"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/go-logr/logr"
    11  	"github.com/stretchr/testify/assert"
    12  )
    13  
    14  // Test improperUsage WithLabels: expect failure via odd number of inputs
    15  // Test Proper usage of WithLabels: single pair & multiple pairs
    16  func TestWithLabels(t *testing.T) {
    17  	l := New(setDevelopment())
    18  	assert.Panics(t, func() { WithLabels(l, "testBadPair") })
    19  
    20  	type testCase struct {
    21  		message        string
    22  		labelPairs     []string
    23  		keys           []string
    24  		expectedValues []string
    25  	}
    26  
    27  	tests := []testCase{
    28  		{
    29  			message:        "test proper pair",
    30  			labelPairs:     []string{"testKey", "testValue"},
    31  			keys:           []string{"testKey"},
    32  			expectedValues: []string{"testValue"},
    33  		},
    34  		{
    35  			message:        "test multiple pairs",
    36  			labelPairs:     []string{"key", "value", "testKey2", "testValue2"},
    37  			keys:           []string{"key", "testKey2"},
    38  			expectedValues: []string{"value", "testValue2"},
    39  		},
    40  	}
    41  
    42  	for _, tt := range tests {
    43  		buf := new(bytes.Buffer)
    44  		l := New(To(buf))
    45  		l = WithLabels(l, tt.labelPairs...)
    46  		l.Info(tt.message)
    47  
    48  		var out map[string]interface{}
    49  		if err := json.Unmarshal(buf.Bytes(), &out); err != nil {
    50  			t.Fatal(err)
    51  		}
    52  
    53  		labels, _ := out[labelsKey].(map[string]interface{})
    54  		for i, k := range tt.keys {
    55  			assert.Equal(t, tt.expectedValues[i], labels[k])
    56  		}
    57  	}
    58  }
    59  
    60  func TestInfo(t *testing.T) {
    61  	t.Parallel()
    62  
    63  	type testCase struct {
    64  		msg     string
    65  		names   []string
    66  		kv      []any                             // inline logging context key/value pairs
    67  		withKV  []any                             // context key/value pairs
    68  		wrapper func(logr.Logger, string, ...any) // logging wrapper
    69  	}
    70  
    71  	testCases := map[string]testCase{
    72  		"simple": {
    73  			msg: "simple log",
    74  		},
    75  		"inline simple kv": {
    76  			msg: "look at my values",
    77  			kv:  []any{"foo", "bar", "pods", 2},
    78  		},
    79  		"with simple kv": {
    80  			msg: "look at my values that i didnt set on the message 8-)",
    81  			kv:  []any{"foo", "bar", "pods", 2},
    82  		},
    83  		"single name": {
    84  			msg:   "ive got a name",
    85  			kv:    []any{"foo", "bar"},
    86  			names: []string{"single"},
    87  		},
    88  		"single name with kv": {
    89  			msg:    "ive got a name",
    90  			withKV: []any{"foo", "bar"},
    91  			names:  []string{"single-with-style"},
    92  		},
    93  		"multiple names": {
    94  			msg:   "ive got a name",
    95  			kv:    []any{"foo", "bar"},
    96  			names: []string{"single", "joiner", "tony"},
    97  		},
    98  		"multiple names with kv": {
    99  			msg:    "ive got a name",
   100  			withKV: []any{"foo", "bar"},
   101  			names:  []string{"single", "joiner", "tony"},
   102  		},
   103  		// TODO: more complex KV pairs
   104  		// TODO: panic
   105  		// TODO: wrapper (call depth is correct?)
   106  	}
   107  
   108  	test := func(t *testing.T, data testCase) {
   109  		t.Helper()
   110  
   111  		buf := new(bytes.Buffer)
   112  		l := New(To(buf))
   113  
   114  		for _, n := range data.names {
   115  			l = l.WithName(n)
   116  		}
   117  
   118  		if len(data.withKV) > 0 {
   119  			l = l.WithValues(data.withKV...)
   120  		}
   121  
   122  		if data.wrapper != nil {
   123  			data.wrapper(l, data.msg, data.kv...)
   124  		} else {
   125  			l.Info(data.msg, data.kv...)
   126  		}
   127  		// Parse log message object
   128  		out := make(map[string]any)
   129  		assert.NoError(t, json.Unmarshal(buf.Bytes(), &out))
   130  
   131  		// Verify logger name field
   132  		switch len(data.names) {
   133  		case 0:
   134  			assert.NotContains(t, out, "logger",
   135  				"'logger' field should not be present for unnamed loggers")
   136  		case 1:
   137  			assert.Contains(t, out, "logger",
   138  				"'logger' field should be present for named loggers")
   139  			assert.Equal(t, data.names[0], out["logger"])
   140  		default:
   141  			assert.Contains(t, out, "logger",
   142  				"'logger' field should be present for named loggers")
   143  			assert.Equal(t, strings.Join(data.names, "."), out["logger"],
   144  				"'logger' field should be joined by periods for multiple names")
   145  		}
   146  
   147  		// Verify logger source location
   148  		// TODO: should verify that src info is well formed (line is number, etc)
   149  		assert.Contains(t, out, SourceKey)
   150  		assert.Contains(t, out[SourceKey], "function")
   151  		assert.Contains(t, out[SourceKey], "file")
   152  		assert.Contains(t, out[SourceKey], "line")
   153  
   154  		// Verify logger timestamp
   155  		_, err := time.Parse(time.RFC3339, out["time"].(string))
   156  		assert.NoError(t, err, "failed to parse 'time' from log into RFC3339 format")
   157  
   158  		// Verify logger values
   159  		// TODO: verify more complex values (fmt.Stringer, logr.Marshaler, structs, maps, arrays, yada yada)
   160  		// TODO: verify non-string key behavior
   161  		args := append(data.kv, data.withKV...)
   162  		for i := 0; i < len(args); {
   163  			key, val := args[i], args[i+1]
   164  			t.Logf("key %s type: %T", key, val)
   165  			assert.Contains(t, out, key)
   166  			assert.EqualValues(t, val, out[key.(string)])
   167  			i += 2
   168  		}
   169  	}
   170  
   171  	for name, tc := range testCases {
   172  		tc := tc
   173  		t.Run(name, func(t *testing.T) {
   174  			t.Parallel()
   175  			test(t, tc)
   176  		})
   177  	}
   178  }
   179  

View as plain text