UpdaterTest.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. <?php
  2. require_once 'application/config/ConfigManager.php';
  3. require_once 'tests/Updater/DummyUpdater.php';
  4. /**
  5. * Class UpdaterTest.
  6. * Runs unit tests against the Updater class.
  7. */
  8. class UpdaterTest extends PHPUnit_Framework_TestCase
  9. {
  10. /**
  11. * @var string Path to test datastore.
  12. */
  13. protected static $testDatastore = 'sandbox/datastore.php';
  14. /**
  15. * @var string Config file path (without extension).
  16. */
  17. protected static $configFile = 'tests/utils/config/configJson';
  18. /**
  19. * @var ConfigManager
  20. */
  21. protected $conf;
  22. /**
  23. * Executed before each test.
  24. */
  25. public function setUp()
  26. {
  27. $this->conf = new ConfigManager(self::$configFile);
  28. }
  29. /**
  30. * Test read_updates_file with an empty/missing file.
  31. */
  32. public function testReadEmptyUpdatesFile()
  33. {
  34. $this->assertEquals(array(), read_updates_file(''));
  35. $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt';
  36. touch($updatesFile);
  37. $this->assertEquals(array(), read_updates_file($updatesFile));
  38. unlink($updatesFile);
  39. }
  40. /**
  41. * Test read/write updates file.
  42. */
  43. public function testReadWriteUpdatesFile()
  44. {
  45. $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt';
  46. $updatesMethods = array('m1', 'm2', 'm3');
  47. write_updates_file($updatesFile, $updatesMethods);
  48. $readMethods = read_updates_file($updatesFile);
  49. $this->assertEquals($readMethods, $updatesMethods);
  50. // Update
  51. $updatesMethods[] = 'm4';
  52. write_updates_file($updatesFile, $updatesMethods);
  53. $readMethods = read_updates_file($updatesFile);
  54. $this->assertEquals($readMethods, $updatesMethods);
  55. unlink($updatesFile);
  56. }
  57. /**
  58. * Test errors in write_updates_file(): empty updates file.
  59. *
  60. * @expectedException Exception
  61. * @expectedExceptionMessageRegExp /Updates file path is not set(.*)/
  62. */
  63. public function testWriteEmptyUpdatesFile()
  64. {
  65. write_updates_file('', array('test'));
  66. }
  67. /**
  68. * Test errors in write_updates_file(): not writable updates file.
  69. *
  70. * @expectedException Exception
  71. * @expectedExceptionMessageRegExp /Unable to write(.*)/
  72. */
  73. public function testWriteUpdatesFileNotWritable()
  74. {
  75. $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt';
  76. touch($updatesFile);
  77. chmod($updatesFile, 0444);
  78. try {
  79. @write_updates_file($updatesFile, array('test'));
  80. } catch (Exception $e) {
  81. unlink($updatesFile);
  82. throw $e;
  83. }
  84. }
  85. /**
  86. * Test the update() method, with no update to run.
  87. * 1. Everything already run.
  88. * 2. User is logged out.
  89. */
  90. public function testNoUpdates()
  91. {
  92. $updates = array(
  93. 'updateMethodDummy1',
  94. 'updateMethodDummy2',
  95. 'updateMethodDummy3',
  96. 'updateMethodException',
  97. );
  98. $updater = new DummyUpdater($updates, array(), $this->conf, true);
  99. $this->assertEquals(array(), $updater->update());
  100. $updater = new DummyUpdater(array(), array(), $this->conf, false);
  101. $this->assertEquals(array(), $updater->update());
  102. }
  103. /**
  104. * Test the update() method, with all updates to run (except the failing one).
  105. */
  106. public function testUpdatesFirstTime()
  107. {
  108. $updates = array('updateMethodException',);
  109. $expectedUpdates = array(
  110. 'updateMethodDummy1',
  111. 'updateMethodDummy2',
  112. 'updateMethodDummy3',
  113. );
  114. $updater = new DummyUpdater($updates, array(), $this->conf, true);
  115. $this->assertEquals($expectedUpdates, $updater->update());
  116. }
  117. /**
  118. * Test the update() method, only one update to run.
  119. */
  120. public function testOneUpdate()
  121. {
  122. $updates = array(
  123. 'updateMethodDummy1',
  124. 'updateMethodDummy3',
  125. 'updateMethodException',
  126. );
  127. $expectedUpdate = array('updateMethodDummy2');
  128. $updater = new DummyUpdater($updates, array(), $this->conf, true);
  129. $this->assertEquals($expectedUpdate, $updater->update());
  130. }
  131. /**
  132. * Test Update failed.
  133. *
  134. * @expectedException UpdaterException
  135. */
  136. public function testUpdateFailed()
  137. {
  138. $updates = array(
  139. 'updateMethodDummy1',
  140. 'updateMethodDummy2',
  141. 'updateMethodDummy3',
  142. );
  143. $updater = new DummyUpdater($updates, array(), $this->conf, true);
  144. $updater->update();
  145. }
  146. /**
  147. * Test update mergeDeprecatedConfig:
  148. * 1. init a config file.
  149. * 2. init a options.php file with update value.
  150. * 3. merge.
  151. * 4. check updated value in config file.
  152. */
  153. public function testUpdateMergeDeprecatedConfig()
  154. {
  155. $this->conf->setConfigFile('tests/utils/config/configPhp');
  156. $this->conf->reset();
  157. $optionsFile = 'tests/Updater/options.php';
  158. $options = '<?php
  159. $GLOBALS[\'privateLinkByDefault\'] = true;';
  160. file_put_contents($optionsFile, $options);
  161. // tmp config file.
  162. $this->conf->setConfigFile('tests/Updater/config');
  163. // merge configs
  164. $updater = new Updater(array(), array(), $this->conf, true);
  165. // This writes a new config file in tests/Updater/config.php
  166. $updater->updateMethodMergeDeprecatedConfigFile();
  167. // make sure updated field is changed
  168. $this->conf->reload();
  169. $this->assertTrue($this->conf->get('privacy.default_private_links'));
  170. $this->assertFalse(is_file($optionsFile));
  171. // Delete the generated file.
  172. unlink($this->conf->getConfigFileExt());
  173. }
  174. /**
  175. * Test mergeDeprecatedConfig in without options file.
  176. */
  177. public function testMergeDeprecatedConfigNoFile()
  178. {
  179. $updater = new Updater(array(), array(), $this->conf, true);
  180. $updater->updateMethodMergeDeprecatedConfigFile();
  181. $this->assertEquals('root', $this->conf->get('credentials.login'));
  182. }
  183. /**
  184. * Test renameDashTags update method.
  185. */
  186. public function testRenameDashTags()
  187. {
  188. $refDB = new ReferenceLinkDB();
  189. $refDB->write(self::$testDatastore);
  190. $linkDB = new LinkDB(self::$testDatastore, true, false);
  191. $this->assertEmpty($linkDB->filterSearch(array('searchtags' => 'exclude')));
  192. $updater = new Updater(array(), $linkDB, $this->conf, true);
  193. $updater->updateMethodRenameDashTags();
  194. $this->assertNotEmpty($linkDB->filterSearch(array('searchtags' => 'exclude')));
  195. }
  196. /**
  197. * Convert old PHP config file to JSON config.
  198. */
  199. public function testConfigToJson()
  200. {
  201. $configFile = 'tests/utils/config/configPhp';
  202. $this->conf->setConfigFile($configFile);
  203. $this->conf->reset();
  204. // The ConfigIO is initialized with ConfigPhp.
  205. $this->assertTrue($this->conf->getConfigIO() instanceof ConfigPhp);
  206. $updater = new Updater(array(), array(), $this->conf, false);
  207. $done = $updater->updateMethodConfigToJson();
  208. $this->assertTrue($done);
  209. // The ConfigIO has been updated to ConfigJson.
  210. $this->assertTrue($this->conf->getConfigIO() instanceof ConfigJson);
  211. $this->assertTrue(file_exists($this->conf->getConfigFileExt()));
  212. // Check JSON config data.
  213. $this->conf->reload();
  214. $this->assertEquals('root', $this->conf->get('credentials.login'));
  215. $this->assertEquals('lala', $this->conf->get('redirector.url'));
  216. $this->assertEquals('data/datastore.php', $this->conf->get('resource.datastore'));
  217. $this->assertEquals('1', $this->conf->get('plugins.WALLABAG_VERSION'));
  218. rename($configFile . '.save.php', $configFile . '.php');
  219. unlink($this->conf->getConfigFileExt());
  220. }
  221. /**
  222. * Launch config conversion update with an existing JSON file => nothing to do.
  223. */
  224. public function testConfigToJsonNothingToDo()
  225. {
  226. $filetime = filemtime($this->conf->getConfigFileExt());
  227. $updater = new Updater(array(), array(), $this->conf, false);
  228. $done = $updater->updateMethodConfigToJson();
  229. $this->assertTrue($done);
  230. $expected = filemtime($this->conf->getConfigFileExt());
  231. $this->assertEquals($expected, $filetime);
  232. }
  233. /**
  234. * Test escapeUnescapedConfig with valid data.
  235. */
  236. public function testEscapeConfig()
  237. {
  238. $sandbox = 'sandbox/config';
  239. copy(self::$configFile . '.json.php', $sandbox . '.json.php');
  240. $this->conf = new ConfigManager($sandbox);
  241. $title = '<script>alert("title");</script>';
  242. $headerLink = '<script>alert("header_link");</script>';
  243. $redirectorUrl = '<script>alert("redirector");</script>';
  244. $this->conf->set('general.title', $title);
  245. $this->conf->set('general.header_link', $headerLink);
  246. $this->conf->set('redirector.url', $redirectorUrl);
  247. $updater = new Updater(array(), array(), $this->conf, true);
  248. $done = $updater->updateMethodEscapeUnescapedConfig();
  249. $this->assertTrue($done);
  250. $this->conf->reload();
  251. $this->assertEquals(escape($title), $this->conf->get('general.title'));
  252. $this->assertEquals(escape($headerLink), $this->conf->get('general.header_link'));
  253. $this->assertEquals(escape($redirectorUrl), $this->conf->get('redirector.url'));
  254. unlink($sandbox . '.json.php');
  255. }
  256. /**
  257. * Test updateMethodApiSettings(): create default settings for the API (enabled + secret).
  258. */
  259. public function testUpdateApiSettings()
  260. {
  261. $confFile = 'sandbox/config';
  262. copy(self::$configFile .'.json.php', $confFile .'.json.php');
  263. $conf = new ConfigManager($confFile);
  264. $updater = new Updater(array(), array(), $conf, true);
  265. $this->assertFalse($conf->exists('api.enabled'));
  266. $this->assertFalse($conf->exists('api.secret'));
  267. $updater->updateMethodApiSettings();
  268. $conf->reload();
  269. $this->assertTrue($conf->get('api.enabled'));
  270. $this->assertTrue($conf->exists('api.secret'));
  271. unlink($confFile .'.json.php');
  272. }
  273. /**
  274. * Test updateMethodApiSettings(): already set, do nothing.
  275. */
  276. public function testUpdateApiSettingsNothingToDo()
  277. {
  278. $confFile = 'sandbox/config';
  279. copy(self::$configFile .'.json.php', $confFile .'.json.php');
  280. $conf = new ConfigManager($confFile);
  281. $conf->set('api.enabled', false);
  282. $conf->set('api.secret', '');
  283. $updater = new Updater(array(), array(), $conf, true);
  284. $updater->updateMethodApiSettings();
  285. $this->assertFalse($conf->get('api.enabled'));
  286. $this->assertEmpty($conf->get('api.secret'));
  287. unlink($confFile .'.json.php');
  288. }
  289. /**
  290. * Test updateMethodDatastoreIds().
  291. */
  292. public function testDatastoreIds()
  293. {
  294. $links = array(
  295. '20121206_182539' => array(
  296. 'linkdate' => '20121206_182539',
  297. 'title' => 'Geek and Poke',
  298. 'url' => 'http://geek-and-poke.com/',
  299. 'description' => 'desc',
  300. 'tags' => 'dev cartoon tag1 tag2 tag3 tag4 ',
  301. 'updated' => '20121206_190301',
  302. 'private' => false,
  303. ),
  304. '20121206_172539' => array(
  305. 'linkdate' => '20121206_172539',
  306. 'title' => 'UserFriendly - Samba',
  307. 'url' => 'http://ars.userfriendly.org/cartoons/?id=20010306',
  308. 'description' => '',
  309. 'tags' => 'samba cartoon web',
  310. 'private' => false,
  311. ),
  312. '20121206_142300' => array(
  313. 'linkdate' => '20121206_142300',
  314. 'title' => 'UserFriendly - Web Designer',
  315. 'url' => 'http://ars.userfriendly.org/cartoons/?id=20121206',
  316. 'description' => 'Naming conventions... #private',
  317. 'tags' => 'samba cartoon web',
  318. 'private' => true,
  319. ),
  320. );
  321. $refDB = new ReferenceLinkDB();
  322. $refDB->setLinks($links);
  323. $refDB->write(self::$testDatastore);
  324. $linkDB = new LinkDB(self::$testDatastore, true, false);
  325. $checksum = hash_file('sha1', self::$testDatastore);
  326. $this->conf->set('resource.data_dir', 'sandbox');
  327. $this->conf->set('resource.datastore', self::$testDatastore);
  328. $updater = new Updater(array(), $linkDB, $this->conf, true);
  329. $this->assertTrue($updater->updateMethodDatastoreIds());
  330. $linkDB = new LinkDB(self::$testDatastore, true, false);
  331. $backup = glob($this->conf->get('resource.data_dir') . '/datastore.'. date('YmdH') .'*.php');
  332. $backup = $backup[0];
  333. $this->assertFileExists($backup);
  334. $this->assertEquals($checksum, hash_file('sha1', $backup));
  335. unlink($backup);
  336. $this->assertEquals(3, count($linkDB));
  337. $this->assertTrue(isset($linkDB[0]));
  338. $this->assertFalse(isset($linkDB[0]['linkdate']));
  339. $this->assertEquals(0, $linkDB[0]['id']);
  340. $this->assertEquals('UserFriendly - Web Designer', $linkDB[0]['title']);
  341. $this->assertEquals('http://ars.userfriendly.org/cartoons/?id=20121206', $linkDB[0]['url']);
  342. $this->assertEquals('Naming conventions... #private', $linkDB[0]['description']);
  343. $this->assertEquals('samba cartoon web', $linkDB[0]['tags']);
  344. $this->assertTrue($linkDB[0]['private']);
  345. $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_142300'), $linkDB[0]['created']);
  346. $this->assertTrue(isset($linkDB[1]));
  347. $this->assertFalse(isset($linkDB[1]['linkdate']));
  348. $this->assertEquals(1, $linkDB[1]['id']);
  349. $this->assertEquals('UserFriendly - Samba', $linkDB[1]['title']);
  350. $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_172539'), $linkDB[1]['created']);
  351. $this->assertTrue(isset($linkDB[2]));
  352. $this->assertFalse(isset($linkDB[2]['linkdate']));
  353. $this->assertEquals(2, $linkDB[2]['id']);
  354. $this->assertEquals('Geek and Poke', $linkDB[2]['title']);
  355. $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_182539'), $linkDB[2]['created']);
  356. $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_190301'), $linkDB[2]['updated']);
  357. }
  358. /**
  359. * Test updateMethodDatastoreIds() with the update already applied: nothing to do.
  360. */
  361. public function testDatastoreIdsNothingToDo()
  362. {
  363. $refDB = new ReferenceLinkDB();
  364. $refDB->write(self::$testDatastore);
  365. $linkDB = new LinkDB(self::$testDatastore, true, false);
  366. $this->conf->set('resource.data_dir', 'sandbox');
  367. $this->conf->set('resource.datastore', self::$testDatastore);
  368. $checksum = hash_file('sha1', self::$testDatastore);
  369. $updater = new Updater(array(), $linkDB, $this->conf, true);
  370. $this->assertTrue($updater->updateMethodDatastoreIds());
  371. $this->assertEquals($checksum, hash_file('sha1', self::$testDatastore));
  372. }
  373. }