Some checks failed
lotterLaravel CI / test (push) Has been cancelled
- 扩大玩家ID随机数位宽降低碰撞概率 - 授信额度变更加 lockForUpdate 防并发下调 - 结算冲正与入账利用唯一索引实现幂等闸门 - 失败登录计数加锁防丢失 - 代理子树查询改用子查询替代全表 pluck - 修复返点默认值百分比单位转换 - 测试中全量 fake 广播事件防 CI 500
169 lines
5.4 KiB
PHP
169 lines
5.4 KiB
PHP
<?php
|
||
|
||
use Tests\TestCase;
|
||
use App\Models\AdminUser;
|
||
use Illuminate\Support\Carbon;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Facades\Schema;
|
||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Test Case
|
||
|--------------------------------------------------------------------------
|
||
|
|
||
| The closure you provide to your test functions is always bound to a specific PHPUnit test
|
||
| case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may
|
||
| need to change it using the "pest()" function to bind different classes or traits.
|
||
|
|
||
*/
|
||
|
||
pest()->extend(TestCase::class)
|
||
// ->use(RefreshDatabase::class)
|
||
->in('Feature');
|
||
|
||
pest()->extend(TestCase::class)->in('Unit');
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Expectations
|
||
|--------------------------------------------------------------------------
|
||
|
|
||
| When you're writing tests, you often need to check that values meet certain conditions. The
|
||
| "expect()" function gives you access to a set of "expectations" methods that you can use
|
||
| to assert different things. Of course, you may extend the Expectation API at any time.
|
||
|
|
||
*/
|
||
|
||
expect()->extend('toBeOne', function () {
|
||
return $this->toBe(1);
|
||
});
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Functions
|
||
|--------------------------------------------------------------------------
|
||
|
|
||
| While Pest is very powerful out-of-the-box, you may have some testing code specific to your
|
||
| project that you don't want to repeat in every file. Here you can also expose helpers as
|
||
| global functions to help you to reduce the number of lines of code in your test files.
|
||
|
|
||
*/
|
||
|
||
/** 为后台测试账号挂上唯一超级管理员(不绑定站点)。 */
|
||
function grantSuperAdminRole(AdminUser $admin): void
|
||
{
|
||
\App\Support\PlatformSystemRoles::ensureSuperAdminRole();
|
||
\App\Support\SuperAdminAccount::assign($admin);
|
||
}
|
||
|
||
/** 为后台测试账号挂上代理节点(需已存在 agent_nodes / admin_user_agents 表)。 */
|
||
/** Feature 测直调 {@see AgentNodeService::createChild()} 时使用的密码。 */
|
||
function agentNodeTestPassword(): string
|
||
{
|
||
return 'TestPass1!';
|
||
}
|
||
|
||
/** @param array<string, mixed> $overrides
|
||
* @return array<string, mixed>
|
||
*/
|
||
function agentChildPayload(array $overrides = []): array
|
||
{
|
||
return array_merge([
|
||
'password' => agentNodeTestPassword(),
|
||
'can_create_child_agent' => true,
|
||
'can_create_player' => true,
|
||
], $overrides);
|
||
}
|
||
|
||
function bindAdminUserToAgent(AdminUser $admin, int $agentNodeId): void
|
||
{
|
||
DB::table('admin_user_agents')->updateOrInsert(
|
||
['admin_user_id' => $admin->id],
|
||
[
|
||
'agent_node_id' => $agentNodeId,
|
||
'is_primary' => true,
|
||
'granted_at' => now(),
|
||
],
|
||
);
|
||
}
|
||
|
||
/** 确保默认站点一级代理已有占成/授信档案(子代理创建与额度校验依赖)。 */
|
||
function ensureRootAgentProfileSeeded(): void
|
||
{
|
||
$rootId = DB::table('agent_nodes')->where('depth', 0)->value('id');
|
||
if ($rootId === null) {
|
||
return;
|
||
}
|
||
|
||
\App\Models\AgentProfile::query()->updateOrCreate(
|
||
['agent_node_id' => (int) $rootId],
|
||
[
|
||
'total_share_rate' => 100,
|
||
'credit_limit' => 1_000_000,
|
||
'allocated_credit' => 0,
|
||
'used_credit' => 0,
|
||
'rebate_limit' => 1,
|
||
'default_player_rebate' => 0,
|
||
],
|
||
);
|
||
}
|
||
|
||
function ensureAdminActionCatalogSeeded(): void
|
||
{
|
||
if (! Schema::hasTable('admin_action_catalog')) {
|
||
Schema::create('admin_action_catalog', static function ($table): void {
|
||
$table->id();
|
||
$table->string('code')->unique();
|
||
$table->string('name');
|
||
$table->unsignedTinyInteger('status')->default(1);
|
||
$table->timestamps();
|
||
});
|
||
}
|
||
|
||
$now = Carbon::now();
|
||
foreach ([
|
||
['code' => 'view', 'name' => '查看'],
|
||
['code' => 'manage', 'name' => '管理'],
|
||
] as $row) {
|
||
DB::table('admin_action_catalog')->updateOrInsert(
|
||
['code' => $row['code']],
|
||
[
|
||
'name' => $row['name'],
|
||
'status' => 1,
|
||
'created_at' => $now,
|
||
'updated_at' => $now,
|
||
],
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 返回项目内所有 Broadcast 事件类列表,供 Event::fake() 拦截广播使用。
|
||
*
|
||
* 业务切到 reverb driver 后,fake 列表不全会导致未拦截的 broadcast 真实派发、
|
||
* 真实连接 Reverb/Pusher,CI 环境无可用 server 时直接 500。本 helper 保证:
|
||
* Event::fake(allBroadcastEvents())
|
||
* 一行覆盖流程中可能触发的所有事件。
|
||
*
|
||
* 不可使用 Event::fake() 无参形式:会同时拦截 Illuminate\Database\Events\* 等框架事件,
|
||
* 干扰 RefreshDatabase / model events / 自定义 boot hooks。
|
||
*
|
||
* @return list<class-string>
|
||
*/
|
||
function allBroadcastEvents(): array
|
||
{
|
||
return [
|
||
\App\Events\BalanceUpdateBroadcast::class,
|
||
\App\Events\DrawCountdownBroadcast::class,
|
||
\App\Events\DrawResultPublishedBroadcast::class,
|
||
\App\Events\DrawStatusChangeBroadcast::class,
|
||
\App\Events\JackpotBurstBroadcast::class,
|
||
\App\Events\OddsUpdateBroadcast::class,
|
||
\App\Events\PlayCatalogUpdatedBroadcast::class,
|
||
\App\Events\PlayToggleBroadcast::class,
|
||
\App\Events\RiskSoldOutBroadcast::class,
|
||
\App\Events\RiskWarningBroadcast::class,
|
||
];
|
||
}
|