From 3b73d720f193eada2a854e99687e2430159bb948 Mon Sep 17 00:00:00 2001 From: samosvalishe Date: Thu, 21 May 2026 02:02:23 +0300 Subject: [PATCH] =?UTF-8?q?test:=20=D0=BF=D0=BE=D0=BA=D1=80=D1=8B=D1=82?= =?UTF-8?q?=D1=8C=20NopAuthenticator,=20GenerateSelfSignedCert,=20Handshak?= =?UTF-8?q?eSem?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Минимальное покрытие для заготовки auth и хелперов dtlsdial: - NopAuthenticator.Authenticate возвращает (Anonymous, nil) - GenerateSelfSignedCert выдаёт рабочий сертификат с приватным ключом - HandshakeSem блокирует захват при заполнении и уважает отмену ctx Также документирует на Authenticator, что интерфейс stream-ориентирован; auth UDP-режима получит отдельный token-based интерфейс. --- internal/auth/auth.go | 5 +++ internal/auth/auth_test.go | 13 +++++++ .../transport/dtlsdial/handshakesem_test.go | 39 +++++++++++++++++++ .../transport/dtlsdial/selfsigned_test.go | 16 ++++++++ 4 files changed, 73 insertions(+) create mode 100644 internal/auth/auth_test.go create mode 100644 internal/transport/dtlsdial/handshakesem_test.go create mode 100644 internal/transport/dtlsdial/selfsigned_test.go diff --git a/internal/auth/auth.go b/internal/auth/auth.go index f4dcd11..c649807 100644 --- a/internal/auth/auth.go +++ b/internal/auth/auth.go @@ -20,6 +20,11 @@ const Anonymous TenantID = "" // A nil error with [Anonymous] means the connection is accepted in // non-multi-tenant mode. Any non-nil error must be treated as a rejection // and the caller must close conn. +// +// This interface is stream-oriented: it consumes a net.Conn and is intended +// for bondserver/tcpfwdserver wiring. UDP-mode auth (when needed) will get +// a separate interface taking a token []byte read out-of-band from the +// handshake, since udpserver has no per-tenant stream abstraction. type Authenticator interface { Authenticate(ctx context.Context, conn net.Conn) (TenantID, error) } diff --git a/internal/auth/auth_test.go b/internal/auth/auth_test.go new file mode 100644 index 0000000..6cae62a --- /dev/null +++ b/internal/auth/auth_test.go @@ -0,0 +1,13 @@ +package auth + +import "testing" + +func TestNopAuthenticatorReturnsAnonymous(t *testing.T) { + tenant, err := NopAuthenticator{}.Authenticate(t.Context(), nil) + if err != nil { + t.Fatalf("NopAuthenticator.Authenticate: %v", err) + } + if tenant != Anonymous { + t.Fatalf("tenant = %q want Anonymous (%q)", tenant, Anonymous) + } +} diff --git a/internal/transport/dtlsdial/handshakesem_test.go b/internal/transport/dtlsdial/handshakesem_test.go new file mode 100644 index 0000000..3cf894e --- /dev/null +++ b/internal/transport/dtlsdial/handshakesem_test.go @@ -0,0 +1,39 @@ +package dtlsdial + +import ( + "context" + "errors" + "net" + "testing" + "time" +) + +// TestHandshakeSemBlocksWhenFull verifies the contract: when HandshakeSem +// is at capacity, a new Dial blocks on the slot acquisition and respects +// ctx cancellation. Validates the bound that prevents unbounded concurrent +// handshakes under high -n values. +func TestHandshakeSemBlocksWhenFull(t *testing.T) { + sem := make(chan struct{}, 1) + sem <- struct{}{} // pre-fill: cap = 1, full + + d := &Dialer{HandshakeSem: sem} + + pc, err := net.ListenPacket("udp", "127.0.0.1:0") + if err != nil { + t.Fatalf("listen: %v", err) + } + defer pc.Close() + peer := &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 1} + + ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) + defer cancel() + + start := time.Now() + _, err = d.Dial(ctx, pc, peer) + if !errors.Is(err, context.DeadlineExceeded) { + t.Fatalf("err = %v want DeadlineExceeded", err) + } + if elapsed := time.Since(start); elapsed < 40*time.Millisecond { + t.Fatalf("Dial returned too fast (%v); expected to block on sem", elapsed) + } +} diff --git a/internal/transport/dtlsdial/selfsigned_test.go b/internal/transport/dtlsdial/selfsigned_test.go new file mode 100644 index 0000000..8e41e33 --- /dev/null +++ b/internal/transport/dtlsdial/selfsigned_test.go @@ -0,0 +1,16 @@ +package dtlsdial + +import "testing" + +func TestGenerateSelfSignedCert(t *testing.T) { + cert, err := GenerateSelfSignedCert() + if err != nil { + t.Fatalf("GenerateSelfSignedCert: %v", err) + } + if len(cert.Certificate) == 0 { + t.Fatal("certificate chain is empty") + } + if cert.PrivateKey == nil { + t.Fatal("private key is nil") + } +}