CI / go-test (push) Waiting to run
CI / postgres-durable-first (push) Waiting to run
CI / codegen (push) Waiting to run
CI / govulncheck (push) Waiting to run
CI / race (push) Waiting to run
CI / fuzz-smoke (push) Waiting to run
CI / golangci (push) Waiting to run
CI / frontend (push) Waiting to run
Release 3X-UI / build (386) (push) Waiting to run
Release 3X-UI / build (amd64) (push) Waiting to run
Release 3X-UI / build (arm64) (push) Waiting to run
Release 3X-UI / build (armv5) (push) Waiting to run
Release 3X-UI / build (armv6) (push) Waiting to run
Release 3X-UI / build (armv7) (push) Waiting to run
Release 3X-UI / build (s390x) (push) Waiting to run
Release 3X-UI / Build for Windows (amd64) (push) Waiting to run
Release 3X-UI / Publish rolling dev release (push) Blocked by required conditions
CodeQL Advanced / Analyze (go) (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
64 lines
1.8 KiB
Go
64 lines
1.8 KiB
Go
package controller
|
|
|
|
import (
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
ws "github.com/gorilla/websocket"
|
|
|
|
"github.com/mhsanaei/3x-ui/v3/internal/web/service"
|
|
)
|
|
|
|
// V2.0.2: /api/ws frame cadence follows the operator's fast-report
|
|
// interval (probe_fast_interval) instead of the hub's fixed 2 s tick.
|
|
// A mid-stream settings change re-paces a live socket: the timer
|
|
// already in flight still fires on the old cadence, the next one is
|
|
// armed from the re-read setting.
|
|
func TestProbeWebSocketCadenceFollowsFastInterval(t *testing.T) {
|
|
rig := newProbeTestRig(t)
|
|
_, _ = rig.seedAgent(t, "CadenceNode", true)
|
|
rig.setSetting(t, "public_page", "on")
|
|
rig.setSetting(t, "probe_fast_interval", "1")
|
|
service.InvalidateProbeSnapshot()
|
|
|
|
srv := httptest.NewServer(rig.engine)
|
|
defer srv.Close()
|
|
wsURL := "ws" + strings.TrimPrefix(srv.URL, "http") + "/api/ws"
|
|
|
|
conn, _, err := ws.DefaultDialer.Dial(wsURL, nil)
|
|
if err != nil {
|
|
t.Fatalf("dial: %v", err)
|
|
}
|
|
defer conn.Close()
|
|
|
|
readAt := func() time.Time {
|
|
t.Helper()
|
|
_ = conn.SetReadDeadline(time.Now().Add(10 * time.Second))
|
|
if _, _, err := conn.ReadMessage(); err != nil {
|
|
t.Fatalf("ws read: %v", err)
|
|
}
|
|
return time.Now()
|
|
}
|
|
|
|
_ = readAt() // first frame: immediate
|
|
prev := readAt()
|
|
for i := 0; i < 2; i++ {
|
|
now := readAt()
|
|
if gap := now.Sub(prev); gap < 500*time.Millisecond || gap > 2500*time.Millisecond {
|
|
t.Fatalf("frame gap at 1 s cadence: %v", gap)
|
|
}
|
|
prev = now
|
|
}
|
|
|
|
// Change to 3 s mid-stream: one in-flight 1 s frame, then the
|
|
// stream settles onto the new cadence without a reconnect.
|
|
rig.setSetting(t, "probe_fast_interval", "3")
|
|
prev = readAt()
|
|
now := readAt()
|
|
if gap := now.Sub(prev); gap < 2200*time.Millisecond || gap > 6*time.Second {
|
|
t.Fatalf("frame gap after change to 3 s: %v", gap)
|
|
}
|
|
}
|