@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 158 lines 4.16 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 network
16
17 import (
18 "context"
19 "errors"
20 "testing"
21 "time"
22
23 "go.uber.org/zap"
24 )
25
26 func TestLookupGate(t *testing.T) {
27 g := newLookupGate(2, 1)
28 for i := range 2 {
29 if err := g.acquire(context.Background()); err != nil {
30 t.Fatalf("acquire %d: %v", i, err)
31 }
32 }
33
34 // the third caller queues; with the queue then full, a fourth is shed
35 queued := make(chan error, 1)
36 queuedCtx, cancelQueued := context.WithCancel(context.Background())
37 go func() { queued <- g.acquire(queuedCtx) }()
38 for g.pending.Load() != 1 {
39 time.Sleep(time.Millisecond)
40 }
41 if err := g.acquire(context.Background()); !errors.Is(err, errTooManyLookups) {
42 t.Fatalf("acquire with full queue: err = %v, want errTooManyLookups", err)
43 }
44
45 // a queued caller can give up
46 cancelQueued()
47 if err := <-queued; !errors.Is(err, context.Canceled) {
48 t.Fatalf("cancelled queued acquire: err = %v, want context.Canceled", err)
49 }
50
51 // and a released slot is usable again
52 g.release()
53 if err := g.acquire(context.Background()); err != nil {
54 t.Fatalf("acquire after release: %v", err)
55 }
56 }
57
58 func TestEvictedResetMarkerRejectsStaleLookup(t *testing.T) {
59 c := newCache("test")
60 started := make(chan struct{})
61 release := make(chan struct{})
62 done := make(chan error, 1)
63
64 go func() {
65 _, err := c.get(context.Background(), "key", time.Minute, 0, zap.NewNop(), func(context.Context) ([]Target, error) {
66 close(started)
67 <-release
68 return []Target{{Host: "old.example"}}, nil
69 })
70 done <- err
71 }()
72 <-started
73
74 c.reset("key")
75 c.mu.Lock()
76 delete(c.entries, "key")
77 c.mu.Unlock()
78 close(release)
79
80 if err := <-done; err != nil {
81 t.Fatal(err)
82 }
83 c.mu.RLock()
84 _, exists := c.entries["key"]
85 c.mu.RUnlock()
86 if exists {
87 t.Fatal("lookup repopulated an entry after its reset marker was evicted")
88 }
89 }
90
91 func TestDifferentGracePoliciesDoNotShareLookup(t *testing.T) {
92 for _, tc := range []struct {
93 name string
94 graceFirst bool
95 }{
96 {name: "no grace first"},
97 {name: "grace first", graceFirst: true},
98 } {
99 t.Run(tc.name, func(t *testing.T) {
100 c := newCache("test")
101 c.entries["key"] = cacheEntry{
102 refresh: time.Minute,
103 freshness: time.Now().Add(-time.Hour),
104 targets: []Target{{Host: "stale.example"}},
105 }
106
107 started := make(chan struct{}, 2)
108 release := make(chan struct{})
109 lookup := func(context.Context) ([]Target, error) {
110 started <- struct{}{}
111 <-release
112 return nil, errors.New("lookup failed")
113 }
114 type result struct {
115 targets []Target
116 err error
117 }
118 start := func(grace time.Duration) <-chan result {
119 ch := make(chan result, 1)
120 go func() {
121 targets, err := c.get(context.Background(), "key", time.Minute, grace, zap.NewNop(), lookup)
122 ch <- result{targets, err}
123 }()
124 return ch
125 }
126
127 firstGrace := time.Duration(0)
128 secondGrace := time.Minute
129 if tc.graceFirst {
130 firstGrace, secondGrace = secondGrace, firstGrace
131 }
132 first := start(firstGrace)
133 <-started
134 second := start(secondGrace)
135 select {
136 case <-started:
137 case <-time.After(time.Second):
138 close(release)
139 <-first
140 <-second
141 t.Fatalf("different grace policies shared one lookup")
142 }
143 close(release)
144
145 firstResult := <-first
146 secondResult := <-second
147 if tc.graceFirst {
148 firstResult, secondResult = secondResult, firstResult
149 }
150 if firstResult.err == nil {
151 t.Fatal("caller without grace did not receive the lookup error")
152 }
153 if secondResult.err != nil || len(secondResult.targets) != 1 || secondResult.targets[0].Host != "stale.example" {
154 t.Fatalf("caller with grace: targets = %v, err = %v", secondResult.targets, secondResult.err)
155 }
156 })
157 }
158 }