Skip to content

Commit f5776c6

Browse files
test: integration test for proxy and 502 fallback
1 parent b41eb6b commit f5776c6

1 file changed

Lines changed: 151 additions & 0 deletions

File tree

proxy_test.go

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
package main
2+
3+
import (
4+
"crypto/rand"
5+
"crypto/rsa"
6+
"crypto/tls"
7+
"crypto/x509"
8+
"crypto/x509/pkix"
9+
"encoding/pem"
10+
"fmt"
11+
"io"
12+
"math/big"
13+
"net"
14+
"net/http"
15+
"net/http/httptest"
16+
"net/url"
17+
"os"
18+
"path/filepath"
19+
"strconv"
20+
"strings"
21+
"testing"
22+
"time"
23+
)
24+
25+
func TestProxy_RoundTrip(t *testing.T) {
26+
// 1. Dummy upstream on a random port.
27+
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
28+
fmt.Fprintf(w, "hello from %s", r.URL.Path)
29+
}))
30+
defer upstream.Close()
31+
upURL, _ := url.Parse(upstream.URL)
32+
upPort, _ := strconv.Atoi(upURL.Port())
33+
34+
// 2. Generate self-signed cert to a temp dir.
35+
dir := t.TempDir()
36+
certPath := filepath.Join(dir, "cert.pem")
37+
keyPath := filepath.Join(dir, "key.pem")
38+
writeSelfSigned(t, certPath, keyPath)
39+
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
40+
if err != nil {
41+
t.Fatal(err)
42+
}
43+
44+
// 3. Start TLS proxy on a random port.
45+
ln, err := tls.Listen("tcp", "127.0.0.1:0", &tls.Config{
46+
Certificates: []tls.Certificate{cert},
47+
MinVersion: tls.VersionTLS12,
48+
})
49+
if err != nil {
50+
t.Fatal(err)
51+
}
52+
events := make(chan Event, 8)
53+
srv := &http.Server{Handler: newProxyHandler(upPort, events)}
54+
go srv.Serve(ln)
55+
defer srv.Close()
56+
57+
// 4. HTTPS client with skip-verify (self-signed).
58+
client := &http.Client{
59+
Transport: &http.Transport{
60+
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
61+
},
62+
Timeout: 5 * time.Second,
63+
}
64+
65+
// 5. Round-trip.
66+
resp, err := client.Get("https://" + ln.Addr().String() + "/greet")
67+
if err != nil {
68+
t.Fatal(err)
69+
}
70+
defer resp.Body.Close()
71+
if resp.StatusCode != 200 {
72+
t.Fatalf("status = %d, want 200", resp.StatusCode)
73+
}
74+
body, _ := io.ReadAll(resp.Body)
75+
if !strings.Contains(string(body), "hello from /greet") {
76+
t.Fatalf("body = %q, want it to contain 'hello from /greet'", body)
77+
}
78+
79+
// 6. Event was published.
80+
select {
81+
case ev := <-events:
82+
if ev.Method != "GET" || ev.Path != "/greet" || ev.Status != 200 {
83+
t.Fatalf("bad event: %+v", ev)
84+
}
85+
case <-time.After(time.Second):
86+
t.Fatal("timed out waiting for event")
87+
}
88+
}
89+
90+
func TestProxy_UpstreamDown_Returns502(t *testing.T) {
91+
// Find a definitely-free port by opening then closing a listener.
92+
l, _ := net.Listen("tcp", "127.0.0.1:0")
93+
deadPort := l.Addr().(*net.TCPAddr).Port
94+
l.Close()
95+
96+
dir := t.TempDir()
97+
certPath := filepath.Join(dir, "cert.pem")
98+
keyPath := filepath.Join(dir, "key.pem")
99+
writeSelfSigned(t, certPath, keyPath)
100+
cert, _ := tls.LoadX509KeyPair(certPath, keyPath)
101+
102+
ln, _ := tls.Listen("tcp", "127.0.0.1:0", &tls.Config{
103+
Certificates: []tls.Certificate{cert},
104+
MinVersion: tls.VersionTLS12,
105+
})
106+
srv := &http.Server{Handler: newProxyHandler(deadPort, nil)}
107+
go srv.Serve(ln)
108+
defer srv.Close()
109+
110+
client := &http.Client{
111+
Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}},
112+
Timeout: 3 * time.Second,
113+
}
114+
resp, err := client.Get("https://" + ln.Addr().String() + "/")
115+
if err != nil {
116+
t.Fatal(err)
117+
}
118+
defer resp.Body.Close()
119+
if resp.StatusCode != http.StatusBadGateway {
120+
t.Fatalf("status = %d, want 502", resp.StatusCode)
121+
}
122+
}
123+
124+
func writeSelfSigned(t *testing.T, certPath, keyPath string) {
125+
t.Helper()
126+
key, err := rsa.GenerateKey(rand.Reader, 2048)
127+
if err != nil {
128+
t.Fatal(err)
129+
}
130+
tmpl := x509.Certificate{
131+
SerialNumber: big.NewInt(1),
132+
Subject: pkix.Name{CommonName: "test"},
133+
NotBefore: time.Now().Add(-time.Hour),
134+
NotAfter: time.Now().Add(time.Hour),
135+
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
136+
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
137+
IPAddresses: []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP("::1")},
138+
DNSNames: []string{"localhost"},
139+
}
140+
der, err := x509.CreateCertificate(rand.Reader, &tmpl, &tmpl, &key.PublicKey, key)
141+
if err != nil {
142+
t.Fatal(err)
143+
}
144+
certOut, _ := os.Create(certPath)
145+
pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: der})
146+
certOut.Close()
147+
148+
keyOut, _ := os.Create(keyPath)
149+
pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
150+
keyOut.Close()
151+
}

0 commit comments

Comments
 (0)