Skip to content

Commit 3b47946

Browse files
authored
Merge pull request #37 from adlnet/Unit-testing
Unit testing / db fix
2 parents 60004c2 + 183adcb commit 3b47946

17 files changed

+1757
-437
lines changed

.github/workflows/ci.yml

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
name: Moodle Plugin CI
2+
3+
on: [push, pull_request]
4+
5+
jobs:
6+
test:
7+
runs-on: ubuntu-22.04
8+
9+
services:
10+
postgres:
11+
image: postgres:13
12+
env:
13+
POSTGRES_USER: 'postgres'
14+
POSTGRES_HOST_AUTH_METHOD: 'trust'
15+
ports:
16+
- 5432:5432
17+
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3
18+
19+
mariadb:
20+
image: mariadb:10
21+
env:
22+
MYSQL_USER: 'root'
23+
MYSQL_ALLOW_EMPTY_PASSWORD: "true"
24+
MYSQL_CHARACTER_SET_SERVER: "utf8mb4"
25+
MYSQL_COLLATION_SERVER: "utf8mb4_unicode_ci"
26+
ports:
27+
- 3306:3306
28+
options: --health-cmd="mysqladmin ping" --health-interval 10s --health-timeout 5s --health-retries 3
29+
30+
strategy:
31+
fail-fast: false
32+
matrix:
33+
php: ['7.4', '8.0', '8.1']
34+
moodle-branch: ['MOODLE_401_STABLE']
35+
database: [pgsql, mariadb]
36+
37+
steps:
38+
- name: Check out repository code
39+
uses: actions/checkout@v4
40+
with:
41+
path: plugin
42+
43+
- name: Setup PHP ${{ matrix.php }}
44+
uses: shivammathur/setup-php@v2
45+
with:
46+
php-version: ${{ matrix.php }}
47+
extensions: ${{ matrix.extensions }}
48+
ini-values: max_input_vars=5000
49+
# If you are not using code coverage, keep "none". Otherwise, use "pcov" (Moodle 3.10 and up) or "xdebug".
50+
# If you try to use code coverage with "none", it will fallback to phpdbg (which has known problems).
51+
coverage: none
52+
53+
- name: Initialise moodle-plugin-ci
54+
run: |
55+
composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^4
56+
echo $(cd ci/bin; pwd) >> $GITHUB_PATH
57+
echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH
58+
sudo locale-gen en_AU.UTF-8
59+
echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV
60+
61+
- name: Install moodle-plugin-ci
62+
run: moodle-plugin-ci install --plugin ./plugin --db-host=127.0.0.1
63+
env:
64+
DB: ${{ matrix.database }}
65+
MOODLE_BRANCH: ${{ matrix.moodle-branch }}
66+
# Uncomment this to run Behat tests using the Moodle App.
67+
# MOODLE_APP: 'true'
68+
69+
- name: PHP Lint
70+
if: ${{ !cancelled() }}
71+
run: moodle-plugin-ci phplint
72+
73+
- name: PHP Mess Detector
74+
continue-on-error: true # This step will show errors but will not fail
75+
if: ${{ !cancelled() }}
76+
run: moodle-plugin-ci phpmd
77+
78+
- name: Moodle Code Checker
79+
if: ${{ !cancelled() }}
80+
run: moodle-plugin-ci phpcs --max-warnings 0
81+
82+
- name: Moodle PHPDoc Checker
83+
if: ${{ !cancelled() }}
84+
run: moodle-plugin-ci phpdoc --max-warnings 0
85+
86+
- name: Validating
87+
if: ${{ !cancelled() }}
88+
run: moodle-plugin-ci validate
89+
90+
- name: Check upgrade savepoints
91+
if: ${{ !cancelled() }}
92+
run: moodle-plugin-ci savepoints
93+
94+
- name: Mustache Lint
95+
if: ${{ !cancelled() }}
96+
run: moodle-plugin-ci mustache
97+
98+
- name: Grunt
99+
if: ${{ !cancelled() }}
100+
run: moodle-plugin-ci grunt --max-lint-warnings 0
101+
102+
- name: PHPUnit tests
103+
if: ${{ !cancelled() }}
104+
run: moodle-plugin-ci phpunit --fail-on-warning
105+
106+
- name: Behat features
107+
id: behat
108+
if: ${{ !cancelled() }}
109+
run: moodle-plugin-ci behat --profile chrome
110+
111+
- name: Upload Behat Faildump
112+
if: ${{ failure() && steps.behat.outcome == 'failure' }}
113+
uses: actions/upload-artifact@v4
114+
with:
115+
name: Behat Faildump (${{ join(matrix.*, ', ') }})
116+
path: ${{ github.workspace }}/moodledata/behat_dump
117+
retention-days: 7
118+
if-no-files-found: ignore
119+
120+
- name: Mark cancelled jobs as failed.
121+
if: ${{ cancelled() }}
122+
run: exit 1

classes/local/cmi5_connectors.php

Lines changed: 65 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,15 @@ public function cmi5launch_create_course($id, $tenanttoken, $filename) {
7474
$databody = $filename->get_content();
7575
// Sends the stream to the specified URL.
7676
$result = $this->cmi5launch_send_request_to_cmi5_player_post($databody, $url, $filetype, $tenanttoken);
77-
77+
7878
// Check result and display message if not 200.
7979
$resulttest = $this->cmi5launch_connectors_error_message($result, "creating the course");
8080

8181
if ($resulttest == true) {
8282
// Return an array with course info.
8383
return $result;
84+
} else {
85+
return false;
8486
}
8587
}
8688

@@ -118,6 +120,8 @@ public function cmi5launch_create_tenant($urltosend, $username, $password, $newt
118120

119121
// Return an array with tenant name and info.
120122
return $returnedinfo;
123+
} else {
124+
return false;
121125
};
122126
}
123127

@@ -149,6 +153,8 @@ public function cmi5launch_retrieve_registration_with_get($registration, $id) {
149153
if ($resulttest == true) {
150154

151155
return $result;
156+
} else {
157+
return false;
152158
}
153159
}
154160

@@ -207,6 +213,8 @@ public function cmi5launch_retrieve_registration_with_post($courseid, $id) {
207213
$registration = $registrationinfo["code"];
208214

209215
return $registration;
216+
} else {
217+
return false;
210218
}
211219
}
212220

@@ -236,11 +244,13 @@ public function cmi5launch_retrieve_token($url, $username, $password, $audience,
236244
$result = $this->cmi5launch_send_request_to_cmi5_player_post($data, $url, $filetype, $username, $password);
237245

238246
// Check result and display message if not 200.
239-
$resulttest = $this->cmi5launch_connectors_error_message($result, "retrieving the registration");
247+
$resulttest = $this->cmi5launch_connectors_error_message($result, "retrieving the token");
240248

241249
if ($resulttest == true) {
242250

243251
return $result;
252+
} else {
253+
return false;
244254
}
245255
}
246256

@@ -269,6 +279,7 @@ public function cmi5launch_retrieve_url($id, $auindex) {
269279
$playerurl = $settings['cmi5launchplayerurl'];
270280
$courseid = $userscourse->courseid;
271281

282+
272283
// Build URL for launch URL request.
273284
$url = $playerurl . "/api/v1/course/" . $courseid ."/launch-url/" . $auindex;
274285

@@ -301,6 +312,8 @@ public function cmi5launch_retrieve_url($id, $auindex) {
301312
$urldecoded = json_decode($result, true);
302313

303314
return $urldecoded;
315+
} else {
316+
return false;
304317
}
305318
}
306319

@@ -322,13 +335,14 @@ public function cmi5launch_send_request_to_cmi5_player_post($databody, $url, $fi
322335
} else if ("json") {
323336
$contenttype = "application/json\r\n";
324337
}
325-
338+
326339
// If number of args is greater than one it is for retrieving tenant info and args are username and password.
327340
if (count($tokenorpassword) == 2 ) {
328341

329342
$username = $tokenorpassword[0];
330343
$password = $tokenorpassword[1];
331344

345+
332346
// Use key 'http' even if you send the request to https://...
333347
// There can be multiple headers but as an array under the ONE header.
334348
// Content(body) must be JSON encoded here, as that is what CMI5 player accepts.
@@ -342,13 +356,11 @@ public function cmi5launch_send_request_to_cmi5_player_post($databody, $url, $fi
342356
),
343357
);
344358

345-
// The options are here placed into a stream to be sent.
346-
$context = stream_context_create($options);
347-
348359
// Sends the stream to the specified URL and stores results.
349360
// The false is use_include_path, which we dont want in this case, we want to go to the url.
350-
$result = file_get_contents( $url, false, $context );
361+
$result = $this->cmi5launch_stream_and_send( $url, $options );
351362

363+
352364
// Else the args are what we need for posting a course.
353365
} else {
354366

@@ -370,12 +382,11 @@ public function cmi5launch_send_request_to_cmi5_player_post($databody, $url, $fi
370382
),
371383
);
372384

373-
// The options are placed into a stream to be sent.
374-
$context = stream_context_create(($options));
385+
375386

376387
// Sends the stream to the specified URL and stores results.
377388
// The false is use_include_path, which we dont want in this case, we want to go to the url.
378-
$result = file_get_contents( $url, false, $context );
389+
$result = $this->cmi5launch_stream_and_send( $url, $options );
379390

380391
}
381392

@@ -404,14 +415,14 @@ public function cmi5launch_send_request_to_cmi5_player_get($token, $url) {
404415
),
405416
);
406417

407-
// The options are here placed into a stream to be sent.
408-
$context = stream_context_create(($options));
409418

410-
// Sends the stream to the specified URL and stores results. False is to not use_include_path, we want to go to the url.
411-
$launchresponse = file_get_contents( $url, false, $context );
419+
// Sends the stream to the specified URL and stores results.
420+
// The false is use_include_path, which we dont want in this case, we want to go to the url.
421+
$launchresponse = $this->cmi5launch_stream_and_send( $url, $options );
412422

413423
$sessiondecoded = json_decode($launchresponse, true);
414424

425+
// Return response.
415426
return $sessiondecoded;
416427
}
417428

@@ -442,6 +453,8 @@ public function cmi5launch_retrieve_session_info_from_player($sessionid, $id) {
442453
if ($resulttest == true) {
443454

444455
return $result;
456+
} else {
457+
return false;
445458
}
446459
}
447460

@@ -454,7 +467,7 @@ public function cmi5launch_retrieve_session_info_from_player($sessionid, $id) {
454467
* @param string $type - The type missing to be added to the error message.
455468
* @return bool
456469
*/
457-
public function cmi5launch_connectors_error_message($resulttotest, $type) {
470+
public static function cmi5launch_connectors_error_message($resulttotest, $type) {
458471

459472
// Decode result because if it is not 200 then something went wrong
460473
// If it's a string, decode it.
@@ -464,12 +477,24 @@ public function cmi5launch_connectors_error_message($resulttotest, $type) {
464477
$resulttest = $resulttotest;
465478
}
466479

467-
if ($resulttest === false || array_key_exists("statusCode", $resulttest) && $resulttest["statusCode"] != 200) {
480+
// I think splittin these to return two seperate messages deppennnding on whether player is running is better.
481+
// Player cannot return an error if not runnin,
482+
if ($resulttest === false ){
483+
484+
echo "<br>";
485+
486+
echo "Something went wrong " . $type . ". CMI5 Player is not communicating. Is it running?";
468487

469488
echo "<br>";
470489

471-
echo "Something went wrong " . $type . ". CMI5 Player returned " . var_dump($resulttotest);
490+
return false;
491+
}
492+
else if( array_key_exists("statusCode", $resulttest) && $resulttest["statusCode"] != 200) {
493+
494+
echo "<br>";
472495

496+
echo "Something went wrong " . $type . ". CMI5 Player returned " . $resulttest["statusCode"] . " error. With message '"
497+
. $resulttest["message"] . "'." ;
473498
echo "<br>";
474499

475500
return false;
@@ -479,4 +504,27 @@ public function cmi5launch_connectors_error_message($resulttotest, $type) {
479504
return true;
480505
}
481506
}
507+
508+
/**
509+
* Wrapper function to allow for testing where file_get_contents cannot be overriden.
510+
* Also has create_stream as this makes a resource which interfers with testing.
511+
* @param mixed $url - the url to be sent to
512+
* @param mixed $use_include_path
513+
* @param mixed $context - the data to be sent
514+
* @param mixed $offset
515+
* @param mixed $maxlen
516+
* @return mixed $result - either a string or false.
517+
*/
518+
public function cmi5launch_stream_and_send($options, $url) {
519+
520+
// The options are placed into a stream to be sent.
521+
$context = stream_context_create(($options));
522+
523+
// Sends the stream to the specified URL and stores results.
524+
// The false is use_include_path, which we dont want in this case, we want to go to the url.
525+
$result = file_get_contents( $url, false, $context );
526+
527+
// Return result.
528+
return $result;
529+
}
482530
}

classes/local/course.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
defined('MOODLE_INTERNAL') || die();
2525

2626
class course {
27+
28+
// Lowercase values are for saving to DB.
2729
public $id, $url, $ausgrades, $type, $lmsid, $grade, $scores, $title, $moveon, $auindex,
2830
$parents, $objectives, $launchurl, $sessions = array(), $sessionid, $returnurl, $description = [], $activitytype, $launchmethod,
2931
$masteryscore, $progress, $noattempt, $completed, $passed, $inprogress, $satisfied, $moodlecourseid;

0 commit comments

Comments
 (0)