package user import ( "context" "fmt" "os" "testing" "time" "github.com/alicebob/miniredis/v2" "github.com/perfect-panel/server/internal/config" "github.com/perfect-panel/server/internal/model/order" "github.com/perfect-panel/server/internal/model/subscribe" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/constant" "github.com/redis/go-redis/v9" "github.com/stretchr/testify/assert" "gorm.io/driver/sqlite" "gorm.io/gorm" ) // setupTestSvcCtx 初始化测试上下文 func setupTestSvcCtx(t *testing.T) (*svc.ServiceContext, *gorm.DB) { // 1. Setup Miniredis mr, err := miniredis.Run() assert.NoError(t, err) rdb := redis.NewClient(&redis.Options{ Addr: mr.Addr(), }) // 2. Setup GORM with SQLite dbName := fmt.Sprintf("test_sales_%d.db", time.Now().UnixNano()) db, err := gorm.Open(sqlite.Open(dbName), &gorm.Config{}) assert.NoError(t, err) t.Cleanup(func() { os.Remove(dbName) mr.Close() }) // Migrate tables _ = db.Migrator().CreateTable(&user.User{}) _ = db.Migrator().CreateTable(&subscribe.Subscribe{}) // Plan definition _ = db.Migrator().CreateTable(&order.Order{}) // 3. Create ServiceContext svcCtx := &svc.ServiceContext{ Redis: rdb, DB: db, Config: config.Config{}, UserModel: user.NewModel(db, rdb), } return svcCtx, db } func TestGetInviteSales_TimeFilter(t *testing.T) { svcCtx, db := setupTestSvcCtx(t) // 1. Prepare Data // Referrer User (Current User) referrer := &user.User{ Id: 100, // Email removed (not in struct) ReferCode: "REF100", } db.Create(referrer) // Invited User invitedUser := &user.User{ Id: 200, // Email removed RefererId: referrer.Id, // Linked to referrer } db.Create(invitedUser) // Subscribe (Plan) sub := &subscribe.Subscribe{ Id: 1, Name: "Standard Plan", } db.Create(sub) // Orders // Order 1: Inside Range (2023-10-15) timeIn := time.Date(2023, 10, 15, 12, 0, 0, 0, time.UTC) db.Create(&order.Order{ UserId: invitedUser.Id, OrderNo: "ORD001", Status: 5, // Finished Amount: 1000, Quantity: 30, SubscribeId: sub.Id, UpdatedAt: timeIn, }) // Order 2: Before Range (2023-09-15) timeBefore := time.Date(2023, 9, 15, 12, 0, 0, 0, time.UTC) db.Create(&order.Order{ UserId: invitedUser.Id, OrderNo: "ORD002", Status: 5, // Finished Amount: 1000, Quantity: 30, SubscribeId: sub.Id, UpdatedAt: timeBefore, }) // Order 3: After Range (2023-11-15) timeAfter := time.Date(2023, 11, 15, 12, 0, 0, 0, time.UTC) db.Create(&order.Order{ UserId: invitedUser.Id, OrderNo: "ORD003", Status: 5, // Finished Amount: 1000, Quantity: 30, SubscribeId: sub.Id, UpdatedAt: timeAfter, }) // Order 4: Wrong Status (2023-10-16) - Should be ignored db.Create(&order.Order{ UserId: invitedUser.Id, OrderNo: "ORD004", Status: 1, // Pending Amount: 1000, Quantity: 30, SubscribeId: sub.Id, UpdatedAt: timeIn.Add(24 * time.Hour), }) // 2. Execute Logic // Context with current user ctx := context.WithValue(context.Background(), constant.CtxKeyUser, referrer) l := NewGetInviteSalesLogic(ctx, svcCtx) // Filter for October 2023 startTime := time.Date(2023, 10, 1, 0, 0, 0, 0, time.UTC).Unix() endTime := time.Date(2023, 10, 31, 23, 59, 59, 0, time.UTC).Unix() req := &types.GetInviteSalesRequest{ Page: 1, Size: 10, StartTime: startTime, // 2023-10-01 EndTime: endTime, // 2023-10-31 } resp, err := l.GetInviteSales(req) assert.NoError(t, err) // 3. Verify Results // Should match exactly 1 order (ORD001) assert.Equal(t, int64(1), resp.Total, "Should return exactly 1 order matching time range and status") if assert.NotEmpty(t, resp.List) { assert.Equal(t, 1, len(resp.List)) // Log result for debug t.Logf("Found Sale: Amount=%.2f, Time=%d", resp.List[0].Amount, resp.List[0].UpdatedAt) // Verify timestamp is roughly correct (millisecond precision in logic) expectedMs := timeIn.Unix() * 1000 assert.Equal(t, expectedMs, resp.List[0].UpdatedAt) } else { t.Error("Returned list is empty") } }