chore(addon/huaweipay): 更新huaweipay
This commit is contained in:
@@ -3,263 +3,417 @@
|
||||
* 华为支付模型测试类
|
||||
*/
|
||||
|
||||
namespace addon\huaweipay\tests;
|
||||
// 设置错误报告
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
use addon\huaweipay\model\Pay;
|
||||
use addon\huaweipay\model\Config;
|
||||
use think\facade\Log;
|
||||
// 添加自动加载路径
|
||||
$root_path = dirname(__DIR__, 3);
|
||||
require_once $root_path . '/vendor/autoload.php';
|
||||
|
||||
// 定义常量
|
||||
if (!defined('ROOT_PATH')) {
|
||||
define('ROOT_PATH', $root_path . '/');
|
||||
}
|
||||
|
||||
// 模拟app()函数,解决框架依赖问题
|
||||
function app() {
|
||||
return new class {
|
||||
public function getRootPath() {
|
||||
return dirname(__DIR__, 3) . '\\';
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class PayModelTest
|
||||
{
|
||||
/**
|
||||
* 测试站点ID
|
||||
* @var int
|
||||
*/
|
||||
protected $siteId = 1;
|
||||
|
||||
/**
|
||||
* 测试配置数据
|
||||
* @var array
|
||||
*/
|
||||
protected $configData;
|
||||
protected $config = [];
|
||||
protected $pay_model = null;
|
||||
|
||||
/**
|
||||
* 构造函数,加载配置文件
|
||||
* 构造函数
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// 加载配置文件
|
||||
$yamlPath = __DIR__ . '/mock/data.yml';
|
||||
if (file_exists($yamlPath)) {
|
||||
if (function_exists('yaml_parse_file')) {
|
||||
$this->configData = yaml_parse_file($yamlPath);
|
||||
} else {
|
||||
// 如果没有yaml_parse_file函数,手动解析
|
||||
$this->configData = $this->parseYamlFile($yamlPath);
|
||||
}
|
||||
} else {
|
||||
throw new Exception("配置文件不存在: {$yamlPath}");
|
||||
}
|
||||
// 加载测试配置
|
||||
$this->config = $this->parseYamlFile(__DIR__ . '/mock/data.yml');
|
||||
echo "配置加载完成\n";
|
||||
// print_r($this->config);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 手动解析YAML文件
|
||||
* @param string $filePath
|
||||
* 解析YAML文件
|
||||
* @param string $file_path YAML文件路径
|
||||
* @return array
|
||||
*/
|
||||
private function parseYamlFile($filePath)
|
||||
protected function parseYamlFile($file_path)
|
||||
{
|
||||
$content = file_get_contents($filePath);
|
||||
$lines = explode("\n", $content);
|
||||
$result = [];
|
||||
$currentKey = '';
|
||||
$isMultiline = false;
|
||||
$multilineValue = '';
|
||||
if (!file_exists($file_path)) {
|
||||
throw new Exception("YAML文件不存在: {$file_path}");
|
||||
}
|
||||
|
||||
$yaml_content = file_get_contents($file_path);
|
||||
if ($yaml_content === false) {
|
||||
throw new Exception("读取YAML文件失败: {$file_path}");
|
||||
}
|
||||
|
||||
// 使用正则替换YAML中的\n为实际换行符
|
||||
$yaml_content = preg_replace_callback('/\\\\n/', function($matches) {
|
||||
return "\n";
|
||||
}, $yaml_content);
|
||||
|
||||
// 简单的YAML解析(仅支持当前测试文件的格式)
|
||||
$config = [];
|
||||
$lines = explode("\n", $yaml_content);
|
||||
$current_key = '';
|
||||
$in_block = false;
|
||||
$block_content = '';
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$line = trim($line);
|
||||
|
||||
// 跳过注释和空行
|
||||
if (empty($line) || strpos($line, '#') === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 处理多行值
|
||||
if ($isMultiline) {
|
||||
if (strpos($line, '-----END') === 0) {
|
||||
$multilineValue .= $line . "\n";
|
||||
$result[$currentKey] = rtrim($multilineValue);
|
||||
$isMultiline = false;
|
||||
$multilineValue = '';
|
||||
} else {
|
||||
$multilineValue .= $line . "\n";
|
||||
|
||||
if ($in_block) {
|
||||
if (strpos($line, '---') === 0) {
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/^\w+:/', $line)) {
|
||||
$config[$current_key] = $block_content;
|
||||
$in_block = false;
|
||||
$block_content = '';
|
||||
} else {
|
||||
$block_content .= $line . "\n";
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 处理单行键值对
|
||||
|
||||
if (strpos($line, ':') !== false) {
|
||||
list($key, $value) = explode(':', $line, 2);
|
||||
$key = trim($key);
|
||||
$value = trim($value);
|
||||
|
||||
// 处理多行值开始
|
||||
if ($value === '|') {
|
||||
$isMultiline = true;
|
||||
$currentKey = $key;
|
||||
if (strpos($value, '|') !== false) {
|
||||
$in_block = true;
|
||||
$current_key = $key;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 处理普通值
|
||||
if (!empty($value)) {
|
||||
$result[$key] = $value;
|
||||
$config[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
if ($in_block && !empty($current_key)) {
|
||||
$config[$current_key] = $block_content;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行所有测试
|
||||
* 运行测试
|
||||
*/
|
||||
public function runTests()
|
||||
{
|
||||
echo "开始测试华为支付模型...\n";
|
||||
echo "开始运行华为支付模型测试...\n";
|
||||
|
||||
try {
|
||||
// 1. 测试支付方法
|
||||
echo "1. 测试支付方法...\n";
|
||||
$this->testPayMethod();
|
||||
$this->testNotifyMethod();
|
||||
$this->testCloseOrderMethod();
|
||||
$this->testRefundMethod();
|
||||
$this->testQueryOrderMethod();
|
||||
echo "1. 支付方法测试通过\n";
|
||||
|
||||
echo "\n✅ 所有测试通过!\n";
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
echo "\n❌ 测试失败:" . $e->getMessage() . "\n";
|
||||
echo "错误位置:" . $e->getFile() . " 第" . $e->getLine() . "行\n";
|
||||
// 2. 测试关闭订单方法
|
||||
echo "2. 测试关闭订单方法...\n";
|
||||
$this->testCloseOrderMethod();
|
||||
echo "2. 关闭订单方法测试通过\n";
|
||||
|
||||
// 3. 测试退款方法
|
||||
echo "3. 测试退款方法...\n";
|
||||
$this->testRefundMethod();
|
||||
echo "3. 退款方法测试通过\n";
|
||||
|
||||
// 4. 测试查询订单方法
|
||||
echo "4. 测试查询订单方法...\n";
|
||||
$this->testQueryOrderMethod();
|
||||
echo "4. 查询订单方法测试通过\n";
|
||||
|
||||
// 5. 测试回调验证方法
|
||||
echo "5. 测试回调验证方法...\n";
|
||||
$this->testCallbackVerification();
|
||||
echo "5. 回调验证方法测试通过\n";
|
||||
|
||||
echo "\n所有测试通过!\n";
|
||||
} catch (Exception $e) {
|
||||
echo "\n测试失败:" . $e->getMessage() . "\n";
|
||||
echo "错误堆栈:" . $e->getTraceAsString() . "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试支付方法
|
||||
*/
|
||||
public function testPayMethod()
|
||||
protected function testPayMethod()
|
||||
{
|
||||
echo "测试支付方法...";
|
||||
// 创建支付模型实例
|
||||
require_once dirname(__DIR__) . '/model/Pay.php';
|
||||
require_once dirname(__DIR__) . '/data/sdk/utils.php';
|
||||
require_once dirname(__DIR__) . '/data/sdk/HuaweiPayClient.php';
|
||||
|
||||
// 添加必要的配置
|
||||
$site_id = '1';
|
||||
$config_data = $this->config;
|
||||
$config_data['site_id'] = $site_id;
|
||||
// 使用文本模式的密钥,而不是证书文件
|
||||
unset($config_data['private_key']);
|
||||
unset($config_data['huawei_public_key']);
|
||||
|
||||
try {
|
||||
// 模拟配置
|
||||
$this->mockConfig();
|
||||
// 创建实际的华为支付客户端实例
|
||||
$project_root = dirname(__DIR__, 4); // 获取项目根目录
|
||||
$huawei_pay_client = new \addon\huaweipay\data\sdk\HuaweiPayClient($config_data, $project_root);
|
||||
echo " - 华为支付客户端实例创建成功\n";
|
||||
|
||||
// 创建测试订单数据
|
||||
$orderInfo = [
|
||||
'out_trade_no' => 'test_order_' . time(),
|
||||
'total_amount' => 100,
|
||||
'subject' => '测试商品',
|
||||
'notify_url' => $this->configData['notifyUrl'],
|
||||
'return_url' => $this->configData['returnUrl'],
|
||||
'buyer_id' => '1',
|
||||
'type' => 'h5'
|
||||
// 测试H5支付
|
||||
$h5_params = [
|
||||
'out_trade_no' => 'TEST_H5_' . time(),
|
||||
'subject' => '测试H5支付商品',
|
||||
'body' => '测试H5支付商品描述',
|
||||
'total_amount' => 0.01,
|
||||
'client_ip' => '127.0.0.1'
|
||||
];
|
||||
|
||||
// 尝试创建Pay实例
|
||||
$payModel = new Pay($this->siteId);
|
||||
// 调用真实的H5支付方法
|
||||
$h5_result = $huawei_pay_client->h5Pay($h5_params, $config_data['returnUrl'], $config_data['notifyUrl']);
|
||||
echo " - H5支付方法调用成功\n";
|
||||
echo " 结果: " . json_encode($h5_result, JSON_UNESCAPED_UNICODE) . "\n";
|
||||
|
||||
// 由于需要实际的支付客户端,这里只测试模型初始化
|
||||
echo " ⚠️ 跳过实际支付测试,仅测试模型初始化\n";
|
||||
} catch (\Exception $e) {
|
||||
echo " ⚠️ 模型初始化测试跳过: " . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试通知方法
|
||||
*/
|
||||
public function testNotifyMethod()
|
||||
{
|
||||
echo "测试通知方法...";
|
||||
|
||||
try {
|
||||
// 模拟配置
|
||||
$this->mockConfig();
|
||||
|
||||
// 创建模拟通知数据
|
||||
$notifyData = [
|
||||
'app_id' => $this->configData['app_id'],
|
||||
'merc_no' => $this->configData['mch_id'],
|
||||
'order_id' => 'test_order_001',
|
||||
'trade_status' => 'SUCCESS',
|
||||
'sign' => 'mock_signature'
|
||||
// 测试APP支付
|
||||
$app_params = [
|
||||
'out_trade_no' => 'TEST_APP_' . time(),
|
||||
'subject' => '测试APP支付商品',
|
||||
'body' => '测试APP支付商品描述',
|
||||
'total_amount' => 0.01
|
||||
];
|
||||
|
||||
// 尝试创建Pay实例
|
||||
$payModel = new Pay($this->siteId);
|
||||
// 调用真实的APP支付方法
|
||||
$app_result = $huawei_pay_client->appPay($app_params, $config_data['notifyUrl']);
|
||||
echo " - APP支付方法调用成功\n";
|
||||
echo " 结果: " . json_encode($app_result, JSON_UNESCAPED_UNICODE) . "\n";
|
||||
|
||||
echo " ⚠️ 跳过实际通知处理测试\n";
|
||||
} catch (\Exception $e) {
|
||||
echo " ⚠️ 通知测试跳过: " . $e->getMessage() . "\n";
|
||||
} catch (Exception $e) {
|
||||
echo " - 支付测试失败: " . $e->getMessage() . "\n";
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试关闭订单方法
|
||||
*/
|
||||
public function testCloseOrderMethod()
|
||||
protected function testCloseOrderMethod()
|
||||
{
|
||||
echo "测试关闭订单方法...";
|
||||
require_once dirname(__DIR__) . '/data/sdk/utils.php';
|
||||
require_once dirname(__DIR__) . '/data/sdk/HuaweiPayClient.php';
|
||||
|
||||
// 添加必要的配置
|
||||
$site_id = '1';
|
||||
$config_data = $this->config;
|
||||
$config_data['site_id'] = $site_id;
|
||||
// 使用文本模式的密钥,而不是证书文件
|
||||
unset($config_data['private_key']);
|
||||
unset($config_data['huawei_public_key']);
|
||||
|
||||
try {
|
||||
// 模拟配置
|
||||
$this->mockConfig();
|
||||
// 创建实际的华为支付客户端实例
|
||||
$project_root = dirname(__DIR__, 4); // 获取项目根目录
|
||||
$huawei_pay_client = new \addon\huaweipay\data\sdk\HuaweiPayClient($config_data, $project_root);
|
||||
echo " - 华为支付客户端实例创建成功\n";
|
||||
|
||||
// 尝试创建Pay实例
|
||||
$payModel = new Pay($this->siteId);
|
||||
// 测试关闭订单
|
||||
$params = [
|
||||
'out_trade_no' => 'TEST_CLOSE_' . time()
|
||||
];
|
||||
|
||||
echo " ⚠️ 跳过实际关闭订单测试\n";
|
||||
} catch (\Exception $e) {
|
||||
echo " ⚠️ 关闭订单测试跳过: " . $e->getMessage() . "\n";
|
||||
// 调用真实的关闭订单方法
|
||||
$close_result = $huawei_pay_client->closeOrder($params);
|
||||
echo " - 关闭订单方法调用成功\n";
|
||||
echo " 结果: " . json_encode($close_result, JSON_UNESCAPED_UNICODE) . "\n";
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo " - 关闭订单测试失败: " . $e->getMessage() . "\n";
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试退款方法
|
||||
*/
|
||||
public function testRefundMethod()
|
||||
protected function testRefundMethod()
|
||||
{
|
||||
echo "测试退款方法...";
|
||||
require_once dirname(__DIR__) . '/data/sdk/utils.php';
|
||||
require_once dirname(__DIR__) . '/data/sdk/HuaweiPayClient.php';
|
||||
|
||||
// 添加必要的配置
|
||||
$site_id = '1';
|
||||
$config_data = $this->config;
|
||||
$config_data['site_id'] = $site_id;
|
||||
// 使用文本模式的密钥,而不是证书文件
|
||||
unset($config_data['private_key']);
|
||||
unset($config_data['huawei_public_key']);
|
||||
|
||||
try {
|
||||
// 模拟配置
|
||||
$this->mockConfig();
|
||||
// 创建实际的华为支付客户端实例
|
||||
$project_root = dirname(__DIR__, 4); // 获取项目根目录
|
||||
$huawei_pay_client = new \addon\huaweipay\data\sdk\HuaweiPayClient($config_data, $project_root);
|
||||
echo " - 华为支付客户端实例创建成功\n";
|
||||
|
||||
// 尝试创建Pay实例
|
||||
$payModel = new Pay($this->siteId);
|
||||
// 测试退款
|
||||
$params = [
|
||||
'out_trade_no' => 'TEST_REFUND_' . time(),
|
||||
'out_request_no' => 'REFUND_' . time(),
|
||||
'refund_amount' => 0.01,
|
||||
'refund_reason' => '测试退款'
|
||||
];
|
||||
|
||||
echo " ⚠️ 跳过实际退款测试\n";
|
||||
} catch (\Exception $e) {
|
||||
echo " ⚠️ 退款测试跳过: " . $e->getMessage() . "\n";
|
||||
// 调用真实的退款方法
|
||||
$refund_result = $huawei_pay_client->refund($params);
|
||||
echo " - 退款方法调用成功\n";
|
||||
echo " 结果: " . json_encode($refund_result, JSON_UNESCAPED_UNICODE) . "\n";
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo " - 退款测试失败: " . $e->getMessage() . "\n";
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试查询订单方法
|
||||
*/
|
||||
public function testQueryOrderMethod()
|
||||
protected function testQueryOrderMethod()
|
||||
{
|
||||
echo "测试查询订单方法...";
|
||||
require_once dirname(__DIR__) . '/data/sdk/utils.php';
|
||||
require_once dirname(__DIR__) . '/data/sdk/HuaweiPayClient.php';
|
||||
|
||||
// 添加必要的配置
|
||||
$site_id = '1';
|
||||
$config_data = $this->config;
|
||||
$config_data['site_id'] = $site_id;
|
||||
// 使用文本模式的密钥,而不是证书文件
|
||||
unset($config_data['private_key']);
|
||||
unset($config_data['huawei_public_key']);
|
||||
|
||||
try {
|
||||
// 模拟配置
|
||||
$this->mockConfig();
|
||||
// 创建实际的华为支付客户端实例
|
||||
$project_root = dirname(__DIR__, 4); // 获取项目根目录
|
||||
$huawei_pay_client = new \addon\huaweipay\data\sdk\HuaweiPayClient($config_data, $project_root);
|
||||
echo " - 华为支付客户端实例创建成功\n";
|
||||
|
||||
// 尝试创建Pay实例
|
||||
$payModel = new Pay($this->siteId);
|
||||
// 测试查询订单
|
||||
$params = [
|
||||
'out_trade_no' => 'TEST_QUERY_' . time()
|
||||
];
|
||||
|
||||
echo " ⚠️ 跳过实际查询订单测试\n";
|
||||
} catch (\Exception $e) {
|
||||
echo " ⚠️ 查询订单测试跳过: " . $e->getMessage() . "\n";
|
||||
// 调用真实的查询订单方法
|
||||
$query_result = $huawei_pay_client->queryOrder($params);
|
||||
echo " - 查询订单方法调用成功\n";
|
||||
echo " 结果: " . json_encode($query_result, JSON_UNESCAPED_UNICODE) . "\n";
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo " - 查询订单测试失败: " . $e->getMessage() . "\n";
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 模拟配置
|
||||
* 测试回调验证方法
|
||||
*/
|
||||
private function mockConfig()
|
||||
protected function testCallbackVerification()
|
||||
{
|
||||
// 这里可以添加更高级的模拟技术,例如使用PHPUnit的mock对象
|
||||
// 目前我们只需要确保配置数据能正确加载
|
||||
echo "\n使用配置数据:\n";
|
||||
echo "App ID: {$this->configData['app_id']}\n";
|
||||
echo "商户号: {$this->configData['mch_id']}\n";
|
||||
echo "证书ID: {$this->configData['mch_auth_id']}\n";
|
||||
require_once dirname(__DIR__) . '/data/sdk/utils.php';
|
||||
require_once dirname(__DIR__) . '/data/sdk/HuaweiPayClient.php';
|
||||
|
||||
// 添加必要的配置
|
||||
$site_id = '1';
|
||||
$config_data = $this->config;
|
||||
$config_data['site_id'] = $site_id;
|
||||
// 使用文本模式的密钥,而不是证书文件
|
||||
unset($config_data['private_key']);
|
||||
unset($config_data['huawei_public_key']);
|
||||
|
||||
try {
|
||||
// 创建实际的华为支付客户端实例
|
||||
$project_root = dirname(__DIR__, 4); // 获取项目根目录
|
||||
$huawei_pay_client = new \addon\huaweipay\data\sdk\HuaweiPayClient($config_data, $project_root);
|
||||
echo " - 华为支付客户端实例创建成功\n";
|
||||
|
||||
// 生成模拟回调参数并签名
|
||||
$timestamp = date('Y-m-d H:i:s');
|
||||
$callback_params = [
|
||||
'out_trade_no' => 'TEST_CALLBACK_' . time(),
|
||||
'trade_no' => 'HWPAY_' . time(),
|
||||
'total_amount' => '0.01',
|
||||
'trade_status' => 'SUCCESS',
|
||||
'timestamp' => $timestamp,
|
||||
'app_id' => $config_data['app_id'],
|
||||
'merc_no' => $config_data['merc_no'],
|
||||
'sign_type' => 'RSA2'
|
||||
];
|
||||
|
||||
// 生成签名
|
||||
$sign = '';
|
||||
$signParams = $callback_params;
|
||||
unset($signParams['sign']);
|
||||
unset($signParams['sign_type']);
|
||||
ksort($signParams);
|
||||
|
||||
$stringToSign = '';
|
||||
foreach ($signParams as $key => $value) {
|
||||
$stringToSign .= $key . '=' . $value . '&';
|
||||
}
|
||||
$stringToSign = rtrim($stringToSign, '&');
|
||||
|
||||
// 使用文本模式的私钥生成签名
|
||||
$private_key_content = $config_data['private_key_text'];
|
||||
|
||||
// 对私钥进行格式化,确保openssl_sign能够正确处理
|
||||
$cleanContent = preg_replace('/\s+/', '', $private_key_content);
|
||||
$cleanContent = preg_replace('/-----BEGIN.*?-----/', '', $cleanContent);
|
||||
$cleanContent = preg_replace('/-----END.*?-----/', '', $cleanContent);
|
||||
$formattedKey = "-----BEGIN PRIVATE KEY-----\n";
|
||||
$length = strlen($cleanContent);
|
||||
for ($i = 0; $i < $length; $i += 64) {
|
||||
$formattedKey .= substr($cleanContent, $i, 64) . "\n";
|
||||
}
|
||||
$formattedKey .= "-----END PRIVATE KEY-----";
|
||||
|
||||
openssl_sign($stringToSign, $sign, $formattedKey, OPENSSL_ALGO_SHA256);
|
||||
$callback_params['sign'] = base64_encode($sign);
|
||||
|
||||
// 使用华为支付客户端验证签名
|
||||
$verify_result = $huawei_pay_client->verifySign($callback_params);
|
||||
|
||||
if ($verify_result) {
|
||||
echo " - 回调签名验证通过\n";
|
||||
echo " - 回调参数:" . json_encode($callback_params, JSON_UNESCAPED_UNICODE) . "\n";
|
||||
echo " - 交易状态:{$callback_params['trade_status']}\n";
|
||||
} else {
|
||||
throw new Exception("回调签名验证失败");
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo " - 回调验证测试失败: " . $e->getMessage() . "\n";
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果直接运行此文件,则执行测试
|
||||
if (basename(__FILE__) == basename($_SERVER['PHP_SELF'])) {
|
||||
$test = new PayModelTest();
|
||||
$test->runTests();
|
||||
}
|
||||
// 运行测试
|
||||
$test = new PayModelTest();
|
||||
$test->runTests();
|
||||
Reference in New Issue
Block a user