chore: build
This commit is contained in:
@@ -0,0 +1,256 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"gestion/handlers"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func cmdContext(method, username, role string, body []byte, commandID int) (*gin.Context, *httptest.ResponseRecorder) {
|
||||
var reader *bytes.Reader
|
||||
if body != nil {
|
||||
reader = bytes.NewReader(body)
|
||||
} else {
|
||||
reader = bytes.NewReader([]byte{})
|
||||
}
|
||||
req := httptest.NewRequest(method, "/api/v1/commands", reader)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
rec := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(rec)
|
||||
c.Request = req
|
||||
c.Set("database", testDB)
|
||||
if username != "" {
|
||||
c.Set("username", username)
|
||||
}
|
||||
c.Set("role", role)
|
||||
if commandID != 0 {
|
||||
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", commandID)}}
|
||||
}
|
||||
return c, rec
|
||||
}
|
||||
|
||||
// ── CancelCommandByClient (HTTP layer) ───────────────────────────────────
|
||||
|
||||
func TestCancelCommandByClient_RejectsNonClientRole(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
c, rec := cmdContext(http.MethodPost, testUserPrefix+"cancel_role", "admin", nil, 1)
|
||||
handlers.CancelCommandByClient(c)
|
||||
if rec.Code != http.StatusForbidden {
|
||||
t.Errorf("role admin doit être refusé: got=%d want=403", rec.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelCommandByClient_InvalidCommandIDReturns400(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
username := newTestClient(t, "cancel_badid")
|
||||
c, rec := cmdContext(http.MethodPost, username, "client", nil, 0)
|
||||
c.Params = gin.Params{{Key: "id", Value: "not-a-number"}}
|
||||
handlers.CancelCommandByClient(c)
|
||||
if rec.Code != http.StatusBadRequest {
|
||||
t.Errorf("ID invalide doit retourner 400: got=%d", rec.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelCommandByClient_UnknownCommandReturns404(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
username := newTestClient(t, "cancel_404")
|
||||
c, rec := cmdContext(http.MethodPost, username, "client", nil, 99999999)
|
||||
handlers.CancelCommandByClient(c)
|
||||
if rec.Code != http.StatusNotFound {
|
||||
t.Errorf("commande inconnue doit retourner 404: got=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelCommandByClient_WrongOwnerReturns403(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
owner := newTestClient(t, "cancel_owner")
|
||||
intruder := newTestClient(t, "cancel_intruder")
|
||||
productID := newTestProduct(t, "CancelWrongOwner", 10)
|
||||
cmdID := newTestCommandWithItem(t, owner, "pending", "", productID, 1, 10)
|
||||
|
||||
c, rec := cmdContext(http.MethodPost, intruder, "client", nil, cmdID)
|
||||
handlers.CancelCommandByClient(c)
|
||||
if rec.Code != http.StatusForbidden {
|
||||
t.Errorf("un autre client ne doit pas pouvoir annuler: got=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelCommandByClient_SuccessNoPenaltyWhenNoLivreur(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
username := newTestClient(t, "cancel_ok_nopenalty")
|
||||
productID := newTestProduct(t, "CancelOkNoPenalty", 10)
|
||||
cmdID := newTestCommandWithItem(t, username, "pending", "", productID, 1, 10)
|
||||
|
||||
c, rec := cmdContext(http.MethodPost, username, "client", nil, cmdID)
|
||||
handlers.CancelCommandByClient(c)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("annulation sans livreur doit réussir: got=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
if got := commandStatus(t, cmdID); got != "cancelled" {
|
||||
t.Errorf("statut après annulation: got=%s want=cancelled", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelCommandByClient_TerminalStatusReturns400(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
username := newTestClient(t, "cancel_terminal")
|
||||
productID := newTestProduct(t, "CancelTerminal", 10)
|
||||
cmdID := newTestCommandWithItem(t, username, "livre", "", productID, 1, 10)
|
||||
|
||||
c, rec := cmdContext(http.MethodPost, username, "client", nil, cmdID)
|
||||
handlers.CancelCommandByClient(c)
|
||||
if rec.Code != http.StatusBadRequest {
|
||||
t.Errorf("annulation d'une commande livrée doit être rejetée: got=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelCommandByClient_ConfirmationRequiredReturns409WithPenaltyWarning(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
username := newTestClient(t, "cancel_confirm")
|
||||
livreur := "cancel_confirm_livreur"
|
||||
productID := newTestProduct(t, "CancelConfirm", 10)
|
||||
cmdID := newTestCommandWithItem(t, username, "en_route", livreur, productID, 1, 10)
|
||||
if err := testDB.SetCommandETA(cmdID, 14); err != nil {
|
||||
t.Fatalf("SetCommandETA: %v", err)
|
||||
}
|
||||
|
||||
c, rec := cmdContext(http.MethodPost, username, "client", nil, cmdID)
|
||||
handlers.CancelCommandByClient(c)
|
||||
if rec.Code != http.StatusConflict {
|
||||
t.Fatalf("annulation tardive sans force doit demander confirmation: got=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
if !bytes.Contains(rec.Body.Bytes(), []byte(`"will_apply":true`)) {
|
||||
t.Errorf("la réponse doit avertir d'une pénalité à venir: body=%s", rec.Body.String())
|
||||
}
|
||||
|
||||
// Statut inchangé tant que non confirmé.
|
||||
if got := commandStatus(t, cmdID); got != "en_route" {
|
||||
t.Errorf("statut ne doit pas changer avant confirmation: got=%s want=en_route", got)
|
||||
}
|
||||
}
|
||||
|
||||
// ── GetMyCancellationHistory ──────────────────────────────────────────────
|
||||
|
||||
func TestGetMyCancellationHistory_RejectsNonClientRole(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
c, rec := cmdContext(http.MethodGet, testUserPrefix+"hist_role", "livreur", nil, 0)
|
||||
handlers.GetMyCancellationHistory(c)
|
||||
if rec.Code != http.StatusForbidden {
|
||||
t.Errorf("role livreur doit être refusé: got=%d want=403", rec.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMyCancellationHistory_ReturnsHistoryAndTotalPenalties(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
username := newTestClient(t, "hist_ok")
|
||||
c, rec := cmdContext(http.MethodGet, username, "client", nil, 0)
|
||||
handlers.GetMyCancellationHistory(c)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("historique doit réussir pour un client: got=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
if !bytes.Contains(rec.Body.Bytes(), []byte(`"total_penalties"`)) {
|
||||
t.Errorf("la réponse doit inclure total_penalties: body=%s", rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
// ── GetAllCancelledOrders ─────────────────────────────────────────────────
|
||||
|
||||
func TestGetAllCancelledOrders_RejectsNonAdminNonCabine(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
c, rec := cmdContext(http.MethodGet, testUserPrefix+"allcancel_role", "livreur", nil, 0)
|
||||
handlers.GetAllCancelledOrders(c)
|
||||
if rec.Code != http.StatusForbidden {
|
||||
t.Errorf("role livreur doit être refusé: got=%d want=403", rec.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAllCancelledOrders_InvalidLimitFallsBackToDefault(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
c, rec := cmdContext(http.MethodGet, testUserPrefix+"allcancel_limit", "admin", nil, 0)
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/admin/cancelled?limit=not-a-number", nil)
|
||||
c.Request = req
|
||||
c.Set("database", testDB)
|
||||
c.Set("username", testUserPrefix+"allcancel_limit")
|
||||
c.Set("role", "admin")
|
||||
handlers.GetAllCancelledOrders(c)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("limit invalide doit quand même réussir avec un défaut: got=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAllCancelledOrders_LimitCapsAt500(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
rec := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(rec)
|
||||
c.Request = httptest.NewRequest(http.MethodGet, "/api/v1/admin/cancelled?limit=99999", nil)
|
||||
c.Set("database", testDB)
|
||||
c.Set("username", testUserPrefix+"allcancel_cap")
|
||||
c.Set("role", "admin")
|
||||
handlers.GetAllCancelledOrders(c)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("limit énorme doit quand même réussir (plafonné): got=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
// ── DeleteCommandByCabine ─────────────────────────────────────────────────
|
||||
|
||||
func TestDeleteCommandByCabine_RejectsNonCabineNonAdmin(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
c, rec := cmdContext(http.MethodDelete, testUserPrefix+"delcab_role", "client", nil, 1)
|
||||
handlers.DeleteCommandByCabine(c)
|
||||
if rec.Code != http.StatusForbidden {
|
||||
t.Errorf("role client doit être refusé: got=%d want=403", rec.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteCommandByCabine_UnknownCommandReturns404(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
c, rec := cmdContext(http.MethodDelete, testUserPrefix+"delcab_404", "cabine", nil, 99999999)
|
||||
handlers.DeleteCommandByCabine(c)
|
||||
if rec.Code != http.StatusNotFound {
|
||||
t.Errorf("commande inconnue doit retourner 404: got=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteCommandByCabine_SuccessDeletesCommand(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
username := newTestClient(t, "delcab_ok")
|
||||
productID := newTestProduct(t, "DelCabOk", 10)
|
||||
cmdID := newTestCommandWithItem(t, username, "pending", "", productID, 1, 10)
|
||||
|
||||
c, rec := cmdContext(http.MethodDelete, testUserPrefix+"delcab_ok_actor", "cabine", nil, cmdID)
|
||||
handlers.DeleteCommandByCabine(c)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("suppression par cabine doit réussir: got=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
var count int64
|
||||
testDB.GDB.Raw(`SELECT COUNT(*) FROM commandes WHERE id = ?`, cmdID).Scan(&count)
|
||||
if count != 0 {
|
||||
t.Errorf("la commande doit être supprimée: got=%d lignes restantes", count)
|
||||
}
|
||||
}
|
||||
|
||||
// ── validateReason (testé indirectement via CancelCommandByClient) ───────
|
||||
|
||||
func TestCancelCommandByClient_BlankReasonDefaultsToStandardMessage(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
username := newTestClient(t, "reason_blank")
|
||||
productID := newTestProduct(t, "ReasonBlank", 10)
|
||||
cmdID := newTestCommandWithItem(t, username, "pending", "", productID, 1, 10)
|
||||
|
||||
body := []byte(`{"reason":""}`)
|
||||
c, rec := cmdContext(http.MethodPost, username, "client", body, cmdID)
|
||||
handlers.CancelCommandByClient(c)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("annulation avec reason vide doit réussir (validateReason doit fournir un défaut, pas rejeter): got=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
if got := commandStatus(t, cmdID); got != "cancelled" {
|
||||
t.Errorf("statut après annulation avec raison vide: got=%s want=cancelled", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user