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 "
Q1 name
Q1 Category
Q2 name
Q2 category
\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'] = '
+
Number of runs: How many times each included question will be tested.
+
Repeat random only: Limits repeated runs to questions with random in their names.
+
randomseed: If set to a postive integer then the PHP randomseed is set to this value before running the test(s) for each question that has 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).
For a given seed the sequence of random question instances should be the same (assuming your question template uses the random seed it is given correctly).
Setting the random seed allows you to recreate a specific sequences of random question instances (eg, you could do 100 runs with 1 being
-the initial seed, then try 100 runs with 200 being the seed, etc, hopefully getting more coverage).';
+the initial seed, then try 100 runs with 200 being the seed, etc, hopefully getting more coverage).
';
$string['cachepurgeindextitle'] = 'Coderunner Cache Purge Index';
$string['cachepurgepagetitle'] = 'Purging cache for {$a}';
-$string['cachepurgeindexinfo'] = 'Purging OLD keys will only delete cache entries for grading runs that are older than the Coderunner cache Time To Live (TTL) as set in the admin settings. Pruging ALL will delete all cache entries for the given course.';
+$string['cachepurgeindexinfo'] = 'Purging OLD keys will only delete cache entries for grading runs that are older than the Coderunner cache Time To Live (TTL) as set in the admin settings. Purging ALL will delete all cache entries for the given course.';
$string['currentttlinfo'] = 'Coderunner grading cache Time to Live is currently set to TTL = {$a->seconds} seconds (={$a->days} days)';
$string['unauthorisedcachepurging'] = 'You do not have suitable access to any CodeRunner questions!';
$string['contextidnotacourse'] = 'Nothing to do as context_id $contextid is not a course.';
diff --git a/prototypeusageindex.php b/prototypeusageindex.php
index 2bd8cf3e..99192b3c 100644
--- a/prototypeusageindex.php
+++ b/prototypeusageindex.php
@@ -37,9 +37,7 @@
$PAGE->set_context($context);
$PAGE->set_title(get_string('prototypeusageindex', 'qtype_coderunner'));
-// Create the helper class.
-$bulktester = new qtype_coderunner_bulk_tester();
-$allcourses = $bulktester->get_all_courses();
+$allcourses = qtype_coderunner_bulk_tester::get_all_courses();
// Start display.
echo $OUTPUT->header();