diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7004f47 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "github.copilot.enable": { + + "*": true, + "plaintext": false, + "markdown": false, + "scminput": false + }, + "github.copilot.advanced": {}, + "files.eol": "\n" +} \ No newline at end of file diff --git a/AUview.php b/AUview.php index 13318ea..c91f43d 100755 --- a/AUview.php +++ b/AUview.php @@ -154,14 +154,13 @@ function mod_cmi5launch_launchexperience(registration) { // Array to hold data for table. $sessioninfo = array(); - // Retrieve createdAt and format. $date = new DateTime($session->createdat, new DateTimeZone('US/Eastern')); $date->setTimezone(new DateTimeZone('America/New_York')); $sessioninfo[] = $date->format('D d M Y H:i:s'); // Retrieve lastRequestTime and format. - $date = new DateTime($session->updatedat, new DateTimeZone('US/Eastern')); + $date = new DateTime($session->lastrequesttime, new DateTimeZone('US/Eastern')); $date->setTimezone(new DateTimeZone('America/New_York')); $sessioninfo[] = $date->format('D d M Y H:i:s'); diff --git a/classes/local/au.php b/classes/local/au.php old mode 100755 new mode 100644 index 55e2d4d..b3eb7fe --- a/classes/local/au.php +++ b/classes/local/au.php @@ -21,6 +21,9 @@ */ namespace mod_cmi5launch\local; +// Include the errorover (error override) funcs. +require_once ($CFG->dirroot . '/mod/cmi5launch/classes/local/errorover.php'); + class au { // Lowercase values are for saving to DB. @@ -34,6 +37,13 @@ class au { // Constructs AUs. Is fed array and where array key matches property, sets the property. public function __construct($statement) { + // What can go wrong here? It could be that a statement is null + // or that the statement is not an array or not an object. + if (is_null($statement) || (!is_array($statement) && !is_object($statement) )) { + + throw new nullException('Statement to build AU is null or not an array/object.', 0); + } + // If it is an array, create the object. foreach ($statement as $key => $value) { $this->$key = ($value); diff --git a/classes/local/au_helpers.php b/classes/local/au_helpers.php old mode 100755 new mode 100644 index 5785ad5..5fad354 --- a/classes/local/au_helpers.php +++ b/classes/local/au_helpers.php @@ -24,6 +24,12 @@ namespace mod_cmi5launch\local; use mod_cmi5launch\local\au; +use mod_cmi5launch\local\errorover; + +global $CFG; +// Include the errorover (error override) funcs. +require_once ($CFG->dirroot . '/mod/cmi5launch/classes/local/errorover.php'); + defined('MOODLE_INTERNAL') || die(); class au_helpers { @@ -46,38 +52,67 @@ public function get_cmi5launch_retrieve_aus_from_db() { * @return array */ public function cmi5launch_retrieve_aus($returnedinfo) { + + $resultchunked = ""; + + + // Use our own more specific error handler, to give better info tto user. + set_error_handler('mod_cmi5launch\local\array_chunk_warning', E_WARNING); + // The results come back as nested array under more then just AUs. - // We only want the info pertaining to the AU. - $resultchunked = array_chunk($returnedinfo["metadata"]["aus"], 1, ); + // We only want the info pertaining to the AU. However, if the wrong info is passed array_chunk will through an exception. + try { + $resultchunked = array_chunk($returnedinfo["metadata"]["aus"], 1, ); + } + catch (\Exception $e) { + + echo "Cannot retrieve AUs. Error found when trying to parse them from course creation: " . + "Please check the connection to player or course format and try again. \n" + . $e->getMessage() . "\n"; + + //exit; + } + // Restore the error handler. + restore_error_handler(); + return $resultchunked; } + /** * So it should be fed an array of statements that then assigns the values to * several aus, and then returns them as au objects. * @param mixed $austatements * @return array */ - public function cmi5launch_create_aus($austatements) { - + public function cmi5launch_create_aus($austatements) + { // Needs to return our new AU objects. $newaus = array(); - foreach ($austatements as $int => $info) { + // We should not be able to get here but what if null is pulled from record and passed in? + // So in case it is given null. + if ($austatements == null) { + + throw new nullException('Cannot retrieve AU information. AU statements from DB are: ' . $austatements, 0); - // The aus come back decoded from DB nestled in an array. - // So they are the first key, which is '0'. - $statement = $info[0]; + } else { + foreach ($austatements as $int => $info) { - $au = new au($statement); + // The aus come back decoded from DB nestled in an array. + // So they are the first key, which is '0'. + $statement = $info[0]; - // Assign the newly created au to the return array. - $newaus[] = $au; - } + $au = new au($statement); + + // Assign the newly created au to the return array. + $newaus[] = $au; + } - // Return our new list of AU. - return $newaus; + // Return our new list of AU. + return $newaus; + } } /** @@ -89,50 +124,105 @@ public function cmi5launch_save_aus($auobjectarray) { // Add userid to the record. global $DB, $USER, $cmi5launch; $table = "cmi5launch_aus"; - + // An array to hold the created ids. $auids = array(); - // For each AU in array build a new record and save it. - // Because of so many nested variables this needs to be done manually. - foreach ($auobjectarray as $auobject) { - - // Make a newrecord to save. - $newrecord = new \stdClass(); - - $newrecord->userid = $USER->id; - $newrecord->attempt = $auobject->attempt; - $newrecord->auid = $auobject->id; - $newrecord->launchmethod = $auobject->launchMethod; - $newrecord->lmsid = json_decode(json_encode($auobject->lmsId, true) ); - $newrecord->url = $auobject->url; - $newrecord->type = $auobject->type; - $title = json_decode(json_encode($auobject->title), true); - $newrecord->title = $title[0]['text']; - $newrecord->moveon = $auobject->moveOn; - $newrecord->auindex = $auobject->auIndex; - $newrecord->parents = json_encode($auobject->parents, true); - $newrecord->objectives = json_encode($auobject->objectives); - $desc = json_decode(json_encode($auobject->description), true); - $newrecord->description = $desc[0]['text']; - $newrecord->activitytype = $auobject->activityType; - $newrecord->masteryscore = $auobject->masteryscore; - $newrecord->completed = $auobject->completed; - $newrecord->passed = $auobject->passed; - $newrecord->inprogress = $auobject->inprogress; - $newrecord->noattempt = $auobject->noattempt; - $newrecord->satisfied = $auobject->satisfied; - // And HERE we can add the moodlecourseid. - $newrecord->moodlecourseid = $cmi5launch->id; - - // Save the record and get the new id. - $newid = $DB->insert_record($table, $newrecord, true); - // Save new id to list to pass back. - $auids[] = $newid; - } + // Variables for error over and exception handling. + // Array of all items in new record, this will be useful for troubleshooting. + $newrecorditems = array('id', 'attempt', 'auid', 'launchmethod', 'lmsid', 'url', 'type', 'title', 'moveon', 'auindex', 'parents', 'objectives', 'description', 'activitytype', 'masteryscore', 'completed', 'passed', 'inprogress', 'noattempt', 'satisfied', 'moodlecourseid'); + $currentrecord = 1; + $newid = ""; + $newrecord = ""; + + // Set error and exception handler to catch and override the default PHP error messages, to make messages more user friendly. + set_error_handler('mod_cmi5launch\local\sifting_data_warning', E_WARNING); + set_exception_handler('mod_cmi5launch\local\exception_au'); + + //Check it's not null. + if ($auobjectarray == null) { - return $auids; + throw new nullException('Cannot save AU information. AU object array is: null' , 0); + + } else { + // For each AU in array build a new record and save it. + // Because of so many nested variables this needs to be done manually. + foreach ($auobjectarray as $auobject) { + + // A try statement to catch any errors that may be thrown. + try { + // Make a newrecord to save. + $newrecord = new \stdClass(); + + // Assign the values to the new record. + $newrecord->userid = $USER->id; + $newrecord->attempt = $auobject->attempt; + $newrecord->auid = $auobject->id; + $newrecord->launchmethod = $auobject->launchMethod; + $newrecord->lmsid = json_decode(json_encode($auobject->lmsId, true)); + $newrecord->url = $auobject->url; + $newrecord->type = $auobject->type; + $title = json_decode(json_encode($auobject->title), true); + $newrecord->title = $title[0]['text']; + $newrecord->moveon = $auobject->moveOn; + $newrecord->auindex = $auobject->auIndex; + $newrecord->parents = json_encode($auobject->parents, true); + $newrecord->objectives = json_encode($auobject->objectives); + $desc = json_decode(json_encode($auobject->description), true); + $newrecord->description = $desc[0]['text']; + $newrecord->activitytype = $auobject->activityType; + $newrecord->masteryscore = $auobject->masteryscore; + $newrecord->completed = $auobject->completed; + $newrecord->passed = $auobject->passed; + $newrecord->inprogress = $auobject->inprogress; + $newrecord->noattempt = $auobject->noattempt; + $newrecord->satisfied = $auobject->satisfied; + $newrecord->moodlecourseid = $cmi5launch->id; + + // Save the record and get the new id. + $newid = $DB->insert_record($table, $newrecord, true); + + // Save new id to list to pass back. + $auids[] = $newid; + + // This is for troubleshooting, so we know where the error is. + $currentrecord++; + + // The set exception handler catches exceptionas that SLIP by, + // so maybe DONT make it throwable and catch type errror + } catch (\Throwable $e) { + + + echo "Cannot save to DB. Stopped at record with ID number " . ($currentrecord) . "."; + + // This is the tricky part, we need to find out which field is missing. But because the error is thrown ON the field, we need to do some + // manuevering to find out which field is missing. + // Typecast to array to grab the list item. + $items = (array) $newrecord; + + // Get the last ley of array + $lastkey = array_key_last($items); + + // Heres thhe tricky part, the lastkey here is somewhere in the array we earlier made and the NEXT one would be the one that threw the error. + // So now we can grab the key after the last one. + $key = array_search($lastkey, $newrecorditems) + 1; + + // Ok, NOW the missin element is key in newrecorditems. + $missing = $newrecorditems[$key]; + + // Now use the found missing value to give feedback to user. + echo " One of the fields is incorrect. Check data for field '$missing'. " . $e->getMessage() . "\n"; + } + } + + // Restore default hadlers. + restore_exception_handler(); + restore_error_handler(); + + return $auids; + } } + /** * Retrieves AU info from DB, converts to AU object, and returns it. @@ -145,22 +235,24 @@ public function cmi5launch_retrieve_aus_from_db($auid) { $check = $DB->record_exists( 'cmi5launch_aus', ['id' => $auid], '*', IGNORE_MISSING); - // If check is negative, the record does not exist. It should so throw error. + + // If check is negative, the record does not exist. It should also throw error. // Moodle will throw the error, but we want to pass this message back ot user. if (!$check) { - echo "

Error attempting to get AU data from DB. Check AU id. AU id is: " . $auid ."

"; + throw new nullException("Error attempting to get AU data from DB. Check AU id. AU id is: " . $auid ."

", 0); - return false; } else { $auitem = $DB->get_record('cmi5launch_aus', array('id' => $auid)); $au = new au($auitem); + + // Return our new list of AU. + return $au; } - // Return our new list of AU. - return $au; + } } diff --git a/classes/local/cmi5_connectors.php b/classes/local/cmi5_connectors.php index 439576c..1f3ab33 100755 --- a/classes/local/cmi5_connectors.php +++ b/classes/local/cmi5_connectors.php @@ -25,6 +25,8 @@ defined('MOODLE_INTERNAL') || die(); use mod_cmi5launch\local\cmi5launch_helpers; +// Include the errorover (error override) funcs. +require_once ($CFG->dirroot . '/mod/cmi5launch/classes/local/errorover.php'); class cmi5_connectors { @@ -60,6 +62,10 @@ public function cmi5launch_get_send_request_to_cmi5_player_get() { } + public function cmi5launch_get_connectors_error_message() { + return [$this, 'cmi5launch_connectors_error_message']; + } + /** * Function to create a course. * @param mixed $id - tenant id in Moodle. @@ -81,20 +87,37 @@ public function cmi5launch_create_course($id, $tenanttoken, $filename) { $databody = $filename->get_content(); + // So this one has some troubleshooting built in already, but we probably need to throw an exception to stop function or moodle will freak + // Sends the stream to the specified URL. $result = $this->cmi5launch_send_request_to_cmi5_player_post('cmi5launch_stream_and_send',$databody, $url, $filetype, $tenanttoken); - // Check result and display message if not 200. - $resulttest = $this->cmi5launch_connectors_error_message($result, "creating the course"); - - if ($resulttest == true) { - // Return an array with course info. - return $result; - } else { - return false; + // Now this will never return false, it will throw an exception if it fails, so we can just return the result + try { + // Check result and display message if not 200. + $resulttest = $this->cmi5launch_connectors_error_message($result, "creating the course"); + + // echo "Is it resulting?"; + if ($resulttest == true) { + // Return an array with course info. + return $result; + // I think this is the problem, it is coming back and throwing another error! I thought it would stop... do I need a kill in the error message hander? + // Its throwing BOB??? The third path is executing, THATS the problem! + // either way though, shouldn't the error funtion have ITS own test? like, + // what we need to test here is is resulttrue is true or not + } else { + // This should never be false, it should throw an exception if it is, so we can just return the result + // But catch all else that miht go wrong + throw new playerException("creating the course."); + } + }// catch all else that might go wrong + catch (\Throwable $e){ + throw new playerException("creating the course" . $e); } + } + /** * Function to create a tenant. * @param $urltosend - URL retrieved from user in URL textbox. @@ -108,11 +131,9 @@ public function cmi5launch_create_tenant($newtenantname) { $settings = cmi5launch_settings($cmi5launchid); - //$actor = $USER->username; $username = $settings['cmi5launchbasicname']; $playerurl = $settings['cmi5launchplayerurl']; $password = $settings['cmi5launchbasepass']; - global $CFG; // Build URL for launch URL request. $url = $playerurl . "/api/v1/tenant"; @@ -130,19 +151,27 @@ public function cmi5launch_create_tenant($newtenantname) { // Sends the stream to the specified URL. $result = $this->cmi5launch_send_request_to_cmi5_player_post('cmi5launch_stream_and_send', $data, $url, $filetype, $username, $password); + // Check result and display message if not 200. $resulttest = $this->cmi5launch_connectors_error_message($result, "creating the tenant"); - - if ($resulttest == true) { - - // Decode returned response into array. - $returnedinfo = json_decode($result, true); - - // Return an array with tenant name and info. - return $returnedinfo; - } else { - return false; - }; + // why is it coming back null and shouldnt we go to else the? + + + // Now this will never return false, it will throw an exception if it fails, so we can just return the result + try { + if ($resulttest == true) { + + return $result; + } else { + + throw new playerException("creating the tenant."); + } + }// catch all else that might go wrong + catch (\Throwable $e){ + + throw new playerException("Uncaught error creating the tenant" . $e); + } + } /** @@ -169,13 +198,21 @@ public function cmi5launch_retrieve_registration_with_get($registration, $id) { // Check result and display message if not 200. $resulttest = $this->cmi5launch_connectors_error_message($result, "retrieving the registration"); - - if ($resulttest == true) { - - return $result; - } else { - return false; + + // Now this will never return false, it will throw an exception if it fails, so we can just return the result + try { + if ($resulttest == true) { + return $result; + } else { + + throw new playerException("retrieving the registration information."); + } + }// catch all else that might go wrong + catch (\Throwable $e){ + + throw new playerException("Uncaught error retrieving the registration information." . $e); } + } /** @@ -223,19 +260,26 @@ public function cmi5launch_retrieve_registration_with_post($courseid, $id) { // Check result and display message if not 200. $resulttest = $this->cmi5launch_connectors_error_message($result, "retrieving the registration"); - // Catch errors. - if ($resulttest == true) { - - $registrationinfo = json_decode($result, true); - - // The returned 'registration info' is a large json object. - // Code is the registration id we want. - $registration = $registrationinfo["code"]; - - return $registration; - } else { - return false; + // Now this will never return false, it will throw an exception if it fails, so we can just return the result + try { + if ($resulttest == true) { + + $registrationinfo = json_decode($result, true); + + // The returned 'registration info' is a large json object. + // Code is the registration id we want. + $registration = $registrationinfo["code"]; + + return $registration; + } else { + throw new playerException("retrieving the registration information."); + } + }// catch all else that might go wrong + catch (\Throwable $e){ + + throw new playerException("Uncaught error retrieving the registration information." . $e); } + } /** @@ -260,7 +304,6 @@ public function cmi5launch_retrieve_token($audience, $tenantid) { $username = $settings['cmi5launchbasicname']; $playerurl = $settings['cmi5launchplayerurl']; $password = $settings['cmi5launchbasepass']; - global $CFG; // Build URL for launch URL request. $url = $playerurl . "/api/v1/auth"; @@ -279,15 +322,23 @@ public function cmi5launch_retrieve_token($audience, $tenantid) { $result = $this->cmi5launch_send_request_to_cmi5_player_post('cmi5launch_stream_and_send', $data, $url, $filetype, $username, $password); // Check result and display message if not 200. - $resulttest = $this->cmi5launch_connectors_error_message($result, "retrieving the token"); + $resulttest = $this->cmi5launch_connectors_error_message($result, 'retrieving the tenant token.'); - if ($resulttest == true) { - $resultDecoded = json_decode($result, true); - $token = $resultDecoded['token']; + // Now this will never return false, it will throw an exception if it fails, so we can just return the result + try { + if ($resulttest == true) { - return $token; - } else { - return false; + $resultDecoded = json_decode($result, true); + $token = $resultDecoded['token']; + + return $token; + + } else { + throw new playerException("retrieving the tenant token."); + } + }// catch all else that might go wrong + catch (\Throwable $e){ + throw new playerException("Uncaught error retrieving the tenant token." . $e); } } @@ -340,18 +391,24 @@ public function cmi5launch_retrieve_url($id, $auindex) { $result = $this->cmi5launch_send_request_to_cmi5_player_post('cmi5launch_stream_and_send', $data, $url, $filetype, $token); // Check result and display message if not 200. - $resulttest = $this->cmi5launch_connectors_error_message($result, "retrieving launch url"); + $resulttest = $this->cmi5launch_connectors_error_message($result, "retrieving the launch url from player."); - // Catch errors. + // Now this will never return false, it will throw an exception if it fails, so we can just return the result + try { if ($resulttest == true) { - // Only return the URL. $urldecoded = json_decode($result, true); return $urldecoded; } else { - return false; + throw new playerException("retrieving the launch url from player."); } + }// catch all else that might go wrong + catch (\Throwable $e){ + throw new playerException("Uncaught error retrieving the launch url from player." . $e); + } + + } /** @@ -364,72 +421,96 @@ public function cmi5launch_retrieve_url($id, $auindex) { */ public function cmi5launch_send_request_to_cmi5_player_post($cmi5launch_stream_and_send, $databody, $url, $filetype, ...$tokenorpassword) { - // Assign passed in function to variable. - $stream = $cmi5launch_stream_and_send; - // Determine content type to be used in header. - // It is also the same as accepted type. - $contenttype = $filetype; - if ($contenttype == "zip") { - $contenttype = "application/zip\r\n"; - } else if ("json") { - $contenttype = "application/json\r\n"; - } - - // If number of args is greater than one it is for retrieving tenant info and args are username and password. - if (count($tokenorpassword) == 2 ) { + // Set error and exception handler to catch and override the default PHP error messages, to make messages more user friendly. + set_error_handler('mod_cmi5launch\local\sifting_data_warning', E_WARNING); + set_exception_handler('mod_cmi5launch\local\exception_au'); + + try { + + // I rhink this whole thing should be try catch cause there are several things that cango w + // Assign passed in function to variable. + $stream = $cmi5launch_stream_and_send; + // Determine content type to be used in header. + // It is also the same as accepted type. + $contenttype = $filetype; + if ($contenttype == "zip") { + $contenttype = "application/zip\r\n"; + } else if ("json") { + $contenttype = "application/json\r\n"; + } + + // If number of args is greater than one it is for retrieving tenant info and args are username and password. + if (count($tokenorpassword) == 2) { + + $username = $tokenorpassword[0]; + $password = $tokenorpassword[1]; + + + // Use key 'http' even if you send the request to https://... + // There can be multiple headers but as an array under the ONE header. + // Content(body) must be JSON encoded here, as that is what CMI5 player accepts. + $options = array( + 'http' => array( + 'method' => 'POST', + 'header' => array( + 'Authorization: Basic ' . base64_encode("$username:$password"), + "Content-Type: " . $contenttype . + "Accept: " . $contenttype + ), + 'content' => ($databody), + ), + ); + + //By calling the function this way, it enables encapsulation of the function and allows for testing. + //It is an extra step, but necessary for required PHP Unit testing. + $result = call_user_func($stream, $options, $url); + + + // Else the args are what we need for posting a course. + } else { + + // First arg will be token. + $token = $tokenorpassword[0]; + + // Use key 'http' even if you send the request to https://... + // There can be multiple headers but as an array under the ONE header + // content(body) must be JSON encoded here, as that is what CMI5 player accepts + // JSON_UNESCAPED_SLASHES used so http addresses are displayed correctly. + $options = array( + 'http' => array( + 'method' => 'POST', + 'ignore_errors' => true, + 'header' => array( + "Authorization: Bearer " . $token, + "Content-Type: " . $contenttype . + "Accept: " . $contenttype + ), + 'content' => ($databody), + ), + ); + + + //By calling the function this way, it enables encapsulation of the function and allows for testing. + //It is an extra step, but necessary for required PHP Unit testing. + $result = call_user_func($stream, $options, $url); + + // Ok, calling it throuw the third party isn't workin, what if we mock call_user_func instead and have an eror thrown there + } + + + // Restore default hadlers. + restore_exception_handler(); + restore_error_handler(); + + // Return response. + return $result; - $username = $tokenorpassword[0]; - $password = $tokenorpassword[1]; + }catch(\Throwable $e) { + // + throw new playerException("communicating with player, sending or crafting a POST request: " . $e); + } - // Use key 'http' even if you send the request to https://... - // There can be multiple headers but as an array under the ONE header. - // Content(body) must be JSON encoded here, as that is what CMI5 player accepts. - $options = array( - 'http' => array( - 'method' => 'POST', - 'header' => array('Authorization: Basic '. base64_encode("$username:$password"), - "Content-Type: " .$contenttype . - "Accept: " . $contenttype), - 'content' => ($databody), - ), - ); - - //By calling the function this way, it enables encapsulation of the function and allows for testing. - //It is an extra step, but necessary for required PHP Unit testing. - $result = call_user_func($stream, $options, $url); - - - // Else the args are what we need for posting a course. - } else { - - // First arg will be token. - $token = $tokenorpassword[0]; - - // Use key 'http' even if you send the request to https://... - // There can be multiple headers but as an array under the ONE header - // content(body) must be JSON encoded here, as that is what CMI5 player accepts - // JSON_UNESCAPED_SLASHES used so http addresses are displayed correctly. - $options = array( - 'http' => array( - 'method' => 'POST', - 'ignore_errors' => true, - 'header' => array("Authorization: Bearer ". $token, - "Content-Type: " .$contenttype . - "Accept: " . $contenttype), - 'content' => ($databody), - ), - ); - - - //By calling the function this way, it enables encapsulation of the function and allows for testing. - //It is an extra step, but necessary for required PHP Unit testing. - $result = call_user_func($stream, $options, $url); - - } - - // Return response. - return $result; } /** @@ -455,21 +536,18 @@ public function cmi5launch_send_request_to_cmi5_player_get($cmi5launch_stream_an ), ); - //$helper = new cmi5launch_helpers; - // $stream = cmi5launch_stream_and_send(); - // Sends the stream to the specified URL and stores results. - // The false is use_include_path, which we dont want in this case, we want to go to the url. - //$launchresponse = cmi5launch_stream_and_send( $options, $url ); - + try { //By calling the function this way, it enables encapsulation of the function and allows for testing. //It is an extra step, but necessary for required PHP Unit testing. $result = call_user_func($stream, $options, $url); - - - $sessiondecoded = json_decode($result, true); - // Return response. - return $sessiondecoded; + // Return response. + return $result; + + } catch (\Throwable $e) { + // echo" are we here?"; + throw new playerException("communicating with player, sending or crafting a GET request: " . $e); + } } /** @@ -494,13 +572,21 @@ public function cmi5launch_retrieve_session_info_from_player($sessionid, $id) { $result = $this->cmi5launch_send_request_to_cmi5_player_get('cmi5launch_stream_and_send', $token, $url); // Check result and display message if not 200. - $resulttest = $this->cmi5launch_connectors_error_message($result, "retrieving session info"); + $resulttest = $this->cmi5launch_connectors_error_message($result, "retrieving the session information."); - if ($resulttest == true) { + // Now this will never return false, it will throw an exception if it fails, so we can just return the result + try { + if ($resulttest == true) { - return $result; - } else { - return false; + return $result; + + } else { + throw new playerException("retrieving the session information."); + } + }// catch all else that might go wrong + catch (\Throwable $e){ + + throw new playerException("Uncaught error retrieving the session information." . $e); } } @@ -513,8 +599,9 @@ public function cmi5launch_retrieve_session_info_from_player($sessionid, $id) { * @param string $type - The type missing to be added to the error message. * @return bool */ - public static function cmi5launch_connectors_error_message($resulttotest, $type) { - + public function cmi5launch_connectors_error_message($resulttotest, $type) { + + // Decode result because if it is not 200 then something went wrong // If it's a string, decode it. if (is_string($resulttotest)) { @@ -527,26 +614,24 @@ public static function cmi5launch_connectors_error_message($resulttotest, $type) // Player cannot return an error if not runnin, if ($resulttest === false ){ - echo "
"; - - echo "Something went wrong " . $type . ". CMI5 Player is not communicating. Is it running?"; - - echo "
"; + + $errormessage = $type . ". CMI5 Player is not communicating. Is it running?"; - return false; + throw new playerException($errormessage); } else if( array_key_exists("statusCode", $resulttest) && $resulttest["statusCode"] != 200) { - echo "
"; + + $errormessage = $type . " CMI5 Player returned " . $resulttest["statusCode"] . " error. With message '" + . $resulttest["message"] . "'." ; - echo "Something went wrong " . $type . ". CMI5 Player returned " . $resulttest["statusCode"] . " error. With message '" - . $resulttest["message"] . "'." ; - echo "
"; - - return false; + // echo"whatt is error messae before throwing::: " . $errormessage; + // echo" what is error messae: " . $errormessage;""; + throw new playerException($errormessage); + } else { - - // No errors, continue. + // No errors, continue. + return true; } } diff --git a/classes/local/course.php b/classes/local/course.php old mode 100755 new mode 100644 diff --git a/classes/local/errorover.php b/classes/local/errorover.php new file mode 100644 index 0000000..5e60a27 --- /dev/null +++ b/classes/local/errorover.php @@ -0,0 +1,199 @@ +. + +/** + * Lets see if this works. making an ovrride error class, or several + * + * @copyright 2023 Megan Bohland + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_cmi5launch\local; + +/** + * An exception handler to use in AU cases when many different exceptions for data errors may be thrown. + * @param mixed $errno + * @param mixed $errstr + * @param mixed $errfile + * @param mixed $errline + * @throws \mod_cmi5launch\local\nullException + * @return never + */ +function exception_au(\Throwable $exception) +{ + // echo"Error stirn --- $errstr"; + // echo"Error number --- $errno"; + echo " EHAT?"; + // Maybe we can construct the new errors here. This would allow the error personalization? And keep main code clean + + throw new fieldException('Error OVER: ' . $exception->getMessage(), 0); + // exit; +} + function array_chunk_warning($errno, $errstr, $errfile, $errline) + { + // echo"Error stirn --- $errstr"; + // echo"Error number --- $errno"; + + // Maybe we can construct the new errors here. This would allow the error personalization? And keep main code clean + + throw new nullException('Cannot parse array. Error: ' . $errstr, 0); + // exit; + } + + /// Ok, this i a different error handler + function sifting_data_warning($errno, $errstr, $errfile, $errline) + { + // echo"Error stirn --- $errstr"; + // echo"Error number --- $errno"; +//echo"Error errfile --- $errfile"; + // echo"Error errline --- $errline"; + // Maybe we can construct the new errors here. This would allow the error personalization? And keep main code clean + + throw new fieldException('Error: ' . $errstr, 0); + // exit; + } + +/** + * Define a custom exception class, this will make pour tests meaningful + * from php webpage: "Custom exception classes can allow you to write tests that prove your exceptions + * are meaningful. Usually testing exceptions, you either assert the message equals +*something in which case you can't change the message format without refactoring, +*or not make any assertions at all in which case you can get misleading messages +*later down the line. Especially if your $e->getMessage is something complicated +*like a var_dump'ed context array." + */ +class nullException extends \Exception +{ + // Redefine the exception so message isn't optional + public function __construct($message, $code = 0, Throwable $previous = null) { + // some code + + // make sure everything is assigned properly + parent::__construct($message, $code, $previous); + } + + // custom string representation of object (what is returned with echo) + public function __toString(): string { + return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; + } + + public function customFunction() { + echo "A custom function for this type of exception\n"; + } +} +/** + * Define a custom exception class, this will make pour tests meaningful + * from php webpage: "Custom exception classes can allow you to write tests that prove your exceptions + * are meaningful. Usually testing exceptions, you either assert the message equals +*something in which case you can't change the message format without refactoring, +*or not make any assertions at all in which case you can get misleading messages +*later down the line. Especially if your $e->getMessage is something complicated +*like a var_dump'ed context array." + */ +class missingException extends \Exception +{ + // Redefine the exception so message isn't optional + // I want an exception that takkkes what is missing and adds it to messsssage? + // Is this possivlbe? + public function __construct($message, $code = 0, Throwable $previous = null) { + // some code + + // make sure everything is assigned properly + parent::__construct($message, $code, $previous); + } + + + // custom string representation of object (what is returned with echo) + public function __toString(): string { + return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; + // maybe here? + } + + public function customFunction() { + echo " This error to string :"; + // $this->getTraceAsString(); + } +} +/** + * Define a custom exception class, this will make pour tests meaningful + * from php webpage: "Custom exception classes can allow you to write tests that prove your exceptions + * are meaningful. Usually testing exceptions, you either assert the message equals +*something in which case you can't change the message format without refactoring, +*or not make any assertions at all in which case you can get misleading messages +*later down the line. Especially if your $e->getMessage is something complicated +*like a var_dump'ed context array." + */ +class fieldException extends \Exception +{ + // Redefine the exception so message isn't optional + // I want an exception that takkkes what is missing and adds it to messsssage? + // Is this possivlbe? + public function __construct($message, $code = 0, Throwable $previous = null) { + // some code + + // make sure everything is assigned properly + parent::__construct($message, $code, $previous); + } + + + // custom string representation of object (what is returned with echo) + public function __toString(): string { + return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; + // maybe here? + } + + public function customFunction() { + echo " This error to string :"; + // $this->getTraceAsString(); + } +} +/** + * Define a custom exception class, this will make pour tests meaningful + * from php webpage: "Custom exception classes can allow you to write tests that prove your exceptions + * are meaningful. Usually testing exceptions, you either assert the message equals +*something in which case you can't change the message format without refactoring, +*or not make any assertions at all in which case you can get misleading messages +*later down the line. Especially if your $e->getMessage is something complicated +*like a var_dump'ed context array." + */ +class playerException extends \Exception +{ + // Redefine the exception so message isn't optional + // I want an exception that takkkes what is missing and adds it to messsssage? + // Is this possivlbe? + public function __construct($message, $code = 0, Throwable $previous = null) { + // some code + + // Ah maybe here is where I can differentiate them + $playermessage = "Player communication error. Something went wrong " . $message; + // make sure everything is assigned properly + parent::__construct($playermessage, $code, $previous); + } + + + // custom string representation of object (what is returned with echo) + public function __toString(): string { + return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; + // maybe here? + } + + public function customFunction() { + echo " This error to string :"; + // $this->getTraceAsString(); + } +} + +// If all my exceptions are the same, just diff names, are they necessary? Do any of my try/catches really differentiate? \ No newline at end of file diff --git a/classes/local/grade_helpers.php b/classes/local/grade_helpers.php old mode 100755 new mode 100644 index 818fc57..fe78c85 --- a/classes/local/grade_helpers.php +++ b/classes/local/grade_helpers.php @@ -202,10 +202,10 @@ public function cmi5launch_check_user_grades_for_updates($user) { switch ($gradetype) { - // MOD_CMI5LAUNCH_AUS_GRADE = 0. - // MOD_CMI5LAUNCH_GRADE_HIGHEST = 1. - // MOD_CMI5LAUNCH_GRADE_AVERAGE = 2. - // MOD_CMI5LAUNCH_GRADE_SUM = 3. + // GRADE_AUS_CMI5 = 0. + // GRADE_HIGHEST_CMI5 = 1. + // GRADE_AVERAGE_CMI5 = 2. + // GRADE_SUM_CMI5 = 3. case 1: $aurecord->grade = $this->cmi5launch_highest_grade($sessiongrades); diff --git a/classes/local/progress.php b/classes/local/progress.php old mode 100755 new mode 100644 diff --git a/classes/local/session.php b/classes/local/session.php old mode 100755 new mode 100644 index 58fefb7..283c2ee --- a/classes/local/session.php +++ b/classes/local/session.php @@ -44,7 +44,6 @@ public function __construct($statement) { foreach ($statement as $key => $value) { - $this->$key = ($value); } diff --git a/classes/local/session_helpers.php b/classes/local/session_helpers.php old mode 100755 new mode 100644 diff --git a/cmi5PHP/tests/auTest.php b/cmi5PHP/tests/auTest.php old mode 100755 new mode 100644 index 3292a92..7d36302 --- a/cmi5PHP/tests/auTest.php +++ b/cmi5PHP/tests/auTest.php @@ -1,6 +1,7 @@ auProperties = array( + $this->auproperties = array( 'id', 'attempt', 'url', @@ -54,10 +55,10 @@ protected function setUp(): void 'userid' ); - $this->emptyStatement = array(); + $this->emptystatement = array(); - // Perhaps a good test would be to test the constructor with a statement that has all the properties set. - $this->mockStatementValues = array( + // A good test would be to test the constructor with a statement that has all the properties set. + $this->mockstatementvalues = array( 'id' => 'id', 'attempt' => 'attempt', 'url' => 'url', @@ -105,16 +106,15 @@ protected function tearDown(): void */ public function testInstantiationWithEmpty() { - $obj = new au($this->emptyStatement); + // Make an AU object with no values. + $obj = new au($this->emptystatement); - // Is an AU object? + // Assert its an AU object. $this->assertInstanceOf(au::class, $obj); - //It is saying AU is not transversable - //Implementing traversable in AU is breaking the code, - //Make sure the AU object does not have any 'extra' properties, only the amount passed in - $expectedAmount = count($this->auProperties); - //could typecasting the object as an array help? dirty fix + // It is saying AU is not transversable. Implementing traversable in AU is breaking the code, typecast the object as array for dirty fix. + // Make sure the AU object does not have any 'extra' properties, only the amount passed in + $expectedAmount = count($this->auproperties); $auArray = (array) $obj; $this->assertCount($expectedAmount, $auArray, "AU has $expectedAmount properties"); @@ -124,7 +124,6 @@ public function testInstantiationWithEmpty() $this->assertArrayHasKey($property, $auArray, "$property exists"); $this->assertNull($value, "$property empty"); } - } /** @@ -132,19 +131,16 @@ public function testInstantiationWithEmpty() * Should instantiate an AU object with values. * @return void */ - public function testInstantiationWithValues() { - $obj = new au($this->mockStatementValues); + $obj = new au($this->mockstatementvalues); - // Is an AU object? + // Assert it's an AU object? $this->assertInstanceOf(au::class, $obj); - - //It is saying AU is not transversable - //Implementing traversable in AU is breaking the code, - //Make sure the AU object does not have any 'extra' properties, only the amount passed in - $expectedAmount = count($this->auProperties); - //could typecasting the object as an array help? dirty fix + + // It is saying AU is not transversable. Implementing traversable in AU is breaking the code, typecast the object as array for dirty fix. + // Make sure the AU object does not have any 'extra' properties, only the amount passed in + $expectedAmount = count($this->auproperties); $auArray = (array) $obj; $this->assertCount($expectedAmount, $auArray, "AU has $expectedAmount properties"); @@ -155,4 +151,41 @@ public function testInstantiationWithValues() $this->assertEquals($property, $value, "$value does not equal $property"); } } + + /** + * Test of AU constructor class exceptions. This one tests if statement is null. + * @return void + */ + public function testInstantiation_except_null() + { + // Null statement to send and trigger exception. + $nullstatement = null; + + // Expected message + // Catch the exception. + $this->expectException(nullException::class); + $this->expectExceptionMessage("Statement to build AU is null or not an array/object." ); + + $obj = new au($nullstatement); + + } + + /** + * Test of AU constructor class exceptions. This one tests if statement passed in is not an array. + * @return void + */ + public function testInstantiation_except_nonarray() + { + // Null statement to send and trigger exception. + $nullstatement = "string"; + + // Catch the exception. + $this->expectException(nullException::class); + $this->expectExceptionMessage("Statement to build AU is null or not an array/object." ); + + $obj = new au($nullstatement); + + } + + } \ No newline at end of file diff --git a/cmi5PHP/tests/ausHelpersTest.php b/cmi5PHP/tests/ausHelpersTest.php old mode 100755 new mode 100644 index 9e3bdd7..3d4584e --- a/cmi5PHP/tests/ausHelpersTest.php +++ b/cmi5PHP/tests/ausHelpersTest.php @@ -1,6 +1,8 @@ auProperties = array( - 'id', - 'attempt', - 'url', - 'type', - 'lmsid', - 'grade', - 'scores', - 'title', - 'moveon', - 'auindex', - 'parents', - 'objectives', - 'description', - 'activitytype', - 'launchmethod', - 'masteryscore', - 'satisfied', - 'launchurl', - 'sessions', - 'progress', - 'noattempt', - 'completed', - 'passed', - 'inprogress', - ); - - $this->emptyStatement = array(); - // Based on created AU in program, but with some values removed. + // Based on created AU in program. $this->mockStatement2 = array( "id" => "https://exampleau", "attempt" => NULL, @@ -63,9 +36,68 @@ protected function setUp(): void "title" => array( 0 => array( "lang" => "en-US", "text" => "Example AU") + ), + "parents" => array(), + "objectives" => NULL, + "description" => array( 0 => array( + "lang" => "en-US", + "text" => "Example AU lesson description") ), - "moveOn"=> NULL, - "auIndex" => NULL, + 'satisfied' => NULL, + 'sessions' => NULL, + 'progress' => NULL, + 'noattempt' => NULL, + 'completed' => NULL, + 'passed' => NULL, + 'inprogress' => NULL, + 'launchMethod' => "AnyWindow", + 'lmsId' => "https://exampleau/ranomnum/au0", + 'moveOn' => "CompletedOrPassed", + 'auIndex' => 0, + 'activityType' => NULL, + 'masteryScore' => NULL + ); + + // Based on created AU in program, but with some values changed. + // For instance title is an empty array + $this->mockStatementExcept = array( + "id" => "https://exampleau", + "attempt" => NULL, + "url" => "example.html?pages=1&complete=launch", + "type" => "au example", + "grade" => NULL, + "scores" => NULL, + "title" => array() + , + "parents" => array(), + "objectives" => NULL, + "description" => array( 0 => array( + "lang" => "en-US", + "text" => "Example AU lesson description") + ), + 'satisfied' => NULL, + 'sessions' => NULL, + 'progress' => NULL, + 'noattempt' => NULL, + 'completed' => NULL, + 'passed' => NULL, + 'inprogress' => NULL, + 'launchMethod' => "AnyWindow", + 'lmsId' => "https://exampleau/ranomnum/au0", + 'auIndex' => 0, + 'activityType' => NULL, + 'masteryScore' => NULL + ); + // Based on created AU in program, but with some values changed. Here title is a string. + $this->mockStatementExcept2 = array( + "id" => "https://exampleau", + "attempt" => NULL, + "url" => "example.html?pages=1&complete=launch", + "type" => "au example", + "lmsid" => NULL, + "grade" => NULL, + "scores" => NULL, + "title" => array( "title "), "parents" => array(), "objectives" => NULL, "description" => array( 0 => array( @@ -76,7 +108,6 @@ protected function setUp(): void 'launchmethod' => NULL, 'masteryscore' => NULL, 'satisfied' => NULL, - 'launchurl' => NULL, 'sessions' => NULL, 'progress' => NULL, 'noattempt' => NULL, @@ -91,7 +122,7 @@ protected function setUp(): void 'masteryScore' => NULL ); // Perhaps a good test would be to test the constructor with a statement that has all the properties set. - $this->mockStatementValues = array( + $this->mockstatementvalues = array( 'id' => 'id', 'attempt' => 'attempt', 'url' => 'url', @@ -117,7 +148,6 @@ protected function setUp(): void 'passed' => 'passed', 'inprogress' => 'inprogress', ); - } protected function tearDown(): void @@ -126,14 +156,11 @@ protected function tearDown(): void } - // Retrieve Aus parses and returns AUs from large statements from the CMI5 player - // So to test, maybe make a statement and ensure the test value is returned? - // Arbitrarily pick a word and put in right place? See if it is returned? + // Retrieve Aus parses and returns AUs from large statements from the CMI5 player. + // So to test, we will make a statement and ensure the test value is returned. public function testcmi5launch_retrieve_aus() { - //It's not just returning it, it's splitting it into chuncks~! - - //Fake values to return + // Fake values to return. $mockStatement = array( "createdAt" => "2023-06-26T18:36:15.000Z", "id"=> 000, @@ -186,9 +213,10 @@ public function testcmi5launch_retrieve_aus() ) ); - //This is the value that should be returned, basically, an array holding all the aus separately - $shouldBeReturned = array ( - //First au, nestled in array + // This is the value that should be returned, basically, an array holding all the aus separately. + $shouldbereturned = array ( + + //First au, nestled in array. 0 => array ( 0 => array ( "activityType" => null, @@ -212,7 +240,7 @@ public function testcmi5launch_retrieve_aus() "url" => "index.html?pages=1&complete=launch", ) ), - //second au nestled in array + // Second au nestled in array. 1 => array ( 0 => array ( "activityType" => null, @@ -236,59 +264,150 @@ public function testcmi5launch_retrieve_aus() "url"=> "index.html?pages=2&complete=launch" ), ) - ); $helper = new au_helpers(); - //So now with this fake 'statement', lets ensure it pulls the correct value which is "correct Retrieval" + + // So now with this fake 'statement', lets ensure it pulls the correct value which is "correct retrieval". $retrieved = $helper->cmi5launch_retrieve_aus($mockStatement); - // It should retrieve the mock aus - $this->assertEquals($shouldBeReturned, $retrieved, "Expected retrieved statement to be equal to mock statement"); - //This is being flaged as risky? - //Is there a different way to test this? - //Maybe we 'expect' two properties since 2 aus were passed in? - //I mean we aren't testing 'chunked?' so....? + $this->assertEquals($shouldbereturned, $retrieved, "Expected retrieved statement to be equal to mock statement"); - //It DOES return as array + // It returns as array. $this->assertIsArray($retrieved, "Expected retrieved statement to be an array"); - //And it returns two in array? Since we passed in two? + // And it returns two in array? $this->assertCount(2, $retrieved, "Expected retrieved statement to have two aus"); - //TODO MB - //Those seem to pass, so take away line 206? } - //Test function that is fed an array of statments and returns an array of aus onjects + //Lets try testing so it throws excrption if thhe array doesn't have the right keys + + // We cannot test 'caught' exception because it is thrown by the overriden error handler, not the SUT. + // To test the exception we need to test the right output (from the exception) is generated, + public function testcmi5launch_retrieve_aus_exception() + { + // Note this is an incorrect statement, cut off before 'aus'. + $mockStatement = array( + "createdAt" => "2023-06-26T18:36:15.000Z", + "id"=> 000, + "lmsId"=> "https://example", + "metadata" => array( + )); + + // This is the expected output message. + $expectedMessage = "Cannot retrieve AUs. Error found when trying to parse them from course creation: " . + "Please check the connection to player or course format and try again. \n" + . 'Cannot parse array. Error: Undefined array key "aus"' . "\n"; + $helper = new au_helpers(); + + // Call function under test. + $retrieved = $helper->cmi5launch_retrieve_aus($mockStatement); + + // If the right message is displayed the try/catch wworked! + $this->expectOutputString($expectedMessage); + } + + + // Test function that is fed an array of statments and returns an array of aus objects. public function testcmi5launch_create_aus() { - // Should be enough to pass the mock statement values here, make an array of them first - $testStatements = array(); + // Should be enough to pass the mock statement values here, make an array of them first. + $teststatements = array(); - //Lets create 4 aus statement + //Lets create 4 aus statement. for ($i = 0; $i < 4; $i++) { - $testStatements[$i][] = $this->mockStatementValues; + $teststatements[$i][] = $this->mockstatementvalues; } $helper = new au_helpers(); - //So now with this fake 'statement', lets ensure it pulls the correct value which is "correct Retrieval" - $auList = $helper->cmi5launch_create_aus($testStatements); + // So now with this fake 'statement', lets ensure it pulls the correct value which is "correct Retrieval" + $auList = $helper->cmi5launch_create_aus($teststatements); - //There should be a total of 4 Aus in this array + // There should be a total of 4 Aus in this array. $this->assertCount(4, $auList, "Expected retrieved statement to have four aus"); - //And they should all be au objects + // And they should all be au objects. foreach ($auList as $au) { $this->assertInstanceOf(au::class, $au, "Expected retrieved statement to be an array of aus"); } } - //This one is going to be tricky, it saves to a DB! I know test php can have TEST DBs, but is that setup here? - //And how to freaking test THAT? - //Well, actually we don't need to test it goes to the DB, THAT was the job of the person who invented insert_record - //We just need tothat it saves the correct values and CALLS insert_record - //Technically this function returns ids, so we can make a stub which just returns ids - //This will test it is called without messing with the DB - public function testcmi5launch_save_aus() + // Test function creat aus null exception. + public function testcmi5launch_create_aus_exception() + { + + // If we pass a null value in, it should throw an exception immedietely + $teststatements = null; + + $this->expectException(nullException::class); + $this->expectExceptionMessage('Cannot retrieve AU information. AU statements from DB are: ' . null); + + $helper = new au_helpers(); + + // Pass null to SUT. + $helper->cmi5launch_create_aus($teststatements); + } + + + + // test saving aus with exceptions. + public function testcmi5launch_save_aus_exceptions() + { + // Make a global variable to hold the id's to pretend to be cmi5launch instance id. + global $cmi5launch; + + $cmi5launch = new \stdClass(); + $cmi5launch->id = 1; + + // The func should return auids created by the DB when AU's were saved in array format. + $helper = new au_helpers(); + + + // Pass in a statement with something wrong. This one has a null title. + $testAus[0][] = $this->mockStatementExcept; + + // Because this exception is thrown by the error handler, not the SUT, test the output to ensure right exception was thrown. + $expected = "Cannot save to DB. Stopped at record with ID number " . 1 . "." + . " One of the fields is incorrect. Check data for field 'title'. Error: Undefined array key 0\n"; + + // Call function under test. + $returnedAUids = $helper->cmi5launch_save_aus($helper->cmi5launch_create_aus($testAus)); + // If the right message is displayed the try/catch wworked! + $this->expectOutputString($expected); + } + + + // Test saving aus with exceptions, a different exception. + public function testcmi5launch_save_aus_exceptions_2() + { + // Make a global variable to hold the id's to pretend to be cmi5launch instance id. + global $cmi5launch; + + $cmi5launch = new \stdClass(); + $cmi5launch->id = 1; + + // The func should return auids created by the DB when AU's were saved in array format. + $helper = new au_helpers(); + + // This first statement is correct. We want to test that it gets the SECOND statement number, + $testAus[0][] = $this->mockStatement2; + // This one has 'title' as string instead of array. + $testAus[1][] = $this->mockStatementExcept2; + + // The expected is built by the two messages knowing 'title' is a string. + $expected = "Cannot save to DB. Stopped at record with ID number " . 2 . "." + . " One of the fields is incorrect. Check data for field 'title'. Cannot access offset of type string on string\n"; + + // Call the function to throw the exception. + $returnedAUids = $helper->cmi5launch_save_aus($helper->cmi5launch_create_aus($testAus)); + + // Because this exception is thrown by the error handler, not the SUT, test the output to ensure right exception was thrown. + $this->expectOutputString($expected); + + } + + + // Test saving aus with exceptions, a (null) exception. + public function testcmi5launch_save_aus_exceptions_test_null() { // Make a global variable to hold the id's to pretend to be cmi5launch instance id. @@ -296,7 +415,33 @@ public function testcmi5launch_save_aus() $cmi5launch = new \stdClass(); $cmi5launch->id = 1; - // $cmi5launch->id = 1; + + $helper = new au_helpers(); + + // A test statement with a null value. + $testAus = null; + + // Catch the exception. + $this->expectException(nullException::class); + $this->expectExceptionMessage('Cannot save AU information. AU object array is: null' . null); + + // The expected is built bby the two messages knowing 'title' is an empty array. + $expected = "Cannot save to DB. Stopped at record with ID number " . 1 . "." + . " One of the fields is incorrect. Check data for field 'title'. Error: Undefined array key 0\n"; + //So now with this fake 'statement', lets ensure it pulls the correct value which is "correct Retrieval" + $returnedAUids = $helper->cmi5launch_save_aus($testAus); + + } + + // Test saving aus, this function returns ids, so we can make a stub which just returns ids. + // This will test it is called without messing with the DB. + public function testcmi5launch_save_aus() + { + // Make a global variable to hold the id's to pretend to be cmi5launch instance id. + global $cmi5launch, $auidForTest; + + $cmi5launch = new \stdClass(); + $cmi5launch->id = 1; // The func should return auids created by the DB when AU's were saved in array format. $helper = new au_helpers(); @@ -304,8 +449,6 @@ public function testcmi5launch_save_aus() //Lets create 4 aus statement for ($i = 0; $i < 3; $i++) { $testAus[$i][] = $this->mockStatement2; - // $testAus[$i][] = ($this->$cmi5launch); - // $testAus = array_merge($testAus, $cmi5launch); } //So now with this fake 'statement', lets ensure it pulls the correct value which is "correct Retrieval" @@ -316,46 +459,63 @@ public function testcmi5launch_save_aus() // The array should have the same count of ids as AU's passed in $this->assertCount(3, $returnedAUids, "Expected retrieved statement to have three aus"); + // Now iterate through the returned array and ensure ids were passed back, numeric ids foreach ($returnedAUids as $auId) { - // what is id? - // echo"auId: $auId"; $this->assertIsNumeric($auId, "Expected array to have numeric values"); } - global $auidForTest; - //Save to use in next test? - $auidForTest = $returnedAUids; - //Do I need to test fail? + // Is this not savin? + // echo "Returned AU ids: " . var_dump($returnedAUids) . "\n"; - } - + $auidForTest = $returnedAUids; + } + // Test retrieving an AU from the DB with a correct value. public function testcmi5launch_retrieve_aus_from_db() { - // Access the global array of ids from above test + // ok, what if we saved ere the retrieved + // Access the global array of ids from above test global $auidForTest; // global $auidForTest; $helper = new au_helpers(); + // Save new aus to db to pull. + //Lets create 4 aus statement + for ($i = 0; $i < 3; $i++) { + $testAus[$i][] = $this->mockStatement2; + } + + //So now with this fake 'statement', lets ensure it pulls the correct value which is "correct Retrieval" + $returnedAUids = $helper->cmi5launch_save_aus($helper->cmi5launch_create_aus($testAus)); + + //and what is here? + // echo"au id for test: " . var_dump($auidForTest) . "\n"; // It takes singular ids, so we will iterate through them - foreach ($auidForTest as $auId) { + foreach ($returnedAUids as $auId) { $returnedAu = $helper->cmi5launch_retrieve_aus_from_db($auId); // And the return should be an au object $this->assertInstanceOf(au::class, $returnedAu, "Expected retrieved object to be an au object"); } + } + - // And if it fails it should fail gracefully + // Test retrieving an AU from the DB with a null value and thrown exception. + public function testcmi5launch_retrieve_aus_from_db_null_exception() + { + $helper = new au_helpers(); + + // And if it fails it should fail gracefully, throwin the correct exception. $badid = 0; + + // Catch the exception. + $this->expectException(nullException::class); + $this->expectExceptionMessage("Error attempting to get AU data from DB. Check AU id. AU id is: " . $badid ."

" . null); + $returnedAu = $helper->cmi5launch_retrieve_aus_from_db($badid); - - // And the return should be a false value - $this->assertNotTrue($returnedAu, "Expected retrieved object to be false"); - //And it should output this error message - $this->expectOutputString("

Error attempting to get AU data from DB. Check AU id. AU id is: " . $badid . "

"); } } \ No newline at end of file diff --git a/cmi5PHP/tests/cmi5TestHelpers.php b/cmi5PHP/tests/cmi5TestHelpers.php old mode 100755 new mode 100644 index db477f5..5db6485 --- a/cmi5PHP/tests/cmi5TestHelpers.php +++ b/cmi5PHP/tests/cmi5TestHelpers.php @@ -532,5 +532,11 @@ function cmi5launch_test_stream_and_send_fail($options, $url) // Lets pass in the 'return' value as the option. return $errormessage; } + // should I have it throw an error? would that work, or would that take the erorr out of SUT? + // So now all the test has to do is inject THIS which will return as we please + function cmi5launch_test_stream_and_send_excep($options, $url) + { + throw new \Exception('test error'); + } ?> diff --git a/cmi5PHP/tests/cmi5_connectorsTest.php b/cmi5PHP/tests/cmi5_connectorsTest.php index e0d28d3..0028976 100755 --- a/cmi5PHP/tests/cmi5_connectorsTest.php +++ b/cmi5PHP/tests/cmi5_connectorsTest.php @@ -5,6 +5,8 @@ use PHPUnit\Framework\TestCase; use mod_cmi5launch\local\cmi5_connectors; use mod_cmi5launch\test\cmi5TestHelpers; +use mod_cmi5launch\local\playerException; + require_once( "cmi5TestHelpers.php"); /** @@ -33,7 +35,7 @@ public static function setUpBeforeClass(): void { global $DB, $cmi5launch, $cmi5launchid; - // Mke a fake cmi5 launch record. + // Make a fake cmi5 launch record. $cmi5launchid = maketestcmi5launch(); } @@ -51,7 +53,8 @@ protected function setUp(): void { global $DB, $cmi5launch, $cmi5launchid, $USER, $testcourseid, $cmi5launchsettings; - $cmi5launchsettings = array("cmi5launchtenanttoken" => "Testtoken", "cmi5launchplayerurl" => "http://test/launch.php", "cmi5launchcustomacchp" => "http://testhomepage.com"); + $cmi5launchsettings = array("cmi5launchtenanttoken" => "Testtoken", "cmi5launchplayerurl" => "http://test/launch.php", "cmi5launchcustomacchp" => "http://testhomepage.com", + "cmi5launchbasicname" => 'testname', "cmi5launchbasepass" => "testpassword"); // Override global variable and function so that it returns test data. @@ -129,9 +132,8 @@ public function testcmi5launch_create_course_fail_with_message() // Function that will be called in function under test. $testfunction = 'cmi5launch_stream_and_send'; - // Message we expect to be output. - $expectedstring= "
Something went wrong creating the course. CMI5 Player returned 404 error. With message 'testmessage'.
"; - // Arguments to be passed to the method under test. + + // Arguments to be passed to the method under test. $id = 0; $tenanttoken = "testtoken"; // Error message for stubbed method to return. @@ -143,7 +145,10 @@ public function get_content() { return "testfilecontents"; } }; - + $test = false; + // Expected exceptions + $exceptionmessage = "Player communication error. Something went wrong creating the course. CMI5 Player returned 404 error. With message 'testmessage'." ; + // Mock a cmi5 connector object but only stub ONE method, as we want to test the other methods. // Create a mock of the send_request class as we don't actually want // to create a new course in the player. @@ -158,16 +163,77 @@ public function get_content() { ->with($testfunction, 'testfilecontents', 'http://test/launch.php/api/v1/course', 'zip', 'testtoken') ->willReturn($errormessage); - // Call the method under test. - $returnedresult =$csc->cmi5launch_create_course($id, $tenanttoken, $filename); + // - // Result should be debug echo string and false. - $this->assertNotTrue($returnedresult, "Expected retrieved object to be false"); - //And it should output this error message - $this->expectOutputString($expectedstring); + // Wait, i bet this is being thrown in the cmi5 connectors error message func and so we need to catch + // the correct output not an exception + $this->expectExceptionMessage($exceptionmessage); + $this->expectException(playerException::class); + + // Call the method under test. + $returnedresult = $csc->cmi5launch_create_course($id, $tenanttoken, $filename); + } + /** + * Test of the cmi5launch_create_course method with a failed response from the player. + * This one tests if resulttest is false. This path shouldnt be able to be reached but is here to test the failsafe. + * @return void + */ + public function testcmi5launch_create_course_fail_with_exception() + { + + // Function that will be called in function under test. + $testfunction = 'cmi5launch_stream_and_send'; + // Arguments to be passed to the method under test. + $id = 0; + $tenanttoken = "testtoken"; + // Error message for stubbed method to return. + $errormessage = array("statusCode" => "404", "error" => "Not Found","message" => "testmessage" ); + + //If we make filename an object with it's own get_content method, we can stub it out. + $filename = new class { + public function get_content() { + return "testfilecontents"; + } + }; + $test = false; + // Expected exceptions + $exceptionmessage = "Player communication error. Something went wrong creating the course." ; + + // Mock a cmi5 connector object but only stub ONE method, as we want to test the other methods. + // Create a mock of the send_request class as we don't actually want + // to create a new course in the player. + $csc = $this->getMockBuilder('mod_cmi5launch\local\cmi5_connectors') + ->onlyMethods(array('cmi5launch_send_request_to_cmi5_player_post', 'cmi5launch_connectors_error_message')) + ->getMock(); + + // We will have the mock return a fake message as if the player had a problem with request. + // This should enable us to test the method under failing conditions. We do expect create_course to only call this once. + $csc->expects($this->once()) + ->method('cmi5launch_send_request_to_cmi5_player_post') + ->with($testfunction, 'testfilecontents', 'http://test/launch.php/api/v1/course', 'zip', 'testtoken') + ->willReturn($errormessage); + + // The string just needs to be returned as is. We do expect create_tenant to only call this once. + $csc->expects($this->once()) + ->method('cmi5launch_connectors_error_message') + ->with($errormessage, 'creating the course') // for tomorrow, is thi failing because with only evaluates strings? Like do we need to string the array out> + // IRL it returns something that needs to be json decoded, so lets pass somethin that is encoded> + ->willReturn(false); + + // + + // Wait, i bet this is being thrown in the cmi5 connectors error message func and so we need to catch + // the correct output not an exception + $this->expectExceptionMessage($exceptionmessage); + $this->expectException(playerException::class); + + // Call the method under test. + $returnedresult = $csc->cmi5launch_create_course($id, $tenanttoken, $filename); + + } /** * Test of the cmi5launch_create_tenant method with a successful response from the player. * @return void @@ -179,21 +245,14 @@ public function testcmi5launch_create_tenant_pass() $testfunction = 'cmi5launch_stream_and_send'; // Arguments to be passed to the method under test. - $urltosend = "playerwebaddress"; - $username = "testname"; - $password = "testpassword"; - $newtenantname = "testtenantname"; - $data = array ('code' => 'testtenantname'); + $newtenantname = "newtenantname"; + $data = array ('code' => 'newtenantname'); // Encode data as it will be encoded when sent to player $data = json_encode($data); - - // This is the expected return value. - $returnvalue = array( - "code" => "testtenantname", - "id" => 9 - ); - - + + // Message for stubbed method to return. + $returnvalue = json_encode(array("statusCode" => "200", "code" => "newtenantname","id" => "9" ) ); + // Mock a cmi5 connector object but only stub ONE method, as we want to test the other methods. // Create a mock of the send_request class as we don't actually want // to create a new tenant. @@ -205,24 +264,24 @@ public function testcmi5launch_create_tenant_pass() // The string just needs to be returned as is. We do expect create_tenant to only call this once. $csc->expects($this->once()) ->method('cmi5launch_send_request_to_cmi5_player_post') - ->with($testfunction, $data, 'playerwebaddress','json', 'testname', 'testpassword') // for tomorrow, is thi failing because with only evaluates strings? Like do we need to string the array out> + ->with($testfunction, $data, 'http://test/launch.php/api/v1/tenant','json', 'testname', 'testpassword') // for tomorrow, is thi failing because with only evaluates strings? Like do we need to string the array out> // IRL it returns something that needs to be json decoded, so lets pass somethin that is encoded> - ->willReturn('{ - "code": "testtenantname", - "id": 9 - }' - ); + ->willReturn($returnvalue); + //Call the method under test. - $result =$csc->cmi5launch_create_tenant($urltosend, $username, $password, $newtenantname); + $result =$csc->cmi5launch_create_tenant( $newtenantname); + // And the return should be a string (the original method returns what the player sends back json-decoded or FALSE) - $this->assertIsArray($result); + $this->assertIsString($result); $this->assertEquals( $returnvalue, $result); + } + /** - * Test of the cmi5launch_create_tenant method with a error response from the player. + * Test of the cmi5launch_create_tenant method with a failed response from the player. Should trigger an exception. * @return void */ public function testcmi5launch_create_tenant_fail() @@ -232,44 +291,103 @@ public function testcmi5launch_create_tenant_fail() $testfunction = 'cmi5launch_stream_and_send'; // Arguments to be passed to the method under test. - $urltosend = "playerwebaddress"; - $username = "testname"; - $password = "testpassword"; - $newtenantname = "testtenantname"; - $data = array ('code' => 'testtenantname'); + + $newtenantname = "newtenantname"; + $data = array ('code' => 'newtenantname'); // Encode data as it will be encoded when sent to player $data = json_encode($data); - // The expected error message to be output. - $expectedstring= "
Something went wrong creating the tenant. CMI5 Player returned 404 error. With message 'testmessage'.
"; + + // Message for stubbed method to return. + $errormessage = array("statusCode" => "400", "message" => "website not found","id" => "9" ); + - // Error message for stubbed method to return. - $errormessage = array("statusCode" => "404", "error" => "Not Found","message" => "testmessage" ); - - // Mock a cmi5 connector object but only stub ONE method, as we want to test the others. + // Mock a cmi5 connector object but only stub ONE method, as we want to test the other methods. // Create a mock of the send_request class as we don't actually want - // to create a new course in the player. + // to create a new tenant. $csc = $this->getMockBuilder('mod_cmi5launch\local\cmi5_connectors') ->onlyMethods(array('cmi5launch_send_request_to_cmi5_player_post')) ->getMock(); - - // We will have the mock return a fake message as if the player had a problem with request. - // This will enable us to test the method under failing conditions. We do expect create_tenant to only call this once. + // We will have the mock return a basic string, as it's not under test. + // The string just needs to be returned as is. We do expect create_tenant to only call this once. $csc->expects($this->once()) ->method('cmi5launch_send_request_to_cmi5_player_post') - ->with($testfunction, $data, 'playerwebaddress', 'json', 'testname', 'testpassword') + ->with($testfunction, $data, 'http://test/launch.php/api/v1/tenant','json', 'testname', 'testpassword') // for tomorrow, is thi failing because with only evaluates strings? Like do we need to string the array out> + // IRL it returns something that needs to be json decoded, so lets pass somethin that is encoded> ->willReturn($errormessage); - //Call the method under test. - $result =$csc->cmi5launch_create_tenant($urltosend, $username, $password, $newtenantname); + // Expected exceptions + $exceptionmessage = "Player communication error. Something went wrong retrieving the registration information. CMI5 Player returned 400 error. With message 'website not found'." ; + - // Result should be debug echo string and false - $this->assertNotTrue($result, "Expected retrieved object to be false"); - // And it should output this error message - $this->expectOutputString($expectedstring); + // the correct output not an exception + $this->expectExceptionMessage($exceptionmessage); + $this->expectException(playerException::class); + + //Call the method under test. + $result =$csc->cmi5launch_create_tenant( $newtenantname); + } + + /** + * Test of the cmi5launch_create_tenant method with a failed response from the player. Should trigger an exception. + * This one tests if resulttest is false. This path shouldnt be able to be reached but is here to test the failsafe. + * @return void + */ + public function testcmi5launch_create_tenant_fail_2() + { + + // Function that will be called in function under test. + $testfunction = 'cmi5launch_stream_and_send'; + + // Arguments to be passed to the method under test. + + $newtenantname = "newtenantname"; + $data = array ('code' => 'newtenantname'); + // Encode data as it will be encoded when sent to player + $data = json_encode($data); + + + // Message for stubbed method to return. + $errormessage = array("statusCode" => "400", "message" => "website not found","id" => "9" ); + + + // Mock a cmi5 connector object but only stub ONE method, as we want to test the other methods. + // Create a mock of the send_request class as we don't actually want + // to create a new tenant. + $csc = $this->getMockBuilder('mod_cmi5launch\local\cmi5_connectors') + ->onlyMethods(array('cmi5launch_send_request_to_cmi5_player_post','cmi5launch_connectors_error_message')) + ->getMock(); + + // We will have the mock return a basic string, as it's not under test. + // The string just needs to be returned as is. We do expect create_tenant to only call this once. + $csc->expects($this->once()) + ->method('cmi5launch_send_request_to_cmi5_player_post') + ->with($testfunction, $data, 'http://test/launch.php/api/v1/tenant','json', 'testname', 'testpassword') // for tomorrow, is thi failing because with only evaluates strings? Like do we need to string the array out> + // IRL it returns something that needs to be json decoded, so lets pass somethin that is encoded> + ->willReturn($errormessage); + // We will have the mock return a basic string, as it's not under test. + // The string just needs to be returned as is. We do expect create_tenant to only call this once. + $csc->expects($this->once()) + ->method('cmi5launch_connectors_error_message') + ->with($errormessage, "creating the tenant") // for tomorrow, is thi failing because with only evaluates strings? Like do we need to string the array out> + // IRL it returns something that needs to be json decoded, so lets pass somethin that is encoded> + ->willReturn(false); + + // Expected exceptions + $exceptionmessage = "Player communication error. Something went wrong creating the tenant." ; + + + // the correct output not an exception + $this->expectExceptionMessage($exceptionmessage); + $this->expectException(playerException::class); + + //Call the method under test. + $result =$csc->cmi5launch_create_tenant( $newtenantname); + + } /** * * Test the retrieve_registration method with a successful response from the player. * @return void @@ -327,7 +445,7 @@ public function testcmi5launch_retrieve_registration_with_get_fail() $errormessage = array("statusCode" => "404", "error" => "Not Found","message" => "testmessage" ); // The expected error message to be output. - $expectedstring= "
Something went wrong retrieving the registration. CMI5 Player returned 404 error. With message 'testmessage'.
"; + // $expectedstring= "
Something went wrong retrieving the registration. CMI5 Player returned 404 error. With message 'testmessage'.
"; // The arguments to be passed to the method under test. $id = 0; @@ -350,13 +468,68 @@ public function testcmi5launch_retrieve_registration_with_get_fail() ->with($testfunction, "Testtoken", $urltosend) ->willReturn($errormessage); + // Expected exceptions + $exceptionmessage = "Player communication error. Something went wrong retrieving the registration. CMI5 Player returned 404 error. With message 'testmessage'" ; + + // Expected exceptions and messages + $this->expectExceptionMessage($exceptionmessage); + $this->expectException(playerException::class); + + //Call the method under test. + $result = $mockedclass->cmi5launch_retrieve_registration_with_get($registration, $id); + + } + + /** + * * Test the retrieve_registration method with a failed response from the player. + * This one tests if resulttest is false. This path shouldnt be able to be reached but is here to test the failsafe. + * @return void + */ + public function testcmi5launch_retrieve_registration_with_get_fail_2() + { + // Error message for stubbed method to return. + $errormessage = array("statusCode" => "404", "error" => "Not Found","message" => "testmessage" ); + + // The expected error message to be output. + // $expectedstring= "
Something went wrong retrieving the registration. CMI5 Player returned 404 error. With message 'testmessage'.
"; + + // The arguments to be passed to the method under test. + $id = 0; + $registration = "testregistration"; + + // This is the url the stubbed method shopuld receive. + $urltosend = "http://test/launch.php/api/v1/registration/testregistration"; + + // Function that will be called in function under test. + $testfunction = 'cmi5launch_stream_and_send'; + + + // Mock a cmi5 connector object but only stub ONE method, as we want to test the others. + $mockedclass = $this->getMockBuilder('mod_cmi5launch\local\cmi5_connectors') + ->onlyMethods(array('cmi5launch_send_request_to_cmi5_player_get', 'cmi5launch_connectors_error_message')) + ->getMock(); + + $mockedclass->expects($this->once()) + ->method('cmi5launch_send_request_to_cmi5_player_get') + ->with($testfunction, "Testtoken", $urltosend) + ->willReturn($errormessage); + + + $mockedclass->expects($this->once()) + ->method('cmi5launch_connectors_error_message') + ->with($errormessage, "retrieving the registration") + ->willReturn(false); + + // Expected exceptions + $exceptionmessage = "Player communication error. Something went wrong retrieving the registration information." ; + + // Expected exceptions and messages + $this->expectExceptionMessage($exceptionmessage); + $this->expectException(playerException::class); + //Call the method under test. $result = $mockedclass->cmi5launch_retrieve_registration_with_get($registration, $id); - // Result should be debug echo string and false - $this->assertNotTrue($result, "Expected retrieved object to be false"); - //And it should output this error message - $this->expectOutputString($expectedstring); } /** @@ -416,17 +589,72 @@ public function testcmi5launch_retrieve_registration_with_post_pass() } /** - * * Test the retrieve_registration_with_post method with a failed response from the player. + * * Test the retrieve_registration_with_post method with a failed response from the player. Should throw exception. + * This one tests if resulttest is false. This path shouldnt be able to be reached but is here to test the failsafe. * @return void */ - public function testcmi5launch_retrieve_registration_with_post_fail() + public function testcmi5launch_retrieve_registration_with_post_fail_2() { // Error message for stubbed method to return. $errormessage = array("statusCode" => "404", "error" => "Not Found","message" => "testmessage" ); + // The arguments to be passed to the method under test. + $id = 0; + $courseid = 1; + $filetype = "json"; - // The expected error message to be output. - $expectedstring= "
Something went wrong retrieving the registration. CMI5 Player returned 404 error. With message 'testmessage'.
"; + // The data to be passed to the mocked method. + $data = array( + "courseId" => $courseid, + "actor" => array( + "account" => array ( + "homePage" => "http://testhomepage.com", + "name" => "testname" + ), + ), + ); + + // This is the url the stubbed method shopuld receive. + $urltosend = "http://test/launch.php/api/v1/registration"; + + // Function that will be called in function under test. + $testfunction = 'cmi5launch_stream_and_send'; + + // Mock a cmi5 connector object but only stub ONE method, as we want to test the others. + $mockedclass = $this->getMockBuilder('mod_cmi5launch\local\cmi5_connectors') + ->onlyMethods(array('cmi5launch_send_request_to_cmi5_player_post', 'cmi5launch_connectors_error_message')) + ->getMock(); + + // Mock returns json encoded data, as it would be from the player. + $mockedclass->expects($this->once()) + ->method('cmi5launch_send_request_to_cmi5_player_post') + ->with($testfunction, json_encode($data), $urltosend, $filetype, "Testtoken") + ->willReturn($errormessage); + + + $mockedclass->expects($this->once()) + ->method('cmi5launch_connectors_error_message') + ->with($errormessage, "retrieving the registration") + ->willReturn(false); + + // Expected exceptions + $exceptionmessage = "Player communication error. Something went wrong retrieving the registration information." ; + + // Expected exceptions and messages + $this->expectExceptionMessage($exceptionmessage); + $this->expectException(playerException::class); + + //Call the method under test. + $result = $mockedclass->cmi5launch_retrieve_registration_with_post($courseid, $id); + } + /** + * * Test the retrieve_registration_with_post method with a failed response from the player. Should throw exception. + * @return void + */ + public function testcmi5launch_retrieve_registration_with_post_fail() + { + // Error message for stubbed method to return. + $errormessage = array("statusCode" => "404", "error" => "Not Found","message" => "testmessage" ); // The arguments to be passed to the method under test. $id = 0; $courseid = 1; @@ -460,15 +688,17 @@ public function testcmi5launch_retrieve_registration_with_post_fail() ->with($testfunction, json_encode($data), $urltosend, $filetype, "Testtoken") ->willReturn($errormessage); - //Call the method under test. - $result = $mockedclass->cmi5launch_retrieve_registration_with_post($courseid, $id); + // Expected exceptions + $exceptionmessage = "Player communication error. Something went wrong retrieving the registration. CMI5 Player returned 404 error. With message 'testmessage'" ; - // Result should be debug echo string and false - $this->assertNotTrue($result, "Expected retrieved object to be false"); - //And it should output this error message - $this->expectOutputString($expectedstring); - } + // Expected exceptions and messages + $this->expectExceptionMessage($exceptionmessage); + $this->expectException(playerException::class); + + //Call the method under test. + $result = $mockedclass->cmi5launch_retrieve_registration_with_post($courseid, $id); + } /** * * Test the retrieve_token method with a successful response from the player. @@ -476,14 +706,19 @@ public function testcmi5launch_retrieve_registration_with_post_fail() */ public function testcmi5launch_retrieve_token_pass() { + global $CFG, $cmi5launchid; + + $settings = cmi5launch_settings($cmi5launchid); // Arguments to be passed to the method under test. - $url = "http://test/launch.php"; - $username = "testname"; + //$url = "http://test/launch.php"; + // $username = "testname"; $filetype = "json"; - $password = "testpassword"; + //$password = "testpassword"; $audience = "testaudience"; $tenantid = 0; - + $username = $settings['cmi5launchbasicname']; + $url = $settings['cmi5launchplayerurl'] . "/api/v1/auth"; + $password = $settings['cmi5launchbasepass']; // The data to be passed to the mocked method. $data = array( "tenantId" => $tenantid, @@ -491,9 +726,10 @@ public function testcmi5launch_retrieve_token_pass() ); // The player returns a json string. - $returnvalue = '{ - "token": "testtoken" - }'; + $returnvalue = "testtoken"; + + $playervalue = array("statusCode" => "200", "token" => "testtoken","message" => "testmessage" ); + // Function that will be called in function under test. $testfunction = 'cmi5launch_stream_and_send'; @@ -505,10 +741,10 @@ public function testcmi5launch_retrieve_token_pass() $mockedclass->expects($this->once()) ->method('cmi5launch_send_request_to_cmi5_player_post') ->with($testfunction, json_encode($data), $url, $filetype, $username, $password) - ->willReturn($returnvalue); + ->willReturn(json_encode($playervalue)); //Call the method under test. - $result = $mockedclass->cmi5launch_retrieve_token($url, $username, $password, $audience, $tenantid); + $result = $mockedclass->cmi5launch_retrieve_token($audience, $tenantid); // And the return should be a string (the original method returns what the player sends back or FALSE. $this->assertIsString($result); @@ -521,18 +757,21 @@ public function testcmi5launch_retrieve_token_pass() */ public function testcmi5launch_retrieve_token_fail() { + global $CFG, $cmi5launchid; + $settings = cmi5launch_settings($cmi5launchid); + // Error message for stubbed method to return. $errormessage = array("statusCode" => "404", "error" => "Not Found","message" => "testmessage" ); - // The expected error message to be output. - $expectedstring= "
Something went wrong retrieving the token. CMI5 Player returned 404 error. With message 'testmessage'.
"; - // Arguments to be passed to the method under test. - $url = "http://test/launch.php"; - $username = "testname"; - $password = "testpassword"; + $url = $settings['cmi5launchplayerurl'] . '/api/v1/auth'; + $audience = "testaudience"; $tenantid = 0; + + //$actor = $USER->username; + $username = $settings['cmi5launchbasicname']; + $password = $settings['cmi5launchbasepass']; // The data to be passed to the mocked method. $filetype = "json"; @@ -555,13 +794,80 @@ public function testcmi5launch_retrieve_token_fail() ->with($testfunction, json_encode($data), $url, $filetype, $username, $password) ->willReturn($errormessage); + // Expected exceptions + $exceptionmessage = "Player communication error. Something went wrong retrieving the tenant token. CMI5 Player returned 404 error. With message 'testmessage'" ; + + // Expected exceptions and messages + $this->expectExceptionMessage($exceptionmessage); + $this->expectException(playerException::class); + + + //Call the method under test. + $result = $mockedclass->cmi5launch_retrieve_token($audience, $tenantid); + + } + + /** + * * Test the retrieve_token method with a failed response from the player. + * This one tests if resulttest is false. This path shouldnt be able to be reached but is here to test the failsafe. + * @return void + */ + public function testcmi5launch_retrieve_token_fail_2() + { + global $CFG, $cmi5launchid; + $settings = cmi5launch_settings($cmi5launchid); + + // Error message for stubbed method to return. + $errormessage = array("statusCode" => "404", "error" => "Not Found","message" => "testmessage" ); + + // Arguments to be passed to the method under test. + $url = $settings['cmi5launchplayerurl'] . '/api/v1/auth'; + + $audience = "testaudience"; + $tenantid = 0; + + //$actor = $USER->username; + $username = $settings['cmi5launchbasicname']; + $password = $settings['cmi5launchbasepass']; + + // The data to be passed to the mocked method. + $filetype = "json"; + $data = array( + "tenantId" => $tenantid, + "audience" => $audience, + ); + // Function that will be called in function under test. + $testfunction = 'cmi5launch_stream_and_send'; + + + // Mock a cmi5 connector object but only stub ONE method, as we want to test the others. + $mockedclass = $this->getMockBuilder('mod_cmi5launch\local\cmi5_connectors' ) + ->onlyMethods(array('cmi5launch_send_request_to_cmi5_player_post', 'cmi5launch_connectors_error_message')) + ->getMock(); + + // Mock returns json encoded data, as it would be from the player. + $mockedclass->expects($this->once()) + ->method('cmi5launch_send_request_to_cmi5_player_post') + ->with($testfunction, json_encode($data), $url, $filetype, $username, $password) + ->willReturn($errormessage); + + // Mock returns json encoded data, as it would be from the player. + $mockedclass->expects($this->once()) + ->method('cmi5launch_connectors_error_message') + ->with($errormessage, 'retrieving the tenant token.') + ->willReturn(false); + + // Expected exceptions + $exceptionmessage = "Player communication error. Something went wrong retrieving the tenant token." ; + + // Expected exceptions and messages + $this->expectExceptionMessage($exceptionmessage); + $this->expectException(playerException::class); + + //Call the method under test. - $result = $mockedclass->cmi5launch_retrieve_token($url, $username, $password, $audience, $tenantid); + $result = $mockedclass->cmi5launch_retrieve_token($audience, $tenantid); - // Result should be debug echo string and false. - $this->assertNotTrue($result, "Expected retrieved object to be false"); - // And it should output this error message. - $this->expectOutputString($expectedstring); } /** @@ -683,13 +989,93 @@ public function testcmi5launch_retrieve_url_fail() ->with($testfunction, json_encode($data), $urltosend, $filetype, "Testtoken") ->willReturn($errormessage); + + // Expected exceptions + $exceptionmessage = "Player communication error. Something went wrong retrieving the launch url from player. CMI5 Player returned 404 error. With message 'testmessage'" ; + + // Expected exceptions and messages + $this->expectExceptionMessage($exceptionmessage); + $this->expectException(playerException::class); + //Call the method under test. $result = $mockedclass->cmi5launch_retrieve_url($id, $auindex); - // Result should be debug echo string and false - $this->assertNotTrue($result, "Expected retrieved object to be false"); - //And it should output this error message - $this->expectOutputString($expectedstring); + + } + + /** + * * Test the retrieve_url (launchurl) method with a failed response from the player. + * This one tests if resulttest is false. This path shouldnt be able to be reached but is here to test the failsafe. + * @return void + */ + public function testcmi5launch_retrieve_url_fail_2() + { + global $cmi5launchid; + + // Error message for stubbed method to return. + $errormessage = array("statusCode" => "404", "error" => "Not Found","message" => "testmessage" ); + + // The id to be passed to method under test. + $id = $cmi5launchid; + $auindex = 1; + $filetype = "json"; + + //Retrieve settings like the method under test will. + $settings = cmi5launch_settings($id); + $playerurl = $settings['cmi5launchplayerurl']; + + $returnurl = "https://testmoodle.com"; + $registrationid = "testregistrationid"; + + // The data to be passed to the mocked method. + $data = array( + 'actor' => array( + 'account' => array( + "homePage" => "http://testhomepage.com", + "name" => "testname", + ), + ), + 'returnUrl' => $returnurl, + 'reg' => $registrationid, + ); + + // This is the url the stubbed method shopuld receive. + $urltosend = $playerurl . "/api/v1/course/" . "1" ."/launch-url/" . $auindex; + + // Function that will be called in function under test. + $testfunction = 'cmi5launch_stream_and_send'; + + // Mock a cmi5 connector object but only stub ONE method, as we want to test the other. + // Create a mock of the send_request class as we don't actually want + // to create a new course in the player. + $mockedclass = $this->getMockBuilder('mod_cmi5launch\local\cmi5_connectors') + ->onlyMethods(array('cmi5launch_send_request_to_cmi5_player_post', 'cmi5launch_connectors_error_message')) + ->getMock(); + + // Mock returns json encoded data, as it would be from the player. + $mockedclass->expects($this->once()) + ->method('cmi5launch_send_request_to_cmi5_player_post') + ->with($testfunction, json_encode($data), $urltosend, $filetype, "Testtoken") + ->willReturn($errormessage); + + + // Mock returns json encoded data, as it would be from the player. + $mockedclass->expects($this->once()) + ->method('cmi5launch_connectors_error_message') + ->with($errormessage, 'retrieving the launch url from player.') + ->willReturn(false); + + // Expected exceptions + $exceptionmessage = "Player communication error. Something went wrong retrieving the launch url from player." ; + + // Expected exceptions and messages + $this->expectExceptionMessage($exceptionmessage); + $this->expectException(playerException::class); + + //Call the method under test. + $result = $mockedclass->cmi5launch_retrieve_url($id, $auindex); + + } /** @@ -728,17 +1114,80 @@ public function testcmi5launch_send_request_to_cmi5_player_post_with_one_arg() //The arguments to pass in, in this case one, a pretend token. $token = "testtoken"; + // Expected exceptions + $exceptionmessage = "Player communication error. Error communicating with player, sending a POST request." ; + + // Expected exceptions and messages + // $this->expectExceptionMessage($exceptionmessage); + // $this->expectException(playerException::class); + // Class for function under test. $helper = new cmi5_connectors; // Call the method under test. $test = $helper->cmi5launch_send_request_to_cmi5_player_post($testfunction, $data, $url, $filetype, $token); + // If the right message is displayed the try/catch wworked! + $this->expectOutputString($exceptionmessage); + + } + + /** + * Test the send_request_to_cmi5_player_post method with one arg. + * Test the thrown exception. + * @return void + */ + public function testcmi5launch_send_request_to_cmi5_player_post_with_one_arg_fail() + { + // We send the TEST function to the function under test now! + $testfunction = 'cmi5Test\cmi5launch_test_stream_and_send_excep'; + // Which returns the 'options' parameter passed to it. + // The player returns a string under normal circumstances. + $returnvalue = json_encode(array( + "statusCode" => 200, + "Response" => "Successful Post", + )); + + // The data to be passed to the mocked method. + $data = array( + 'actor' => array( + 'account' => array( + "homePage" => "http://testhomepage.com", + "name" => "testname", + ), + ), + 'returnUrl' => 'returnurl', + 'reg' => 'registrationid', + ); + + // Fake arguments to pass in. + $filetype = "json"; + $url = "http://test/url.com"; + + + //The arguments to pass in, in this case one, a pretend token. + $token = "testtoken"; + + // Expected exceptions + $exceptionmessage = "Player communication error. Something went wrong communicating with player, sending or crafting a POST request: " ; + + + // Expected exceptions and messages + $this->expectExceptionMessage($exceptionmessage); + $this->expectException(playerException::class); + + // Class for function under test. + $helper = new cmi5_connectors; + // Call the method under test. + // Note: by not sending an actual function, this will cause an exception and allow testing of try/catch and error override. + $test = $helper->cmi5launch_send_request_to_cmi5_player_post('testfunction', $data, $url, $filetype, $token); + // And the return should be a string. $this->assertIsString($test); // And it should be the same as the return value. $this->assertEquals($test, $returnvalue); } + /** * * Test the send_request_to_cmi5_player_post method with two args. * This is what is used to retrieve info like tenant info. @@ -789,12 +1238,67 @@ public function testcmi5launch_send_request_to_cmi5_player_post_with_two_args() $this->assertEquals($test, $returnvalue); } + + /** + * * Test the send_request_to_cmi5_player_post method with two args. + * This is what is used to retrieve info like tenant info. + * @return void + */ + public function testcmi5launch_send_request_to_cmi5_player_post_with_two_args_fail() + { + + // We send the TEST function to the function under test now! + $testfunction = 'cmi5Test\cmi5launch_test_stream_and_send_pass'; + + // The player returns a string under normal circumstances. + $returnvalue = json_encode(array( + "statusCode" => 200, + "Response" => "Successful Post", + )); + + // The data to be passed to the mocked method. + $data = array( + 'actor' => array( + 'account' => array( + "homePage" => "http://testhomepage.com", + "name" => "testname", + ), + ), + 'returnUrl' => 'returnurl', + 'reg' => 'registrationid', + ); + + // Fake arguments to pass in. + $filetype = "json"; + $url = "http://test/url.com"; + $contenttype = "application/json\r\n"; + + //The arguments to pass in, in this case one, a pretend username and password. + $username = "testname"; + $password = "testpassword"; + + // Expected exceptions + $exceptionmessage = "Player communication error. Something went wrong communicating with player, sending or crafting a POST request: " ; + + + // Expected exceptions and messages + $this->expectExceptionMessage($exceptionmessage); + $this->expectException(playerException::class); + + // Class for function under test. + $helper = new cmi5_connectors; + $test = $helper->cmi5launch_send_request_to_cmi5_player_post('testfunction', $data, $url, $filetype, $username, $password); + + + } + + /** * * Test the send_request_to_cmi5_player_get * This is what is used to retrieve info like tenant info. * @return void */ - public function testcmi5launch_send_request_to_cmi5_player_post_with_get_pass() + public function testcmi5launch_send_request_to_cmi5_player_with_get_pass() { // We send the TEST function to the function under test now! @@ -816,7 +1320,7 @@ public function testcmi5launch_send_request_to_cmi5_player_post_with_get_pass() $test = $helper->cmi5launch_send_request_to_cmi5_player_get($testfunction, $token, $url); // And the return should be an array. - $this->assertIsArray($test); + $this->assertIsString($test); // And it should be the same as the return value. $this->assertEquals($test, json_decode($returnvalue, true) ); @@ -828,10 +1332,10 @@ public function testcmi5launch_send_request_to_cmi5_player_post_with_get_pass() * This is meant to fail, we want it to act as if the player is unreachable * @return void */ - public function testcmi5launch_send_request_to_cmi5_player_post_with_get_fail() + public function testcmi5launch_send_request_to_cmi5_player_with_get_fail() { // We send the TEST function to the function under test now! - $testfunction = 'cmi5Test\cmi5launch_test_stream_and_send_fail'; + $testfunction = 'cmi5Test\cmi5launch_test_stream_and_send_excep'; // Error message for stubbed method to return. @@ -852,32 +1356,32 @@ public function testcmi5launch_send_request_to_cmi5_player_post_with_get_fail() "Accept: application/json\r\n"), ), ); + // Expected exceptions + $exceptionmessage = "Player communication error. Something went wrong communicating with player, sending or crafting a GET request: " ; - // What if we run the entire class mocked except the one under test? - // would it run in the riht namespace? - // AKA OUR test namepspace - // Mock a cmi5 connector object but only stub ONE method, as we want to test the other. - + + // Expected exceptions and messages + $this->expectExceptionMessage($exceptionmessage); + $this->expectException(playerException::class); // This is the SUT? $helper = new cmi5_connectors; - $post = $helper->cmi5launch_get_send_request_to_cmi5_player_get(); + $get = $helper->cmi5launch_get_send_request_to_cmi5_player_get(); //$test = $mockedclass->cmi5launch_send_request_to_cmi5_player_get($token, $url); - $test = $post($testfunction, $token, $url); + $test = $get($testfunction, $token, $url); - // And the return should be an array since the method under test returns player message decoded. - $this->assertIsArray($test); - // And it should be the same as the return value. - $this->assertEquals($test, $errormessage); + } + + /** * * Test the retrieve_session method with a successful response from the player. * @return void */ - public function testcmi5launch_session_info_from_player_pass() + public function testcmi5launch_retrieve_session_info_from_player_pass() { global $cmi5launchid; @@ -894,11 +1398,11 @@ public function testcmi5launch_session_info_from_player_pass() $urltosend = $playerurl . "/api/v1/session/" . $sessionid; // The player returns a string, but the mocked method returns an array. - $returnvalue = array( + $returnvalue = json_encode(array( "statusCode" => 200, "launchMethod" => "AnyWindow", "url" => "http://testlaunchurl" - ); + )); // We send the TEST function to the function under test now! $testfunction = 'cmi5launch_stream_and_send'; @@ -913,7 +1417,7 @@ public function testcmi5launch_session_info_from_player_pass() $mockedclass->expects($this->once()) ->method('cmi5launch_send_request_to_cmi5_player_get') ->with($testfunction, $token, $urltosend) - ->willReturn(json_encode($returnvalue)); + ->willReturn(($returnvalue)); //Call the method under test. @@ -921,14 +1425,69 @@ public function testcmi5launch_session_info_from_player_pass() // And the return should be an array (the original method returns what the player sends back json-decoded or FALSE) $this->assertIsString($result); - $this->assertEquals($result, json_encode($returnvalue)); + $this->assertEquals($result,($returnvalue)); } /** * * Test the retrieve_session (launchurl) method with a failed response from the player. * @return void */ - public function testcmi5launch_session_info_from_player_fail() + public function testcmi5launch_retrieve_session_info_from_player_fail() + { + global $cmi5launchid; + + // Error message for stubbed method to return. + $errormessage = json_encode( + array("statusCode" => "404", + "error" => "Not Found", + "message" => "testmessage" )); + + + // The id to be passed to method under test. + $id = $cmi5launchid; + + //Retrieve settings like the method under test will. + $settings = cmi5launch_settings($id); + $playerurl = $settings['cmi5launchplayerurl']; + $sessionid = "testsessionid"; + $token = $settings['cmi5launchtenanttoken']; + // This is the url the stubbed method shopuld receive. + $urltosend = $playerurl . "/api/v1/session/" . $sessionid; + + // We send the TEST function to the function under test now! + $testfunction = 'cmi5launch_stream_and_send'; + + + // Mock a cmi5 connector object but only stub ONE method, as we want to test the others. + $mockedclass = $this->getMockBuilder('mod_cmi5launch\local\cmi5_connectors') + ->onlyMethods(array('cmi5launch_send_request_to_cmi5_player_get')) + ->getMock(); + + // Mock returns json encoded data, as it would be from the player. + $mockedclass->expects($this->once()) + ->method('cmi5launch_send_request_to_cmi5_player_get') + ->with($testfunction, $token, $urltosend) + ->willReturn($errormessage); + + // Expected exceptions + $exceptionmessage = "Player communication error. Something went wrong retrieving the session information. CMI5 Player returned 404 error. With message 'testmessage'." ; + + + // Expected exceptions and messages + $this->expectExceptionMessage($exceptionmessage); + $this->expectException(playerException::class); + + //Call the method under test. + $result = $mockedclass->cmi5launch_retrieve_session_info_from_player($sessionid, $id); + + } + + /** + * * Test the retrieve_session (launchurl) method with a failed response from the player. + * This one tests if resulttest is false. This path shouldnt be able to be reached but is here to test the failsafe. + * @return void + */ + public function testcmi5launch_retrieve_session_info_from_player_fail_excep() { global $cmi5launchid; @@ -936,7 +1495,7 @@ public function testcmi5launch_session_info_from_player_fail() $errormessage = array("statusCode" => "404", "error" => "Not Found","message" => "testmessage" ); // The expected error message to be output. - $expectedstring= "
Something went wrong retrieving session info. CMI5 Player returned 404 error. With message 'testmessage'.
"; + $expectedstring= "
Something went wrong retrieving session information. CMI5 Player returned 404 error. With message 'testmessage'.
"; // The id to be passed to method under test. $id = $cmi5launchid; @@ -948,28 +1507,39 @@ public function testcmi5launch_session_info_from_player_fail() $token = $settings['cmi5launchtenanttoken']; // This is the url the stubbed method shopuld receive. $urltosend = $playerurl . "/api/v1/session/" . $sessionid; - // We send the TEST function to the function under test now! - $testfunction = 'cmi5launch_stream_and_send'; + + // We send the TEST function to the function under test now! + $testfunction = 'cmi5launch_stream_and_send'; // Mock a cmi5 connector object but only stub ONE method, as we want to test the others. $mockedclass = $this->getMockBuilder('mod_cmi5launch\local\cmi5_connectors') - ->onlyMethods(array('cmi5launch_send_request_to_cmi5_player_get')) + ->onlyMethods(array('cmi5launch_send_request_to_cmi5_player_get', 'cmi5launch_connectors_error_message')) ->getMock(); // Mock returns json encoded data, as it would be from the player. $mockedclass->expects($this->once()) ->method('cmi5launch_send_request_to_cmi5_player_get') ->with($testfunction, $token, $urltosend) - ->willReturn(json_encode($errormessage)); + ->willReturn(($errormessage)); + + // Mock returns json encoded data, as it would be from the player. + $mockedclass->expects($this->once()) + ->method('cmi5launch_connectors_error_message') + ->with($errormessage, 'retrieving the session information.') + ->willReturn(false); + + // Expected exceptions + $exceptionmessage = "Player communication error. Something went wrong retrieving the session information." ; - //Call the method under test. - $result = $mockedclass->cmi5launch_retrieve_session_info_from_player($sessionid, $id); - // Result should be debug echo string and false - $this->assertNotTrue($result, "Expected retrieved object to be false"); - //And it should output this error message - $this->expectOutputString($expectedstring); + // Expected exceptions and messages + $this->expectExceptionMessage($exceptionmessage); + $this->expectException(playerException::class); + + //Call the method under test. + $result = $mockedclass->cmi5launch_retrieve_session_info_from_player($sessionid, $id); + } /** @@ -984,16 +1554,22 @@ public function testcmi5launch_connectors_error_message_path_one() $response = false; $type = "retreiving 'item'"; + $helper = new cmi5_connectors; + $error = $helper->cmi5launch_get_connectors_error_message(); + + // The expected error message to be output. - $errormessage ="
Something went wrong " . $type . ". CMI5 Player is not communicating. Is it running?
"; + $exceptionmessage ="Something went wrong " . $type . ". CMI5 Player is not communicating. Is it running?"; + + + // Expected exceptions and messages + $this->expectExceptionMessage($exceptionmessage); + $this->expectException(playerException::class); // Call the method under test. - $result = cmi5_connectors::cmi5launch_connectors_error_message($response, $type); + $result = $error($response, $type); - // Result should be debug echo string and false - $this->assertNotTrue($result, "Expected retrieved object to be false"); - //And it should output this error message - $this->expectOutputString($errormessage); + } /** @@ -1009,15 +1585,19 @@ public function testcmi5launch_connectors_error_message_path_two() $response = array("statusCode" => "404", "error" => "Not Found","message" => "testmessage" ); // The expected error message to be output. - $expectedstring ="
Something went wrong " . $type . ". CMI5 Player returned " . $response['statusCode'] . " error. With message '" . $response['message'] . "'.
"; + $exceptionmessage="Something went wrong " . $type . " CMI5 Player returned " . $response['statusCode'] . " error. With message '" . $response['message'] . "'."; + + $helper = new cmi5_connectors; + $error = $helper->cmi5launch_get_connectors_error_message(); + + + // Expected exceptions and messages + $this->expectExceptionMessage($exceptionmessage); + $this->expectException(playerException::class); // Call the method under test. - $result = cmi5_connectors::cmi5launch_connectors_error_message($response, $type); - - // Result should be debug echo string and false - $this->assertNotTrue($result, "Expected retrieved object to be false"); - //And it should output this error message - $this->expectOutputString($expectedstring); + $result = $error($response, $type); + } /** @@ -1036,8 +1616,11 @@ public function testcmi5launch_connectors_error_message_path_three() "Response" => "Successful Post", )); + $helper = new cmi5_connectors; + $error = $helper->cmi5launch_get_connectors_error_message(); + // Call the method under test. - $result = cmi5_connectors::cmi5launch_connectors_error_message($response, $type); + $result = $error($response, $type); // Result should be debug echo string and false $this->assertTrue($result, "Expected retrieved object to be true"); diff --git a/cmi5PHP/tests/errorOverTest.php b/cmi5PHP/tests/errorOverTest.php new file mode 100644 index 0000000..38d4c7c --- /dev/null +++ b/cmi5PHP/tests/errorOverTest.php @@ -0,0 +1,36 @@ +expectException(nullException::class); + + //can we just call it? + // is this necessary? errorover::array_chunk_warning(E_WARNING, "This is a test error", "testfile.php", 1); + + + } +} \ No newline at end of file diff --git a/db/install.php b/db/install.php index 83d5b22..a66fb03 100755 --- a/db/install.php +++ b/db/install.php @@ -25,7 +25,7 @@ require_once(dirname(dirname(dirname(dirname(__FILE__)))).'/config.php'); -//require_login($course, false, $cm); + /** * Post installation procedure diff --git a/grade.php b/grade.php old mode 100755 new mode 100644 diff --git a/lib.php b/lib.php index 8fb9c67..af2db5e 100755 --- a/lib.php +++ b/lib.php @@ -610,6 +610,8 @@ function cmi5launch_process_new_package($cmi5launch) { $record->courseid = $returnedinfo["id"]; + // TEST + $test = ""; // Create url for sending to when requesting launch url for course. $playerurl = $settings['cmi5launchplayerurl']; @@ -617,7 +619,8 @@ function cmi5launch_process_new_package($cmi5launch) { $url = $playerurl . "/api/v1/" . $record->courseid . "/launch-url/"; $record->launchurl = $url; - // Retrieve AUs and save to table. + + $aus = ($retrieveaus($returnedinfo)); $record->aus = (json_encode($aus)); @@ -1098,10 +1101,10 @@ function cmi5launch_grade_item_update($cmi5launch, $grades = null) { // Calculate grade based on grade type, and update rawgrade (a param of grade item). switch($gradetype){ - // 'MOD_CMI5LAUNCH_AUS_GRADE' = '0'. - // 'MOD_CMI5LAUNCH_GRADE_HIGHEST' = '1'. - // 'MOD_CMI5LAUNCH_GRADE_AVERAGE', = '2'. - // 'MOD_CMI5LAUNCH_GRADE_SUM', = '3'. + // 'GRADE_AUS_CMI5' = '0'. + // 'GRADE_HIGHEST_CMI5' = '1'. + // 'GRADE_AVERAGE_CMI5', = '2'. + // 'GRADE_SUM_CMI5', = '3'. case 1: foreach ($grades as $key => $grade) { diff --git a/locallib.php b/locallib.php index 30c3ae0..3ee2f5c 100755 --- a/locallib.php +++ b/locallib.php @@ -33,7 +33,7 @@ use mod_cmi5launch\local\cmi5_connectors; // Grade stuff. -define('MOD_CMI5LAUNCH_AUS_GRADE', '0'); +define('MOD_CMI5LAUNCH_GRADE_AUS', '0'); define('MOD_CMI5LAUNCH_GRADE_HIGHEST', '1'); define('MOD_CMI5LAUNCH_GRADE_AVERAGE', '2'); define('MOD_CMI5LAUNCH_GRADE_SUM', '3'); @@ -43,13 +43,13 @@ define('MOD_CMI5LAUNCH_FIRST_ATTEMPT', '2'); define('MOD_CMI5LAUNCH_LAST_ATTEMPT', '3'); -define('MOD_CMI5LAUNCH_FORCEATTEMPT_NO', 0); -define('MOD_CMI5LAUNCH_FORCEATTEMPT_ONCOMPLETE', 1); -define('MOD_CMI5LAUNCH_FORCEATTEMPT_ALWAYS', 2); +define('CMI5_FORCEATTEMPT_NO', 0); +define('CMI5_FORCEATTEMPT_ONCOMPLETE', 1); +define('CMI5_FORCEATTEMPT_ALWAYS', 2); -define('MOD_CMI5LAUNCH_UPDATE_NEVER', '0'); -define('MOD_CMI5LAUNCH_UPDATE_EVERYDAY', '2'); -define('MOD_CMI5LAUNCH_UPDATE_EVERYTIME', '3'); +define('CMI5_UPDATE_NEVER', '0'); +define('CMI5_UPDATE_EVERYDAY', '2'); +define('CMI5_UPDATE_EVERYTIME', '3'); diff --git a/report.php b/report.php old mode 100755 new mode 100644 index fc768cc..7681097 --- a/report.php +++ b/report.php @@ -280,10 +280,10 @@ function mod_cmi5launch_open_report(inforfornextpage) { // This is just to display, it calculates here so it doesn't effect the base array stored for AU. switch($gradetype){ - // MOD_CMI5LAUNCH_AUS_GRADE' = '0'. - // MOD_CMI5LAUNCH_GRADE_HIGHEST' = '1'. - // MOD_CMI5LAUNCH_GRADE_AVERAGE', = '2'. - // MOD_CMI5LAUNCH_GRADE_SUM', = '3'. + // GRADE_AUS_CMI5' = '0'. + // GRADE_HIGHEST_CMI5' = '1'. + // GRADE_AVERAGE_CMI5', = '2'. + // GRADE_SUM_CMI5', = '3'. case 1: $userscore = strval($highestgrade($augrades)); break; diff --git a/session_report.php b/session_report.php old mode 100755 new mode 100644 index 738afdd..be1d918 --- a/session_report.php +++ b/session_report.php @@ -229,10 +229,10 @@ switch ($gradetype) { - // 'MOD_CMI5LAUNCH_AUS_GRADE' = '0'). - // 'MOD_CMI5LAUNCH_GRADE_HIGHEST' = '1'. - // 'MOD_CMI5LAUNCH_GRADE_AVERAGE', = '2'. - // 'MOD_CMI5LAUNCH_GRADE_SUM', = '3'. + // 'GRADE_AUS_CMI5' = '0'). + // 'GRADE_HIGHEST_CMI5' = '1'. + // 'GRADE_AVERAGE_CMI5', = '2'. + // 'GRADE_SUM_CMI5', = '3'. case 1: $grade = "Highest"; diff --git a/view.php b/view.php index ce7855c..7fde793 100755 --- a/view.php +++ b/view.php @@ -156,6 +156,8 @@ function mod_cmi5launch_launchexperience(registrationInfo) { // Retrieve AU ids for this user/course. $aus = json_decode($record->aus); + // We should not even be able to et here if these are false on record + $auids = $saveaus($createaus($aus)); $userscourse->aus = (json_encode($auids));