github.com/avenga/couper@v1.12.2/server/http_custom_logs_test.go (about)

     1  package server_test
     2  
     3  import (
     4  	"net/http"
     5  	"reflect"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/google/go-cmp/cmp"
    10  	"github.com/sirupsen/logrus"
    11  
    12  	"github.com/avenga/couper/internal/test"
    13  	"github.com/avenga/couper/logging"
    14  )
    15  
    16  func TestCustomLogs_Upstream(t *testing.T) {
    17  	client := test.NewHTTPClient()
    18  
    19  	shutdown, hook := newCouper("testdata/integration/logs/01_couper.hcl", test.New(t))
    20  	defer shutdown()
    21  
    22  	type testCase struct {
    23  		path        string
    24  		expAccess   logrus.Fields
    25  		expUpstream logrus.Fields
    26  	}
    27  
    28  	hmacToken := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwic2NvcGUiOiJmb28gYmFyIiwiaWF0IjoxNTE2MjM5MDIyfQ.7wz7Z7IajfEpwYayfshag6tQVS0e0zZJyjAhuFC0L-E"
    29  
    30  	for _, tc := range []testCase{
    31  		{
    32  			"/",
    33  			logrus.Fields{
    34  				"api":      "couper test-backend",
    35  				"endpoint": "couper test-backend",
    36  				"server":   "couper test-backend",
    37  			},
    38  			logrus.Fields{
    39  				"array": []interface{}{
    40  					float64(1),
    41  					"couper test-backend",
    42  					[]interface{}{
    43  						float64(2),
    44  						"couper test-backend",
    45  					},
    46  					logrus.Fields{"x": "X"},
    47  				},
    48  				"bool":   true,
    49  				"float":  1.23,
    50  				"int":    float64(123),
    51  				"object": logrus.Fields{"a": "A", "b": "B", "c": float64(123)},
    52  				"req":    "GET",
    53  				"string": "couper test-backend",
    54  			},
    55  		},
    56  		{
    57  			"/backend",
    58  			logrus.Fields{"api": "couper test-backend", "server": "couper test-backend"},
    59  			logrus.Fields{"backend": "couper test-backend"},
    60  		},
    61  		{
    62  			"/jwt-valid",
    63  			logrus.Fields{"jwt_regular": "GET", "server": "couper test-backend"},
    64  			logrus.Fields{"backend": "couper test-backend"},
    65  		},
    66  	} {
    67  		t.Run(tc.path, func(st *testing.T) {
    68  			helper := test.New(st)
    69  			req, err := http.NewRequest(http.MethodGet, "http://localhost:8080"+tc.path, nil)
    70  			helper.Must(err)
    71  
    72  			req.Header.Set("Authorization", "Bearer "+hmacToken)
    73  
    74  			hook.Reset()
    75  			_, err = client.Do(req)
    76  			helper.Must(err)
    77  
    78  			// Wait for logs
    79  			time.Sleep(100 * time.Millisecond)
    80  
    81  			entries := hook.AllEntries()
    82  			var accessLog, upstreamLog logrus.Fields
    83  			for _, entry := range entries {
    84  				request := entry.Data["request"].(logging.Fields)
    85  				path, _ := request["path"].(string)
    86  				if entry.Data["type"] == "couper_access" {
    87  					accessLog = entry.Data
    88  				} else if entry.Data["type"] == "couper_backend" && path != "/jwks.json" {
    89  					upstreamLog = entry.Data
    90  				}
    91  			}
    92  
    93  			if accessLog == nil || upstreamLog == nil {
    94  				st.Fatalf("expected logs, got access: %p, got upstream: %p", accessLog, upstreamLog)
    95  			}
    96  
    97  			customAccess, ok := accessLog["custom"].(logrus.Fields)
    98  			if !ok {
    99  				st.Fatal("expected access log custom field")
   100  			}
   101  
   102  			customUpstream, ok := upstreamLog["custom"].(logrus.Fields)
   103  			if !ok {
   104  				st.Fatal("expected upstream log custom field")
   105  			}
   106  
   107  			if !cmp.Equal(tc.expAccess, customAccess) {
   108  				st.Error(cmp.Diff(tc.expAccess, customAccess))
   109  			}
   110  
   111  			if !cmp.Equal(tc.expUpstream, customUpstream) {
   112  				st.Error(cmp.Diff(tc.expUpstream, customUpstream))
   113  			}
   114  		})
   115  	}
   116  }
   117  
   118  func TestCustomLogs_Local(t *testing.T) {
   119  	client := newClient()
   120  
   121  	shutdown, hook := newCouper("testdata/integration/logs/01_couper.hcl", test.New(t))
   122  	defer shutdown()
   123  
   124  	type testCase struct {
   125  		name   string
   126  		path   string
   127  		header test.Header
   128  		exp    logrus.Fields
   129  	}
   130  
   131  	for _, tc := range []testCase{
   132  		{"basic-auth", "/secure", nil, logrus.Fields{"error_handler": "GET"}},
   133  		{"jwt with error-handler", "/jwt", nil, logrus.Fields{"jwt_error": "GET", "jwt_regular": "GET"}},
   134  		{"jwt with * error-handler", "/jwt-wildcard", nil, logrus.Fields{"jwt_error_wildcard": "GET", "jwt_regular": "GET"}},
   135  		{"oauth2 error-handler", "/oauth2cb?pkcecv=qerbnr&error=qeuboub", nil, logrus.Fields{"oauth2_error": "GET", "oauth2_regular": "GET"}},
   136  		{"oauth2 * error-handler", "/oauth2cb-wildcard?pkcecv=qerbnr&error=qeuboub", nil, logrus.Fields{"oauth2_wildcard_error": "GET", "oauth2_regular": "GET"}},
   137  		{"saml with saml2 error-handler", "/saml-saml2/acs", nil, logrus.Fields{"saml_saml2_error": "GET", "saml_regular": "GET"}},
   138  		{"saml with saml error-handler", "/saml-saml/acs", nil, logrus.Fields{"saml_saml_error": "GET", "saml_regular": "GET"}},
   139  		{"saml with * error-handler", "/saml-wildcard/acs", nil, logrus.Fields{"saml_wildcard_error": "GET", "saml_regular": "GET"}},
   140  		{"oidc with error-handler", "/oidc/cb", nil, logrus.Fields{"oidc_error": "GET", "oidc_regular": "GET"}},
   141  		{"oidc with * error-handler", "/oidc-wildcard/cb", nil, logrus.Fields{"oidc_wildcard_error": "GET", "oidc_regular": "GET"}},
   142  		{"file access", "/file.html", nil, logrus.Fields{"files": "GET"}},
   143  		{"spa access", "/spa", nil, logrus.Fields{"spa": "GET"}},
   144  		{"endpoint with error-handler", "/error-handler/endpoint",
   145  			test.Header{"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.Qf0lkeZKZ3NJrYm3VdgiQiQ6QTrjCvISshD_q9F8GAM"},
   146  			logrus.Fields{"error_handler": "GET", "jwt_regular": "GET"}},
   147  		{"endpoint standard", "/standard", nil, logrus.Fields{
   148  			"server": "couper test-backend",
   149  			"item-1": "item1",
   150  			"item-2": "item1",
   151  		}},
   152  		{"endpoint sequence", "/sequence", nil, logrus.Fields{
   153  			"server":     "couper test-backend",
   154  			"seq-item-1": "item1",
   155  			"seq-item-2": "item1",
   156  		}},
   157  	} {
   158  		t.Run(tc.name, func(st *testing.T) {
   159  			hook.Reset()
   160  
   161  			helper := test.New(st)
   162  			req, err := http.NewRequest(http.MethodGet, "http://localhost:8080"+tc.path, nil)
   163  			helper.Must(err)
   164  
   165  			for k, v := range tc.header {
   166  				req.Header.Set(k, v)
   167  			}
   168  
   169  			res, err := client.Do(req)
   170  			helper.Must(err)
   171  
   172  			helper.Must(res.Body.Close())
   173  
   174  			// Wait for logs
   175  			time.Sleep(time.Second / 5)
   176  
   177  			// Access log
   178  			entries := hook.AllEntries()
   179  			if len(entries) == 0 {
   180  				st.Errorf("expected log entries, got none")
   181  				return
   182  			}
   183  
   184  			var accessLogEntry *logrus.Entry
   185  			for _, e := range entries {
   186  				if e.Data["type"] == "couper_access" {
   187  					accessLogEntry = e
   188  					break
   189  				}
   190  			}
   191  			if accessLogEntry == nil {
   192  				st.Fatal("Expected access log entry")
   193  			}
   194  
   195  			got, ok := accessLogEntry.Data["custom"].(logrus.Fields)
   196  			if !ok {
   197  				st.Fatal("expected custom log field, got none")
   198  			}
   199  
   200  			if !reflect.DeepEqual(tc.exp, got) {
   201  				st.Error(cmp.Diff(tc.exp, got))
   202  			}
   203  		})
   204  	}
   205  }
   206  
   207  func TestCustomLogs_Merge(t *testing.T) {
   208  	client := newClient()
   209  	helper := test.New(t)
   210  
   211  	shutdown, hook := newCouper("testdata/integration/logs/02_couper.hcl", test.New(t))
   212  	defer shutdown()
   213  
   214  	req, err := http.NewRequest(http.MethodGet, "http://localhost:8080/", nil)
   215  	helper.Must(err)
   216  
   217  	hook.Reset()
   218  	_, err = client.Do(req)
   219  	helper.Must(err)
   220  
   221  	// Wait for logs
   222  	time.Sleep(200 * time.Millisecond)
   223  
   224  	exp := logrus.Fields{
   225  		"api":      true,
   226  		"endpoint": true,
   227  		"l1":       "endpoint",
   228  		"l2":       []interface{}{"server", "api", "endpoint"},
   229  		"l3":       []interface{}{"endpoint"},
   230  		"server":   true,
   231  	}
   232  
   233  	// Access log
   234  	got, ok := hook.AllEntries()[0].Data["custom"].(logrus.Fields)
   235  	if !ok {
   236  		t.Fatalf("expected\n%#v\ngot\n%#v", exp, got)
   237  	}
   238  	if !reflect.DeepEqual(exp, got) {
   239  		t.Errorf("expected\n%#v\ngot\n%#v", exp, got)
   240  	}
   241  }
   242  
   243  func TestCustomLogs_EvalError(t *testing.T) {
   244  	client := newClient()
   245  	helper := test.New(t)
   246  
   247  	shutdown, hook := newCouper("testdata/integration/logs/04_couper.hcl", test.New(t))
   248  	defer shutdown()
   249  
   250  	req, err := http.NewRequest(http.MethodGet, "http://localhost:8080/", nil)
   251  	helper.Must(err)
   252  
   253  	hook.Reset()
   254  	_, err = client.Do(req)
   255  	helper.Must(err)
   256  }