-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathcf_debug_server_test.go
More file actions
224 lines (187 loc) · 5.96 KB
/
cf_debug_server_test.go
File metadata and controls
224 lines (187 loc) · 5.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
package debugserver_test
import (
"crypto/tls"
"flag"
"fmt"
"io"
"net"
"net/http"
"net/http/httptest"
"strings"
cf_debug_server "code.cloudfoundry.org/debugserver"
lager "code.cloudfoundry.org/lager/v3"
"github.com/tedsuo/ifrit"
ginkgomon "github.com/tedsuo/ifrit/ginkgomon_v2"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gbytes"
)
var _ = Describe("CF Debug Server", func() {
var (
logBuf *gbytes.Buffer
sink *lager.ReconfigurableSink
process ifrit.Process
)
BeforeEach(func() {
logBuf = gbytes.NewBuffer()
sink = lager.NewReconfigurableSink(
lager.NewWriterSink(logBuf, lager.DEBUG),
// permit no logging by default, for log reconfiguration below
lager.FATAL+1,
)
})
AfterEach(func() {
ginkgomon.Interrupt(process)
})
Describe("AddFlags", func() {
It("adds flags to the flagset", func() {
flags := flag.NewFlagSet("test", flag.ContinueOnError)
cf_debug_server.AddFlags(flags)
f := flags.Lookup(cf_debug_server.DebugFlag)
Expect(f).NotTo(BeNil())
})
})
Describe("DebugAddress", func() {
Context("when flags are not added", func() {
It("returns the empty string", func() {
flags := flag.NewFlagSet("test", flag.ContinueOnError)
Expect(cf_debug_server.DebugAddress(flags)).To(Equal(""))
})
})
Context("when flags are added", func() {
var flags *flag.FlagSet
BeforeEach(func() {
flags = flag.NewFlagSet("test", flag.ContinueOnError)
cf_debug_server.AddFlags(flags)
})
Context("when set", func() {
It("returns the address", func() {
flags.Parse([]string{"-debugAddr", address})
Expect(cf_debug_server.DebugAddress(flags)).To(Equal(address))
})
})
Context("when not set", func() {
It("returns the empty string", func() {
Expect(cf_debug_server.DebugAddress(flags)).To(Equal(""))
})
})
})
})
Describe("Run", func() {
It("serves debug information", func() {
var err error
process, err = cf_debug_server.Run(address, sink)
Expect(err).NotTo(HaveOccurred())
debugResponse, err := http.Get(fmt.Sprintf("http://%s/debug/pprof/goroutine", address))
Expect(err).NotTo(HaveOccurred())
defer debugResponse.Body.Close()
})
Context("when the address is already in use", func() {
var listener net.Listener
BeforeEach(func() {
var err error
listener, err = net.Listen("tcp", address)
Expect(err).NotTo(HaveOccurred())
})
AfterEach(func() {
listener.Close()
})
It("returns an error", func() {
var err error
process, err = cf_debug_server.Run(address, sink)
Expect(err).To(HaveOccurred())
Expect(err).To(BeAssignableToTypeOf(&net.OpError{}))
netErr := err.(*net.OpError)
Expect(netErr.Op).To(Equal("listen"))
})
})
})
Describe("checking log-level endpoint with various inputs", func() {
var (
req *http.Request
writer *httptest.ResponseRecorder
)
BeforeEach(func() {
writer = httptest.NewRecorder()
req = httptest.NewRequest(http.MethodPost, fmt.Sprintf("http://%s/log-level", address), nil)
})
Context("valid log levels", func() {
DescribeTable("returns normalized log level",
func(input string, expected string) {
req.Body = io.NopCloser(strings.NewReader(input))
levelBytes, _ := io.ReadAll(req.Body)
actual, err := cf_debug_server.ValidateAndNormalize(writer, req, levelBytes)
Expect(err).ToNot(HaveOccurred())
Expect(actual).To(Equal(expected))
},
// Debug
Entry("debug - 0", "0", "debug"),
Entry("debug - d", "d", "debug"),
Entry("debug - debug", "debug", "debug"),
Entry("debug - DEBUG", "DEBUG", "debug"),
Entry("debug - DeBuG", "DeBuG", "debug"),
// Info
Entry("info - 1", "1", "info"),
Entry("info - i", "i", "info"),
Entry("info - info", "info", "info"),
Entry("info - INFO", "INFO", "info"),
Entry("info - InFo", "InFo", "info"),
// Warn
Entry("warn - 2", "2", "warn"),
Entry("warn - w", "w", "warn"),
Entry("warn - warn", "warn", "warn"),
Entry("warn - WARN", "WARN", "warn"),
Entry("warn - wARn", "wARn", "warn"),
// Error
Entry("error - 3", "3", "error"),
Entry("error - e", "e", "error"),
Entry("error - error", "error", "error"),
Entry("error - ERROR", "ERROR", "error"),
Entry("error - eRroR", "eRroR", "error"),
// Fatal
Entry("fatal - 4", "4", "fatal"),
Entry("fatal - f", "f", "fatal"),
Entry("fatal - fatal", "fatal", "fatal"),
Entry("fatal - FATAL", "FATAL", "fatal"),
Entry("fatal - FaTaL", "FaTaL", "fatal"),
)
})
Context("invalid log levels", func() {
It("fails on unsupported level", func() {
level := []byte("invalid")
actual, err := cf_debug_server.ValidateAndNormalize(writer, req, level)
Expect(err).To(HaveOccurred())
Expect(actual).To(BeEmpty())
})
It("fails on empty level", func() {
level := []byte("")
actual, err := cf_debug_server.ValidateAndNormalize(writer, req, level)
Expect(err).To(HaveOccurred())
Expect(actual).To(BeEmpty())
})
})
Context("invalid request method", func() {
It("returns error for non-POST", func() {
req.Method = http.MethodGet
actual, err := cf_debug_server.ValidateAndNormalize(writer, req, []byte("info"))
Expect(err).To(MatchError(ContainSubstring("method not allowed")))
Expect(actual).To(BeEmpty())
})
})
Context("invalid TLS scheme", func() {
It("returns error if TLS is used", func() {
req.TLS = &tls.ConnectionState{}
actual, err := cf_debug_server.ValidateAndNormalize(writer, req, []byte("debug"))
Expect(err).To(MatchError(ContainSubstring("invalid scheme")))
Expect(actual).To(BeEmpty())
})
})
It("returns error if the request is made over HTTPS", func() {
// Simulate HTTPS by assigning a non-nil TLS connection state
req.TLS = &tls.ConnectionState{}
actual, err := cf_debug_server.ValidateAndNormalize(writer, req, []byte("debug"))
Expect(err).To(MatchError(ContainSubstring("invalid scheme")))
Expect(actual).To(BeEmpty())
})
})
})