How to run the tests (moodle 45)
Versión 2 (Emilio Penna, Jueves, 19 de Marzo de 2026 10:07:52 -0300)
| 1 | 1 | h2. JMeter script configuration |
|
|---|---|---|---|
| 2 | 1 | ||
| 3 | 1 | The script requires the JMeter Plugins Manager. Download @plugins-manager.jar@ from |
|
| 4 | 1 | https://jmeter-plugins.org/install/Install/ and place it in @lib/ext/@ (restart JMeter). |
|
| 5 | 1 | ||
| 6 | 1 | Tested with JMeter 5.6.3 and Moodle 4.5. |
|
| 7 | 1 | ||
| 8 | 2 | Emilio Penna | h3. User-defined variables (Test Plan level) |
| 9 | 1 | ||
| 10 | 2 | Emilio Penna | All parameters are configured as user-defined variables at the top of the Test Plan: |
| 11 | 1 | ||
| 12 | 2 | Emilio Penna | |_.Variable|_.Description|_.Example| |
| 13 | 2 | Emilio Penna | |@curso@|Course ID (numeric)|@2@| |
| 14 | 2 | Emilio Penna | |@prueba@|Quiz module ID (numeric, the @cmid@)|@2@| |
| 15 | 2 | Emilio Penna | |@host@|Server hostname (no protocol)|@eva-perf.seciu.edu.uy@| |
| 16 | 2 | Emilio Penna | |@servidor@|Server URL with protocol|@https://eva-perf.seciu.edu.uy@| |
| 17 | 2 | Emilio Penna | |@port@|HTTPS port|@443@| |
| 18 | 2 | Emilio Penna | |@csvfile@|Absolute path to the users CSV file|@/home/user/perftestusers5000.csv@| |
| 19 | 2 | Emilio Penna | |@twaitmin@|Minimum think time in milliseconds|@30000@| |
| 20 | 2 | Emilio Penna | |@twaitmax@|Maximum think time in milliseconds|@90000@| |
| 21 | 2 | Emilio Penna | |@assertiontext1@|Text asserted on quiz pages (English)|@page@| |
| 22 | 2 | Emilio Penna | |@assertiontext2@|Text asserted on quiz pages (Spanish)|@página@| |
| 23 | 1 | ||
| 24 | 2 | Emilio Penna | The @assertiontext1@/@assertiontext2@ pair handles Moodle installations in either language. |
| 25 | 2 | Emilio Penna | They verify that quiz attempt pages loaded correctly after each @processattempt.php@ call. |
| 26 | 1 | ||
| 27 | 2 | Emilio Penna | h3. Thread Group |
| 28 | 1 | ||
| 29 | 2 | Emilio Penna | Set the number of threads (VUs) and ramp-up time in the Thread Group. The script is configured |
| 30 | 2 | Emilio Penna | for a single iteration per thread (@LoopController.loops=1@): each virtual user logs in, |
| 31 | 2 | Emilio Penna | completes the quiz once, and exits. On error, the thread stops (@stopthread@). |
| 32 | 1 | ||
| 33 | 2 | Emilio Penna | We tested up to 3000 threads with a 180 s ramp-up. |
| 34 | 1 | ||
| 35 | 2 | Emilio Penna | Start with 1 thread to confirm the script runs without errors before scaling up. |
| 36 | 1 | ||
| 37 | 2 | Emilio Penna | h3. CSV Data Set Config |
| 38 | 1 | ||
| 39 | 2 | Emilio Penna | The script reads user credentials from the CSV file. Columns are: @user,n1,n2,mail,pwd@. |
| 40 | 2 | Emilio Penna | Set the @csvfile@ variable to the absolute path of your users file. |
| 41 | 1 | ||
| 42 | 2 | Emilio Penna | h3. Synchronizing Timer and Gaussian Random Timer |
| 43 | 1 | ||
| 44 | 2 | Emilio Penna | The script simulates students starting the exam at the same moment using two timers placed |
| 45 | 2 | Emilio Penna | inside the @startattempt@ transaction controller, just before the POST to @startattempt.php@: |
| 46 | 1 | ||
| 47 | 2 | Emilio Penna | * *Synchronizing Timer* (@groupSize=0@): holds all threads at this point until the entire |
| 48 | 2 | Emilio Penna | thread group has arrived, then releases them simultaneously. This models the worst-case |
| 49 | 2 | Emilio Penna | scenario of all students clicking "Start attempt" at exactly the same time. |
| 50 | 2 | Emilio Penna | * *Gaussian Random Timer* (deviation @30000@ ms, offset @5000@ ms): after release, each |
| 51 | 2 | Emilio Penna | thread waits a random delay before actually sending the startattempt request. With these |
| 52 | 2 | Emilio Penna | settings, approximately *66% of threads fire within the first 30 seconds*, and ~95% within |
| 53 | 2 | Emilio Penna | the first minute. This models the real-world observation that in large exams, 55–75% of |
| 54 | 2 | Emilio Penna | students tend to start in the first minute, making this a conservative worst-case scenario. |
| 55 | 1 | ||
| 56 | 2 | Emilio Penna | h3. Think time |
| 57 | 1 | ||
| 58 | 2 | Emilio Penna | Each quiz page uses a @TestAction@ pause of @${twait}@ milliseconds, where @twait@ is |
| 59 | 2 | Emilio Penna | initialized per thread at the start of the test by a JSR223 sampler (Groovy) that picks a |
| 60 | 2 | Emilio Penna | random value uniformly between @twaitmin@ and @twaitmax@. This means each virtual user has |
| 61 | 2 | Emilio Penna | a *fixed* think time for the entire test, but different users have different values — a |
| 62 | 2 | Emilio Penna | reasonable model for students answering at different speeds. |
| 63 | 1 | ||
| 64 | 2 | Emilio Penna | h3. Script coverage and limitations |
| 65 | 2 | Emilio Penna | |
| 66 | 2 | Emilio Penna | The script covers the main HTTP interactions of the quiz flow: login, course page, quiz view, |
| 67 | 2 | Emilio Penna | exam start, answering all 16 questions across 8 pages (via @processattempt.php@), and |
| 68 | 2 | Emilio Penna | finishing the attempt. Quiz attempts and answers are saved correctly in Moodle — this has |
| 69 | 2 | Emilio Penna | been verified after each test run by reviewing the quiz results in the admin interface. |
| 70 | 2 | Emilio Penna | |
| 71 | 2 | Emilio Penna | The script does not replicate every browser request. In particular, it omits most AJAX calls |
| 72 | 2 | Emilio Penna | (e.g. autosave, flag updates, analytics beacons) and does not fetch all embedded static |
| 73 | 2 | Emilio Penna | resources on each page. A real browser session generates significantly more requests per page. |
| 74 | 2 | Emilio Penna | However, the requests that drive server-side PHP processing — which is the actual bottleneck — |
| 75 | 2 | Emilio Penna | are all included. The "get static resources" controller in the script is disabled; static |
| 76 | 2 | Emilio Penna | asset delivery is better tested via @mod_cache@ or a dedicated CDN rather than through JMeter. |
| 77 | 2 | Emilio Penna | |
| 78 | 2 | Emilio Penna | The @sesskey@ token (Moodle's CSRF protection) is extracted dynamically via regex after login |
| 79 | 2 | Emilio Penna | and after the quiz view page, and included in all subsequent POST requests. The @attempt@ ID |
| 80 | 2 | Emilio Penna | is similarly extracted after @startattempt.php@ and used throughout. |