diff --git a/app/Console/Commands/CleanDatabase.php b/app/Console/Commands/CleanDatabase.php new file mode 100644 index 0000000000..8fe0bbf3d2 --- /dev/null +++ b/app/Console/Commands/CleanDatabase.php @@ -0,0 +1,51 @@ + 'stderr']); + + Log::info("Deleting unused rows from `banner`"); + $num_deleted = DB::delete("DELETE FROM banner WHERE projectid != 0 AND + NOT EXISTS (SELECT 1 FROM project WHERE project.id = banner.projectid)"); + Log::info("{$num_deleted} rows deleted from `banner`"); + + DatabaseCleanupUtils::deleteUnusedRows('dailyupdate', 'projectid', 'project'); + + DatabaseCleanupUtils::deleteUnusedRows('buildfailuredetails', 'id', 'buildfailure', 'detailsid'); + DatabaseCleanupUtils::deleteUnusedRows('configure', 'id', 'build2configure', 'configureid'); + DatabaseCleanupUtils::deleteUnusedRows('coveragefile', 'id', 'coverage', 'fileid'); + DatabaseCleanupUtils::deleteUnusedRows('dailyupdatefile', 'dailyupdateid', 'dailyupdate'); + DatabaseCleanupUtils::deleteUnusedRows('note', 'id', 'build2note', 'noteid'); + DatabaseCleanupUtils::deleteUnusedRows('testoutput', 'id', 'build2test', 'outputid'); + DatabaseCleanupUtils::deleteUnusedRows('uploadfile', 'id', 'build2uploadfile', 'fileid'); + + Log::info("Deleting unused rows from `image`"); + $num_deleted = DB::delete("DELETE FROM image WHERE + NOT EXISTS (SELECT 1 FROM project WHERE project.imageid = image.id) AND + NOT EXISTS (SELECT 1 FROM test2image WHERE test2image.imgid = image.id)"); + Log::info("{$num_deleted} rows deleted from `image`"); + } +} diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php index 337e816dd1..4dc163e556 100644 --- a/app/Http/Controllers/AdminController.php +++ b/app/Http/Controllers/AdminController.php @@ -331,7 +331,6 @@ public function upgrade() @$ComputeTestTiming = $_POST['ComputeTestTiming']; @$ComputeUpdateStatistics = $_POST['ComputeUpdateStatistics']; - @$Cleanup = $_POST['Cleanup']; @$Dependencies = $_POST['Dependencies']; @$Audit = $_POST['Audit']; @$ClearAudit = $_POST['Clear']; @@ -377,55 +376,6 @@ public function upgrade() unlink($configFile); } - - /* Cleanup the database */ - if ($Cleanup) { - self::delete_unused_rows('banner', 'projectid', 'project'); - self::delete_unused_rows('blockbuild', 'projectid', 'project'); - self::delete_unused_rows('build', 'projectid', 'project'); - self::delete_unused_rows('buildgroup', 'projectid', 'project'); - self::delete_unused_rows('labelemail', 'projectid', 'project'); - self::delete_unused_rows('project2repositories', 'projectid', 'project'); - self::delete_unused_rows('dailyupdate', 'projectid', 'project'); - self::delete_unused_rows('subproject', 'projectid', 'project'); - self::delete_unused_rows('coveragefilepriority', 'projectid', 'project'); - self::delete_unused_rows('user2project', 'projectid', 'project'); - self::delete_unused_rows('userstatistics', 'projectid', 'project'); - - self::delete_unused_rows('build2configure', 'buildid', 'build'); - self::delete_unused_rows('build2note', 'buildid', 'build'); - self::delete_unused_rows('build2test', 'buildid', 'build'); - self::delete_unused_rows('buildemail', 'buildid', 'build'); - self::delete_unused_rows('builderror', 'buildid', 'build'); - self::delete_unused_rows('builderrordiff', 'buildid', 'build'); - self::delete_unused_rows('buildfailure', 'buildid', 'build'); - self::delete_unused_rows('buildfailuredetails', 'id', 'buildfailure', 'detailsid'); - self::delete_unused_rows('buildtesttime', 'buildid', 'build'); - self::delete_unused_rows('configure', 'id', 'build2configure', 'configureid'); - self::delete_unused_rows('configureerror', 'configureid', 'configure'); - self::delete_unused_rows('configureerrordiff', 'buildid', 'build'); - self::delete_unused_rows('coverage', 'buildid', 'build'); - self::delete_unused_rows('coveragefilelog', 'buildid', 'build'); - self::delete_unused_rows('coveragesummary', 'buildid', 'build'); - self::delete_unused_rows('coveragesummarydiff', 'buildid', 'build'); - self::delete_unused_rows('dynamicanalysis', 'buildid', 'build'); - self::delete_unused_rows('label2build', 'buildid', 'build'); - self::delete_unused_rows('subproject2build', 'buildid', 'build'); - self::delete_unused_rows('summaryemail', 'buildid', 'build'); - self::delete_unused_rows('testdiff', 'buildid', 'build'); - - self::delete_unused_rows('dynamicanalysisdefect', 'dynamicanalysisid', 'dynamicanalysis'); - self::delete_unused_rows('subproject2subproject', 'subprojectid', 'subproject'); - - self::delete_unused_rows('dailyupdatefile', 'dailyupdateid', 'dailyupdate'); - self::delete_unused_rows('coveragefile', 'id', 'coverage', 'fileid'); - - self::delete_unused_rows('dailyupdatefile', 'dailyupdateid', 'dailyupdate'); - self::delete_unused_rows('test2image', 'outputid', 'testoutput'); - - $xml .= add_XML_value('alert', 'Database cleanup complete.'); - } - /* Check the builds with wrong date */ if ($CheckBuildsWrongDate) { $currentdate = time() + 3600 * 24 * 3; // or 3 days away from now @@ -506,11 +456,4 @@ public function userStatistics(): View { return $this->angular_view('userStatistics'); } - - /** Delete unused rows */ - private static function delete_unused_rows($table, $field, $targettable, $selectfield = 'id'): void - { - DB::delete("DELETE FROM $table WHERE $field NOT IN (SELECT $selectfield AS $field FROM $targettable)"); - echo pdo_error(); - } } diff --git a/app/Utils/DatabaseCleanupUtils.php b/app/Utils/DatabaseCleanupUtils.php index b12dc4d936..615d69ac7e 100644 --- a/app/Utils/DatabaseCleanupUtils.php +++ b/app/Utils/DatabaseCleanupUtils.php @@ -266,8 +266,6 @@ public static function removeBuild($buildid) : void // Use array_diff to get the list of tests that should be deleted. $testoutputs_to_delete = array_diff($all_outputids, $testoutputs_to_save); if (!empty($testoutputs_to_delete)) { - self::deleteRowsChunked('DELETE FROM testoutput WHERE id IN ', $testoutputs_to_delete); - $testoutputs_to_delete_prepare_array = $db->createPreparedArray(count($testoutputs_to_delete)); // Check if the images for the test are not shared $test2image = DB::select(" @@ -291,6 +289,8 @@ public static function removeBuild($buildid) : void $imgids_prepare_array = $db->createPreparedArray(count($imgids)); DB::delete("DELETE FROM image WHERE id IN $imgids_prepare_array", $imgids); } + + self::deleteRowsChunked('DELETE FROM testoutput WHERE id IN ', $testoutputs_to_delete); } } @@ -366,4 +366,50 @@ private static function deleteRowsChunked(string $query, array $ids): void usleep(1); } } + + /** Delete unused rows in batches */ + public static function deleteUnusedRows(string $table, string $field, string $targettable, string $selectfield = 'id'): void + { + $start = DB::table($table)->min($field); + $max = DB::table($table)->max($field); + if (!is_numeric($start) || !is_numeric($max)) { + Log::info("Could not determine min and max for `{$field}` on `{$table}`"); + return; + } + + $start = intval($start); + $max = intval($max); + $total = $max - $start + 1; + if ($total < 1) { + Log::info("Invalid values found for min ({$start}) and/or max ({$max}) for `{$field}` on `{$table}`"); + return; + } + $num_done = 0; + $num_deleted = 0; + $next_report = 10; + $done = false; + Log::info("Deleting unused rows from `{$table}`"); + while (!$done) { + $end = $start + 49999; + $num_deleted += DB::delete(" + DELETE FROM {$table} + WHERE {$field} BETWEEN {$start} AND {$end} + AND NOT EXISTS + (SELECT 1 FROM {$targettable} WHERE {$targettable}.{$selectfield} = {$table}.{$field})"); + $num_done += 50000; + if ($end >= $max) { + $done = true; + } else { + usleep(1); + $start += 50000; + // Calculate percentage of work completed so far. + $percent = round(($num_done / $total) * 100, -1); + if ($percent > $next_report) { + Log::info("Cleaning `{$table}`: {$next_report}%"); + $next_report = $next_report + 10; + } + } + } + Log::info("{$num_deleted} rows deleted from `{$table}`"); + } } diff --git a/app/cdash/public/upgrade.xsl b/app/cdash/public/upgrade.xsl index 6142c3acf9..993ea88e5f 100644 --- a/app/cdash/public/upgrade.xsl +++ b/app/cdash/public/upgrade.xsl @@ -30,10 +30,6 @@
Compute update statistics:
for the last days
- -
Cleanup CDash (can take a long time):
- -
Manage CDash dependencies:
diff --git a/app/cdash/tests/test_removebuilds.php b/app/cdash/tests/test_removebuilds.php index 314b022932..bb14f3b351 100644 --- a/app/cdash/tests/test_removebuilds.php +++ b/app/cdash/tests/test_removebuilds.php @@ -27,6 +27,7 @@ use CDash\Model\Image; use CDash\Model\Label; use CDash\Model\UploadFile; +use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\DB; class RemoveBuildsTestCase extends KWWebTestCase @@ -36,19 +37,17 @@ public function __construct() parent::__construct(); } - public function testRemoveBuilds() + public function testRemoveBuilds(): void { $this->login(); $this->get($this->url . '/removeBuilds.php?projectid=5'); $this->clickSubmitByName('Submit'); if (strpos($this->getBrowser()->getContentAsText(), 'Removed') === false) { $this->fail("'Removed' not found when expected"); - return 1; } - $this->pass('Passed'); } - public function testBuildRemovalWorksAsExpected() + public function testBuildRemovalWorksAsExpected(): void { $time = gmdate(FMT_DATETIME); @@ -272,7 +271,7 @@ public function testBuildRemovalWorksAsExpected() $measurement = new TestMeasurement(); $measurement->name = 'Exit Value'; $measurement->type = 'text/string'; - $measurement->value = 5; + $measurement->value = '5'; $test_creator->measurements->push($measurement); $image = new Image(); @@ -301,7 +300,7 @@ public function testBuildRemovalWorksAsExpected() $measurement2 = new TestMeasurement(); $measurement2->name = 'Exit Value'; $measurement2->type = 'text/string'; - $measurement2->value = 0; + $measurement2->value = '0'; $test_creator2->measurements->push($measurement2); $image2 = new Image(); @@ -340,32 +339,130 @@ public function testBuildRemovalWorksAsExpected() // Various tables that are too hard to spoof with models so we resort // to direct insertion. - pdo_query( - "INSERT INTO buildemail (userid, buildid, category) - VALUES (1, $build->Id, 0)"); - pdo_query( - "INSERT INTO builderrordiff - (buildid, type, difference_positive, difference_negative) - VALUES ($build->Id, 0, 1, 1)"); - pdo_query( - "INSERT INTO configureerrordiff (buildid, type, difference) - VALUES ($build->Id, 0, 1)"); - pdo_query( - "INSERT INTO coveragesummarydiff (buildid, loctested, locuntested) - VALUES ($build->Id, 1, 1)"); - pdo_query( - "INSERT INTO summaryemail (buildid, date, groupid) - VALUES ($build->Id, '$time', 1)"); - pdo_query( - "INSERT INTO subproject2build (subprojectid, buildid) - VALUES (1, $build->Id)"); - pdo_query( - "INSERT INTO testdiff - (buildid, type, difference_positive, difference_negative) - VALUES ($build->Id, 0, 1, 1)"); - - - // Check that everything was created successfully. + DB::table('buildemail')->insert([ + 'userid' => 1, + 'buildid' => $build->Id, + 'category' => 0, + ]); + DB::table('builderrordiff')->insert([ + 'buildid' => $build->Id, + 'type' => 0, + 'difference_positive' => 1, + 'difference_negative' => 1, + ]); + DB::table('configureerrordiff')->insert([ + 'buildid' => $build->Id, + 'type' => 0, + 'difference' => 1, + ]); + DB::table('coveragesummarydiff')->insert([ + 'buildid' => $build->Id, + 'loctested' => 1, + 'locuntested' => 1, + ]); + DB::table('summaryemail')->insert([ + 'buildid' => $build->Id, + 'date' => $time, + 'groupid' => 1, + ]); + DB::table('subproject2build')->insert([ + 'subprojectid' => 1, + 'buildid' => $build->Id, + ]); + DB::table('testdiff')->insert([ + 'buildid' => $build->Id, + 'type' => 0, + 'difference_positive' => 1, + 'difference_negative' => 1, + ]); + + // Insert some unused records to make sure they get properly pruned by db:clean + // without impacting the data created above. + $crc32 = crc32(''); + DB::table('banner')->insert([ + 'projectid' => 999, + 'text' => 'created by test_removebuilds', + ]); + $buildfailuredetails_id = DB::table('buildfailuredetails')->insertGetId([ + 'type' => 0, + 'stdoutput' => '', + 'stderror' => '', + 'exitcondition' => 'normal', + 'language' => 'PHP', + 'targetname' => 'test_removebuilds', + 'outputfile' => 'test_removebuilds', + 'outputtype' => 'test', + 'crc32' => $crc32, + ]); + $configure_id = DB::table('configure')->insertGetId([ + 'command' => 'test_removebuilds', + 'log' => 'created by test_removebuilds', + 'status' => 0, + 'warnings' => 0, + 'crc32' => $crc32, + ]); + $coveragefile_id = DB::table('coveragefile')->insertGetId([ + 'fullpath' => 'tests/test_removebuild.php', + 'file' => 'asdf', + 'crc32' => $crc32, + ]); + $dailyupdate_id = DB::table('dailyupdate')->insertGetId([ + 'projectid' => 999, + 'date' => $time, + 'command' => 'created by test_removebuilds', + 'type' => 'ok', + 'status' => 0, + 'revision' => 'DEADBEEF', + ]); + DB::table('dailyupdatefile')->insert([ + 'dailyupdateid' => $dailyupdate_id, + 'filename' => 'test_removebuilds.php', + 'checkindate' => $time, + 'author' => 'CDash', + 'email' => 'admin@cdash.org', + 'log' => 'test_removebuilds.php', + 'revision' => 'DEADBEEF', + 'priorrevision' => '00000000', + ]); + $image_id = DB::table('image')->insertGetId([ + 'img' => 'asdf', + 'extension' => 'png', + 'checksum' => 0, + ]); + $note_id = DB::table('note')->insertGetId([ + 'text' => 'note for test_removebuildds', + 'name' => 'test_removebuilds.log', + 'crc32' => $crc32, + ]); + $testoutput_id = DB::table('testoutput')->insertGetId([ + 'output' => 'testoutput for test_removebuildds', + 'command' => 'php test_removebuilds.php', + 'path' => '/cdash/tests/test_removebuilds.php', + 'crc32' => $crc32, + ]); + $uploadfile_id = DB::table('uploadfile')->insertGetId([ + 'filename' => 'test_removebuilds.php', + 'filesize' => 0, + 'sha1sum' => '00000000', + 'isurl' => 0, + ]); + + // Verify that db:clean works as expected. + Artisan::call('db:clean'); + $extra_msg = 'after db:clean'; + $this->verify('banner', 'projectid', '=', 999, 0, $extra_msg); + $this->verify('buildfailuredetails', 'id', '=', $buildfailuredetails_id, 0, $extra_msg); + $this->verify('configure', 'id', '=', $configure_id, 0, $extra_msg); + $this->verify('coveragefile', 'id', '=', $coveragefile_id, 0, $extra_msg); + $this->verify('dailyupdate', 'id', '=', $dailyupdate_id, 0, $extra_msg); + $this->verify('dailyupdatefile', 'dailyupdateid', '=', $dailyupdate_id, 0, $extra_msg); + $this->verify('image', 'id', '=', $image_id, 0, $extra_msg); + $this->verify('note', 'id', '=', $note_id, 0, $extra_msg); + $this->verify('testoutput', 'id', '=', $testoutput_id, 0, $extra_msg); + $this->verify('uploadfile', 'id', '=', $uploadfile_id, 0, $extra_msg); + + // Verify that our build-related data was created successfully + // and not accidentally removed by db:clean. $this->verify('build', 'id', '=', $build->Id, 1); $this->verify('build2group', 'buildid', '=', $build->Id, 1); $this->verify('buildemail', 'buildid', '=', $build->Id, 1); @@ -426,68 +523,110 @@ public function testBuildRemovalWorksAsExpected() $this->verify('label2dynamicanalysis', 'labelid', '=', $labelid, 1); $this->verify('label2test', 'labelid', '=', $labelid, 3); - echo "Check on labelid = $labelid\n"; - return; - // Remove the build. DatabaseCleanupUtils::removeBuild($build->Id); - // Check that everything was deleted properly. - $this->verify('build', 'id', '=', $build->Id, 0, true); - $this->verify('build2configure', 'buildid', '=', $build->Id, 0, true); - $this->verify('build2configure', 'buildid', '=', $existing_build->Id, 1, true); - $this->verify('build2group', 'buildid', '=', $build->Id, 0, true); - $this->verify('build2note', 'buildid', '=', $build->Id, 0, true); - $this->verify('build2test', 'buildid', '=', $build->Id, 0, true); - $this->verify('build2update', 'buildid', '=', $build->Id, 0, true); - $this->verify('build2uploadfile', 'buildid', '=', $build->Id, 0, true); - $this->verify('buildemail', 'buildid', '=', $build->Id, 0, true); - $this->verify('builderror', 'buildid', '=', $build->Id, 0, true); - $this->verify('builderrordiff', 'buildid', '=', $build->Id, 0, true); - $this->verify('buildfailure', 'buildid', '=', $build->Id, 0, true); - $this->verify('buildfailure2argument', 'buildfailureid', '=', $buildfailureid, 0, true); - $this->verify('buildfailuredetails', 'id', '=', $detailsid, 1, true); - $this->verify('buildtesttime', 'buildid', '=', $build->Id, 0, true); - $this->verify('buildupdate', 'id', '=', $updateid, 1, true); - $this->verify('configure', 'id', '=', $configureid, 1, true); - $this->verify('configureerror', 'configureid', '=', $configureid, 1, true); - $this->verify('configureerrordiff', 'buildid', '=', $build->Id, 0, true); - $this->verify('coverage', 'buildid', '=', $build->Id, 0, true); - $this->verify('coveragefile', 'id', 'IN', $coveragefileids, 1, true); - $this->verify('coveragefilelog', 'buildid', '=', $build->Id, 0, true); - $this->verify('coveragesummary', 'buildid', '=', $build->Id, 0, true); - $this->verify('coveragesummarydiff', 'buildid', '=', $build->Id, 0, true); - $this->verify('dynamicanalysis', 'buildid', '=', $build->Id, 0, true); - $this->verify('dynamicanalysissummary', 'buildid', '=', $build->Id, 0, true); - $this->verify('dynamicanalysisdefect', 'dynamicanalysisid', '=', $dynamicanalysisid, 0, true); - $this->verify('image', 'id', 'IN', $imgids, 1, true); - $this->verify('label2build', 'buildid', '=', $build->Id, 0, true); - $this->verify('label2buildfailure', 'labelid', '=', $labelid, 1, true); - $this->verify('label2coveragefile', 'labelid', '=', $labelid, 1, true); - $this->verify('label2dynamicanalysis', 'labelid', '=', $labelid, 0, true); - $this->verify('label2test', 'labelid', '=', $labelid, 0, true); - $this->verify('note', 'id', 'IN', $noteids, 1, true); - $this->verify('summaryemail', 'buildid', '=', $build->Id, 0, true); - $this->verify('subproject2build', 'buildid', '=', $build->Id, 0, true); - $this->verify('test2image', 'outputid', 'IN', $outputids, 1, true); - $this->verify('testdiff', 'buildid', '=', $build->Id, 0, true); - $this->verify('updatefile', 'updateid', '=', $updateid, 1, true); - $this->verify('uploadfile', 'id', 'IN', $uploadfileids, 1, true); + // Check that everything was deleted properly but shared records remain. + $extra_msg = 'after 1st delete'; + $this->verify('build', 'id', '=', $build->Id, 0, $extra_msg); + $this->verify('build2configure', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('build2configure', 'buildid', '=', $existing_build->Id, 1, $extra_msg); + $this->verify('build2group', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('build2note', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('build2test', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('build2update', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('build2uploadfile', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('buildemail', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('builderror', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('builderrordiff', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('buildfailure', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('buildfailure2argument', 'buildfailureid', '=', $buildfailureid, 0, $extra_msg); + $this->verify('buildfailuredetails', 'id', '=', $detailsid, 1, $extra_msg); + $this->verify('buildtesttime', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('buildupdate', 'id', '=', $updateid, 1, $extra_msg); + $this->verify('configure', 'id', '=', $configureid, 1, $extra_msg); + $this->verify('configureerror', 'configureid', '=', $configureid, 1, $extra_msg); + $this->verify('configureerrordiff', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('coverage', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('coveragefile', 'id', 'IN', $coveragefileids, 1, $extra_msg); + $this->verify('coveragefilelog', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('coveragesummary', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('coveragesummarydiff', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('dynamicanalysis', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('dynamicanalysissummary', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('dynamicanalysisdefect', 'dynamicanalysisid', '=', $dynamicanalysisid, 0, $extra_msg); + $this->verify('image', 'id', 'IN', $imgids, 1, $extra_msg); + $this->verify('label2build', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('label2buildfailure', 'labelid', '=', $labelid, 1, $extra_msg); + $this->verify('label2coveragefile', 'labelid', '=', $labelid, 1, $extra_msg); + $this->verify('label2dynamicanalysis', 'labelid', '=', $labelid, 0, $extra_msg); + $this->verify('label2test', 'labelid', '=', $labelid, 1, $extra_msg); + $this->verify('note', 'id', 'IN', $noteids, 1, $extra_msg); + $this->verify('summaryemail', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('subproject2build', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('test2image', 'outputid', 'IN', $outputids, 1, $extra_msg); + $this->verify('testdiff', 'buildid', '=', $build->Id, 0, $extra_msg); + $this->verify('updatefile', 'updateid', '=', $updateid, 1, $extra_msg); + $this->verify('uploadfile', 'id', 'IN', $uploadfileids, 1, $extra_msg); + + // Remove the other build too to verify that shared resources get cleaned up + // and to make this test idempotent. + DatabaseCleanupUtils::removeBuild($existing_build->Id); + + $extra_msg = 'after 2nd delete'; + $this->verify('build', 'id', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('build2configure', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('build2group', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('build2note', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('build2test', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('build2update', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('build2uploadfile', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('buildemail', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('builderror', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('builderrordiff', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('buildfailure', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('buildfailuredetails', 'id', '=', $detailsid, 0, $extra_msg); + $this->verify('buildtesttime', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('buildupdate', 'id', '=', $updateid, 0, $extra_msg); + $this->verify('configure', 'id', '=', $configureid, 0, $extra_msg); + $this->verify('configureerror', 'configureid', '=', $configureid, 0, $extra_msg); + $this->verify('configureerrordiff', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('coverage', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('coveragefile', 'id', 'IN', $coveragefileids, 0, $extra_msg); + $this->verify('coveragefilelog', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('coveragesummary', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('coveragesummarydiff', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('dynamicanalysis', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('dynamicanalysissummary', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('dynamicanalysisdefect', 'dynamicanalysisid', '=', $dynamicanalysisid, 0, $extra_msg); + $this->verify('image', 'id', 'IN', $imgids, 0, $extra_msg); + $this->verify('label2build', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('label2buildfailure', 'labelid', '=', $labelid, 0, $extra_msg); + $this->verify('label2coveragefile', 'labelid', '=', $labelid, 0, $extra_msg); + $this->verify('label2dynamicanalysis', 'labelid', '=', $labelid, 0, $extra_msg); + $this->verify('label2test', 'labelid', '=', $labelid, 0, $extra_msg); + $this->verify('note', 'id', 'IN', $noteids, 0, $extra_msg); + $this->verify('summaryemail', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('subproject2build', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('test2image', 'outputid', 'IN', $outputids, 0, $extra_msg); + $this->verify('testdiff', 'buildid', '=', $existing_build->Id, 0, $extra_msg); + $this->verify('updatefile', 'updateid', '=', $updateid, 0, $extra_msg); + $this->verify('uploadfile', 'id', 'IN', $uploadfileids, 0, $extra_msg); } - public function verify($table, $field, $compare, $value, $expected, $deleted=false) + public function verify(string $table, string $field, string $compare, string|int $value, int $expected, string $extra_msg=''): void { - $delete_msg = ''; - if ($deleted) { - $delete_msg = 'after deletion'; - } $num_rows = count(DB::select("SELECT $field FROM $table WHERE $field $compare $value")); if ($num_rows !== $expected) { - $this->fail("Expected $expected for $table $delete_msg, found $num_rows"); + $this->fail("Expected $expected for $table $extra_msg, found $num_rows"); } } - public function verify_get_columns($table, $columns, $field, $compare, $value, $expected) + /** + * @param array $columns + * @return array + */ + public function verify_get_columns(string $table, array $columns, string $field, string $compare, string $value, int $expected): array { $col_arg = implode(',', $columns); $result = DB::select("SELECT $col_arg FROM $table WHERE $field $compare $value"); @@ -503,7 +642,7 @@ public function verify_get_columns($table, $columns, $field, $compare, $value, $ return $retval; } - public function verify_get_rows($table, $column, $field, $compare, $value, $expected) + public function verify_get_rows(string $table, string $column, string $field, string $compare, string $value, int $expected): string { $result = DB::select("SELECT $column FROM $table WHERE $field $compare $value"); $num_rows = count($result); diff --git a/app/cdash/tests/test_upgrade.php b/app/cdash/tests/test_upgrade.php index a697b37266..9b72a5f7fe 100644 --- a/app/cdash/tests/test_upgrade.php +++ b/app/cdash/tests/test_upgrade.php @@ -76,18 +76,6 @@ function testComputeUpdateStatistics() } */ - public function testCleanup() - { - if (!$this->getMaintenancePage()) { - return 1; - } - set_time_limit(0); - if (!$this->clickSubmitByName('Cleanup')) { - $this->fail('clicking Cleanup returned false'); - } - $this->assertText('Database cleanup complete.'); - } - public function getMaintenancePage() { $this->login(); diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 01b4e298cf..5670fa2089 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -301,7 +301,7 @@ parameters: #^Call to deprecated function pdo_error\\(\\)\\: 04/01/2023$# """ - count: 7 + count: 6 path: app/Http/Controllers/AdminController.php - @@ -410,26 +410,6 @@ parameters: count: 1 path: app/Http/Controllers/AdminController.php - - - message: "#^Method App\\\\Http\\\\Controllers\\\\AdminController\\:\\:delete_unused_rows\\(\\) has parameter \\$field with no type specified\\.$#" - count: 1 - path: app/Http/Controllers/AdminController.php - - - - message: "#^Method App\\\\Http\\\\Controllers\\\\AdminController\\:\\:delete_unused_rows\\(\\) has parameter \\$selectfield with no type specified\\.$#" - count: 1 - path: app/Http/Controllers/AdminController.php - - - - message: "#^Method App\\\\Http\\\\Controllers\\\\AdminController\\:\\:delete_unused_rows\\(\\) has parameter \\$table with no type specified\\.$#" - count: 1 - path: app/Http/Controllers/AdminController.php - - - - message: "#^Method App\\\\Http\\\\Controllers\\\\AdminController\\:\\:delete_unused_rows\\(\\) has parameter \\$targettable with no type specified\\.$#" - count: 1 - path: app/Http/Controllers/AdminController.php - - message: "#^Method App\\\\Http\\\\Controllers\\\\AdminController\\:\\:removeBuilds\\(\\) never returns Illuminate\\\\Http\\\\RedirectResponse so it can be removed from the return type\\.$#" count: 1 @@ -447,7 +427,7 @@ parameters: - message: "#^Only booleans are allowed in an if condition, mixed given\\.$#" - count: 9 + count: 8 path: app/Http/Controllers/AdminController.php - @@ -26667,149 +26647,11 @@ parameters: count: 1 path: app/cdash/tests/test_redundanttests.php - - - message: """ - #^Call to deprecated function pdo_query\\(\\)\\: - 04/01/2023$# - """ - count: 7 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Call to deprecated method pass\\(\\) of class SimpleTestCase\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:testBuildRemovalWorksAsExpected\\(\\) has no return type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:testRemoveBuilds\\(\\) has no return type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify\\(\\) has no return type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify\\(\\) has parameter \\$compare with no type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify\\(\\) has parameter \\$deleted with no type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify\\(\\) has parameter \\$expected with no type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify\\(\\) has parameter \\$field with no type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify\\(\\) has parameter \\$table with no type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify\\(\\) has parameter \\$value with no type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify_get_columns\\(\\) has no return type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify_get_columns\\(\\) has parameter \\$columns with no type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify_get_columns\\(\\) has parameter \\$compare with no type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify_get_columns\\(\\) has parameter \\$expected with no type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify_get_columns\\(\\) has parameter \\$field with no type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify_get_columns\\(\\) has parameter \\$table with no type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify_get_columns\\(\\) has parameter \\$value with no type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify_get_rows\\(\\) has no return type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify_get_rows\\(\\) has parameter \\$column with no type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify_get_rows\\(\\) has parameter \\$compare with no type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify_get_rows\\(\\) has parameter \\$expected with no type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify_get_rows\\(\\) has parameter \\$field with no type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify_get_rows\\(\\) has parameter \\$table with no type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Method RemoveBuildsTestCase\\:\\:verify_get_rows\\(\\) has parameter \\$value with no type specified\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - message: "#^Parameter \\#1 \\$string of function base64_encode expects string, string\\|false given\\.$#" count: 1 path: app/cdash/tests/test_removebuilds.php - - - message: "#^Property App\\\\Models\\\\TestMeasurement\\:\\:\\$value \\(string\\) does not accept int\\.$#" - count: 2 - path: app/cdash/tests/test_removebuilds.php - - - - message: "#^Unreachable statement \\- code above always terminates\\.$#" - count: 1 - path: app/cdash/tests/test_removebuilds.php - - message: "#^Variable property access on mixed\\.$#" count: 2 @@ -28491,11 +28333,6 @@ parameters: count: 1 path: app/cdash/tests/test_upgrade.php - - - message: "#^Method UpgradeTestCase\\:\\:testCleanup\\(\\) has no return type specified\\.$#" - count: 1 - path: app/cdash/tests/test_upgrade.php - - message: "#^Method UpgradeTestCase\\:\\:testComputeTestTiming\\(\\) has no return type specified\\.$#" count: 1