@marcel91200 / caddy Mirror · read-only
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 01:00 UTC

master
go 187 lines 5.02 KB
Raw
1 // Copyright 2015 Matthew Holt and The Caddy 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
15 package caddyevents
16
17 import (
18 "context"
19 "io"
20 "testing"
21
22 "go.uber.org/zap"
23 "go.uber.org/zap/zapcore"
24
25 "github.com/caddyserver/caddy/v2"
26 )
27
28 // discardLogger stands in for a production logger: a real core at info level,
29 // so debug output is filtered but everything else behaves normally.
30 func discardLogger() *zap.Logger {
31 return zap.New(zapcore.NewCore(
32 zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
33 zapcore.AddSync(io.Discard),
34 zapcore.InfoLevel,
35 ))
36 }
37
38 func testApp(tb testing.TB) (*App, caddy.Context, context.CancelFunc) {
39 tb.Helper()
40 app := &App{
41 logger: discardLogger(),
42 subscriptions: make(map[string]map[caddy.ModuleID][]Handler),
43 }
44 ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()})
45 return app, ctx, cancel
46 }
47
48 type countingHandler struct{ count int }
49
50 func (h *countingHandler) Handle(context.Context, caddy.Event) error {
51 h.count++
52 return nil
53 }
54
55 // Emit takes a shortcut when nothing is subscribed; a handler bound to the
56 // event by name must still be invoked.
57 func TestEmitDispatchesToNamedSubscriber(t *testing.T) {
58 app, ctx, cancel := testApp(t)
59 defer cancel()
60
61 h := new(countingHandler)
62 if err := app.On("cert_obtained", h); err != nil {
63 t.Fatal(err)
64 }
65
66 app.Emit(ctx, "cert_obtained", nil)
67 if h.count != 1 {
68 t.Errorf("handler invoked %d times, want 1", h.count)
69 }
70
71 // an event nobody subscribed to must not reach it
72 app.Emit(ctx, "cert_failed", nil)
73 if h.count != 1 {
74 t.Errorf("handler invoked %d times after unrelated event, want 1", h.count)
75 }
76 }
77
78 // Subscribing without naming an event binds to every event, which is stored
79 // under the empty event name; the shortcut has to account for that.
80 func TestEmitDispatchesToCatchAllSubscriber(t *testing.T) {
81 app, ctx, cancel := testApp(t)
82 defer cancel()
83
84 h := new(countingHandler)
85 if err := app.Subscribe(&Subscription{Handlers: []Handler{h}}); err != nil {
86 t.Fatal(err)
87 }
88
89 app.Emit(ctx, "tls_get_certificate", nil)
90 if h.count != 1 {
91 t.Errorf("handler invoked %d times, want 1", h.count)
92 }
93 }
94
95 // Emit writes a debug line for every event, so with debug logging on an event
96 // is observable even when nothing is subscribed. A predicate that answered
97 // only about subscribers would silence that line.
98 func TestShouldEmit(t *testing.T) {
99 app, _, cancel := testApp(t)
100 defer cancel()
101
102 if app.ShouldEmit("cert_obtained") {
103 t.Error("nothing is subscribed and debug is off; should not emit")
104 }
105
106 if err := app.On("cert_obtained", new(countingHandler)); err != nil {
107 t.Fatal(err)
108 }
109 if !app.ShouldEmit("cert_obtained") {
110 t.Error("a handler is bound by name; should emit")
111 }
112 if app.ShouldEmit("tls_get_certificate") {
113 t.Error("nothing is bound to this event; should not emit")
114 }
115 }
116
117 func TestShouldEmitWithCatchAllSubscriber(t *testing.T) {
118 app, _, cancel := testApp(t)
119 defer cancel()
120
121 if err := app.Subscribe(&Subscription{Handlers: []Handler{new(countingHandler)}}); err != nil {
122 t.Fatal(err)
123 }
124 if !app.ShouldEmit("tls_get_certificate") {
125 t.Error("a catch-all subscription observes every event; should emit")
126 }
127 }
128
129 func TestShouldEmitWithDebugLogging(t *testing.T) {
130 app, _, cancel := testApp(t)
131 defer cancel()
132 app.logger = zap.New(zapcore.NewCore(
133 zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
134 zapcore.AddSync(io.Discard),
135 zapcore.DebugLevel,
136 ))
137
138 if !app.ShouldEmit("tls_get_certificate") {
139 t.Error("debug logging observes every event; should emit")
140 }
141 }
142
143 // Some events, such as tls_get_certificate, are emitted on every TLS
144 // handshake, whether or not anything is subscribed to them.
145 func BenchmarkEmitNoSubscribers(b *testing.B) {
146 app, ctx, cancel := testApp(b)
147 defer cancel()
148
149 data := map[string]any{"client_hello": "example.com"}
150
151 b.ReportAllocs()
152 b.ResetTimer()
153 for i := 0; i < b.N; i++ {
154 app.Emit(ctx, "tls_get_certificate", data)
155 }
156 }
157
158 func BenchmarkEmitNoSubscribersParallel(b *testing.B) {
159 app, ctx, cancel := testApp(b)
160 defer cancel()
161
162 data := map[string]any{"client_hello": "example.com"}
163
164 b.ReportAllocs()
165 b.ResetTimer()
166 b.RunParallel(func(pb *testing.PB) {
167 for pb.Next() {
168 app.Emit(ctx, "tls_get_certificate", data)
169 }
170 })
171 }
172
173 func BenchmarkEmitWithSubscriber(b *testing.B) {
174 app, ctx, cancel := testApp(b)
175 defer cancel()
176
177 if err := app.On("tls_get_certificate", new(countingHandler)); err != nil {
178 b.Fatal(err)
179 }
180 data := map[string]any{"client_hello": "example.com"}
181
182 b.ReportAllocs()
183 b.ResetTimer()
184 for i := 0; i < b.N; i++ {
185 app.Emit(ctx, "tls_get_certificate", data)
186 }
187 }