#feature: some update

This commit is contained in:
2026-08-12 18:00:09 +08:00
parent ba916f5ce1
commit 103340536b
39 changed files with 2916 additions and 227 deletions
+65
View File
@@ -0,0 +1,65 @@
<?php
namespace Tests\Feature;
use Tests\TestCase;
class HostAccessTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();
config(['toolbox.admin_host' => 'toolbox.local']);
}
public function test_admin_host_can_open_the_toolbox_menu(): void
{
$response = $this->get('http://toolbox.local/');
$response->assertOk();
$response->assertSee('<admin-dashboard>', false);
}
public function test_ip_host_gets_the_standalone_production_diagnosis_page(): void
{
$response = $this->get('http://192.168.1.20/production-diagnosis');
$response->assertOk();
$response->assertSee('<production-diagnosis>', false);
$response->assertDontSee('<admin-dashboard>', false);
}
public function test_ip_host_cannot_open_other_toolbox_pages(): void
{
$this
->get('http://192.168.1.20/')
->assertNotFound();
$this
->get('http://192.168.1.20/env')
->assertNotFound();
$this
->get('http://192.168.1.20/settings')
->assertNotFound();
}
public function test_ip_host_can_only_call_the_production_diagnosis_api(): void
{
$this
->postJson('http://192.168.1.20/api/production-diagnosis/diagnose', [])
->assertUnprocessable();
$this
->getJson('http://192.168.1.20/api/admin/meta')
->assertNotFound();
}
public function test_unconfigured_hostname_is_rejected(): void
{
$this
->get('http://attacker.example/production-diagnosis')
->assertNotFound();
}
}
+98
View File
@@ -0,0 +1,98 @@
<?php
namespace Tests\Feature;
use App\Services\ProductionDiagnosisService;
use Mockery;
use RuntimeException;
use Tests\TestCase;
class ProductionDiagnosisTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();
config(['toolbox.admin_host' => 'toolbox.local']);
}
public function test_validation_errors_are_returned_to_ip_clients(): void
{
$this
->postJson('http://192.168.1.20/api/production-diagnosis/diagnose', [])
->assertUnprocessable()
->assertJson([
'success' => false,
'message' => '请求参数验证失败',
]);
}
public function test_successful_diagnosis_response_is_unchanged(): void
{
$result = [
'type' => 'case',
'type_label' => '病例',
'code' => 'C123',
'found' => true,
'entity' => ['patient_name' => '测试患者'],
'checks' => [],
'can_production' => true,
];
$service = Mockery::mock(ProductionDiagnosisService::class);
$service->shouldReceive('diagnose')
->once()
->with('case', 'C123')
->andReturn($result);
$this->app->instance(ProductionDiagnosisService::class, $service);
$this
->postJson('http://192.168.1.20/api/production-diagnosis/diagnose', [
'type' => 'case',
'code' => ' C123 ',
])
->assertOk()
->assertExactJson([
'success' => true,
'data' => $result,
]);
}
public function test_internal_exception_details_are_not_returned(): void
{
$service = Mockery::mock(ProductionDiagnosisService::class);
$service->shouldReceive('diagnose')
->once()
->andThrow(new RuntimeException('SQLSTATE[HY000] secret database detail'));
$this->app->instance(ProductionDiagnosisService::class, $service);
$response = $this->postJson('http://192.168.1.20/api/production-diagnosis/diagnose', [
'type' => 'case',
'code' => 'C123',
]);
$response
->assertInternalServerError()
->assertExactJson([
'success' => false,
'message' => '诊断服务暂不可用,请稍后重试',
]);
$response->assertDontSee('SQLSTATE');
$response->assertDontSee('secret database detail');
}
public function test_ip_client_is_rate_limited_after_thirty_requests_per_minute(): void
{
for ($attempt = 1; $attempt <= 30; $attempt++) {
$this
->withServerVariables(['REMOTE_ADDR' => '192.168.1.50'])
->postJson('http://192.168.1.20/api/production-diagnosis/diagnose', [])
->assertUnprocessable();
}
$this
->withServerVariables(['REMOTE_ADDR' => '192.168.1.50'])
->postJson('http://192.168.1.20/api/production-diagnosis/diagnose', [])
->assertTooManyRequests();
}
}