orama/e2e/shared/webrtc_test.go

242 lines
6.4 KiB
Go

//go:build e2e
package shared_test
import (
"bytes"
"encoding/json"
"net/http"
"strings"
"testing"
"time"
e2e "github.com/DeBrosOfficial/network/e2e"
)
// turnCredentialsResponse is the expected response from the TURN credentials endpoint.
type turnCredentialsResponse struct {
URLs []string `json:"urls"`
Username string `json:"username"`
Credential string `json:"credential"`
TTL int `json:"ttl"`
}
// TestWebRTC_TURNCredentials_RequiresAuth verifies that the TURN credentials endpoint
// rejects unauthenticated requests.
func TestWebRTC_TURNCredentials_RequiresAuth(t *testing.T) {
e2e.SkipIfMissingGateway(t)
gatewayURL := e2e.GetGatewayURL()
client := e2e.NewHTTPClient(10 * time.Second)
req, err := http.NewRequest("POST", gatewayURL+"/v1/webrtc/turn/credentials", nil)
if err != nil {
t.Fatalf("failed to create request: %v", err)
}
resp, err := client.Do(req)
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusUnauthorized {
t.Fatalf("expected 401 Unauthorized, got %d", resp.StatusCode)
}
}
// TestWebRTC_TURNCredentials_ValidResponse verifies that authenticated requests to the
// TURN credentials endpoint return a valid credential structure.
func TestWebRTC_TURNCredentials_ValidResponse(t *testing.T) {
e2e.SkipIfMissingGateway(t)
gatewayURL := e2e.GetGatewayURL()
apiKey := e2e.GetAPIKey()
if apiKey == "" {
t.Skip("no API key configured")
}
client := e2e.NewHTTPClient(10 * time.Second)
req, err := http.NewRequest("POST", gatewayURL+"/v1/webrtc/turn/credentials", nil)
if err != nil {
t.Fatalf("failed to create request: %v", err)
}
req.Header.Set("Authorization", "Bearer "+apiKey)
resp, err := client.Do(req)
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Fatalf("expected 200 OK, got %d", resp.StatusCode)
}
var creds turnCredentialsResponse
if err := json.NewDecoder(resp.Body).Decode(&creds); err != nil {
t.Fatalf("failed to decode response: %v", err)
}
if len(creds.URLs) == 0 {
t.Fatal("expected at least one TURN URL")
}
if creds.Username == "" {
t.Fatal("expected non-empty username")
}
if creds.Credential == "" {
t.Fatal("expected non-empty credential")
}
if creds.TTL <= 0 {
t.Fatalf("expected positive TTL, got %d", creds.TTL)
}
}
// TestWebRTC_Rooms_RequiresAuth verifies that the rooms endpoint rejects unauthenticated requests.
func TestWebRTC_Rooms_RequiresAuth(t *testing.T) {
e2e.SkipIfMissingGateway(t)
gatewayURL := e2e.GetGatewayURL()
client := e2e.NewHTTPClient(10 * time.Second)
req, err := http.NewRequest("GET", gatewayURL+"/v1/webrtc/rooms", nil)
if err != nil {
t.Fatalf("failed to create request: %v", err)
}
resp, err := client.Do(req)
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusUnauthorized {
t.Fatalf("expected 401 Unauthorized, got %d", resp.StatusCode)
}
}
// TestWebRTC_Signal_RequiresAuth verifies that the signaling WebSocket rejects
// unauthenticated connections.
func TestWebRTC_Signal_RequiresAuth(t *testing.T) {
e2e.SkipIfMissingGateway(t)
gatewayURL := e2e.GetGatewayURL()
client := e2e.NewHTTPClient(10 * time.Second)
// Use regular HTTP GET to the signal endpoint — without auth it should return 401
// before WebSocket upgrade
req, err := http.NewRequest("GET", gatewayURL+"/v1/webrtc/signal?room=test-room", nil)
if err != nil {
t.Fatalf("failed to create request: %v", err)
}
resp, err := client.Do(req)
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusUnauthorized {
t.Fatalf("expected 401, got %d", resp.StatusCode)
}
}
// TestWebRTC_Rooms_CreateAndList verifies room creation and listing with proper auth.
func TestWebRTC_Rooms_CreateAndList(t *testing.T) {
e2e.SkipIfMissingGateway(t)
gatewayURL := e2e.GetGatewayURL()
apiKey := e2e.GetAPIKey()
if apiKey == "" {
t.Skip("no API key configured")
}
client := e2e.NewHTTPClient(10 * time.Second)
roomID := e2e.GenerateUniqueID("e2e-webrtc-room")
// Create room
createBody, _ := json.Marshal(map[string]string{"room_id": roomID})
req, err := http.NewRequest("POST", gatewayURL+"/v1/webrtc/rooms", bytes.NewReader(createBody))
if err != nil {
t.Fatalf("failed to create request: %v", err)
}
req.Header.Set("Authorization", "Bearer "+apiKey)
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
t.Fatalf("create room failed: %v", err)
}
resp.Body.Close()
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
t.Fatalf("expected 200/201, got %d", resp.StatusCode)
}
// List rooms
req, err = http.NewRequest("GET", gatewayURL+"/v1/webrtc/rooms", nil)
if err != nil {
t.Fatalf("failed to create request: %v", err)
}
req.Header.Set("Authorization", "Bearer "+apiKey)
resp, err = client.Do(req)
if err != nil {
t.Fatalf("list rooms failed: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Fatalf("expected 200, got %d", resp.StatusCode)
}
// Clean up: delete room
req, err = http.NewRequest("DELETE", gatewayURL+"/v1/webrtc/rooms?room_id="+roomID, nil)
if err != nil {
t.Fatalf("failed to create request: %v", err)
}
req.Header.Set("Authorization", "Bearer "+apiKey)
resp2, err := client.Do(req)
if err != nil {
t.Fatalf("delete room failed: %v", err)
}
resp2.Body.Close()
}
// TestWebRTC_PermissionsPolicy verifies the Permissions-Policy header allows camera and microphone.
func TestWebRTC_PermissionsPolicy(t *testing.T) {
e2e.SkipIfMissingGateway(t)
gatewayURL := e2e.GetGatewayURL()
apiKey := e2e.GetAPIKey()
if apiKey == "" {
t.Skip("no API key configured")
}
client := e2e.NewHTTPClient(10 * time.Second)
req, err := http.NewRequest("GET", gatewayURL+"/v1/webrtc/rooms", nil)
if err != nil {
t.Fatalf("failed to create request: %v", err)
}
req.Header.Set("Authorization", "Bearer "+apiKey)
resp, err := client.Do(req)
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close()
pp := resp.Header.Get("Permissions-Policy")
if pp == "" {
t.Skip("Permissions-Policy header not set")
}
if !strings.Contains(pp, "camera=(self)") {
t.Errorf("Permissions-Policy missing camera=(self), got: %s", pp)
}
if !strings.Contains(pp, "microphone=(self)") {
t.Errorf("Permissions-Policy missing microphone=(self), got: %s", pp)
}
}