140 lines
4.5 KiB
Go

package luckygift_test
import (
"bytes"
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"hyapp-luck-gateway/internal/config"
"hyapp-luck-gateway/internal/integration/luckygiftclient"
"hyapp-luck-gateway/internal/modules/luckygift"
"hyapp-luck-gateway/internal/router"
)
type fakeClient struct {
got luckygiftclient.SendCommand
calls int
}
func (f *fakeClient) SendLuckyGift(_ context.Context, cmd luckygiftclient.SendCommand) (luckygiftclient.SendResult, error) {
f.calls++
f.got = cmd
return luckygiftclient.SendResult{DrawID: "draw-1", RequestID: cmd.RequestID, AppCode: cmd.AppCode, RewardStatus: "granted"}, nil
}
func TestSendAcceptsAllowedAppAndComputesAmount(t *testing.T) {
client := &fakeClient{}
handler := testRouter(client, "aslan,yumi")
body := []byte(`{"app_code":"Aslan","request_id":"req-1","external_user_id":"u-1001","gift_count":3,"unit_amount":7,"currency":"COIN","metadata":{"gift":"rose"}}`)
req := httptest.NewRequest(http.MethodPost, "/api/v1/lucky-gifts/send", bytes.NewReader(body))
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status=%d body=%s", rec.Code, rec.Body.String())
}
if client.calls != 1 {
t.Fatalf("client calls=%d", client.calls)
}
if client.got.AppCode != "aslan" || client.got.RequestID != "req-1" || client.got.TotalAmount != 21 || client.got.GiftCount != 3 {
t.Fatalf("unexpected command: %+v", client.got)
}
}
func TestSendRejectsPoolAndPaidAtOverrides(t *testing.T) {
client := &fakeClient{}
handler := testRouter(client, "aslan")
body := []byte(`{"app_code":"aslan","request_id":"req-1","external_user_id":"u-1001","pool_id":"pool-1","paid_at_ms":1700000000000,"gift_count":1,"unit_amount":7}`)
req := httptest.NewRequest(http.MethodPost, "/api/v1/lucky-gifts/send", bytes.NewReader(body))
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Code != http.StatusBadRequest {
t.Fatalf("status=%d body=%s", rec.Code, rec.Body.String())
}
if client.calls != 0 {
t.Fatalf("client should not be called, calls=%d", client.calls)
}
}
func TestSendRejectsDisallowedAppBeforeClientCall(t *testing.T) {
client := &fakeClient{}
handler := testRouter(client, "aslan,yumi")
body := []byte(`{"app_code":"hyapp","request_id":"req-1","external_user_id":"u-1001","gift_count":1,"unit_amount":9}`)
req := httptest.NewRequest(http.MethodPost, "/api/v1/lucky-gifts/send", bytes.NewReader(body))
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Code != http.StatusForbidden {
t.Fatalf("status=%d body=%s", rec.Code, rec.Body.String())
}
if client.calls != 0 {
t.Fatalf("client should not be called, calls=%d", client.calls)
}
}
func TestSendRejectsInvalidAmount(t *testing.T) {
client := &fakeClient{}
handler := testRouter(client, "aslan")
body, _ := json.Marshal(map[string]any{
"app_code": "aslan",
"request_id": "req-1",
"external_user_id": "u-1",
"gift_count": 0,
"unit_amount": 10,
})
req := httptest.NewRequest(http.MethodPost, "/api/v1/lucky-gifts/send", bytes.NewReader(body))
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Code != http.StatusBadRequest {
t.Fatalf("status=%d body=%s", rec.Code, rec.Body.String())
}
if client.calls != 0 {
t.Fatalf("client should not be called, calls=%d", client.calls)
}
}
func TestSendRejectsTooLongExternalFields(t *testing.T) {
client := &fakeClient{}
handler := testRouter(client, "aslan")
body, _ := json.Marshal(map[string]any{
"app_code": "aslan",
"request_id": "req-1",
"external_user_id": strings.Repeat("u", 129),
"gift_count": 1,
"unit_amount": 10,
})
req := httptest.NewRequest(http.MethodPost, "/api/v1/lucky-gifts/send", bytes.NewReader(body))
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Code != http.StatusBadRequest {
t.Fatalf("status=%d body=%s", rec.Code, rec.Body.String())
}
if client.calls != 0 {
t.Fatalf("client should not be called, calls=%d", client.calls)
}
}
func testRouter(client *fakeClient, allowedApps string) http.Handler {
cfg := config.Config{AllowedApps: parseAllowedAppsForTest(allowedApps)}
return router.New(cfg, router.Handlers{LuckyGift: luckygift.New(client, time.Second, cfg.AllowedApps)})
}
func parseAllowedAppsForTest(raw string) map[string]struct{} {
out := map[string]struct{}{}
for _, app := range strings.Split(raw, ",") {
app = strings.ToLower(strings.TrimSpace(app))
if app != "" {
out[app] = struct{}{}
}
}
return out
}