How to run the tests (moodle 45)
Versión 1 (Emilio Penna, Jueves, 19 de Marzo de 2026 10:03:19 -0300)
| 1 | 1 | h1. How to run the tests (moodle 45) |
|
|---|---|---|---|
| 2 | 1 | ||
| 3 | 1 | h1. Moodle Quiz Load Testing — Setup and Procedure (Moodle 4.5, 2026) |
|
| 4 | 1 | ||
| 5 | 1 | This page describes how to set up and run the quiz load tests. |
|
| 6 | 1 | For actual results and infrastructure sizing data, see: [[Load_test_results_moodle45_2026]] |
|
| 7 | 1 | ||
| 8 | 1 | Attached to this page: |
|
| 9 | 1 | * Moodle quiz backup (16-question quiz, 8 pages) |
|
| 10 | 1 | * Test users file (CSV, for bulk upload and enrollment) |
|
| 11 | 1 | * JMeter script (jmx) |
|
| 12 | 1 | ||
| 13 | 1 | --- |
|
| 14 | 1 | ||
| 15 | 1 | h2. Setting up test data in Moodle |
|
| 16 | 1 | ||
| 17 | 1 | # Create a course for the test (or use an existing one). |
|
| 18 | 1 | # Restore the quiz backup (@.mbz@ file) into that course. |
|
| 19 | 1 | # Upload test users via _Site administration > Users > Accounts > Upload users_. |
|
| 20 | 1 | ** The CSV file contains 5000 users. Edit the @course@ column to match your course shortname. |
|
| 21 | 1 | ** Set "Force password change" to _None_. |
|
| 22 | 1 | # Enroll all users in the course (handled by the upload if the CSV includes the course column). |
|
| 23 | 1 | ||
| 24 | 1 | After the test, verify that attempts and answers were recorded correctly in the quiz results. |
|
| 25 | 1 | ||
| 26 | 1 | *Resetting between runs:* if a test run is interrupted before finishing, attempts remain "in progress". |
|
| 27 | 1 | Users cannot start a new attempt in that state. Reset with: |
|
| 28 | 1 | ||
| 29 | 1 | <pre> |
|
| 30 | 1 | UPDATE mdl_quiz_attempts SET state='finished' WHERE quiz=<quiz_id>; |
|
| 31 | 1 | </pre> |
|
| 32 | 1 | ||
| 33 | 1 | --- |
|
| 34 | 1 | ||
| 35 | 1 | h2. JMeter script configuration |
|
| 36 | 1 | ||
| 37 | 1 | The script requires the JMeter Plugins Manager. Download @plugins-manager.jar@ from |
|
| 38 | 1 | https://jmeter-plugins.org/install/Install/ and place it in @lib/ext/@ (restart JMeter). |
|
| 39 | 1 | ||
| 40 | 1 | Tested with JMeter 5.6.3 and Moodle 4.5. |
|
| 41 | 1 | ||
| 42 | 1 | Open the @.jmx@ file and adjust: |
|
| 43 | 1 | ||
| 44 | 1 | # *Test Plan* — set @course_id@, @quiz_id@, and server hostname. |
|
| 45 | 1 | # *CSV Data Set Config* — set the path to the users CSV file. |
|
| 46 | 1 | # *Thread Group* — set number of threads (VUs) and ramp-up time. |
|
| 47 | 1 | ** Start with 1 thread to confirm the test runs without errors before scaling up. |
|
| 48 | 1 | ** We tested up to 3000 threads with 180 s ramp-up. |
|
| 49 | 1 | # *Synchronizing Timer* (before startattempt) — holds all VUs at the exam start point until |
|
| 50 | 1 | the configured number arrive, then releases them together. This simulates the real-world |
|
| 51 | 1 | burst when all students click "Start attempt" at the same time. Set the number of simultaneous |
|
| 52 | 1 | threads to match your VU count. |
|
| 53 | 1 | # *Gaussian Random Timer* (after startattempt, σ=30s, offset=5s) — introduces post-start |
|
| 54 | 1 | dispersion simulating students reading and answering at different rates. |
|
| 55 | 1 | ||
| 56 | 1 | --- |
|
| 57 | 1 | ||
| 58 | 1 | h2. Running the tests |
|
| 59 | 1 | ||
| 60 | 1 | From the command line (recommended for load tests — GUI mode has overhead): |
|
| 61 | 1 | ||
| 62 | 1 | <pre> |
|
| 63 | 1 | ./jmeter -n -t /path/to/moo4quiz.jmx -l /path/to/output.jtl \ |
|
| 64 | 1 | -Xms8g -Xmx8g -XX:+UseG1GC |
|
| 65 | 1 | </pre> |
|
| 66 | 1 | ||
| 67 | 1 | *JMeter machine sizing:* use a dedicated machine. We used 32 GB RAM / 8 CPU. |
|
| 68 | 1 | With a single client we ran up to 2000 VUs reliably. For 3000 VUs we did not observe |
|
| 69 | 1 | client-side errors, but if you do, consider splitting the load across two JMeter instances |
|
| 70 | 1 | or using JMeter's distributed testing mode. |
|
| 71 | 1 | ||
| 72 | 1 | --- |
|
| 73 | 1 | ||
| 74 | 1 | h2. Server monitoring during tests |
|
| 75 | 1 | ||
| 76 | 1 | Capture server-side metrics during each run to correlate with JMeter results. |
|
| 77 | 1 | A simple shell script running at 10-second intervals collecting the following is sufficient: |
|
| 78 | 1 | ||
| 79 | 1 | * @uptime@ — load average (1, 5, 15 min) |
|
| 80 | 1 | * @free -m@ — RAM and swap used |
|
| 81 | 1 | * @ps aux | grep apache@ — Apache process count |
|
| 82 | 1 | * @curl -s 127.0.0.1/fpm-status@ — PHP-FPM pool status (total, busy, idle workers) |
|
| 83 | 1 | * @ss -s@ or @netstat@ — HTTPS connections (port 443), MySQL TCP connections |
|
| 84 | 1 | ||
| 85 | 1 | Write output as CSV (one line per interval) for easy post-processing. |
|
| 86 | 1 | ||
| 87 | 1 | For the database server, @nmon -f -s 5@ provides CPU, memory, disk I/O, and network at |
|
| 88 | 1 | 5-second granularity. |
|
| 89 | 1 | ||
| 90 | 1 | --- |
|
| 91 | 1 | ||
| 92 | 1 | h2. Tips and lessons learned |
|
| 93 | 1 | ||
| 94 | 1 | * *Repeat each test at least twice.* On shared VMware infrastructure, hypervisor contention |
|
| 95 | 1 | from other VMs introduces variability. Two identical runs let you distinguish real behavior |
|
| 96 | 1 | from noise. |
|
| 97 | 1 | * *The startattempt spike is the critical moment.* Everything else in the quiz is easy for |
|
| 98 | 1 | the server. Focus your analysis on the synchronized exam start — that is where the system |
|
| 99 | 1 | will fail first. |
|
| 100 | 1 | * *mod_cache on the reverse proxy* improves static asset delivery (10–35% latency reduction) |
|
| 101 | 1 | but can worsen the startattempt spike by delivering pre-exam pages faster, clustering VUs |
|
| 102 | 1 | more tightly at the synchronization point. |
|
| 103 | 1 | * *CPU, not RAM, is the bottleneck* with PHP-FPM + OPcache. Don't over-provision RAM at the |
|
| 104 | 1 | expense of CPU cores. See [[Load_test_results_moodle45_2026]] for detailed data. |
|
| 105 | 1 | * *InnoDB buffer pool sizing matters.* If the working dataset fits in the buffer pool, |
|
| 106 | 1 | the database server will show near-zero read I/O during the test. Ensure |
|
| 107 | 1 | @innodb_buffer_pool_size@ is set appropriately (we used 16 GB RAM on the DB server). |
|
| 108 | 1 | * *Check OPcache hit rate* during tests (@opcache_get_status()@). With a warm cache, |
|
| 109 | 1 | hit rate should be above 99%. A cold OPcache at test start will produce artificially |
|
| 110 | 1 | poor results for the first few requests. |