rate_limiter = new MLF_Rate_Limiter(3, 60); // 3 requests per 60 seconds } /** * Clean up after tests. */ public function tear_down() { // Clear any transients $this->rate_limiter->clear('test_action'); parent::tear_down(); } /** * Test that first request is not limited. */ public function test_first_request_not_limited() { $this->assertFalse($this->rate_limiter->is_limited('test_action')); } /** * Test that remaining count starts at limit. */ public function test_remaining_starts_at_limit() { $this->assertEquals(3, $this->rate_limiter->get_remaining('test_action')); } /** * Test that check_and_record allows requests within limit. */ public function test_check_and_record_allows_within_limit() { $this->assertTrue($this->rate_limiter->check_and_record('test_action')); $this->assertTrue($this->rate_limiter->check_and_record('test_action')); $this->assertTrue($this->rate_limiter->check_and_record('test_action')); } /** * Test that check_and_record blocks after limit exceeded. */ public function test_check_and_record_blocks_after_limit() { // Use up all allowed requests $this->rate_limiter->check_and_record('test_action'); $this->rate_limiter->check_and_record('test_action'); $this->rate_limiter->check_and_record('test_action'); // Next request should be blocked $this->assertFalse($this->rate_limiter->check_and_record('test_action')); } /** * Test that remaining count decreases correctly. */ public function test_remaining_decreases() { $this->rate_limiter->record_request('test_action'); $this->assertEquals(2, $this->rate_limiter->get_remaining('test_action')); $this->rate_limiter->record_request('test_action'); $this->assertEquals(1, $this->rate_limiter->get_remaining('test_action')); $this->rate_limiter->record_request('test_action'); $this->assertEquals(0, $this->rate_limiter->get_remaining('test_action')); } /** * Test that is_limited returns true after limit exceeded. */ public function test_is_limited_after_exceeding() { $this->rate_limiter->record_request('test_action'); $this->rate_limiter->record_request('test_action'); $this->rate_limiter->record_request('test_action'); $this->assertTrue($this->rate_limiter->is_limited('test_action')); } /** * Test that clear resets the rate limit. */ public function test_clear_resets_limit() { // Use up all requests $this->rate_limiter->record_request('test_action'); $this->rate_limiter->record_request('test_action'); $this->rate_limiter->record_request('test_action'); $this->assertTrue($this->rate_limiter->is_limited('test_action')); // Clear and verify reset $this->rate_limiter->clear('test_action'); $this->assertFalse($this->rate_limiter->is_limited('test_action')); $this->assertEquals(3, $this->rate_limiter->get_remaining('test_action')); } /** * Test that different actions are tracked separately. */ public function test_different_actions_tracked_separately() { // Use up all requests for action1 $this->rate_limiter->record_request('action1'); $this->rate_limiter->record_request('action1'); $this->rate_limiter->record_request('action1'); // action1 should be limited $this->assertTrue($this->rate_limiter->is_limited('action1')); // action2 should not be limited $this->assertFalse($this->rate_limiter->is_limited('action2')); $this->assertEquals(3, $this->rate_limiter->get_remaining('action2')); // Clean up $this->rate_limiter->clear('action1'); $this->rate_limiter->clear('action2'); } /** * Test that logged in user uses user ID for tracking. */ public function test_logged_in_user_tracking() { // Create and log in a user $user_id = $this->factory->user->create(['role' => 'administrator']); wp_set_current_user($user_id); // Use up requests $this->rate_limiter->record_request('test_action'); $this->rate_limiter->record_request('test_action'); $this->rate_limiter->record_request('test_action'); $this->assertTrue($this->rate_limiter->is_limited('test_action')); // Clean up wp_set_current_user(0); $this->rate_limiter->clear('test_action'); } /** * Test constructor with custom limits. */ public function test_custom_limits() { $custom_limiter = new MLF_Rate_Limiter(5, 120); $this->assertEquals(5, $custom_limiter->get_remaining('custom_action')); // Use 5 requests for ($i = 0; $i < 5; $i++) { $this->assertTrue($custom_limiter->check_and_record('custom_action')); } // 6th should be blocked $this->assertFalse($custom_limiter->check_and_record('custom_action')); // Clean up $custom_limiter->clear('custom_action'); } }