aboutsummaryrefslogtreecommitdiffhomepage
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/FeedBuilderTest.php14
-rw-r--r--tests/HttpUtils/ServerUrlTest.php13
-rw-r--r--tests/Updater/UpdaterTest.php40
-rw-r--r--tests/Url/CleanupUrlTest.php102
-rw-r--r--tests/UtilsTest.php29
-rw-r--r--tests/api/ApiMiddlewareTest.php184
-rw-r--r--tests/api/ApiUtilsTest.php206
-rw-r--r--tests/api/controllers/InfoTest.php113
-rw-r--r--tests/plugins/PluginPubsubhubbubTest.php54
9 files changed, 705 insertions, 50 deletions
diff --git a/tests/FeedBuilderTest.php b/tests/FeedBuilderTest.php
index 06a44506..a590306d 100644
--- a/tests/FeedBuilderTest.php
+++ b/tests/FeedBuilderTest.php
@@ -75,7 +75,6 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase
75 $data = $feedBuilder->buildData(); 75 $data = $feedBuilder->buildData();
76 // Test headers (RSS) 76 // Test headers (RSS)
77 $this->assertEquals(self::$RSS_LANGUAGE, $data['language']); 77 $this->assertEquals(self::$RSS_LANGUAGE, $data['language']);
78 $this->assertEmpty($data['pubsubhub_url']);
79 $this->assertRegExp('/Wed, 03 Aug 2016 09:30:33 \+\d{4}/', $data['last_update']); 78 $this->assertRegExp('/Wed, 03 Aug 2016 09:30:33 \+\d{4}/', $data['last_update']);
80 $this->assertEquals(true, $data['show_dates']); 79 $this->assertEquals(true, $data['show_dates']);
81 $this->assertEquals('http://host.tld/index.php?do=feed', $data['self_link']); 80 $this->assertEquals('http://host.tld/index.php?do=feed', $data['self_link']);
@@ -211,19 +210,6 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase
211 } 210 }
212 211
213 /** 212 /**
214 * Test buildData with hide dates settings.
215 */
216 public function testBuildDataPubsubhub()
217 {
218 $feedBuilder = new FeedBuilder(self::$linkDB, FeedBuilder::$FEED_ATOM, self::$serverInfo, null, false);
219 $feedBuilder->setLocale(self::$LOCALE);
220 $feedBuilder->setPubsubhubUrl('http://pubsubhub.io');
221 $data = $feedBuilder->buildData();
222 $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
223 $this->assertEquals('http://pubsubhub.io', $data['pubsubhub_url']);
224 }
225
226 /**
227 * Test buildData when Shaarli is served from a subdirectory 213 * Test buildData when Shaarli is served from a subdirectory
228 */ 214 */
229 public function testBuildDataServerSubdir() 215 public function testBuildDataServerSubdir()
diff --git a/tests/HttpUtils/ServerUrlTest.php b/tests/HttpUtils/ServerUrlTest.php
index 8a55a220..7fdad659 100644
--- a/tests/HttpUtils/ServerUrlTest.php
+++ b/tests/HttpUtils/ServerUrlTest.php
@@ -69,6 +69,19 @@ class ServerUrlTest extends PHPUnit_Framework_TestCase
69 ); 69 );
70 70
71 $this->assertEquals( 71 $this->assertEquals(
72 'https://host.tld',
73 server_url(
74 array(
75 'HTTPS' => 'Off',
76 'SERVER_NAME' => 'host.tld',
77 'SERVER_PORT' => '80',
78 'HTTP_X_FORWARDED_PROTO' => 'https',
79 'HTTP_X_FORWARDED_PORT' => '443'
80 )
81 )
82 );
83
84 $this->assertEquals(
72 'https://host.tld:4974', 85 'https://host.tld:4974',
73 server_url( 86 server_url(
74 array( 87 array(
diff --git a/tests/Updater/UpdaterTest.php b/tests/Updater/UpdaterTest.php
index 4948fe52..0171daad 100644
--- a/tests/Updater/UpdaterTest.php
+++ b/tests/Updater/UpdaterTest.php
@@ -271,7 +271,7 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
271 public function testEscapeConfig() 271 public function testEscapeConfig()
272 { 272 {
273 $sandbox = 'sandbox/config'; 273 $sandbox = 'sandbox/config';
274 copy(self::$configFile .'.json.php', $sandbox .'.json.php'); 274 copy(self::$configFile . '.json.php', $sandbox . '.json.php');
275 $this->conf = new ConfigManager($sandbox); 275 $this->conf = new ConfigManager($sandbox);
276 $title = '<script>alert("title");</script>'; 276 $title = '<script>alert("title");</script>';
277 $headerLink = '<script>alert("header_link");</script>'; 277 $headerLink = '<script>alert("header_link");</script>';
@@ -286,7 +286,43 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
286 $this->assertEquals(escape($title), $this->conf->get('general.title')); 286 $this->assertEquals(escape($title), $this->conf->get('general.title'));
287 $this->assertEquals(escape($headerLink), $this->conf->get('general.header_link')); 287 $this->assertEquals(escape($headerLink), $this->conf->get('general.header_link'));
288 $this->assertEquals(escape($redirectorUrl), $this->conf->get('redirector.url')); 288 $this->assertEquals(escape($redirectorUrl), $this->conf->get('redirector.url'));
289 unlink($sandbox .'.json.php'); 289 unlink($sandbox . '.json.php');
290 }
291
292 /**
293 * Test updateMethodApiSettings(): create default settings for the API (enabled + secret).
294 */
295 public function testUpdateApiSettings()
296 {
297 $confFile = 'sandbox/config';
298 copy(self::$configFile .'.json.php', $confFile .'.json.php');
299 $conf = new ConfigManager($confFile);
300 $updater = new Updater(array(), array(), $conf, true);
301
302 $this->assertFalse($conf->exists('api.enabled'));
303 $this->assertFalse($conf->exists('api.secret'));
304 $updater->updateMethodApiSettings();
305 $conf->reload();
306 $this->assertTrue($conf->get('api.enabled'));
307 $this->assertTrue($conf->exists('api.secret'));
308 unlink($confFile .'.json.php');
309 }
310
311 /**
312 * Test updateMethodApiSettings(): already set, do nothing.
313 */
314 public function testUpdateApiSettingsNothingToDo()
315 {
316 $confFile = 'sandbox/config';
317 copy(self::$configFile .'.json.php', $confFile .'.json.php');
318 $conf = new ConfigManager($confFile);
319 $conf->set('api.enabled', false);
320 $conf->set('api.secret', '');
321 $updater = new Updater(array(), array(), $conf, true);
322 $updater->updateMethodApiSettings();
323 $this->assertFalse($conf->get('api.enabled'));
324 $this->assertEmpty($conf->get('api.secret'));
325 unlink($confFile .'.json.php');
290 } 326 }
291 327
292 /** 328 /**
diff --git a/tests/Url/CleanupUrlTest.php b/tests/Url/CleanupUrlTest.php
index ba9a0437..1407d7d2 100644
--- a/tests/Url/CleanupUrlTest.php
+++ b/tests/Url/CleanupUrlTest.php
@@ -8,7 +8,13 @@ require_once 'application/Url.php';
8class CleanupUrlTest extends PHPUnit_Framework_TestCase 8class CleanupUrlTest extends PHPUnit_Framework_TestCase
9{ 9{
10 /** 10 /**
11 * Clean empty UrlThanks for building nothing 11 * @var string reference URL
12 */
13 protected $ref = 'http://domain.tld:3000';
14
15
16 /**
17 * Clean empty URL
12 */ 18 */
13 public function testCleanupUrlEmpty() 19 public function testCleanupUrlEmpty()
14 { 20 {
@@ -16,59 +22,87 @@ class CleanupUrlTest extends PHPUnit_Framework_TestCase
16 } 22 }
17 23
18 /** 24 /**
19 * Clean an already cleaned Url 25 * Clean an already cleaned URL
20 */ 26 */
21 public function testCleanupUrlAlreadyClean() 27 public function testCleanupUrlAlreadyClean()
22 { 28 {
23 $ref = 'http://domain.tld:3000'; 29 $this->assertEquals($this->ref, cleanup_url($this->ref));
24 $this->assertEquals($ref, cleanup_url($ref)); 30 $this->ref2 = $this->ref.'/path/to/dir/';
25 $ref = $ref.'/path/to/dir/'; 31 $this->assertEquals($this->ref2, cleanup_url($this->ref2));
26 $this->assertEquals($ref, cleanup_url($ref)); 32 }
33
34 /**
35 * Clean URL fragments
36 */
37 public function testCleanupUrlFragment()
38 {
39 $this->assertEquals($this->ref, cleanup_url($this->ref.'#tk.rss_all'));
40 $this->assertEquals($this->ref, cleanup_url($this->ref.'#xtor=RSS-'));
41 $this->assertEquals($this->ref, cleanup_url($this->ref.'#xtor=RSS-U3ht0tkc4b'));
42 }
43
44 /**
45 * Clean URL query - single annoying parameter
46 */
47 public function testCleanupUrlQuerySingle()
48 {
49 $this->assertEquals($this->ref, cleanup_url($this->ref.'?action_object_map=junk'));
50 $this->assertEquals($this->ref, cleanup_url($this->ref.'?action_ref_map=Cr4p!'));
51 $this->assertEquals($this->ref, cleanup_url($this->ref.'?action_type_map=g4R84g3'));
52
53 $this->assertEquals($this->ref, cleanup_url($this->ref.'?fb_stuff=v41u3'));
54 $this->assertEquals($this->ref, cleanup_url($this->ref.'?fb=71m3w4573'));
55
56 $this->assertEquals($this->ref, cleanup_url($this->ref.'?utm_campaign=zomg'));
57 $this->assertEquals($this->ref, cleanup_url($this->ref.'?utm_medium=numnum'));
58 $this->assertEquals($this->ref, cleanup_url($this->ref.'?utm_source=c0d3'));
59 $this->assertEquals($this->ref, cleanup_url($this->ref.'?utm_term=1n4l'));
60
61 $this->assertEquals($this->ref, cleanup_url($this->ref.'?xtor=some-url'));
62
63 $this->assertEquals($this->ref, cleanup_url($this->ref.'?campaign_name=junk'));
64 $this->assertEquals($this->ref, cleanup_url($this->ref.'?campaign_start=junk'));
65 $this->assertEquals($this->ref, cleanup_url($this->ref.'?campaign_item_index=junk'));
27 } 66 }
28 67
29 /** 68 /**
30 * Clean Url needing cleaning 69 * Clean URL query - multiple annoying parameters
31 */ 70 */
32 public function testCleanupUrlNeedClean() 71 public function testCleanupUrlQueryMultiple()
33 { 72 {
34 $ref = 'http://domain.tld:3000'; 73 $this->assertEquals($this->ref, cleanup_url($this->ref.'?xtor=some-url&fb=som3th1ng'));
35 $this->assertEquals($ref, cleanup_url($ref.'#tk.rss_all')); 74
36 $this->assertEquals($ref, cleanup_url($ref.'#xtor=RSS-')); 75 $this->assertEquals($this->ref, cleanup_url(
37 $this->assertEquals($ref, cleanup_url($ref.'#xtor=RSS-U3ht0tkc4b')); 76 $this->ref.'?fb=stuff&utm_campaign=zomg&utm_medium=numnum&utm_source=c0d3'
38 $this->assertEquals($ref, cleanup_url($ref.'?action_object_map=junk'));
39 $this->assertEquals($ref, cleanup_url($ref.'?action_ref_map=Cr4p!'));
40 $this->assertEquals($ref, cleanup_url($ref.'?action_type_map=g4R84g3'));
41
42 $this->assertEquals($ref, cleanup_url($ref.'?fb_stuff=v41u3'));
43 $this->assertEquals($ref, cleanup_url($ref.'?fb=71m3w4573'));
44
45 $this->assertEquals($ref, cleanup_url($ref.'?utm_campaign=zomg'));
46 $this->assertEquals($ref, cleanup_url($ref.'?utm_medium=numnum'));
47 $this->assertEquals($ref, cleanup_url($ref.'?utm_source=c0d3'));
48 $this->assertEquals($ref, cleanup_url($ref.'?utm_term=1n4l'));
49
50 $this->assertEquals($ref, cleanup_url($ref.'?xtor=some-url'));
51 $this->assertEquals($ref, cleanup_url($ref.'?xtor=some-url&fb=som3th1ng'));
52 $this->assertEquals($ref, cleanup_url(
53 $ref.'?fb=stuff&utm_campaign=zomg&utm_medium=numnum&utm_source=c0d3'
54 )); 77 ));
55 $this->assertEquals($ref, cleanup_url( 78
56 $ref.'?xtor=some-url&fb=som3th1ng#tk.rss_all' 79 $this->assertEquals($this->ref, cleanup_url(
80 $this->ref.'?campaign_start=zomg&campaign_name=numnum'
81 ));
82 }
83
84 /**
85 * Clean URL query - multiple annoying parameters and fragment
86 */
87 public function testCleanupUrlQueryFragment()
88 {
89 $this->assertEquals($this->ref, cleanup_url(
90 $this->ref.'?xtor=some-url&fb=som3th1ng#tk.rss_all'
57 )); 91 ));
58 92
59 // ditch annoying query params and fragment, keep useful params 93 // ditch annoying query params and fragment, keep useful params
60 $this->assertEquals( 94 $this->assertEquals(
61 $ref.'?my=stuff&is=kept', 95 $this->ref.'?my=stuff&is=kept',
62 cleanup_url( 96 cleanup_url(
63 $ref.'?fb=zomg&my=stuff&utm_medium=numnum&is=kept#tk.rss_all' 97 $this->ref.'?fb=zomg&my=stuff&utm_medium=numnum&is=kept#tk.rss_all'
64 ) 98 )
65 ); 99 );
66 100
67 // ditch annoying query params, keep useful params and fragment 101 // ditch annoying query params, keep useful params and fragment
68 $this->assertEquals( 102 $this->assertEquals(
69 $ref.'?my=stuff&is=kept#again', 103 $this->ref.'?my=stuff&is=kept#again',
70 cleanup_url( 104 cleanup_url(
71 $ref.'?fb=zomg&my=stuff&utm_medium=numnum&is=kept#again' 105 $this->ref.'?fb=zomg&my=stuff&utm_medium=numnum&is=kept#again'
72 ) 106 )
73 ); 107 );
74 } 108 }
diff --git a/tests/UtilsTest.php b/tests/UtilsTest.php
index 6a7870c4..c885f552 100644
--- a/tests/UtilsTest.php
+++ b/tests/UtilsTest.php
@@ -253,4 +253,33 @@ class UtilsTest extends PHPUnit_Framework_TestCase
253 is_session_id_valid('c0ZqcWF3VFE2NmJBdm1HMVQ0ZHJ3UmZPbTFsNGhkNHI=') 253 is_session_id_valid('c0ZqcWF3VFE2NmJBdm1HMVQ0ZHJ3UmZPbTFsNGhkNHI=')
254 ); 254 );
255 } 255 }
256
257 /**
258 * Test generateSecretApi.
259 */
260 public function testGenerateSecretApi()
261 {
262 $this->assertEquals(12, strlen(generate_api_secret('foo', 'bar')));
263 }
264
265 /**
266 * Test generateSecretApi with invalid parameters.
267 */
268 public function testGenerateSecretApiInvalid()
269 {
270 $this->assertFalse(generate_api_secret('', ''));
271 $this->assertFalse(generate_api_secret(false, false));
272 }
273
274 /**
275 * Test normalize_spaces.
276 */
277 public function testNormalizeSpace()
278 {
279 $str = ' foo bar is important ';
280 $this->assertEquals('foo bar is important', normalize_spaces($str));
281 $this->assertEquals('foo', normalize_spaces('foo'));
282 $this->assertEquals('', normalize_spaces(''));
283 $this->assertEquals(null, normalize_spaces(null));
284 }
256} 285}
diff --git a/tests/api/ApiMiddlewareTest.php b/tests/api/ApiMiddlewareTest.php
new file mode 100644
index 00000000..4d4dd9b9
--- /dev/null
+++ b/tests/api/ApiMiddlewareTest.php
@@ -0,0 +1,184 @@
1<?php
2
3namespace Shaarli\Api;
4
5use Slim\Container;
6use Slim\Http\Environment;
7use Slim\Http\Request;
8use Slim\Http\Response;
9
10/**
11 * Class ApiMiddlewareTest
12 *
13 * Test the REST API Slim Middleware.
14 *
15 * Note that we can't test a valid use case here, because the middleware
16 * needs to call a valid controller/action during its execution.
17 *
18 * @package Api
19 */
20class ApiMiddlewareTest extends \PHPUnit_Framework_TestCase
21{
22 /**
23 * @var string datastore to test write operations
24 */
25 protected static $testDatastore = 'sandbox/datastore.php';
26
27 /**
28 * @var \ConfigManager instance
29 */
30 protected $conf;
31
32 /**
33 * @var \ReferenceLinkDB instance.
34 */
35 protected $refDB = null;
36
37 /**
38 * @var Container instance.
39 */
40 protected $container;
41
42 /**
43 * Before every test, instantiate a new Api with its config, plugins and links.
44 */
45 public function setUp()
46 {
47 $this->conf = new \ConfigManager('tests/utils/config/configJson.json.php');
48 $this->conf->set('api.secret', 'NapoleonWasALizard');
49
50 $this->refDB = new \ReferenceLinkDB();
51 $this->refDB->write(self::$testDatastore);
52
53 $this->container = new Container();
54 $this->container['conf'] = $this->conf;
55 }
56
57 /**
58 * After every test, remove the test datastore.
59 */
60 public function tearDown()
61 {
62 @unlink(self::$testDatastore);
63 }
64
65 /**
66 * Invoke the middleware with the API disabled:
67 * should return a 401 error Unauthorized.
68 */
69 public function testInvokeMiddlewareApiDisabled()
70 {
71 $this->conf->set('api.enabled', false);
72 $mw = new ApiMiddleware($this->container);
73 $env = Environment::mock([
74 'REQUEST_METHOD' => 'GET',
75 'REQUEST_URI' => '/echo',
76 ]);
77 $request = Request::createFromEnvironment($env);
78 $response = new Response();
79 /** @var Response $response */
80 $response = $mw($request, $response, null);
81
82 $this->assertEquals(401, $response->getStatusCode());
83 $body = json_decode((string) $response->getBody());
84 $this->assertEquals('Not authorized', $body);
85 }
86
87 /**
88 * Invoke the middleware with the API disabled in debug mode:
89 * should return a 401 error Unauthorized - with a specific message and a stacktrace.
90 */
91 public function testInvokeMiddlewareApiDisabledDebug()
92 {
93 $this->conf->set('api.enabled', false);
94 $this->conf->set('dev.debug', true);
95 $mw = new ApiMiddleware($this->container);
96 $env = Environment::mock([
97 'REQUEST_METHOD' => 'GET',
98 'REQUEST_URI' => '/echo',
99 ]);
100 $request = Request::createFromEnvironment($env);
101 $response = new Response();
102 /** @var Response $response */
103 $response = $mw($request, $response, null);
104
105 $this->assertEquals(401, $response->getStatusCode());
106 $body = json_decode((string) $response->getBody());
107 $this->assertEquals('Not authorized: API is disabled', $body->message);
108 $this->assertContains('ApiAuthorizationException', $body->stacktrace);
109 }
110
111 /**
112 * Invoke the middleware without a token (debug):
113 * should return a 401 error Unauthorized - with a specific message and a stacktrace.
114 */
115 public function testInvokeMiddlewareNoTokenProvidedDebug()
116 {
117 $this->conf->set('dev.debug', true);
118 $mw = new ApiMiddleware($this->container);
119 $env = Environment::mock([
120 'REQUEST_METHOD' => 'GET',
121 'REQUEST_URI' => '/echo',
122 ]);
123 $request = Request::createFromEnvironment($env);
124 $response = new Response();
125 /** @var Response $response */
126 $response = $mw($request, $response, null);
127
128 $this->assertEquals(401, $response->getStatusCode());
129 $body = json_decode((string) $response->getBody());
130 $this->assertEquals('Not authorized: JWT token not provided', $body->message);
131 $this->assertContains('ApiAuthorizationException', $body->stacktrace);
132 }
133
134 /**
135 * Invoke the middleware without a secret set in settings (debug):
136 * should return a 401 error Unauthorized - with a specific message and a stacktrace.
137 */
138 public function testInvokeMiddlewareNoSecretSetDebug()
139 {
140 $this->conf->set('dev.debug', true);
141 $this->conf->set('api.secret', '');
142 $mw = new ApiMiddleware($this->container);
143 $env = Environment::mock([
144 'REQUEST_METHOD' => 'GET',
145 'REQUEST_URI' => '/echo',
146 'HTTP_JWT'=> 'jwt',
147 ]);
148 $request = Request::createFromEnvironment($env);
149 $response = new Response();
150 /** @var Response $response */
151 $response = $mw($request, $response, null);
152
153 $this->assertEquals(401, $response->getStatusCode());
154 $body = json_decode((string) $response->getBody());
155 $this->assertEquals('Not authorized: Token secret must be set in Shaarli\'s administration', $body->message);
156 $this->assertContains('ApiAuthorizationException', $body->stacktrace);
157 }
158
159 /**
160 * Invoke the middleware without an invalid JWT token (debug):
161 * should return a 401 error Unauthorized - with a specific message and a stacktrace.
162 *
163 * Note: specific JWT errors tests are handled in ApiUtilsTest.
164 */
165 public function testInvokeMiddlewareInvalidJwtDebug()
166 {
167 $this->conf->set('dev.debug', true);
168 $mw = new ApiMiddleware($this->container);
169 $env = Environment::mock([
170 'REQUEST_METHOD' => 'GET',
171 'REQUEST_URI' => '/echo',
172 'HTTP_JWT'=> 'bad jwt',
173 ]);
174 $request = Request::createFromEnvironment($env);
175 $response = new Response();
176 /** @var Response $response */
177 $response = $mw($request, $response, null);
178
179 $this->assertEquals(401, $response->getStatusCode());
180 $body = json_decode((string) $response->getBody());
181 $this->assertEquals('Not authorized: Malformed JWT token', $body->message);
182 $this->assertContains('ApiAuthorizationException', $body->stacktrace);
183 }
184}
diff --git a/tests/api/ApiUtilsTest.php b/tests/api/ApiUtilsTest.php
new file mode 100644
index 00000000..10da1459
--- /dev/null
+++ b/tests/api/ApiUtilsTest.php
@@ -0,0 +1,206 @@
1<?php
2
3namespace Shaarli\Api;
4
5/**
6 * Class ApiUtilsTest
7 */
8class ApiUtilsTest extends \PHPUnit_Framework_TestCase
9{
10 /**
11 * Force the timezone for ISO datetimes.
12 */
13 public static function setUpBeforeClass()
14 {
15 date_default_timezone_set('UTC');
16 }
17
18 /**
19 * Generate a valid JWT token.
20 *
21 * @param string $secret API secret used to generate the signature.
22 *
23 * @return string Generated token.
24 */
25 public static function generateValidJwtToken($secret)
26 {
27 $header = base64_encode('{
28 "typ": "JWT",
29 "alg": "HS512"
30 }');
31 $payload = base64_encode('{
32 "iat": '. time() .'
33 }');
34 $signature = hash_hmac('sha512', $header .'.'. $payload , $secret);
35 return $header .'.'. $payload .'.'. $signature;
36 }
37
38 /**
39 * Generate a JWT token from given header and payload.
40 *
41 * @param string $header Header in JSON format.
42 * @param string $payload Payload in JSON format.
43 * @param string $secret API secret used to hash the signature.
44 *
45 * @return string JWT token.
46 */
47 public static function generateCustomJwtToken($header, $payload, $secret)
48 {
49 $header = base64_encode($header);
50 $payload = base64_encode($payload);
51 $signature = hash_hmac('sha512', $header . '.' . $payload, $secret);
52 return $header . '.' . $payload . '.' . $signature;
53 }
54
55 /**
56 * Test validateJwtToken() with a valid JWT token.
57 */
58 public function testValidateJwtTokenValid()
59 {
60 $secret = 'WarIsPeace';
61 ApiUtils::validateJwtToken(self::generateValidJwtToken($secret), $secret);
62 }
63
64 /**
65 * Test validateJwtToken() with a malformed JWT token.
66 *
67 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
68 * @expectedExceptionMessage Malformed JWT token
69 */
70 public function testValidateJwtTokenMalformed()
71 {
72 $token = 'ABC.DEF';
73 ApiUtils::validateJwtToken($token, 'foo');
74 }
75
76 /**
77 * Test validateJwtToken() with an empty JWT token.
78 *
79 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
80 * @expectedExceptionMessage Malformed JWT token
81 */
82 public function testValidateJwtTokenMalformedEmpty()
83 {
84 $token = false;
85 ApiUtils::validateJwtToken($token, 'foo');
86 }
87
88 /**
89 * Test validateJwtToken() with a JWT token without header.
90 *
91 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
92 * @expectedExceptionMessage Malformed JWT token
93 */
94 public function testValidateJwtTokenMalformedEmptyHeader()
95 {
96 $token = '.payload.signature';
97 ApiUtils::validateJwtToken($token, 'foo');
98 }
99
100 /**
101 * Test validateJwtToken() with a JWT token without payload
102 *
103 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
104 * @expectedExceptionMessage Malformed JWT token
105 */
106 public function testValidateJwtTokenMalformedEmptyPayload()
107 {
108 $token = 'header..signature';
109 ApiUtils::validateJwtToken($token, 'foo');
110 }
111
112 /**
113 * Test validateJwtToken() with a JWT token with an empty signature.
114 *
115 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
116 * @expectedExceptionMessage Invalid JWT signature
117 */
118 public function testValidateJwtTokenInvalidSignatureEmpty()
119 {
120 $token = 'header.payload.';
121 ApiUtils::validateJwtToken($token, 'foo');
122 }
123
124 /**
125 * Test validateJwtToken() with a JWT token with an invalid signature.
126 *
127 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
128 * @expectedExceptionMessage Invalid JWT signature
129 */
130 public function testValidateJwtTokenInvalidSignature()
131 {
132 $token = 'header.payload.nope';
133 ApiUtils::validateJwtToken($token, 'foo');
134 }
135
136 /**
137 * Test validateJwtToken() with a JWT token with a signature generated with the wrong API secret.
138 *
139 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
140 * @expectedExceptionMessage Invalid JWT signature
141 */
142 public function testValidateJwtTokenInvalidSignatureSecret()
143 {
144 ApiUtils::validateJwtToken(self::generateValidJwtToken('foo'), 'bar');
145 }
146
147 /**
148 * Test validateJwtToken() with a JWT token with a an invalid header (not JSON).
149 *
150 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
151 * @expectedExceptionMessage Invalid JWT header
152 */
153 public function testValidateJwtTokenInvalidHeader()
154 {
155 $token = $this->generateCustomJwtToken('notJSON', '{"JSON":1}', 'secret');
156 ApiUtils::validateJwtToken($token, 'secret');
157 }
158
159 /**
160 * Test validateJwtToken() with a JWT token with a an invalid payload (not JSON).
161 *
162 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
163 * @expectedExceptionMessage Invalid JWT payload
164 */
165 public function testValidateJwtTokenInvalidPayload()
166 {
167 $token = $this->generateCustomJwtToken('{"JSON":1}', 'notJSON', 'secret');
168 ApiUtils::validateJwtToken($token, 'secret');
169 }
170
171 /**
172 * Test validateJwtToken() with a JWT token without issued time.
173 *
174 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
175 * @expectedExceptionMessage Invalid JWT issued time
176 */
177 public function testValidateJwtTokenInvalidTimeEmpty()
178 {
179 $token = $this->generateCustomJwtToken('{"JSON":1}', '{"JSON":1}', 'secret');
180 ApiUtils::validateJwtToken($token, 'secret');
181 }
182
183 /**
184 * Test validateJwtToken() with an expired JWT token.
185 *
186 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
187 * @expectedExceptionMessage Invalid JWT issued time
188 */
189 public function testValidateJwtTokenInvalidTimeExpired()
190 {
191 $token = $this->generateCustomJwtToken('{"JSON":1}', '{"iat":' . (time() - 600) . '}', 'secret');
192 ApiUtils::validateJwtToken($token, 'secret');
193 }
194
195 /**
196 * Test validateJwtToken() with a JWT token issued in the future.
197 *
198 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
199 * @expectedExceptionMessage Invalid JWT issued time
200 */
201 public function testValidateJwtTokenInvalidTimeFuture()
202 {
203 $token = $this->generateCustomJwtToken('{"JSON":1}', '{"iat":' . (time() + 60) . '}', 'secret');
204 ApiUtils::validateJwtToken($token, 'secret');
205 }
206}
diff --git a/tests/api/controllers/InfoTest.php b/tests/api/controllers/InfoTest.php
new file mode 100644
index 00000000..2916eed8
--- /dev/null
+++ b/tests/api/controllers/InfoTest.php
@@ -0,0 +1,113 @@
1<?php
2
3namespace Shaarli\Api\Controllers;
4
5use Slim\Container;
6use Slim\Http\Environment;
7use Slim\Http\Request;
8use Slim\Http\Response;
9
10/**
11 * Class InfoTest
12 *
13 * Test REST API controller Info.
14 *
15 * @package Api\Controllers
16 */
17class InfoTest extends \PHPUnit_Framework_TestCase
18{
19 /**
20 * @var string datastore to test write operations
21 */
22 protected static $testDatastore = 'sandbox/datastore.php';
23
24 /**
25 * @var \ConfigManager instance
26 */
27 protected $conf;
28
29 /**
30 * @var \ReferenceLinkDB instance.
31 */
32 protected $refDB = null;
33
34 /**
35 * @var Container instance.
36 */
37 protected $container;
38
39 /**
40 * @var Info controller instance.
41 */
42 protected $controller;
43
44 /**
45 * Before every test, instantiate a new Api with its config, plugins and links.
46 */
47 public function setUp()
48 {
49 $this->conf = new \ConfigManager('tests/utils/config/configJson.json.php');
50 $this->refDB = new \ReferenceLinkDB();
51 $this->refDB->write(self::$testDatastore);
52
53 $this->container = new Container();
54 $this->container['conf'] = $this->conf;
55 $this->container['db'] = new \LinkDB(self::$testDatastore, true, false);
56
57 $this->controller = new Info($this->container);
58 }
59
60 /**
61 * After every test, remove the test datastore.
62 */
63 public function tearDown()
64 {
65 @unlink(self::$testDatastore);
66 }
67
68 /**
69 * Test /info service.
70 */
71 public function testGetInfo()
72 {
73 $env = Environment::mock([
74 'REQUEST_METHOD' => 'GET',
75 ]);
76 $request = Request::createFromEnvironment($env);
77
78 $response = $this->controller->getInfo($request, new Response());
79 $this->assertEquals(200, $response->getStatusCode());
80 $data = json_decode((string) $response->getBody(), true);
81
82 $this->assertEquals(8, $data['global_counter']);
83 $this->assertEquals(2, $data['private_counter']);
84 $this->assertEquals('Shaarli', $data['settings']['title']);
85 $this->assertEquals('?', $data['settings']['header_link']);
86 $this->assertEquals('UTC', $data['settings']['timezone']);
87 $this->assertEquals(\ConfigManager::$DEFAULT_PLUGINS, $data['settings']['enabled_plugins']);
88 $this->assertEquals(false, $data['settings']['default_private_links']);
89
90 $title = 'My links';
91 $headerLink = 'http://shaarli.tld';
92 $timezone = 'Europe/Paris';
93 $enabledPlugins = array('foo', 'bar');
94 $defaultPrivateLinks = true;
95 $this->conf->set('general.title', $title);
96 $this->conf->set('general.header_link', $headerLink);
97 $this->conf->set('general.timezone', $timezone);
98 $this->conf->set('general.enabled_plugins', $enabledPlugins);
99 $this->conf->set('privacy.default_private_links', $defaultPrivateLinks);
100
101 $response = $this->controller->getInfo($request, new Response());
102 $this->assertEquals(200, $response->getStatusCode());
103 $data = json_decode((string) $response->getBody(), true);
104
105 $this->assertEquals(8, $data['global_counter']);
106 $this->assertEquals(2, $data['private_counter']);
107 $this->assertEquals($title, $data['settings']['title']);
108 $this->assertEquals($headerLink, $data['settings']['header_link']);
109 $this->assertEquals($timezone, $data['settings']['timezone']);
110 $this->assertEquals($enabledPlugins, $data['settings']['enabled_plugins']);
111 $this->assertEquals($defaultPrivateLinks, $data['settings']['default_private_links']);
112 }
113}
diff --git a/tests/plugins/PluginPubsubhubbubTest.php b/tests/plugins/PluginPubsubhubbubTest.php
new file mode 100644
index 00000000..24dd7a11
--- /dev/null
+++ b/tests/plugins/PluginPubsubhubbubTest.php
@@ -0,0 +1,54 @@
1<?php
2
3require_once 'plugins/pubsubhubbub/pubsubhubbub.php';
4require_once 'application/Router.php';
5
6/**
7 * Class PluginPubsubhubbubTest
8 * Unit test for the pubsubhubbub plugin
9 */
10class PluginPubsubhubbubTest extends PHPUnit_Framework_TestCase
11{
12 /**
13 * @var string Config file path (without extension).
14 */
15 protected static $configFile = 'tests/utils/config/configJson';
16
17 /**
18 * Reset plugin path
19 */
20 function setUp()
21 {
22 PluginManager::$PLUGINS_PATH = 'plugins';
23 }
24
25 /**
26 * Test render_feed hook with an RSS feed.
27 */
28 function testPubSubRssRenderFeed()
29 {
30 $hub = 'http://domain.hub';
31 $conf = new ConfigManager(self::$configFile);
32 $conf->set('plugins.PUBSUBHUB_URL', $hub);
33 $data['_PAGE_'] = Router::$PAGE_FEED_RSS;
34
35 $data = hook_pubsubhubbub_render_feed($data, $conf);
36 $expected = '<atom:link rel="hub" href="'. $hub .'" />';
37 $this->assertEquals($expected, $data['feed_plugins_header'][0]);
38 }
39
40 /**
41 * Test render_feed hook with an ATOM feed.
42 */
43 function testPubSubAtomRenderFeed()
44 {
45 $hub = 'http://domain.hub';
46 $conf = new ConfigManager(self::$configFile);
47 $conf->set('plugins.PUBSUBHUB_URL', $hub);
48 $data['_PAGE_'] = Router::$PAGE_FEED_ATOM;
49
50 $data = hook_pubsubhubbub_render_feed($data, $conf);
51 $expected = '<link rel="hub" href="'. $hub .'" />';
52 $this->assertEquals($expected, $data['feed_plugins_header'][0]);
53 }
54}