// NewTestController creates a new *Controller for // the input specified, with a filename of "Testfile". // The Config is bare, consisting only of a Root of cwd. // // Used primarily for testing but needs to be exported so // add-ons can use this as a convenience. Does not initialize // the server-block-related fields. func NewTestController(input string) *Controller { return &Controller{ instance: &Instance{serverType: ""}, Dispenser: caddyfile.NewDispenser("Testfile", strings.NewReader(input)), OncePerServerBlock: func(f func() error) error { return f() }, } }
func TestReverseProxyRetry(t *testing.T) { log.SetOutput(ioutil.Discard) defer log.SetOutput(os.Stderr) // set up proxy backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { io.Copy(w, r.Body) r.Body.Close() })) defer backend.Close() su, err := NewStaticUpstreams(caddyfile.NewDispenser("Testfile", strings.NewReader(` proxy / localhost:65535 localhost:65534 `+backend.URL+` { policy round_robin fail_timeout 5s max_fails 1 try_duration 5s try_interval 250ms } `))) if err != nil { t.Fatal(err) } p := &Proxy{ Next: httpserver.EmptyNext, // prevents panic in some cases when test fails Upstreams: su, } // middle is required to simulate closable downstream request body middle := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, err = p.ServeHTTP(w, r) if err != nil { t.Error(err) } })) defer middle.Close() testcase := "test content" r, err := http.NewRequest("POST", middle.URL, bytes.NewBufferString(testcase)) if err != nil { t.Fatal(err) } resp, err := http.DefaultTransport.RoundTrip(r) if err != nil { t.Fatal(err) } b, err := ioutil.ReadAll(resp.Body) resp.Body.Close() if err != nil { t.Fatal(err) } if string(b) != testcase { t.Fatalf("string(b) = %s, want %s", string(b), testcase) } }
// NewTestController creates a new Controller for // the server type and input specified. The filename // is "Testfile". If the server type is not empty and // is plugged in, a context will be created so that // the results of setup functions can be checked for // correctness. // // Used only for testing, but exported so plugins can // use this for convenience. func NewTestController(serverType, input string) *Controller { var ctx Context if stype, err := getServerType(serverType); err == nil { ctx = stype.NewContext() } return &Controller{ instance: &Instance{serverType: serverType, context: ctx}, Dispenser: caddyfile.NewDispenser("Testfile", strings.NewReader(input)), OncePerServerBlock: func(f func() error) error { return f() }, } }
func TestParseBlockHealthCheck(t *testing.T) { tests := []struct { config string interval string timeout string }{ // Test #1: Both options set correct time {"health_check /health\n health_check_interval 10s\n health_check_timeout 20s", "10s", "20s"}, // Test #2: Health check options flipped around. Making sure health_check doesn't overwrite it {"health_check_interval 10s\n health_check_timeout 20s\n health_check /health", "10s", "20s"}, // Test #3: No health_check options. So default. {"health_check /health", "30s", "1m0s"}, // Test #4: Interval sets it to 15s and timeout defaults {"health_check /health\n health_check_interval 15s", "15s", "1m0s"}, // Test #5: Timeout sets it to 15s and interval defaults {"health_check /health\n health_check_timeout 15s", "30s", "15s"}, // Test #6: Some funky spelling to make sure it still defaults {"health_check /health health_check_time 15s", "30s", "1m0s"}, } for i, test := range tests { u := staticUpstream{} c := caddyfile.NewDispenser("Testfile", strings.NewReader(test.config)) for c.Next() { parseBlock(&c, &u) } if u.HealthCheck.Interval.String() != test.interval { t.Errorf( "Test %d: HealthCheck interval not the same from config. Got %v. Expected: %v", i+1, u.HealthCheck.Interval, test.interval, ) } if u.HealthCheck.Timeout.String() != test.timeout { t.Errorf( "Test %d: HealthCheck timeout not the same from config. Got %v. Expected: %v", i+1, u.HealthCheck.Timeout, test.timeout, ) } } }
func TestParseBlock(t *testing.T) { r, _ := http.NewRequest("GET", "/", nil) tests := []struct { config string }{ // Test #1: transparent preset {"proxy / localhost:8080 {\n transparent \n}"}, // Test #2: transparent preset with another param {"proxy / localhost:8080 {\n transparent \nproxy_header X-Test Tester \n}"}, // Test #3: transparent preset on multiple sites {"proxy / localhost:8080 {\n transparent \n} \nproxy /api localhost:8081 { \ntransparent \n}"}, } for i, test := range tests { upstreams, err := NewStaticUpstreams(caddyfile.NewDispenser("Testfile", strings.NewReader(test.config))) if err != nil { t.Error("Expected no error. Got:", err.Error()) } for _, upstream := range upstreams { headers := upstream.Select(r).UpstreamHeaders if _, ok := headers["Host"]; !ok { t.Errorf("Test %d: Could not find the Host header", i+1) } if _, ok := headers["X-Real-Ip"]; !ok { t.Errorf("Test %d: Could not find the X-Real-Ip header", i+1) } if _, ok := headers["X-Forwarded-Proto"]; !ok { t.Errorf("Test %d: Could not find the X-Forwarded-Proto header", i+1) } } } }