fix: Restore all files lost during destructive rebase
A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.
This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).
Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
407
consent-service/internal/handlers/communication_handlers_test.go
Normal file
407
consent-service/internal/handlers/communication_handlers_test.go
Normal file
@@ -0,0 +1,407 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// TestGetCommunicationStatus_NoServices tests status with no services configured
|
||||
func TestGetCommunicationStatus_NoServices_ReturnsDisabled(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
// Create handler with no services
|
||||
handler := NewCommunicationHandlers(nil, nil)
|
||||
|
||||
router := gin.New()
|
||||
router.GET("/api/v1/communication/status", handler.GetCommunicationStatus)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/api/v1/communication/status", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status 200, got %d", w.Code)
|
||||
}
|
||||
|
||||
var response map[string]interface{}
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("Failed to parse response: %v", err)
|
||||
}
|
||||
|
||||
// Check matrix is disabled
|
||||
matrix, ok := response["matrix"].(map[string]interface{})
|
||||
if !ok {
|
||||
t.Fatal("Expected matrix in response")
|
||||
}
|
||||
if matrix["enabled"] != false {
|
||||
t.Error("Expected matrix.enabled to be false")
|
||||
}
|
||||
|
||||
// Check jitsi is disabled
|
||||
jitsi, ok := response["jitsi"].(map[string]interface{})
|
||||
if !ok {
|
||||
t.Fatal("Expected jitsi in response")
|
||||
}
|
||||
if jitsi["enabled"] != false {
|
||||
t.Error("Expected jitsi.enabled to be false")
|
||||
}
|
||||
|
||||
// Check timestamp exists
|
||||
if _, ok := response["timestamp"]; !ok {
|
||||
t.Error("Expected timestamp in response")
|
||||
}
|
||||
}
|
||||
|
||||
// TestCreateRoom_NoMatrixService tests room creation without Matrix
|
||||
func TestCreateRoom_NoMatrixService_Returns503(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
handler := NewCommunicationHandlers(nil, nil)
|
||||
|
||||
router := gin.New()
|
||||
router.POST("/api/v1/communication/rooms", handler.CreateRoom)
|
||||
|
||||
body := `{"type": "class_info", "class_name": "5b"}`
|
||||
req, _ := http.NewRequest("POST", "/api/v1/communication/rooms", bytes.NewBufferString(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusServiceUnavailable {
|
||||
t.Errorf("Expected status 503, got %d", w.Code)
|
||||
}
|
||||
|
||||
var response map[string]string
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("Failed to parse response: %v", err)
|
||||
}
|
||||
|
||||
if response["error"] != "Matrix service not configured" {
|
||||
t.Errorf("Unexpected error message: %s", response["error"])
|
||||
}
|
||||
}
|
||||
|
||||
// TestCreateRoom_InvalidBody tests room creation with invalid body
|
||||
func TestCreateRoom_InvalidBody_Returns400(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
handler := NewCommunicationHandlers(nil, nil)
|
||||
|
||||
router := gin.New()
|
||||
router.POST("/api/v1/communication/rooms", handler.CreateRoom)
|
||||
|
||||
req, _ := http.NewRequest("POST", "/api/v1/communication/rooms", bytes.NewBufferString("{invalid"))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
// Service unavailable check happens first, so we get 503
|
||||
// This is expected behavior - service check before body validation
|
||||
if w.Code != http.StatusServiceUnavailable {
|
||||
t.Errorf("Expected status 503, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
// TestInviteUser_NoMatrixService tests invite without Matrix
|
||||
func TestInviteUser_NoMatrixService_Returns503(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
handler := NewCommunicationHandlers(nil, nil)
|
||||
|
||||
router := gin.New()
|
||||
router.POST("/api/v1/communication/rooms/invite", handler.InviteUser)
|
||||
|
||||
body := `{"room_id": "!abc:server", "user_id": "@user:server"}`
|
||||
req, _ := http.NewRequest("POST", "/api/v1/communication/rooms/invite", bytes.NewBufferString(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusServiceUnavailable {
|
||||
t.Errorf("Expected status 503, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
// TestSendMessage_NoMatrixService tests message sending without Matrix
|
||||
func TestSendMessage_NoMatrixService_Returns503(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
handler := NewCommunicationHandlers(nil, nil)
|
||||
|
||||
router := gin.New()
|
||||
router.POST("/api/v1/communication/messages", handler.SendMessage)
|
||||
|
||||
body := `{"room_id": "!abc:server", "message": "Hello"}`
|
||||
req, _ := http.NewRequest("POST", "/api/v1/communication/messages", bytes.NewBufferString(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusServiceUnavailable {
|
||||
t.Errorf("Expected status 503, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
// TestSendNotification_NoMatrixService tests notification without Matrix
|
||||
func TestSendNotification_NoMatrixService_Returns503(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
handler := NewCommunicationHandlers(nil, nil)
|
||||
|
||||
router := gin.New()
|
||||
router.POST("/api/v1/communication/notifications", handler.SendNotification)
|
||||
|
||||
body := `{"room_id": "!abc:server", "type": "absence", "student_name": "Max"}`
|
||||
req, _ := http.NewRequest("POST", "/api/v1/communication/notifications", bytes.NewBufferString(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusServiceUnavailable {
|
||||
t.Errorf("Expected status 503, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
// TestCreateMeeting_NoJitsiService tests meeting creation without Jitsi
|
||||
func TestCreateMeeting_NoJitsiService_Returns503(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
handler := NewCommunicationHandlers(nil, nil)
|
||||
|
||||
router := gin.New()
|
||||
router.POST("/api/v1/communication/meetings", handler.CreateMeeting)
|
||||
|
||||
body := `{"type": "quick", "display_name": "Teacher"}`
|
||||
req, _ := http.NewRequest("POST", "/api/v1/communication/meetings", bytes.NewBufferString(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusServiceUnavailable {
|
||||
t.Errorf("Expected status 503, got %d", w.Code)
|
||||
}
|
||||
|
||||
var response map[string]string
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("Failed to parse response: %v", err)
|
||||
}
|
||||
|
||||
if response["error"] != "Jitsi service not configured" {
|
||||
t.Errorf("Unexpected error message: %s", response["error"])
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetEmbedURL_NoJitsiService tests embed URL without Jitsi
|
||||
func TestGetEmbedURL_NoJitsiService_Returns503(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
handler := NewCommunicationHandlers(nil, nil)
|
||||
|
||||
router := gin.New()
|
||||
router.POST("/api/v1/communication/meetings/embed", handler.GetEmbedURL)
|
||||
|
||||
body := `{"room_name": "test-room", "display_name": "User"}`
|
||||
req, _ := http.NewRequest("POST", "/api/v1/communication/meetings/embed", bytes.NewBufferString(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusServiceUnavailable {
|
||||
t.Errorf("Expected status 503, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetJitsiInfo_NoJitsiService tests Jitsi info without service
|
||||
func TestGetJitsiInfo_NoJitsiService_Returns503(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
handler := NewCommunicationHandlers(nil, nil)
|
||||
|
||||
router := gin.New()
|
||||
router.GET("/api/v1/communication/jitsi/info", handler.GetJitsiInfo)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/api/v1/communication/jitsi/info", nil)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusServiceUnavailable {
|
||||
t.Errorf("Expected status 503, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
// TestRegisterMatrixUser_NoMatrixService tests user registration without Matrix
|
||||
func TestRegisterMatrixUser_NoMatrixService_Returns503(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
handler := NewCommunicationHandlers(nil, nil)
|
||||
|
||||
router := gin.New()
|
||||
router.POST("/api/v1/communication/admin/matrix/users", handler.RegisterMatrixUser)
|
||||
|
||||
body := `{"username": "testuser", "display_name": "Test User"}`
|
||||
req, _ := http.NewRequest("POST", "/api/v1/communication/admin/matrix/users", bytes.NewBufferString(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusServiceUnavailable {
|
||||
t.Errorf("Expected status 503, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetAdminStats_NoServices tests admin stats without services
|
||||
func TestGetAdminStats_NoServices_ReturnsDisabledStats(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
handler := NewCommunicationHandlers(nil, nil)
|
||||
|
||||
router := gin.New()
|
||||
router.GET("/api/v1/communication/admin/stats", handler.GetAdminStats)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/api/v1/communication/admin/stats", nil)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status 200, got %d", w.Code)
|
||||
}
|
||||
|
||||
var response CommunicationStats
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("Failed to parse response: %v", err)
|
||||
}
|
||||
|
||||
if response.Matrix.Enabled {
|
||||
t.Error("Expected matrix.enabled to be false")
|
||||
}
|
||||
|
||||
if response.Jitsi.Enabled {
|
||||
t.Error("Expected jitsi.enabled to be false")
|
||||
}
|
||||
}
|
||||
|
||||
// TestErrToString tests the helper function
|
||||
func TestErrToString_NilError_ReturnsEmpty(t *testing.T) {
|
||||
result := errToString(nil)
|
||||
if result != "" {
|
||||
t.Errorf("Expected empty string, got %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
// TestErrToString_WithError_ReturnsMessage tests error string conversion
|
||||
func TestErrToString_WithError_ReturnsMessage(t *testing.T) {
|
||||
err := &testError{"test error message"}
|
||||
result := errToString(err)
|
||||
if result != "test error message" {
|
||||
t.Errorf("Expected 'test error message', got %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
// testError is a simple error implementation for testing
|
||||
type testError struct {
|
||||
message string
|
||||
}
|
||||
|
||||
func (e *testError) Error() string {
|
||||
return e.message
|
||||
}
|
||||
|
||||
// TestCreateRoomRequest_Types tests different room types validation
|
||||
func TestCreateRoom_InvalidType_Returns400(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
// Since we don't have Matrix service, we get 503 first
|
||||
// This test documents expected behavior when Matrix IS available
|
||||
handler := NewCommunicationHandlers(nil, nil)
|
||||
|
||||
router := gin.New()
|
||||
router.POST("/api/v1/communication/rooms", handler.CreateRoom)
|
||||
|
||||
body := `{"type": "invalid_type", "class_name": "5b"}`
|
||||
req, _ := http.NewRequest("POST", "/api/v1/communication/rooms", bytes.NewBufferString(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
// Without Matrix service, we get 503 before type validation
|
||||
if w.Code != http.StatusServiceUnavailable {
|
||||
t.Errorf("Expected status 503, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
// TestCreateMeeting_InvalidType tests invalid meeting type
|
||||
func TestCreateMeeting_InvalidType_Returns503(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
handler := NewCommunicationHandlers(nil, nil)
|
||||
|
||||
router := gin.New()
|
||||
router.POST("/api/v1/communication/meetings", handler.CreateMeeting)
|
||||
|
||||
body := `{"type": "invalid", "display_name": "User"}`
|
||||
req, _ := http.NewRequest("POST", "/api/v1/communication/meetings", bytes.NewBufferString(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
// Without Jitsi service, we get 503 before type validation
|
||||
if w.Code != http.StatusServiceUnavailable {
|
||||
t.Errorf("Expected status 503, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
// TestSendNotification_InvalidType tests invalid notification type
|
||||
func TestSendNotification_InvalidType_Returns503(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
handler := NewCommunicationHandlers(nil, nil)
|
||||
|
||||
router := gin.New()
|
||||
router.POST("/api/v1/communication/notifications", handler.SendNotification)
|
||||
|
||||
body := `{"room_id": "!abc:server", "type": "invalid", "student_name": "Max"}`
|
||||
req, _ := http.NewRequest("POST", "/api/v1/communication/notifications", bytes.NewBufferString(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
// Without Matrix service, we get 503 before type validation
|
||||
if w.Code != http.StatusServiceUnavailable {
|
||||
t.Errorf("Expected status 503, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
// TestNewCommunicationHandlers tests constructor
|
||||
func TestNewCommunicationHandlers_WithNilServices_CreatesHandler(t *testing.T) {
|
||||
handler := NewCommunicationHandlers(nil, nil)
|
||||
|
||||
if handler == nil {
|
||||
t.Fatal("Expected handler to be created")
|
||||
}
|
||||
|
||||
if handler.matrixService != nil {
|
||||
t.Error("Expected matrixService to be nil")
|
||||
}
|
||||
|
||||
if handler.jitsiService != nil {
|
||||
t.Error("Expected jitsiService to be nil")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user