package handlers import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "testing" "github.com/breakpilot/consent-service/internal/models" "github.com/gin-gonic/gin" ) func init() { gin.SetMode(gin.TestMode) } // TestCreateDSR_InvalidBody tests create DSR with invalid body func TestCreateDSR_InvalidBody_Returns400(t *testing.T) { router := gin.New() // Mock handler that mimics the actual behavior for invalid body router.POST("/api/v1/dsr", func(c *gin.Context) { var req models.CreateDSRRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body", "details": err.Error()}) return } }) // Invalid JSON req, _ := http.NewRequest("POST", "/api/v1/dsr", bytes.NewBufferString("{invalid json")) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusBadRequest { t.Errorf("Expected status 400, got %d", w.Code) } } // TestCreateDSR_MissingType tests create DSR with missing type func TestCreateDSR_MissingType_Returns400(t *testing.T) { router := gin.New() router.POST("/api/v1/dsr", func(c *gin.Context) { var req models.CreateDSRRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) return } if req.RequestType == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "request_type is required"}) return } }) body := `{"requester_email": "test@example.com"}` req, _ := http.NewRequest("POST", "/api/v1/dsr", bytes.NewBufferString(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusBadRequest { t.Errorf("Expected status 400, got %d", w.Code) } } // TestCreateDSR_InvalidType tests create DSR with invalid type func TestCreateDSR_InvalidType_Returns400(t *testing.T) { router := gin.New() router.POST("/api/v1/dsr", func(c *gin.Context) { var req models.CreateDSRRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) return } if !models.IsValidDSRRequestType(req.RequestType) { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request_type"}) return } }) body := `{"request_type": "invalid_type", "requester_email": "test@example.com"}` req, _ := http.NewRequest("POST", "/api/v1/dsr", bytes.NewBufferString(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusBadRequest { t.Errorf("Expected status 400, got %d", w.Code) } } // TestAdminListDSR_Unauthorized_Returns401 tests admin list without auth func TestAdminListDSR_Unauthorized_Returns401(t *testing.T) { router := gin.New() // Simplified auth check router.GET("/api/v1/admin/dsr", func(c *gin.Context) { authHeader := c.GetHeader("Authorization") if authHeader == "" { c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization required"}) return } c.JSON(http.StatusOK, gin.H{"requests": []interface{}{}}) }) req, _ := http.NewRequest("GET", "/api/v1/admin/dsr", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusUnauthorized { t.Errorf("Expected status 401, got %d", w.Code) } } // TestAdminListDSR_ValidRequest tests admin list with valid auth func TestAdminListDSR_ValidRequest_Returns200(t *testing.T) { router := gin.New() router.GET("/api/v1/admin/dsr", func(c *gin.Context) { authHeader := c.GetHeader("Authorization") if authHeader == "" { c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization required"}) return } c.JSON(http.StatusOK, gin.H{ "requests": []interface{}{}, "total": 0, "limit": 20, "offset": 0, }) }) req, _ := http.NewRequest("GET", "/api/v1/admin/dsr", nil) req.Header.Set("Authorization", "Bearer test-token") 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{} json.Unmarshal(w.Body.Bytes(), &response) if _, ok := response["requests"]; !ok { t.Error("Response should contain 'requests' field") } if _, ok := response["total"]; !ok { t.Error("Response should contain 'total' field") } } // TestAdminGetDSRStats_ValidRequest tests admin stats endpoint func TestAdminGetDSRStats_ValidRequest_Returns200(t *testing.T) { router := gin.New() router.GET("/api/v1/admin/dsr/stats", func(c *gin.Context) { authHeader := c.GetHeader("Authorization") if authHeader == "" { c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization required"}) return } c.JSON(http.StatusOK, gin.H{ "total_requests": 0, "pending_requests": 0, "overdue_requests": 0, "completed_this_month": 0, "average_processing_days": 0, "by_type": map[string]int{}, "by_status": map[string]int{}, }) }) req, _ := http.NewRequest("GET", "/api/v1/admin/dsr/stats", nil) req.Header.Set("Authorization", "Bearer test-token") 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{} json.Unmarshal(w.Body.Bytes(), &response) expectedFields := []string{"total_requests", "pending_requests", "overdue_requests", "by_type", "by_status"} for _, field := range expectedFields { if _, ok := response[field]; !ok { t.Errorf("Response should contain '%s' field", field) } } } // TestAdminUpdateDSR_InvalidStatus_Returns400 tests admin update with invalid status func TestAdminUpdateDSR_InvalidStatus_Returns400(t *testing.T) { router := gin.New() router.PUT("/api/v1/admin/dsr/:id", func(c *gin.Context) { var req models.UpdateDSRRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) return } if req.Status != nil && !models.IsValidDSRStatus(*req.Status) { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid status"}) return } c.JSON(http.StatusOK, gin.H{"message": "Updated"}) }) body := `{"status": "invalid_status"}` req, _ := http.NewRequest("PUT", "/api/v1/admin/dsr/123", bytes.NewBufferString(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer test-token") w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusBadRequest { t.Errorf("Expected status 400, got %d", w.Code) } } // TestAdminVerifyIdentity_ValidRequest_Returns200 tests identity verification func TestAdminVerifyIdentity_ValidRequest_Returns200(t *testing.T) { router := gin.New() router.POST("/api/v1/admin/dsr/:id/verify-identity", func(c *gin.Context) { var req models.VerifyDSRIdentityRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) return } if req.Method == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "method is required"}) return } c.JSON(http.StatusOK, gin.H{"message": "Identität verifiziert"}) }) body := `{"method": "id_card"}` req, _ := http.NewRequest("POST", "/api/v1/admin/dsr/123/verify-identity", bytes.NewBufferString(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer test-token") w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("Expected status 200, got %d", w.Code) } } // TestAdminExtendDeadline_MissingReason_Returns400 tests extend deadline without reason func TestAdminExtendDeadline_MissingReason_Returns400(t *testing.T) { router := gin.New() router.POST("/api/v1/admin/dsr/:id/extend", func(c *gin.Context) { var req models.ExtendDSRDeadlineRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) return } if req.Reason == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "reason is required"}) return } c.JSON(http.StatusOK, gin.H{"message": "Deadline extended"}) }) body := `{"days": 30}` req, _ := http.NewRequest("POST", "/api/v1/admin/dsr/123/extend", bytes.NewBufferString(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer test-token") w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusBadRequest { t.Errorf("Expected status 400, got %d", w.Code) } } // TestAdminCompleteDSR_ValidRequest_Returns200 tests complete DSR func TestAdminCompleteDSR_ValidRequest_Returns200(t *testing.T) { router := gin.New() router.POST("/api/v1/admin/dsr/:id/complete", func(c *gin.Context) { var req models.CompleteDSRRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) return } c.JSON(http.StatusOK, gin.H{"message": "Anfrage erfolgreich abgeschlossen"}) }) body := `{"result_summary": "Alle Daten wurden bereitgestellt"}` req, _ := http.NewRequest("POST", "/api/v1/admin/dsr/123/complete", bytes.NewBufferString(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer test-token") w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("Expected status 200, got %d", w.Code) } } // TestAdminRejectDSR_MissingLegalBasis_Returns400 tests reject DSR without legal basis func TestAdminRejectDSR_MissingLegalBasis_Returns400(t *testing.T) { router := gin.New() router.POST("/api/v1/admin/dsr/:id/reject", func(c *gin.Context) { var req models.RejectDSRRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) return } if req.LegalBasis == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "legal_basis is required"}) return } c.JSON(http.StatusOK, gin.H{"message": "Rejected"}) }) body := `{"reason": "Some reason"}` req, _ := http.NewRequest("POST", "/api/v1/admin/dsr/123/reject", bytes.NewBufferString(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer test-token") w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusBadRequest { t.Errorf("Expected status 400, got %d", w.Code) } } // TestAdminRejectDSR_ValidRequest_Returns200 tests reject DSR with valid data func TestAdminRejectDSR_ValidRequest_Returns200(t *testing.T) { router := gin.New() router.POST("/api/v1/admin/dsr/:id/reject", func(c *gin.Context) { var req models.RejectDSRRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) return } if req.LegalBasis == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "legal_basis is required"}) return } c.JSON(http.StatusOK, gin.H{"message": "Anfrage abgelehnt"}) }) body := `{"reason": "Daten benötigt für Rechtsstreit", "legal_basis": "Art. 17(3)e"}` req, _ := http.NewRequest("POST", "/api/v1/admin/dsr/123/reject", bytes.NewBufferString(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer test-token") w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("Expected status 200, got %d", w.Code) } } // TestGetDSRTemplates_Returns200 tests templates endpoint func TestGetDSRTemplates_Returns200(t *testing.T) { router := gin.New() router.GET("/api/v1/admin/dsr-templates", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "templates": []map[string]interface{}{ { "id": "uuid-1", "template_type": "dsr_receipt_access", "name": "Eingangsbestätigung (Art. 15)", }, }, }) }) req, _ := http.NewRequest("GET", "/api/v1/admin/dsr-templates", nil) req.Header.Set("Authorization", "Bearer test-token") 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{} json.Unmarshal(w.Body.Bytes(), &response) if _, ok := response["templates"]; !ok { t.Error("Response should contain 'templates' field") } } // TestRequestTypeValidation tests all valid request types func TestRequestTypeValidation(t *testing.T) { validTypes := []string{"access", "rectification", "erasure", "restriction", "portability"} for _, reqType := range validTypes { if !models.IsValidDSRRequestType(reqType) { t.Errorf("Expected %s to be a valid request type", reqType) } } invalidTypes := []string{"invalid", "delete", "copy", ""} for _, reqType := range invalidTypes { if models.IsValidDSRRequestType(reqType) { t.Errorf("Expected %s to be an invalid request type", reqType) } } } // TestStatusValidation tests all valid statuses func TestStatusValidation(t *testing.T) { validStatuses := []string{"intake", "identity_verification", "processing", "completed", "rejected", "cancelled"} for _, status := range validStatuses { if !models.IsValidDSRStatus(status) { t.Errorf("Expected %s to be a valid status", status) } } invalidStatuses := []string{"invalid", "pending", "done", ""} for _, status := range invalidStatuses { if models.IsValidDSRStatus(status) { t.Errorf("Expected %s to be an invalid status", status) } } }