Files
kra-new/tmp/live_acceptance/verify_recharge.go
T
2026-09-23 17:42:55 +08:00

79 lines
4.0 KiB
Go

package main
import (
"io"
"net/http"
"net/url"
"strings"
"time"
"kra/internal/data/ledger"
"kra/internal/service/dto"
"gorm.io/gorm"
)
func verifyRecharge(admin, viewer, other *apiClient, f *fixtures, db *gorm.DB, report *acceptanceReport) {
must(configureMockPayment(admin))
var plans struct {
List []dto.RechargePlan `json:"list"`
}
must(newClient().call("GET", "/live/recharge/plans", nil, &plans))
check(len(plans.List) > 0 && plans.List[0].AmountCents > 0, "recharge plans missing")
var providers struct {
List []dto.RechargeProvider `json:"list"`
}
must(newClient().call("GET", "/live/recharge/providers", nil, &providers))
found := false
for _, item := range providers.List {
found = found || item.ID == "alipay"
}
check(found, "local mock payment provider was not available")
before := wallet(db, f.Viewer.ID)
var checkout dto.RechargeCheckoutResponse
must(viewer.call("POST", "/live/recharge/orders", dto.RechargeOrderRequest{
PlanID: plans.List[0].ID, Provider: "alipay", NotifyURL: baseURL + "/payment/callback/alipay",
Extra: map[string]any{"userId": f.Other.ID, "diamonds": 99999},
}, &checkout))
check(checkout.Order != nil && checkout.Payment != nil, "recharge checkout missing order or payment")
order := checkout.Order
check(order.UserID == f.Viewer.ID && order.Diamonds == 60 && order.AmountCents == 600, "untrusted checkout values changed ownership or price: %+v", order)
check(wallet(db, f.Viewer.ID).DiamondBalance == before.DiamondBalance, "pending recharge credited wallet")
path := "/live/recharge/orders/" + order.OrderNo
var owned dto.RechargeOrderResponse
must(viewer.call("GET", path, nil, &owned))
check(other.call("GET", path, nil, nil) != nil, "another user accessed recharge order")
check(other.call("GET", path+"/status", nil, nil) != nil, "another user accessed recharge status")
check(newClient().call("GET", path, nil, nil) != nil, "anonymous user accessed recharge order")
must(admin.call("GET", "/live/admin/orders/"+order.OrderNo, nil, nil))
client := &http.Client{Timeout: 15 * time.Second}
badResponse, err := client.PostForm(baseURL+"/payment/callback/alipay", url.Values{
"app_id": {mockAppID}, "out_trade_no": {order.OrderNo}, "trade_no": {"LOCAL-" + order.OrderNo},
"trade_status": {"TRADE_SUCCESS"}, "total_amount": {"6.00"}, "sign_type": {"RSA2"}, "sign": {"invalid"},
})
must(err)
badBody, err := io.ReadAll(badResponse.Body)
must(err)
must(badResponse.Body.Close())
check(strings.TrimSpace(string(badBody)) != "success", "invalid callback signature was acknowledged")
check(wallet(db, f.Viewer.ID).DiamondBalance == before.DiamondBalance, "invalid callback credited wallet")
passed(report, "public recharge plans/provider, signed local checkout, order ownership and invalid callback rejection")
for repeat := 0; repeat < 2; repeat++ {
response, err := client.PostForm(mockURL+"/confirm", url.Values{"orderNo": {order.OrderNo}})
must(err)
body, err := io.ReadAll(response.Body)
must(err)
must(response.Body.Close())
check(response.StatusCode == 200 && strings.TrimSpace(string(body)) == "success", "local signed callback rejected: status=%d body=%s", response.StatusCode, body)
current := wallet(db, f.Viewer.ID)
check(current.DiamondBalance == before.DiamondBalance+60 && current.TotalRechargeCents == before.TotalRechargeCents+600, "recharge was not credited exactly once: before=%+v after=%+v", before, current)
}
must(viewer.call("GET", path, nil, &owned))
check(owned.PaymentStatus == "paid" && owned.FulfillmentStatus == "succeeded" && owned.CreditedAt != nil, "recharge status was not fulfilled: %+v", owned)
var stored ledger.RechargeOrderPO
must(db.Where("order_no = ?", order.OrderNo).First(&stored).Error)
check(stored.UserID == f.Viewer.ID && stored.CreditedAt != nil, "recharge database ownership or credit marker incorrect")
report.Records["rechargeOrderNo"] = order.OrderNo
passed(report, "valid local RSA2 callback, authoritative signed query and duplicate callback credit wallet only once")
}