1// Copyright 2018 Envoyproxy 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//       http://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_test
16
17import (
18	"context"
19	"io"
20	"net/http"
21	"net/http/httptest"
22	"strings"
23	"testing"
24	"testing/iotest"
25
26	"github.com/envoyproxy/go-control-plane/pkg/cache/types"
27	"github.com/envoyproxy/go-control-plane/pkg/cache/v2"
28	"github.com/envoyproxy/go-control-plane/pkg/resource/v2"
29	"github.com/envoyproxy/go-control-plane/pkg/server/v2"
30)
31
32type logger struct {
33	t *testing.T
34}
35
36func (log logger) Debugf(format string, args ...interface{}) { log.t.Logf(format, args...) }
37func (log logger) Infof(format string, args ...interface{})  { log.t.Logf(format, args...) }
38func (log logger) Warnf(format string, args ...interface{})  { log.t.Logf(format, args...) }
39func (log logger) Errorf(format string, args ...interface{}) { log.t.Logf(format, args...) }
40
41func TestGateway(t *testing.T) {
42	config := makeMockConfigWatcher()
43	config.responses = map[string][]cache.Response{
44		resource.ClusterType: []cache.Response{{
45			Version:   "2",
46			Resources: []types.Resource{cluster},
47		}},
48		resource.RouteType: []cache.Response{{
49			Version:   "3",
50			Resources: []types.Resource{route},
51		}},
52		resource.ListenerType: []cache.Response{{
53			Version:   "4",
54			Resources: []types.Resource{listener},
55		}},
56	}
57	gtw := server.HTTPGateway{Log: logger{t: t}, Server: server.NewServer(context.Background(), config, nil)}
58
59	failCases := []struct {
60		path   string
61		body   io.Reader
62		expect int
63	}{
64		{
65			path:   "/hello/",
66			expect: http.StatusNotFound,
67		},
68		{
69			path:   "/v2/discovery:endpoints",
70			expect: http.StatusBadRequest,
71		},
72		{
73			path:   "/v2/discovery:endpoints",
74			body:   iotest.TimeoutReader(strings.NewReader("hello")),
75			expect: http.StatusBadRequest,
76		},
77		{
78			path:   "/v2/discovery:endpoints",
79			body:   strings.NewReader("hello"),
80			expect: http.StatusBadRequest,
81		},
82		{
83			// missing response
84			path:   "/v2/discovery:endpoints",
85			body:   strings.NewReader("{\"node\": {\"id\": \"test\"}}"),
86			expect: http.StatusInternalServerError,
87		},
88	}
89	for _, cs := range failCases {
90		rr := httptest.NewRecorder()
91		req, err := http.NewRequest(http.MethodPost, cs.path, cs.body)
92		if err != nil {
93			t.Fatal(err)
94		}
95		gtw.ServeHTTP(rr, req)
96		if status := rr.Code; status != cs.expect {
97			t.Errorf("handler returned wrong status: %d, want %d", status, cs.expect)
98		}
99	}
100
101	for _, path := range []string{"/v2/discovery:clusters", "/v2/discovery:routes", "/v2/discovery:listeners"} {
102		rr := httptest.NewRecorder()
103		req, err := http.NewRequest(http.MethodPost, path, strings.NewReader("{\"node\": {\"id\": \"test\"}}"))
104		if err != nil {
105			t.Fatal(err)
106		}
107		gtw.ServeHTTP(rr, req)
108		if status := rr.Code; status != 200 {
109			t.Errorf("handler returned wrong status: %d, want %d", status, 200)
110		}
111	}
112}
113