diff --git a/bulktest.php b/bulktest.php index 8b5abdfb..0f8b7ff9 100644 --- a/bulktest.php +++ b/bulktest.php @@ -33,7 +33,7 @@ // Get the parameters from the URL. $contextid = required_param('contextid', PARAM_INT); // Set to 0 if providing a list of question IDs to check. $categoryid = optional_param('categoryid', null, PARAM_INT); -$randomseed = optional_param('randomseed', 0, PARAM_INT); +$randomseed = optional_param('randomseed', -1, PARAM_INT); $repeatrandomonly = optional_param('repeatrandomonly', 1, PARAM_INT); $nruns = optional_param('nruns', 1, PARAM_INT); $questionids = optional_param('questionids', '', PARAM_RAW); // A list of specific questions to check, eg, for rechecking failed tests. diff --git a/bulktestall.php b/bulktestall.php index 1ee693b6..ee030f36 100644 --- a/bulktestall.php +++ b/bulktestall.php @@ -45,8 +45,7 @@ $title = get_string('bulktesttitle', 'qtype_coderunner', $context->get_context_name()); $PAGE->set_title($title); -// Create the helper class. -$bulktester = new qtype_coderunner_bulk_tester(); + $numpasses = 0; $allfailingtests = []; $allmissinganswers = []; @@ -60,14 +59,16 @@ echo $OUTPUT->heading($title, 1); // Run the tests. -foreach ($bulktester->get_num_coderunner_questions_by_context() as $contextid => $numcoderunnerquestions) { +$contextdata = qtype_coderunner_bulk_tester::get_num_coderunner_questions_by_context(); +foreach ($contextdata as $contextid => $numcoderunnerquestions) { if ($skipping && $contextid != $startfromcontextid) { continue; } $skipping = false; - $testcontext = context::instance_by_id($contextid); if (has_capability('moodle/question:editall', $context)) { + $PAGE->set_context($testcontext); // Helps grading cache pickup right course id. + $bulktester = new qtype_coderunner_bulk_tester($testcontext); echo $OUTPUT->heading(get_string('bulktesttitle', 'qtype_coderunner', $testcontext->get_context_name())); echo html_writer::tag('p', html_writer::link( new moodle_url( @@ -77,7 +78,7 @@ get_string('bulktestcontinuefromhere', 'qtype_coderunner') )); - [$passes, $failingtests, $missinganswers] = $bulktester->run_all_tests_for_context($testcontext); + [$passes, $failingtests, $missinganswers] = $bulktester->run_all_tests_for_context(); $numpasses += $passes; $allfailingtests = array_merge($allfailingtests, $failingtests); $allmissinganswers = array_merge($allmissinganswers, $missinganswers); @@ -85,5 +86,5 @@ } // Display the final summary. -$bulktester->print_overall_result($numpasses, $allfailingtests, $allmissinganswers); +qtype_coderunner_bulk_tester::print_summary_after_bulktestall($numpasses, $allfailingtests, $allmissinganswers); echo $OUTPUT->footer(); diff --git a/bulktestindex.php b/bulktestindex.php index d0fe701c..dc85c5ef 100644 --- a/bulktestindex.php +++ b/bulktestindex.php @@ -59,10 +59,10 @@
- + - - + +
@@ -86,25 +86,23 @@ $testallstr = get_string('bulktestallincontext', 'qtype_coderunner'); $testalltitledetails = ['title' => get_string('testalltitle', 'qtype_coderunner'), 'style' => $buttonstyle]; - $testallspan = html_writer::tag('span', $testallstr, - ['class' => 'test-link', + $testallspan = html_writer::tag( + 'span', $testallstr, + ['class' => 'test-link', 'data-contextid' => $contextid, - 'style' => $buttonstyle . ';cursor:pointer;']); - + 'style' => $buttonstyle . ';cursor:pointer;'] + ); $expandlink = html_writer::link( '#expand', get_string('expand', 'qtype_coderunner'), ['class' => 'expander', 'title' => get_string('expandtitle', 'qtype_coderunner'), 'style' => $buttonstyle] ); - $litext = $name . ' (' . $numcoderunnerquestions . ') ' . $testallspan . ' ' . $expandlink; - if (strpos($name, ": Quiz: ") === false) { $class = 'bulktest coderunner context normal'; } else { $class = 'bulktest coderunner context quiz'; } - echo html_writer::start_tag('li', ['class' => $class]); echo $litext; @@ -115,11 +113,12 @@ foreach ($categories as $cat) { if ($cat->count > 0) { $linktext = $cat->name . ' (' . $cat->count . ')'; - $span = html_writer::tag('span', $linktext, + $span = html_writer::tag('span', $linktext, ['class' => 'test-link', 'data-contextid' => $contextid, 'data-categoryid' => $cat->id, - 'style' => $buttonstyle . ';cursor:pointer;']); + 'style' => $buttonstyle . ';cursor:pointer;'] + ); echo html_writer::tag('li', $span, $titledetails); } } @@ -145,7 +144,7 @@ Array.from(expandables).forEach(function (expandable) { expandable.style.display = 'none'; }); - + var expanders = document.getElementsByClassName('expander'); Array.from(expanders).forEach(function(expander) { expander.addEventListener('click', function(event) { @@ -165,24 +164,24 @@ Array.from(testLinks).forEach(function(link) { link.addEventListener('click', function(event) { event.preventDefault(); - + // Get configuration values var nruns = document.getElementById('nruns').value; var randomseed = document.getElementById('randomseed').value; var repeatrandomonly = document.getElementById('repeatrandomonly').checked ? 1 : 0; - + // Build URL parameters var params = new URLSearchParams(); params.append('contextid', link.dataset.contextid); params.append('randomseed', randomseed); params.append('repeatrandomonly', repeatrandomonly); params.append('nruns', nruns); - + // Add category ID if present if (link.dataset.categoryid) { params.append('categoryid', link.dataset.categoryid); } - + // Construct and navigate to URL var url = M.cfg.wwwroot + '/question/type/coderunner/bulktest.php?' + params.toString(); window.location.href = url; diff --git a/classes/bulk_tester.php b/classes/bulk_tester.php index a810b999..c28692e5 100644 --- a/classes/bulk_tester.php +++ b/classes/bulk_tester.php @@ -71,7 +71,7 @@ class qtype_coderunner_bulk_tester { /** * @param context $context the context to run the tests for. * @param int $categoryid test only questions in this category. Default to all. - * @param int $randomseed used to set random seed before runs for each question. Default = 0 --- meaning seed is not set. + * @param int $randomseed used to set random seed before runs for each question. Default = -1 --- meaning seed is not set. * Use this to have more chance of the series of questions being generated for testing is the same for a new run * of the tests. This works well with grader caching as you won't keep getting new random variations. * Also allows you to mix up the space that is being tested. @@ -80,12 +80,16 @@ class qtype_coderunner_bulk_tester { * @param int $nruns the number times to test each question. Default to 1. */ public function __construct( - $context, + $context = null, $categoryid = null, - $randomseed = 0, + $randomseed = -1, $repeatrandomonly = 1, $nruns = 1 ) { + if ($context === null) { + $site = get_site(); // Get front page course. + $context = context_course::instance($site->id); + } $this->context = $context; $this->categoryid = $categoryid; $this->randomseed = $randomseed; @@ -309,7 +313,7 @@ public function run_all_tests_for_context($questionidstoinclude = []) { } else { $qparams['courseid'] = SITEID; } - $questiontestsurl = new moodle_url('/question/type/coderunner/questiontestrun.php'); + $questiontestsurl = new moodle_url('/question/type/coderunner/questiontestrun.php'); $questiontestsurl->params($qparams); $this->numpasses = 0; @@ -345,12 +349,9 @@ public function run_all_tests_for_context($questionidstoinclude = []) { } else { $nrunsthistime = $this->nruns; } - if ($this->randomseed > 0) { + if ($this->randomseed >= 0) { mt_srand($this->randomseed); } - if ($question->id == 6273) { - echo $question->id; - } // Now run the test for the required number of times. for ($i = 0; $i < $nrunsthistime; $i++) { // Only records last outcome and message. @@ -403,7 +404,7 @@ public function run_all_tests_for_context($questionidstoinclude = []) { } echo "\n"; } - return; + return [$this->numpasses, $this->failedtestdetails, $this->missinganswerdetails]; } @@ -496,8 +497,6 @@ public function print_overall_result() { } echo html_writer::end_tag('ul'); } - - if (count($this->failedtestdetails) > 0) { echo $OUTPUT->heading(get_string('coderunner_install_testsuite_failures', 'qtype_coderunner'), 5); echo html_writer::start_tag('ul'); @@ -531,6 +530,36 @@ public function print_overall_result() { echo html_writer::tag('p', $link); } + /** + * Print an overall summary of the failed tests. + */ + public static function print_summary_after_bulktestall($numpasses, $allfailingtests, $allmissinganswers) { + global $OUTPUT; + echo $OUTPUT->heading(get_string('bulktestoverallresults', 'qtype_coderunner'), 5); + $spacer = '  |  '; + $passstr = $numpasses . ' ' . get_string('passes', 'qtype_coderunner') . $spacer; + $failstr = count($allfailingtests) . ' ' . get_string('fails', 'qtype_coderunner') . $spacer; + $missingstr = count($allmissinganswers) . ' ' . get_string('missinganswers', 'qtype_coderunner'); + echo html_writer::tag('p', $passstr . $failstr . $missingstr); + + if (count($allmissinganswers) > 0) { + echo $OUTPUT->heading(get_string('coderunner_install_testsuite_noanswer', 'qtype_coderunner'), 5); + echo html_writer::start_tag('ul'); + foreach ($allmissinganswers as $message) { + echo html_writer::tag('li', $message); + } + echo html_writer::end_tag('ul'); + } + if (count($allfailingtests) > 0) { + echo $OUTPUT->heading(get_string('coderunner_install_testsuite_failures', 'qtype_coderunner'), 5); + echo html_writer::start_tag('ul'); + foreach ($allfailingtests as $message) { + echo html_writer::tag('li', $message); + } + echo html_writer::end_tag('ul'); + } + } + /** * Display the results of scanning all the CodeRunner questions to diff --git a/classes/jobesandbox.php b/classes/jobesandbox.php index 39cb4a86..c4ba6a03 100644 --- a/classes/jobesandbox.php +++ b/classes/jobesandbox.php @@ -162,7 +162,7 @@ public function execute($sourcecode, $language, $input, $files = null, $params = try { // Had to use try here as isset($PAGE->context) always seems to fail even if the context has been set. $context = $PAGE->context; - $courseid = $context->get_course_context(strict: true)->instanceid; + $courseid = $context->get_course_context(true)->instanceid; // raises exception if context is unknown. } catch (Exception $e) { $courseid = 1; // Use context of 1 as no $PAGE context is set, eg, could be a websocket UI run. } diff --git a/downloadquizattempts.php b/downloadquizattempts.php index b3e6acfb..f5b2e9b1 100644 --- a/downloadquizattempts.php +++ b/downloadquizattempts.php @@ -47,9 +47,7 @@ $PAGE->requires->jquery_plugin('ui'); $PAGE->requires->jquery_plugin('ui-css'); -// Create the helper class. -$bulktester = new qtype_coderunner_bulk_tester(); -$courses = $bulktester->get_all_courses(); +$courses = qtype_coderunner_bulk_tester::get_all_courses(); // Start display. echo $OUTPUT->header(); diff --git a/findduplicates.php b/findduplicates.php index 550b4a10..c5ab2807 100644 --- a/findduplicates.php +++ b/findduplicates.php @@ -50,12 +50,6 @@ $PAGE->set_cm($cm, $DB->get_record('course', ['id' => $cm->course], '*', MUST_EXIST)); } -// Create the helper class. -$bulktester = new qtype_coderunner_bulk_tester(); - -// Release the session, so the user can do other things while this runs. -\core\session\manager::write_close(); - // Display. echo $OUTPUT->header(); echo $OUTPUT->heading($title); @@ -63,7 +57,7 @@ echo "\n"; echo "\n"; // Find all the duplicates. -$allquestionsmap = $bulktester->get_all_coderunner_questions_in_context($contextid); +$allquestionsmap = qtype_coderunner_bulk_tester::get_all_coderunner_questions_in_context($contextid); $allquestions = array_values($allquestionsmap); $numduplicates = 0; for ($i = 0; $i < count($allquestions); $i++) { diff --git a/findduplicatesindex.php b/findduplicatesindex.php index 92680c8d..c134a12c 100644 --- a/findduplicatesindex.php +++ b/findduplicatesindex.php @@ -35,15 +35,12 @@ $PAGE->set_context($context); $PAGE->set_title('Find duplicate questions'); -// Create the helper class. -$bulktester = new qtype_coderunner_bulk_tester(); - // Display. echo $OUTPUT->header(); echo $OUTPUT->heading('Courses containing CodeRunner questions'); // Find in which contexts the user can edit questions. -$questionsbycontext = $bulktester->get_num_coderunner_questions_by_context(); +$questionsbycontext = qtype_coderunner_bulk_tester::get_num_coderunner_questions_by_context(); $availablequestionsbycontext = []; foreach ($questionsbycontext as $contextid => $numcoderunnerquestions) { $context = context::instance_by_id($contextid); diff --git a/lang/en/qtype_coderunner.php b/lang/en/qtype_coderunner.php index 6e3a764c..425cdd36 100644 --- a/lang/en/qtype_coderunner.php +++ b/lang/en/qtype_coderunner.php @@ -1374,18 +1374,17 @@ function should be applied, e.g. {{STUDENT_ANSWER | e(\'py\')}} is $string['purgeoldcachekeysbutton'] = 'Purge only OLD keys'; $string['purgeallcachekeysbutton'] = 'Purge ALL keys'; -$string['bulktestinfo'] = 'By default clicking on test links will test with ...&randomseed=0&repeatrandomonly=1&nruns=1. Feel free to change the url as you see fit.
-By default each question with \'random\' in the name will be tested nruns times -unless repeatrandomonly is 0, in which case all questions are tested that many times.
A randomseed of 0 means the seed is not set. -Setting it to another value (eg, 1) will mean that the php randomseed is set before doing the test(s) for each question with random in its name.
-If you don\'t set the random seed then each time you do a bulk test you will get random sequences of question instances, which may mean the grade -cache isn\'t so useful and more questions have to actually be run on the Jobe server (depending on how random your questions are).
+$string['bulktestinfo'] = '
Q1 nameQ1 CategoryQ2 nameQ2 category