From 8e98ad3438846d823da6449bc5e3a43c1b0f7ff3 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Thu, 26 Oct 2023 10:38:22 +0200 Subject: [PATCH] Add tests for dialout messages. --- backend_server_test.go | 264 +++++++++++++++++++++++++++++++++++++++++ hub_test.go | 211 ++++++++++++++++++++++++++++++++ testclient_test.go | 12 ++ 3 files changed, 487 insertions(+) diff --git a/backend_server_test.go b/backend_server_test.go index 983924e..a950b5c 100644 --- a/backend_server_test.go +++ b/backend_server_test.go @@ -1789,3 +1789,267 @@ func Test_IsNumeric(t *testing.T) { } } } + +func TestBackendServer_DialoutNoSipBridge(t *testing.T) { + _, _, _, hub, _, server := CreateBackendServerForTest(t) + + client := NewTestClient(t, server, hub) + defer client.CloseWithBye() + if err := client.SendHelloInternal(); err != nil { + t.Fatal(err) + } + + ctx, cancel := context.WithTimeout(context.Background(), testTimeout) + defer cancel() + + _, err := client.RunUntilHello(ctx) + if err != nil { + t.Fatal(err) + } + + roomId := "12345" + msg := &BackendServerRoomRequest{ + Type: "dialout", + Dialout: &BackendRoomDialoutRequest{ + Number: "+1234567890", + }, + } + + data, err := json.Marshal(msg) + if err != nil { + t.Fatal(err) + } + res, err := performBackendRequest(server.URL+"/api/v1/room/"+roomId, data) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + body, err := io.ReadAll(res.Body) + if err != nil { + t.Error(err) + } + if res.StatusCode != http.StatusNotFound { + t.Fatalf("Expected error %d, got %s: %s", http.StatusNotFound, res.Status, string(body)) + } + + var response BackendServerRoomResponse + if err := json.Unmarshal(body, &response); err != nil { + t.Fatal(err) + } + + if response.Type != "dialout" || response.Dialout == nil { + t.Fatalf("expected type dialout, got %s", string(body)) + } + if response.Dialout.Error == nil { + t.Fatalf("expected dialout error, got %s", string(body)) + } + if expected := "no_client_available"; response.Dialout.Error.Code != expected { + t.Errorf("expected error code %s, got %s", expected, string(body)) + } +} + +func TestBackendServer_DialoutAccepted(t *testing.T) { + _, _, _, hub, _, server := CreateBackendServerForTest(t) + + client := NewTestClient(t, server, hub) + defer client.CloseWithBye() + if err := client.SendHelloInternalWithFeatures([]string{"start-dialout"}); err != nil { + t.Fatal(err) + } + + ctx, cancel := context.WithTimeout(context.Background(), testTimeout) + defer cancel() + + _, err := client.RunUntilHello(ctx) + if err != nil { + t.Fatal(err) + } + + roomId := "12345" + callId := "call-123" + + stopped := make(chan struct{}) + go func() { + defer close(stopped) + + msg, err := client.RunUntilMessage(ctx) + if err != nil { + t.Error(err) + return + } + + if msg.Type != "internal" || msg.Internal.Type != "dialout" { + t.Errorf("expected internal dialout message, got %+v", msg) + return + } + + if msg.Internal.Dialout.RoomId != roomId { + t.Errorf("expected room id %s, got %+v", roomId, msg) + } + + response := &ClientMessage{ + Id: msg.Id, + Type: "internal", + Internal: &InternalClientMessage{ + Type: "dialout", + Dialout: &DialoutInternalClientMessage{ + Type: "status", + RoomId: msg.Internal.Dialout.RoomId, + Status: &DialoutStatusInternalClientMessage{ + Status: "accepted", + CallId: callId, + }, + }, + }, + } + if err := client.WriteJSON(response); err != nil { + t.Error(err) + } + }() + + defer func() { + <-stopped + }() + + msg := &BackendServerRoomRequest{ + Type: "dialout", + Dialout: &BackendRoomDialoutRequest{ + Number: "+1234567890", + }, + } + + data, err := json.Marshal(msg) + if err != nil { + t.Fatal(err) + } + res, err := performBackendRequest(server.URL+"/api/v1/room/"+roomId, data) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + body, err := io.ReadAll(res.Body) + if err != nil { + t.Error(err) + } + if res.StatusCode != http.StatusOK { + t.Fatalf("Expected error %d, got %s: %s", http.StatusOK, res.Status, string(body)) + } + + var response BackendServerRoomResponse + if err := json.Unmarshal(body, &response); err != nil { + t.Fatal(err) + } + + if response.Type != "dialout" || response.Dialout == nil { + t.Fatalf("expected type dialout, got %s", string(body)) + } + if response.Dialout.Error != nil { + t.Fatalf("expected dialout success, got %s", string(body)) + } + if response.Dialout.CallId != callId { + t.Errorf("expected call id %s, got %s", callId, string(body)) + } +} + +func TestBackendServer_DialoutRejected(t *testing.T) { + _, _, _, hub, _, server := CreateBackendServerForTest(t) + + client := NewTestClient(t, server, hub) + defer client.CloseWithBye() + if err := client.SendHelloInternalWithFeatures([]string{"start-dialout"}); err != nil { + t.Fatal(err) + } + + ctx, cancel := context.WithTimeout(context.Background(), testTimeout) + defer cancel() + + _, err := client.RunUntilHello(ctx) + if err != nil { + t.Fatal(err) + } + + roomId := "12345" + errorCode := "error-code" + errorMessage := "rejected call" + + stopped := make(chan struct{}) + go func() { + defer close(stopped) + + msg, err := client.RunUntilMessage(ctx) + if err != nil { + t.Error(err) + return + } + + if msg.Type != "internal" || msg.Internal.Type != "dialout" { + t.Errorf("expected internal dialout message, got %+v", msg) + return + } + + if msg.Internal.Dialout.RoomId != roomId { + t.Errorf("expected room id %s, got %+v", roomId, msg) + } + + response := &ClientMessage{ + Id: msg.Id, + Type: "internal", + Internal: &InternalClientMessage{ + Type: "dialout", + Dialout: &DialoutInternalClientMessage{ + Type: "error", + Error: NewError(errorCode, errorMessage), + }, + }, + } + if err := client.WriteJSON(response); err != nil { + t.Error(err) + } + }() + + defer func() { + <-stopped + }() + + msg := &BackendServerRoomRequest{ + Type: "dialout", + Dialout: &BackendRoomDialoutRequest{ + Number: "+1234567890", + }, + } + + data, err := json.Marshal(msg) + if err != nil { + t.Fatal(err) + } + res, err := performBackendRequest(server.URL+"/api/v1/room/"+roomId, data) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + body, err := io.ReadAll(res.Body) + if err != nil { + t.Error(err) + } + if res.StatusCode != http.StatusBadGateway { + t.Fatalf("Expected error %d, got %s: %s", http.StatusBadGateway, res.Status, string(body)) + } + + var response BackendServerRoomResponse + if err := json.Unmarshal(body, &response); err != nil { + t.Fatal(err) + } + + if response.Type != "dialout" || response.Dialout == nil { + t.Fatalf("expected type dialout, got %s", string(body)) + } + if response.Dialout.Error == nil { + t.Fatalf("expected dialout error, got %s", string(body)) + } + if response.Dialout.Error.Code != errorCode { + t.Errorf("expected error code %s, got %s", errorCode, string(body)) + } + if response.Dialout.Error.Message != errorMessage { + t.Errorf("expected error message %s, got %s", errorMessage, string(body)) + } +} diff --git a/hub_test.go b/hub_test.go index 9bfa242..90b5f93 100644 --- a/hub_test.go +++ b/hub_test.go @@ -5349,3 +5349,214 @@ func TestGeoipOverrides(t *testing.T) { t.Errorf("expected country %s, got %s", strings.ToUpper(country3), country) } } + +func TestDialoutStatus(t *testing.T) { + _, _, _, hub, _, server := CreateBackendServerForTest(t) + + internalClient := NewTestClient(t, server, hub) + defer internalClient.CloseWithBye() + if err := internalClient.SendHelloInternalWithFeatures([]string{"start-dialout"}); err != nil { + t.Fatal(err) + } + + ctx, cancel := context.WithTimeout(context.Background(), testTimeout) + defer cancel() + + _, err := internalClient.RunUntilHello(ctx) + if err != nil { + t.Fatal(err) + } + + roomId := "12345" + client := NewTestClient(t, server, hub) + defer client.CloseWithBye() + + if err := client.SendHello(testDefaultUserId); err != nil { + t.Fatal(err) + } + + hello, err := client.RunUntilHello(ctx) + if err != nil { + t.Fatal(err) + } + + if _, err := client.JoinRoom(ctx, roomId); err != nil { + t.Fatal(err) + } + + if err := client.RunUntilJoined(ctx, hello.Hello); err != nil { + t.Error(err) + } + + callId := "call-123" + + stopped := make(chan struct{}) + go func(client *TestClient) { + defer close(stopped) + + msg, err := client.RunUntilMessage(ctx) + if err != nil { + t.Error(err) + return + } + + if msg.Type != "internal" || msg.Internal.Type != "dialout" { + t.Errorf("expected internal dialout message, got %+v", msg) + return + } + + if msg.Internal.Dialout.RoomId != roomId { + t.Errorf("expected room id %s, got %+v", roomId, msg) + } + + response := &ClientMessage{ + Id: msg.Id, + Type: "internal", + Internal: &InternalClientMessage{ + Type: "dialout", + Dialout: &DialoutInternalClientMessage{ + Type: "status", + RoomId: msg.Internal.Dialout.RoomId, + Status: &DialoutStatusInternalClientMessage{ + Status: "accepted", + CallId: callId, + }, + }, + }, + } + if err := client.WriteJSON(response); err != nil { + t.Error(err) + } + }(internalClient) + + defer func() { + <-stopped + }() + + msg := &BackendServerRoomRequest{ + Type: "dialout", + Dialout: &BackendRoomDialoutRequest{ + Number: "+1234567890", + }, + } + + data, err := json.Marshal(msg) + if err != nil { + t.Fatal(err) + } + res, err := performBackendRequest(server.URL+"/api/v1/room/"+roomId, data) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + body, err := io.ReadAll(res.Body) + if err != nil { + t.Error(err) + } + if res.StatusCode != http.StatusOK { + t.Fatalf("Expected error %d, got %s: %s", http.StatusOK, res.Status, string(body)) + } + + var response BackendServerRoomResponse + if err := json.Unmarshal(body, &response); err != nil { + t.Fatal(err) + } + + if response.Type != "dialout" || response.Dialout == nil { + t.Fatalf("expected type dialout, got %s", string(body)) + } + if response.Dialout.Error != nil { + t.Fatalf("expected dialout success, got %s", string(body)) + } + if response.Dialout.CallId != callId { + t.Errorf("expected call id %s, got %s", callId, string(body)) + } + + key := "callstatus_" + callId + if msg, err := client.RunUntilMessage(ctx); err != nil { + t.Fatal(err) + } else { + if err := checkMessageTransientSet(msg, key, map[string]interface{}{ + "callid": callId, + "status": "accepted", + }, nil); err != nil { + t.Error(err) + } + } + + if err := internalClient.SendInternalDialout(&DialoutInternalClientMessage{ + RoomId: roomId, + Type: "status", + Status: &DialoutStatusInternalClientMessage{ + CallId: callId, + Status: "ringing", + }, + }); err != nil { + t.Fatal(err) + } + + if msg, err := client.RunUntilMessage(ctx); err != nil { + t.Fatal(err) + } else { + if err := checkMessageTransientSet(msg, key, map[string]interface{}{ + "callid": callId, + "status": "ringing", + }, + map[string]interface{}{ + "callid": callId, + "status": "accepted", + }); err != nil { + t.Error(err) + } + } + + old := removeCallStatusTTL + defer func() { + removeCallStatusTTL = old + }() + removeCallStatusTTL = 500 * time.Millisecond + + clearedCause := "cleared-call" + if err := internalClient.SendInternalDialout(&DialoutInternalClientMessage{ + RoomId: roomId, + Type: "status", + Status: &DialoutStatusInternalClientMessage{ + CallId: callId, + Status: "cleared", + Cause: clearedCause, + }, + }); err != nil { + t.Fatal(err) + } + + if msg, err := client.RunUntilMessage(ctx); err != nil { + t.Fatal(err) + } else { + if err := checkMessageTransientSet(msg, key, map[string]interface{}{ + "callid": callId, + "status": "cleared", + "cause": clearedCause, + }, + map[string]interface{}{ + "callid": callId, + "status": "ringing", + }); err != nil { + t.Error(err) + } + } + + ctx2, cancel := context.WithTimeout(ctx, removeCallStatusTTL*2) + defer cancel() + + if msg, err := client.RunUntilMessage(ctx2); err != nil { + t.Fatal(err) + } else { + if err := checkMessageTransientRemove(msg, key, map[string]interface{}{ + "callid": callId, + "status": "cleared", + "cause": clearedCause, + }); err != nil { + t.Error(err) + } + } +} diff --git a/testclient_test.go b/testclient_test.go index acb64e6..a3d0251 100644 --- a/testclient_test.go +++ b/testclient_test.go @@ -578,6 +578,18 @@ func (c *TestClient) SendInternalRemoveSession(msg *RemoveSessionInternalClientM return c.WriteJSON(message) } +func (c *TestClient) SendInternalDialout(msg *DialoutInternalClientMessage) error { + message := &ClientMessage{ + Id: "abcd", + Type: "internal", + Internal: &InternalClientMessage{ + Type: "dialout", + Dialout: msg, + }, + } + return c.WriteJSON(message) +} + func (c *TestClient) SetTransientData(key string, value interface{}, ttl time.Duration) error { payload, err := json.Marshal(value) if err != nil {