package dailyAdverCalc import ( "91porn-server/common" "91porn-server/models/commod" "91porn-server/models/s/dailyretentionmod" "testing" "time" "go.mongodb.org/mongo-driver/bson" ) func TestCalculateRetentionRate(t *testing.T) { t.Run("zero cohort size returns zero", func(t *testing.T) { if got := calculateRetentionRate(10, 0); got != 0 { t.Fatalf("expected zero rate, got %v", got) } }) t.Run("uses retained divided by cohort size", func(t *testing.T) { got := calculateRetentionRate(25, 100) want := 0.25 if got != want { t.Fatalf("expected %v, got %v", want, got) } }) } func TestGetPrevAccum(t *testing.T) { t.Run("nil item or day zero returns zeros", func(t *testing.T) { adClick, totalClick, payCount, payTotal := getPrevAccum(nil, 0) if adClick != 0 || totalClick != 0 || payCount != 0 || payTotal != 0 { t.Fatalf("expected all zero values, got %d %d %d %d", adClick, totalClick, payCount, payTotal) } }) t.Run("reads previous day accumulators", func(t *testing.T) { item := &dailyretentionmod.DailyRetention{ AdClickAcc: map[int]int64{1: 3, 2: 8}, TotalClickAcc: map[int]int64{1: 5, 2: 13}, PayCountAcc: map[int]int64{1: 1, 2: 2}, PayTotalAcc: map[int]int64{1: 100, 2: 300}, } adClick, totalClick, payCount, payTotal := getPrevAccum(item, 3) if adClick != 8 || totalClick != 13 || payCount != 2 || payTotal != 300 { t.Fatalf("unexpected previous accum values: %d %d %d %d", adClick, totalClick, payCount, payTotal) } }) } func TestBuildDailyRetentionUpsertData(t *testing.T) { loc, err := time.LoadLocation("Asia/Shanghai") if err != nil { t.Fatalf("load location failed: %v", err) } regDay := time.Date(2026, 3, 18, 14, 25, 0, 0, loc) now := time.Date(2026, 3, 19, 9, 30, 0, 0, loc) t.Run("day zero writes new users and normalizes date", func(t *testing.T) { filter, update := buildDailyRetentionUpsertData(regDay, commod.AdGroupA, 0, 12, 1, 4, 8, 2, 600, now) wantDate := common.NormalizeDate(regDay) if got := filter["date"].(time.Time); !got.Equal(wantDate) { t.Fatalf("expected normalized date %v, got %v", wantDate, got) } if got := filter["adGroup"]; got != commod.AdGroupA { t.Fatalf("expected ad group %v, got %v", commod.AdGroupA, got) } setOnInsert := update["$setOnInsert"].(bson.M) if got := setOnInsert["date"].(time.Time); !got.Equal(wantDate) { t.Fatalf("expected setOnInsert date %v, got %v", wantDate, got) } if got := setOnInsert["createdAt"].(time.Time); !got.Equal(now) { t.Fatalf("expected createdAt %v, got %v", now, got) } setFields := update["$set"].(bson.M) if got := setFields["userRetained.0"]; got != int64(12) { t.Fatalf("expected userRetained.0 to be 12, got %v", got) } if got := setFields["userRates.0"]; got != float64(1) { t.Fatalf("expected userRates.0 to be 1, got %v", got) } if got := setFields["newUsers"]; got != int64(12) { t.Fatalf("expected newUsers to be 12, got %v", got) } }) t.Run("non day zero does not overwrite new users", func(t *testing.T) { _, update := buildDailyRetentionUpsertData(regDay, commod.AdGroupB, 2, 6, 0.3, 9, 11, 3, 800, now) setFields := update["$set"].(bson.M) if got := setFields["userRetained.2"]; got != int64(6) { t.Fatalf("expected userRetained.2 to be 6, got %v", got) } if got := setFields["userRates.2"]; got != 0.3 { t.Fatalf("expected userRates.2 to be 0.3, got %v", got) } if _, ok := setFields["newUsers"]; ok { t.Fatalf("did not expect newUsers on non-day-zero update") } }) }