makePartial(); $svc->shouldReceive('domainResolvesHere')->once()->with('example.com') ->andReturn(['ok' => false, 'resolved' => ['203.0.113.9'], 'serverIp' => '198.51.100.1']); $svc->shouldReceive('probeCertificate')->never(); // never trigger ACME against a wrong host $result = $svc->requestCertificate('example.com'); $this->assertSame('dns_mismatch', $result['status']); $this->assertSame('dns_mismatch', $svc->certStatus()['status']); } public function test_dns_ok_and_handshake_success_is_issued(): void { $svc = Mockery::mock(DeploymentService::class)->makePartial(); $svc->shouldReceive('domainResolvesHere')->once() ->andReturn(['ok' => true, 'resolved' => ['198.51.100.1'], 'serverIp' => '198.51.100.1']); $svc->shouldReceive('probeCertificate')->once()->with('example.com')->andReturnTrue(); $this->assertSame('issued', $svc->requestCertificate('example.com')['status']); } public function test_dns_ok_but_handshake_failure_is_failed(): void { $svc = Mockery::mock(DeploymentService::class)->makePartial(); $svc->shouldReceive('domainResolvesHere')->once()->andReturn(['ok' => true, 'resolved' => [], 'serverIp' => null]); $svc->shouldReceive('probeCertificate')->once()->andReturnFalse(); $this->assertSame('failed', $svc->requestCertificate('example.com')['status']); } public function test_external_tls_mode_is_not_applicable_and_never_probes(): void { Setting::put('tls_mode', 'external'); $svc = Mockery::mock(DeploymentService::class)->makePartial(); $svc->shouldReceive('domainResolvesHere')->never(); $svc->shouldReceive('probeCertificate')->never(); $this->assertSame('not_applicable', $svc->requestCertificate('example.com')['status']); } public function test_request_action_is_throttled_per_user(): void { $this->mock(DeploymentService::class, function ($m) { $m->makePartial(); // Stub the serving state directly (domain() otherwise reads a shared snapshot file). $m->shouldReceive('domain')->andReturn('example.com'); $m->shouldReceive('externalTls')->andReturn(false); // The network-touching request is stubbed; the throttle must cap it at 5 calls. $m->shouldReceive('requestCertificate')->times(5) ->andReturn(['status' => 'issued', 'checkedAt' => now()->toIso8601String()]); }); $this->actingAs(User::factory()->create(['must_change_password' => false])); for ($i = 0; $i < 6; $i++) { Livewire::test(SystemIndex::class)->call('requestCertificate'); } // 6th call was throttled before reaching the service; 5 audited requests. $this->assertSame(5, AuditEvent::where('action', 'tls.cert_request')->count()); } }