sslService = Mockery::mock(SslCertificateService::class); $this->environment = Mockery::mock(Environment::class); // Setup environment mock $this->environment->shouldReceive('get') ->with('DOMAIN_NAME', 'michaelschiemer.de') ->andReturn('example.com'); $this->environment->shouldReceive('get') ->with('SSL_EMAIL', 'mail@michaelschiemer.de') ->andReturn('admin@example.com'); $this->environment->shouldReceive('get') ->with('LETSENCRYPT_STAGING', '0') ->andReturn('0'); $this->healthCheck = new SslCertificateHealthCheck( $this->sslService, $this->environment ); }); afterEach(function () { Mockery::close(); }); it('returns healthy status for valid certificate', function () { $status = new CertificateStatus( exists: true, isValid: true, notBefore: new DateTimeImmutable('-30 days'), notAfter: new DateTimeImmutable('+60 days'), issuer: 'Let\'s Encrypt Authority X3', subject: 'example.com', daysUntilExpiry: 60, isExpiring: false, isExpired: false ); $this->sslService->shouldReceive('getStatus') ->once() ->andReturn($status); $result = $this->healthCheck->check(); expect($result->status)->toBe(HealthStatus::HEALTHY); expect($result->operation)->toBe('SSL Certificate Check'); expect($result->details['domain'])->toBe('example.com'); expect($result->details['days_until_expiry'])->toBe(60); }); it('returns unhealthy status when certificate does not exist', function () { $status = CertificateStatus::notFound(); $this->sslService->shouldReceive('getStatus') ->once() ->andReturn($status); $result = $this->healthCheck->check(); expect($result->status)->toBe(HealthStatus::UNHEALTHY); expect($result->reason)->toBe('Certificate not found'); }); it('returns unhealthy status for expired certificate', function () { $status = new CertificateStatus( exists: true, isValid: false, notBefore: new DateTimeImmutable('-180 days'), notAfter: new DateTimeImmutable('-10 days'), issuer: 'Let\'s Encrypt Authority X3', subject: 'example.com', daysUntilExpiry: -10, isExpiring: false, isExpired: true ); $this->sslService->shouldReceive('getStatus') ->once() ->andReturn($status); $result = $this->healthCheck->check(); expect($result->status)->toBe(HealthStatus::UNHEALTHY); expect($result->reason)->toBe('Certificate has expired'); expect($result->details['days_since_expiry'])->toBe(10); }); it('returns warning status for expiring certificate', function () { $status = new CertificateStatus( exists: true, isValid: true, notBefore: new DateTimeImmutable('-60 days'), notAfter: new DateTimeImmutable('+20 days'), issuer: 'Let\'s Encrypt Authority X3', subject: 'example.com', daysUntilExpiry: 20, isExpiring: true, isExpired: false ); $this->sslService->shouldReceive('getStatus') ->once() ->andReturn($status); $result = $this->healthCheck->check(); expect($result->status)->toBe(HealthStatus::WARNING); expect($result->reason)->toBe('Certificate expires in 20 days'); expect($result->details['days_until_expiry'])->toBe(20); }); it('returns unhealthy status for invalid certificate', function () { $status = new CertificateStatus( exists: true, isValid: false, notBefore: new DateTimeImmutable('-30 days'), notAfter: new DateTimeImmutable('+60 days'), issuer: null, subject: null, daysUntilExpiry: 60, isExpiring: false, isExpired: false, errors: ['Certificate verification failed'] ); $this->sslService->shouldReceive('getStatus') ->once() ->andReturn($status); $result = $this->healthCheck->check(); expect($result->status)->toBe(HealthStatus::UNHEALTHY); expect($result->reason)->toBe('Certificate is invalid'); expect($result->details['errors'])->toContain('Certificate verification failed'); }); it('returns unhealthy status on exception', function () { $this->sslService->shouldReceive('getStatus') ->once() ->andThrow(new \RuntimeException('Connection failed')); $result = $this->healthCheck->check(); expect($result->status)->toBe(HealthStatus::UNHEALTHY); expect($result->reason)->toBe('Health check failed'); expect($result->exception)->toBeInstanceOf(\RuntimeException::class); }); it('has correct name and category', function () { expect($this->healthCheck->getName())->toBe('SSL Certificate'); expect($this->healthCheck->getCategory())->toBe(HealthCheckCategory::SECURITY); }); it('has reasonable timeout', function () { $timeout = $this->healthCheck->getTimeout(); expect($timeout)->toBeInt(); expect($timeout)->toBeGreaterThan(0); expect($timeout)->toBeLessThanOrEqual(10000); // Max 10 seconds }); it('measures response time', function () { $status = new CertificateStatus( exists: true, isValid: true, notBefore: null, notAfter: null, issuer: null, subject: null, daysUntilExpiry: 60, isExpiring: false, isExpired: false ); $this->sslService->shouldReceive('getStatus') ->once() ->andReturn($status); $result = $this->healthCheck->check(); expect($result->responseTimeMs)->toBeFloat(); expect($result->responseTimeMs)->toBeGreaterThanOrEqual(0); }); });