where('key', 'supplier_webhook_secret')->update(['value' => 'test-secret-32chars-aaaaaaaaaaaaaa']); SystemSetting::query()->where('key', 'supplier_ip_allowlist')->update(['value' => '[]']); // Clear rate limiter between tests RateLimiter::clear('supplier-webhook:127.0.0.1'); }); it('logs status=received when lead is accepted (202)', function () { Bus::fake(); $this->postJson('/api/webhook/supplier/test-secret-32chars-aaaaaaaaaaaaaa', [ 'vid' => 900001, 'project' => 'B1_log-test.ru', 'phone' => '79991234567', 'time' => time(), ])->assertStatus(202); $log = DB::table('webhook_log') ->where('status', 'received') ->where('source', 'supplier') ->latest('created_at') ->first(); expect($log)->not->toBeNull(); expect($log->status)->toBe('received'); expect($log->source)->toBe('supplier'); expect($log->tenant_id)->toBeNull(); }); it('logs status=rejected_secret when secret is wrong (404)', function () { $this->postJson('/api/webhook/supplier/wrong-secret-here', [ 'vid' => 900002, 'project' => 'B1_log-test.ru', 'phone' => '79991234567', 'time' => time(), ])->assertStatus(404); $log = DB::table('webhook_log') ->where('status', 'rejected_secret') ->where('source', 'supplier') ->latest('created_at') ->first(); expect($log)->not->toBeNull(); expect($log->status)->toBe('rejected_secret'); expect($log->tenant_id)->toBeNull(); }); it('logs status=rejected_ip when IP is not in allowlist (404)', function () { SystemSetting::query()->where('key', 'supplier_ip_allowlist') ->update(['value' => '["1.2.3.4"]']); $this->withServerVariables(['REMOTE_ADDR' => '5.6.7.8']) ->postJson('/api/webhook/supplier/test-secret-32chars-aaaaaaaaaaaaaa', [ 'vid' => 900003, 'project' => 'B1_log-test.ru', 'phone' => '79991234567', 'time' => time(), ])->assertStatus(404); $log = DB::table('webhook_log') ->where('status', 'rejected_ip') ->where('source', 'supplier') ->latest('created_at') ->first(); expect($log)->not->toBeNull(); expect($log->status)->toBe('rejected_ip'); expect($log->tenant_id)->toBeNull(); }); it('logs status=rate_limited when per-IP rate limit exceeded (429)', function () { Bus::fake(); // Saturate the rate limiter $key = 'supplier-webhook:127.0.0.1'; $limit = 600; // RATE_LIMIT_PER_MINUTE constant for ($i = 0; $i < $limit; $i++) { RateLimiter::hit($key, 60); } $this->postJson('/api/webhook/supplier/test-secret-32chars-aaaaaaaaaaaaaa', [ 'vid' => 900004, 'project' => 'B1_log-test.ru', 'phone' => '79991234567', 'time' => time(), ])->assertStatus(429); $log = DB::table('webhook_log') ->where('status', 'rate_limited') ->where('source', 'supplier') ->latest('created_at') ->first(); expect($log)->not->toBeNull(); expect($log->status)->toBe('rate_limited'); expect($log->tenant_id)->toBeNull(); });