package tlscheck_test import ( "context" "crypto/tls" "net" "net/http" "net/http/httptest" "testing" "time" "sneak.berlin/go/dnswatcher/internal/tlscheck" ) func startTLSServer( t *testing.T, ) (*httptest.Server, string, int) { t.Helper() srv := httptest.NewTLSServer( http.HandlerFunc( func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) }, ), ) addr, ok := srv.Listener.Addr().(*net.TCPAddr) if !ok { t.Fatal("unexpected address type") } return srv, addr.IP.String(), addr.Port } func TestCheckCertificateValid(t *testing.T) { t.Parallel() srv, ip, port := startTLSServer(t) defer srv.Close() checker := tlscheck.NewStandalone( tlscheck.WithTimeout(5 * time.Second), tlscheck.WithTLSConfig(&tls.Config{ //nolint:gosec // test uses self-signed cert InsecureSkipVerify: true, }), tlscheck.WithPort(port), ) info, err := checker.CheckCertificate( context.Background(), ip, "localhost", ) if err != nil { t.Fatalf("unexpected error: %v", err) } if info == nil { t.Fatal("expected non-nil CertificateInfo") } if info.NotAfter.IsZero() { t.Error("expected non-zero NotAfter") } if info.SerialNumber == "" { t.Error("expected non-empty SerialNumber") } } func TestCheckCertificateConnectionRefused(t *testing.T) { t.Parallel() lc := &net.ListenConfig{} ln, err := lc.Listen( context.Background(), "tcp", "127.0.0.1:0", ) if err != nil { t.Fatalf("failed to listen: %v", err) } addr, ok := ln.Addr().(*net.TCPAddr) if !ok { t.Fatal("unexpected address type") } port := addr.Port _ = ln.Close() checker := tlscheck.NewStandalone( tlscheck.WithTimeout(2*time.Second), tlscheck.WithPort(port), ) _, err = checker.CheckCertificate( context.Background(), "127.0.0.1", "localhost", ) if err == nil { t.Fatal("expected error for connection refused") } } func TestCheckCertificateContextCanceled(t *testing.T) { t.Parallel() ctx, cancel := context.WithCancel(context.Background()) cancel() checker := tlscheck.NewStandalone( tlscheck.WithTimeout(2 * time.Second), tlscheck.WithPort(1), ) _, err := checker.CheckCertificate( ctx, "127.0.0.1", "localhost", ) if err == nil { t.Fatal("expected error for canceled context") } } func TestCheckCertificateTimeout(t *testing.T) { t.Parallel() checker := tlscheck.NewStandalone( tlscheck.WithTimeout(1 * time.Millisecond), tlscheck.WithPort(1), ) _, err := checker.CheckCertificate( context.Background(), "192.0.2.1", "example.com", ) if err == nil { t.Fatal("expected error for timeout") } } func TestCheckCertificateSANs(t *testing.T) { t.Parallel() srv, ip, port := startTLSServer(t) defer srv.Close() checker := tlscheck.NewStandalone( tlscheck.WithTimeout(5*time.Second), tlscheck.WithTLSConfig(&tls.Config{ //nolint:gosec // test uses self-signed cert InsecureSkipVerify: true, }), tlscheck.WithPort(port), ) info, err := checker.CheckCertificate( context.Background(), ip, "localhost", ) if err != nil { t.Fatalf("unexpected error: %v", err) } if info.CommonName == "" && len(info.SubjectAlternativeNames) == 0 { t.Error("expected CN or SANs to be populated") } }