37 lines
1.8 KiB
PHP
37 lines
1.8 KiB
PHP
<?php
|
|
|
|
it('enforces a global 2 second Shelly gate in sendPostRequest', function (): void {
|
|
$shellyClass = file_get_contents(app_path('classes/shelly.php'));
|
|
|
|
expect($shellyClass)->not->toBeFalse();
|
|
expect($shellyClass)->toContain('private const SHELLY_RATE_LIMIT_WINDOW_MILLISECONDS = 2000;');
|
|
expect($shellyClass)->toContain("private const SHELLY_RATE_LIMIT_GATE_KEY = 'shelly_cloud_rate_limit_gate';");
|
|
|
|
$sendPostRequestOffset = strpos($shellyClass, 'function sendPostRequest(string $endpoint, array $data): array|object|null');
|
|
expect($sendPostRequestOffset)->not->toBeFalse();
|
|
$sendPostRequestBody = substr($shellyClass, (int)$sendPostRequestOffset, 2200);
|
|
|
|
expect($sendPostRequestBody)->toContain('$this->waitForShellyRateLimitWindow();');
|
|
});
|
|
|
|
it('bounds Shelly cloud HTTP requests with curl timeouts', function (): void {
|
|
$shellyClass = file_get_contents(app_path('classes/shelly.php'));
|
|
|
|
expect($shellyClass)->not->toBeFalse();
|
|
expect($shellyClass)->toContain('private const SHELLY_CONNECT_TIMEOUT_SECONDS = 2;');
|
|
expect($shellyClass)->toContain('private const SHELLY_REQUEST_TIMEOUT_SECONDS = 5;');
|
|
expect($shellyClass)->toContain('CURLOPT_CONNECTTIMEOUT, self::SHELLY_CONNECT_TIMEOUT_SECONDS');
|
|
expect($shellyClass)->toContain('CURLOPT_TIMEOUT, self::SHELLY_REQUEST_TIMEOUT_SECONDS');
|
|
expect($shellyClass)->toContain('CURLOPT_NOSIGNAL, true');
|
|
});
|
|
|
|
it('uses Redis NX PX semantics for cross-request Shelly rate limiting', function (): void {
|
|
$shellyClass = file_get_contents(app_path('classes/shelly.php'));
|
|
|
|
expect($shellyClass)->not->toBeFalse();
|
|
expect($shellyClass)->toContain("self::SHELLY_RATE_LIMIT_GATE_KEY");
|
|
expect($shellyClass)->toContain("'PX'");
|
|
expect($shellyClass)->toContain("'NX'");
|
|
expect($shellyClass)->toContain('pttl(self::SHELLY_RATE_LIMIT_GATE_KEY)');
|
|
});
|