Files
olcrtc/internal/runtime/runtime_test.go
zarazaex69 f469bd72af refactor: extract shared session runtime into internal/runtime
server.go and client.go each carried byte-identical copies of
smuxConfig (~20 lines), setupCipher (~18 lines), and the health
bookkeeping pair recordSession/Pong/Missed/Unhealthy/Reconnect plus a
private healthMu+status+notifyHealth scaffold. Same code, twice.

Add internal/runtime exposing:
- SetupCipher, SmuxConfig, MaxPayload — common construction helpers,
  ErrKeyRequired/ErrKeySize re-exported from runtime so existing
  errors.Is checks on server.ErrKeyRequired etc. keep working.
- HealthTracker — nil-safe wrapper around control.Status with
  RecordSession/Pong/Missed/Unhealthy/Reconnect that publishes through an
  OnHealth callback supplied at construction.

server and client now hold a *runtime.HealthTracker instead of their own
mu+status+notify scaffolds. recordX methods on Server/Client are now
one-liners that forward to the tracker. smuxConfig(0) replaces the prior
variadic smuxConfig() in test call sites; nil-safe Status()/update() on
HealthTracker means tests that build raw &Server{}/&Client{} no longer
need to wire up a tracker for the records to be no-ops.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 14:24:46 +03:00

85 lines
2.3 KiB
Go

package runtime_test
import (
"errors"
"testing"
"time"
"github.com/openlibrecommunity/olcrtc/internal/control"
"github.com/openlibrecommunity/olcrtc/internal/runtime"
)
func TestSetupCipherErrors(t *testing.T) {
if _, err := runtime.SetupCipher(""); !errors.Is(err, runtime.ErrKeyRequired) {
t.Fatalf("empty key error = %v, want ErrKeyRequired", err)
}
if _, err := runtime.SetupCipher("notHex"); err == nil {
t.Fatalf("bad hex error = nil")
}
if _, err := runtime.SetupCipher("00"); !errors.Is(err, runtime.ErrKeySize) {
t.Fatalf("short key error = %v, want ErrKeySize", err)
}
}
func TestSetupCipherSuccess(t *testing.T) {
key := "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff"
c, err := runtime.SetupCipher(key)
if err != nil {
t.Fatalf("SetupCipher() error = %v", err)
}
if c == nil {
t.Fatal("SetupCipher() returned nil cipher")
}
}
func TestSmuxConfigDefault(t *testing.T) {
cfg := runtime.SmuxConfig(0)
if cfg.Version != 2 || cfg.MaxFrameSize != 32768 {
t.Fatalf("SmuxConfig(0) = %+v", cfg)
}
}
func TestSmuxConfigShrinks(t *testing.T) {
// 100-byte wire payload minus crypto overhead is far below default 32768,
// so MaxFrameSize must shrink.
cfg := runtime.SmuxConfig(100)
if cfg.MaxFrameSize >= 32768 {
t.Fatalf("MaxFrameSize = %d, want shrunk", cfg.MaxFrameSize)
}
}
func TestHealthTrackerEmitsOnEveryChange(t *testing.T) {
var got []control.Status
h := runtime.NewHealthTracker(func(s control.Status) {
got = append(got, s)
})
h.RecordSession("s1")
h.RecordPong(control.Health{LastSeen: time.Unix(100, 0), RTT: time.Millisecond})
h.RecordMissed(2)
h.RecordReconnect()
h.RecordUnhealthy(3)
if len(got) != 5 {
t.Fatalf("notify count = %d, want 5", len(got))
}
if got[0].SessionID != "s1" {
t.Fatalf("first snapshot session id = %q", got[0].SessionID)
}
if got[1].LastRTT != time.Millisecond {
t.Fatalf("second snapshot rtt = %v", got[1].LastRTT)
}
final := h.Status()
if final.Reconnects != 1 || final.UnhealthyEvents != 1 || final.MissedPongs != 3 {
t.Fatalf("final snapshot = %+v", final)
}
}
func TestHealthTrackerNilNotifyOK(t *testing.T) {
h := runtime.NewHealthTracker(nil)
h.RecordSession("s") // must not panic
if h.Status().SessionID != "s" {
t.Fatal("Status() did not record without notify")
}
}