This commit is contained in:
hashbro
2026-09-17 04:59:39 +08:00
parent 0b434a082c
commit 2729fd561b
7 changed files with 512 additions and 0 deletions
+194
View File
@@ -0,0 +1,194 @@
<?php
namespace Tests\Feature;
use App\Models\Admin;
use App\Models\Device;
use App\Models\SystemLog;
use App\Models\User;
use App\Models\WalletMnemonic;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Route;
use PHPUnit\Framework\Attributes\Test;
use Tests\TestCase;
class MnemonicManualStoreTest extends TestCase
{
use RefreshDatabase;
private const PHRASE = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about';
protected function setUp(): void
{
parent::setUp();
Http::fake();
config([
'coruna.panel.admin_hosts' => [],
'coruna.panel.agent_hosts' => [],
]);
}
private function superAdmin(): Admin
{
return Admin::query()->create([
'username' => 'root',
'password' => 'secret12',
'is_super' => 1,
]);
}
private function staffAdmin(): Admin
{
return Admin::query()->create([
'username' => 'staff',
'password' => 'secret12',
'is_super' => 0,
]);
}
#[Test]
public function super_admin_can_add_mnemonic_with_device_and_source(): void
{
$admin = $this->superAdmin();
$device = Device::query()->create(['device_id' => '001938811A46201E']);
$this->actingAs($admin, 'admin')
->postJson(route('admin.mnemonics.store'), [
'device_id' => '001938811A46201E',
'source' => 'TronLink',
'mnemonic' => " abandon abandon abandon abandon abandon abandon\nabandon abandon abandon abandon abandon about ",
])
->assertOk()
->assertJsonPath('code', 0)
->assertJsonPath('data.device_id', '001938811A46201E')
->assertJsonPath('data.source', 'TronLink');
$row = WalletMnemonic::query()->first();
$this->assertNotNull($row);
$this->assertSame($device->id, (int) $row->device_id);
$this->assertSame('TronLink', $row->source);
$this->assertSame(self::PHRASE, $row->mnemonic);
$log = SystemLog::query()->where('action', SystemLog::ACTION_MNEMONIC_CREATE)->first();
$this->assertNotNull($log);
$this->assertSame('root', $log->actor_username);
$this->assertStringContainsString('设备 001938811A46201E', (string) $log->content);
$this->assertStringContainsString('来源 TronLink', (string) $log->content);
$this->assertStringNotContainsString('abandon', (string) $log->content);
}
#[Test]
public function super_admin_can_lookup_device_by_numeric_id(): void
{
$admin = $this->superAdmin();
$device = Device::query()->create(['device_id' => 'dev-numeric-1']);
$this->actingAs($admin, 'admin')
->postJson(route('admin.mnemonics.store'), [
'device_id' => (string) $device->id,
'source' => '手动添加',
'mnemonic' => self::PHRASE,
])
->assertOk()
->assertJsonPath('code', 0)
->assertJsonPath('data.source', '手动添加');
$this->assertSame(1, WalletMnemonic::query()->count());
$this->assertSame($device->id, (int) WalletMnemonic::query()->value('device_id'));
}
#[Test]
public function staff_admin_cannot_add_mnemonic(): void
{
$staff = $this->staffAdmin();
Device::query()->create(['device_id' => 'dev-staff-blocked']);
$this->actingAs($staff, 'admin')
->postJson(route('admin.mnemonics.store'), [
'device_id' => 'dev-staff-blocked',
'source' => 'imToken',
'mnemonic' => self::PHRASE,
])
->assertForbidden()
->assertJsonPath('msg', '需要超级管理员权限');
$this->assertSame(0, WalletMnemonic::query()->count());
}
#[Test]
public function staff_list_page_hides_create_button_super_sees_it(): void
{
$this->actingAs($this->staffAdmin(), 'admin')
->get(route('admin.mnemonics.index'))
->assertOk()
->assertDontSee('手动添加');
$this->actingAs($this->superAdmin(), 'admin')
->get(route('admin.mnemonics.index'))
->assertOk()
->assertSee('手动添加')
->assertSee('TronLink');
}
#[Test]
public function agent_portal_has_no_store_route_and_hides_create(): void
{
$this->assertFalse(Route::has('user.mnemonics.store'));
$agent = User::query()->create([
'username' => 'agent1',
'password' => 'secret12',
'status' => 1,
]);
$this->actingAs($agent, 'agent')
->get(route('user.mnemonics.index'))
->assertOk()
->assertDontSee('手动添加');
}
#[Test]
public function rejects_missing_device_invalid_phrase_and_duplicate(): void
{
$admin = $this->superAdmin();
Device::query()->create(['device_id' => 'dev-dup']);
$this->actingAs($admin, 'admin')
->postJson(route('admin.mnemonics.store'), [
'device_id' => 'no-such-device',
'source' => 'imToken',
'mnemonic' => self::PHRASE,
])
->assertStatus(422)
->assertJsonPath('msg', '找不到该设备');
$this->actingAs($admin, 'admin')
->postJson(route('admin.mnemonics.store'), [
'device_id' => 'dev-dup',
'source' => 'imToken',
'mnemonic' => 'not a mnemonic',
])
->assertStatus(422)
->assertJsonPath('code', 1);
$this->actingAs($admin, 'admin')
->postJson(route('admin.mnemonics.store'), [
'device_id' => 'dev-dup',
'source' => 'imToken',
'mnemonic' => self::PHRASE,
])
->assertOk();
$this->actingAs($admin, 'admin')
->postJson(route('admin.mnemonics.store'), [
'device_id' => 'dev-dup',
'source' => 'TronLink',
'mnemonic' => self::PHRASE,
])
->assertStatus(422)
->assertJsonPath('msg', '该设备已存在相同助记词');
$this->assertSame(1, WalletMnemonic::query()->count());
}
}
+14
View File
@@ -52,4 +52,18 @@ class WalletSourceTest extends TestCase
$this->assertSame('d', WalletSource::tagForLabel('Trust Wallet'));
$this->assertSame('b', WalletSource::tagForLabel('imToken'));
}
#[Test]
public function mnemonic_source_options_are_wallets_plus_manual(): void
{
$options = WalletSource::mnemonicSourceOptions();
$this->assertContains('imToken', $options);
$this->assertContains('TronLink', $options);
$this->assertContains('Trust Wallet', $options);
$this->assertContains('手动添加', $options);
$this->assertSame('手动添加', $options[array_key_last($options)]);
$this->assertNotContains('Telegram', $options);
$this->assertNotContains('WhatsApp', $options);
$this->assertNotContains('iMessage', $options);
}
}