|
|
@@ -0,0 +1,193 @@
|
|
|
+package handler
|
|
|
+
|
|
|
+import (
|
|
|
+ "bytes"
|
|
|
+ "encoding/json"
|
|
|
+ "net/http"
|
|
|
+ "net/http/httptest"
|
|
|
+ "testing"
|
|
|
+ "time"
|
|
|
+
|
|
|
+ "job-cheng-xing/model"
|
|
|
+ "job-cheng-xing/repository"
|
|
|
+ "job-cheng-xing/service"
|
|
|
+
|
|
|
+ "github.com/gin-gonic/gin"
|
|
|
+)
|
|
|
+
|
|
|
+func setupRouter() *gin.Engine {
|
|
|
+ gin.SetMode(gin.TestMode)
|
|
|
+ repo := repository.NewMemoryRepo()
|
|
|
+ svc := service.NewOrderService(repo)
|
|
|
+ handler := NewOrderHandler(svc)
|
|
|
+
|
|
|
+ r := gin.New()
|
|
|
+ r.POST("/orders", handler.CreateOrder)
|
|
|
+ r.PUT("/orders/:id/accept", handler.AcceptOrder)
|
|
|
+ r.PUT("/orders/:id/cancel", handler.CancelOrder)
|
|
|
+ return r
|
|
|
+}
|
|
|
+
|
|
|
+func TestCreateOrder_Handler(t *testing.T) {
|
|
|
+ r := setupRouter()
|
|
|
+
|
|
|
+ body := map[string]interface{}{
|
|
|
+ "service_time": time.Now().Add(24 * time.Hour).Format(time.RFC3339),
|
|
|
+ "duration": 120,
|
|
|
+ "address": "北京朝阳区xxx路xxx号",
|
|
|
+ }
|
|
|
+ jsonBody, _ := json.Marshal(body)
|
|
|
+
|
|
|
+ req, _ := http.NewRequest("POST", "/orders", bytes.NewBuffer(jsonBody))
|
|
|
+ req.Header.Set("Content-Type", "application/json")
|
|
|
+ w := httptest.NewRecorder()
|
|
|
+ r.ServeHTTP(w, req)
|
|
|
+
|
|
|
+ if w.Code != http.StatusCreated {
|
|
|
+ t.Errorf("expected 201, got %d: %s", w.Code, w.Body.String())
|
|
|
+ }
|
|
|
+
|
|
|
+ var order model.Order
|
|
|
+ json.Unmarshal(w.Body.Bytes(), &order)
|
|
|
+ if order.ID == "" {
|
|
|
+ t.Error("expected non-empty ID")
|
|
|
+ }
|
|
|
+ if order.Status != model.StatusPending {
|
|
|
+ t.Errorf("expected pending, got %s", order.Status)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestAcceptOrder_Handler_Success(t *testing.T) {
|
|
|
+ r := setupRouter()
|
|
|
+
|
|
|
+ body := map[string]interface{}{
|
|
|
+ "service_time": time.Now().Add(24 * time.Hour).Format(time.RFC3339),
|
|
|
+ "duration": 120,
|
|
|
+ "address": "北京朝阳",
|
|
|
+ }
|
|
|
+ jsonBody, _ := json.Marshal(body)
|
|
|
+ req, _ := http.NewRequest("POST", "/orders", bytes.NewBuffer(jsonBody))
|
|
|
+ req.Header.Set("Content-Type", "application/json")
|
|
|
+ w := httptest.NewRecorder()
|
|
|
+ r.ServeHTTP(w, req)
|
|
|
+
|
|
|
+ var order model.Order
|
|
|
+ json.Unmarshal(w.Body.Bytes(), &order)
|
|
|
+
|
|
|
+ acceptBody := map[string]string{"provider_id": "prov_001"}
|
|
|
+ acceptJSON, _ := json.Marshal(acceptBody)
|
|
|
+ req2, _ := http.NewRequest("PUT", "/orders/"+order.ID+"/accept", bytes.NewBuffer(acceptJSON))
|
|
|
+ req2.Header.Set("Content-Type", "application/json")
|
|
|
+ w2 := httptest.NewRecorder()
|
|
|
+ r.ServeHTTP(w2, req2)
|
|
|
+
|
|
|
+ if w2.Code != http.StatusOK {
|
|
|
+ t.Errorf("expected 200, got %d: %s", w2.Code, w2.Body.String())
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestAcceptOrder_Handler_DoubleAccept(t *testing.T) {
|
|
|
+ r := setupRouter()
|
|
|
+
|
|
|
+ body := map[string]interface{}{
|
|
|
+ "service_time": time.Now().Add(24 * time.Hour).Format(time.RFC3339),
|
|
|
+ "duration": 120,
|
|
|
+ "address": "北京朝阳",
|
|
|
+ }
|
|
|
+ jsonBody, _ := json.Marshal(body)
|
|
|
+ req, _ := http.NewRequest("POST", "/orders", bytes.NewBuffer(jsonBody))
|
|
|
+ req.Header.Set("Content-Type", "application/json")
|
|
|
+ w := httptest.NewRecorder()
|
|
|
+ r.ServeHTTP(w, req)
|
|
|
+ var order model.Order
|
|
|
+ json.Unmarshal(w.Body.Bytes(), &order)
|
|
|
+
|
|
|
+ acceptBody1 := map[string]string{"provider_id": "prov_001"}
|
|
|
+ acceptJSON1, _ := json.Marshal(acceptBody1)
|
|
|
+ req1, _ := http.NewRequest("PUT", "/orders/"+order.ID+"/accept", bytes.NewBuffer(acceptJSON1))
|
|
|
+ req1.Header.Set("Content-Type", "application/json")
|
|
|
+ w1 := httptest.NewRecorder()
|
|
|
+ r.ServeHTTP(w1, req1)
|
|
|
+
|
|
|
+ if w1.Code != http.StatusOK {
|
|
|
+ t.Fatalf("first accept should succeed, got %d", w1.Code)
|
|
|
+ }
|
|
|
+
|
|
|
+ acceptBody2 := map[string]string{"provider_id": "prov_002"}
|
|
|
+ acceptJSON2, _ := json.Marshal(acceptBody2)
|
|
|
+ req2, _ := http.NewRequest("PUT", "/orders/"+order.ID+"/accept", bytes.NewBuffer(acceptJSON2))
|
|
|
+ req2.Header.Set("Content-Type", "application/json")
|
|
|
+ w2 := httptest.NewRecorder()
|
|
|
+ r.ServeHTTP(w2, req2)
|
|
|
+
|
|
|
+ if w2.Code != http.StatusConflict {
|
|
|
+ t.Errorf("expected 409, got %d: %s", w2.Code, w2.Body.String())
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestCancelOrder_Handler_ThenAcceptFails(t *testing.T) {
|
|
|
+ r := setupRouter()
|
|
|
+
|
|
|
+ body := map[string]interface{}{
|
|
|
+ "service_time": time.Now().Add(24 * time.Hour).Format(time.RFC3339),
|
|
|
+ "duration": 120,
|
|
|
+ "address": "北京朝阳",
|
|
|
+ }
|
|
|
+ jsonBody, _ := json.Marshal(body)
|
|
|
+ req, _ := http.NewRequest("POST", "/orders", bytes.NewBuffer(jsonBody))
|
|
|
+ req.Header.Set("Content-Type", "application/json")
|
|
|
+ w := httptest.NewRecorder()
|
|
|
+ r.ServeHTTP(w, req)
|
|
|
+ var order model.Order
|
|
|
+ json.Unmarshal(w.Body.Bytes(), &order)
|
|
|
+
|
|
|
+ req1, _ := http.NewRequest("PUT", "/orders/"+order.ID+"/cancel", bytes.NewBuffer([]byte("{}")))
|
|
|
+ req1.Header.Set("Content-Type", "application/json")
|
|
|
+ w1 := httptest.NewRecorder()
|
|
|
+ r.ServeHTTP(w1, req1)
|
|
|
+ if w1.Code != http.StatusOK {
|
|
|
+ t.Fatalf("cancel should succeed, got %d", w1.Code)
|
|
|
+ }
|
|
|
+
|
|
|
+ acceptBody := map[string]string{"provider_id": "prov_001"}
|
|
|
+ acceptJSON, _ := json.Marshal(acceptBody)
|
|
|
+ req2, _ := http.NewRequest("PUT", "/orders/"+order.ID+"/accept", bytes.NewBuffer(acceptJSON))
|
|
|
+ req2.Header.Set("Content-Type", "application/json")
|
|
|
+ w2 := httptest.NewRecorder()
|
|
|
+ r.ServeHTTP(w2, req2)
|
|
|
+
|
|
|
+ if w2.Code != http.StatusBadRequest {
|
|
|
+ t.Errorf("expected 400, got %d: %s", w2.Code, w2.Body.String())
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestCancelOrder_Handler_DoubleCancel(t *testing.T) {
|
|
|
+ r := setupRouter()
|
|
|
+
|
|
|
+ body := map[string]interface{}{
|
|
|
+ "service_time": time.Now().Add(24 * time.Hour).Format(time.RFC3339),
|
|
|
+ "duration": 120,
|
|
|
+ "address": "北京朝阳",
|
|
|
+ }
|
|
|
+ jsonBody, _ := json.Marshal(body)
|
|
|
+ req, _ := http.NewRequest("POST", "/orders", bytes.NewBuffer(jsonBody))
|
|
|
+ req.Header.Set("Content-Type", "application/json")
|
|
|
+ w := httptest.NewRecorder()
|
|
|
+ r.ServeHTTP(w, req)
|
|
|
+ var order model.Order
|
|
|
+ json.Unmarshal(w.Body.Bytes(), &order)
|
|
|
+
|
|
|
+ req1, _ := http.NewRequest("PUT", "/orders/"+order.ID+"/cancel", bytes.NewBuffer([]byte("{}")))
|
|
|
+ req1.Header.Set("Content-Type", "application/json")
|
|
|
+ w1 := httptest.NewRecorder()
|
|
|
+ r.ServeHTTP(w1, req1)
|
|
|
+
|
|
|
+ req2, _ := http.NewRequest("PUT", "/orders/"+order.ID+"/cancel", bytes.NewBuffer([]byte("{}")))
|
|
|
+ req2.Header.Set("Content-Type", "application/json")
|
|
|
+ w2 := httptest.NewRecorder()
|
|
|
+ r.ServeHTTP(w2, req2)
|
|
|
+
|
|
|
+ if w2.Code != http.StatusBadRequest {
|
|
|
+ t.Errorf("expected 400, got %d: %s", w2.Code, w2.Body.String())
|
|
|
+ }
|
|
|
+}
|