Files
moodle/message/tests/inbound_test.php
T
Eloy Lafuente (stronk7) 1093256560 MDL-81522 phpunit: Add missing void return type to all tests
While this change is not 100% required now, it's good habit
and we are checking for it since Moodle 4.4.

All the changes in this commit have been applied automatically
using the moodle.PHPUnit.TestReturnType sniff and are, exclusively
adding the ": void" return types when missing.
2024-06-11 12:18:04 +02:00

671 lines
24 KiB
PHP

<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Tests for core_message_inbound to test Variable Envelope Return Path functionality.
*
* @package core_message
* @copyright 2014 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_message;
defined('MOODLE_INTERNAL') || die();
require_once(__DIR__ . '/fixtures/inbound_fixtures.php');
/**
* Tests for core_message_inbound to test Variable Envelope Return Path functionality.
*
* @package core_message
* @copyright 2014 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class inbound_test extends \advanced_testcase {
/**
* Perform setup tasks generic to each test.
* This includes:
* * configuring the messageinbound_mailbox.
*/
public function setUp(): void {
global $CFG;
$this->resetAfterTest(true);
// Setup the default Inbound Message mailbox settings.
$CFG->messageinbound_domain = 'example.com';
$CFG->messageinbound_enabled = true;
// Must be no longer than 15 characters.
$CFG->messageinbound_mailbox = 'moodlemoodle123';
}
/**
* Helper to create a new Inbound Message handler.
*
* @param $handlerclass The class of the handler to create
* @param $enabled Whether the handler should be enabled
* @param $component The component
* @param $namepace The namepace
*/
public function helper_create_handler($handlerclass, $enabled = true, $component = 'core_test', $namespace = '\\core\\test\\') {
global $DB;
$classname = $namespace . $handlerclass;
$record = \core\message\inbound\manager::record_from_handler(new $classname());
$record->component = $component;
$record->enabled = $enabled;
$record->id = $DB->insert_record('messageinbound_handlers', $record);
$handler = core_message_inbound_test_manager::handler_from_record($record);
return $handler;
}
/**
* Test that the enabled check perform as expected.
*/
public function test_is_enabled(): void {
global $CFG;
// First clear all of the settings set in the setUp.
$CFG->messageinbound_domain = null;
$CFG->messageinbound_enabled = null;
$CFG->messageinbound_mailbox = null;
$this->assertFalse(\core\message\inbound\manager::is_enabled());
// Check whether only setting the enabled flag keeps it disabled.
$CFG->messageinbound_enabled = true;
$this->assertFalse(\core\message\inbound\manager::is_enabled());
// Check that the mailbox entry on it's own does not enable Inbound Message handling.
$CFG->messageinbound_mailbox = 'moodlemoodle123';
$CFG->messageinbound_domain = null;
$this->assertFalse(\core\message\inbound\manager::is_enabled());
// And that the domain on it's own does not.
$CFG->messageinbound_domain = 'example.com';
$CFG->messageinbound_mailbox = null;
$this->assertFalse(\core\message\inbound\manager::is_enabled());
// And that an invalid mailbox does not.
$CFG->messageinbound_mailbox = '';
$CFG->messageinbound_domain = 'example.com';
$this->assertFalse(\core\message\inbound\manager::is_enabled());
// And that an invalid domain does not.
$CFG->messageinbound_domain = '';
$CFG->messageinbound_mailbox = 'moodlemoodle123';
$this->assertFalse(\core\message\inbound\manager::is_enabled());
// Finally a test that ensures that all settings correct enables the system.
$CFG->messageinbound_mailbox = 'moodlemoodle123';
$CFG->messageinbound_domain = 'example.com';
$CFG->messageinbound_enabled = true;
$this->assertTrue(\core\message\inbound\manager::is_enabled());
}
/**
* Test that data items conform to RFCs 5231, and 5322 standards for
* addressing, and to RFC 5233 for sub-addressing.
*/
public function test_address_constraints(): void {
$handler = $this->helper_create_handler('handler_one');
// Using the handler created, generate an address for our data entry.
$processor = new core_message_inbound_test_helper();
$processor->set_handler($handler->classname);
// Generate some IDs for the data and generate addresses for them.
$dataids = array(
-1,
0,
42,
1073741823,
2147483647,
);
$user = $this->getDataGenerator()->create_user();
foreach ($dataids as $dataid) {
$processor->set_data($dataid);
$address = $processor->generate($user->id);
$this->assertNotNull($address);
$this->assertTrue(strlen($address) > 0, 'No address generated.');
$this->assertTrue(strpos($address, '@') !== false, 'No domain found.');
$this->assertTrue(strpos($address, '+') !== false, 'No subaddress found.');
// The localpart must be less than 64 characters.
list($localpart) = explode('@', $address);
$this->assertTrue(strlen($localpart) <= 64, 'Localpart section of address too long');
// And the data section should be no more than 48 characters.
list(, $datasection) = explode('+', $localpart);
$this->assertTrue(strlen($datasection) <= 48, 'Data section of address too long');
}
}
/**
* Test that the generated e-mail addresses are sufficiently random by
* testing the multiple handlers, multiple users, and multiple data
* items.
*/
public function test_address_uniqueness(): void {
// Generate a set of handlers. These are in two components, and each
// component has two different generators.
$handlers = array();
$handlers[] = $this->helper_create_handler('handler_one', true, 'core_test');
$handlers[] = $this->helper_create_handler('handler_two', true, 'core_test');
$handlers[] = $this->helper_create_handler('handler_three', true, 'core_test_example');
$handlers[] = $this->helper_create_handler('handler_four', true, 'core_test_example');
// Generate some IDs for the data and generate addresses for them.
$dataids = array(
0,
42,
1073741823,
2147483647,
);
$users = array();
for ($i = 0; $i < 5; $i++) {
$users[] = $this->getDataGenerator()->create_user();
}
// Store the addresses for later comparison.
$addresses = array();
foreach ($handlers as $handler) {
$processor = new core_message_inbound_test_helper();
$processor->set_handler($handler->classname);
// Check each dataid.
foreach ($dataids as $dataid) {
$processor->set_data($dataid);
// Check each user.
foreach ($users as $user) {
$address = $processor->generate($user->id);
$this->assertFalse(isset($addresses[$address]));
$addresses[$address] = true;
}
}
}
}
/**
* Test address parsing of a generated address.
*/
public function test_address_parsing(): void {
$dataid = 42;
// Generate a handler to use for this set of tests.
$handler = $this->helper_create_handler('handler_one');
// And a user.
$user = $this->getDataGenerator()->create_user();
// Using the handler created, generate an address for our data entry.
$processor = new core_message_inbound_test_helper();
$processor->set_handler($handler->classname);
$processor->set_data($dataid);
$address = $processor->generate($user->id);
// We should be able to parse the address.
$parser = new core_message_inbound_test_helper();
$parser->process($address);
$parsedresult = $parser->get_data();
$this->assertEquals($user->id, $parsedresult->userid);
$this->assertEquals($dataid, $parsedresult->datavalue);
$this->assertEquals($dataid, $parsedresult->data->datavalue);
$this->assertEquals($handler->id, $parsedresult->handlerid);
$this->assertEquals($handler->id, $parsedresult->data->handler);
}
/**
* Test address parsing of an address with an unrecognised format.
*/
public function test_address_validation_invalid_format_failure(): void {
// Create test data.
$user = $this->getDataGenerator()->create_user();
$handler = $this->helper_create_handler('handler_one');
$dataid = 42;
$parser = new core_message_inbound_test_helper();
$generator = new core_message_inbound_test_helper();
$generator->set_handler($handler->classname);
// Check that validation fails when no address has been processed.
$result = $parser->validate($user->email);
$this->assertEquals(\core\message\inbound\address_manager::VALIDATION_INVALID_ADDRESS_FORMAT, $result);
// Test that an address without data fails validation.
$parser->process('bob@example.com');
$result = $parser->validate($user->email);
$this->assertEquals(\core\message\inbound\address_manager::VALIDATION_INVALID_ADDRESS_FORMAT, $result);
// Test than address with a subaddress but invalid data fails with VALIDATION_UNKNOWN_DATAKEY.
$parser->process('bob+nodata@example.com');
$result = $parser->validate($user->email);
$this->assertEquals(\core\message\inbound\address_manager::VALIDATION_INVALID_ADDRESS_FORMAT, $result);
}
/**
* Test address parsing of an address with an unknown handler.
*/
public function test_address_validation_unknown_handler(): void {
global $DB;
// Create test data.
$user = $this->getDataGenerator()->create_user();
$handler = $this->helper_create_handler('handler_one');
$dataid = 42;
$parser = new core_message_inbound_test_helper();
$generator = new core_message_inbound_test_helper();
$generator->set_handler($handler->classname);
$generator->set_data($dataid);
$address = $generator->generate($user->id);
// Remove the handler record to invalidate it.
$DB->delete_records('messageinbound_handlers', array(
'id' => $handler->id,
));
$parser->process($address);
$result = $parser->validate($user->email);
$expectedfail = \core\message\inbound\address_manager::VALIDATION_UNKNOWN_HANDLER;
$this->assertEquals($expectedfail, $result & $expectedfail);
}
/**
* Test address parsing of an address with a disabled handler.
*/
public function test_address_validation_disabled_handler(): void {
global $DB;
// Create test data.
$user = $this->getDataGenerator()->create_user();
$handler = $this->helper_create_handler('handler_one');
$dataid = 42;
$parser = new core_message_inbound_test_helper();
$generator = new core_message_inbound_test_helper();
$generator->set_handler($handler->classname);
$generator->set_data($dataid);
$address = $generator->generate($user->id);
// Disable the handler.
$record = \core\message\inbound\manager::record_from_handler($handler);
$record->enabled = false;
$DB->update_record('messageinbound_handlers', $record);
$parser->process($address);
$result = $parser->validate($user->email);
$expectedfail = \core\message\inbound\address_manager::VALIDATION_DISABLED_HANDLER;
$this->assertEquals($expectedfail, $result & $expectedfail);
}
/**
* Test address parsing of an address for an invalid user.
*/
public function test_address_validation_invalid_user(): void {
global $DB;
// Create test data.
$user = $this->getDataGenerator()->create_user();
$handler = $this->helper_create_handler('handler_one');
$dataid = 42;
$parser = new core_message_inbound_test_helper();
$generator = new core_message_inbound_test_helper();
$generator->set_handler($handler->classname);
$generator->set_data($dataid);
$address = $generator->generate(-1);
$parser->process($address);
$result = $parser->validate($user->email);
$expectedfail = \core\message\inbound\address_manager::VALIDATION_UNKNOWN_USER;
$this->assertEquals($expectedfail, $result & $expectedfail);
}
/**
* Test address parsing of an address for a disabled user.
*/
public function test_address_validation_disabled_user(): void {
global $DB;
// Create test data.
$user = $this->getDataGenerator()->create_user();
$handler = $this->helper_create_handler('handler_one');
$dataid = 42;
$parser = new core_message_inbound_test_helper();
$generator = new core_message_inbound_test_helper();
$generator->set_handler($handler->classname);
$generator->set_data($dataid);
$address = $generator->generate($user->id);
// Unconfirm the user.
$user->confirmed = 0;
$DB->update_record('user', $user);
$parser->process($address);
$result = $parser->validate($user->email);
$expectedfail = \core\message\inbound\address_manager::VALIDATION_DISABLED_USER;
$this->assertEquals($expectedfail, $result & $expectedfail);
}
/**
* Test address parsing of an address for an invalid key.
*/
public function test_address_validation_invalid_key(): void {
global $DB;
// Create test data.
$user = $this->getDataGenerator()->create_user();
$handler = $this->helper_create_handler('handler_one');
$dataid = 42;
$parser = new core_message_inbound_test_helper();
$generator = new core_message_inbound_test_helper();
$generator->set_handler($handler->classname);
$generator->set_data($dataid);
$address = $generator->generate($user->id);
// Remove the data record to invalidate it.
$DB->delete_records('messageinbound_datakeys', array(
'handler' => $handler->id,
'datavalue' => $dataid,
));
$parser->process($address);
$result = $parser->validate($user->email);
$expectedfail = \core\message\inbound\address_manager::VALIDATION_UNKNOWN_DATAKEY;
$this->assertEquals($expectedfail, $result & $expectedfail);
}
/**
* Test address parsing of an address for an expired key.
*/
public function test_address_validation_expired_key(): void {
global $DB;
// Create test data.
$user = $this->getDataGenerator()->create_user();
$handler = $this->helper_create_handler('handler_one');
$dataid = 42;
$parser = new core_message_inbound_test_helper();
$generator = new core_message_inbound_test_helper();
$generator->set_handler($handler->classname);
$generator->set_data($dataid);
$address = $generator->generate($user->id);
// Expire the key by setting it's expiry time in the past.
$key = $DB->get_record('messageinbound_datakeys', array(
'handler' => $handler->id,
'datavalue' => $dataid,
));
$key->expires = time() - 3600;
$DB->update_record('messageinbound_datakeys', $key);
$parser->process($address);
$result = $parser->validate($user->email);
$expectedfail = \core\message\inbound\address_manager::VALIDATION_EXPIRED_DATAKEY;
$this->assertEquals($expectedfail, $result & $expectedfail);
}
/**
* Test address parsing of an address for an invalid hash.
*/
public function test_address_validation_invalid_hash(): void {
global $DB;
// Create test data.
$user = $this->getDataGenerator()->create_user();
$handler = $this->helper_create_handler('handler_one');
$dataid = 42;
$parser = new core_message_inbound_test_helper();
$generator = new core_message_inbound_test_helper();
$generator->set_handler($handler->classname);
$generator->set_data($dataid);
$address = $generator->generate($user->id);
// Expire the key by setting it's expiry time in the past.
$key = $DB->get_record('messageinbound_datakeys', array(
'handler' => $handler->id,
'datavalue' => $dataid,
));
$key->datakey = 'invalid value';
$DB->update_record('messageinbound_datakeys', $key);
$parser->process($address);
$result = $parser->validate($user->email);
$expectedfail = \core\message\inbound\address_manager::VALIDATION_INVALID_HASH;
$this->assertEquals($expectedfail, $result & $expectedfail);
}
/**
* Test address parsing of an address for an invalid sender.
*/
public function test_address_validation_invalid_sender(): void {
global $DB;
// Create test data.
$user = $this->getDataGenerator()->create_user();
$handler = $this->helper_create_handler('handler_one');
$dataid = 42;
$parser = new core_message_inbound_test_helper();
$generator = new core_message_inbound_test_helper();
$generator->set_handler($handler->classname);
$generator->set_data($dataid);
$address = $generator->generate($user->id);
$parser->process($address);
$result = $parser->validate('incorrectuser@example.com');
$expectedfail = \core\message\inbound\address_manager::VALIDATION_ADDRESS_MISMATCH;
$this->assertEquals($expectedfail, $result & $expectedfail);
}
/**
* Test address parsing of an address for an address which is correct.
*/
public function test_address_validation_success(): void {
global $DB;
// Create test data.
$user = $this->getDataGenerator()->create_user();
$handler = $this->helper_create_handler('handler_one');
$dataid = 42;
$parser = new core_message_inbound_test_helper();
$generator = new core_message_inbound_test_helper();
$generator->set_handler($handler->classname);
$generator->set_data($dataid);
$address = $generator->generate($user->id);
$parser->process($address);
$result = $parser->validate($user->email);
$this->assertEquals(\core\message\inbound\address_manager::VALIDATION_SUCCESS, $result);
}
/**
* Test that a handler with no default expiration does not have an
* expiration time applied.
*/
public function test_default_hander_expiry_unlimited(): void {
global $DB;
// Set the default expiry of the handler to 0 - no expiration.
$expiration = 0;
// Create test data.
$user = $this->getDataGenerator()->create_user();
$handler = $this->helper_create_handler('handler_one');
$record = \core\message\inbound\manager::record_from_handler($handler);
$record->defaultexpiration = $expiration;
$DB->update_record('messageinbound_handlers', $record);
// Generate an address for the handler.
$dataid = 42;
$generator = new core_message_inbound_test_helper();
$generator->set_handler($handler->classname);
$generator->set_data($dataid);
$address = $generator->generate($user->id);
// Check that the datakey created matches the expirytime.
$key = $DB->get_record('messageinbound_datakeys', array('handler' => $record->id, 'datavalue' => $dataid));
$this->assertNull($key->expires);
}
/**
* Test application of the default expiry on a handler.
*/
public function test_default_hander_expiry_low(): void {
global $DB;
// Set the default expiry of the handler to 60 seconds.
$expiration = 60;
// Create test data.
$user = $this->getDataGenerator()->create_user();
$handler = $this->helper_create_handler('handler_one');
$record = \core\message\inbound\manager::record_from_handler($handler);
$record->defaultexpiration = $expiration;
$DB->update_record('messageinbound_handlers', $record);
// Generate an address for the handler.
$dataid = 42;
$generator = new core_message_inbound_test_helper();
$generator->set_handler($handler->classname);
$generator->set_data($dataid);
$address = $generator->generate($user->id);
// Check that the datakey created matches the expirytime.
$key = $DB->get_record('messageinbound_datakeys', array('handler' => $record->id, 'datavalue' => $dataid));
$this->assertEquals($key->timecreated + $expiration, $key->expires);
}
/**
* Test application of the default expiry on a handler.
*/
public function test_default_hander_expiry_medium(): void {
global $DB;
// Set the default expiry of the handler to 3600 seconds.
$expiration = 3600;
// Create test data.
$user = $this->getDataGenerator()->create_user();
$handler = $this->helper_create_handler('handler_one');
$record = \core\message\inbound\manager::record_from_handler($handler);
$record->defaultexpiration = $expiration;
$DB->update_record('messageinbound_handlers', $record);
// Generate an address for the handler.
$dataid = 42;
$generator = new core_message_inbound_test_helper();
$generator->set_handler($handler->classname);
$generator->set_data($dataid);
$address = $generator->generate($user->id);
// Check that the datakey created matches the expirytime.
$key = $DB->get_record('messageinbound_datakeys', array('handler' => $record->id, 'datavalue' => $dataid));
$this->assertEquals($key->timecreated + $expiration, $key->expires);
}
}
/**
* A helper function for unit testing to expose protected functions in the core_message_inbound API for testing.
*
* @copyright 2014 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_message_inbound_test_helper extends \core\message\inbound\address_manager {
/**
* The validate function.
*
* @param string $address
* @return int
*/
public function validate($address) {
return parent::validate($address);
}
/**
* The get_data function.
*
* @return stdClass
*/
public function get_data() {
return parent::get_data();
}
/**
* The address processor function.
*
* @param string $address
* @return void
*/
public function process($address) {
return parent::process($address);
}
}
/**
* A helper function for unit testing to expose protected functions in the core_message_inbound API for testing.
*
* @copyright 2014 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_message_inbound_test_manager extends \core\message\inbound\manager {
/**
* Helper to fetch make the handler_from_record public for unit testing.
*
* @param $record The handler record to fetch
*/
public static function handler_from_record($record) {
return parent::handler_from_record($record);
}
}