Commit 355b69d2 authored by Lückemeyer's avatar Lückemeyer
Browse files

reviewed test-moodle.sh

parent 7c38bfd4
Pipeline #11946 failed with stage
in 1 minute and 34 seconds
...@@ -10,18 +10,23 @@ MOODLE_URL="${MOODLE_URL:-http://localhost:8080}" ...@@ -10,18 +10,23 @@ MOODLE_URL="${MOODLE_URL:-http://localhost:8080}"
BACKEND_URL="${BACKEND_URL:-http://localhost:8081}" BACKEND_URL="${BACKEND_URL:-http://localhost:8081}"
MOODLE_ADMIN_USER="user" MOODLE_ADMIN_USER="user"
MOODLE_ADMIN_PASS="QAYwsx@12345" MOODLE_ADMIN_PASS="QAYwsx@12345"
# Automation User (Course creator) # Automation User (Course creator)
# GL: - rather moodle terminology: TEACHER_USER, what does the name maaer abbreviate?
AUTOMATION_USER_NAME="maaeruser" AUTOMATION_USER_NAME="maaeruser"
AUTOMATION_USER_PASS="AutomationPassword123" AUTOMATION_USER_PASS="AutomationPassword123"
# Student User (created by script) # Student User (created by script)
STUDENT_USER_NAME="tstudent" STUDENT_USER_NAME="tstudent"
STUDENT_USER_PASS="StudentPassword123" STUDENT_USER_PASS="StudentPassword123"
# GL: - make repos externally configurable to support different code bases, moodle versions, and runner examples
# + and fetch from repo to ensure identical config to provided examples
DTA_CONFIG_FILE="teacher-dta-dir-test-runner-jdk21.txt" DTA_CONFIG_FILE="teacher-dta-dir-test-runner-jdk21.txt"
# GL: + fetch from repo to ensure identical config to provided examples
DTA_STUDENT_SUBMISSION_FILE="student-dir.txt" DTA_STUDENT_SUBMISSION_FILE="student-dir.txt"
# --- Static Configuration --- # --- Static Configuration ---
MOODLE_CONTAINER="moodle-web-official" MOODLE_CONTAINER="moodle-web-official"
MOODLE_SYSTEM_USER="www-data" MOODLE_SYSTEM_USER="www-data"
MOODLE_ROOT_IN_CONTAINER="/var/www/html" MOODLE_ROOT_IN_CONTAINER="/var/www/html"
# GL: + fetch from repo and create zip during test to ensure current code base
PLUGIN_ZIP_NAME="dta.zip" PLUGIN_ZIP_NAME="dta.zip"
CUSTOM_SERVICE_NAME="dta_automation_service" CUSTOM_SERVICE_NAME="dta_automation_service"
DB_CONTAINER_NAME="moodle-db-official" DB_CONTAINER_NAME="moodle-db-official"
...@@ -31,11 +36,13 @@ DB_NAME="moodle" ...@@ -31,11 +36,13 @@ DB_NAME="moodle"
# ============================================================================== # ==============================================================================
# SCRIPT EXECUTION # SCRIPT EXECUTION
# ============================================================================== # ==============================================================================
# GL: - remove "definitive"
echo "🚀 Starting Definitive Moodle Automation Script..." echo "🚀 Starting Definitive Moodle Automation Script..."
echo " -> Using Moodle URL: $MOODLE_URL" echo " -> Using Moodle URL: $MOODLE_URL"
echo " -> Using Backend URL: $BACKEND_URL" echo " -> Using Backend URL: $BACKEND_URL"
# GL: - consider placing the following steps 1 and 2 in a dockerfile and create your own image. That way, you can later spin up multiple instances easily if the test load grows.
# remove next comment line
# --- THIS IS THE FIX --- # --- THIS IS THE FIX ---
# We now wait for the Moodle web application itself to be fully responsive. # We now wait for the Moodle web application itself to be fully responsive.
# We repeatedly curl the login page until we get a 200 OK status code. # We repeatedly curl the login page until we get a 200 OK status code.
...@@ -57,9 +64,11 @@ echo "✅ Moodle web server is responsive." ...@@ -57,9 +64,11 @@ echo "✅ Moodle web server is responsive."
# --- Pre-flight Checks & Plugin Install (Step 1) --- # --- Pre-flight Checks & Plugin Install (Step 1) ---
if ! docker ps --format '{{.Names}}' | grep -qw "$MOODLE_CONTAINER"; then echo "❌ Moodle container not running." && exit 1; fi if ! docker ps --format '{{.Names}}' | grep -qw "$MOODLE_CONTAINER"; then echo "❌ Moodle container not running." && exit 1; fi
if [ ! -f "$PLUGIN_ZIP_NAME" ]; then echo "❌ Plugin ZIP file not found." && exit 1; fi if [ ! -f "$PLUGIN_ZIP_NAME" ]; then echo "❌ Plugin ZIP file not found." && exit 1; fi
# GL: + move check to directly in front of teacher exercise creation and name "Teacher DTA exercise config file not found."
if [ ! -f "$DTA_CONFIG_FILE" ]; then echo "❌ DTA config file not found." && exit 1; fi if [ ! -f "$DTA_CONFIG_FILE" ]; then echo "❌ DTA config file not found." && exit 1; fi
echo "✅ Pre-flight checks passed." echo "✅ Pre-flight checks passed."
# GL: - name "Installing DTA plugin"
echo "📦 Step 1: Installing custom plugin..." echo "📦 Step 1: Installing custom plugin..."
docker exec -u "$MOODLE_SYSTEM_USER" "$MOODLE_CONTAINER" bash -c "set -e; mkdir -p '$MOODLE_ROOT_IN_CONTAINER/mod/assign/submission'; unzip -o '/tmp/$PLUGIN_ZIP_NAME' -d '$MOODLE_ROOT_IN_CONTAINER/mod/assign/submission'; php '$MOODLE_ROOT_IN_CONTAINER/admin/cli/upgrade.php' --non-interactive; php '$MOODLE_ROOT_IN_CONTAINER/admin/cli/purge_caches.php'" docker exec -u "$MOODLE_SYSTEM_USER" "$MOODLE_CONTAINER" bash -c "set -e; mkdir -p '$MOODLE_ROOT_IN_CONTAINER/mod/assign/submission'; unzip -o '/tmp/$PLUGIN_ZIP_NAME' -d '$MOODLE_ROOT_IN_CONTAINER/mod/assign/submission'; php '$MOODLE_ROOT_IN_CONTAINER/admin/cli/upgrade.php' --non-interactive; php '$MOODLE_ROOT_IN_CONTAINER/admin/cli/purge_caches.php'"
echo "✅ Plugin installed." echo "✅ Plugin installed."
...@@ -74,6 +83,7 @@ docker exec -u "$MOODLE_SYSTEM_USER" "$MOODLE_CONTAINER" php "$MOODLE_ROOT_IN_CO ...@@ -74,6 +83,7 @@ docker exec -u "$MOODLE_SYSTEM_USER" "$MOODLE_CONTAINER" php "$MOODLE_ROOT_IN_CO
echo " -> Enabling Web Service File Uploads (System-wide)..." echo " -> Enabling Web Service File Uploads (System-wide)..."
docker exec -u "$MOODLE_SYSTEM_USER" "$MOODLE_CONTAINER" php "$MOODLE_ROOT_IN_CONTAINER/admin/cli/cfg.php" --name=webserviceuploaddisabled --set=0 docker exec -u "$MOODLE_SYSTEM_USER" "$MOODLE_CONTAINER" php "$MOODLE_ROOT_IN_CONTAINER/admin/cli/cfg.php" --name=webserviceuploaddisabled --set=0
# remove next comment line
# --- THIS IS THE FINAL FIX --- # --- THIS IS THE FINAL FIX ---
# Enable username/password authentication for web service token generation # Enable username/password authentication for web service token generation
echo " -> Enabling password authentication for web services..." echo " -> Enabling password authentication for web services..."
...@@ -182,7 +192,7 @@ INSERT INTO mdl_config (name, value) VALUES ('webserviceprotocols', 'rest') ON D ...@@ -182,7 +192,7 @@ INSERT INTO mdl_config (name, value) VALUES ('webserviceprotocols', 'rest') ON D
# --- End of addition -- # --- End of addition --
-- Create our custom service, now with a requiredcapability set for robustness -- Create our custom service, now with a required capability set for robustness
INSERT IGNORE INTO mdl_external_services (name, shortname, enabled, requiredcapability, restrictedusers, uploadfiles, downloadfiles) INSERT IGNORE INTO mdl_external_services (name, shortname, enabled, requiredcapability, restrictedusers, uploadfiles, downloadfiles)
VALUES ('DTA Automation Service', '$CUSTOM_SERVICE_NAME', 1, '', 0, 1, 1); -- <-- The capability fix VALUES ('DTA Automation Service', '$CUSTOM_SERVICE_NAME', 1, '', 0, 1, 1); -- <-- The capability fix
...@@ -200,9 +210,9 @@ INSERT IGNORE INTO mdl_external_services_functions (externalserviceid, functionn ...@@ -200,9 +210,9 @@ INSERT IGNORE INTO mdl_external_services_functions (externalserviceid, functionn
(@serviceid, 'mod_assign_get_submissions'), (@serviceid, 'mod_assign_get_submissions'),
(@serviceid, 'mod_assign_save_grade'), (@serviceid, 'mod_assign_save_grade'),
(@serviceid, 'assignsubmission_dta_save_submission'); (@serviceid, 'assignsubmission_dta_save_submission');
# GL: - remove following comment line
# -- *** THIS IS THE CRITICAL FIX *** # -- *** THIS IS THE CRITICAL FIX ***
# -- Authorize the admin user to use this service. # -- Authorize the teacher user to use this service.
SET @automationuserid = (SELECT id FROM mdl_user WHERE username = '$AUTOMATION_USER_NAME' AND deleted = 0 ORDER BY id ASC LIMIT 1); SET @automationuserid = (SELECT id FROM mdl_user WHERE username = '$AUTOMATION_USER_NAME' AND deleted = 0 ORDER BY id ASC LIMIT 1);
INSERT IGNORE INTO mdl_external_services_users (externalserviceid, userid, iprestriction, validuntil, timecreated) INSERT IGNORE INTO mdl_external_services_users (externalserviceid, userid, iprestriction, validuntil, timecreated)
VALUES (@serviceid, @automationuserid , NULL, NULL, UNIX_TIMESTAMP()); VALUES (@serviceid, @automationuserid , NULL, NULL, UNIX_TIMESTAMP());
...@@ -216,8 +226,8 @@ echo " -> Purging Moodle caches.." ...@@ -216,8 +226,8 @@ echo " -> Purging Moodle caches.."
docker exec -u "$MOODLE_SYSTEM_USER" "$MOODLE_CONTAINER" php "$MOODLE_ROOT_IN_CONTAINER/admin/cli/purge_caches.php" docker exec -u "$MOODLE_SYSTEM_USER" "$MOODLE_CONTAINER" php "$MOODLE_ROOT_IN_CONTAINER/admin/cli/purge_caches.php"
sleep 15 sleep 15
# --- Step 6: Assign System Roles via API (The Definitive Fix) --- # --- Step 6: Assign System Roles via API ---
echo "🛡️ Step 6: Assigning System Roles to Automation User..." echo "🛡️ Step 6: Assigning System Roles to teacher User..."
# We use the main site admin's token for this one-time setup task, as it's guaranteed to have permissions. # We use the main site admin's token for this one-time setup task, as it's guaranteed to have permissions.
ADMIN_SETUP_TOKEN_RESPONSE=$(curl --fail -sS -L -X POST "$MOODLE_URL/login/token.php" --data-urlencode "username=$MOODLE_ADMIN_USER" --data-urlencode "password=$MOODLE_ADMIN_PASS" --data-urlencode "service=moodle_mobile_app") ADMIN_SETUP_TOKEN_RESPONSE=$(curl --fail -sS -L -X POST "$MOODLE_URL/login/token.php" --data-urlencode "username=$MOODLE_ADMIN_USER" --data-urlencode "password=$MOODLE_ADMIN_PASS" --data-urlencode "service=moodle_mobile_app")
ADMIN_SETUP_TOKEN=$(echo "$ADMIN_SETUP_TOKEN_RESPONSE" | jq -r '.token') ADMIN_SETUP_TOKEN=$(echo "$ADMIN_SETUP_TOKEN_RESPONSE" | jq -r '.token')
...@@ -237,12 +247,13 @@ echo "✅ Assigned System Roles to Automation User." ...@@ -237,12 +247,13 @@ echo "✅ Assigned System Roles to Automation User."
docker exec -u "$MOODLE_SYSTEM_USER" "$MOODLE_CONTAINER" php "$MOODLE_ROOT_IN_CONTAINER/admin/cli/purge_caches.php" docker exec -u "$MOODLE_SYSTEM_USER" "$MOODLE_CONTAINER" php "$MOODLE_ROOT_IN_CONTAINER/admin/cli/purge_caches.php"
sleep 15 sleep 15
# GL: - remove the following comment line
# --- THIS IS THE CRITICAL FIX --- # --- THIS IS THE CRITICAL FIX ---
echo " -> Purging Moodle caches to apply service changes..." echo " -> Purging Moodle caches to apply service changes..."
docker exec -u "$MOODLE_SYSTEM_USER" "$MOODLE_CONTAINER" php "$MOODLE_ROOT_IN_CONTAINER/admin/cli/purge_caches.php" docker exec -u "$MOODLE_SYSTEM_USER" "$MOODLE_CONTAINER" php "$MOODLE_ROOT_IN_CONTAINER/admin/cli/purge_caches.php"
echo "✅ Caches purged." echo "✅ Caches purged."
sleep 5 sleep 5
# GL: - potential dockerfile content until here
echo "🔐 Step 3: Obtaining API Token...$AUTOMATION_USER_NAME..$AUTOMATION_USER_PASS" echo "🔐 Step 3: Obtaining API Token...$AUTOMATION_USER_NAME..$AUTOMATION_USER_PASS"
TOKEN_RESPONSE=$(curl --fail -sS -L -X POST "$MOODLE_URL/login/token.php" \ TOKEN_RESPONSE=$(curl --fail -sS -L -X POST "$MOODLE_URL/login/token.php" \
...@@ -260,7 +271,7 @@ fi ...@@ -260,7 +271,7 @@ fi
TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.token') TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.token')
echo "✅ Successfully obtained API token. $TOKEN" echo "✅ Successfully obtained API token. $TOKEN"
# GL: optionally for every test, rather avoid to save test execution time
# --- Step 4: Create a Course --- # --- Step 4: Create a Course ---
echo "📚 Step 4: Creating a new course..." echo "📚 Step 4: Creating a new course..."
COURSE_SHORTNAME="DTA-Course-$(date +%s)" COURSE_SHORTNAME="DTA-Course-$(date +%s)"
...@@ -287,11 +298,12 @@ if [ -z "$NEW_COURSE_ID" ] || [ "$NEW_COURSE_ID" == "null" ]; then ...@@ -287,11 +298,12 @@ if [ -z "$NEW_COURSE_ID" ] || [ "$NEW_COURSE_ID" == "null" ]; then
exit 1 exit 1
fi fi
echo "✅ Successfully created course '$COURSE_SHORTNAME' with ID: $NEW_COURSE_ID" echo "✅ Successfully created course '$COURSE_SHORTNAME' with ID: $NEW_COURSE_ID"
# GL: - remove following comment line
# --- END OF ROBUST ERROR CHECK --- # --- END OF ROBUST ERROR CHECK ---
# --- Step 5: Enroll Admin User into the New Course --- # --- Step 5: Enroll Teacher User into the New Course ---
echo "🧑‍🏫 Step 5: Enrolling you as a teacher in the new course..." echo "🧑‍🏫 Step 5: Enrolling teacher in the new course..."
# First, get the User ID for your admin user # First, get the User ID for your teacher user
AUTOMATION_USER_ID=$(docker exec "$DB_CONTAINER_NAME" mysql -u root -p"$DB_ROOT_PASSWORD" "$DB_NAME" -se "SELECT id FROM mdl_user WHERE username='$AUTOMATION_USER_NAME';") AUTOMATION_USER_ID=$(docker exec "$DB_CONTAINER_NAME" mysql -u root -p"$DB_ROOT_PASSWORD" "$DB_NAME" -se "SELECT id FROM mdl_user WHERE username='$AUTOMATION_USER_NAME';")
# The roleid for a Teacher is typically 3 (editingteacher) or 4 (teacher). We'll use 3. # The roleid for a Teacher is typically 3 (editingteacher) or 4 (teacher). We'll use 3.
TEACHER_ROLE_ID=3 TEACHER_ROLE_ID=3
...@@ -315,6 +327,7 @@ if echo "$ENROL_RESPONSE" | jq -e 'if type=="object" and .exception then true el ...@@ -315,6 +327,7 @@ if echo "$ENROL_RESPONSE" | jq -e 'if type=="object" and .exception then true el
fi fi
echo "✅ Successfully enrolled you in the course." echo "✅ Successfully enrolled you in the course."
# GL: - second file from here
# --- Step 5: Upload Configuration File for DTA Plugin --- # --- Step 5: Upload Configuration File for DTA Plugin ---
echo "📤 Step 5: Uploading config file for DTA plugin..." echo "📤 Step 5: Uploading config file for DTA plugin..."
FILE_UPLOAD_RESPONSE=$(curl --fail -sS -L -X POST "$MOODLE_URL/webservice/upload.php" \ FILE_UPLOAD_RESPONSE=$(curl --fail -sS -L -X POST "$MOODLE_URL/webservice/upload.php" \
...@@ -341,7 +354,7 @@ require('/var/www/html/config.php'); ...@@ -341,7 +354,7 @@ require('/var/www/html/config.php');
require_once(\$CFG->dirroot.'/course/modlib.php'); require_once(\$CFG->dirroot.'/course/modlib.php');
global \$DB, \$USER; global \$DB, \$USER;
// programmatically "log in" as the admin user // programmatically "log in" as the teacher user
// This gives file_save_draft_area_files the user context it needs. // This gives file_save_draft_area_files the user context it needs.
\$adminusername = "$AUTOMATION_USER_NAME"; \$adminusername = "$AUTOMATION_USER_NAME";
\$adminuser = \$DB->get_record('user', ['username' => \$adminusername, 'deleted' => 0], '*', MUST_EXIST); \$adminuser = \$DB->get_record('user', ['username' => \$adminusername, 'deleted' => 0], '*', MUST_EXIST);
...@@ -360,7 +373,7 @@ if (count(\$argv) < 3) { exit("Error: Course ID and DTA Item ID are required.\n" ...@@ -360,7 +373,7 @@ if (count(\$argv) < 3) { exit("Error: Course ID and DTA Item ID are required.\n"
\$data->course = \$courseid; \$data->course = \$courseid;
\$data->modulename = 'assign'; \$data->modulename = 'assign';
\$data->name = 'Fully Automated DTA Assignment'; \$data->name = 'Fully Automated DTA Assignment';
\$data->intro = 'This assignment was created by the final automation script.'; \$data->intro = 'This assignment was created by the DTA automation script.';
\$data->introformat = FORMAT_HTML; \$data->introformat = FORMAT_HTML;
\$data->section = 1; \$data->section = 1;
\$data->visible = 1; \$data->visible = 1;
...@@ -369,6 +382,7 @@ if (count(\$argv) < 3) { exit("Error: Course ID and DTA Item ID are required.\n" ...@@ -369,6 +382,7 @@ if (count(\$argv) < 3) { exit("Error: Course ID and DTA Item ID are required.\n"
\$data->assignsubmission_dta_enabled = 1; \$data->assignsubmission_dta_enabled = 1;
\$data->assignsubmission_file_enabled = 1; \$data->assignsubmission_file_enabled = 1;
//GL: - remove following comment line
// --- THIS IS FIX #1: Correct property name for the DTA file manager --- // --- THIS IS FIX #1: Correct property name for the DTA file manager ---
// This assumes the form element for your file manager is named 'package_filemanager' // This assumes the form element for your file manager is named 'package_filemanager'
// The final property name becomes assignsubmission_dta_package_filemanager // The final property name becomes assignsubmission_dta_package_filemanager
...@@ -402,7 +416,7 @@ if (count(\$argv) < 3) { exit("Error: Course ID and DTA Item ID are required.\n" ...@@ -402,7 +416,7 @@ if (count(\$argv) < 3) { exit("Error: Course ID and DTA Item ID are required.\n"
\$data->cutoffdate = 0; // No hard cutoff \$data->cutoffdate = 0; // No hard cutoff
\$data->gradingduedate = 0; \$data->gradingduedate = 0;
// --- Moodle Magic - these fields are necessary but we don't need to change them --- // these fields are necessary but we don't need to change them ---
\$data->module = \$DB->get_field('modules', 'id', ['name' => 'assign'], MUST_EXIST); \$data->module = \$DB->get_field('modules', 'id', ['name' => 'assign'], MUST_EXIST);
\$data->timemodified = time(); \$data->timemodified = time();
\$data->alwaysshowdescription = 0; \$data->alwaysshowdescription = 0;
...@@ -458,6 +472,7 @@ rm "$LOCAL_PHP_ASSIGN_SCRIPT_PATH" ...@@ -458,6 +472,7 @@ rm "$LOCAL_PHP_ASSIGN_SCRIPT_PATH"
echo " -> Created assignment with ID: $NEW_ASSIGNMENT_ID" echo " -> Created assignment with ID: $NEW_ASSIGNMENT_ID"
echo "✅ Test scenario created." echo "✅ Test scenario created."
# GL: + third file from here
# --- Step 8: Student Submission Workflow --- # --- Step 8: Student Submission Workflow ---
echo "🧑‍🎓 Step 8: Beginning student submission workflow..." echo "🧑‍🎓 Step 8: Beginning student submission workflow..."
STUDENT_USER_ID=$(docker exec "$DB_CONTAINER_NAME" mysql -u root -p"$DB_ROOT_PASSWORD" "$DB_NAME" -se "SELECT id FROM mdl_user WHERE username='$STUDENT_USER_NAME';") STUDENT_USER_ID=$(docker exec "$DB_CONTAINER_NAME" mysql -u root -p"$DB_ROOT_PASSWORD" "$DB_NAME" -se "SELECT id FROM mdl_user WHERE username='$STUDENT_USER_NAME';")
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment