🎉 live server seems to be working now
This commit is contained in:
139
third_party/sendspin-go/pkg/sendspin/client_discovery_integration_test.go
vendored
Normal file
139
third_party/sendspin-go/pkg/sendspin/client_discovery_integration_test.go
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
// ABOUTME: Integration test for server-initiated client discovery
|
||||
// ABOUTME: Fakes an mDNS advertisement and verifies the server dials + handshakes
|
||||
|
||||
package sendspin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Sendspin/sendspin-go/pkg/protocol"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/hashicorp/mdns"
|
||||
)
|
||||
|
||||
func TestServerDiscoversAndDialsClient(t *testing.T) {
|
||||
// mDNS multicast is unreliable in some environments (CI sandboxes,
|
||||
// Windows boxes with strict firewalls or Hyper-V virtual switches).
|
||||
// Opt in with SENDSPIN_MULTICAST_TESTS=1 when running locally.
|
||||
if os.Getenv("SENDSPIN_MULTICAST_TESTS") == "" {
|
||||
t.Skip("requires multicast; set SENDSPIN_MULTICAST_TESTS=1 to enable")
|
||||
}
|
||||
|
||||
// 1. Stand up a fake "player" HTTP server that upgrades to WS and
|
||||
// sends client/hello.
|
||||
upgrader := websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}
|
||||
playerReady := make(chan string, 1) // receives serverID via server/hello
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
t.Errorf("upgrade: %v", err)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
hello := protocol.Message{
|
||||
Type: "client/hello",
|
||||
Payload: protocol.ClientHello{
|
||||
ClientID: "test-player-1",
|
||||
Name: "Test Player",
|
||||
SupportedRoles: []string{"player@v1"},
|
||||
},
|
||||
}
|
||||
data, _ := json.Marshal(hello)
|
||||
if err := conn.WriteMessage(websocket.TextMessage, data); err != nil {
|
||||
t.Errorf("write hello: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
_, resp, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var msg protocol.Message
|
||||
if err := json.Unmarshal(resp, &msg); err != nil {
|
||||
return
|
||||
}
|
||||
if msg.Type == "server/hello" {
|
||||
playerReady <- "ok"
|
||||
}
|
||||
|
||||
// Block until the server closes us.
|
||||
for {
|
||||
if _, _, err := conn.ReadMessage(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
_, portStr, err := net.SplitHostPort(strings.TrimPrefix(ts.URL, "http://"))
|
||||
if err != nil {
|
||||
t.Fatalf("split host: %v", err)
|
||||
}
|
||||
port, _ := strconv.Atoi(portStr)
|
||||
|
||||
// 2. Advertise an mDNS _sendspin._tcp record pointing at httptest.
|
||||
ips := []net.IP{net.ParseIP("127.0.0.1")}
|
||||
svc, err := mdns.NewMDNSService(
|
||||
"test-player-instance",
|
||||
"_sendspin._tcp",
|
||||
"",
|
||||
"",
|
||||
port,
|
||||
ips,
|
||||
[]string{"path=/", "name=Test Player"},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("mdns service: %v", err)
|
||||
}
|
||||
mdnsServer, err := mdns.NewServer(&mdns.Config{Zone: svc})
|
||||
if err != nil {
|
||||
t.Fatalf("mdns server: %v", err)
|
||||
}
|
||||
defer mdnsServer.Shutdown()
|
||||
|
||||
// 3. Start a Sendspin server with DiscoverClients=true.
|
||||
source := NewTestTone(48000, 2)
|
||||
srv, err := NewServer(ServerConfig{
|
||||
Port: findFreePort(t),
|
||||
Name: "Test Server",
|
||||
Source: source,
|
||||
EnableMDNS: false,
|
||||
DiscoverClients: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("NewServer: %v", err)
|
||||
}
|
||||
|
||||
serverDone := make(chan error, 1)
|
||||
go func() { serverDone <- srv.Start() }()
|
||||
defer srv.Stop()
|
||||
|
||||
// 4. Wait for the player to confirm it received server/hello.
|
||||
select {
|
||||
case <-playerReady:
|
||||
// success
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Fatal("timed out waiting for dialed handshake")
|
||||
}
|
||||
}
|
||||
|
||||
// findFreePort returns a TCP port that is free at call time.
|
||||
func findFreePort(t *testing.T) int {
|
||||
t.Helper()
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("listen: %v", err)
|
||||
}
|
||||
defer l.Close()
|
||||
return l.Addr().(*net.TCPAddr).Port
|
||||
}
|
||||
Reference in New Issue
Block a user