Files
2026-11-11 23:19:20 +01:00

94 lines
2.9 KiB
PHP

<?php
use Carbon\CarbonImmutable;
use Illuminate\Support\Facades\Log;
use Mattitja\BadIpBlocker\BadIpStore;
beforeEach(fn () => $this->store = app(BadIpStore::class));
afterEach(fn () => CarbonImmutable::setTestNow());
it('starts empty when no file exists', function () {
expect($this->store->all())->toBe([])
->and($this->store->isBlocked('203.0.113.10'))->toBeFalse();
});
it('blocks and unblocks an ip', function () {
$this->store->block('203.0.113.10', 'test');
expect($this->store->isBlocked('203.0.113.10'))->toBeTrue()
->and($this->store->all()['203.0.113.10']['reason'])->toBe('test');
expect($this->store->unblock('203.0.113.10'))->toBeTrue()
->and($this->store->unblock('203.0.113.10'))->toBeFalse()
->and($this->store->isBlocked('203.0.113.10'))->toBeFalse();
});
it('supports ipv6', function () {
$this->store->block('2001:db8::1');
expect($this->store->isBlocked('2001:db8::1'))->toBeTrue();
});
it('rejects invalid ips', function () {
$this->store->block('not-an-ip');
})->throws(InvalidArgumentException::class);
it('persists to the json file and is visible to other instances', function () {
$this->store->block('198.51.100.20');
$other = new BadIpStore($this->store->path());
expect($other->isBlocked('198.51.100.20'))->toBeTrue()
->and(json_decode(file_get_contents($this->store->path()), true)['ips'])->toHaveKey('198.51.100.20');
});
it('picks up changes made by another process', function () {
expect($this->store->isBlocked('192.0.2.30'))->toBeFalse();
(new BadIpStore($this->store->path()))->block('192.0.2.30');
expect($this->store->isBlocked('192.0.2.30'))->toBeTrue();
});
it('expires blocks with a ttl', function () {
CarbonImmutable::setTestNow('2026-11-11 20:00:00');
$this->store->block('203.0.113.10', null, 60);
expect($this->store->isBlocked('203.0.113.10'))->toBeTrue();
CarbonImmutable::setTestNow('2026-11-11 20:01:01');
expect($this->store->isBlocked('203.0.113.10'))->toBeFalse()
->and($this->store->all())->toBe([]);
});
it('prunes expired entries', function () {
CarbonImmutable::setTestNow('2026-11-11 20:00:00');
$this->store->block('203.0.113.10', null, 60);
$this->store->block('198.51.100.20');
CarbonImmutable::setTestNow('2026-11-11 21:00:00');
expect($this->store->prune())->toBe(1)
->and(array_keys($this->store->all()))->toBe(['198.51.100.20']);
});
it('clears all entries', function () {
$this->store->block('203.0.113.10');
$this->store->clear();
expect($this->store->all())->toBe([]);
});
it('treats a corrupt file as empty and logs a warning', function () {
Log::spy();
@mkdir(dirname($this->store->path()), 0755, true);
file_put_contents($this->store->path(), '{not json');
expect($this->store->all())->toBe([]);
Log::shouldHaveReceived('warning')->once();
});