topfans/backend/gateway/controller/app_download_controller_test.go

170 lines
4.6 KiB
Go

package controller
import (
"context"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/topfans/backend/pkg/models"
"github.com/topfans/backend/gateway/service"
)
// fakeAppDownloadSvc 是 AppDownloadSvc 的 in-memory fake
type fakeAppDownloadSvc struct {
configs []models.AppDownloadConfig
getAllErr error
syncErr error
syncCalled bool
lastSyncReq *service.SyncVersionRequest
}
func (f *fakeAppDownloadSvc) GetAllNativeApp(ctx context.Context) ([]models.AppDownloadConfig, error) {
if f.getAllErr != nil {
return nil, f.getAllErr
}
return f.configs, nil
}
func (f *fakeAppDownloadSvc) SyncVersion(ctx context.Context, req *service.SyncVersionRequest) error {
f.syncCalled = true
f.lastSyncReq = req
return f.syncErr
}
func setupTestRouter(ctrl *AppDownloadController) *gin.Engine {
gin.SetMode(gin.TestMode)
r := gin.New()
r.GET("/api/v1/app/download-urls", ctrl.GetDownloadUrls)
r.POST("/api/v1/admin/app/versions/sync", ctrl.SyncVersion)
return r
}
// ========== GET /api/v1/app/download-urls ==========
func TestGetDownloadUrls_Success(t *testing.T) {
gin.SetMode(gin.TestMode)
fakeSvc := &fakeAppDownloadSvc{
configs: []models.AppDownloadConfig{
{Platform: "android", Type: "native_app", DownloadURL: "https://app.apk", Version: "1.0.5"},
{Platform: "ios", Type: "native_app", DownloadURL: "https://apps.apple.com/...", Version: "1.0.5"},
},
}
ctrl := NewAppDownloadController(fakeSvc)
router := setupTestRouter(ctrl)
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/api/v1/app/download-urls", nil)
router.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
var resp map[string]interface{}
json.Unmarshal(w.Body.Bytes(), &resp)
assert.Equal(t, float64(0), resp["code"])
data := resp["data"].(map[string]interface{})
assert.NotNil(t, data["android"])
assert.NotNil(t, data["ios"])
}
func TestGetDownloadUrls_EmptyData(t *testing.T) {
gin.SetMode(gin.TestMode)
fakeSvc := &fakeAppDownloadSvc{configs: []models.AppDownloadConfig{}}
ctrl := NewAppDownloadController(fakeSvc)
router := setupTestRouter(ctrl)
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/api/v1/app/download-urls", nil)
router.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
var resp map[string]interface{}
json.Unmarshal(w.Body.Bytes(), &resp)
assert.Equal(t, float64(0), resp["code"])
data := resp["data"].(map[string]interface{})
assert.Nil(t, data["android"])
assert.Nil(t, data["ios"])
}
func TestGetDownloadUrls_ServiceError(t *testing.T) {
gin.SetMode(gin.TestMode)
fakeSvc := &fakeAppDownloadSvc{getAllErr: errors.New("db down")}
ctrl := NewAppDownloadController(fakeSvc)
router := setupTestRouter(ctrl)
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/api/v1/app/download-urls", nil)
router.ServeHTTP(w, req)
assert.Equal(t, 500, w.Code)
}
// ========== POST /api/v1/admin/app/versions/sync ==========
func TestSyncVersion_InvalidJSON(t *testing.T) {
gin.SetMode(gin.TestMode)
fakeSvc := &fakeAppDownloadSvc{}
ctrl := NewAppDownloadController(fakeSvc)
router := setupTestRouter(ctrl)
w := httptest.NewRecorder()
req, _ := http.NewRequest("POST", "/api/v1/admin/app/versions/sync",
strings.NewReader(`{"android": "not_an_object"}`))
req.Header.Set("Content-Type", "application/json")
router.ServeHTTP(w, req)
assert.Equal(t, 400, w.Code)
}
func TestSyncVersion_MissingRequiredField(t *testing.T) {
gin.SetMode(gin.TestMode)
fakeSvc := &fakeAppDownloadSvc{}
ctrl := NewAppDownloadController(fakeSvc)
router := setupTestRouter(ctrl)
// 缺少必填字段 url
w := httptest.NewRecorder()
req, _ := http.NewRequest("POST", "/api/v1/admin/app/versions/sync",
strings.NewReader(`{"android": {"version": "1.0.5", "type": "native_app"}}`))
req.Header.Set("Content-Type", "application/json")
router.ServeHTTP(w, req)
assert.Equal(t, 400, w.Code)
}
func TestSyncVersion_Success(t *testing.T) {
gin.SetMode(gin.TestMode)
fakeSvc := &fakeAppDownloadSvc{}
ctrl := NewAppDownloadController(fakeSvc)
router := setupTestRouter(ctrl)
body := `{
"android": {"url": "https://app.apk", "version": "1.0.5", "type": "native_app"},
"ios": {"url": "https://apps.apple.com/...", "version": "1.0.5", "type": "native_app"}
}`
w := httptest.NewRecorder()
req, _ := http.NewRequest("POST", "/api/v1/admin/app/versions/sync",
strings.NewReader(body))
req.Header.Set("Content-Type", "application/json")
router.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
assert.True(t, fakeSvc.syncCalled)
assert.NotNil(t, fakeSvc.lastSyncReq.Android)
assert.NotNil(t, fakeSvc.lastSyncReq.IOS)
}