Skip to content

Commit 9c3bc18

Browse files
committed
add more moodle api tests, add pipeline for moodle hurl tests
1 parent c1852ea commit 9c3bc18

10 files changed

Lines changed: 1646 additions & 12 deletions

.github/workflows/playwright.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,34 @@ on:
99
workflow_call:
1010

1111
jobs:
12+
test-hurl:
13+
steps:
14+
- uses: actions/checkout@v5
15+
16+
- name: Remove existing Docker containers and volumes
17+
run: docker compose down -v
18+
19+
- name: Start Docker services
20+
run: docker compose up -d --wait --timeout 600 --pull always
21+
22+
- name: Install hurl
23+
run: |
24+
curl --location --remote-name https://github.com/Orange-OpenSource/hurl/releases/download/6.0.0/hurl_6.0.0_amd64.deb
25+
sudo dpkg -i hurl_6.0.0_amd64.deb
26+
27+
- name: run hurl tests
28+
run: |
29+
for file in tests/*.hurl; do
30+
cat setup_test_environment/setup.hurl "$file" | hurl --variables-file envrionments/env_localhost_adler_stack.env --report-html report || exit 1
31+
done
32+
33+
- uses: actions/upload-artifact@v4
34+
if: ${{ !cancelled() }}
35+
with:
36+
name: hurl-report-moodle
37+
path: moodle/report/
38+
retention-days: 30
39+
1240
test-playwright:
1341
timeout-minutes: 60
1442
runs-on: ${{ matrix.runner }}

moodle/setup_test_environment/setup.hurl

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
# - s1_id: User ID for student 1
1111
# - s2_username: Username for student 2
1212
# - m1_username: Username for manager 1
13+
# - m1_category_id: Category ID for manager 1
1314
# - m2_username: Username for manager 2
1415
# - moodleM1Token: Token for manager 1
1516
# - moodleM2Token: Token for manager 2
@@ -18,12 +19,16 @@
1819
# - course_c1_id: Course ID for course c1 (created by m1)
1920
# - c1_cm_uuid: UUID of a course module in course c1
2021
# - c1_cm_id: Course module ID for a learning element in course c1
22+
# - c1_adaptivity_uuid: UUID of the adaptivity element in c1
23+
# - c1_adaptivity_id: Course module ID for the adaptivity element in c1
24+
# - c1_adaptivity_question1_uuid: uuid of the first question of the adaptivity element
2125

2226
# Initialize variables (needs a fake request)
23-
GET {{host}}
27+
GET {{host}}/webservice/rest/simpleserver.php
2428
[Options]
2529
variable: c1_cm_uuid=f734f354-6b0a-4102-a19d-57ab6f151146
26-
30+
variable: c1_adaptivity_uuid=b228a001-d5a6-4298-9321-56270b476465
31+
variable: c1_adaptivity_question1_uuid=ac525937-0dd3-45a6-9e31-7e64936db61d
2732

2833
# test login as site admin for adler_admin_service
2934
POST {{host}}/webservice/rest/simpleserver.php
@@ -98,6 +103,8 @@ elements[1][username]: {{m2_username}}
98103
elements[1][role]: adler_manager
99104

100105
HTTP 200
106+
[Captures]
107+
m1_category_id: jsonpath "$.data[0].category_id"
101108

102109
# {"data":[{"username":"m1-8f3206a5-3969-42a0-94a4-0102779f23f9","role":"adler_manager","category_path":null,"category_id":4},{"username":"m2-d579316a-d1db-4ae8-a03a-189fce37bb78","role":"adler_manager","category_path":null,"category_id":5}]}
103110

@@ -174,14 +181,14 @@ Content-Type: application/x-www-form-urlencoded
174181
wsfunction: enrol_manual_enrol_users
175182
moodlewsrestformat: json
176183
wstoken: {{moodleAdminToken}}
177-
enrolments[0][roleid]: 5 # student role
184+
enrolments[0][roleid]: 5 # student role, there is no api endpoint to convert role name to id
178185
enrolments[0][userid]: {{s1_id}}
179186
enrolments[0][courseid]: {{course_c1_id}}
180187
HTTP 200
181188
[Asserts]
182189
jsonpath "$.exception" not exists
183190

184-
# Get module id of one learning element in course c1
191+
# Get module id of one learning element and the adaptivity element in course c1
185192
POST {{host}}/webservice/rest/server.php
186193
Content-Type: application/x-www-form-urlencoded
187194
[FormParams]
@@ -191,10 +198,13 @@ wstoken: {{moodleS1Token}}
191198
elements[0][course_id]: {{course_c1_id}}
192199
elements[0][element_type]: cm
193200
elements[0][uuid]: {{c1_cm_uuid}}
201+
elements[1][course_id]: {{course_c1_id}}
202+
elements[1][element_type]: cm
203+
elements[1][uuid]: {{c1_adaptivity_uuid}}
194204
HTTP 200
195205
[Captures]
196206
c1_cm_id: jsonpath "$.data[0].moodle_id"
197-
207+
c1_adaptivity_id: jsonpath "$.data[1].moodle_id"
198208

199209
# complete learning element as s1 to have progress in the course
200210
POST {{host}}/webservice/rest/server.php

moodle/tests/local_adler_get_element_ids_by_uuids.hurl

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,25 @@
1+
##############################################
2+
# TEST 0: Valid request - S1 queries element from C1 (enrolled)
3+
# POSITIVE TEST: S1 is enrolled in C1, should successfully get element IDs
4+
# Expected: HTTP 200 with valid element data, no exception
5+
##############################################
6+
POST {{host}}/webservice/rest/server.php
7+
Content-Type: application/x-www-form-urlencoded
8+
[FormParams]
9+
wsfunction: local_adler_get_element_ids_by_uuids
10+
moodlewsrestformat: json
11+
wstoken: {{moodleS1Token}}
12+
elements[0][course_id]: {{course_c1_id}}
13+
elements[0][element_type]: cm
14+
elements[0][uuid]: {{c1_cm_uuid}}
15+
16+
HTTP 200
17+
[Asserts]
18+
# Should NOT have an exception - this is a valid request
19+
jsonpath "$.exception" not exists
20+
# Should return element data
21+
jsonpath "$.data" count > 0
22+
123
##############################################
224
# TEST 1: S2 queries element from C1 (not enrolled)
325
# Should be BLOCKED - s2 is not enrolled in c1
@@ -8,7 +30,9 @@ Content-Type: application/x-www-form-urlencoded
830
wsfunction: local_adler_get_element_ids_by_uuids
931
moodlewsrestformat: json
1032
wstoken: {{moodleS2Token}}
11-
elements: [{"course_id":"{{course_c1_id}}","element_type":"cm","uuid":"{{c1_cm_uuid}}"}]
33+
elements[0][course_id]: {{course_c1_id}}
34+
elements[0][element_type]: cm
35+
elements[0][uuid]: {{c1_cm_uuid}}
1236

1337
HTTP 200
1438
[Asserts]
@@ -26,7 +50,9 @@ Content-Type: application/x-www-form-urlencoded
2650
wsfunction: local_adler_get_element_ids_by_uuids
2751
moodlewsrestformat: json
2852
wstoken: {{moodleM2Token}}
29-
elements: [{"course_id":"{{course_c1_id}}","element_type":"cm","uuid":"{{c1_cm_uuid}}"}]
53+
elements[0][course_id]: {{course_c1_id}}
54+
elements[0][element_type]: cm
55+
elements[0][uuid]: {{c1_cm_uuid}}
3056

3157
HTTP 200
3258
[Asserts]
@@ -42,7 +68,9 @@ Content-Type: application/x-www-form-urlencoded
4268
wsfunction: local_adler_get_element_ids_by_uuids
4369
moodlewsrestformat: json
4470
wstoken: {{moodleS2Token}}
45-
elements: [{"course_id":"999999","element_type":"cm","uuid":"{{c1_cm_uuid}}"}]
71+
elements[0][course_id]: 999999
72+
elements[0][element_type]: cm
73+
elements[0][uuid]: {{c1_cm_uuid}}
4674

4775
HTTP 200
4876
[Asserts]
@@ -58,7 +86,9 @@ Content-Type: application/x-www-form-urlencoded
5886
wsfunction: local_adler_get_element_ids_by_uuids
5987
moodlewsrestformat: json
6088
wstoken: {{moodleS2Token}}
61-
elements: [{"course_id":"1' OR '1'='1","element_type":"cm","uuid":"{{c1_cm_uuid}}"}]
89+
elements[0][course_id]: 1' OR '1'='1
90+
elements[0][element_type]: cm
91+
elements[0][uuid]: {{c1_cm_uuid}}
6292

6393
HTTP 200
6494
[Asserts]
@@ -74,7 +104,9 @@ Content-Type: application/x-www-form-urlencoded
74104
wsfunction: local_adler_get_element_ids_by_uuids
75105
moodlewsrestformat: json
76106
wstoken: {{moodleS2Token}}
77-
elements: [{"course_id":"{{course_c1_id}}","element_type":"cm","uuid":"abc' OR '1'='1"}]
107+
elements[0][course_id]: {{course_c1_id}}
108+
elements[0][element_type]: cm
109+
elements[0][uuid]: abc' OR '1'='1
78110

79111
HTTP 200
80112
[Asserts]
@@ -90,7 +122,9 @@ Content-Type: application/x-www-form-urlencoded
90122
wsfunction: local_adler_get_element_ids_by_uuids
91123
moodlewsrestformat: json
92124
wstoken: {{moodleS1Token}}
93-
elements: [{"course_id":"{{course_c1_id}}","element_type":"cm","uuid":""}]
125+
elements[0][course_id]: {{course_c1_id}}
126+
elements[0][element_type]: cm
127+
elements[0][uuid]:
94128

95129
HTTP 200
96130
[Asserts]
@@ -106,7 +140,9 @@ Content-Type: application/x-www-form-urlencoded
106140
wsfunction: local_adler_get_element_ids_by_uuids
107141
moodlewsrestformat: json
108142
wstoken: {{moodleS1Token}}
109-
elements: [{"course_id":"{{course_c1_id}}","element_type":"cm","uuid":"*"}]
143+
elements[0][course_id]: {{course_c1_id}}
144+
elements[0][element_type]: cm
145+
elements[0][uuid]: *
110146

111147
HTTP 200
112148
[Asserts]

moodle/tests/local_adler_score_get_course_scores.hurl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
1+
##############################################
2+
# TEST 0: Valid request - S1 gets scores for C1 (enrolled)
3+
# POSITIVE TEST: S1 is enrolled in C1, should successfully get scores
4+
# Expected: HTTP 200 with valid course scores data, no exception
5+
##############################################
6+
POST {{host}}/webservice/rest/server.php
7+
Content-Type: application/x-www-form-urlencoded
8+
[FormParams]
9+
wsfunction: local_adler_score_get_course_scores
10+
moodlewsrestformat: json
11+
wstoken: {{moodleS1Token}}
12+
course_id: {{course_c1_id}}
13+
14+
HTTP 200
15+
[Asserts]
16+
# Should NOT have an exception - this is a valid request
17+
jsonpath "$.exception" not exists
18+
# Should return course scores data
19+
jsonpath "$.data" exists
20+
jsonpath "$.data" count > 0
21+
122
##############################################
223
# TEST 1: S2 gets scores for C1 (not enrolled)
324
# VULNERABILITY: S2 should NOT access C1 scores

0 commit comments

Comments
 (0)