test(jobs): add controller and model test coverage

Add PHPUnit tests for Jobs feature to lock in current
behavior before further changes.

- JobsControllerTest: covers /jobs index render, saveSettings
  validation (invalid mode, non-natural max_seconds) and
  success path, saveThrottles save/soft-delete-missing/invalid
  period handling, throttles partial render, and stub
  processAllJobs/processSelectedJobs endpoints
- JobThrottleModelTest: covers exists(), saveValue() insert vs
  update, getAll() excluding soft-deleted rows, and delete()
  soft-delete behavior

Signed-off-by: objecttothis <17935339+objecttothis@users.noreply.github.com>
This commit is contained in:
objecttothis committed 2026-09-17 15:14:10 +04:00
1 parent 84abb9a4af
commit f2b73fda36
2 files changed
+264

No files matched your search

+172
View File
@@ -0,0 +1,172 @@
<?php
namespace Tests\Controllers;
use App\Models\JobThrottle;
use CodeIgniter\Database\Config;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\DatabaseTestTrait;
use CodeIgniter\Test\FeatureTestTrait;
class JobsControllerTest extends CIUnitTestCase
{
use DatabaseTestTrait;
use FeatureTestTrait;
protected $migrate = true;
protected $migrateOnce = true;
protected $seedOnce = true;
protected $refresh = false;
protected $namespace = null;
private static bool $doneBootstrap = false;
protected JobThrottle $jobThrottle;
protected function setUp(): void
{
if (self::$doneBootstrap === false) {
Config::seeder($this->DBGroup)->call('App\Database\Seeds\TestDatabaseBootstrapSeeder');
Config::connect($this->DBGroup)->close();
self::$doneBootstrap = true;
}
parent::setUp();
$this->jobThrottle = model(JobThrottle::class);
$this->db->table('job_throttles')->truncate();
}
protected function loginAsAdmin(): void
{
$this->withSession([
'person_id' => 1,
'menu_group' => 'office'
]);
}
public function testGetIndexRendersManageView(): void
{
$this->loginAsAdmin();
$response = $this->get('/jobs');
$response->assertStatus(200);
$response->assertSee(lang('Jobs.settings'));
}
public function testPostSaveSettingsRejectsInvalidMode(): void
{
$this->loginAsAdmin();
$response = $this->post('/jobs/saveSettings', [
'mode' => 'bogus',
'web_max_seconds' => 5,
]);
$response->assertStatus(200);
$result = json_decode($response->getJSON(), true);
$this->assertFalse($result['success']);
}
public function testPostSaveSettingsRejectsNonNaturalMaxSeconds(): void
{
$this->loginAsAdmin();
$response = $this->post('/jobs/saveSettings', [
'mode' => 'web',
'web_max_seconds' => -5,
]);
$response->assertStatus(200);
$result = json_decode($response->getJSON(), true);
$this->assertFalse($result['success']);
}
public function testPostSaveSettingsSavesValidSettings(): void
{
$this->loginAsAdmin();
$response = $this->post('/jobs/saveSettings', [
'mode' => 'manual',
'web_max_seconds' => 10,
]);
$response->assertStatus(200);
$result = json_decode($response->getJSON(), true);
$this->assertTrue($result['success']);
$this->seeInDatabase('app_config', ['key' => 'jobs_mode', 'value' => 'manual']);
$this->seeInDatabase('app_config', ['key' => 'jobs_web_max_seconds', 'value' => '10']);
}
public function testPostSaveThrottlesSavesAndDeletesMissingThrottles(): void
{
$this->loginAsAdmin();
$this->jobThrottle->saveValue(['max_count' => 5, 'period' => 'minute'], 1);
$this->jobThrottle->saveValue(['max_count' => 20, 'period' => 'day'], 2);
// Throttle 2 is omitted from the post payload, so it should be soft-deleted.
$response = $this->post('/jobs/saveThrottles', [
'throttle_count_1' => 15,
'throttle_period_1' => 'hour',
]);
$response->assertStatus(200);
$result = json_decode($response->getJSON(), true);
$this->assertTrue($result['success']);
$this->seeInDatabase('job_throttles', ['throttle_id' => 1, 'max_count' => 15, 'period' => 'hour', 'deleted' => 0]);
$this->seeInDatabase('job_throttles', ['throttle_id' => 2, 'deleted' => 1]);
}
public function testPostSaveThrottlesRejectsInvalidPeriod(): void
{
$this->loginAsAdmin();
$response = $this->post('/jobs/saveThrottles', [
'throttle_count_1' => 15,
'throttle_period_1' => 'fortnight',
]);
$response->assertStatus(200);
$result = json_decode($response->getJSON(), true);
$this->assertFalse($result['success']);
}
public function testGetThrottlesRendersPartial(): void
{
$this->loginAsAdmin();
$this->jobThrottle->saveValue(['max_count' => 5, 'period' => 'minute'], 1);
$response = $this->get('/jobs/throttles');
$response->assertStatus(200);
$response->assertSeeElement('#throttle_count_1');
}
public function testPostProcessAllJobsReturnsStub(): void
{
$this->loginAsAdmin();
$response = $this->post('/jobs/processAllJobs');
$response->assertStatus(200);
$result = json_decode($response->getJSON(), true);
$this->assertFalse($result['success']);
$this->assertTrue($result['stub']);
}
public function testPostProcessSelectedJobsReturnsStub(): void
{
$this->loginAsAdmin();
$response = $this->post('/jobs/processSelectedJobs');
$response->assertStatus(200);
$result = json_decode($response->getJSON(), true);
$this->assertFalse($result['success']);
$this->assertTrue($result['stub']);
}
}
+92
View File
@@ -0,0 +1,92 @@
<?php
namespace Tests\Models;
use App\Models\JobThrottle;
use CodeIgniter\Database\Config;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\DatabaseTestTrait;
class JobThrottleModelTest extends CIUnitTestCase
{
use DatabaseTestTrait;
protected $migrate = true;
protected $migrateOnce = true;
protected $refresh = false;
protected $namespace = null;
private static bool $doneBootstrap = false;
protected JobThrottle $jobThrottle;
protected function setUp(): void
{
if (self::$doneBootstrap === false) {
Config::seeder($this->DBGroup)->call('App\Database\Seeds\TestDatabaseBootstrapSeeder');
Config::connect($this->DBGroup)->close();
self::$doneBootstrap = true;
}
parent::setUp();
$this->jobThrottle = model(JobThrottle::class);
$this->db->table('job_throttles')->truncate();
}
public function testExistsReturnsFalseForUnknownId(): void
{
$this->assertFalse($this->jobThrottle->exists(999999));
}
public function testSaveValueInsertsWhenThrottleDoesNotExist(): void
{
$this->assertTrue($this->jobThrottle->saveValue(['max_count' => 10, 'period' => 'hour'], 1));
$this->seeInDatabase('job_throttles', [
'throttle_id' => 1,
'max_count' => 10,
'period' => 'hour',
'deleted' => 0,
]);
}
public function testSaveValueUpdatesWhenThrottleExists(): void
{
$this->jobThrottle->saveValue(['max_count' => 10, 'period' => 'hour'], 1);
$this->assertTrue($this->jobThrottle->exists(1));
$this->assertTrue($this->jobThrottle->saveValue(['max_count' => 25, 'period' => 'day'], 1));
$this->seeInDatabase('job_throttles', [
'throttle_id' => 1,
'max_count' => 25,
'period' => 'day',
]);
$this->assertEquals(1, $this->db->table('job_throttles')->countAllResults());
}
public function testGetAllExcludesDeletedThrottles(): void
{
$this->jobThrottle->saveValue(['max_count' => 5, 'period' => 'minute'], 1);
$this->jobThrottle->saveValue(['max_count' => 15, 'period' => 'day'], 2);
$this->jobThrottle->delete(2);
$results = $this->jobThrottle->getAll()->getResultArray();
$this->assertCount(1, $results);
$this->assertSame('1', (string) $results[0]['throttle_id']);
}
public function testDeleteSoftDeletesThrottle(): void
{
$this->jobThrottle->saveValue(['max_count' => 5, 'period' => 'minute'], 1);
$this->assertTrue($this->jobThrottle->delete(1));
$this->seeInDatabase('job_throttles', ['throttle_id' => 1, 'deleted' => 1]);
$this->assertCount(0, $this->jobThrottle->getAll()->getResultArray());
}
}