145 lines
5.4 KiB
PHP
145 lines
5.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use app\adminapi\logic\firstvisit\WecomAcquisitionCustomerLogic;
|
|
use app\common\service\qywx\QywxCustomerAcquisitionApiService;
|
|
use app\common\service\qywx\QywxCustomerAcquisitionCustomerService;
|
|
use think\facade\Db;
|
|
|
|
require dirname(__DIR__) . '/vendor/autoload.php';
|
|
|
|
$app = new think\App();
|
|
$app->initialize();
|
|
|
|
$assert = static function (bool $condition, string $message): void {
|
|
if (!$condition) {
|
|
throw new RuntimeException($message);
|
|
}
|
|
};
|
|
$admin = Db::name('admin')->where('root', 1)->whereNull('delete_time')->find();
|
|
if (!$admin) {
|
|
throw new RuntimeException('未找到 root 管理员,无法执行获客客户统计冒烟测试');
|
|
}
|
|
$assert(
|
|
Db::name('dev_crontab')
|
|
->where('command', 'qywx:retry-customer-acquisition-events')
|
|
->whereNull('delete_time')
|
|
->count() === 1,
|
|
'获客回调每分钟重试任务未写入数据库'
|
|
);
|
|
|
|
$suffix = bin2hex(random_bytes(5));
|
|
$linkId = '__smoke_link_' . $suffix;
|
|
$externalUserId = '__smoke_external_' . $suffix;
|
|
$userId = '__smoke_user_' . $suffix;
|
|
$eventTime = time();
|
|
$api = new class($linkId, $externalUserId, $userId) extends QywxCustomerAcquisitionApiService {
|
|
public function __construct(
|
|
private string $testLinkId,
|
|
private string $testExternalUserId,
|
|
private string $testUserId
|
|
) {
|
|
}
|
|
|
|
public function listCustomers(string $linkId, string $cursor = '', int $limit = 1000): array
|
|
{
|
|
return [
|
|
'customer_list' => [[
|
|
'external_userid' => $this->testExternalUserId,
|
|
'userid' => $this->testUserId,
|
|
'chat_status' => 2,
|
|
'state' => 'smoke-sync',
|
|
]],
|
|
'next_cursor' => '',
|
|
];
|
|
}
|
|
|
|
public function getChatInfo(string $chatKey): array
|
|
{
|
|
return [
|
|
'external_userid' => $this->testExternalUserId,
|
|
'userid' => $this->testUserId,
|
|
'chat_info' => [
|
|
'link_id' => $this->testLinkId,
|
|
'state' => 'smoke-chat',
|
|
'recv_msg_cnt' => 5,
|
|
],
|
|
];
|
|
}
|
|
};
|
|
$service = new QywxCustomerAcquisitionCustomerService($api);
|
|
|
|
Db::startTrans();
|
|
try {
|
|
$startMessage = [
|
|
'MsgId' => 'smoke-start-' . $suffix,
|
|
'ChangeType' => 'customer_start_chat',
|
|
'CreateTime' => $eventTime,
|
|
'LinkID' => $linkId,
|
|
'ExternalUserID' => $externalUserId,
|
|
'UserID' => $userId,
|
|
'State' => 'smoke-start',
|
|
];
|
|
$service->handleCallback($startMessage);
|
|
|
|
$chatMessage = [
|
|
'MsgId' => 'smoke-chat-' . $suffix,
|
|
'ChangeType' => 'message_from_customer',
|
|
'CreateTime' => $eventTime + 1,
|
|
'ChatKey' => 'smoke-chat-key-' . $suffix,
|
|
];
|
|
$service->handleCallback($chatMessage);
|
|
$duplicate = $service->handleCallback($chatMessage);
|
|
$assert(($duplicate['duplicate'] ?? false) === true, '相同 message_from_customer 回调必须幂等');
|
|
|
|
// 远端客户列表中的 chat_status=2 是“未知”,不能把已由回调确认的状态 1 回退。
|
|
$service->syncLink($linkId);
|
|
|
|
$customer = Db::name('qywx_customer_acquisition_customer')
|
|
->where('link_id', $linkId)
|
|
->where('external_userid', $externalUserId)
|
|
->where('userid', $userId)
|
|
->find();
|
|
$assert((int) ($customer['chat_status'] ?? -1) === 1, '列表同步错误回退了已确认的聊天状态');
|
|
$assert((int) ($customer['recv_msg_cnt'] ?? -1) === 5, '累计接收消息数不正确或被重复累加');
|
|
$assert((int) ($customer['message_count_known'] ?? 0) === 1, '精确消息次数标识未保存');
|
|
|
|
$stats = WecomAcquisitionCustomerLogic::statistics(
|
|
['keyword' => $externalUserId, 'page_size' => 20],
|
|
(int) $admin['id'],
|
|
$admin
|
|
);
|
|
$summary = $stats['summary'] ?? [];
|
|
$assert((int) ($summary['customer_count'] ?? 0) === 1, '获客客户汇总数量不正确');
|
|
$assert((int) ($summary['started_chat_count'] ?? 0) === 1, '已发消息客户数不正确');
|
|
$assert((int) ($summary['received_message_count'] ?? 0) === 5, '接收消息汇总不正确');
|
|
$assert((int) ($summary['message_count_known_count'] ?? 0) === 1, '精确消息统计覆盖数不正确');
|
|
$row = $stats['lists'][0] ?? [];
|
|
$assert(!array_key_exists('external_userid', $row), '接口不应返回原始客户 ExternalUserID');
|
|
$assert(str_contains((string) ($row['external_userid_masked'] ?? ''), '*'), '客户标识没有脱敏');
|
|
|
|
$eventKeys = [
|
|
QywxCustomerAcquisitionCustomerService::eventKey($startMessage, 'customer_start_chat', '', $eventTime),
|
|
QywxCustomerAcquisitionCustomerService::eventKey(
|
|
$chatMessage,
|
|
'message_from_customer',
|
|
(string) $chatMessage['ChatKey'],
|
|
$eventTime + 1
|
|
),
|
|
];
|
|
$events = Db::name('qywx_customer_acquisition_event')
|
|
->whereIn('event_key', $eventKeys)
|
|
->select()->toArray();
|
|
$assert(count($events) === 2, '回调事件审计数量不正确');
|
|
foreach ($events as $event) {
|
|
$assert((int) ($event['status'] ?? 0) === 1, '成功回调未进入成功终态');
|
|
$assert((string) ($event['chat_key'] ?? '') === '', '成功后仍保存了敏感 ChatKey');
|
|
$assert(($event['raw_json'] ?? null) === null, '成功后仍保存了原始回调');
|
|
}
|
|
|
|
echo "WECOM_ACQUISITION_CUSTOMER_STATISTICS_SMOKE_OK messages=5\n";
|
|
} finally {
|
|
Db::rollback();
|
|
}
|