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  }