package ymt_v3_generate_test import ( "context" "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/base64" "encoding/json" "encoding/pem" "fmt" "net/http" "net/http/httptest" "strings" "testing" "time" sdk "ymt_v3_generate" ) // 生成测试用的 RSA 密钥对和 AES key func generateTestKeys() (privateKeyPEM, publicKeyPEM string, aesKey []byte, err error) { // RSA 密钥 priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return "", "", nil, err } privBytes := x509.MarshalPKCS1PrivateKey(priv) privPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: privBytes}) publicKey := &priv.PublicKey pubBytes, err := x509.MarshalPKIXPublicKey(publicKey) if err != nil { return "", "", nil, err } pubPEM := pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: pubBytes}) // AES key (16字节) aesKey = make([]byte, 16) _, err = rand.Read(aesKey) if err != nil { return "", "", nil, err } return string(privPEM), string(pubPEM), aesKey, nil } // 模拟服务器,返回加密的响应 func mockServer(t *testing.T, aesKey []byte, responseBody interface{}) *httptest.Server { return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // 验证请求头 appID := r.Header.Get("Appid") timestamp := r.Header.Get("Timestamp") sign := r.Header.Get("Sign") if appID == "" || timestamp == "" || sign == "" { http.Error(w, "missing headers", http.StatusBadRequest) return } // 读取请求体 var reqBody map[string]string if err := json.NewDecoder(r.Body).Decode(&reqBody); err != nil { http.Error(w, "invalid body", http.StatusBadRequest) return } ciphertext := reqBody["ciphertext"] if ciphertext == "" { http.Error(w, "missing ciphertext", http.StatusBadRequest) return } // 这里不验证签名,仅测试流程 // 构造响应 respPlaintext, _ := json.Marshal(responseBody) // 加密 encrypted, err := sdk.EncryptPlaintext(string(respPlaintext), aesKey) if err != nil { http.Error(w, "encrypt error", http.StatusInternalServerError) return } apiResp := map[string]interface{}{ "code": 200, "message": "成功", "data": map[string]string{ "ciphertext": encrypted, }, } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(apiResp) })) } func TestCreateKeyOrder(t *testing.T) { privPEM, pubPEM, aesKey, err := generateTestKeys() if err != nil { t.Fatal(err) } server := mockServer(t, aesKey, sdk.KeyOrderResponse{ OutBizNo: "order_001", TradeNo: "7251449503000383488", Key: "aZKdU9BymzR6qGRzJM", ValidBeginTime: "2026-06-22 15:30:00", ValidEndTime: "2026-12-31 23:59:59", UsableNum: 1, UsageNum: 0, Status: 1, SettlementPrice: 9.9, Account: "18666666666", }) defer server.Close() client := sdk.NewClient( sdk.WithAppID("test_app"), sdk.WithPrivateKey(privPEM), sdk.WithPublicKey(pubPEM), sdk.WithKey(base64.StdEncoding.EncodeToString(aesKey)), sdk.WithBaseURL(server.URL), ) req := &sdk.KeyOrderRequest{ OutBizNo: "order_001", ActivityNo: "ACT20260622001", Account: "18666666666", NotifyURL: "https://notify.example.com/openapi", } resp, err := client.CreateKeyOrder(context.Background(), req) if err != nil { t.Fatal(err) } if resp.TradeNo != "7251449503000383488" { t.Errorf("expected trade_no 7251449503000383488, got %s", resp.TradeNo) } } func TestQueryKey(t *testing.T) { privPEM, pubPEM, aesKey, err := generateTestKeys() if err != nil { t.Fatal(err) } server := mockServer(t, aesKey, sdk.KeyQueryResponse{ OutBizNo: "order_001", TradeNo: "7251449503000383488", Key: "aZKdU9BymzR6qGRzJM", ValidBeginTime: "2026-06-22 15:30:00", ValidEndTime: "2026-12-31 23:59:59", UsableNum: 1, UsageNum: 0, Status: 1, SettlementPrice: 9.9, Account: "18666666666", }) defer server.Close() client := sdk.NewClient( sdk.WithAppID("test_app"), sdk.WithPrivateKey(privPEM), sdk.WithPublicKey(pubPEM), sdk.WithKey(base64.StdEncoding.EncodeToString(aesKey)), sdk.WithBaseURL(server.URL), ) req := &sdk.KeyQueryRequest{ OutBizNo: "order_001", } resp, err := client.QueryKey(context.Background(), req) if err != nil { t.Fatal(err) } if resp.TradeNo != "7251449503000383488" { t.Errorf("expected trade_no 7251449503000383488, got %s", resp.TradeNo) } } func TestDiscardKey(t *testing.T) { privPEM, pubPEM, aesKey, err := generateTestKeys() if err != nil { t.Fatal(err) } server := mockServer(t, aesKey, sdk.KeyDiscardResponse{ OutBizNo: "order_001", TradeNo: "7251449503000383488", Status: 3, }) defer server.Close() client := sdk.NewClient( sdk.WithAppID("test_app"), sdk.WithPrivateKey(privPEM), sdk.WithPublicKey(pubPEM), sdk.WithKey(base64.StdEncoding.EncodeToString(aesKey)), sdk.WithBaseURL(server.URL), ) req := &sdk.KeyDiscardRequest{ TradeNo: "7251449503000383488", } resp, err := client.DiscardKey(context.Background(), req) if err != nil { t.Fatal(err) } if resp.Status != 3 { t.Errorf("expected status 3, got %d", resp.Status) } } func TestBatchOrder(t *testing.T) { privPEM, pubPEM, aesKey, err := generateTestKeys() if err != nil { t.Fatal(err) } server := mockServer(t, aesKey, sdk.BatchOrderResponse{ OutBizNo: "batch_001", TradeNo: "7251449503000383499", Status: "processing", }) defer server.Close() client := sdk.NewClient( sdk.WithAppID("test_app"), sdk.WithPrivateKey(privPEM), sdk.WithPublicKey(pubPEM), sdk.WithKey(base64.StdEncoding.EncodeToString(aesKey)), sdk.WithBaseURL(server.URL), ) req := &sdk.BatchOrderRequest{ OutBizNo: "batch_001", ActivityNo: "ACT20260622001", Number: 100, } resp, err := client.BatchOrder(context.Background(), req) if err != nil { t.Fatal(err) } if resp.Status != "processing" { t.Errorf("expected status processing, got %s", resp.Status) } } func TestBatchQuery(t *testing.T) { privPEM, pubPEM, aesKey, err := generateTestKeys() if err != nil { t.Fatal(err) } server := mockServer(t, aesKey, sdk.BatchQueryResponse{ OutBizNo: "batch_001", TradeNo: "7251449503000383499", Status: "success", DownloadURL: "https://oss.example.com/openapi_7251449503000383499.zip", ZipPassword: "123456", }) defer server.Close() client := sdk.NewClient( sdk.WithAppID("test_app"), sdk.WithPrivateKey(privPEM), sdk.WithPublicKey(pubPEM), sdk.WithKey(base64.StdEncoding.EncodeToString(aesKey)), sdk.WithBaseURL(server.URL), ) req := &sdk.BatchQueryRequest{ TradeNo: "7251449503000383499", } resp, err := client.BatchQuery(context.Background(), req) if err != nil { t.Fatal(err) } if resp.Status != "success" { t.Errorf("expected status success, got %s", resp.Status) } if resp.DownloadURL == "" { t.Error("expected download_url not empty") } }