Initial commit
This commit is contained in:
160
tests/Feature/Evaluation/AggregateLogResultsJobTest.php
Normal file
160
tests/Feature/Evaluation/AggregateLogResultsJobTest.php
Normal file
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Evaluation;
|
||||
|
||||
use App\Jobs\AggregateLogResultsJob;
|
||||
use App\Models\LogResult;
|
||||
use App\Models\QsoResult;
|
||||
use App\Models\WorkingQso;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AggregateLogResultsJobTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
private function createQso(int $runId, int $logId, int $bandId, Carbon $ts, int $points): int
|
||||
{
|
||||
$logQso = $this->createLogQso(['log_id' => $logId]);
|
||||
|
||||
$this->createQsoResult([
|
||||
'evaluation_run_id' => $runId,
|
||||
'log_qso_id' => $logQso->id,
|
||||
'is_valid' => true,
|
||||
'points' => $points,
|
||||
]);
|
||||
|
||||
WorkingQso::create([
|
||||
'evaluation_run_id' => $runId,
|
||||
'log_qso_id' => $logQso->id,
|
||||
'log_id' => $logId,
|
||||
'ts_utc' => $ts,
|
||||
'band_id' => $bandId,
|
||||
'call_norm' => 'OK1AAA',
|
||||
'rcall_norm' => 'OK1BBB',
|
||||
'loc_norm' => 'JN00AA',
|
||||
'rloc_norm' => 'JN00AA',
|
||||
]);
|
||||
|
||||
return $logQso->id;
|
||||
}
|
||||
|
||||
public function test_aggregate_applies_operating_window_for_6h(): void
|
||||
{
|
||||
$ruleSet = $this->createRuleSet([
|
||||
'use_multipliers' => false,
|
||||
'multiplier_type' => 'NONE',
|
||||
'multiplier_scope' => 'OVERALL',
|
||||
'multiplier_source' => 'VALID_ONLY',
|
||||
'operating_window_mode' => 'BEST_CONTIGUOUS',
|
||||
'operating_window_hours' => 6,
|
||||
]);
|
||||
$round = $this->createRound();
|
||||
$log = $this->createLog(['round_id' => $round->id]);
|
||||
$run = $this->createEvaluationRun([
|
||||
'round_id' => $round->id,
|
||||
'rule_set_id' => $ruleSet->id,
|
||||
]);
|
||||
$band = $this->createBand();
|
||||
|
||||
$t0 = Carbon::create(2025, 1, 1, 0, 0, 0, 'UTC');
|
||||
$t1 = Carbon::create(2025, 1, 1, 1, 0, 0, 'UTC');
|
||||
$t2 = Carbon::create(2025, 1, 1, 7, 0, 0, 'UTC');
|
||||
$t3 = Carbon::create(2025, 1, 1, 8, 0, 0, 'UTC');
|
||||
|
||||
$firstA = $this->createQso($run->id, $log->id, $band->id, $t0, 10);
|
||||
$firstB = $this->createQso($run->id, $log->id, $band->id, $t1, 10);
|
||||
$secondA = $this->createQso($run->id, $log->id, $band->id, $t2, 10);
|
||||
$secondB = $this->createQso($run->id, $log->id, $band->id, $t3, 10);
|
||||
|
||||
$this->createLogResult([
|
||||
'evaluation_run_id' => $run->id,
|
||||
'log_id' => $log->id,
|
||||
'sixhr_category' => true,
|
||||
'status' => 'OK',
|
||||
]);
|
||||
|
||||
(new AggregateLogResultsJob($run->id, $log->id))->handle();
|
||||
|
||||
$result = LogResult::where('evaluation_run_id', $run->id)
|
||||
->where('log_id', $log->id)
|
||||
->first();
|
||||
|
||||
$this->assertNotNull($result);
|
||||
$this->assertSame(40, $result->official_score);
|
||||
$this->assertSame($t0->toDateTimeString(), $result->operating_window_start_utc?->toDateTimeString());
|
||||
$this->assertSame($t1->toDateTimeString(), $result->operating_window_end_utc?->toDateTimeString());
|
||||
$this->assertSame($t2->toDateTimeString(), $result->operating_window_2_start_utc?->toDateTimeString());
|
||||
$this->assertSame($t3->toDateTimeString(), $result->operating_window_2_end_utc?->toDateTimeString());
|
||||
$this->assertSame(6, $result->operating_window_hours);
|
||||
$this->assertSame(4, $result->operating_window_qso_count);
|
||||
|
||||
$included = QsoResult::where('evaluation_run_id', $run->id)
|
||||
->whereIn('log_qso_id', [$firstA, $firstB, $secondA, $secondB])
|
||||
->pluck('is_operating_window_excluded')
|
||||
->all();
|
||||
$this->assertSame([false, false, false, false], $included);
|
||||
|
||||
$excludedCount = QsoResult::where('evaluation_run_id', $run->id)
|
||||
->where('is_operating_window_excluded', true)
|
||||
->count();
|
||||
$this->assertSame(0, $excludedCount);
|
||||
}
|
||||
|
||||
public function test_aggregate_keeps_all_qso_for_non_6h(): void
|
||||
{
|
||||
$ruleSet = $this->createRuleSet([
|
||||
'use_multipliers' => false,
|
||||
'multiplier_type' => 'NONE',
|
||||
'multiplier_scope' => 'OVERALL',
|
||||
'multiplier_source' => 'VALID_ONLY',
|
||||
'operating_window_mode' => 'BEST_CONTIGUOUS',
|
||||
'operating_window_hours' => 6,
|
||||
]);
|
||||
$round = $this->createRound();
|
||||
$log = $this->createLog(['round_id' => $round->id]);
|
||||
$run = $this->createEvaluationRun([
|
||||
'round_id' => $round->id,
|
||||
'rule_set_id' => $ruleSet->id,
|
||||
]);
|
||||
$band = $this->createBand();
|
||||
|
||||
$t0 = Carbon::create(2025, 1, 1, 0, 0, 0, 'UTC');
|
||||
$t1 = Carbon::create(2025, 1, 1, 1, 0, 0, 'UTC');
|
||||
$t2 = Carbon::create(2025, 1, 1, 7, 0, 0, 'UTC');
|
||||
$t3 = Carbon::create(2025, 1, 1, 8, 0, 0, 'UTC');
|
||||
|
||||
$this->createQso($run->id, $log->id, $band->id, $t0, 10);
|
||||
$this->createQso($run->id, $log->id, $band->id, $t1, 10);
|
||||
$this->createQso($run->id, $log->id, $band->id, $t2, 10);
|
||||
$this->createQso($run->id, $log->id, $band->id, $t3, 10);
|
||||
|
||||
$this->createLogResult([
|
||||
'evaluation_run_id' => $run->id,
|
||||
'log_id' => $log->id,
|
||||
'sixhr_category' => false,
|
||||
'status' => 'OK',
|
||||
]);
|
||||
|
||||
(new AggregateLogResultsJob($run->id, $log->id))->handle();
|
||||
|
||||
$result = LogResult::where('evaluation_run_id', $run->id)
|
||||
->where('log_id', $log->id)
|
||||
->first();
|
||||
|
||||
$this->assertNotNull($result);
|
||||
$this->assertSame(40, $result->official_score);
|
||||
$this->assertNull($result->operating_window_start_utc);
|
||||
$this->assertNull($result->operating_window_end_utc);
|
||||
$this->assertNull($result->operating_window_2_start_utc);
|
||||
$this->assertNull($result->operating_window_2_end_utc);
|
||||
$this->assertNull($result->operating_window_hours);
|
||||
$this->assertNull($result->operating_window_qso_count);
|
||||
|
||||
$excludedCount = QsoResult::where('evaluation_run_id', $run->id)
|
||||
->where('is_operating_window_excluded', true)
|
||||
->count();
|
||||
$this->assertSame(0, $excludedCount);
|
||||
}
|
||||
}
|
||||
72
tests/Feature/Evaluation/EvaluationRunControllerTest.php
Normal file
72
tests/Feature/Evaluation/EvaluationRunControllerTest.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Evaluation;
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class EvaluationRunControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_cancel_requires_authentication(): void
|
||||
{
|
||||
$run = $this->createEvaluationRun();
|
||||
|
||||
$this->postJson("/api/evaluation-runs/{$run->id}/cancel")
|
||||
->assertStatus(401);
|
||||
}
|
||||
|
||||
public function test_non_admin_cannot_cancel(): void
|
||||
{
|
||||
$this->actingAsUser();
|
||||
$run = $this->createEvaluationRun(['status' => 'RUNNING']);
|
||||
|
||||
$this->postJson("/api/evaluation-runs/{$run->id}/cancel")
|
||||
->assertStatus(403);
|
||||
}
|
||||
|
||||
public function test_admin_can_cancel_running_run(): void
|
||||
{
|
||||
$this->actingAsAdmin();
|
||||
$run = $this->createEvaluationRun(['status' => 'RUNNING']);
|
||||
|
||||
$response = $this->postJson("/api/evaluation-runs/{$run->id}/cancel");
|
||||
|
||||
$response->assertStatus(200)
|
||||
->assertJsonFragment(['status' => 'canceled']);
|
||||
|
||||
$this->assertDatabaseHas('evaluation_runs', [
|
||||
'id' => $run->id,
|
||||
'status' => 'CANCELED',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_cancel_rejects_finished_runs(): void
|
||||
{
|
||||
$this->actingAsAdmin();
|
||||
$run = $this->createEvaluationRun(['status' => 'SUCCEEDED']);
|
||||
|
||||
$this->postJson("/api/evaluation-runs/{$run->id}/cancel")
|
||||
->assertStatus(409);
|
||||
}
|
||||
|
||||
public function test_admin_can_set_result_type_and_update_round(): void
|
||||
{
|
||||
$this->actingAsAdmin();
|
||||
$run = $this->createEvaluationRun(['result_type' => null]);
|
||||
$round = $run->round;
|
||||
|
||||
$response = $this->postJson("/api/evaluation-runs/{$run->id}/result-type", [
|
||||
'result_type' => 'PRELIMINARY',
|
||||
]);
|
||||
|
||||
$response->assertStatus(200)
|
||||
->assertJsonFragment(['result_type' => 'PRELIMINARY']);
|
||||
|
||||
$round->refresh();
|
||||
$this->assertSame($run->id, $round->preliminary_evaluation_run_id);
|
||||
$this->assertNull($round->official_evaluation_run_id);
|
||||
$this->assertNull($round->test_evaluation_run_id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Evaluation;
|
||||
|
||||
use App\Jobs\RecalculateOfficialRanksJob;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class RecalculateOfficialRanksSixhrModeTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_iaru_sixhr_merges_single_and_multi(): void
|
||||
{
|
||||
$ruleSet = $this->createRuleSet(['sixhr_ranking_mode' => 'IARU']);
|
||||
$round = $this->createRound();
|
||||
$run = $this->createEvaluationRun(['round_id' => $round->id, 'rule_set_id' => $ruleSet->id]);
|
||||
|
||||
$band = $this->createBand();
|
||||
$single = $this->createCategory(['name' => 'SINGLE']);
|
||||
$multi = $this->createCategory(['name' => 'MULTI']);
|
||||
|
||||
$logSingle = $this->createLog(['round_id' => $round->id]);
|
||||
$logMulti = $this->createLog(['round_id' => $round->id]);
|
||||
|
||||
$resSingle = $this->createLogResult([
|
||||
'evaluation_run_id' => $run->id,
|
||||
'log_id' => $logSingle->id,
|
||||
'band_id' => $band->id,
|
||||
'category_id' => $single->id,
|
||||
'official_score' => 200,
|
||||
'valid_qso_count' => 10,
|
||||
'status' => 'OK',
|
||||
'sixhr_category' => true,
|
||||
]);
|
||||
$resMulti = $this->createLogResult([
|
||||
'evaluation_run_id' => $run->id,
|
||||
'log_id' => $logMulti->id,
|
||||
'band_id' => $band->id,
|
||||
'category_id' => $multi->id,
|
||||
'official_score' => 150,
|
||||
'valid_qso_count' => 8,
|
||||
'status' => 'OK',
|
||||
'sixhr_category' => true,
|
||||
]);
|
||||
|
||||
(new RecalculateOfficialRanksJob($run->id))->handle();
|
||||
|
||||
$resSingle->refresh();
|
||||
$resMulti->refresh();
|
||||
|
||||
$this->assertSame(1, $resSingle->rank_overall);
|
||||
$this->assertSame(2, $resMulti->rank_overall);
|
||||
$this->assertSame('ALL', $resSingle->sixhr_ranking_bucket);
|
||||
$this->assertSame('ALL', $resMulti->sixhr_ranking_bucket);
|
||||
}
|
||||
|
||||
public function test_crk_sixhr_keeps_single_and_multi_separate(): void
|
||||
{
|
||||
$ruleSet = $this->createRuleSet(['sixhr_ranking_mode' => 'CRK']);
|
||||
$round = $this->createRound();
|
||||
$run = $this->createEvaluationRun(['round_id' => $round->id, 'rule_set_id' => $ruleSet->id]);
|
||||
|
||||
$band = $this->createBand();
|
||||
$single = $this->createCategory(['name' => 'SINGLE']);
|
||||
$multi = $this->createCategory(['name' => 'MULTI']);
|
||||
|
||||
$logSingle = $this->createLog(['round_id' => $round->id]);
|
||||
$logMulti = $this->createLog(['round_id' => $round->id]);
|
||||
|
||||
$resSingle = $this->createLogResult([
|
||||
'evaluation_run_id' => $run->id,
|
||||
'log_id' => $logSingle->id,
|
||||
'band_id' => $band->id,
|
||||
'category_id' => $single->id,
|
||||
'official_score' => 200,
|
||||
'valid_qso_count' => 10,
|
||||
'status' => 'OK',
|
||||
'sixhr_category' => true,
|
||||
]);
|
||||
$resMulti = $this->createLogResult([
|
||||
'evaluation_run_id' => $run->id,
|
||||
'log_id' => $logMulti->id,
|
||||
'band_id' => $band->id,
|
||||
'category_id' => $multi->id,
|
||||
'official_score' => 150,
|
||||
'valid_qso_count' => 8,
|
||||
'status' => 'OK',
|
||||
'sixhr_category' => true,
|
||||
]);
|
||||
|
||||
(new RecalculateOfficialRanksJob($run->id))->handle();
|
||||
|
||||
$resSingle->refresh();
|
||||
$resMulti->refresh();
|
||||
|
||||
$this->assertSame(1, $resSingle->rank_overall);
|
||||
$this->assertSame(1, $resMulti->rank_overall);
|
||||
$this->assertSame('SINGLE', $resSingle->sixhr_ranking_bucket);
|
||||
$this->assertSame('MULTI', $resMulti->sixhr_ranking_bucket);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user