/** * Creates a run to the given problem * * @param type $problemData * @param type $contestant */ public static function createRunToProblem($problemData, $contestant) { $r = self::createRequestCommon($problemData, null, $contestant); // Call API RunController::$grader = new GraderMock(); $response = RunController::apiCreate($r); // Clean up unset($_REQUEST); return array('request' => $r, 'contestant' => $contestant, 'response' => $response); }
public function testRunTotals() { // Get a problem $problemData = ProblemsFactory::createProblem(); // Get a contest $contestData = ContestsFactory::createContest(); // Add the problem to the contest ContestsFactory::addProblemToContest($problemData, $contestData); // Create our contestant $contestant = UserFactory::createUser(); // Create a run $runData = RunsFactory::createRun($problemData, $contestData, $contestant); $runDataOld = RunsFactory::createRun($problemData, $contestData, $contestant); $run = RunsDAO::getByAlias($runDataOld['response']['guid']); $run->setTime(date('Y-m-d H:i:s', strtotime('-72 hours'))); RunsDAO::save($run); $response = RunController::apiCounts(new Request()); $this->assertGreaterThan(1, count($response)); }
/** * Basic test of viewing run details * */ public function testShowRunDetailsValid() { // Get a problem $problemData = ProblemsFactory::createProblem(); // Get a contest $contestData = ContestsFactory::createContest(); // Add the problem to the contest ContestsFactory::addProblemToContest($problemData, $contestData); // Create our contestant $contestant = UserFactory::createUser(); // Create a run $runData = RunsFactory::createRun($problemData, $contestData, $contestant); // Prepare request $r = new Request(); $r['auth_token'] = $this->login($contestant); $r['run_alias'] = $runData['response']['guid']; // Call API $response = RunController::apiStatus($r); $this->assertEquals($r['run_alias'], $response['guid']); $this->assertEquals('JE', $response['verdict']); $this->assertEquals('new', $response['status']); }
/** * Basic test of viewing run details * */ public function testShowRunDetailsValid() { // Get a problem $problemData = ProblemsFactory::createProblem(); // Get a contest $contestData = ContestsFactory::createContest(); // Add the problem to the contest ContestsFactory::addProblemToContest($problemData, $contestData); // Create our contestant $contestant = UserFactory::createUser(); // Create a run $runData = RunsFactory::createRun($problemData, $contestData, $contestant); // Prepare request $r = new Request(); $r["auth_token"] = $this->login($contestant); $r["run_alias"] = $runData["response"]["guid"]; // Call API $response = RunController::apiStatus($r); $this->assertEquals($r["run_alias"], $response["guid"]); $this->assertEquals("JE", $response["verdict"]); $this->assertEquals("new", $response["status"]); }
/** * Basic test of rerun */ public function testRejudgeWithoutCompileError() { // Get a problem $problemData = ProblemsFactory::createProblem(); // Get a contest $contestData = ContestsFactory::createContest(); // Add the problem to the contest ContestsFactory::addProblemToContest($problemData, $contestData); // Create our contestant $contestant = UserFactory::createUser(); // Create a run $runData = RunsFactory::createRun($problemData, $contestData, $contestant); // Grade the run RunsFactory::gradeRun($runData); // Detour grader calls expecting one call $this->detourGraderCalls($this->once()); // Build request $r = new Request(); $r['run_alias'] = $runData['response']['guid']; $r['auth_token'] = $this->login($contestData['director']); // Call API $response = RunController::apiRejudge($r); $this->assertEquals('ok', $response['status']); }
/** * Detours the Grader calls. * Problem: Submiting a new run invokes the Grader::grade() function which makes * a HTTP call to official grader using CURL. This call will fail if grader is * not turned on. We are not testing the Grader functionallity itself, we are * only validating that we populate the DB correctly and that we make a call * to the function Grader::grade(), without executing the contents. * * Solution: We create a phpunit mock of the Grader class. We create a fake * object Grader with the function grade() which will always return true * and expects to be excecuted once. * */ public function detourGraderCalls($times = null) { if (is_null($times)) { $times = $this->once(); } // Create a fake Grader object which will always return true (see // next line) $graderMock = $this->getMock('Grader', array('Grade')); // Set expectations: $graderMock->expects($times)->method('Grade')->will($this->returnValue(true)); // Detour all Grader::grade() calls to our mock RunController::$grader = $graderMock; ProblemController::$grader = $graderMock; }
private static function getScoreboardFromRuns($runs, $raw_contest_users, $problem_mapping, $contest_penalty, $scoreboard_time_limit, $contest, $showAllRuns, $sortByName, $withRunDetails = false, $auth_token = null) { $test_only = array(); $no_runs = array(); $users_info = array(); $problems = array(); foreach ($problem_mapping as $problem) { array_push($problems, $problem); } // Calculate score for each contestant x problem foreach ($raw_contest_users as $contestant) { $user_problems = array(); $test_only[$contestant->getUserId()] = true; $no_runs[$contestant->getUserId()] = true; foreach ($problem_mapping as $id => $problem) { array_push($user_problems, array('points' => 0, 'percent' => 0, 'penalty' => 0, 'runs' => 0)); } // Add the problems' information $users_info[$contestant->getUserId()] = array('problems' => $user_problems, 'username' => $contestant->getUsername(), 'name' => $contestant->getName() ? $contestant->getName() : $contestant->getUsername(), 'total' => null, 'country' => $contestant->getCountryId()); } foreach ($runs as $run) { $user_id = $run->user_id; $problem_id = $run->problem_id; $contest_score = $run->contest_score; $score = $run->score; $is_test = $run->test != 0; $problem =& $users_info[$user_id]['problems'][$problem_mapping[$problem_id]['order']]; if (!array_key_exists($user_id, $test_only)) { // // Hay un usuario en la lista de Runs, // que no fue regresado por RunsDAO::GetAllRelevantUsers() // continue; } $test_only[$user_id] &= $is_test; $no_runs[$user_id] = false; if (!$showAllRuns) { if ($is_test) { continue; } if (!is_null($scoreboard_time_limit) && strtotime($run->getTime()) >= $scoreboard_time_limit) { $problem['runs']++; $problem['pending'] = true; continue; } } $totalPenalty = $run->penalty + $problem['runs'] * $contest_penalty; $rounded_score = round($contest_score, 2); if ($problem['points'] < $rounded_score || $problem['points'] == $rounded_score && $problem['penalty'] > $totalPenalty) { $problem['points'] = $rounded_score; $problem['percent'] = round($score * 100, 2); $problem['penalty'] = $totalPenalty; if ($withRunDetails === true) { $runDetails = array(); $runDetailsRequest = new Request(array('run_alias' => $run->guid, 'auth_token' => $auth_token)); $runDetails = RunController::apiDetails($runDetailsRequest); unset($runDetails['source']); $problem['run_details'] = $runDetails; } } $problem['runs']++; } $result = array(); foreach ($raw_contest_users as $contestant) { $user_id = $contestant->getUserId(); // Add contestant results to scoreboard data if (!$showAllRuns && $test_only[$user_id] && !$no_runs[$user_id]) { continue; } $info = $users_info[$user_id]; if ($info == null) { continue; } $info[self::TOTAL_COLUMN] = Scoreboard::getTotalScore($info['problems']); array_push($result, $info); } Scoreboard::sortScoreboard($result, $sortByName); usort($problems, array('Scoreboard', 'compareOrder')); return array('problems' => $problems, 'ranking' => $result, 'start_time' => strtotime($contest->start_time), 'finish_time' => strtotime($contest->finish_time), 'title' => $contest->title, 'time' => time() * 1000); }
/** * Given the run alias, returns a .zip file with all the .out files generated for a run. * * @param Request $r * @throws ForbiddenAccessException */ public static function apiDownload(Request $r) { if (OMEGAUP_LOCKDOWN) { throw new ForbiddenAccessException('lockdown'); } // Get the user who is calling this API self::authenticateRequest($r); self::validateAdminDetailsRequest($r); $grade_dir = RunController::getGradePath($r['run']); $results_zip = "{$grade_dir}/results.zip"; header('Content-Type: application/zip'); header('Content-Disposition: attachment; filename=' . $r['run']->guid . '.zip'); header('Content-Length: ' . filesize($results_zip)); readfile($results_zip); exit; }
public static function apiDownload(Request $r) { self::authenticateRequest($r); self::validateStats($r); // Get our runs $relevant_columns = array("run_id", "guid", "language", "status", "verdict", "runtime", "penalty", "memory", "score", "contest_score", "time", "submit_delay", "Users.username", "Problems.alias"); try { $runs = RunsDAO::search(new Runs(array("contest_id" => $r["contest"]->getContestId())), "time", "DESC", $relevant_columns); } catch (Exception $e) { // Operation failed in the data layer throw new InvalidDatabaseOperationException($e); } $zip = new ZipStream($r["contest_alias"] . '.zip'); // Add runs to zip $table = "guid,user,problem,verdict,points\n"; foreach ($runs as $run) { $zip->add_file_from_path("runs/" . $run->getGuid(), RunController::getSubmissionPath($run)); $columns[0] = 'username'; $columns[1] = 'alias'; $usernameProblemData = $run->asFilteredArray($columns); $table .= $run->getGuid() . "," . $usernameProblemData['username'] . "," . $usernameProblemData['alias'] . "," . $run->getVerdict() . "," . $run->getContestScore(); $table .= "\n"; } $zip->add_file("summary.csv", $table); // Add problem cases to zip $contest_problems = ContestProblemsDAO::GetRelevantProblems($r["contest"]->getContestId()); foreach ($contest_problems as $problem) { $zip->add_file_from_path($problem->getAlias() . "_cases.zip", PROBLEMS_PATH . "/" . $problem->getAlias() . "/cases.zip"); } // Return zip $zip->finish(); die; }
public static function apiDownload(Request $r) { self::authenticateRequest($r); self::validateStats($r); // Get our runs $relevant_columns = array('run_id', 'guid', 'language', 'status', 'verdict', 'runtime', 'penalty', 'memory', 'score', 'contest_score', 'time', 'submit_delay', 'Users.username', 'Problems.alias'); try { $runs = RunsDAO::search(new Runs(array('contest_id' => $r['contest']->getContestId())), 'time', 'DESC', $relevant_columns); } catch (Exception $e) { // Operation failed in the data layer throw new InvalidDatabaseOperationException($e); } $zip = new ZipStream($r['contest_alias'] . '.zip'); // Add runs to zip $table = "guid,user,problem,verdict,points\n"; foreach ($runs as $run) { $zip->add_file_from_path('runs/' . $run->getGuid(), RunController::getSubmissionPath($run)); $columns[0] = 'username'; $columns[1] = 'alias'; $usernameProblemData = $run->asFilteredArray($columns); $table .= $run->getGuid() . ',' . $usernameProblemData['username'] . ',' . $usernameProblemData['alias'] . ',' . $run->getVerdict() . ',' . $run->getContestScore(); $table .= "\n"; } $zip->add_file('summary.csv', $table); // Add problem cases to zip $contest_problems = ContestProblemsDAO::GetRelevantProblems($r['contest']->getContestId()); foreach ($contest_problems as $problem) { $zip->add_file_from_path($problem->getAlias() . '_cases.zip', PROBLEMS_PATH . '/' . $problem->getAlias() . '/cases.zip'); } // Return zip $zip->finish(); die; }
// Load test utils require_once OMEGAUP_ROOT . "/tests/controllers/OmegaupTestCase.php"; require_once OMEGAUP_ROOT . "/tests/common/Utils.php"; // Load Factories require_once OMEGAUP_ROOT . '/tests/factories/ProblemsFactory.php'; require_once OMEGAUP_ROOT . '/tests/factories/ContestsFactory.php'; require_once OMEGAUP_ROOT . '/tests/factories/ClarificationsFactory.php'; require_once OMEGAUP_ROOT . '/tests/factories/UserFactory.php'; require_once OMEGAUP_ROOT . '/tests/factories/RunsFactory.php'; require_once OMEGAUP_ROOT . '/tests/factories/GroupsFactory.php'; // Clean previous log Utils::CleanLog(); // Clean problems and runs path Utils::CleanPath(PROBLEMS_PATH); Utils::CleanPath(PROBLEMS_GIT_PATH); Utils::CleanPath(RUNS_PATH); Utils::CleanPath(GRADE_PATH); Utils::CleanPath(IMAGES_PATH); for ($i = 0; $i < 256; $i++) { mkdir(RUNS_PATH . sprintf('/%02x', $i), 0775, true); mkdir(GRADE_PATH . sprintf('/%02x', $i), 0775, true); } // Clean DB Utils::CleanupDB(); // Create a test default user for manual UI operations UserController::$sendEmailOnVerify = false; UserFactory::createUser("test", "testtesttest"); UserController::$sendEmailOnVerify = true; // Globally disable run wait gap. RunController::$defaultSubmissionGap = 0;
/** * Stats of a problem * * @param Request $r * @return array * @throws ForbiddenAccessException * @throws InvalidDatabaseOperationException */ public static function apiStats(Request $r) { // Get user self::authenticateRequest($r); // Validate request self::validateRuns($r); // We need to check that the user has priviledges on the problem if (!Authorization::CanEditProblem($r['current_user_id'], $r['problem'])) { throw new ForbiddenAccessException(); } try { // Array of GUIDs of pending runs $pendingRunsGuids = RunsDAO::GetPendingRunsOfProblem($r['problem']->getProblemId()); // Count of pending runs (int) $totalRunsCount = RunsDAO::CountTotalRunsOfProblem($r['problem']->getProblemId()); // List of verdicts $verdict_counts = array(); foreach (self::$verdicts as $verdict) { $verdict_counts[$verdict] = RunsDAO::CountTotalRunsOfProblemByVerdict($r['problem']->getProblemId(), $verdict); } // Array to count AC stats per case. // Let's try to get the last snapshot from cache. $problemStatsCache = new Cache(Cache::PROBLEM_STATS, $r['problem']->getAlias()); $cases_stats = $problemStatsCache->get(); if (is_null($cases_stats)) { // Initialize the array at counts = 0 $cases_stats = array(); $cases_stats['counts'] = array(); // We need to save the last_id that we processed, so next time we do not repeat this $cases_stats['last_id'] = 0; // Build problem dir $problem_dir = PROBLEMS_PATH . '/' . $r['problem']->getAlias() . '/cases/'; // Get list of cases $dir = opendir($problem_dir); if (is_dir($problem_dir)) { while (($file = readdir($dir)) !== false) { // If we have an input if (strstr($file, '.in')) { // Initialize it to 0 $cases_stats['counts'][str_replace('.in', '', $file)] = 0; } } closedir($dir); } } // Get all runs of this problem after the last id we had $runs = RunsDAO::searchRunIdGreaterThan(new Runs(array('problem_id' => $r['problem']->getProblemId())), $cases_stats['last_id'], 'run_id'); // For each run we got foreach ($runs as $run) { // Build grade dir $grade_dir = RunController::getGradePath($run); // Skip it if it failed to compile. if (file_exists("{$grade_dir}/compile_error.log")) { continue; } // Try to open the details file. if (file_exists("{$grade_dir}/details.json")) { $details = json_decode(file_get_contents("{$grade_dir}/details.json")); foreach ($details as $group) { foreach ($group->cases as $case) { if ($case->score > 0) { $cases_stats['counts'][$case->name]++; } } } } } } catch (Exception $e) { throw new InvalidDatabaseOperationException($e); } // Save the last id we saw in case we saw something if (!is_null($runs) && count($runs) > 0) { $cases_stats['last_id'] = $runs[count($runs) - 1]->getRunId(); } // Save in cache what we got $problemStatsCache->set($cases_stats, APC_USER_CACHE_PROBLEM_STATS_TIMEOUT); return array('total_runs' => $totalRunsCount, 'pending_runs' => $pendingRunsGuids, 'verdict_counts' => $verdict_counts, 'cases_stats' => $cases_stats['counts'], 'status' => 'ok'); }
/** * User should wait between consecutive runs. * * @expectedException NotAllowedToSubmitException */ public function testRunsToPublicProblemInsideSubmissionGap() { $originalGap = RunController::$defaultSubmissionGap; RunController::$defaultSubmissionGap = 60; try { // Create public problem $problemData = ProblemsFactory::createProblem(); // Create our contestant $this->contestant = UserFactory::createUser(); // Create an empty request $r = new Request(); // Log in as contest director $r["auth_token"] = $this->login($this->contestant); // Build request $r["contest_alias"] = ""; // Not inside a contest $r["problem_alias"] = $problemData["request"]["alias"]; $r["language"] = "c"; $r["source"] = "#include <stdio.h>\nint main() { printf(\"3\"); return 0; }"; //PHPUnit does not set IP address, doing it manually $_SERVER["REMOTE_ADDR"] = "127.0.0.1"; // Call API $this->detourGraderCalls($this->exactly(1)); $response = RunController::apiCreate($r); // Validate the run $this->assertRun($r, $response); // Call API $response = RunController::apiCreate($r); } finally { RunController::$defaultSubmissionGap = $originalGap; } }
/** * User should wait between consecutive runs. * * @expectedException NotAllowedToSubmitException */ public function testRunsToPublicProblemInsideSubmissionGap() { $originalGap = RunController::$defaultSubmissionGap; RunController::$defaultSubmissionGap = 60; try { // Create public problem $problemData = ProblemsFactory::createProblem(); // Create our contestant $this->contestant = UserFactory::createUser(); // Create an empty request $r = new Request(); // Log in as contest director $r['auth_token'] = $this->login($this->contestant); // Build request $r['contest_alias'] = ''; // Not inside a contest $r['problem_alias'] = $problemData['request']['alias']; $r['language'] = 'c'; $r['source'] = "#include <stdio.h>\nint main() { printf(\"3\"); return 0; }"; // Call API $this->detourGraderCalls($this->exactly(1)); $response = RunController::apiCreate($r); // Validate the run $this->assertRun($r, $response); // Call API $response = RunController::apiCreate($r); } finally { RunController::$defaultSubmissionGap = $originalGap; } }