xref: /dokuwiki/_test/tests/Remote/ApiTest.php (revision 1468a1289a0d25e37eb42876e35e2c2efc289a88)
1*1468a128SAndreas Gohr<?php
2*1468a128SAndreas Gohr
3*1468a128SAndreas Gohrnamespace dokuwiki\test\Remote;
4*1468a128SAndreas Gohr
5*1468a128SAndreas Gohruse dokuwiki\Remote\AccessDeniedException;
6*1468a128SAndreas Gohruse dokuwiki\Remote\ApiCall;
7*1468a128SAndreas Gohruse dokuwiki\test\mock\AuthPlugin;
8*1468a128SAndreas Gohruse dokuwiki\Extension\RemotePlugin;
9*1468a128SAndreas Gohruse dokuwiki\Remote\Api;
10*1468a128SAndreas Gohruse dokuwiki\Remote\RemoteException;
11*1468a128SAndreas Gohr
12*1468a128SAndreas Gohrclass ApiTest extends \DokuWikiTest {
13*1468a128SAndreas Gohr
14*1468a128SAndreas Gohr    protected $userinfo;
15*1468a128SAndreas Gohr
16*1468a128SAndreas Gohr    /** @var  Api */
17*1468a128SAndreas Gohr    protected $remote;
18*1468a128SAndreas Gohr
19*1468a128SAndreas Gohr    public function setUp() : void {
20*1468a128SAndreas Gohr        parent::setUp();
21*1468a128SAndreas Gohr        global $plugin_controller;
22*1468a128SAndreas Gohr        global $conf;
23*1468a128SAndreas Gohr        global $USERINFO;
24*1468a128SAndreas Gohr        global $auth;
25*1468a128SAndreas Gohr
26*1468a128SAndreas Gohr        parent::setUp();
27*1468a128SAndreas Gohr
28*1468a128SAndreas Gohr        // mock plugin controller to return our test plugins
29*1468a128SAndreas Gohr        $pluginManager = $this->createMock('dokuwiki\Extension\PluginController');
30*1468a128SAndreas Gohr        $pluginManager->method('getList')->willReturn(array('testplugin', 'testplugin2'));
31*1468a128SAndreas Gohr        $pluginManager->method('load')->willReturnCallback(
32*1468a128SAndreas Gohr            function($type, $plugin) {
33*1468a128SAndreas Gohr                if($plugin == 'testplugin2') {
34*1468a128SAndreas Gohr                    return new remote_plugin_testplugin2();
35*1468a128SAndreas Gohr                } else {
36*1468a128SAndreas Gohr                    return new remote_plugin_testplugin();
37*1468a128SAndreas Gohr                }
38*1468a128SAndreas Gohr            }
39*1468a128SAndreas Gohr        );
40*1468a128SAndreas Gohr        $plugin_controller = $pluginManager;
41*1468a128SAndreas Gohr
42*1468a128SAndreas Gohr        $conf['remote'] = 1;
43*1468a128SAndreas Gohr        $conf['remoteuser'] = '!!not set!!';
44*1468a128SAndreas Gohr        $conf['useacl'] = 0;
45*1468a128SAndreas Gohr
46*1468a128SAndreas Gohr        $this->userinfo = $USERINFO;
47*1468a128SAndreas Gohr        $this->remote = new Api();
48*1468a128SAndreas Gohr
49*1468a128SAndreas Gohr        $auth = new AuthPlugin();
50*1468a128SAndreas Gohr    }
51*1468a128SAndreas Gohr
52*1468a128SAndreas Gohr    public function tearDown() : void {
53*1468a128SAndreas Gohr        global $USERINFO;
54*1468a128SAndreas Gohr        $USERINFO = $this->userinfo;
55*1468a128SAndreas Gohr
56*1468a128SAndreas Gohr    }
57*1468a128SAndreas Gohr
58*1468a128SAndreas Gohr    public function testPluginMethods() {
59*1468a128SAndreas Gohr        $methods = $this->remote->getPluginMethods();
60*1468a128SAndreas Gohr        $actual = array_keys($methods);
61*1468a128SAndreas Gohr        sort($actual);
62*1468a128SAndreas Gohr        $expect = array(
63*1468a128SAndreas Gohr            'plugin.testplugin.method1',
64*1468a128SAndreas Gohr            'plugin.testplugin.method2',
65*1468a128SAndreas Gohr            'plugin.testplugin.methodString',
66*1468a128SAndreas Gohr            'plugin.testplugin.method2ext',
67*1468a128SAndreas Gohr            'plugin.testplugin.publicCall',
68*1468a128SAndreas Gohr
69*1468a128SAndreas Gohr            'plugin.testplugin2.commented'
70*1468a128SAndreas Gohr        );
71*1468a128SAndreas Gohr        sort($expect);
72*1468a128SAndreas Gohr        $this->assertEquals($expect,$actual);
73*1468a128SAndreas Gohr    }
74*1468a128SAndreas Gohr
75*1468a128SAndreas Gohr    public function testPluginDescriptors() {
76*1468a128SAndreas Gohr        $methods = $this->remote->getPluginMethods();
77*1468a128SAndreas Gohr        $this->assertEquals(
78*1468a128SAndreas Gohr            [
79*1468a128SAndreas Gohr                'str' => [
80*1468a128SAndreas Gohr                    'type' => 'string',
81*1468a128SAndreas Gohr                    'description' => 'some more parameter description',
82*1468a128SAndreas Gohr                ],
83*1468a128SAndreas Gohr                'int' => [
84*1468a128SAndreas Gohr                    'type' => 'int',
85*1468a128SAndreas Gohr                    'description' => '',
86*1468a128SAndreas Gohr                ],
87*1468a128SAndreas Gohr                'bool' => [
88*1468a128SAndreas Gohr                    'type' => 'bool',
89*1468a128SAndreas Gohr                    'description' => '',
90*1468a128SAndreas Gohr                ],
91*1468a128SAndreas Gohr                'unknown' => [
92*1468a128SAndreas Gohr                    'type' => 'string',
93*1468a128SAndreas Gohr                    'description' => '',
94*1468a128SAndreas Gohr                ],
95*1468a128SAndreas Gohr            ],
96*1468a128SAndreas Gohr            $methods['plugin.testplugin2.commented']->getArgs()
97*1468a128SAndreas Gohr        );
98*1468a128SAndreas Gohr
99*1468a128SAndreas Gohr        $this->assertEquals(
100*1468a128SAndreas Gohr            [
101*1468a128SAndreas Gohr                'type' => 'array',
102*1468a128SAndreas Gohr                'description' => '',
103*1468a128SAndreas Gohr            ],
104*1468a128SAndreas Gohr            $methods['plugin.testplugin2.commented']->getReturn()
105*1468a128SAndreas Gohr        );
106*1468a128SAndreas Gohr
107*1468a128SAndreas Gohr        $this->assertEquals(0, $methods['plugin.testplugin2.commented']->isPublic());
108*1468a128SAndreas Gohr        $this->assertStringContainsString(
109*1468a128SAndreas Gohr            'This is a dummy method',
110*1468a128SAndreas Gohr            $methods['plugin.testplugin2.commented']->getSummary()
111*1468a128SAndreas Gohr        );
112*1468a128SAndreas Gohr    }
113*1468a128SAndreas Gohr
114*1468a128SAndreas Gohr    public function testHasAccessSuccess()
115*1468a128SAndreas Gohr    {
116*1468a128SAndreas Gohr        global $conf;
117*1468a128SAndreas Gohr        $conf['remoteuser'] = '';
118*1468a128SAndreas Gohr
119*1468a128SAndreas Gohr        $this->remote->ensureAccessIsAllowed(new ApiCall('time'));
120*1468a128SAndreas Gohr        $this->assertTrue(true);
121*1468a128SAndreas Gohr    }
122*1468a128SAndreas Gohr
123*1468a128SAndreas Gohr    public function testHasAccessFailAcl() {
124*1468a128SAndreas Gohr        global $conf;
125*1468a128SAndreas Gohr        $conf['useacl'] = 1;
126*1468a128SAndreas Gohr
127*1468a128SAndreas Gohr        $this->expectException(AccessDeniedException::class);
128*1468a128SAndreas Gohr        $this->remote->ensureAccessIsAllowed(new ApiCall('time'));
129*1468a128SAndreas Gohr    }
130*1468a128SAndreas Gohr
131*1468a128SAndreas Gohr    public function testHasAccessSuccessAclEmptyRemoteUser() {
132*1468a128SAndreas Gohr        global $conf;
133*1468a128SAndreas Gohr        $conf['useacl'] = 1;
134*1468a128SAndreas Gohr        $conf['remoteuser'] = '';
135*1468a128SAndreas Gohr
136*1468a128SAndreas Gohr        $this->remote->ensureAccessIsAllowed(new ApiCall('time'));
137*1468a128SAndreas Gohr        $this->assertTrue(true);
138*1468a128SAndreas Gohr    }
139*1468a128SAndreas Gohr
140*1468a128SAndreas Gohr    public function testHasAccessSuccessAcl() {
141*1468a128SAndreas Gohr        global $conf;
142*1468a128SAndreas Gohr        global $USERINFO;
143*1468a128SAndreas Gohr        $conf['useacl'] = 1;
144*1468a128SAndreas Gohr        $conf['remoteuser'] = '@grp,@grp2';
145*1468a128SAndreas Gohr        $USERINFO['grps'] = array('grp');
146*1468a128SAndreas Gohr
147*1468a128SAndreas Gohr        $this->remote->ensureAccessIsAllowed(new ApiCall('time'));
148*1468a128SAndreas Gohr        $this->assertTrue(true);
149*1468a128SAndreas Gohr    }
150*1468a128SAndreas Gohr
151*1468a128SAndreas Gohr    public function testHasAccessFailAcl2() {
152*1468a128SAndreas Gohr        global $conf;
153*1468a128SAndreas Gohr        global $USERINFO;
154*1468a128SAndreas Gohr        $conf['useacl'] = 1;
155*1468a128SAndreas Gohr        $conf['remoteuser'] = '@grp';
156*1468a128SAndreas Gohr        $USERINFO['grps'] = array('grp1');
157*1468a128SAndreas Gohr
158*1468a128SAndreas Gohr        $this->expectException(AccessDeniedException::class);
159*1468a128SAndreas Gohr        $this->remote->ensureAccessIsAllowed(new ApiCall('time'));
160*1468a128SAndreas Gohr    }
161*1468a128SAndreas Gohr
162*1468a128SAndreas Gohr    public function testIsEnabledFail1() {
163*1468a128SAndreas Gohr        global $conf;
164*1468a128SAndreas Gohr        $conf['remote'] = 0;
165*1468a128SAndreas Gohr        $this->expectException(AccessDeniedException::class);
166*1468a128SAndreas Gohr        $this->remote->ensureApiIsEnabled();
167*1468a128SAndreas Gohr    }
168*1468a128SAndreas Gohr
169*1468a128SAndreas Gohr    public function testIsEnabledFail2() {
170*1468a128SAndreas Gohr        global $conf;
171*1468a128SAndreas Gohr        $conf['remoteuser'] = '!!not set!!';
172*1468a128SAndreas Gohr        $this->expectException(AccessDeniedException::class);
173*1468a128SAndreas Gohr        $this->remote->ensureApiIsEnabled();
174*1468a128SAndreas Gohr    }
175*1468a128SAndreas Gohr
176*1468a128SAndreas Gohr    public function testIsEnabledSuccess() {
177*1468a128SAndreas Gohr        global $conf;
178*1468a128SAndreas Gohr        $conf['remote'] = 1;
179*1468a128SAndreas Gohr        $conf['remoteuser'] = '';
180*1468a128SAndreas Gohr        $this->remote->ensureApiIsEnabled();
181*1468a128SAndreas Gohr        $this->assertTrue(true);
182*1468a128SAndreas Gohr    }
183*1468a128SAndreas Gohr
184*1468a128SAndreas Gohr
185*1468a128SAndreas Gohr    public function testGeneralCoreFunctionWithoutArguments() {
186*1468a128SAndreas Gohr        global $conf;
187*1468a128SAndreas Gohr        global $USERINFO;
188*1468a128SAndreas Gohr        $conf['remote'] = 1;
189*1468a128SAndreas Gohr        $conf['remoteuser'] = '';
190*1468a128SAndreas Gohr        $conf['useacl'] = 1;
191*1468a128SAndreas Gohr        $USERINFO['grps'] = array('grp');
192*1468a128SAndreas Gohr        $remoteApi = new Api();
193*1468a128SAndreas Gohr        $remoteApi->getCoreMethods(new MockApiCore());
194*1468a128SAndreas Gohr
195*1468a128SAndreas Gohr        $this->assertEquals($remoteApi->call('wiki.stringTestMethod'), 'success');
196*1468a128SAndreas Gohr        $this->assertEquals($remoteApi->call('wiki.intTestMethod'), 42);
197*1468a128SAndreas Gohr        $this->assertEquals($remoteApi->call('wiki.floatTestMethod'), 3.14159265);
198*1468a128SAndreas Gohr        $this->assertEquals($remoteApi->call('wiki.dateTestMethod'), 2623452346);
199*1468a128SAndreas Gohr        $this->assertEquals($remoteApi->call('wiki.fileTestMethod'), 'file content');
200*1468a128SAndreas Gohr        $this->assertEquals($remoteApi->call('wiki.voidTestMethod'), null);
201*1468a128SAndreas Gohr    }
202*1468a128SAndreas Gohr
203*1468a128SAndreas Gohr    public function testGeneralCoreFunctionOnArgumentMismatch() {
204*1468a128SAndreas Gohr        global $conf;
205*1468a128SAndreas Gohr        $conf['remote'] = 1;
206*1468a128SAndreas Gohr        $remoteApi = new Api();
207*1468a128SAndreas Gohr        $remoteApi->getCoreMethods(new MockApiCore());
208*1468a128SAndreas Gohr
209*1468a128SAndreas Gohr        try {
210*1468a128SAndreas Gohr            $remoteApi->call('wiki.voidTestMethod', array('something'));
211*1468a128SAndreas Gohr            $this->fail('Expects RemoteException to be raised');
212*1468a128SAndreas Gohr        } catch (RemoteException $th) {
213*1468a128SAndreas Gohr            $this->assertEquals(-32604, $th->getCode());
214*1468a128SAndreas Gohr        }
215*1468a128SAndreas Gohr    }
216*1468a128SAndreas Gohr
217*1468a128SAndreas Gohr    public function testGeneralCoreFunctionWithArguments() {
218*1468a128SAndreas Gohr        global $conf;
219*1468a128SAndreas Gohr        global $USERINFO;
220*1468a128SAndreas Gohr        $conf['remote'] = 1;
221*1468a128SAndreas Gohr        $conf['remoteuser'] = '';
222*1468a128SAndreas Gohr        $conf['useacl'] = 1;
223*1468a128SAndreas Gohr
224*1468a128SAndreas Gohr        $remoteApi = new Api();
225*1468a128SAndreas Gohr        $remoteApi->getCoreMethods(new MockApiCore());
226*1468a128SAndreas Gohr
227*1468a128SAndreas Gohr        $this->assertEquals($remoteApi->call('wiki.oneStringArgMethod', array('string')), 'string');
228*1468a128SAndreas Gohr        $this->assertEquals($remoteApi->call('wiki.twoArgMethod', array('string', 1)), array('string' , 1));
229*1468a128SAndreas Gohr        $this->assertEquals($remoteApi->call('wiki.twoArgWithDefaultArg', array('string')), array('string', 'default'));
230*1468a128SAndreas Gohr        $this->assertEquals($remoteApi->call('wiki.twoArgWithDefaultArg', array('string', 'another')), array('string', 'another'));
231*1468a128SAndreas Gohr    }
232*1468a128SAndreas Gohr
233*1468a128SAndreas Gohr    public function testGeneralCoreFunctionOnArgumentMissing() {
234*1468a128SAndreas Gohr        global $conf;
235*1468a128SAndreas Gohr        $conf['remote'] = 1;
236*1468a128SAndreas Gohr        $conf['remoteuser'] = '';
237*1468a128SAndreas Gohr        $remoteApi = new Api();
238*1468a128SAndreas Gohr        $remoteApi->getCoreMethods(new MockApiCore());
239*1468a128SAndreas Gohr
240*1468a128SAndreas Gohr        try {
241*1468a128SAndreas Gohr            $remoteApi->call('wiki.twoArgWithDefaultArg', array());
242*1468a128SAndreas Gohr            $this->fail('Expects RemoteException to be raised');
243*1468a128SAndreas Gohr        } catch (RemoteException $th) {
244*1468a128SAndreas Gohr            $this->assertEquals(-32603, $th->getCode());
245*1468a128SAndreas Gohr        }
246*1468a128SAndreas Gohr    }
247*1468a128SAndreas Gohr
248*1468a128SAndreas Gohr    public function testPluginCallMethods() {
249*1468a128SAndreas Gohr        global $conf;
250*1468a128SAndreas Gohr        global $USERINFO;
251*1468a128SAndreas Gohr        $conf['remote'] = 1;
252*1468a128SAndreas Gohr        $conf['remoteuser'] = '';
253*1468a128SAndreas Gohr        $conf['useacl'] = 1;
254*1468a128SAndreas Gohr
255*1468a128SAndreas Gohr        $remoteApi = new Api();
256*1468a128SAndreas Gohr        $this->assertEquals($remoteApi->call('plugin.testplugin.method1'), null);
257*1468a128SAndreas Gohr        $this->assertEquals($remoteApi->call('plugin.testplugin.method2', array('string', 7)), array('string', 7, false));
258*1468a128SAndreas Gohr        $this->assertEquals($remoteApi->call('plugin.testplugin.method2ext', array('string', 7, true)), array('string', 7, true));
259*1468a128SAndreas Gohr        $this->assertEquals($remoteApi->call('plugin.testplugin.methodString'), 'success');
260*1468a128SAndreas Gohr    }
261*1468a128SAndreas Gohr
262*1468a128SAndreas Gohr    public function testPluginCallMethodsOnArgumentMissing() {
263*1468a128SAndreas Gohr        global $conf;
264*1468a128SAndreas Gohr        $conf['remote'] = 1;
265*1468a128SAndreas Gohr        $conf['remoteuser'] = '';
266*1468a128SAndreas Gohr        $remoteApi = new Api();
267*1468a128SAndreas Gohr        $remoteApi->getCoreMethods(new MockApiCore());
268*1468a128SAndreas Gohr
269*1468a128SAndreas Gohr        try {
270*1468a128SAndreas Gohr            $remoteApi->call('plugin.testplugin.method2', array());
271*1468a128SAndreas Gohr            $this->fail('Expects RemoteException to be raised');
272*1468a128SAndreas Gohr        } catch (RemoteException $th) {
273*1468a128SAndreas Gohr            $this->assertEquals(-32603, $th->getCode());
274*1468a128SAndreas Gohr        }
275*1468a128SAndreas Gohr    }
276*1468a128SAndreas Gohr
277*1468a128SAndreas Gohr    public function testNotExistingCall() {
278*1468a128SAndreas Gohr        global $conf;
279*1468a128SAndreas Gohr        $conf['remote'] = 1;
280*1468a128SAndreas Gohr        $conf['remoteuser'] = '';
281*1468a128SAndreas Gohr
282*1468a128SAndreas Gohr        $this->expectException(RemoteException::class);
283*1468a128SAndreas Gohr        $this->expectExceptionCode(-32603);
284*1468a128SAndreas Gohr
285*1468a128SAndreas Gohr        $remoteApi = new Api();
286*1468a128SAndreas Gohr        $remoteApi->call('invalid method'); // no '.'
287*1468a128SAndreas Gohr        $remoteApi->call('does.not exist'); // unknown method type
288*1468a128SAndreas Gohr    }
289*1468a128SAndreas Gohr
290*1468a128SAndreas Gohr    public function testPublicCallCore() {
291*1468a128SAndreas Gohr        global $conf;
292*1468a128SAndreas Gohr        $conf['useacl'] = 1;
293*1468a128SAndreas Gohr        $conf['remote'] = 1;
294*1468a128SAndreas Gohr        $conf['remoteuser'] = 'restricted';
295*1468a128SAndreas Gohr        $remoteApi = new Api();
296*1468a128SAndreas Gohr        $remoteApi->getCoreMethods(new MockApiCore());
297*1468a128SAndreas Gohr        $this->assertTrue($remoteApi->call('wiki.publicCall'));
298*1468a128SAndreas Gohr    }
299*1468a128SAndreas Gohr
300*1468a128SAndreas Gohr    public function testPublicCallPlugin() {
301*1468a128SAndreas Gohr        global $conf;
302*1468a128SAndreas Gohr        $conf['useacl'] = 1;
303*1468a128SAndreas Gohr        $conf['remote'] = 1;
304*1468a128SAndreas Gohr        $conf['remoteuser'] = 'restricted';
305*1468a128SAndreas Gohr        $remoteApi = new Api();
306*1468a128SAndreas Gohr        $this->assertTrue($remoteApi->call('plugin.testplugin.publicCall'));
307*1468a128SAndreas Gohr    }
308*1468a128SAndreas Gohr
309*1468a128SAndreas Gohr    public function testPublicCallCoreDeny() {
310*1468a128SAndreas Gohr        global $conf;
311*1468a128SAndreas Gohr        $conf['useacl'] = 1;
312*1468a128SAndreas Gohr        $this->expectException(AccessDeniedException::class);
313*1468a128SAndreas Gohr        $remoteApi = new Api();
314*1468a128SAndreas Gohr        $remoteApi->getCoreMethods(new MockApiCore());
315*1468a128SAndreas Gohr        $remoteApi->call('wiki.stringTestMethod');
316*1468a128SAndreas Gohr    }
317*1468a128SAndreas Gohr
318*1468a128SAndreas Gohr    public function testPublicCallPluginDeny() {
319*1468a128SAndreas Gohr        global $conf;
320*1468a128SAndreas Gohr        $conf['useacl'] = 1;
321*1468a128SAndreas Gohr        $this->expectException(AccessDeniedException::class);
322*1468a128SAndreas Gohr        $remoteApi = new Api();
323*1468a128SAndreas Gohr        $remoteApi->call('plugin.testplugin.methodString');
324*1468a128SAndreas Gohr    }
325*1468a128SAndreas Gohr}
326*1468a128SAndreas Gohr
327*1468a128SAndreas Gohr
328*1468a128SAndreas Gohr
329*1468a128SAndreas Gohr
330*1468a128SAndreas Gohrclass remote_plugin_testplugin extends RemotePlugin {
331*1468a128SAndreas Gohr    function getMethods() {
332*1468a128SAndreas Gohr        $methods = parent::getMethods(); // auto add all methods, then adjust
333*1468a128SAndreas Gohr
334*1468a128SAndreas Gohr        $methods['method2']->limitArgs(['str', 'int']); // skip optional parameter
335*1468a128SAndreas Gohr        $methods['method2ext'] = new ApiCall([$this, 'method2']); // add second call with all params
336*1468a128SAndreas Gohr        $methods['publicCall']->setPublic(); // make this one public
337*1468a128SAndreas Gohr
338*1468a128SAndreas Gohr        return $methods;
339*1468a128SAndreas Gohr    }
340*1468a128SAndreas Gohr
341*1468a128SAndreas Gohr    function method1() { return null; }
342*1468a128SAndreas Gohr    function methodString() { return 'success'; }
343*1468a128SAndreas Gohr    function method2($str, $int, $bool = false) { return array($str, $int, $bool); }
344*1468a128SAndreas Gohr    function publicCall() {return true;}
345*1468a128SAndreas Gohr}
346*1468a128SAndreas Gohr
347*1468a128SAndreas Gohrclass remote_plugin_testplugin2 extends RemotePlugin {
348*1468a128SAndreas Gohr    /**
349*1468a128SAndreas Gohr     * This is a dummy method
350*1468a128SAndreas Gohr     *
351*1468a128SAndreas Gohr     * @param string $str some more parameter description
352*1468a128SAndreas Gohr     * @param int $int
353*1468a128SAndreas Gohr     * @param bool $bool
354*1468a128SAndreas Gohr     * @param Object $unknown
355*1468a128SAndreas Gohr     * @return array
356*1468a128SAndreas Gohr     */
357*1468a128SAndreas Gohr    public function commented($str, $int, $bool, $unknown) { return array($str, $int, $bool); }
358*1468a128SAndreas Gohr
359*1468a128SAndreas Gohr    private function privateMethod() {return true;}
360*1468a128SAndreas Gohr    protected function protectedMethod() {return true;}
361*1468a128SAndreas Gohr    public function _underscore() {return true;}
362*1468a128SAndreas Gohr}
363