1// Copyright (c) 2016 Uber Technologies, Inc.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19// THE SOFTWARE.
20
21package zap_test
22
23import (
24	"encoding/json"
25	"fmt"
26	"io"
27	"io/ioutil"
28	"net/http"
29	"net/http/httptest"
30	"strings"
31	"testing"
32
33	. "go.uber.org/zap"
34	"go.uber.org/zap/zapcore"
35
36	"github.com/stretchr/testify/assert"
37	"github.com/stretchr/testify/require"
38)
39
40func newHandler() (AtomicLevel, *Logger) {
41	lvl := NewAtomicLevel()
42	logger := New(zapcore.NewNopCore())
43	return lvl, logger
44}
45
46func assertCodeOK(t testing.TB, code int) {
47	assert.Equal(t, http.StatusOK, code, "Unexpected response status code.")
48}
49
50func assertCodeBadRequest(t testing.TB, code int) {
51	assert.Equal(t, http.StatusBadRequest, code, "Unexpected response status code.")
52}
53
54func assertCodeMethodNotAllowed(t testing.TB, code int) {
55	assert.Equal(t, http.StatusMethodNotAllowed, code, "Unexpected response status code.")
56}
57
58func assertResponse(t testing.TB, expectedLevel zapcore.Level, actualBody string) {
59	assert.Equal(t, fmt.Sprintf(`{"level":"%s"}`, expectedLevel)+"\n", actualBody, "Unexpected response body.")
60}
61
62func assertJSONError(t testing.TB, body string) {
63	// Don't need to test exact error message, but one should be present.
64	var payload map[string]interface{}
65	require.NoError(t, json.Unmarshal([]byte(body), &payload), "Expected error response to be JSON.")
66
67	msg, ok := payload["error"]
68	require.True(t, ok, "Error message is an unexpected type.")
69	assert.NotEqual(t, "", msg, "Expected an error message in response.")
70}
71
72func makeRequest(t testing.TB, method string, handler http.Handler, reader io.Reader) (int, string) {
73	ts := httptest.NewServer(handler)
74	defer ts.Close()
75
76	req, err := http.NewRequest(method, ts.URL, reader)
77	require.NoError(t, err, "Error constructing %s request.", method)
78
79	res, err := http.DefaultClient.Do(req)
80	require.NoError(t, err, "Error making %s request.", method)
81	defer res.Body.Close()
82
83	body, err := ioutil.ReadAll(res.Body)
84	require.NoError(t, err, "Error reading request body.")
85
86	return res.StatusCode, string(body)
87}
88
89func TestHTTPHandlerGetLevel(t *testing.T) {
90	lvl, _ := newHandler()
91	code, body := makeRequest(t, "GET", lvl, nil)
92	assertCodeOK(t, code)
93	assertResponse(t, lvl.Level(), body)
94}
95
96func TestHTTPHandlerPutLevel(t *testing.T) {
97	lvl, _ := newHandler()
98
99	code, body := makeRequest(t, "PUT", lvl, strings.NewReader(`{"level":"warn"}`))
100
101	assertCodeOK(t, code)
102	assertResponse(t, lvl.Level(), body)
103}
104
105func TestHTTPHandlerPutUnrecognizedLevel(t *testing.T) {
106	lvl, _ := newHandler()
107	code, body := makeRequest(t, "PUT", lvl, strings.NewReader(`{"level":"unrecognized-level"}`))
108	assertCodeBadRequest(t, code)
109	assertJSONError(t, body)
110}
111
112func TestHTTPHandlerNotJSON(t *testing.T) {
113	lvl, _ := newHandler()
114	code, body := makeRequest(t, "PUT", lvl, strings.NewReader(`{`))
115	assertCodeBadRequest(t, code)
116	assertJSONError(t, body)
117}
118
119func TestHTTPHandlerNoLevelSpecified(t *testing.T) {
120	lvl, _ := newHandler()
121	code, body := makeRequest(t, "PUT", lvl, strings.NewReader(`{}`))
122	assertCodeBadRequest(t, code)
123	assertJSONError(t, body)
124}
125
126func TestHTTPHandlerMethodNotAllowed(t *testing.T) {
127	lvl, _ := newHandler()
128	code, body := makeRequest(t, "POST", lvl, strings.NewReader(`{`))
129	assertCodeMethodNotAllowed(t, code)
130	assertJSONError(t, body)
131}
132