forked from redboxllc/scuttle
-
Notifications
You must be signed in to change notification settings - Fork 1
/
main_test.go
182 lines (163 loc) · 5.72 KB
/
main_test.go
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
package main
import (
"context"
"errors"
"fmt"
"net/http"
"net/http/httptest"
"os"
"testing"
"time"
)
var (
goodServer *httptest.Server
goodEventuallyServer *httptest.Server
badServer *httptest.Server
genericQuitServer *httptest.Server
testsInit bool = false
envoyDelayTimestamp int64 = 0
envoyDelayMax int64 = 15
)
// Sets up minimum env variables and mock http servers
// Can be called multiple times, but will only init once per test session
func initTestingEnv() {
// Always update env variables for new test
os.Setenv("SCUTTLE_LOGGING", "true")
config = getConfig()
// Do not restart http servers for each test
if testsInit {
return
}
fmt.Println("Initiating test HTTP servers")
// Always 200 and live envoy state
goodServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("{\"state\": \"LIVE\"}")) // Envoy live response
}))
// 503 for 5 requests, then 200 + live envoy state
goodEventuallyServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
timeSinceStarted := time.Now().Unix() - envoyDelayTimestamp
if timeSinceStarted < envoyDelayMax {
fmt.Println("Status Unavailable")
w.WriteHeader(http.StatusServiceUnavailable)
return
}
w.Write([]byte("{\"state\": \"LIVE\"}")) // Envoy live response
}))
// Always 503
badServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println("Status Unavailable")
w.WriteHeader(http.StatusServiceUnavailable)
}))
genericQuitServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println("Status Ok")
w.WriteHeader(http.StatusOK)
}))
testsInit = true
}
// Inits the test environment and starts the blocking
// Set any env variables for your specific tests prior to calling this
// Pass in a negative integer to block but skip kill
func initAndRun(exitCode int) {
initTestingEnv()
if blockingCtx := waitForEnvoy(); blockingCtx != nil {
<-blockingCtx.Done()
err := blockingCtx.Err()
if err == nil || errors.Is(err, context.Canceled) {
log("Blocking finished, Envoy has started")
} else if errors.Is(err, context.DeadlineExceeded) {
panic(errors.New("timeout reached while waiting for Envoy to start"))
} else {
panic(err.Error())
}
}
if exitCode >= 0 {
kill(exitCode)
}
}
// Tests START_WITHOUT_ENVOY works with failing envoy mock server
func TestBlockingDisabled(t *testing.T) {
fmt.Println("Starting TestBlockingDisabled")
os.Setenv("START_WITHOUT_ENVOY", "true")
initAndRun(-1)
// If your tests hang and never finish, this test "failed"
// Also try go test -timeout <seconds>s
}
// Tests block function with working envoy mock server
func TestBlockingEnabled(t *testing.T) {
fmt.Println("Starting TestBlockingEnabled")
os.Setenv("START_WITHOUT_ENVOY", "false")
os.Setenv("ENVOY_ADMIN_API", goodServer.URL)
initAndRun(-1)
}
// Tests block function with envoy mock server that fails for 15 seconds, then works
func TestSlowEnvoy(t *testing.T) {
fmt.Println("Starting TestSlowEnvoy")
os.Setenv("START_WITHOUT_ENVOY", "false")
os.Setenv("ENVOY_ADMIN_API", goodEventuallyServer.URL)
envoyDelayTimestamp = time.Now().Unix()
initAndRun(-1)
}
// Tests generic quit endpoints are sent
func TestGenericQuitEndpoints(t *testing.T) {
fmt.Println("Starting TestGenericQuitEndpoints")
// Valid URLs dont matter, just need something that will generate an HTTP response
// 127.0.0.1:1111/idontexist is to verify we don't panic if a nonexistent URL is given
// notaurl^^ is to verify a malformatted URL does not result in panic
os.Setenv("GENERIC_QUIT_ENDPOINTS", "https://google.com/, https://github.com/, 127.0.0.1:1111/idontexist, notaurl^^ ")
initTestingEnv()
killGenericEndpoints()
}
// Tests scuttle does not fail when the /quitquitquit endpoint does not return a response
func TestNoQuitQuitQuitResponse(t *testing.T) {
fmt.Println("Starting TestNoQuitQuitQuitResponse")
os.Setenv("START_WITHOUT_ENVOY", "false")
os.Setenv("ISTIO_QUIT_API", "127.0.0.1:1111/idontexist")
initTestingEnv()
killIstioWithAPI()
}
// Tests scuttle does not fail when the /quitquitquit endpoint is not a valid URL
func TestNoQuitQuitQuitMalformedUrl(t *testing.T) {
fmt.Println("Starting TestNoQuitQuitQuitMalformedUrl")
os.Setenv("START_WITHOUT_ENVOY", "false")
os.Setenv("ISTIO_QUIT_API", "notaurl^^")
initTestingEnv()
killIstioWithAPI()
}
// Tests scuttle waits
func TestWaitTillTimeoutForEnvoy(t *testing.T) {
fmt.Println("Starting TestWaitTillTimeoutForEnvoy")
os.Setenv("QUIT_WITHOUT_ENVOY_TIMEOUT", "500ms")
os.Setenv("ENVOY_ADMIN_API", badServer.URL)
initTestingEnv()
dur, _ := time.ParseDuration("500ms")
config.QuitWithoutEnvoyTimeout = dur
blockingCtx := waitForEnvoy()
if blockingCtx == nil {
t.Fatal("Blocking context was nil")
}
select {
case <-time.After(1 * time.Second):
t.Fatal("Context did not timeout")
case <-blockingCtx.Done():
if !errors.Is(blockingCtx.Err(), context.DeadlineExceeded) {
t.Fatalf("Context contains wrong error: %s", blockingCtx.Err())
}
}
}
// Tests scuttle will continue after WAIT_FOR_ENVOY_TIMEOUT expires and envoy is not ready
func TestWaitForEnvoyTimeoutContinueWithoutEnvoy(t *testing.T) {
fmt.Println("Starting TestWaitForEnvoyTimeoutContinueWithoutEnvoy")
os.Setenv("WAIT_FOR_ENVOY_TIMEOUT", "5s")
os.Setenv("ENVOY_ADMIN_API", badServer.URL)
initTestingEnv()
blockingCtx := waitForEnvoy()
<-blockingCtx.Done()
err := blockingCtx.Err()
if err == nil || !errors.Is(err, context.DeadlineExceeded) {
fmt.Println("TestWaitForEnvoyTimeoutContinueWithoutEnvoy err", err)
// Err is nil (envoy is up)
// or Err is set, but is not a cancellation err
// we expect a cancellation when the time is up
t.Fail()
}
}