Files
Charon/backend/internal/api/handlers/logs_ws_test_utils.go
T
GitHub Actions e299aa6b52 feat(tests): enhance test coverage and error handling across various components
- Added a test case in CrowdSecConfig to show improved error message when preset is not cached.
- Introduced a new test suite for the Dashboard component, verifying counts and health status.
- Updated SMTPSettings tests to utilize a shared render function and added tests for backend validation errors.
- Modified Security.audit tests to improve input handling and removed redundant export failure test.
- Refactored Security tests to remove export functionality and ensure correct rendering of components.
- Enhanced UsersPage tests with new scenarios for updating user permissions and manual invite link flow.
- Created a new utility for rendering components with a QueryClient and MemoryRouter for better test isolation.
- Updated go-test-coverage script to improve error handling and coverage reporting.
2025-12-11 00:26:07 +00:00

101 lines
2.8 KiB
Go

package handlers
import (
"bytes"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/require"
"github.com/Wikid82/charon/backend/internal/logger"
)
// webSocketTestServer wraps a test HTTP server and broadcast hook for WebSocket tests.
type webSocketTestServer struct {
server *httptest.Server
url string
hook *logger.BroadcastHook
}
// resetLogger reinitializes the global logger with an in-memory buffer to avoid cross-test leakage.
func resetLogger(t *testing.T) *logger.BroadcastHook {
t.Helper()
var buf bytes.Buffer
logger.Init(true, &buf)
return logger.GetBroadcastHook()
}
// newWebSocketTestServer builds a gin router exposing the WebSocket handler and starts an httptest server.
func newWebSocketTestServer(t *testing.T) *webSocketTestServer {
t.Helper()
gin.SetMode(gin.TestMode)
hook := resetLogger(t)
router := gin.New()
router.GET("/logs/live", LogsWebSocketHandler)
srv := httptest.NewServer(router)
t.Cleanup(srv.Close)
wsURL := "ws" + strings.TrimPrefix(srv.URL, "http")
return &webSocketTestServer{server: srv, url: wsURL, hook: hook}
}
// dial opens a WebSocket connection to the provided path and asserts upgrade success.
func (s *webSocketTestServer) dial(t *testing.T, path string) *websocket.Conn {
t.Helper()
conn, resp, err := websocket.DefaultDialer.Dial(s.url+path, nil)
require.NoError(t, err)
require.NotNil(t, resp)
require.Equal(t, http.StatusSwitchingProtocols, resp.StatusCode)
t.Cleanup(func() {
_ = resp.Body.Close()
})
conn.SetReadLimit(1 << 20)
t.Cleanup(func() {
_ = conn.Close()
})
return conn
}
// sendEntry broadcasts a log entry through the shared hook.
func (s *webSocketTestServer) sendEntry(t *testing.T, lvl logrus.Level, msg string, fields logrus.Fields) {
t.Helper()
entry := &logrus.Entry{
Level: lvl,
Message: msg,
Time: time.Now().UTC(),
Data: fields,
}
require.NoError(t, s.hook.Fire(entry))
}
// readLogEntry reads a LogEntry from the WebSocket with a short deadline to avoid flakiness.
func readLogEntry(t *testing.T, conn *websocket.Conn) LogEntry {
t.Helper()
require.NoError(t, conn.SetReadDeadline(time.Now().Add(5*time.Second)))
var entry LogEntry
require.NoError(t, conn.ReadJSON(&entry))
return entry
}
// waitForListenerCount waits until the broadcast hook reports the desired listener count.
func waitForListenerCount(t *testing.T, hook *logger.BroadcastHook, expected int) {
t.Helper()
require.Eventually(t, func() bool {
return hook.ActiveListeners() == expected
}, 2*time.Second, 20*time.Millisecond)
}
// subscriberIDs introspects the broadcast hook to return the active subscriber IDs.
func (s *webSocketTestServer) subscriberIDs(t *testing.T) []string {
t.Helper()
return s.hook.ListenerIDs()
}