feat: BreakPilot PWA - Full codebase (clean push without large binaries)
Some checks failed
Tests / Go Tests (push) Has been cancelled
Tests / Python Tests (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / Go Lint (push) Has been cancelled
Tests / Python Lint (push) Has been cancelled
Tests / Security Scan (push) Has been cancelled
Tests / All Checks Passed (push) Has been cancelled
Security Scanning / Secret Scanning (push) Has been cancelled
Security Scanning / Dependency Vulnerability Scan (push) Has been cancelled
Security Scanning / Go Security Scan (push) Has been cancelled
Security Scanning / Python Security Scan (push) Has been cancelled
Security Scanning / Node.js Security Scan (push) Has been cancelled
Security Scanning / Docker Image Security (push) Has been cancelled
Security Scanning / Security Summary (push) Has been cancelled
CI/CD Pipeline / Go Tests (push) Has been cancelled
CI/CD Pipeline / Python Tests (push) Has been cancelled
CI/CD Pipeline / Website Tests (push) Has been cancelled
CI/CD Pipeline / Linting (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Docker Build & Push (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / CI Summary (push) Has been cancelled
ci/woodpecker/manual/build-ci-image Pipeline was successful
ci/woodpecker/manual/main Pipeline failed
Some checks failed
Tests / Go Tests (push) Has been cancelled
Tests / Python Tests (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / Go Lint (push) Has been cancelled
Tests / Python Lint (push) Has been cancelled
Tests / Security Scan (push) Has been cancelled
Tests / All Checks Passed (push) Has been cancelled
Security Scanning / Secret Scanning (push) Has been cancelled
Security Scanning / Dependency Vulnerability Scan (push) Has been cancelled
Security Scanning / Go Security Scan (push) Has been cancelled
Security Scanning / Python Security Scan (push) Has been cancelled
Security Scanning / Node.js Security Scan (push) Has been cancelled
Security Scanning / Docker Image Security (push) Has been cancelled
Security Scanning / Security Summary (push) Has been cancelled
CI/CD Pipeline / Go Tests (push) Has been cancelled
CI/CD Pipeline / Python Tests (push) Has been cancelled
CI/CD Pipeline / Website Tests (push) Has been cancelled
CI/CD Pipeline / Linting (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Docker Build & Push (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / CI Summary (push) Has been cancelled
ci/woodpecker/manual/build-ci-image Pipeline was successful
ci/woodpecker/manual/main Pipeline failed
All services: admin-v2, studio-v2, website, ai-compliance-sdk, consent-service, klausur-service, voice-service, and infrastructure. Large PDFs and compiled binaries excluded via .gitignore.
This commit is contained in:
448
consent-service/internal/handlers/dsr_handlers_test.go
Normal file
448
consent-service/internal/handlers/dsr_handlers_test.go
Normal file
@@ -0,0 +1,448 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user