Skip to content

Commit

Permalink
Progress on scheduled grading cache purging and scripts for purging b…
Browse files Browse the repository at this point in the history
…y course.

Also contains new functionality in bulktester (eg, nruns setting) and updates
to the Coderunner settings.php
  • Loading branch information
mckeownp committed Dec 6, 2024
1 parent d301c32 commit 6a042d9
Show file tree
Hide file tree
Showing 17 changed files with 547 additions and 118 deletions.
3 changes: 2 additions & 1 deletion bulktest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
// Get the parameters from the URL.
$contextid = required_param('contextid', PARAM_INT);
$categoryid = optional_param('categoryid', null, PARAM_INT);
$nruns = optional_param('nruns', 1, PARAM_INT);

// Login and check permissions.
$context = context::instance_by_id($contextid);
Expand Down Expand Up @@ -60,7 +61,7 @@
echo $OUTPUT->heading($title);

// Run the tests.
[$numpasses, $failingtests, $missinganswers] = $bulktester->run_all_tests_for_context($context, $categoryid);
[$numpasses, $failingtests, $missinganswers] = $bulktester->run_all_tests_for_context($context, $categoryid, $nruns);

// Display the final summary.
$bulktester->print_overall_result($numpasses, $failingtests, $missinganswers);
Expand Down
11 changes: 9 additions & 2 deletions bulktestindex.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@
$PAGE->set_context($context);
$PAGE->set_title(get_string('bulktestindextitle', 'qtype_coderunner'));

$nruns = 1;
$nrunsfromsettings = get_config('qtype_coderunner', 'bulktestdefaultnruns');
if (abs($nrunsfromsettings) > 1) {
$nruns = abs($nrunsfromsettings);
}


// Create the helper class.
$bulktester = new qtype_coderunner_bulk_tester();

Expand Down Expand Up @@ -75,7 +82,7 @@
$contextid = $info['contextid'];
$numcoderunnerquestions = $info['numquestions'];

$testallurl = new moodle_url('/question/type/coderunner/bulktest.php', ['contextid' => $contextid]);
$testallurl = new moodle_url('/question/type/coderunner/bulktest.php', ['contextid' => $contextid, 'nruns' => $nruns]);
$testalllink = html_writer::link(
$testallurl,
get_string('bulktestallincontext', 'qtype_coderunner'),
Expand Down Expand Up @@ -110,7 +117,7 @@
if ($cat->count > 0) {
$url = new moodle_url(
'/question/type/coderunner/bulktest.php',
['contextid' => $contextid, 'categoryid' => $cat->id]
['contextid' => $contextid, 'categoryid' => $cat->id, 'nruns' => $nruns]
);
$linktext = $cat->name . ' (' . $cat->count . ')';
$link = html_writer::link($url, $linktext, ['style' => $buttonstyle]);
Expand Down
65 changes: 65 additions & 0 deletions cachepurge.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php
// This file is part of CodeRunner - http://coderunner.org.nz
//
// CodeRunner is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// CodeRunner is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with CodeRunner. If not, see <http://www.gnu.org/licenses/>.

/**
* This script runs all the question tests for all deployed versions of all
* questions in a given context and, optionally, a given question category.
* It is a modified version of the script from the qtype_stack plugin.
*
* @package qtype_coderunner
* @copyright 2016 Richard Lobb, The University of Canterbury
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace qtype_coderunner;

use context;

define('NO_OUTPUT_BUFFERING', true);

require_once(__DIR__ . '/../../../config.php');
// require_once($CFG->libdir . '/questionlib.php');



// Get the parameters from the URL.
$contextid = required_param('contextid', PARAM_INT);
$usettl = required_param('usettl', PARAM_INT); // 1 for use, 0 for don't use.

// Login and check permissions.
$context = context::instance_by_id($contextid);
require_login();
require_capability('moodle/question:editall', $context);
$PAGE->set_url('/question/type/coderunner/cachepurge.php', ['contextid' => $context->id, 'useTTL' => $usettl]);
$PAGE->set_context($context);
$title = 'Purging cache for ' . $context->get_context_name(); //get_string('bulktesttitle', 'qtype_coderunner', $context->get_context_name());
$PAGE->set_title($title);



// Release the session, so the user can do other things while this runs.
\core\session\manager::write_close();

// Create the helper class.
$purger = new cache_purger();


echo $OUTPUT->header();
echo $OUTPUT->heading($title, 4);

$purger->purge_cache_for_context($context->id, $usettl);


echo $OUTPUT->footer();
107 changes: 107 additions & 0 deletions cachepurgeindex.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?php
// This file is part of CodeRunner - http://coderunner.org.nz
//
// CodeRunner is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// CodeRunner is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Stack. If not, see <http://www.gnu.org/licenses/>.

/**
* This script provides an index for purging grading cache entries by course.
*
* @package qtype_coderunner
* @copyright 2024 Paul McKeown, The University of Canterbury
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

namespace qtype_coderunner;

use context_system;
use context;
use html_writer;
use moodle_url;


require_once(__DIR__ . '/../../../config.php');
require_once($CFG->libdir . '/questionlib.php');

// Login and check permissions.
$context = context_system::instance();
require_login();

$PAGE->set_url('/question/type/coderunner/cachepurgeindex.php');
$PAGE->set_context($context);
$PAGE->set_title('Coderunner Cache Purge Index'); //get_string('bulktestindextitle', 'qtype_coderunner'));


// Display.
echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('coderunnercontexts', 'qtype_coderunner'));

// Find in which contexts the user can edit questions.
//$questionsbycontext = $bulktester->get_num_coderunner_questions_by_context();


$cachepurger = new cache_purger();
$allvisiblecoursecontexts = $cachepurger->get_all_visible_course_contextids();
krsort($allvisiblecoursecontexts); // Effectively newest first.
$keycounts = $cachepurger->key_count_by_course($allvisiblecoursecontexts);

// List all contexts available to the user.
if (count($allvisiblecoursecontexts) == 0) {
echo html_writer::tag('p', get_string('unauthorisedbulktest', 'qtype_coderunner'));
} else {
echo html_writer::start_tag('ul');
//$buttonstyle = 'border: 1px solid gray; padding: 2px 2px 0px 2px;';
$buttonstyle = 'border: 1px solid #F0F0F0; background-color: #FFFFC0; padding: 2px 2px 0px 2px;border: 4px solid white';
foreach ($allvisiblecoursecontexts as $contextid) {
$context = context::instance_by_id($contextid);
$name = $context->get_context_name(true, true);
$courseid = $context->instanceid;

$purgeusingttlurl = new moodle_url('/question/type/coderunner/cachepurge.php', ['contextid' => $contextid, 'usettl' => 1]);
$purgeusingttllink = html_writer::link(
$purgeusingttlurl,
'Purge all old cache entries (ie, using TTL)',
// get_string('bulktestallincontext', 'qtype_coderunner'),
['title' => 'Purge all old', //get_string('testalltitle', 'qtype_coderunner'),
'style' => $buttonstyle]
);

$purgeallurl = new moodle_url('/question/type/coderunner/cachepurge.php', ['contextid' => $contextid, 'usettl' => 0]);
$purgealllink = html_writer::link(
$purgeallurl,
'Purge all in context',
// get_string('bulktestallincontext', 'qtype_coderunner'),
['title' => 'Purge all', //get_string('testalltitle', 'qtype_coderunner'),
'style' => $buttonstyle]
);


$litext = $name . ' [Course id= ' . $courseid . '] &nbsp;&nbsp; cache size=' . $keycounts[$contextid] . '&nbsp;&nbsp;&nbsp;' . $purgeusingttllink . '&nbsp;&nbsp;&nbsp;' . $purgealllink;
$class = 'cachepurge coderunner context normal';
echo html_writer::start_tag('li', ['class' => $class]);
echo $litext;
echo html_writer::end_tag('li');
}
echo html_writer::end_tag('ul');

// Maybe do a purge all later...
// if (has_capability('moodle/site:config', context_system::instance())) {
// echo html_writer::tag('p', html_writer::link(
// new moodle_url('/question/type/coderunner/bulktestall.php'),
// get_string('bulktestrun', 'qtype_coderunner')
// ));
// }
}


echo $OUTPUT->footer();
50 changes: 40 additions & 10 deletions classes/bulk_tester.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,12 +178,13 @@ public function get_all_coderunner_questions_in_context($contextid, $includeprot
*
* @param context $context the context to run the tests for.
* @param int $categoryid test only questions in this category. Default to all.
* @param int $nruns the number times to test each question. Default to 1.
* @return array with three elements:
* int a count of how many tests passed
* array of messages relating to the questions with failures
* array of messages relating to the questions without sample answers
*/
public function run_all_tests_for_context(context $context, $categoryid = null) {
public function run_all_tests_for_context(context $context, $categoryid = null, $nruns = 1) {
global $OUTPUT;

// Load the necessary data.
Expand Down Expand Up @@ -221,33 +222,62 @@ public function run_all_tests_for_context(context $context, $categoryid = null)
);
$enhancedname = "{$question->name} (V{$question->version})";
$questionnamelink = html_writer::link($previewurl, $enhancedname, ['target' => '_blank']);
echo "<li>$questionnamelink:";
echo "<li><small>$questionnamelink: </small>";
flush(); // Force output to prevent timeouts and show progress.

$passstr = get_string('pass', 'qtype_coderunner');
$failstr = get_string('fail', 'qtype_coderunner');
$npasses = 0;
$nfails = 0;
// Now run the test.
try {
[$outcome, $message] = $this->load_and_test_question($question->id);
} catch (Exception $e) {
$message = $e->getMessage();
$outcome = self::FAIL;
for ($i = 0; $i < $nruns; $i++) {
// only records last outcome and message
try {
[$outcome, $message] = $this->load_and_test_question($question->id);
} catch (Exception $e) {
$message = $e->getMessage();
$outcome = self::FAIL;
echo "<i style='color:red'>x</i>";
}
if ($outcome == self::MISSINGANSWER) {
echo " $message ";
break; // No point trying again as there is no answer to check.
} else {
if ($outcome == self::PASS) {
$npasses += 1;
echo "<i style='color:green;'>.</i>";
} else {
$nfails += 1;
echo "<i style='color:red;'>.</i>";
}
//echo " $message, ";
}
}

// Report the result, and record failures for the summary.
echo " $message</li>";
if ($outcome != self::MISSINGANSWER) {
echo "&nbsp;&nbsp;&nbsp;<i style='color:green;'>" . $passstr . "=" . $npasses. "</i>";
if ($nfails > 0) {
echo ", <b style='color:red;'>" . $failstr . '=' . $nfails. "</b>";
}
}
echo "</li>";
flush(); // Force output to prevent timeouts and show progress.
$qparams['category'] = $currentcategoryid . ',' . $context->id;
$qparams['lastchanged'] = $question->id;
$qparams['qperpage'] = 1000;
$questionbankurl = new moodle_url('/question/edit.php', $qparams);
$questionbanklink = html_writer::link($questionbankurl, $nameandcount->name, ['target' => '_blank']);
if ($outcome === self::PASS) {
if ($npasses == $nruns) {
$numpasses += 1;
} else if ($outcome === self::MISSINGANSWER) {
$missinganswers[] = "$coursename / $questionbanklink / $questionnamelink";
} else {
$failingtests[] = "$coursename / $questionbanklink / $questionnamelink: $message";
$failmessage = " <b style='color:red'>" . get_string('fail', 'qtype_coderunner') . '=' . $nfails. "</b>";
$failingtests[] = "$coursename / $questionbanklink / $questionnamelink: $failmessage";
}
}
// echo " $message ";
echo "</ul>\n";
}

Expand Down
Loading

0 comments on commit 6a042d9

Please sign in to comment.