MDL-58454 badges: Fix some minor errors for Open Badges v2
[moodle.git] / lib / tests / messagelib_test.php
blob679175cbdf650071d48d692f78e434538be641cd
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * Tests for messagelib.php.
20 * @package core_message
21 * @category phpunit
22 * @copyright 2012 The Open Universtiy
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') || die();
28 class core_messagelib_testcase extends advanced_testcase {
30 public function test_message_provider_disabled() {
31 $this->resetAfterTest();
32 $this->preventResetByRollback();
34 // Disable instantmessage provider.
35 $disableprovidersetting = 'moodle_instantmessage_disable';
36 set_config($disableprovidersetting, 1, 'message');
37 $preferences = get_message_output_default_preferences();
38 $this->assertTrue($preferences->$disableprovidersetting == 1);
40 $message = new \core\message\message();
41 $message->courseid = 1;
42 $message->component = 'moodle';
43 $message->name = 'instantmessage';
44 $message->userfrom = get_admin();
45 $message->userto = $this->getDataGenerator()->create_user();;
46 $message->subject = 'message subject 1';
47 $message->fullmessage = 'message body';
48 $message->fullmessageformat = FORMAT_MARKDOWN;
49 $message->fullmessagehtml = '<p>message body</p>';
50 $message->smallmessage = 'small message';
51 $message->notification = 0;
53 // Check message is not sent.
54 $sink = $this->redirectEmails();
55 message_send($message);
56 $emails = $sink->get_messages();
57 $this->assertEmpty($emails);
59 // Check message is sent.
60 set_config($disableprovidersetting, 0, 'message');
61 $preferences = get_message_output_default_preferences();
62 $this->assertTrue($preferences->$disableprovidersetting == 0);
64 $sink = $this->redirectEmails();
65 message_send($message);
66 $emails = $sink->get_messages();
67 $email = reset($emails);
68 $this->assertEquals($email->subject, 'message subject 1');
70 public function test_message_get_providers_for_user() {
71 global $CFG, $DB;
73 $this->resetAfterTest();
75 $generator = $this->getDataGenerator();
77 // Create a course category and course.
78 $cat = $generator->create_category(array('parent' => 0));
79 $course = $generator->create_course(array('category' => $cat->id));
80 $quiz = $generator->create_module('quiz', array('course' => $course->id));
81 $user = $generator->create_user();
83 $coursecontext = context_course::instance($course->id);
84 $quizcontext = context_module::instance($quiz->cmid);
85 $frontpagecontext = context_course::instance(SITEID);
87 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
89 // The user is a student in a course, and has the capability for quiz
90 // confirmation emails in one quiz in that course.
91 role_assign($studentrole->id, $user->id, $coursecontext->id);
92 assign_capability('mod/quiz:emailconfirmsubmission', CAP_ALLOW, $studentrole->id, $quizcontext->id);
94 // Give this message type to the front page role.
95 assign_capability('mod/quiz:emailwarnoverdue', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagecontext->id);
97 $providers = message_get_providers_for_user($user->id);
98 $this->assertTrue($this->message_type_present('mod_forum', 'posts', $providers));
99 $this->assertTrue($this->message_type_present('mod_quiz', 'confirmation', $providers));
100 $this->assertTrue($this->message_type_present('mod_quiz', 'attempt_overdue', $providers));
101 $this->assertFalse($this->message_type_present('mod_quiz', 'submission', $providers));
103 // A user is a student in a different course, they should not get confirmation.
104 $course2 = $generator->create_course(array('category' => $cat->id));
105 $user2 = $generator->create_user();
106 $coursecontext2 = context_course::instance($course2->id);
107 role_assign($studentrole->id, $user2->id, $coursecontext2->id);
108 accesslib_clear_all_caches_for_unit_testing();
109 $providers = message_get_providers_for_user($user2->id);
110 $this->assertTrue($this->message_type_present('mod_forum', 'posts', $providers));
111 $this->assertFalse($this->message_type_present('mod_quiz', 'confirmation', $providers));
113 // Now remove the frontpage role id, and attempt_overdue message should go away.
114 unset_config('defaultfrontpageroleid');
115 accesslib_clear_all_caches_for_unit_testing();
117 $providers = message_get_providers_for_user($user->id);
118 $this->assertTrue($this->message_type_present('mod_quiz', 'confirmation', $providers));
119 $this->assertFalse($this->message_type_present('mod_quiz', 'attempt_overdue', $providers));
120 $this->assertFalse($this->message_type_present('mod_quiz', 'submission', $providers));
123 public function test_message_get_providers_for_user_more() {
124 global $DB;
126 $this->resetAfterTest();
128 // Create a course.
129 $course = $this->getDataGenerator()->create_course();
130 $coursecontext = context_course::instance($course->id);
132 // It would probably be better to use a quiz instance as it has capability controlled messages
133 // however mod_quiz doesn't have a data generator.
134 // Instead we're going to use backup notifications and give and take away the capability at various levels.
135 $assign = $this->getDataGenerator()->create_module('assign', array('course'=>$course->id));
136 $modulecontext = context_module::instance($assign->cmid);
138 // Create and enrol a teacher.
139 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
140 $teacher = $this->getDataGenerator()->create_user();
141 role_assign($teacherrole->id, $teacher->id, $coursecontext);
142 $enrolplugin = enrol_get_plugin('manual');
143 $enrolplugin->add_instance($course);
144 $enrolinstances = enrol_get_instances($course->id, false);
145 foreach ($enrolinstances as $enrolinstance) {
146 if ($enrolinstance->enrol === 'manual') {
147 break;
150 $enrolplugin->enrol_user($enrolinstance, $teacher->id);
152 // Make the teacher the current user.
153 $this->setUser($teacher);
155 // Teacher shouldn't have the required capability so they shouldn't be able to see the backup message.
156 $this->assertFalse(has_capability('moodle/site:config', $modulecontext));
157 $providers = message_get_providers_for_user($teacher->id);
158 $this->assertFalse($this->message_type_present('moodle', 'backup', $providers));
160 // Give the user the required capability in an activity module.
161 // They should now be able to see the backup message.
162 assign_capability('moodle/site:config', CAP_ALLOW, $teacherrole->id, $modulecontext->id, true);
163 accesslib_clear_all_caches_for_unit_testing();
164 $modulecontext = context_module::instance($assign->cmid);
165 $this->assertTrue(has_capability('moodle/site:config', $modulecontext));
167 $providers = message_get_providers_for_user($teacher->id);
168 $this->assertTrue($this->message_type_present('moodle', 'backup', $providers));
170 // Prohibit the capability for the user at the course level.
171 // This overrules the CAP_ALLOW at the module level.
172 // They should not be able to see the backup message.
173 assign_capability('moodle/site:config', CAP_PROHIBIT, $teacherrole->id, $coursecontext->id, true);
174 accesslib_clear_all_caches_for_unit_testing();
175 $modulecontext = context_module::instance($assign->cmid);
176 $this->assertFalse(has_capability('moodle/site:config', $modulecontext));
178 $providers = message_get_providers_for_user($teacher->id);
179 // Actually, handling PROHIBITs would be too expensive. We do not
180 // care if users with PROHIBITs see a few more preferences than they should.
181 // $this->assertFalse($this->message_type_present('moodle', 'backup', $providers));
184 public function test_send_message_redirection() {
185 global $DB;
187 $this->resetAfterTest();
189 $user1 = $this->getDataGenerator()->create_user();
190 $user2 = $this->getDataGenerator()->create_user();
192 // Test basic message redirection.
193 $message = new \core\message\message();
194 $message->courseid = 1;
195 $message->component = 'moodle';
196 $message->name = 'instantmessage';
197 $message->userfrom = $user1;
198 $message->userto = $user2;
199 $message->subject = 'message subject 1';
200 $message->fullmessage = 'message body';
201 $message->fullmessageformat = FORMAT_MARKDOWN;
202 $message->fullmessagehtml = '<p>message body</p>';
203 $message->smallmessage = 'small message';
204 $message->notification = '0';
206 $sink = $this->redirectMessages();
207 $this->setCurrentTimeStart();
208 $messageid = message_send($message);
209 $savedmessages = $sink->get_messages();
210 $this->assertCount(1, $savedmessages);
211 $savedmessage = reset($savedmessages);
212 $this->assertEquals($messageid, $savedmessage->id);
213 $this->assertEquals($user1->id, $savedmessage->useridfrom);
214 $this->assertEquals($user2->id, $savedmessage->useridto);
215 $this->assertEquals($message->fullmessage, $savedmessage->fullmessage);
216 $this->assertEquals($message->fullmessageformat, $savedmessage->fullmessageformat);
217 $this->assertEquals($message->fullmessagehtml, $savedmessage->fullmessagehtml);
218 $this->assertEquals($message->smallmessage, $savedmessage->smallmessage);
219 $this->assertEquals($message->smallmessage, $savedmessage->smallmessage);
220 $this->assertEquals($message->notification, $savedmessage->notification);
221 $this->assertTimeCurrent($savedmessage->timecreated);
222 $record = $DB->get_record('messages', array('id' => $savedmessage->id), '*', MUST_EXIST);
223 unset($savedmessage->useridto);
224 unset($savedmessage->notification);
225 $this->assertEquals($record, $savedmessage);
226 $sink->clear();
227 $this->assertTrue($DB->record_exists('message_user_actions', array('userid' => $user2->id, 'messageid' => $messageid,
228 'action' => \core_message\api::MESSAGE_ACTION_READ)));
229 $DB->delete_records('messages', array());
231 $message = new \core\message\message();
232 $message->courseid = 1;
233 $message->component = 'moodle';
234 $message->name = 'instantmessage';
235 $message->userfrom = $user1->id;
236 $message->userto = $user2->id;
237 $message->subject = 'message subject 1';
238 $message->fullmessage = 'message body';
239 $message->fullmessageformat = FORMAT_MARKDOWN;
240 $message->fullmessagehtml = '<p>message body</p>';
241 $message->smallmessage = 'small message';
242 $message->notification = '0';
244 $sink = $this->redirectMessages();
245 $messageid = message_send($message);
246 $savedmessages = $sink->get_messages();
247 $this->assertCount(1, $savedmessages);
248 $savedmessage = reset($savedmessages);
249 $this->assertEquals($messageid, $savedmessage->id);
250 $this->assertEquals($user1->id, $savedmessage->useridfrom);
251 $this->assertEquals($user2->id, $savedmessage->useridto);
252 $this->assertEquals($message->fullmessage, $savedmessage->fullmessage);
253 $this->assertEquals($message->fullmessageformat, $savedmessage->fullmessageformat);
254 $this->assertEquals($message->fullmessagehtml, $savedmessage->fullmessagehtml);
255 $this->assertEquals($message->smallmessage, $savedmessage->smallmessage);
256 $this->assertEquals($message->smallmessage, $savedmessage->smallmessage);
257 $this->assertEquals($message->notification, $savedmessage->notification);
258 $this->assertTimeCurrent($savedmessage->timecreated);
259 $record = $DB->get_record('messages', array('id' => $savedmessage->id), '*', MUST_EXIST);
260 unset($savedmessage->useridto);
261 unset($savedmessage->notification);
262 $this->assertEquals($record, $savedmessage);
263 $sink->clear();
264 $this->assertTrue($DB->record_exists('message_user_actions', array('userid' => $user2->id, 'messageid' => $messageid,
265 'action' => \core_message\api::MESSAGE_ACTION_READ)));
266 $DB->delete_records('messages', array());
268 // Test phpunit problem detection.
270 $message = new \core\message\message();
271 $message->courseid = 1;
272 $message->component = 'xxxxx';
273 $message->name = 'instantmessage';
274 $message->userfrom = $user1;
275 $message->userto = $user2;
276 $message->subject = 'message subject 1';
277 $message->fullmessage = 'message body';
278 $message->fullmessageformat = FORMAT_MARKDOWN;
279 $message->fullmessagehtml = '<p>message body</p>';
280 $message->smallmessage = 'small message';
281 $message->notification = '0';
283 $sink = $this->redirectMessages();
284 try {
285 message_send($message);
286 } catch (moodle_exception $e) {
287 $this->assertInstanceOf('coding_exception', $e);
289 $this->assertCount(0, $sink->get_messages());
290 $this->assertDebuggingCalled('Attempt to send msg from a provider xxxxx/instantmessage '.
291 'that is inactive or not allowed for the user id='.$user2->id);
293 $message->component = 'moodle';
294 $message->name = 'xxx';
295 $sink = $this->redirectMessages();
296 try {
297 message_send($message);
298 } catch (moodle_exception $e) {
299 $this->assertInstanceOf('coding_exception', $e);
301 $this->assertCount(0, $sink->get_messages());
302 $this->assertDebuggingCalled('Attempt to send msg from a provider moodle/xxx '.
303 'that is inactive or not allowed for the user id='.$user2->id);
304 $sink->close();
305 $this->assertFalse($DB->record_exists('messages', array()));
307 // Invalid users.
309 $message = new \core\message\message();
310 $message->courseid = 1;
311 $message->component = 'moodle';
312 $message->name = 'instantmessage';
313 $message->userfrom = $user1;
314 $message->userto = -1;
315 $message->subject = 'message subject 1';
316 $message->fullmessage = 'message body';
317 $message->fullmessageformat = FORMAT_MARKDOWN;
318 $message->fullmessagehtml = '<p>message body</p>';
319 $message->smallmessage = 'small message';
320 $message->notification = '0';
322 $messageid = message_send($message);
323 $this->assertFalse($messageid);
324 $this->assertDebuggingCalled('Attempt to send msg to unknown user');
326 $message = new \core\message\message();
327 $message->courseid = 1;
328 $message->component = 'moodle';
329 $message->name = 'instantmessage';
330 $message->userfrom = -1;
331 $message->userto = $user2;
332 $message->subject = 'message subject 1';
333 $message->fullmessage = 'message body';
334 $message->fullmessageformat = FORMAT_MARKDOWN;
335 $message->fullmessagehtml = '<p>message body</p>';
336 $message->smallmessage = 'small message';
337 $message->notification = '0';
339 $messageid = message_send($message);
340 $this->assertFalse($messageid);
341 $this->assertDebuggingCalled('Attempt to send msg from unknown user');
343 $message = new \core\message\message();
344 $message->courseid = 1;
345 $message->component = 'moodle';
346 $message->name = 'instantmessage';
347 $message->userfrom = $user1;
348 $message->userto = core_user::NOREPLY_USER;
349 $message->subject = 'message subject 1';
350 $message->fullmessage = 'message body';
351 $message->fullmessageformat = FORMAT_MARKDOWN;
352 $message->fullmessagehtml = '<p>message body</p>';
353 $message->smallmessage = 'small message';
354 $message->notification = '0';
356 $messageid = message_send($message);
357 $this->assertFalse($messageid);
358 $this->assertDebuggingCalled('Attempt to send msg to internal (noreply) user');
360 // Some debugging hints for devs.
362 unset($user2->emailstop);
363 $message = new \core\message\message();
364 $message->courseid = 1;
365 $message->component = 'moodle';
366 $message->name = 'instantmessage';
367 $message->userfrom = $user1;
368 $message->userto = $user2;
369 $message->subject = 'message subject 1';
370 $message->fullmessage = 'message body';
371 $message->fullmessageformat = FORMAT_MARKDOWN;
372 $message->fullmessagehtml = '<p>message body</p>';
373 $message->smallmessage = 'small message';
374 $message->notification = '0';
376 $sink = $this->redirectMessages();
377 $messageid = message_send($message);
378 $savedmessages = $sink->get_messages();
379 $this->assertCount(1, $savedmessages);
380 $savedmessage = reset($savedmessages);
381 $this->assertEquals($messageid, $savedmessage->id);
382 $this->assertEquals($user1->id, $savedmessage->useridfrom);
383 $this->assertEquals($user2->id, $savedmessage->useridto);
384 $this->assertDebuggingCalled('Necessary properties missing in userto object, fetching full record');
385 $sink->clear();
386 $user2->emailstop = '0';
389 public function test_send_message() {
390 global $DB, $CFG;
391 $this->preventResetByRollback();
392 $this->resetAfterTest();
394 $user1 = $this->getDataGenerator()->create_user(array('maildisplay' => 1));
395 $user2 = $this->getDataGenerator()->create_user();
396 set_config('allowedemaildomains', 'example.com');
398 // Test basic email redirection.
399 $this->assertFileExists("$CFG->dirroot/message/output/email/version.php");
400 $this->assertFileExists("$CFG->dirroot/message/output/popup/version.php");
402 $DB->set_field_select('message_processors', 'enabled', 0, "name <> 'email' AND name <> 'popup'");
403 get_message_processors(true, true);
405 $eventsink = $this->redirectEvents();
407 // Will always use the pop-up processor.
408 set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'none', $user2);
410 $message = new \core\message\message();
411 $message->courseid = 1;
412 $message->component = 'moodle';
413 $message->name = 'instantmessage';
414 $message->userfrom = $user1;
415 $message->userto = $user2;
416 $message->subject = 'message subject 1';
417 $message->fullmessage = 'message body';
418 $message->fullmessageformat = FORMAT_MARKDOWN;
419 $message->fullmessagehtml = '<p>message body</p>';
420 $message->smallmessage = 'small message';
421 $message->notification = '0';
423 $sink = $this->redirectEmails();
424 $messageid = message_send($message);
425 $emails = $sink->get_messages();
426 $this->assertCount(0, $emails);
427 $savedmessage = $DB->get_record('messages', array('id' => $messageid), '*', MUST_EXIST);
428 $sink->clear();
429 $this->assertFalse($DB->record_exists('message_user_actions', array()));
430 $DB->delete_records('messages', array());
431 $DB->delete_records('message_user_actions', array());
432 $events = $eventsink->get_events();
433 $this->assertCount(1, $events);
434 $this->assertInstanceOf('\core\event\message_sent', $events[0]);
435 $eventsink->clear();
437 // No messages are sent when the feature is disabled.
438 $CFG->messaging = 0;
440 $message = new \core\message\message();
441 $message->courseid = 1;
442 $message->component = 'moodle';
443 $message->name = 'instantmessage';
444 $message->userfrom = $user1;
445 $message->userto = $user2;
446 $message->subject = 'message subject 1';
447 $message->fullmessage = 'message body';
448 $message->fullmessageformat = FORMAT_MARKDOWN;
449 $message->fullmessagehtml = '<p>message body</p>';
450 $message->smallmessage = 'small message';
451 $message->notification = '0';
453 $messageid = message_send($message);
454 $this->assertFalse($messageid);
455 $this->assertDebuggingCalled('Attempt to send msg from a provider moodle/instantmessage '.
456 'that is inactive or not allowed for the user id='.$user2->id);
457 $emails = $sink->get_messages();
458 $this->assertCount(0, $emails);
459 $sink->clear();
460 $DB->delete_records('messages', array());
461 $DB->delete_records('message_user_actions', array());
462 $events = $eventsink->get_events();
463 $this->assertCount(0, $events);
464 $eventsink->clear();
466 // Example of a message that is sent and viewed.
467 $CFG->messaging = 1;
469 $message = new \core\message\message();
470 $message->courseid = 1;
471 $message->component = 'moodle';
472 $message->name = 'instantmessage';
473 $message->userfrom = $user1;
474 $message->userto = $user2;
475 $message->subject = 'message subject 1';
476 $message->fullmessage = 'message body';
477 $message->fullmessageformat = FORMAT_MARKDOWN;
478 $message->fullmessagehtml = '<p>message body</p>';
479 $message->smallmessage = 'small message';
480 $message->notification = '1';
482 $messageid = message_send($message);
483 $emails = $sink->get_messages();
484 $this->assertCount(0, $emails);
485 $savedmessage = $DB->get_record('notifications', array('id' => $messageid), '*', MUST_EXIST);
486 $sink->clear();
487 $this->assertFalse($DB->record_exists('messages', array()));
488 $DB->delete_records('notifications', array());
489 $events = $eventsink->get_events();
490 $this->assertCount(2, $events);
491 $this->assertInstanceOf('\core\event\notification_sent', $events[0]);
492 $this->assertInstanceOf('\core\event\notification_viewed', $events[1]);
493 $eventsink->clear();
495 // Will always use the pop-up processor.
496 set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'email', $user2);
498 $message = new \core\message\message();
499 $message->courseid = 1;
500 $message->component = 'moodle';
501 $message->name = 'instantmessage';
502 $message->userfrom = $user1;
503 $message->userto = $user2;
504 $message->subject = 'message subject 1';
505 $message->fullmessage = 'message body';
506 $message->fullmessageformat = FORMAT_MARKDOWN;
507 $message->fullmessagehtml = '<p>message body</p>';
508 $message->smallmessage = 'small message';
509 $message->notification = '0';
511 $user2->emailstop = '1';
513 $sink = $this->redirectEmails();
514 $messageid = message_send($message);
515 $emails = $sink->get_messages();
516 $this->assertCount(0, $emails);
517 $savedmessage = $DB->get_record('messages', array('id' => $messageid), '*', MUST_EXIST);
518 $sink->clear();
519 $this->assertFalse($DB->record_exists('message_user_actions', array()));
520 $DB->delete_records('messages', array());
521 $DB->delete_records('message_user_actions', array());
522 $events = $eventsink->get_events();
523 $this->assertCount(1, $events);
524 $this->assertInstanceOf('\core\event\message_sent', $events[0]);
525 $eventsink->clear();
526 $user2->emailstop = '0';
528 // Will always use the pop-up processor.
529 set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'email', $user2);
531 $message = new \core\message\message();
532 $message->courseid = 1;
533 $message->component = 'moodle';
534 $message->name = 'instantmessage';
535 $message->userfrom = $user1;
536 $message->userto = $user2;
537 $message->subject = 'message subject 1';
538 $message->fullmessage = 'message body';
539 $message->fullmessageformat = FORMAT_MARKDOWN;
540 $message->fullmessagehtml = '<p>message body</p>';
541 $message->smallmessage = 'small message';
542 $message->notification = '0';
544 $messageid = message_send($message);
545 $emails = $sink->get_messages();
546 $this->assertCount(1, $emails);
547 $email = reset($emails);
548 $savedmessage = $DB->get_record('messages', array('id' => $messageid), '*', MUST_EXIST);
549 $this->assertSame($user1->email, $email->from);
550 $this->assertSame($user2->email, $email->to);
551 $this->assertSame($message->subject, $email->subject);
552 $this->assertNotEmpty($email->header);
553 $this->assertNotEmpty($email->body);
554 $sink->clear();
555 $this->assertFalse($DB->record_exists('message_user_actions', array()));
556 $DB->delete_records('message_user_actions', array());
557 $events = $eventsink->get_events();
558 $this->assertCount(1, $events);
559 $this->assertInstanceOf('\core\event\message_sent', $events[0]);
560 $eventsink->clear();
562 set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'email,popup', $user2);
564 $message = new \core\message\message();
565 $message->courseid = 1;
566 $message->component = 'moodle';
567 $message->name = 'instantmessage';
568 $message->userfrom = $user1;
569 $message->userto = $user2;
570 $message->subject = 'message subject 1';
571 $message->fullmessage = 'message body';
572 $message->fullmessageformat = FORMAT_MARKDOWN;
573 $message->fullmessagehtml = '<p>message body</p>';
574 $message->smallmessage = 'small message';
575 $message->notification = '0';
577 $messageid = message_send($message);
578 $emails = $sink->get_messages();
579 $this->assertCount(1, $emails);
580 $email = reset($emails);
581 $savedmessage = $DB->get_record('messages', array('id' => $messageid), '*', MUST_EXIST);
582 $this->assertSame($user1->email, $email->from);
583 $this->assertSame($user2->email, $email->to);
584 $this->assertSame($message->subject, $email->subject);
585 $this->assertNotEmpty($email->header);
586 $this->assertNotEmpty($email->body);
587 $sink->clear();
588 $this->assertFalse($DB->record_exists('message_user_actions', array()));
589 $DB->delete_records('messages', array());
590 $DB->delete_records('message_user_actions', array());
591 $events = $eventsink->get_events();
592 $this->assertCount(1, $events);
593 $this->assertInstanceOf('\core\event\message_sent', $events[0]);
594 $eventsink->clear();
596 set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'popup', $user2);
598 $message = new \core\message\message();
599 $message->courseid = 1;
600 $message->component = 'moodle';
601 $message->name = 'instantmessage';
602 $message->userfrom = $user1;
603 $message->userto = $user2;
604 $message->subject = 'message subject 1';
605 $message->fullmessage = 'message body';
606 $message->fullmessageformat = FORMAT_MARKDOWN;
607 $message->fullmessagehtml = '<p>message body</p>';
608 $message->smallmessage = 'small message';
609 $message->notification = '0';
611 $messageid = message_send($message);
612 $emails = $sink->get_messages();
613 $this->assertCount(0, $emails);
614 $savedmessage = $DB->get_record('messages', array('id' => $messageid), '*', MUST_EXIST);
615 $sink->clear();
616 $this->assertFalse($DB->record_exists('message_user_actions', array()));
617 $DB->delete_records('messages', array());
618 $events = $eventsink->get_events();
619 $this->assertCount(1, $events);
620 $this->assertInstanceOf('\core\event\message_sent', $events[0]);
621 $eventsink->clear();
623 $this->assertFalse($DB->is_transaction_started());
624 $transaction = $DB->start_delegated_transaction();
625 if (!$DB->is_transaction_started()) {
626 $this->markTestSkipped('Databases that do not support transactions should not be used at all!');
628 $transaction->allow_commit();
630 // Will always use the pop-up processor.
631 set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'none', $user2);
633 $message = new \core\message\message();
634 $message->courseid = 1;
635 $message->component = 'moodle';
636 $message->name = 'instantmessage';
637 $message->userfrom = $user1;
638 $message->userto = $user2;
639 $message->subject = 'message subject 1';
640 $message->fullmessage = 'message body';
641 $message->fullmessageformat = FORMAT_MARKDOWN;
642 $message->fullmessagehtml = '<p>message body</p>';
643 $message->smallmessage = 'small message';
644 $message->notification = '0';
646 $transaction = $DB->start_delegated_transaction();
647 $sink = $this->redirectEmails();
648 $messageid = message_send($message);
649 $emails = $sink->get_messages();
650 $this->assertCount(0, $emails);
651 $savedmessage = $DB->get_record('messages', array('id' => $messageid), '*', MUST_EXIST);
652 $sink->clear();
653 $this->assertFalse($DB->record_exists('message_user_actions', array()));
654 $DB->delete_records('messages', array());
655 $events = $eventsink->get_events();
656 $this->assertCount(0, $events);
657 $eventsink->clear();
658 $transaction->allow_commit();
659 $events = $eventsink->get_events();
660 $this->assertCount(1, $events);
661 $this->assertInstanceOf('\core\event\message_sent', $events[0]);
663 // Will always use the pop-up processor.
664 set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'email', $user2);
666 $message = new \core\message\message();
667 $message->courseid = 1;
668 $message->component = 'moodle';
669 $message->name = 'instantmessage';
670 $message->userfrom = $user1;
671 $message->userto = $user2;
672 $message->subject = 'message subject 1';
673 $message->fullmessage = 'message body';
674 $message->fullmessageformat = FORMAT_MARKDOWN;
675 $message->fullmessagehtml = '<p>message body</p>';
676 $message->smallmessage = 'small message';
677 $message->notification = '0';
679 $transaction = $DB->start_delegated_transaction();
680 $sink = $this->redirectEmails();
681 $messageid = message_send($message);
682 $emails = $sink->get_messages();
683 $this->assertCount(0, $emails);
684 $savedmessage = $DB->get_record('messages', array('id' => $messageid), '*', MUST_EXIST);
685 $sink->clear();
686 $this->assertFalse($DB->record_exists('message_user_actions', array()));
687 $events = $eventsink->get_events();
688 $this->assertCount(1, $events);
689 $this->assertInstanceOf('\core\event\message_sent', $events[0]);
690 $transaction->allow_commit();
691 $events = $eventsink->get_events();
692 $this->assertCount(2, $events);
693 $this->assertInstanceOf('\core\event\message_sent', $events[1]);
694 $eventsink->clear();
696 $transaction = $DB->start_delegated_transaction();
697 message_send($message);
698 message_send($message);
699 $this->assertCount(3, $DB->get_records('messages'));
700 $this->assertFalse($DB->record_exists('message_user_actions', array()));
701 $events = $eventsink->get_events();
702 $this->assertCount(0, $events);
703 $transaction->allow_commit();
704 $events = $eventsink->get_events();
705 $this->assertCount(2, $events);
706 $this->assertInstanceOf('\core\event\message_sent', $events[0]);
707 $this->assertInstanceOf('\core\event\message_sent', $events[1]);
708 $eventsink->clear();
709 $DB->delete_records('messages', array());
711 $transaction = $DB->start_delegated_transaction();
712 message_send($message);
713 message_send($message);
714 $this->assertCount(2, $DB->get_records('messages'));
715 $this->assertCount(0, $DB->get_records('message_user_actions'));
716 $events = $eventsink->get_events();
717 $this->assertCount(0, $events);
718 try {
719 $transaction->rollback(new Exception('ignore'));
720 } catch (Exception $e) {
721 $this->assertSame('ignore', $e->getMessage());
723 $events = $eventsink->get_events();
724 $this->assertCount(0, $events);
725 $this->assertCount(0, $DB->get_records('messages'));
726 message_send($message);
727 $this->assertCount(1, $DB->get_records('messages'));
728 $this->assertCount(0, $DB->get_records('message_user_actions'));
729 $events = $eventsink->get_events();
730 $this->assertCount(1, $events);
731 $this->assertInstanceOf('\core\event\message_sent', $events[0]);
732 $sink->clear();
735 public function test_rollback() {
736 global $DB;
738 $this->resetAfterTest();
739 $this->preventResetByRollback();
741 $user1 = $this->getDataGenerator()->create_user();
742 $user2 = $this->getDataGenerator()->create_user();
744 $message = new \core\message\message();
745 $message->courseid = 1;
746 $message->component = 'moodle';
747 $message->name = 'instantmessage';
748 $message->userfrom = $user1;
749 $message->userto = $user2;
750 $message->subject = 'message subject 1';
751 $message->fullmessage = 'message body';
752 $message->fullmessageformat = FORMAT_MARKDOWN;
753 $message->fullmessagehtml = '<p>message body</p>';
754 $message->smallmessage = 'small message';
755 $message->notification = '0';
757 $mailsink = $this->redirectEmails();
759 // Sending outside of a transaction is fine.
760 message_send($message);
761 $this->assertEquals(1, $mailsink->count());
763 $transaction1 = $DB->start_delegated_transaction();
765 $mailsink->clear();
766 message_send($message);
767 $this->assertEquals(0, $mailsink->count());
769 $transaction2 = $DB->start_delegated_transaction();
771 $mailsink->clear();
772 message_send($message);
773 $this->assertEquals(0, $mailsink->count());
775 try {
776 $transaction2->rollback(new Exception('x'));
777 $this->fail('Expecting exception');
778 } catch (Exception $e) {}
779 $this->assertDebuggingNotCalled();
780 $this->assertEquals(0, $mailsink->count());
782 $this->assertTrue($DB->is_transaction_started());
784 try {
785 $transaction1->rollback(new Exception('x'));
786 $this->fail('Expecting exception');
787 } catch (Exception $e) {}
788 $this->assertDebuggingNotCalled();
789 $this->assertEquals(0, $mailsink->count());
791 $this->assertFalse($DB->is_transaction_started());
793 message_send($message);
794 $this->assertEquals(1, $mailsink->count());
797 public function test_forced_rollback() {
798 global $DB;
800 $this->resetAfterTest();
801 $this->preventResetByRollback();
802 set_config('noemailever', 1);
804 $user1 = $this->getDataGenerator()->create_user();
805 $user2 = $this->getDataGenerator()->create_user();
807 $message = new \core\message\message();
808 $message->courseid = 1;
809 $message->component = 'moodle';
810 $message->name = 'instantmessage';
811 $message->userfrom = $user1;
812 $message->userto = $user2;
813 $message->subject = 'message subject 1';
814 $message->fullmessage = 'message body';
815 $message->fullmessageformat = FORMAT_MARKDOWN;
816 $message->fullmessagehtml = '<p>message body</p>';
817 $message->smallmessage = 'small message';
818 $message->notification = '0';
820 message_send($message);
821 $this->assertDebuggingCalled('Not sending email due to $CFG->noemailever config setting');
823 $transaction1 = $DB->start_delegated_transaction();
825 message_send($message);
826 $this->assertDebuggingNotCalled();
828 $transaction2 = $DB->start_delegated_transaction();
830 message_send($message);
831 $this->assertDebuggingNotCalled();
833 $DB->force_transaction_rollback();
834 $this->assertFalse($DB->is_transaction_started());
835 $this->assertDebuggingNotCalled();
837 message_send($message);
838 $this->assertDebuggingCalled('Not sending email due to $CFG->noemailever config setting');
841 public function test_message_attachment_send() {
842 global $CFG;
843 $this->preventResetByRollback();
844 $this->resetAfterTest();
846 // Set config setting to allow attachments.
847 $CFG->allowattachments = true;
848 unset_config('noemailever');
850 $user = $this->getDataGenerator()->create_user();
851 $context = context_user::instance($user->id);
853 // Create a test file.
854 $fs = get_file_storage();
855 $filerecord = array(
856 'contextid' => $context->id,
857 'component' => 'core',
858 'filearea' => 'unittest',
859 'itemid' => 99999,
860 'filepath' => '/',
861 'filename' => 'emailtest.txt'
863 $file = $fs->create_file_from_string($filerecord, 'Test content');
865 $message = new \core\message\message();
866 $message->courseid = 1;
867 $message->component = 'moodle';
868 $message->name = 'instantmessage';
869 $message->userfrom = get_admin();
870 $message->userto = $user;
871 $message->subject = 'message subject 1';
872 $message->fullmessage = 'message body';
873 $message->fullmessageformat = FORMAT_MARKDOWN;
874 $message->fullmessagehtml = '<p>message body</p>';
875 $message->smallmessage = 'small message';
876 $message->attachment = $file;
877 $message->attachname = 'emailtest.txt';
878 $message->notification = 0;
880 // Make sure we are redirecting emails.
881 $sink = $this->redirectEmails();
882 message_send($message);
884 // Get the email that we just sent.
885 $emails = $sink->get_messages();
886 $email = reset($emails);
887 $this->assertTrue(strpos($email->body, 'Content-Disposition: attachment;') !== false);
888 $this->assertTrue(strpos($email->body, 'emailtest.txt') !== false);
890 // Check if the stored file still exists after remove the temporary attachment.
891 $storedfileexists = $fs->file_exists($filerecord['contextid'], $filerecord['component'], $filerecord['filearea'],
892 $filerecord['itemid'], $filerecord['filepath'], $filerecord['filename']);
893 $this->assertTrue($storedfileexists);
897 * Is a particular message type in the list of message types.
898 * @param string $component
899 * @param string $name a message name.
900 * @param array $providers as returned by message_get_providers_for_user.
901 * @return bool whether the message type is present.
903 protected function message_type_present($component, $name, $providers) {
904 foreach ($providers as $provider) {
905 if ($provider->component == $component && $provider->name == $name) {
906 return true;
909 return false;