mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-13 17:09:07 +02:00
Signal can report a successful start and then stop with exit code 0, or continue without a listener, when a listener fails. Supervisors and operators do not see the failure. Stop at startup when the Let's Encrypt challenge listener cannot bind. Keep a failure that occurs before the run loop waits, and return a non-zero exit code after a server failure. A listener that is closed during shutdown is not a failure.
93 lines
2.6 KiB
Go
93 lines
2.6 KiB
Go
package cmd
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"net"
|
|
"net/http"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"golang.org/x/crypto/acme"
|
|
"golang.org/x/crypto/acme/autocert"
|
|
)
|
|
|
|
func setLetsencryptListen(t *testing.T, port int, address string) {
|
|
t.Helper()
|
|
oldPort, oldAddress := signalPort, signalLetsencryptListen
|
|
signalPort, signalLetsencryptListen = port, address
|
|
t.Cleanup(func() {
|
|
signalPort, signalLetsencryptListen = oldPort, oldAddress
|
|
})
|
|
}
|
|
|
|
func drainStopCh(t *testing.T) {
|
|
t.Helper()
|
|
t.Cleanup(func() {
|
|
select {
|
|
case <-stopCh:
|
|
default:
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestStartServerWithCertManager_CustomAddress(t *testing.T) {
|
|
drainStopCh(t)
|
|
setLetsencryptListen(t, 10000, "127.0.0.1:0")
|
|
|
|
listener, err := startServerWithCertManager(&autocert.Manager{}, http.NotFoundHandler())
|
|
require.NoError(t, err)
|
|
require.NotNil(t, listener, "challenge listener should be created on the configured address")
|
|
t.Cleanup(func() { _ = listener.Close() })
|
|
|
|
conn, err := net.DialTimeout("tcp", listener.Addr().String(), time.Second)
|
|
require.NoError(t, err)
|
|
require.NoError(t, conn.Close())
|
|
}
|
|
|
|
func TestStartServerWithCertManager_BindFailure(t *testing.T) {
|
|
occupied, err := net.Listen("tcp", "127.0.0.1:0")
|
|
require.NoError(t, err)
|
|
t.Cleanup(func() { _ = occupied.Close() })
|
|
setLetsencryptListen(t, 10000, occupied.Addr().String())
|
|
|
|
listener, err := startServerWithCertManager(&autocert.Manager{}, http.NotFoundHandler())
|
|
require.Error(t, err)
|
|
require.Nil(t, listener, "no listener should be returned when the bind fails")
|
|
}
|
|
|
|
func TestCertManagerTLSConfigAnswersTLSALPN01(t *testing.T) {
|
|
// Disabling the separate listener relies on the main listener answering
|
|
// TLS-ALPN-01 challenges through the cert manager's TLS config.
|
|
cfg := (&autocert.Manager{}).TLSConfig()
|
|
require.Contains(t, cfg.NextProtos, acme.ALPNProto, "cert manager TLS config should offer the ACME TLS-ALPN protocol")
|
|
}
|
|
|
|
func TestServeHTTP_ClosedListenerIsNotAFailure(t *testing.T) {
|
|
drainStopCh(t)
|
|
listener, err := tls.Listen("tcp", "127.0.0.1:0", (&autocert.Manager{}).TLSConfig())
|
|
require.NoError(t, err)
|
|
|
|
serveHTTP(listener, http.NotFoundHandler())
|
|
require.NoError(t, listener.Close())
|
|
|
|
select {
|
|
case code := <-stopCh:
|
|
t.Fatalf("closing the listener reported a failure with code %d", code)
|
|
case <-time.After(200 * time.Millisecond):
|
|
}
|
|
}
|
|
|
|
func TestNotifyStop_KeepsEarlyFailure(t *testing.T) {
|
|
drainStopCh(t)
|
|
|
|
notifyStop("failed before the run loop waits")
|
|
|
|
select {
|
|
case code := <-stopCh:
|
|
require.Equal(t, 1, code, "an early failure should be reported with stop code 1")
|
|
default:
|
|
t.Fatal("a failure reported before the run loop waits was dropped")
|
|
}
|
|
}
|