package api
import (
"context"
"errors"
"net"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
// zit says "cannot connect" for every way an upstream is unreachable.
// The fleet page must say which (bf5fbed5): the host no longer
// resolves, nothing listens, or TLS fails. A pull that failed for
// another reason, or whose upstream answers fine, gets no cause.
func TestADeadMirrorSaysWhyItCannotConnect(t *testing.T) {
ctx := context.Background()
cannot := errors.New("zit pull: cannot connect to the peer")
closed, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
refusedURL := "https://" + closed.Addr().String() + "/x"
closed.Close()
selfSigned := httptest.NewTLSServer(http.NotFoundHandler())
defer selfSigned.Close()
plain := httptest.NewServer(http.NotFoundHandler())
defer plain.Close()
cases := []struct {
name, url string
err error
hook string // a stable fragment of the cause, "" for none
}{
{"dns", "https://no-such-host.invalid/x", cannot, "does not resolve"},
{"refused", refusedURL, cannot, "refused"},
{"tls", selfSigned.URL + "/x", cannot, "TLS with"},
{"reachable", plain.URL + "/x", cannot, ""},
{"http status", "https://no-such-host.invalid/x", errors.New("zit pull: the peer answered HTTP 404 (Not Found)"), ""},
{"no error", "https://no-such-host.invalid/x", nil, ""},
}
for _, c := range cases {
got := connectCause(ctx, c.url, c.err)
if c.hook == "" && got != "" || c.hook != "" && !strings.Contains(got, c.hook) {
t.Errorf("FAIL %s: cause %q, want one containing %q", c.name, got, c.hook)
continue
}
t.Logf("ok %s: %q", c.name, got)
}
}