Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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.
13
//
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/>.
16
 
17
namespace core\external\check;
18
 
19
defined('MOODLE_INTERNAL') || die();
20
 
21
use admin_category;
22
use admin_root;
23
use admin_setting_check;
24
use admin_settingpage;
25
use core\check\result;
26
use externallib_advanced_testcase;
27
use required_capability_exception;
28
use context_system;
29
use core\check\access\guestrole;
30
use core\check\check;
31
use core\check\external\get_result_admintree;
32
use core\check\security\passwordpolicy;
33
use ReflectionMethod;
34
 
35
global $CFG;
36
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
37
require_once($CFG->libdir . '/adminlib.php');
38
 
39
/**
40
 * Unit tests check API get_result webservice
41
 *
42
 * @package     core
43
 * @covers      \core\check\external\get_result_admintree
44
 * @author      Matthew Hilton <matthewhilton@catalyst-au.net>
45
 * @copyright   Catalyst IT, 2023
46
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
47
 */
48
class get_result_admintree_test extends externallib_advanced_testcase {
49
 
50
    /**
51
     * Sets up admin tree for the given settings.
52
     *
53
     * @param array $settings array of admin_settings. Each will be placed into a single category, but each on their own page.
54
     * @return admin_root admin root that was created.
55
     */
56
    private function setup_admin_tree(array $settings) {
57
        $root = new admin_root(true);
58
 
59
        $category = new admin_category('testcategory', 'testcategory');
60
        $root->add('root', $category);
61
 
62
        foreach ($settings as $i => $setting) {
63
            $page = new admin_settingpage('testpage_' . $i, 'testpage');
64
            $page->add($setting);
65
            $root->add('testcategory', $page);
66
        }
67
 
68
        return $root;
69
    }
70
 
71
    /**
72
     * Provides values to execute_test
73
     *
74
     * @return array
75
     */
76
    public static function execute_options_provider(): array {
77
        return [
78
            'get check result (ok, no details)' => [
79
                'triggererror' => false,
80
                'check' => new passwordpolicy(),
81
                'includedetails' => false,
82
                'expectedreturn' => [
83
                    'status' => result::OK,
84
                    'summary' => get_string('check_passwordpolicy_ok', 'report_security'),
85
 
86
                    // Note for details and html, null = not returned and anything else will simply check something was returned.
87
                    'details' => null,
88
                    'html' => '',
89
                ],
90
            ],
91
            'get check result (ok, with details)' => [
92
                'triggererror' => false,
93
                'check' => new passwordpolicy(),
94
                'includedetails' => true,
95
                'expectedreturn' => [
96
                    'status' => result::OK,
97
                    'summary' => get_string('check_passwordpolicy_ok', 'report_security'),
98
 
99
                    // Note for details and html, null = not returned and anything else will simply check something was returned.
100
                    'details' => '',
101
                    'html' => '',
102
                ],
103
            ],
104
            'get check result (error, no details)' => [
105
                'triggererror' => true,
106
                'check' => new passwordpolicy(),
107
                'includedetails' => false,
108
                'expectedreturn' => [
109
                    'status' => result::WARNING,
110
                    'summary' => get_string('check_passwordpolicy_error', 'report_security'),
111
 
112
                    // Note for details and html, null = not returned and anything else will simply check something was returned.
113
                    'details' => null,
114
                    'html' => '',
115
                ],
116
            ],
117
            'get check result (error, with details)' => [
118
                'triggererror' => true,
119
                'check' => new passwordpolicy(),
120
                'includedetails' => true,
121
                'expectedreturn' => [
122
                    'status' => result::WARNING,
123
                    'summary' => get_string('check_passwordpolicy_error', 'report_security'),
124
 
125
                    // Note for details and html, null = not returned and anything else will simply check something was returned.
126
                    'details' => '',
127
                    'html' => '',
128
                ],
129
            ],
130
        ];
131
    }
132
 
133
    /**
134
     * Tests the execute function
135
     *
136
     * @param bool $triggererror If the test should setup the conditions so that the check will fail
137
     * @param check $check Check to use
138
     * @param bool $includedetails if details are included
139
     * @param array $expectedreturn an array of key value pairs. For each key, if the value is null it expects the
140
     * webservice to not return it. If it has a value, it checks that that value was inside what was returned from the webservice.
141
     * @dataProvider execute_options_provider
142
     */
143
    public function test_execute_options(bool $triggererror, check $check, bool $includedetails, array $expectedreturn): void {
144
        global $CFG;
145
 
146
        $this->resetAfterTest(true);
147
        $this->setAdminUser();
148
 
149
        // This makes the check we test (password policy) warn or be OK depending on the test.
150
        $CFG->passwordpolicy = $triggererror ? false : true;
151
 
152
        // Add the admin setting.
153
        $checksetting = new admin_setting_check('core/testcheck', $check);
154
        $root = $this->setup_admin_tree([$checksetting]);
155
 
156
        // Execute the ws function.
157
        $this->setAdminUser();
158
        $wsresult = (object) get_result_admintree::execute($checksetting->get_id(), $checksetting->name, $includedetails, $root);
159
 
160
        foreach ($expectedreturn as $key => $expectedvalue) {
161
            // If the expected result is null, ensure the return value was also null.
162
            if (is_null($expectedvalue)) {
163
                $this->assertTrue(empty($wsresult->$key));
164
            }
165
 
166
            // If the expected result is set, ensure it is contained in the return value.
167
            if (!is_null($expectedvalue)) {
168
                $this->assertTrue(!empty($wsresult->$key));
169
                $this->assertStringContainsString($expectedvalue, $wsresult->$key);
170
            }
171
        }
172
    }
173
 
174
    /**
175
     * Provides values to test_find_check_from_settings_tree
176
     *
177
     * @return array
178
     */
179
    public static function find_check_from_setting_tree_provider(): array {
180
        $testsetting1 = new admin_setting_check('testsetting', new passwordpolicy());
181
 
182
        return [
183
            'setting is in tree, correctly linked' => [
184
                'settings' => [
185
                    $testsetting1,
186
                    new admin_setting_check('testsetting2', new guestrole()),
187
                    new admin_setting_check('testsetting3', new guestrole()),
188
                ],
189
                'searchname' => $testsetting1->name,
190
                'searchid' => $testsetting1->get_id(),
191
                'expectedcheck' => passwordpolicy::class,
192
            ],
193
            'setting is not in tree' => [
194
                'settings' => [],
195
                'searchname' => $testsetting1->name,
196
                'searchid' => $testsetting1->get_id(),
197
                'expectedcheck' => '',
198
            ],
199
            'setting in tree, but name has conflict' => [
200
                'settings' => [
201
                    $testsetting1,
202
                    new admin_setting_check('testsetting', new guestrole()),
203
                ],
204
                'searchname' => $testsetting1->name,
205
                'searchid' => $testsetting1->get_id(),
206
 
207
                // Because the two settings have the same name + id, its impossible to tell them apart.
208
                // So the check should not be returned.
209
                'expectedcheck' => '',
210
            ],
211
        ];
212
    }
213
 
214
    /**
215
     * Tests finding the check using the admin tree in various situations.
216
     *
217
     * @param array $settings array of admin_settings to setup
218
     * @param string $searchname name of setting to search for
219
     * @param string $searchid id of setting to search for
220
     * @param string $expectedcheck class name of expected check to be found. If empty, expects that none was found.
221
     * @dataProvider find_check_from_setting_tree_provider
222
     */
223
    public function test_find_check_from_setting_tree(array $settings, string $searchname, string $searchid,
224
        string $expectedcheck): void {
225
        $this->resetAfterTest(true);
226
        $this->setAdminUser();
227
        $root = $this->setup_admin_tree($settings);
228
 
229
        $method = new ReflectionMethod(get_result_admintree::class, 'get_check_from_setting');
230
 
231
        $result = $method->invoke(new get_result_admintree(), $searchid, $searchname, $root);
232
 
233
        if (!empty($expectedcheck)) {
234
            $this->assertInstanceOf($expectedcheck, $result);
235
        } else {
236
            $this->assertEmpty($result);
237
        }
238
    }
239
 
240
    /**
241
     * Provides values to test_capability_check
242
     *
243
     * @return array
244
     */
245
    public static function capability_check_provider(): array {
246
        return [
247
            'has permission' => [
248
                'permission' => CAP_ALLOW,
249
                'expectedexception' => null,
250
            ],
251
            'does not have permission' => [
252
                'permission' => CAP_PROHIBIT,
253
                'expectedexception' => required_capability_exception::class,
254
            ],
255
        ];
256
    }
257
 
258
    /**
259
     * Tests that capabilites are being checked correctly by the webservice.
260
     *
261
     * @param int $permission the permission level to assign the capability to the role for.
262
     * @param string|null $expectedexception Exception class expected, or null if none is expected.
263
     * @dataProvider capability_check_provider
264
     */
265
    public function test_capability_check($permission, $expectedexception): void {
266
        $this->resetAfterTest(true);
267
 
268
        $user = $this->getDataGenerator()->create_user();
269
        $role = $this->getDataGenerator()->create_role();
270
        role_assign($role, $user->id, context_system::instance()->id);
271
        role_change_permission($role, context_system::instance(), 'moodle/site:config', $permission);
272
 
273
        if (!empty($expectedexception)) {
274
            $this->expectException($expectedexception);
275
        }
276
 
277
        // Setup check setting as admin.
278
        $this->setAdminUser();
279
        $checksetting = new admin_setting_check('core/testcheck', new passwordpolicy());
280
        $root = $this->setup_admin_tree([$checksetting]);
281
 
282
        $this->setUser($user);
283
        get_result_admintree::execute($checksetting->get_id(), $checksetting->name, false, $root);
284
    }
285
}