135 lines
4.5 KiB
Go
135 lines
4.5 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"strconv"
|
|
"testing"
|
|
)
|
|
|
|
func TestMessageCreateReturnsFullPayload(t *testing.T) {
|
|
server, _ := setupTestServer(t)
|
|
userID, token := mustSignup(t, server.URL, "full-msg")
|
|
peerID, _ := mustSignup(t, server.URL, "full-msg-peer")
|
|
|
|
convResp := postJSONAuth(t, server.URL+"/conversations", token, createConversationRequest{
|
|
UserIDs: []uint{userID, peerID},
|
|
})
|
|
if convResp.StatusCode != http.StatusOK {
|
|
t.Fatalf("create conversation: %d", convResp.StatusCode)
|
|
}
|
|
var conv map[string]interface{}
|
|
json.NewDecoder(convResp.Body).Decode(&conv)
|
|
convID := uint(conv["id"].(float64))
|
|
|
|
msgResp := postJSON(t, server.URL+"/conversations/"+strconv.FormatUint(uint64(convID), 10)+"/messages", sendMessageRequest{
|
|
SenderID: userID,
|
|
Text: "hello full",
|
|
})
|
|
if msgResp.StatusCode != http.StatusOK {
|
|
t.Fatalf("send: %d", msgResp.StatusCode)
|
|
}
|
|
var out map[string]interface{}
|
|
json.NewDecoder(msgResp.Body).Decode(&out)
|
|
for _, key := range []string{"id", "conversation_id", "sender_id", "sender_mode", "text", "retracted"} {
|
|
if _, ok := out[key]; !ok {
|
|
t.Fatalf("missing key %s in %v", key, out)
|
|
}
|
|
}
|
|
if out["text"] != "hello full" || out["sender_mode"] != "human" {
|
|
t.Fatalf("unexpected payload %v", out)
|
|
}
|
|
}
|
|
|
|
func TestDeviceTokenAndSessions(t *testing.T) {
|
|
server, _ := setupTestServer(t)
|
|
userID, token := mustSignup(t, server.URL, "devices")
|
|
|
|
reg := postJSONAuth(t, server.URL+"/users/"+strconv.FormatUint(uint64(userID), 10)+"/device-tokens", token, registerDeviceRequest{
|
|
Token: "fcm-test-token-abc",
|
|
Platform: "android",
|
|
})
|
|
if reg.StatusCode != http.StatusOK {
|
|
t.Fatalf("device token: %d", reg.StatusCode)
|
|
}
|
|
|
|
req, _ := http.NewRequest(http.MethodGet, server.URL+"/users/"+strconv.FormatUint(uint64(userID), 10)+"/sessions", nil)
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer resp.Body.Close()
|
|
var sout map[string]interface{}
|
|
json.NewDecoder(resp.Body).Decode(&sout)
|
|
sessions := sout["sessions"].([]interface{})
|
|
if len(sessions) < 1 {
|
|
t.Fatalf("expected at least one session, got %v", sout)
|
|
}
|
|
first := sessions[0].(map[string]interface{})
|
|
if first["is_current"] != true {
|
|
t.Fatalf("expected current session flag, got %v", first)
|
|
}
|
|
}
|
|
|
|
func TestRevokeSessionAndPushTestWithoutFCM(t *testing.T) {
|
|
server, _ := setupTestServer(t)
|
|
userID, token := mustSignup(t, server.URL, "revoke")
|
|
|
|
// Second login via invite re-use is blocked; mint another session by signup of peer then
|
|
// just revoke the only session after listing.
|
|
req, _ := http.NewRequest(http.MethodGet, server.URL+"/users/"+strconv.FormatUint(uint64(userID), 10)+"/sessions", nil)
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var sout map[string]interface{}
|
|
json.NewDecoder(resp.Body).Decode(&sout)
|
|
resp.Body.Close()
|
|
sessions := sout["sessions"].([]interface{})
|
|
sid := uint(sessions[0].(map[string]interface{})["id"].(float64))
|
|
|
|
del := deleteJSONAuth(t, server.URL+"/users/"+strconv.FormatUint(uint64(userID), 10)+"/sessions/"+strconv.FormatUint(uint64(sid), 10), token)
|
|
if del.StatusCode != http.StatusOK {
|
|
t.Fatalf("revoke: %d", del.StatusCode)
|
|
}
|
|
|
|
// Push test without FCM_SERVER_KEY should soft-skip.
|
|
push := postJSONAuth(t, server.URL+"/admin/push-test", "test-admin-token", map[string]interface{}{
|
|
"user_id": userID,
|
|
"title": "t",
|
|
"body": "b",
|
|
})
|
|
if push.StatusCode != http.StatusOK {
|
|
t.Fatalf("push-test: %d", push.StatusCode)
|
|
}
|
|
var pout map[string]interface{}
|
|
json.NewDecoder(push.Body).Decode(&pout)
|
|
// Without device tokens / FCM key: sent==0 and a skipped_reason is expected.
|
|
if pout["sent"].(float64) != 0 {
|
|
t.Fatalf("expected zero sent without FCM tokens, got %v", pout)
|
|
}
|
|
if pout["skipped_reason"] == nil || pout["skipped_reason"] == "" {
|
|
t.Fatalf("expected skipped_reason, got %v", pout)
|
|
}
|
|
}
|
|
|
|
func TestAdminMetricsIncludesDraftLatencyFields(t *testing.T) {
|
|
server, _ := setupTestServer(t)
|
|
req, _ := http.NewRequest(http.MethodGet, server.URL+"/admin/metrics", nil)
|
|
req.Header.Set("Authorization", "Bearer test-admin-token")
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer resp.Body.Close()
|
|
var out map[string]interface{}
|
|
json.NewDecoder(resp.Body).Decode(&out)
|
|
for _, key := range []string{"draft_requests", "draft_error_rate", "draft_latency_avg_ms", "escalate_error_rate"} {
|
|
if _, ok := out[key]; !ok {
|
|
t.Fatalf("missing metrics key %s in %v", key, out)
|
|
}
|
|
}
|
|
}
|