aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--application/Config.php27
-rw-r--r--application/LinkDB.php10
-rw-r--r--application/LinkFilter.php1
-rw-r--r--application/Updater.php228
-rw-r--r--index.php80
-rw-r--r--tests/ConfigTest.php42
-rw-r--r--tests/Updater/DummyUpdater.php68
-rw-r--r--tests/Updater/UpdaterTest.php227
8 files changed, 584 insertions, 99 deletions
diff --git a/application/Config.php b/application/Config.php
index 9af5a535..05a59452 100644
--- a/application/Config.php
+++ b/application/Config.php
@@ -174,33 +174,6 @@ function load_plugin_parameter_values($plugins, $config)
174} 174}
175 175
176/** 176/**
177 * Milestone 0.9 - shaarli/Shaarli#41: options.php is not supported anymore.
178 * ==> if user is loggedIn, merge its content with config.php, then delete options.php.
179 *
180 * @param array $config contains all configuration fields.
181 * @param bool $isLoggedIn true if user is logged in.
182 *
183 * @return void
184 */
185function mergeDeprecatedConfig($config, $isLoggedIn)
186{
187 $config_file = $config['config']['CONFIG_FILE'];
188
189 if (is_file($config['config']['DATADIR'].'/options.php') && $isLoggedIn) {
190 include $config['config']['DATADIR'].'/options.php';
191
192 // Load GLOBALS into config
193 foreach ($GLOBALS as $key => $value) {
194 $config[$key] = $value;
195 }
196 $config['config']['CONFIG_FILE'] = $config_file;
197 writeConfig($config, $isLoggedIn);
198
199 unlink($config['config']['DATADIR'].'/options.php');
200 }
201}
202
203/**
204 * Exception used if a mandatory field is missing in given configuration. 177 * Exception used if a mandatory field is missing in given configuration.
205 */ 178 */
206class MissingFieldConfigException extends Exception 179class MissingFieldConfigException extends Exception
diff --git a/application/LinkDB.php b/application/LinkDB.php
index 19ca6435..a95b3f36 100644
--- a/application/LinkDB.php
+++ b/application/LinkDB.php
@@ -260,14 +260,11 @@ You use the community supported version of the original Shaarli project, by Seba
260 } 260 }
261 } 261 }
262 262
263 // Keep the list of the mapping URLs-->linkdate up-to-date.
264 $this->_urls = array(); 263 $this->_urls = array();
265 foreach ($this->_links as $link) { 264 foreach ($this->_links as &$link) {
265 // Keep the list of the mapping URLs-->linkdate up-to-date.
266 $this->_urls[$link['url']] = $link['linkdate']; 266 $this->_urls[$link['url']] = $link['linkdate'];
267 } 267 // Sanitize data fields.
268
269 // Escape links data
270 foreach($this->_links as &$link) {
271 sanitizeLink($link); 268 sanitizeLink($link);
272 // Do not use the redirector for internal links (Shaarli note URL starting with a '?'). 269 // Do not use the redirector for internal links (Shaarli note URL starting with a '?').
273 if (!empty($this->_redirector) && !startsWith($link['url'], '?')) { 270 if (!empty($this->_redirector) && !startsWith($link['url'], '?')) {
@@ -381,6 +378,7 @@ You use the community supported version of the original Shaarli project, by Seba
381 } 378 }
382 $linkDays = array_keys($linkDays); 379 $linkDays = array_keys($linkDays);
383 sort($linkDays); 380 sort($linkDays);
381
384 return $linkDays; 382 return $linkDays;
385 } 383 }
386} 384}
diff --git a/application/LinkFilter.php b/application/LinkFilter.php
index b2e6530f..096d3b04 100644
--- a/application/LinkFilter.php
+++ b/application/LinkFilter.php
@@ -260,7 +260,6 @@ class LinkFilter
260 * Convert a list of tags (str) to an array. Also 260 * Convert a list of tags (str) to an array. Also
261 * - handle case sensitivity. 261 * - handle case sensitivity.
262 * - accepts spaces commas as separator. 262 * - accepts spaces commas as separator.
263 * - remove private tags for loggedout users.
264 * 263 *
265 * @param string $tags string containing a list of tags. 264 * @param string $tags string containing a list of tags.
266 * @param bool $casesensitive will convert everything to lowercase if false. 265 * @param bool $casesensitive will convert everything to lowercase if false.
diff --git a/application/Updater.php b/application/Updater.php
new file mode 100644
index 00000000..20ae0c4d
--- /dev/null
+++ b/application/Updater.php
@@ -0,0 +1,228 @@
1<?php
2
3/**
4 * Class Updater.
5 * Used to update stuff when a new Shaarli's version is reached.
6 * Update methods are ran only once, and the stored in a JSON file.
7 */
8class Updater
9{
10 /**
11 * @var array Updates which are already done.
12 */
13 protected $doneUpdates;
14
15 /**
16 * @var array Shaarli's configuration array.
17 */
18 protected $config;
19
20 /**
21 * @var LinkDB instance.
22 */
23 protected $linkDB;
24
25 /**
26 * @var bool True if the user is logged in, false otherwise.
27 */
28 protected $isLoggedIn;
29
30 /**
31 * @var ReflectionMethod[] List of current class methods.
32 */
33 protected $methods;
34
35 /**
36 * Object constructor.
37 *
38 * @param array $doneUpdates Updates which are already done.
39 * @param array $config Shaarli's configuration array.
40 * @param LinkDB $linkDB LinkDB instance.
41 * @param boolean $isLoggedIn True if the user is logged in.
42 */
43 public function __construct($doneUpdates, $config, $linkDB, $isLoggedIn)
44 {
45 $this->doneUpdates = $doneUpdates;
46 $this->config = $config;
47 $this->linkDB = $linkDB;
48 $this->isLoggedIn = $isLoggedIn;
49
50 // Retrieve all update methods.
51 $class = new ReflectionClass($this);
52 $this->methods = $class->getMethods();
53 }
54
55 /**
56 * Run all new updates.
57 * Update methods have to start with 'updateMethod' and return true (on success).
58 *
59 * @return array An array containing ran updates.
60 *
61 * @throws UpdaterException If something went wrong.
62 */
63 public function update()
64 {
65 $updatesRan = array();
66
67 // If the user isn't logged in, exit without updating.
68 if ($this->isLoggedIn !== true) {
69 return $updatesRan;
70 }
71
72 if ($this->methods == null) {
73 throw new UpdaterException('Couldn\'t retrieve Updater class methods.');
74 }
75
76 foreach ($this->methods as $method) {
77 // Not an update method or already done, pass.
78 if (! startsWith($method->getName(), 'updateMethod')
79 || in_array($method->getName(), $this->doneUpdates)
80 ) {
81 continue;
82 }
83
84 try {
85 $method->setAccessible(true);
86 $res = $method->invoke($this);
87 // Update method must return true to be considered processed.
88 if ($res === true) {
89 $updatesRan[] = $method->getName();
90 }
91 } catch (Exception $e) {
92 throw new UpdaterException($method, $e);
93 }
94 }
95
96 $this->doneUpdates = array_merge($this->doneUpdates, $updatesRan);
97
98 return $updatesRan;
99 }
100
101 /**
102 * @return array Updates methods already processed.
103 */
104 public function getDoneUpdates()
105 {
106 return $this->doneUpdates;
107 }
108
109 /**
110 * Move deprecated options.php to config.php.
111 *
112 * Milestone 0.9 (old versioning) - shaarli/Shaarli#41:
113 * options.php is not supported anymore.
114 */
115 public function updateMethodMergeDeprecatedConfigFile()
116 {
117 $config_file = $this->config['config']['CONFIG_FILE'];
118
119 if (is_file($this->config['config']['DATADIR'].'/options.php')) {
120 include $this->config['config']['DATADIR'].'/options.php';
121
122 // Load GLOBALS into config
123 foreach ($GLOBALS as $key => $value) {
124 $this->config[$key] = $value;
125 }
126 $this->config['config']['CONFIG_FILE'] = $config_file;
127 writeConfig($this->config, $this->isLoggedIn);
128
129 unlink($this->config['config']['DATADIR'].'/options.php');
130 }
131
132 return true;
133 }
134}
135
136/**
137 * Class UpdaterException.
138 */
139class UpdaterException extends Exception
140{
141 /**
142 * @var string Method where the error occurred.
143 */
144 protected $method;
145
146 /**
147 * @var Exception The parent exception.
148 */
149 protected $previous;
150
151 /**
152 * Constructor.
153 *
154 * @param string $message Force the error message if set.
155 * @param string $method Method where the error occurred.
156 * @param Exception|bool $previous Parent exception.
157 */
158 public function __construct($message = '', $method = '', $previous = false)
159 {
160 $this->method = $method;
161 $this->previous = $previous;
162 $this->message = $this->buildMessage($message);
163 }
164
165 /**
166 * Build the exception error message.
167 *
168 * @param string $message Optional given error message.
169 *
170 * @return string The built error message.
171 */
172 private function buildMessage($message)
173 {
174 $out = '';
175 if (! empty($message)) {
176 $out .= $message . PHP_EOL;
177 }
178
179 if (! empty($this->method)) {
180 $out .= 'An error occurred while running the update '. $this->method . PHP_EOL;
181 }
182
183 if (! empty($this->previous)) {
184 $out .= ' '. $this->previous->getMessage();
185 }
186
187 return $out;
188 }
189}
190
191
192/**
193 * Read the updates file, and return already done updates.
194 *
195 * @param string $updatesFilepath Updates file path.
196 *
197 * @return array Already done update methods.
198 */
199function read_updates_file($updatesFilepath)
200{
201 if (! empty($updatesFilepath) && is_file($updatesFilepath)) {
202 $content = file_get_contents($updatesFilepath);
203 if (! empty($content)) {
204 return explode(';', $content);
205 }
206 }
207 return array();
208}
209
210/**
211 * Write updates file.
212 *
213 * @param string $updatesFilepath Updates file path.
214 * @param array $updates Updates array to write.
215 *
216 * @throws Exception Couldn't write version number.
217 */
218function write_updates_file($updatesFilepath, $updates)
219{
220 if (empty($updatesFilepath)) {
221 throw new Exception('Updates file path is not set, can\'t write updates.');
222 }
223
224 $res = file_put_contents($updatesFilepath, implode(';', $updates));
225 if ($res === false) {
226 throw new Exception('Unable to write updates in '. $updatesFilepath . '.');
227 }
228}
diff --git a/index.php b/index.php
index 67290f6f..4382bd80 100644
--- a/index.php
+++ b/index.php
@@ -44,6 +44,9 @@ $GLOBALS['config']['DATASTORE'] = $GLOBALS['config']['DATADIR'].'/datastore.php'
44// Banned IPs 44// Banned IPs
45$GLOBALS['config']['IPBANS_FILENAME'] = $GLOBALS['config']['DATADIR'].'/ipbans.php'; 45$GLOBALS['config']['IPBANS_FILENAME'] = $GLOBALS['config']['DATADIR'].'/ipbans.php';
46 46
47// Processed updates file.
48$GLOBALS['config']['UPDATES_FILE'] = $GLOBALS['config']['DATADIR'].'/updates.txt';
49
47// Access log 50// Access log
48$GLOBALS['config']['LOG_FILE'] = $GLOBALS['config']['DATADIR'].'/log.txt'; 51$GLOBALS['config']['LOG_FILE'] = $GLOBALS['config']['DATADIR'].'/log.txt';
49 52
@@ -64,7 +67,6 @@ $GLOBALS['config']['CACHEDIR'] = 'cache';
64// Atom & RSS feed cache directory 67// Atom & RSS feed cache directory
65$GLOBALS['config']['PAGECACHE'] = 'pagecache'; 68$GLOBALS['config']['PAGECACHE'] = 'pagecache';
66 69
67
68/* 70/*
69 * Global configuration 71 * Global configuration
70 */ 72 */
@@ -163,6 +165,7 @@ require_once 'application/Utils.php';
163require_once 'application/Config.php'; 165require_once 'application/Config.php';
164require_once 'application/PluginManager.php'; 166require_once 'application/PluginManager.php';
165require_once 'application/Router.php'; 167require_once 'application/Router.php';
168require_once 'application/Updater.php';
166 169
167// Ensure the PHP version is supported 170// Ensure the PHP version is supported
168try { 171try {
@@ -1114,6 +1117,25 @@ function renderPage()
1114 $GLOBALS['redirector'] 1117 $GLOBALS['redirector']
1115 ); 1118 );
1116 1119
1120 $updater = new Updater(
1121 read_updates_file($GLOBALS['config']['UPDATES_FILE']),
1122 $GLOBALS,
1123 $LINKSDB,
1124 isLoggedIn()
1125 );
1126 try {
1127 $newUpdates = $updater->update();
1128 if (! empty($newUpdates)) {
1129 write_updates_file(
1130 $GLOBALS['config']['UPDATES_FILE'],
1131 $updater->getDoneUpdates()
1132 );
1133 }
1134 }
1135 catch(Exception $e) {
1136 die($e->getMessage());
1137 }
1138
1117 $PAGE = new pageBuilder; 1139 $PAGE = new pageBuilder;
1118 1140
1119 // Determine which page will be rendered. 1141 // Determine which page will be rendered.
@@ -1530,21 +1552,40 @@ function renderPage()
1530 // -------- User clicked the "Save" button when editing a link: Save link to database. 1552 // -------- User clicked the "Save" button when editing a link: Save link to database.
1531 if (isset($_POST['save_edit'])) 1553 if (isset($_POST['save_edit']))
1532 { 1554 {
1533 if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away! 1555 // Go away!
1534 $tags = trim(preg_replace('/\s\s+/',' ', $_POST['lf_tags'])); // Remove multiple spaces. 1556 if (! tokenOk($_POST['token'])) {
1535 $tags = implode(' ', array_unique(explode(' ', $tags))); // Remove duplicates. 1557 die('Wrong token.');
1536 $linkdate=$_POST['lf_linkdate']; 1558 }
1559 // Remove multiple spaces.
1560 $tags = trim(preg_replace('/\s\s+/', ' ', $_POST['lf_tags']));
1561 // Remove duplicates.
1562 $tags = implode(' ', array_unique(explode(' ', $tags)));
1563 $linkdate = $_POST['lf_linkdate'];
1537 $url = trim($_POST['lf_url']); 1564 $url = trim($_POST['lf_url']);
1538 if (!startsWith($url,'http:') && !startsWith($url,'https:') && !startsWith($url,'ftp:') && !startsWith($url,'magnet:') && !startsWith($url,'?') && !startsWith($url,'javascript:')) 1565 if (! startsWith($url, 'http:') && ! startsWith($url, 'https:')
1539 $url = 'http://'.$url; 1566 && ! startsWith($url, 'ftp:') && ! startsWith($url, 'magnet:')
1540 $link = array('title'=>trim($_POST['lf_title']),'url'=>$url,'description'=>trim($_POST['lf_description']),'private'=>(isset($_POST['lf_private']) ? 1 : 0), 1567 && ! startsWith($url, '?') && ! startsWith($url, 'javascript:')
1541 'linkdate'=>$linkdate,'tags'=>str_replace(',',' ',$tags)); 1568 ) {
1542 if ($link['title']=='') $link['title']=$link['url']; // If title is empty, use the URL as title. 1569 $url = 'http://' . $url;
1570 }
1571
1572 $link = array(
1573 'title' => trim($_POST['lf_title']),
1574 'url' => $url,
1575 'description' => trim($_POST['lf_description']),
1576 'private' => (isset($_POST['lf_private']) ? 1 : 0),
1577 'linkdate' => $linkdate,
1578 'tags' => str_replace(',', ' ', $tags)
1579 );
1580 // If title is empty, use the URL as title.
1581 if ($link['title'] == '') {
1582 $link['title'] = $link['url'];
1583 }
1543 1584
1544 $pluginManager->executeHooks('save_link', $link); 1585 $pluginManager->executeHooks('save_link', $link);
1545 1586
1546 $LINKSDB[$linkdate] = $link; 1587 $LINKSDB[$linkdate] = $link;
1547 $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']); // Save to disk. 1588 $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']);
1548 pubsubhub(); 1589 pubsubhub();
1549 1590
1550 // If we are called from the bookmarklet, we must close the popup: 1591 // If we are called from the bookmarklet, we must close the popup:
@@ -1553,10 +1594,12 @@ function renderPage()
1553 exit; 1594 exit;
1554 } 1595 }
1555 1596
1556 $returnurl = !empty($_POST['returnurl']) ? escape($_POST['returnurl']): '?'; 1597 $returnurl = !empty($_POST['returnurl']) ? $_POST['returnurl'] : '?';
1557 $location = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link')); 1598 $location = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link'));
1558 $location .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited. 1599 // Scroll to the link which has been edited.
1559 header('Location: '. $location); // After saving the link, redirect to the page the user was on. 1600 $location .= '#' . smallHash($_POST['lf_linkdate']);
1601 // After saving the link, redirect to the page the user was on.
1602 header('Location: '. $location);
1560 exit; 1603 exit;
1561 } 1604 }
1562 1605
@@ -2519,15 +2562,6 @@ function resizeImage($filepath)
2519 return true; 2562 return true;
2520} 2563}
2521 2564
2522try {
2523 mergeDeprecatedConfig($GLOBALS, isLoggedIn());
2524} catch(Exception $e) {
2525 error_log(
2526 'ERROR while merging deprecated options.php file.' . PHP_EOL .
2527 $e->getMessage()
2528 );
2529}
2530
2531if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=genthumbnail')) { genThumbnail(); exit; } // Thumbnail generation/cache does not need the link database. 2565if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=genthumbnail')) { genThumbnail(); exit; } // Thumbnail generation/cache does not need the link database.
2532if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=rss')) { showRSS(); exit; } 2566if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=rss')) { showRSS(); exit; }
2533if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=atom')) { showATOM(); exit; } 2567if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=atom')) { showATOM(); exit; }
diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php
index 492ddd3b..7200aae6 100644
--- a/tests/ConfigTest.php
+++ b/tests/ConfigTest.php
@@ -134,48 +134,6 @@ class ConfigTest extends PHPUnit_Framework_TestCase
134 } 134 }
135 135
136 /** 136 /**
137 * Test mergeDeprecatedConfig while being logged in:
138 * 1. init a config file.
139 * 2. init a options.php file with update value.
140 * 3. merge.
141 * 4. check updated value in config file.
142 */
143 public function testMergeDeprecatedConfig()
144 {
145 // init
146 writeConfig(self::$configFields, true);
147 $configCopy = self::$configFields;
148 $invert = !$configCopy['privateLinkByDefault'];
149 $configCopy['privateLinkByDefault'] = $invert;
150
151 // Use writeConfig to create a options.php
152 $configCopy['config']['CONFIG_FILE'] = 'tests/options.php';
153 writeConfig($configCopy, true);
154
155 $this->assertTrue(is_file($configCopy['config']['CONFIG_FILE']));
156
157 // merge configs
158 mergeDeprecatedConfig(self::$configFields, true);
159
160 // make sure updated field is changed
161 include self::$configFields['config']['CONFIG_FILE'];
162 $this->assertEquals($invert, $GLOBALS['privateLinkByDefault']);
163 $this->assertFalse(is_file($configCopy['config']['CONFIG_FILE']));
164 }
165
166 /**
167 * Test mergeDeprecatedConfig while being logged in without options file.
168 */
169 public function testMergeDeprecatedConfigNoFile()
170 {
171 writeConfig(self::$configFields, true);
172 mergeDeprecatedConfig(self::$configFields, true);
173
174 include self::$configFields['config']['CONFIG_FILE'];
175 $this->assertEquals(self::$configFields['login'], $GLOBALS['login']);
176 }
177
178 /**
179 * Test save_plugin_config with valid data. 137 * Test save_plugin_config with valid data.
180 * 138 *
181 * @throws PluginConfigOrderException 139 * @throws PluginConfigOrderException
diff --git a/tests/Updater/DummyUpdater.php b/tests/Updater/DummyUpdater.php
new file mode 100644
index 00000000..e9ef2aaa
--- /dev/null
+++ b/tests/Updater/DummyUpdater.php
@@ -0,0 +1,68 @@
1<?php
2
3require_once 'application/Updater.php';
4
5/**
6 * Class DummyUpdater.
7 * Extends Updater to add update method designed for unit tests.
8 */
9class DummyUpdater extends Updater
10{
11 /**
12 * Object constructor.
13 *
14 * @param array $doneUpdates Updates which are already done.
15 * @param array $config Shaarli's configuration array.
16 * @param LinkDB $linkDB LinkDB instance.
17 * @param boolean $isLoggedIn True if the user is logged in.
18 */
19 public function __construct($doneUpdates, $config, $linkDB, $isLoggedIn)
20 {
21 parent::__construct($doneUpdates, $config, $linkDB, $isLoggedIn);
22
23 // Retrieve all update methods.
24 // For unit test, only retrieve final methods,
25 $class = new ReflectionClass($this);
26 $this->methods = $class->getMethods(ReflectionMethod::IS_FINAL);
27 }
28
29 /**
30 * Update method 1.
31 *
32 * @return bool true.
33 */
34 private final function updateMethodDummy1()
35 {
36 return true;
37 }
38
39 /**
40 * Update method 2.
41 *
42 * @return bool true.
43 */
44 private final function updateMethodDummy2()
45 {
46 return true;
47 }
48
49 /**
50 * Update method 3.
51 *
52 * @return bool true.
53 */
54 private final function updateMethodDummy3()
55 {
56 return true;
57 }
58
59 /**
60 * Update method 4, raise an exception.
61 *
62 * @throws Exception error.
63 */
64 private final function updateMethodException()
65 {
66 throw new Exception('whatever');
67 }
68}
diff --git a/tests/Updater/UpdaterTest.php b/tests/Updater/UpdaterTest.php
new file mode 100644
index 00000000..63ed5e03
--- /dev/null
+++ b/tests/Updater/UpdaterTest.php
@@ -0,0 +1,227 @@
1<?php
2
3require_once 'tests/Updater/DummyUpdater.php';
4
5/**
6 * Class UpdaterTest.
7 * Runs unit tests against the Updater class.
8 */
9class UpdaterTest extends PHPUnit_Framework_TestCase
10{
11 /**
12 * @var array Configuration input set.
13 */
14 private static $configFields;
15
16 /**
17 * Executed before each test.
18 */
19 public function setUp()
20 {
21 self::$configFields = array(
22 'login' => 'login',
23 'hash' => 'hash',
24 'salt' => 'salt',
25 'timezone' => 'Europe/Paris',
26 'title' => 'title',
27 'titleLink' => 'titleLink',
28 'redirector' => '',
29 'disablesessionprotection' => false,
30 'privateLinkByDefault' => false,
31 'config' => array(
32 'CONFIG_FILE' => 'tests/Updater/config.php',
33 'DATADIR' => 'tests/Updater',
34 'config1' => 'config1data',
35 'config2' => 'config2data',
36 )
37 );
38 }
39
40 /**
41 * Executed after each test.
42 *
43 * @return void
44 */
45 public function tearDown()
46 {
47 if (is_file(self::$configFields['config']['CONFIG_FILE'])) {
48 unlink(self::$configFields['config']['CONFIG_FILE']);
49 }
50
51 if (is_file(self::$configFields['config']['DATADIR'] . '/options.php')) {
52 unlink(self::$configFields['config']['DATADIR'] . '/options.php');
53 }
54
55 if (is_file(self::$configFields['config']['DATADIR'] . '/updates.json')) {
56 unlink(self::$configFields['config']['DATADIR'] . '/updates.json');
57 }
58 }
59
60 /**
61 * Test read_updates_file with an empty/missing file.
62 */
63 public function testReadEmptyUpdatesFile()
64 {
65 $this->assertEquals(array(), read_updates_file(''));
66 $updatesFile = self::$configFields['config']['DATADIR'] . '/updates.json';
67 touch($updatesFile);
68 $this->assertEquals(array(), read_updates_file($updatesFile));
69 }
70
71 /**
72 * Test read/write updates file.
73 */
74 public function testReadWriteUpdatesFile()
75 {
76 $updatesFile = self::$configFields['config']['DATADIR'] . '/updates.json';
77 $updatesMethods = array('m1', 'm2', 'm3');
78
79 write_updates_file($updatesFile, $updatesMethods);
80 $readMethods = read_updates_file($updatesFile);
81 $this->assertEquals($readMethods, $updatesMethods);
82
83 // Update
84 $updatesMethods[] = 'm4';
85 write_updates_file($updatesFile, $updatesMethods);
86 $readMethods = read_updates_file($updatesFile);
87 $this->assertEquals($readMethods, $updatesMethods);
88 }
89
90 /**
91 * Test errors in write_updates_file(): empty updates file.
92 *
93 * @expectedException Exception
94 * @expectedExceptionMessageRegExp /Updates file path is not set(.*)/
95 */
96 public function testWriteEmptyUpdatesFile()
97 {
98 write_updates_file('', array('test'));
99 }
100
101 /**
102 * Test errors in write_updates_file(): not writable updates file.
103 *
104 * @expectedException Exception
105 * @expectedExceptionMessageRegExp /Unable to write(.*)/
106 */
107 public function testWriteUpdatesFileNotWritable()
108 {
109 $updatesFile = self::$configFields['config']['DATADIR'] . '/updates.json';
110 touch($updatesFile);
111 chmod($updatesFile, 0444);
112 @write_updates_file($updatesFile, array('test'));
113 }
114
115 /**
116 * Test the update() method, with no update to run.
117 * 1. Everything already run.
118 * 2. User is logged out.
119 */
120 public function testNoUpdates()
121 {
122 $updates = array(
123 'updateMethodDummy1',
124 'updateMethodDummy2',
125 'updateMethodDummy3',
126 'updateMethodException',
127 );
128 $updater = new DummyUpdater($updates, array(), array(), true);
129 $this->assertEquals(array(), $updater->update());
130
131 $updater = new DummyUpdater(array(), array(), array(), false);
132 $this->assertEquals(array(), $updater->update());
133 }
134
135 /**
136 * Test the update() method, with all updates to run (except the failing one).
137 */
138 public function testUpdatesFirstTime()
139 {
140 $updates = array('updateMethodException',);
141 $expectedUpdates = array(
142 'updateMethodDummy1',
143 'updateMethodDummy2',
144 'updateMethodDummy3',
145 );
146 $updater = new DummyUpdater($updates, array(), array(), true);
147 $this->assertEquals($expectedUpdates, $updater->update());
148 }
149
150 /**
151 * Test the update() method, only one update to run.
152 */
153 public function testOneUpdate()
154 {
155 $updates = array(
156 'updateMethodDummy1',
157 'updateMethodDummy3',
158 'updateMethodException',
159 );
160 $expectedUpdate = array('updateMethodDummy2');
161
162 $updater = new DummyUpdater($updates, array(), array(), true);
163 $this->assertEquals($expectedUpdate, $updater->update());
164 }
165
166 /**
167 * Test Update failed.
168 *
169 * @expectedException UpdaterException
170 */
171 public function testUpdateFailed()
172 {
173 $updates = array(
174 'updateMethodDummy1',
175 'updateMethodDummy2',
176 'updateMethodDummy3',
177 );
178
179 $updater = new DummyUpdater($updates, array(), array(), true);
180 $updater->update();
181 }
182
183 /**
184 * Test update mergeDeprecatedConfig:
185 * 1. init a config file.
186 * 2. init a options.php file with update value.
187 * 3. merge.
188 * 4. check updated value in config file.
189 */
190 public function testUpdateMergeDeprecatedConfig()
191 {
192 // init
193 writeConfig(self::$configFields, true);
194 $configCopy = self::$configFields;
195 $invert = !$configCopy['privateLinkByDefault'];
196 $configCopy['privateLinkByDefault'] = $invert;
197
198 // Use writeConfig to create a options.php
199 $configCopy['config']['CONFIG_FILE'] = 'tests/Updater/options.php';
200 writeConfig($configCopy, true);
201
202 $this->assertTrue(is_file($configCopy['config']['CONFIG_FILE']));
203
204 // merge configs
205 $updater = new Updater(array(), self::$configFields, array(), true);
206 $updater->updateMethodMergeDeprecatedConfigFile();
207
208 // make sure updated field is changed
209 include self::$configFields['config']['CONFIG_FILE'];
210 $this->assertEquals($invert, $GLOBALS['privateLinkByDefault']);
211 $this->assertFalse(is_file($configCopy['config']['CONFIG_FILE']));
212 }
213
214 /**
215 * Test mergeDeprecatedConfig in without options file.
216 */
217 public function testMergeDeprecatedConfigNoFile()
218 {
219 writeConfig(self::$configFields, true);
220
221 $updater = new Updater(array(), self::$configFields, array(), true);
222 $updater->updateMethodMergeDeprecatedConfigFile();
223
224 include self::$configFields['config']['CONFIG_FILE'];
225 $this->assertEquals(self::$configFields['login'], $GLOBALS['login']);
226 }
227}