1// Copyright 2018 The Go Cloud Development Kit Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package server
16
17import (
18	"context"
19	"errors"
20	"net/http"
21	"net/http/httptest"
22	"testing"
23
24	"gocloud.dev/server/requestlog"
25)
26
27const (
28	certFile = "my-cert"
29	keyFile  = "my-key"
30)
31
32func TestListenAndServe(t *testing.T) {
33	td := new(testDriver)
34	s := New(http.NotFoundHandler(), &Options{Driver: td})
35	err := s.ListenAndServe(":8080")
36	if err != nil {
37		t.Fatal(err)
38	}
39	if !td.listenAndServeCalled {
40		t.Error("ListenAndServe was not called from the supplied driver")
41	}
42	if td.certFile != "" || td.keyFile != "" {
43		t.Errorf("ListenAndServe got non-empty certFile or keyFile (%q, %q), wanted empty", td.certFile, td.keyFile)
44	}
45	if td.handler == nil {
46		t.Error("testDriver must set handler, got nil")
47	}
48}
49
50func TestListenAndServeTLSNoSupported(t *testing.T) {
51	td := new(testDriverNoTLS)
52	s := New(http.NotFoundHandler(), &Options{Driver: td})
53	err := s.ListenAndServeTLS(":8080", certFile, keyFile)
54	if err == nil {
55		t.Fatal("expected TLS not supported error")
56	}
57}
58
59func TestListenAndServeTLS(t *testing.T) {
60	td := new(testDriver)
61	s := New(http.NotFoundHandler(), &Options{Driver: td})
62	err := s.ListenAndServeTLS(":8080", certFile, keyFile)
63	if err != nil {
64		t.Fatal(err)
65	}
66	if !td.listenAndServeCalled {
67		t.Error("ListenAndServe was not called from the supplied driver")
68	}
69	if td.certFile != certFile {
70		t.Errorf("ListenAndServe got certFile %q, want %q", td.certFile, certFile)
71	}
72	if td.keyFile != keyFile {
73		t.Errorf("ListenAndServe got keyFile %q, want %q", td.keyFile, keyFile)
74	}
75	if td.handler == nil {
76		t.Error("testDriver must set handler, got nil")
77	}
78}
79
80func TestMiddleware(t *testing.T) {
81	onLogCalled := 0
82
83	tl := &testLogger{
84		onLog: func(ent *requestlog.Entry) {
85			onLogCalled++
86			if ent.TraceID.String() == "" {
87				t.Error("TraceID is empty")
88			}
89			if ent.SpanID.String() == "" {
90				t.Error("SpanID is empty")
91			}
92		},
93	}
94
95	td := new(testDriver)
96	s := New(http.NotFoundHandler(), &Options{Driver: td, RequestLogger: tl})
97	err := s.ListenAndServe(":8080")
98	if err != nil {
99		t.Fatal(err)
100	}
101
102	req, err := http.NewRequest("GET", "/", nil)
103	if err != nil {
104		t.Fatal(err)
105	}
106
107	rr := httptest.NewRecorder()
108	td.handler.ServeHTTP(rr, req)
109	if onLogCalled != 1 {
110		t.Fatal("logging middleware was not called")
111	}
112
113	// Repeat with TLS.
114	err = s.ListenAndServeTLS(":8081", certFile, keyFile)
115	if err != nil {
116		t.Fatal(err)
117	}
118
119	req, err = http.NewRequest("GET", "/", nil)
120	if err != nil {
121		t.Fatal(err)
122	}
123	td.handler.ServeHTTP(rr, req)
124	if onLogCalled != 2 {
125		t.Fatal("logging middleware was not called for TLS")
126	}
127
128}
129
130type testDriverNoTLS string
131
132func (td *testDriverNoTLS) ListenAndServe(addr string, h http.Handler) error {
133	return errors.New("this is a method for satisfying the interface")
134}
135
136func (td *testDriverNoTLS) Shutdown(ctx context.Context) error {
137	return errors.New("this is a method for satisfying the interface")
138}
139
140type testDriver struct {
141	listenAndServeCalled bool
142	certFile, keyFile    string
143	handler              http.Handler
144}
145
146func (td *testDriver) ListenAndServe(addr string, h http.Handler) error {
147	td.listenAndServeCalled = true
148	td.handler = h
149	return nil
150}
151
152func (td *testDriver) ListenAndServeTLS(addr, certFile, keyFile string, h http.Handler) error {
153	td.listenAndServeCalled = true
154	td.certFile = certFile
155	td.keyFile = keyFile
156	td.handler = h
157	return nil
158}
159
160func (td *testDriver) Shutdown(ctx context.Context) error {
161	return errors.New("this is a method for satisfying the interface")
162}
163
164type testLogger struct {
165	onLog func(ent *requestlog.Entry)
166}
167
168func (tl *testLogger) Log(ent *requestlog.Entry) {
169	tl.onLog(ent)
170}
171