github.com/ethersphere/bee/v2@v2.2.0/pkg/api/logger_test.go (about) 1 // Copyright 2022 The Swarm 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 5 package api_test 6 7 import ( 8 "encoding/base64" 9 "encoding/json" 10 "fmt" 11 "net/http" 12 "testing" 13 14 "github.com/ethersphere/bee/v2/pkg/api" 15 "github.com/ethersphere/bee/v2/pkg/jsonhttp" 16 "github.com/ethersphere/bee/v2/pkg/jsonhttp/jsonhttptest" 17 "github.com/ethersphere/bee/v2/pkg/log" 18 "github.com/google/go-cmp/cmp" 19 ) 20 21 // nolint:paralleltest 22 func TestGetLoggers(t *testing.T) { 23 defer func(fn api.LogRegistryIterateFn) { 24 api.ReplaceLogRegistryIterateFn(fn) 25 }(api.LogRegistryIterate) 26 27 fn := func(fn func(id, path string, verbosity log.Level, v uint) bool) { 28 data := []struct { 29 id string 30 path string 31 verbosity log.Level 32 v uint 33 }{{ 34 id: `one[0][]>>824634860360`, 35 path: "one", 36 verbosity: log.VerbosityAll, 37 v: 0, 38 }, { 39 id: `one/name[0][]>>824634860360`, 40 path: "one/name", 41 verbosity: log.VerbosityWarning, 42 v: 0, 43 }, { 44 id: `one/name[0][\"val\"=1]>>824634860360`, 45 path: "one/name", 46 verbosity: log.VerbosityWarning, 47 v: 0, 48 }, { 49 id: `one/name[1][]>>824634860360`, 50 path: "one/name", 51 verbosity: log.VerbosityInfo, 52 v: 1, 53 }, { 54 id: `one/name[2][]>>824634860360`, 55 path: "one/name", 56 verbosity: log.VerbosityInfo, 57 v: 2, 58 }} 59 60 for _, d := range data { 61 if !fn(d.id, d.path, d.verbosity, d.v) { 62 return 63 } 64 } 65 } 66 api.ReplaceLogRegistryIterateFn(fn) 67 68 have := make(map[string]interface{}) 69 want := make(map[string]interface{}) 70 data := `{"loggers":[{"id":"b25lWzBdW10-PjgyNDYzNDg2MDM2MA==","logger":"one","subsystem":"one[0][]\u003e\u003e824634860360","verbosity":"all"},{"id":"b25lL25hbWVbMF1bXT4-ODI0NjM0ODYwMzYw","logger":"one/name","subsystem":"one/name[0][]\u003e\u003e824634860360","verbosity":"warning"},{"id":"b25lL25hbWVbMF1bXCJ2YWxcIj0xXT4-ODI0NjM0ODYwMzYw","logger":"one/name","subsystem":"one/name[0][\\\"val\\\"=1]\u003e\u003e824634860360","verbosity":"warning"},{"id":"b25lL25hbWVbMV1bXT4-ODI0NjM0ODYwMzYw","logger":"one/name","subsystem":"one/name[1][]\u003e\u003e824634860360","verbosity":"info"},{"id":"b25lL25hbWVbMl1bXT4-ODI0NjM0ODYwMzYw","logger":"one/name","subsystem":"one/name[2][]\u003e\u003e824634860360","verbosity":"info"}],"tree":{"one":{"+":["all|one[0][]\u003e\u003e824634860360"],"/":{"name":{"+":["warning|one/name[0][]\u003e\u003e824634860360","warning|one/name[0][\\\"val\\\"=1]\u003e\u003e824634860360","info|one/name[1][]\u003e\u003e824634860360","info|one/name[2][]\u003e\u003e824634860360"]}}}}}` 71 if err := json.Unmarshal([]byte(data), &want); err != nil { 72 t.Fatalf("unexpected error: %v", err) 73 } 74 75 client, _, _, _ := newTestServer(t, testServerOptions{}) 76 jsonhttptest.Request(t, client, http.MethodGet, "/loggers", http.StatusOK, 77 jsonhttptest.WithUnmarshalJSONResponse(&have), 78 ) 79 80 if diff := cmp.Diff(want, have); diff != "" { 81 t.Errorf("response body mismatch (-want +have):\n%s", diff) 82 } 83 } 84 85 // nolint:paralleltest 86 func TestSetLoggerVerbosity(t *testing.T) { 87 defer func(fn api.LogSetVerbosityByExpFn) { 88 api.ReplaceLogSetVerbosityByExp(fn) 89 }(api.LogSetVerbosityByExp) 90 91 client, _, _, _ := newTestServer(t, testServerOptions{}) 92 93 type data struct { 94 exp string 95 ver log.Level 96 } 97 98 have := new(data) 99 api.ReplaceLogSetVerbosityByExp(func(e string, v log.Level) error { 100 have.exp = e 101 have.ver = v 102 return nil 103 }) 104 105 tests := []struct { 106 want data 107 }{{ 108 want: data{exp: `name`, ver: log.VerbosityWarning}, 109 }, { 110 want: data{exp: `^name$`, ver: log.VerbosityWarning}, 111 }, { 112 want: data{exp: `^name/\[0`, ver: log.VerbosityWarning}, 113 }, { 114 want: data{exp: `^name/\[0\]\[`, ver: log.VerbosityWarning}, 115 }, { 116 want: data{exp: `^name/\[0\]\[\"val\"=1\]`, ver: log.VerbosityWarning}, 117 }, { 118 want: data{exp: `^name/\[0\]\[\"val\"=1\]>>824634860360`, ver: log.VerbosityWarning}, 119 }} 120 121 for _, tc := range tests { 122 t.Run(fmt.Sprintf("to=%s,exp=%s", tc.want.ver, tc.want.exp), func(t *testing.T) { 123 exp := base64.URLEncoding.EncodeToString([]byte(tc.want.exp)) 124 url := fmt.Sprintf("/loggers/%s/%s", exp, tc.want.ver) 125 jsonhttptest.Request(t, client, http.MethodPut, url, http.StatusOK, 126 jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{ 127 Message: http.StatusText(http.StatusOK), 128 Code: http.StatusOK, 129 }), 130 ) 131 132 if have.exp != tc.want.exp { 133 t.Errorf("exp mismatch: want: %q; have: %q", tc.want.exp, have.exp) 134 } 135 136 if have.ver != tc.want.ver { 137 t.Errorf("verbosity mismatch: want: %q; have: %q", tc.want.ver, have.ver) 138 } 139 }) 140 } 141 } 142 143 func Test_loggerGetHandler_invalidInputs(t *testing.T) { 144 t.Parallel() 145 146 client, _, _, _ := newTestServer(t, testServerOptions{}) 147 148 tests := []struct { 149 name string 150 exp string 151 want jsonhttp.StatusResponse 152 }{{ 153 name: "exp - illegal base64", 154 exp: "123", 155 want: jsonhttp.StatusResponse{ 156 Code: http.StatusBadRequest, 157 Message: "invalid path params", 158 Reasons: []jsonhttp.Reason{ 159 { 160 Field: "exp", 161 Error: "illegal base64 data at input byte 0", 162 }, 163 }, 164 }, 165 }, { 166 name: "exp - invalid regex", 167 exp: base64.URLEncoding.EncodeToString([]byte("[")), 168 want: jsonhttp.StatusResponse{ 169 Code: http.StatusBadRequest, 170 Message: "invalid path params", 171 Reasons: []jsonhttp.Reason{ 172 { 173 Field: "exp", 174 Error: "error parsing regexp: missing closing ]: `[`", 175 }, 176 }, 177 }, 178 }} 179 180 for _, tc := range tests { 181 tc := tc 182 t.Run(tc.name, func(t *testing.T) { 183 t.Parallel() 184 185 jsonhttptest.Request(t, client, http.MethodGet, "/loggers/"+tc.exp, tc.want.Code, 186 jsonhttptest.WithExpectedJSONResponse(tc.want), 187 ) 188 }) 189 } 190 } 191 192 func Test_loggerSetVerbosityHandler_invalidInputs(t *testing.T) { 193 t.Parallel() 194 195 client, _, _, _ := newTestServer(t, testServerOptions{}) 196 197 tests := []struct { 198 name string 199 exp string 200 verbosity string 201 want jsonhttp.StatusResponse 202 }{{ 203 name: "exp - illegal base64", 204 exp: "123", 205 verbosity: "info", 206 want: jsonhttp.StatusResponse{ 207 Code: http.StatusBadRequest, 208 Message: "invalid path params", 209 Reasons: []jsonhttp.Reason{ 210 { 211 Field: "exp", 212 Error: "illegal base64 data at input byte 0", 213 }, 214 }, 215 }, 216 }, { 217 name: "exp - invalid regex", 218 exp: base64.URLEncoding.EncodeToString([]byte("[")), 219 verbosity: "info", 220 want: jsonhttp.StatusResponse{ 221 Code: http.StatusBadRequest, 222 Message: "invalid path params", 223 Reasons: []jsonhttp.Reason{ 224 { 225 Field: "exp", 226 Error: "error parsing regexp: missing closing ]: `[`", 227 }, 228 }, 229 }, 230 }, { 231 name: "verbosity - invalid value", 232 exp: base64.URLEncoding.EncodeToString([]byte("123")), 233 verbosity: "invalid", 234 want: jsonhttp.StatusResponse{ 235 Code: http.StatusBadRequest, 236 Message: "invalid path params", 237 Reasons: []jsonhttp.Reason{ 238 { 239 Field: "verbosity", 240 Error: "want oneof:none error warning info debug all", 241 }, 242 }, 243 }, 244 }} 245 246 for _, tc := range tests { 247 tc := tc 248 t.Run(tc.name, func(t *testing.T) { 249 t.Parallel() 250 251 jsonhttptest.Request(t, client, http.MethodPut, "/loggers/"+tc.exp+"/"+tc.verbosity, tc.want.Code, 252 jsonhttptest.WithExpectedJSONResponse(tc.want), 253 ) 254 }) 255 } 256 }