test(chat,playout): enable test suite, coverage gate, switch to pure-Go SQLite driver
This commit is contained in:
1 parent
b3a10ba3ef
commit
e8a43b8a79
16 files changed
+3257
-8
No files matched your search
@@ -0,0 +1,190 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/glebarez/sqlite"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"chat/src/auth"
|
||||
"chat/src/db"
|
||||
"chat/src/ws"
|
||||
)
|
||||
|
||||
func TestHandleHealth(t *testing.T) {
|
||||
handler := HandleHealth()
|
||||
req := httptest.NewRequest("GET", "/health", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
handler(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("status = %d, want 200", w.Code)
|
||||
}
|
||||
|
||||
body := w.Body.String()
|
||||
if !strings.Contains(body, `"healthy"`) {
|
||||
t.Errorf("body missing healthy: %s", body)
|
||||
}
|
||||
if !strings.Contains(body, `"chat"`) {
|
||||
t.Errorf("body missing service name: %s", body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleNotFound(t *testing.T) {
|
||||
handler := HandleNotFound()
|
||||
req := httptest.NewRequest("GET", "/nonexistent", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
handler(w, req)
|
||||
|
||||
if w.Code != http.StatusNotFound {
|
||||
t.Errorf("status = %d, want 404", w.Code)
|
||||
}
|
||||
|
||||
body := w.Body.String()
|
||||
if !strings.Contains(body, `"not found"`) {
|
||||
t.Errorf("body missing not found: %s", body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleMetrics(t *testing.T) {
|
||||
gormDB, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open test DB: %v", err)
|
||||
}
|
||||
gormDB.AutoMigrate(&db.Message{}, &db.ModerationLog{})
|
||||
|
||||
// Add some test data
|
||||
gormDB.Create(&db.Message{Room: "main", Username: "u1", Text: "hi", Timestamp: time.Now(), Type: "public"})
|
||||
gormDB.Create(&db.ModerationLog{Action: "mute", Target: "u2", Moderator: "admin", Reason: "spam", Timestamp: time.Now()})
|
||||
|
||||
sessionStore := auth.NewSessionStore()
|
||||
hub := ws.NewHub(gormDB, nil, "test-instance", 10, 10*time.Second, "admin")
|
||||
hub.DMsSent = 5
|
||||
|
||||
handler := HandleMetrics(gormDB, nil, hub, sessionStore, "sqlite", "test-instance")
|
||||
req := httptest.NewRequest("GET", "/metrics", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
handler(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("status = %d, want 200", w.Code)
|
||||
}
|
||||
|
||||
body := w.Body.String()
|
||||
|
||||
// Check required metric names
|
||||
requiredMetrics := []string{
|
||||
"linearvoid_chat_connected_clients",
|
||||
"linearvoid_chat_messages_total",
|
||||
"linearvoid_chat_dms_total",
|
||||
"linearvoid_chat_moderation_actions_total",
|
||||
"linearvoid_chat_redis_enabled",
|
||||
"linearvoid_chat_redis_up",
|
||||
"linearvoid_chat_redis_connected_clients",
|
||||
"linearvoid_chat_admin_sessions_active",
|
||||
"linearvoid_chat_build_info",
|
||||
}
|
||||
|
||||
for _, metric := range requiredMetrics {
|
||||
if !strings.Contains(body, metric) {
|
||||
t.Errorf("body missing metric %s", metric)
|
||||
}
|
||||
}
|
||||
|
||||
// Check build_info has instance_id label
|
||||
if !strings.Contains(body, `instance_id="test-instance"`) {
|
||||
t.Error("build_info missing instance_id label")
|
||||
}
|
||||
|
||||
// Check values
|
||||
if !strings.Contains(body, "linearvoid_chat_messages_total 1") {
|
||||
t.Error("messages_total should be 1")
|
||||
}
|
||||
if !strings.Contains(body, "linearvoid_chat_moderation_actions_total 1") {
|
||||
t.Error("moderation_actions_total should be 1")
|
||||
}
|
||||
if !strings.Contains(body, "linearvoid_chat_dms_total 5") {
|
||||
t.Error("dms_total should be 5")
|
||||
}
|
||||
if !strings.Contains(body, "linearvoid_chat_redis_enabled 0") {
|
||||
t.Error("redis_enabled should be 0 (nil redis)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleMetrics_WrongMethod(t *testing.T) {
|
||||
handler := HandleMetrics(nil, nil, nil, nil, "", "")
|
||||
req := httptest.NewRequest("POST", "/metrics", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
handler(w, req)
|
||||
|
||||
if w.Code != http.StatusMethodNotAllowed {
|
||||
t.Errorf("status = %d, want 405", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleMetrics_WithRedis(t *testing.T) {
|
||||
gormDB, _ := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
||||
gormDB.AutoMigrate(&db.Message{}, &db.ModerationLog{})
|
||||
|
||||
// mockRedis for metrics test
|
||||
mr := &metricsMockRedis{}
|
||||
sessionStore := auth.NewSessionStore()
|
||||
hub := ws.NewHub(gormDB, mr, "test-instance", 10, 10*time.Second, "admin")
|
||||
|
||||
handler := HandleMetrics(gormDB, mr, hub, sessionStore, "sqlite", "inst-123")
|
||||
req := httptest.NewRequest("GET", "/metrics", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
handler(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("status = %d, want 200", w.Code)
|
||||
}
|
||||
|
||||
body := w.Body.String()
|
||||
if !strings.Contains(body, "linearvoid_chat_redis_enabled 1") {
|
||||
t.Error("redis_enabled should be 1")
|
||||
}
|
||||
if !strings.Contains(body, "linearvoid_chat_redis_up 1") {
|
||||
t.Error("redis_up should be 1")
|
||||
}
|
||||
if !strings.Contains(body, "linearvoid_chat_redis_connected_clients 5") {
|
||||
t.Error("redis_connected_clients should be 5")
|
||||
}
|
||||
}
|
||||
|
||||
// metricsMockRedis is a minimal mock for metrics tests.
|
||||
type metricsMockRedis struct{}
|
||||
|
||||
func (m *metricsMockRedis) Ping(ctx context.Context) error { return nil }
|
||||
func (m *metricsMockRedis) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error {
|
||||
return nil
|
||||
}
|
||||
func (m *metricsMockRedis) Get(ctx context.Context, key string) (string, error) { return "", nil }
|
||||
func (m *metricsMockRedis) Del(ctx context.Context, keys ...string) error { return nil }
|
||||
func (m *metricsMockRedis) Incr(ctx context.Context, key string) (int64, error) { return 0, nil }
|
||||
func (m *metricsMockRedis) Decr(ctx context.Context, key string) (int64, error) { return 0, nil }
|
||||
func (m *metricsMockRedis) Expire(ctx context.Context, key string, expiration time.Duration) error {
|
||||
return nil
|
||||
}
|
||||
func (m *metricsMockRedis) Exists(ctx context.Context, keys ...string) (int64, error) { return 0, nil }
|
||||
func (m *metricsMockRedis) Publish(ctx context.Context, channel string, message interface{}) error {
|
||||
return nil
|
||||
}
|
||||
func (m *metricsMockRedis) PSubscribe(ctx context.Context, channels ...string) db.PubSub { return nil }
|
||||
func (m *metricsMockRedis) Scan(ctx context.Context, cursor uint64, match string, count int64) ([]string, uint64, error) {
|
||||
return nil, 0, nil
|
||||
}
|
||||
func (m *metricsMockRedis) Info(ctx context.Context, sections ...string) (string, error) {
|
||||
return "connected_clients:5\nused_memory_human:1M\n", nil
|
||||
}
|
||||
func (m *metricsMockRedis) Close() error { return nil }
|
||||
Reference in new issue
Block a user