Files
ttstd-infinite-canvas/backend/internal/app/payment_plugins_test.go
ddCat 3e35f7d687 fix(merge): PR 集成 - fix merge 上传状态与易支付校验
在 #544、#545、#546 的原作者 merge commit 之后独立修复:保留上传 Promise、处理重复上传与复制失败、格式对齐,以及易支付网关、订单证据、签名、通知幂等与安全关单校验。同步重建六平台插件产物和包。

验证:前端 1832 tests、build/typecheck、lint、相关格式检查通过;财务 SQLite、支付、插件 RPC 与产物专项通过。后端全量出现一项未改动的素材删除 SQLite 表锁失败,单独复跑 3 次通过,保留全量未通过记录。浏览器与真实商户验收待完成。#543 因迁移历史与能力限制回退暂缓。
2026-09-20 05:18:16 +08:00

230 lines
8.1 KiB
Go

package app
import (
"errors"
"testing"
"infinite-canvas/backend/internal/payment"
"infinite-canvas/backend/internal/protocol"
)
func TestBundledPaymentPluginsMatchHostProviders(t *testing.T) {
manifests := bundledPaymentPluginManifests()
if len(manifests) != 2 {
t.Fatalf("payment plugin manifests = %d", len(manifests))
}
for _, manifest := range manifests {
if err := protocol.ValidateManifest(manifest); err != nil {
t.Fatalf("validate %s: %v", manifest.Metadata.ID, err)
}
management := pluginManagement(manifest.Metadata.ID, PluginOriginSystem)
if management.Kind != PluginKindPayment || management.Origin != PluginOriginSystem || management.ActivationScope != PluginScopeSystem {
t.Fatalf("plugin %s management = %#v", manifest.Metadata.ID, management)
}
if len(manifest.Contributes.PaymentProviders) != 1 {
t.Fatalf("plugin %s payment contributions = %d", manifest.Metadata.ID, len(manifest.Contributes.PaymentProviders))
}
contribution := manifest.Contributes.PaymentProviders[0]
if contribution.ID == "" || contribution.Icon == "" || contribution.CheckoutMode == "" {
t.Fatalf("plugin %s has incomplete payment contribution: %#v", manifest.Metadata.ID, contribution)
}
}
}
func TestBundledPaymentPluginsLoadFromSystemSource(t *testing.T) {
center, err := newPluginRuntime(t.TempDir())
if err != nil {
t.Fatal(err)
}
plugins := make(map[string]PluginView)
for _, plugin := range center.list() {
plugins[plugin.Manifest.ID] = plugin
}
for _, manifest := range bundledPaymentPluginManifests() {
plugin, ok := plugins[manifest.Metadata.ID]
if !ok {
t.Fatalf("system payment plugin %s is missing", manifest.Metadata.ID)
}
if plugin.Source != PluginOriginSystem || !plugin.Manifest.Trusted {
t.Fatalf("system payment plugin %s = %#v", manifest.Metadata.ID, plugin)
}
}
}
func TestSystemPaymentPluginsRegisterRPCProviders(t *testing.T) {
center, err := newPluginRuntime(t.TempDir())
if err != nil {
t.Fatal(err)
}
registry := center.paymentRegistrySnapshot()
if registry == nil {
t.Fatal("payment registry is nil")
}
for _, providerID := range []string{PaymentProviderAlipay, PaymentProviderWeChat, "xunhupay-aggregate"} {
provider, ok := registry.Get(providerID)
if !ok {
t.Fatalf("payment provider %q is missing", providerID)
}
if _, ok := provider.(*payment.RPCProvider); !ok {
t.Fatalf("payment provider %q has type %T, want *payment.RPCProvider", providerID, provider)
}
if provider.Descriptor().PluginID == "" || provider.Descriptor().PluginVersion == "" {
t.Fatalf("payment provider %q is missing plugin identity: %#v", providerID, provider.Descriptor())
}
err := provider.ValidateConfig(nil)
var providerErr *payment.ProviderError
if !errors.As(err, &providerErr) {
t.Fatalf("provider %q ValidateConfig() = %T %v, want ProviderError", providerID, err, err)
}
if providerErr.Code == "plugin_executable_missing" || providerErr.Code == "plugin_exec_format_error" || providerErr.Code == "plugin_start_failed" {
t.Fatalf("provider %q failed to start: %#v cause=%v", providerID, providerErr, providerErr.Cause)
}
}
}
func TestPaymentRegistryFailsClosedWhenOfficialPackagesAreMissing(t *testing.T) {
t.Setenv("CANVAS_OFFICIAL_PLUGIN_DIR", t.TempDir())
center, err := newPluginRuntime(t.TempDir())
if err != nil {
t.Fatal(err)
}
registry := center.paymentRegistrySnapshot()
if registry == nil {
t.Fatal("payment registry is nil")
}
for _, providerID := range []string{PaymentProviderAlipay, PaymentProviderWeChat, "xunhupay-aggregate"} {
if _, ok := registry.Get(providerID); ok {
t.Fatalf("payment provider %q unexpectedly came from host fallback", providerID)
}
}
for _, plugin := range center.list() {
if plugin.Management.Kind == PluginKindPayment && plugin.Status != "invalid" {
t.Fatalf("missing package payment plugin %q status = %q, want invalid", plugin.Manifest.ID, plugin.Status)
}
}
}
func TestTopupProductCreditAmountStaysWithinSafeLimit(t *testing.T) {
if _, err := topupProductFromRequest("product", "admin", TopupProductRequest{
Name: "过大积分商品", AmountFen: 1, CreditsMicrocredits: maxTopupCreditsMicrocredits + 1,
}); err == nil {
t.Fatal("expected oversized top-up credits to be rejected")
}
if _, err := topupProductFromRequest("product", "admin", TopupProductRequest{
Name: "有效积分商品", AmountFen: 1, CreditsMicrocredits: maxTopupCreditsMicrocredits,
}); err != nil {
t.Fatalf("maximum safe top-up credits: %v", err)
}
}
func TestXunHuPayOfficialPackageIsPaymentPlugin(t *testing.T) {
center, err := newPluginRuntime(t.TempDir())
if err != nil {
t.Fatal(err)
}
var plugin PluginView
for _, item := range center.list() {
if item.Manifest.ID == "official-payment-xunhupay" {
plugin = item
plugin.Management = pluginManagementFromView(item)
break
}
}
if plugin.Manifest.ID == "" {
t.Fatal("official-payment-xunhupay is missing")
}
if plugin.Management.Kind != PluginKindPayment || plugin.Source != PluginOriginOfficial {
t.Fatalf("xunhupay plugin = %#v", plugin)
}
if len(plugin.Manifest.Contributes.PaymentProviders) != 1 || plugin.Manifest.Contributes.PaymentProviders[0].ID != "xunhupay-aggregate" {
t.Fatalf("xunhupay contributions = %#v", plugin.Manifest.Contributes.PaymentProviders)
}
registry := center.paymentRegistrySnapshot()
if registry == nil {
t.Fatal("payment registry is nil")
}
provider, ok := registry.Get("xunhupay-aggregate")
if !ok {
t.Fatal("xunhupay-aggregate provider is missing")
}
if _, ok := provider.(*payment.RPCProvider); !ok {
t.Fatalf("xunhupay provider type = %T", provider)
}
}
func TestZhiFuFMOfficialPackageIsPaymentPlugin(t *testing.T) {
center, err := newPluginRuntime(t.TempDir())
if err != nil {
t.Fatal(err)
}
var plugin PluginView
for _, item := range center.list() {
if item.Manifest.ID == "official-payment-zhifufm" {
plugin = item
plugin.Management = pluginManagementFromView(item)
break
}
}
if plugin.Manifest.ID == "" {
t.Fatal("official-payment-zhifufm is missing")
}
if plugin.Management.Kind != PluginKindPayment || plugin.Source != PluginOriginOfficial {
t.Fatalf("zhifufm plugin = %#v", plugin)
}
if len(plugin.Manifest.Contributes.PaymentProviders) != 1 || plugin.Manifest.Contributes.PaymentProviders[0].ID != "zhifufm-pay" {
t.Fatalf("zhifufm contributions = %#v", plugin.Manifest.Contributes.PaymentProviders)
}
registry := center.paymentRegistrySnapshot()
if registry == nil {
t.Fatal("payment registry is nil")
}
provider, ok := registry.Get("zhifufm-pay")
if !ok {
t.Fatal("zhifufm-pay provider is missing")
}
if _, ok := provider.(*payment.RPCProvider); !ok {
t.Fatalf("zhifufm provider type = %T", provider)
}
}
func TestEpayOfficialPackageIsPaymentPlugin(t *testing.T) {
center, err := newPluginRuntime(t.TempDir())
if err != nil {
t.Fatal(err)
}
var plugin PluginView
for _, item := range center.list() {
if item.Manifest.ID == "official-payment-epay" {
plugin = item
plugin.Management = pluginManagementFromView(item)
break
}
}
if plugin.Manifest.ID == "" {
t.Fatal("official-payment-epay is missing")
}
if plugin.Management.Kind != PluginKindPayment || plugin.Source != PluginOriginOfficial {
t.Fatalf("epay plugin = %#v", plugin)
}
if len(plugin.Manifest.Contributes.PaymentProviders) != 1 || plugin.Manifest.Contributes.PaymentProviders[0].ID != "epay" {
t.Fatalf("epay contributions = %#v", plugin.Manifest.Contributes.PaymentProviders)
}
registry := center.paymentRegistrySnapshot()
if registry == nil {
t.Fatal("payment registry is nil")
}
provider, ok := registry.Get("epay")
if !ok {
t.Fatal("epay provider is missing")
}
if _, ok := provider.(*payment.RPCProvider); !ok {
t.Fatalf("epay provider type = %T", provider)
}
if err := provider.ValidateConfig(payment.Config{"pid": "test-merchant", "key": "test-key"}); err == nil {
t.Fatal("packaged epay executable must reject a missing gateway")
}
if err := provider.ValidateConfig(payment.Config{"pid": "test-merchant", "key": "test-key", "gateway": "https://pay.example"}); err != nil {
t.Fatalf("packaged epay executable rejected explicit configuration: %v", err)
}
}