package main import ( "context" "sync" "testing" "time" "git.asio.asia/nixevol/NixMsg/internal/config" "github.com/mochi-mqtt/server/v2/packets" ) func TestServeShutdownWithLiveMQTT(t *testing.T) { dataDir := t.TempDir() cfgPath := writeTestConfig(t, dataDir) initAdminForTest(t, dataDir) enableRegistration(t, dataDir, "uplink-code") cfg, err := config.Load(cfgPath) if err != nil { t.Fatal(err) } if vErr := cfg.Validate(); vErr != nil { t.Fatal(vErr) } ctx, cancel := context.WithCancel(context.Background()) errCh := make(chan error, 1) go func() { errCh <- runServe(ctx, cfg) }() addr := waitListenAddr(t, dataDir, 15*time.Second) base := "http://" + addr registerEP(t, base, "alice", "password12", "Alice") registerEP(t, base, "bob", "password12", "Bob") ws := mqttSessionLogin(t, base, "alice", "password12") tcp := mqttSessionLoginTCP(t, addr, "bob", "password12") cancel() var gotWG sync.WaitGroup var wsReason, tcpReason byte var wsOK, tcpOK bool gotWG.Add(2) go func() { defer gotWG.Done() wsReason, wsOK = ws.disconnectReason(12 * time.Second) }() go func() { defer gotWG.Done() tcpReason, tcpOK = tcp.disconnectReason(12 * time.Second) }() select { case err := <-errCh: if err != nil { t.Fatalf("runServe: %v", err) } case <-time.After(15 * time.Second): t.Fatal("runServe did not return within 15s") } gotWG.Wait() want := packets.ErrServerShuttingDown.Code if !wsOK || wsReason != want { t.Fatalf("ws disconnect ok=%v reason=%#x want %#x", wsOK, wsReason, want) } if !tcpOK || tcpReason != want { t.Fatalf("tcp disconnect ok=%v reason=%#x want %#x", tcpOK, tcpReason, want) } ws.Close() tcp.Close() }