| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- <?php
- /**
- * 冒烟测试:注册校验与持久化 + 会员开通/续费服务。
- * 通过手工注入 think-orm config + DbManager,绕开 webman worker 容器。
- * 若 sa_rental_user.member_expire_at 字段不存在(迁移未跑),跳过 Logic 集成测试。
- * 全部写入在外层事务中执行,结束后回滚。
- */
- require dirname(__DIR__) . '/vendor/autoload.php';
- \Dotenv\Dotenv::createUnsafeMutable(dirname(__DIR__))->load();
- date_default_timezone_set('Asia/Shanghai');
- // 加载 think-orm config(webman 用 type 字段,不是 driver)
- $databaseConfig = require dirname(__DIR__) . '/config/think-orm.php';
- // 手工初始化 think-orm DbManager
- $dbManager = new \Webman\ThinkOrm\DbManager();
- $dbManager->setConfig($databaseConfig);
- \think\Container::getInstance()->instance('think\DbManager', $dbManager);
- \think\Model::setDb($dbManager);
- use plugin\saiadmin\app\logic\user\RentalUserLogic;
- use plugin\saiadmin\app\validate\system\RegisterValidate;
- use plugin\saiadmin\app\validate\user\MemberActivationValidate;
- $pass = 0;
- $fail = 0;
- $skip = 0;
- function assertTrue(bool $cond, string $msg): void
- {
- global $pass, $fail;
- if ($cond) {
- echo "PASS: {$msg}\n";
- $pass++;
- } else {
- echo "FAIL: {$msg}\n";
- $fail++;
- }
- }
- function assertSkip(string $msg): void
- {
- global $skip;
- echo "SKIP: {$msg}\n";
- $skip++;
- }
- // 测试中会调用业务服务的嵌套事务,外层事务确保夹具不落库。
- \think\facade\Db::startTrans();
- try {
- // 准备
- $userId = (int) \think\facade\Db::table('sa_rental_user')->whereNull('delete_time')->value('id');
- assertTrue($userId > 0, "存在至少一个 sa_rental_user (#{$userId}) 用于会员测试");
- // 检测字段是否已加
- $dbName = $databaseConfig['connections']['mysql']['database'];
- $colRow = \think\facade\Db::query(
- "SELECT COUNT(*) AS cnt FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=? AND TABLE_NAME='sa_rental_user' AND COLUMN_NAME='member_expire_at'",
- [$dbName]
- )[0] ?? ['cnt' => 0];
- $fieldExists = (int) $colRow['cnt'] > 0;
- if (!$fieldExists) {
- echo "INFO: sa_rental_user.member_expire_at 字段不存在,请先跑 php scripts/migrate_rental_user_member_fields.php --apply\n";
- }
- // ============================================================
- // 1. 注册校验及持久化
- // ============================================================
- $uniqueUsername = 'testreg' . mt_rand(10000, 99999);
- $validate = new RegisterValidate();
- $regOk = $validate->scene('register')->check([
- 'username' => $uniqueUsername,
- 'password' => 'P@ss1234',
- 'confirmPassword' => 'P@ss1234',
- ]);
- assertTrue($regOk, "注册校验通过 #{$uniqueUsername}");
- // 两次密码不一致应失败
- $mismatchOk = $validate->scene('register')->check([
- 'username' => 'neverusedxyz',
- 'password' => 'P@ss1234',
- 'confirmPassword' => 'different',
- ]);
- assertTrue(!$mismatchOk, "两次密码不一致被 reject");
- // 含下划线应失败(alphaNum 不允许 _)
- $underOk = $validate->scene('register')->check([
- 'username' => 'with_underscore',
- 'password' => 'P@ss1234',
- 'confirmPassword' => 'P@ss1234',
- ]);
- assertTrue(!$underOk, "下划线用户名被 alphaNum 拒绝");
- // 短用户名应失败
- $shortOk = $validate->scene('register')->check([
- 'username' => 'ab',
- 'password' => 'P@ss1234',
- 'confirmPassword' => 'P@ss1234',
- ]);
- assertTrue(!$shortOk, "短用户名(2字符)被 reject");
- // 短密码应失败
- $shortPwdOk = $validate->scene('register')->check([
- 'username' => 'validUser1',
- 'password' => '123',
- 'confirmPassword' => '123',
- ]);
- assertTrue(!$shortPwdOk, "短密码(3字符)被 reject");
- // 模拟 controller 的 INSERT(先 INSERT,再测重复用户名)
- $newUserId = 0;
- if ($regOk) {
- $newUserId = \think\facade\Db::table('sa_system_user')->insertGetId([
- 'username' => $uniqueUsername,
- 'password' => password_hash('P@ss1234', PASSWORD_DEFAULT),
- 'status' => 1,
- 'is_super' => 0,
- 'dashboard' => 'work',
- 'remark' => '匿名注册',
- 'create_time'=> date('Y-m-d H:i:s'),
- 'update_time'=> date('Y-m-d H:i:s'),
- ]);
- assertTrue((int) $newUserId > 0, "sa_system_user 写入成功 (id={$newUserId})");
- }
- // 此时用户已存在,重复用户名应被 unique 拒绝
- $dupOk = $validate->scene('register')->check([
- 'username' => $uniqueUsername,
- 'password' => 'P@ss1234',
- 'confirmPassword' => 'P@ss1234',
- ]);
- assertTrue(!$dupOk, "已存在用户名被 validate unique 拒绝");
- // ============================================================
- // 2. 会员开通 - Logic(依赖字段)
- // ============================================================
- if (!$fieldExists) {
- assertSkip("会员开通 Logic 测试(依赖 member_expire_at 字段,需先跑迁移)");
- } else {
- // 准备 Logic
- $logic = new RentalUserLogic();
- $logic->init(['id' => 1, 'username' => 'admin', 'deptList' => [], 'roleList' => []]);
- $expireTime = date('Y-m-d H:i:s', strtotime('+30 days'));
- $result = $logic->activateMember([
- 'user_id' => $userId,
- 'card_type' => 0,
- 'pay_amount' => 0,
- 'expire_time' => $expireTime,
- 'remark' => 'TEST smoke',
- ], 1, 'admin');
- assertTrue(isset($result['merchant_order_sn']), "激活返回 OK: " . ($result['merchant_order_sn'] ?? '?'));
- assertTrue(($result['card_type_name'] ?? '') === '月卡', "card_type_name=月卡");
- assertTrue(abs(($result['pay_amount'] ?? -1) - 0) < 0.001, "pay_amount=0");
- // 验证两表
- $newRecord = \think\facade\Db::table('sa_member_activation_record')
- ->where('user_id', $userId)
- ->where('remark', 'TEST smoke')
- ->whereNull('delete_time')
- ->order('id', 'desc')->find();
- assertTrue($newRecord !== null, "sa_member_activation_record 写入");
- if ($newRecord !== null) {
- assertTrue((int) $newRecord['source'] === 3, "source=3 后台开通");
- assertTrue((int) $newRecord['card_type'] === 0, "card_type=0 月卡");
- assertTrue((int) $newRecord['manage_agent_id'] === 1, "manage_agent_id=1 admin");
- }
- $userRow = \think\facade\Db::table('sa_rental_user')->where('id', $userId)->whereNull('delete_time')->find();
- assertTrue($userRow['member_expire_at'] === $expireTime, "sa_rental_user.member_expire_at 同步");
- assertTrue((int) $userRow['member_card_type'] === 0, "sa_rental_user.member_card_type=0");
- // 异常路径
- $threw = false;
- try {
- $logic->activateMember([
- 'user_id' => $userId, 'card_type' => 0, 'pay_amount' => 0,
- 'expire_time' => '2020-01-01 00:00:00',
- ], 1, 'admin');
- } catch (\Throwable $e) {
- $threw = true;
- assertTrue(str_contains($e->getMessage(), '到期'), "过期到期时间被 Logic 拒绝: " . $e->getMessage());
- }
- assertTrue($threw, "过期到期时间触发 Logic 异常");
- $threw = false;
- try {
- $logic->activateMember([
- 'user_id' => $userId, 'card_type' => 99, 'pay_amount' => 0,
- 'expire_time' => $expireTime,
- ], 1, 'admin');
- } catch (\Throwable $e) {
- $threw = true;
- assertTrue(str_contains($e->getMessage(), '卡类型'), "非法卡类型被 Logic 拒绝: " . $e->getMessage());
- }
- assertTrue($threw, "非法卡类型触发 Logic 异常");
- $threw = false;
- try {
- $logic->activateMember([
- 'user_id' => 999999999, 'card_type' => 0, 'pay_amount' => 0,
- 'expire_time' => $expireTime,
- ], 1, 'admin');
- } catch (\Throwable $e) {
- $threw = true;
- assertTrue(str_contains($e->getMessage(), '用户不存在'), "不存在用户被 Logic 拒绝: " . $e->getMessage());
- }
- assertTrue($threw, "不存在用户触发 Logic 异常");
- $threw = false;
- try {
- $logic->activateMember([
- 'user_id' => $userId, 'card_type' => 0, 'pay_amount' => -1,
- 'expire_time' => $expireTime,
- ], 1, 'admin');
- } catch (\Throwable $e) {
- $threw = true;
- assertTrue(str_contains($e->getMessage(), '金额'), "负数金额被 Logic 拒绝: " . $e->getMessage());
- }
- assertTrue($threw, "负数金额触发 Logic 异常");
- // 列表查询
- $listResult = $logic->indexList([
- 'source' => '', 'user_id' => '', 'nickname' => '', 'phone' => '',
- ]);
- assertTrue(is_array($listResult) && isset($listResult['data']), "RentalUserLogic::indexList 返回数组含 data");
- if (!empty($listResult['data'])) {
- assertTrue(array_key_exists('member_expire_at', $listResult['data'][0]), "列表行包含 member_expire_at 字段");
- assertTrue(array_key_exists('member_active', $listResult['data'][0]), "列表行包含 member_active 字段");
- }
- }
- // ============================================================
- // 3. RegisterController 实例化
- // ============================================================
- $ctrl = new \plugin\saiadmin\app\controller\system\RegisterController();
- assertTrue($ctrl instanceof \plugin\saiadmin\basic\OpenController, "RegisterController 实例化 OK");
- // ============================================================
- // 4. MemberActivationValidate 异常路径
- // ============================================================
- $memValidate = new MemberActivationValidate();
- $expireTime = date('Y-m-d H:i:s', strtotime('+30 days'));
- $threw = !$memValidate->scene('activate')->check([
- 'user_id' => $userId, 'card_type' => 99, 'pay_amount' => 0,
- 'expire_time' => $expireTime,
- ]);
- assertTrue($threw, "非法卡类型被 MemberActivationValidate 拒绝");
- $threw = !$memValidate->scene('activate')->check([
- 'user_id' => $userId, 'card_type' => 0, 'pay_amount' => -1,
- 'expire_time' => $expireTime,
- ]);
- assertTrue($threw, "负数金额被 MemberActivationValidate 拒绝");
- $threw = !$memValidate->scene('activate')->check([
- 'user_id' => 0, 'card_type' => 0, 'pay_amount' => 0,
- 'expire_time' => $expireTime,
- ]);
- assertTrue($threw, "user_id=0 被 MemberActivationValidate 拒绝");
- } catch (\Throwable $error) {
- $fail++;
- fwrite(STDERR, 'FAIL: ' . $error->getMessage() . PHP_EOL);
- } finally {
- \think\facade\Db::rollback();
- }
- echo "\n=== RESULT: {$pass} pass, {$fail} fail, {$skip} skip ===\n";
- exit($fail > 0 ? 1 : 0);
|