6 namespace Friendica\Test\legacy;
9 use Friendica\Core\ACL;
10 use Friendica\Core\Config\Capability\IManageConfigValues;
12 use Friendica\Module\BaseApi;
13 use Friendica\Security\BasicAuth;
14 use Friendica\Test\FixtureTest;
15 use Friendica\Util\Arrays;
16 use Friendica\Util\DateTimeFormat;
17 use Monolog\Handler\TestHandler;
19 require_once __DIR__ . '/../../include/api.php';
22 * Tests for the API functions.
24 * Functions that use header() need to be tested in a separate process.
25 * @see https://phpunit.de/manual/5.7/en/appendixes.annotations.html#appendixes.annotations.runTestsInSeparateProcesses
27 * @backupGlobals enabled
29 class ApiTest extends FixtureTest
32 * @var TestHandler Can handle log-outputs
39 protected $friendUser;
43 protected $wrongUserId;
48 /** @var IManageConfigValues */
52 * Create variables used by tests.
54 protected function setUp() : void
56 global $API, $called_api;
62 /** @var IManageConfigValues $config */
63 $this->config = $this->dice->create(IManageConfigValues::class);
65 $this->config->set('system', 'url', 'http://localhost');
66 $this->config->set('system', 'hostname', 'localhost');
67 $this->config->set('system', 'worker_dont_fork', true);
70 $this->config->set('config', 'hostname', 'localhost');
71 $this->config->set('system', 'throttle_limit_day', 100);
72 $this->config->set('system', 'throttle_limit_week', 100);
73 $this->config->set('system', 'throttle_limit_month', 100);
74 $this->config->set('system', 'theme', 'system_theme');
78 $this->app = DI::app();
80 DI::args()->setArgc(1);
82 // User data that the test database is populated with
85 'name' => 'Self contact',
86 'nick' => 'selfcontact',
87 'nurl' => 'http://localhost/profile/selfcontact'
91 'name' => 'Friend contact',
92 'nick' => 'friendcontact',
93 'nurl' => 'http://localhost/profile/friendcontact'
97 'name' => 'othercontact',
98 'nick' => 'othercontact',
99 'nurl' => 'http://localhost/profile/othercontact'
102 // User ID that we know is not in the database
103 $this->wrongUserId = 666;
105 DI::session()->start();
107 // Most API require login so we force the session
109 'authenticated' => true,
110 'uid' => $this->selfUser['id']
112 BasicAuth::setCurrentUserID($this->selfUser['id']);
116 * Assert that a list array contains expected keys.
118 * @param array $list List array
122 private function assertList(array $list = [])
124 self::assertIsString($list['name']);
125 self::assertIsInt($list['id']);
126 self::assertIsString('string', $list['id_str']);
127 self::assertContains($list['mode'], ['public', 'private']);
128 // We could probably do more checks here.
132 * Assert that the string is XML and contain the root element.
134 * @param string $result XML string
135 * @param string $root_element Root element name
139 private function assertXml($result = '', $root_element = '')
141 self::assertStringStartsWith('<?xml version="1.0"?>', $result);
142 self::assertStringContainsString('<' . $root_element, $result);
143 // We could probably do more checks here.
147 * Test the api_user() function.
151 public function testApiUser()
153 self::assertEquals($this->selfUser['id'], BaseApi::getCurrentUserID());
159 * Test the api_source() function.
163 public function testApiSource()
165 self::assertEquals('api', BasicAuth::getCurrentApplicationToken()['name']);
169 * Test the api_source() function with a Twidere user agent.
173 public function testApiSourceWithTwidere()
175 $_SERVER['HTTP_USER_AGENT'] = 'Twidere';
176 self::assertEquals('Twidere', BasicAuth::getCurrentApplicationToken()['name']);
180 * Test the api_source() function with a GET parameter.
184 public function testApiSourceWithGet()
186 $_REQUEST['source'] = 'source_name';
187 self::assertEquals('source_name', BasicAuth::getCurrentApplicationToken()['name']);
191 * Test the api_date() function.
195 public function testApiDate()
197 self::assertEquals('Wed Oct 10 00:00:00 +0000 1990', DateTimeFormat::utc('1990-10-10', DateTimeFormat::API));
201 * Test the api_register_func() function.
205 public function testApiRegisterFunc()
217 self::assertTrue(is_callable($API['api_path']['func']));
221 * Test the BasicAuth::getCurrentUserID() function without any login.
223 * @runInSeparateProcess
224 * @preserveGlobalState disabled
225 * @preserveGlobalState disabled
227 public function testApiLoginWithoutLogin()
229 BasicAuth::setCurrentUserID();
230 $this->expectException(\Friendica\Network\HTTPException\UnauthorizedException::class);
231 BasicAuth::getCurrentUserID(true);
235 * Test the BasicAuth::getCurrentUserID() function with a bad login.
237 * @runInSeparateProcess
238 * @preserveGlobalState disabled
239 * @preserveGlobalState disabled
241 public function testApiLoginWithBadLogin()
243 BasicAuth::setCurrentUserID();
244 $this->expectException(\Friendica\Network\HTTPException\UnauthorizedException::class);
245 $_SERVER['PHP_AUTH_USER'] = 'user@server';
246 BasicAuth::getCurrentUserID(true);
250 * Test the BasicAuth::getCurrentUserID() function with oAuth.
254 public function testApiLoginWithOauth()
256 $this->markTestIncomplete('Can we test this easily?');
260 * Test the BasicAuth::getCurrentUserID() function with authentication provided by an addon.
264 public function testApiLoginWithAddonAuth()
266 $this->markTestIncomplete('Can we test this easily?');
270 * Test the BasicAuth::getCurrentUserID() function with a correct login.
272 * @runInSeparateProcess
273 * @preserveGlobalState disabled
274 * @doesNotPerformAssertions
276 public function testApiLoginWithCorrectLogin()
278 BasicAuth::setCurrentUserID();
279 $_SERVER['PHP_AUTH_USER'] = 'Test user';
280 $_SERVER['PHP_AUTH_PW'] = 'password';
281 BasicAuth::getCurrentUserID(true);
285 * Test the BasicAuth::getCurrentUserID() function with a remote user.
287 * @runInSeparateProcess
288 * @preserveGlobalState disabled
290 public function testApiLoginWithRemoteUser()
292 BasicAuth::setCurrentUserID();
293 $this->expectException(\Friendica\Network\HTTPException\UnauthorizedException::class);
294 $_SERVER['REDIRECT_REMOTE_USER'] = '123456dXNlcjpwYXNzd29yZA==';
295 BasicAuth::getCurrentUserID(true);
299 * Test the api_call() function.
301 * @runInSeparateProcess
302 * @preserveGlobalState disabled
304 public function testApiCall()
308 'method' => 'method',
309 'func' => function () {
310 return ['data' => ['some_data']];
313 $_SERVER['REQUEST_METHOD'] = 'method';
314 $_SERVER['QUERY_STRING'] = 'pagename=api_path';
315 $_GET['callback'] = 'callback_name';
318 'callback_name(["some_data"])',
319 api_call('api_path', 'json')
324 * Test the api_call() function with the profiled enabled.
326 * @runInSeparateProcess
327 * @preserveGlobalState disabled
329 public function testApiCallWithProfiler()
333 'method' => 'method',
334 'func' => function () {
335 return ['data' => ['some_data']];
339 $_SERVER['REQUEST_METHOD'] = 'method';
340 $_SERVER['QUERY_STRING'] = 'pagename=api_path';
342 $this->config->set('system', 'profiler', true);
343 $this->config->set('rendertime', 'callstack', true);
344 $this->app->callstack = [
345 'database' => ['some_function' => 200],
346 'database_write' => ['some_function' => 200],
347 'cache' => ['some_function' => 200],
348 'cache_write' => ['some_function' => 200],
349 'network' => ['some_function' => 200]
354 api_call('api_path', 'json')
359 * Test the api_call() function with a JSON result.
361 * @runInSeparateProcess
362 * @preserveGlobalState disabled
364 public function testApiCallWithJson()
368 'method' => 'method',
369 'func' => function () {
370 return ['data' => ['some_data']];
373 $_SERVER['REQUEST_METHOD'] = 'method';
374 $_SERVER['QUERY_STRING'] = 'pagename=api_path.json';
378 api_call('api_path.json', 'json')
383 * Test the api_call() function with an XML result.
385 * @runInSeparateProcess
386 * @preserveGlobalState disabled
388 public function testApiCallWithXml()
392 'method' => 'method',
393 'func' => function () {
397 $_SERVER['REQUEST_METHOD'] = 'method';
398 $_SERVER['QUERY_STRING'] = 'pagename=api_path.xml';
400 $args = DI::args()->determine($_SERVER, $_GET);
404 api_call('api_path.xml', 'xml')
409 * Test the api_call() function with an RSS result.
411 * @runInSeparateProcess
412 * @preserveGlobalState disabled
414 public function testApiCallWithRss()
418 'method' => 'method',
419 'func' => function () {
423 $_SERVER['REQUEST_METHOD'] = 'method';
424 $_SERVER['QUERY_STRING'] = 'pagename=api_path.rss';
427 '<?xml version="1.0" encoding="UTF-8"?>' . "\n" .
429 api_call('api_path.rss', 'rss')
434 * Test the api_call() function with an Atom result.
436 * @runInSeparateProcess
437 * @preserveGlobalState disabled
439 public function testApiCallWithAtom()
443 'method' => 'method',
444 'func' => function () {
448 $_SERVER['REQUEST_METHOD'] = 'method';
449 $_SERVER['QUERY_STRING'] = 'pagename=api_path.atom';
452 '<?xml version="1.0" encoding="UTF-8"?>' . "\n" .
454 api_call('api_path.atom', 'atom')
459 * Test the Arrays::walkRecursive() function.
463 public function testApiWalkRecursive()
468 Arrays::walkRecursive(
471 // Should we test this with a callback that actually does something?
479 * Test the Arrays::walkRecursive() function with an array.
483 public function testApiWalkRecursiveWithArray()
485 $array = [['item1'], ['item2']];
488 Arrays::walkRecursive(
491 // Should we test this with a callback that actually does something?
499 * Test the api_lists_list() function.
503 public function testApiListsList()
505 $result = api_lists_list('json');
506 self::assertEquals(['lists_list' => []], $result);
510 * Test the api_lists_ownerships() function.
514 public function testApiListsOwnerships()
516 $result = api_lists_ownerships('json');
517 foreach ($result['lists']['lists'] as $list) {
518 self::assertList($list);
523 * Test the api_lists_ownerships() function without an authenticated user.
527 public function testApiListsOwnershipsWithoutAuthenticatedUser()
529 $this->expectException(\Friendica\Network\HTTPException\UnauthorizedException::class);
530 BasicAuth::setCurrentUserID();
531 $_SESSION['authenticated'] = false;
532 api_lists_ownerships('json');
536 * Test the api_fr_photos_list() function.
540 public function testApiFrPhotosList()
542 $result = api_fr_photos_list('json');
543 self::assertArrayHasKey('photo', $result);
547 * Test the api_fr_photos_list() function without an authenticated user.
551 public function testApiFrPhotosListWithoutAuthenticatedUser()
553 $this->expectException(\Friendica\Network\HTTPException\UnauthorizedException::class);
554 BasicAuth::setCurrentUserID();
555 $_SESSION['authenticated'] = false;
556 api_fr_photos_list('json');
560 * Test the api_fr_photo_create_update() function.
562 public function testApiFrPhotoCreateUpdate()
564 $this->expectException(\Friendica\Network\HTTPException\BadRequestException::class);
565 api_fr_photo_create_update('json');
569 * Test the api_fr_photo_create_update() function without an authenticated user.
573 public function testApiFrPhotoCreateUpdateWithoutAuthenticatedUser()
575 $this->expectException(\Friendica\Network\HTTPException\UnauthorizedException::class);
576 BasicAuth::setCurrentUserID();
577 $_SESSION['authenticated'] = false;
578 api_fr_photo_create_update('json');
582 * Test the api_fr_photo_create_update() function with an album name.
586 public function testApiFrPhotoCreateUpdateWithAlbum()
588 $this->expectException(\Friendica\Network\HTTPException\BadRequestException::class);
589 $_REQUEST['album'] = 'album_name';
590 api_fr_photo_create_update('json');
594 * Test the api_fr_photo_create_update() function with the update mode.
598 public function testApiFrPhotoCreateUpdateWithUpdate()
600 $this->markTestIncomplete('We need to create a dataset for this');
604 * Test the api_fr_photo_create_update() function with an uploaded file.
608 public function testApiFrPhotoCreateUpdateWithFile()
610 $this->markTestIncomplete();
614 * Test the api_fr_photo_detail() function.
618 public function testApiFrPhotoDetail()
620 $this->expectException(\Friendica\Network\HTTPException\BadRequestException::class);
621 api_fr_photo_detail('json');
625 * Test the api_fr_photo_detail() function without an authenticated user.
629 public function testApiFrPhotoDetailWithoutAuthenticatedUser()
631 $this->expectException(\Friendica\Network\HTTPException\UnauthorizedException::class);
632 BasicAuth::setCurrentUserID();
633 $_SESSION['authenticated'] = false;
634 api_fr_photo_detail('json');
638 * Test the api_fr_photo_detail() function with a photo ID.
642 public function testApiFrPhotoDetailWithPhotoId()
644 $this->expectException(\Friendica\Network\HTTPException\NotFoundException::class);
645 $_REQUEST['photo_id'] = 1;
646 api_fr_photo_detail('json');
650 * Test the api_fr_photo_detail() function with a correct photo ID.
654 public function testApiFrPhotoDetailCorrectPhotoId()
656 $this->markTestIncomplete('We need to create a dataset for this.');
660 * Test the api_account_update_profile_image() function.
664 public function testApiAccountUpdateProfileImage()
666 $this->expectException(\Friendica\Network\HTTPException\BadRequestException::class);
667 api_account_update_profile_image('json');
671 * Test the api_account_update_profile_image() function without an authenticated user.
675 public function testApiAccountUpdateProfileImageWithoutAuthenticatedUser()
677 $this->expectException(\Friendica\Network\HTTPException\UnauthorizedException::class);
678 BasicAuth::setCurrentUserID();
679 $_SESSION['authenticated'] = false;
680 api_account_update_profile_image('json');
684 * Test the api_account_update_profile_image() function with an uploaded file.
688 public function testApiAccountUpdateProfileImageWithUpload()
690 $this->expectException(\Friendica\Network\HTTPException\BadRequestException::class);
691 $this->markTestIncomplete();
695 * Test the save_media_to_database() function.
699 public function testSaveMediaToDatabase()
701 $this->markTestIncomplete();
705 * Test the post_photo_item() function.
709 public function testPostPhotoItem()
711 $this->markTestIncomplete();
715 * Test the prepare_photo_data() function.
719 public function testPreparePhotoData()
721 $this->markTestIncomplete();
725 * Test the api_friendica_group_show() function.
729 public function testApiFriendicaGroupShow()
731 $this->markTestIncomplete();
735 * Test the api_lists_destroy() function.
739 public function testApiListsDestroy()
741 $this->markTestIncomplete();
745 * Test the group_create() function.
749 public function testGroupCreate()
751 $this->markTestIncomplete();
755 * Test the api_friendica_group_create() function.
759 public function testApiFriendicaGroupCreate()
761 $this->markTestIncomplete();
765 * Test the api_lists_create() function.
769 public function testApiListsCreate()
771 $this->markTestIncomplete();
775 * Test the api_lists_update() function.
779 public function testApiListsUpdate()
781 $this->markTestIncomplete();