1// +build go1.13
2
3// Copyright (c) Microsoft Corporation. All rights reserved.
4// Licensed under the MIT License.
5
6package azcore
7
8import (
9	"bytes"
10	"context"
11	"errors"
12	"net/http"
13	"strings"
14	"testing"
15
16	"github.com/Azure/azure-sdk-for-go/sdk/internal/mock"
17)
18
19func TestPolicyLoggingSuccess(t *testing.T) {
20	log := map[LogClassification]string{}
21	Log().SetListener(func(cls LogClassification, s string) {
22		log[cls] = s
23	})
24	srv, close := mock.NewServer()
25	defer close()
26	srv.SetResponse()
27	pl := NewPipeline(srv, NewLogPolicy(nil))
28	req, err := NewRequest(context.Background(), http.MethodGet, srv.URL())
29	if err != nil {
30		t.Fatalf("unexpected error: %v", err)
31	}
32	qp := req.URL.Query()
33	qp.Set("one", "fish")
34	qp.Set("sig", "redact")
35	req.URL.RawQuery = qp.Encode()
36	resp, err := pl.Do(req)
37	if err != nil {
38		t.Fatalf("unexpected error: %v", err)
39	}
40	if resp.StatusCode != http.StatusOK {
41		t.Fatalf("unexpected status code: %d", resp.StatusCode)
42	}
43	if logReq, ok := log[LogRequest]; ok {
44		// Request ==> OUTGOING REQUEST (Try=1)
45		// 	GET http://127.0.0.1:49475?one=fish&sig=REDACTED
46		// 	(no headers)
47		if !strings.Contains(logReq, "(no headers)") {
48			t.Fatal("missing (no headers)")
49		}
50	} else {
51		t.Fatal("missing LogRequest")
52	}
53	if logResp, ok := log[LogResponse]; ok {
54		// Response ==> REQUEST/RESPONSE (Try=1/1.0034ms, OpTime=1.0034ms) -- RESPONSE SUCCESSFULLY RECEIVED
55		// 	GET http://127.0.0.1:49475?one=fish&sig=REDACTED
56		// 	(no headers)
57		// 	--------------------------------------------------------------------------------
58		// 	RESPONSE Status: 200 OK
59		// 	Content-Length: [0]
60		// 	Date: [Fri, 22 Nov 2019 23:48:02 GMT]
61		if !strings.Contains(logResp, "RESPONSE Status: 200 OK") {
62			t.Fatal("missing response status")
63		}
64	} else {
65		t.Fatal("missing LogResponse")
66	}
67}
68
69func TestPolicyLoggingError(t *testing.T) {
70	log := map[LogClassification]string{}
71	Log().SetListener(func(cls LogClassification, s string) {
72		log[cls] = s
73	})
74	srv, close := mock.NewServer()
75	defer close()
76	srv.SetError(errors.New("bogus error"))
77	pl := NewPipeline(srv, NewLogPolicy(nil))
78	req, err := NewRequest(context.Background(), http.MethodGet, srv.URL())
79	if err != nil {
80		t.Fatalf("unexpected error: %v", err)
81	}
82	req.Header.Add("header", "one")
83	req.Header.Add("Authorization", "redact")
84	resp, err := pl.Do(req)
85	if err == nil {
86		t.Fatal("unexpected nil error")
87	}
88	if resp != nil {
89		t.Fatal("unexpected respose")
90	}
91	if logReq, ok := log[LogRequest]; ok {
92		// Request ==> OUTGOING REQUEST (Try=1)
93		// 	GET http://127.0.0.1:50057
94		// 	Authorization: REDACTED
95		// 	Header: [one]
96		if !strings.Contains(logReq, "Authorization: REDACTED") {
97			t.Fatal("missing redacted authorization header")
98		}
99	} else {
100		t.Fatal("missing LogRequest")
101	}
102	if logResponse, ok := log[LogResponse]; ok {
103		// Response ==> REQUEST/RESPONSE (Try=1/0s, OpTime=0s) -- REQUEST ERROR
104		// 	GET http://127.0.0.1:50057
105		// 	Authorization: REDACTED
106		// 	Header: [one]
107		// 	--------------------------------------------------------------------------------
108		// 	ERROR:
109		// 	bogus error
110		// 	 ...stack track...
111		if !strings.Contains(logResponse, "Authorization: REDACTED") {
112			t.Fatal("missing redacted authorization header")
113		}
114		if !strings.Contains(logResponse, "bogus error") {
115			t.Fatal("missing error message")
116		}
117	} else {
118		t.Fatal("missing LogResponse")
119	}
120}
121
122func TestShouldLogBody(t *testing.T) {
123	b := bytes.NewBuffer(make([]byte, 64))
124	if shouldLogBody(b, "application/octet-stream") {
125		t.Fatal("shouldn't log for application/octet-stream")
126	} else if b.Len() == 0 {
127		t.Fatal("skip logging should write skip message to buffer")
128	}
129	b.Reset()
130	if !shouldLogBody(b, "application/json") {
131		t.Fatal("should log for application/json")
132	} else if b.Len() != 0 {
133		t.Fatal("logging shouldn't write message")
134	}
135	if !shouldLogBody(b, "application/xml") {
136		t.Fatal("should log for application/xml")
137	} else if b.Len() != 0 {
138		t.Fatal("logging shouldn't write message")
139	}
140	if !shouldLogBody(b, "text/plain") {
141		t.Fatal("should log for text/plain")
142	} else if b.Len() != 0 {
143		t.Fatal("logging shouldn't write message")
144	}
145}
146