aboutsummaryrefslogtreecommitdiffhomepage
path: root/tests/api/controllers/links
diff options
context:
space:
mode:
authorArthurHoaro <arthur@hoa.ro>2019-07-27 12:34:30 +0200
committerArthurHoaro <arthur@hoa.ro>2019-07-27 12:34:30 +0200
commit38672ba0d1c722e5d6d33a58255ceb55e9410e46 (patch)
treedae4c7c47532380eac3ae641db99122fc77c93dc /tests/api/controllers/links
parent83faedadff76c5bdca036f39f13943f63b27e164 (diff)
parent1e77e0448bbd25675d8c0fe4a73206ad9048904b (diff)
downloadShaarli-38672ba0d1c722e5d6d33a58255ceb55e9410e46.tar.gz
Shaarli-38672ba0d1c722e5d6d33a58255ceb55e9410e46.tar.zst
Shaarli-38672ba0d1c722e5d6d33a58255ceb55e9410e46.zip
Merge tag 'v0.10.4' into stable
Release v0.10.4
Diffstat (limited to 'tests/api/controllers/links')
-rw-r--r--tests/api/controllers/links/DeleteLinkTest.php126
-rw-r--r--tests/api/controllers/links/GetLinkIdTest.php132
-rw-r--r--tests/api/controllers/links/GetLinksTest.php475
-rw-r--r--tests/api/controllers/links/PostLinkTest.php221
-rw-r--r--tests/api/controllers/links/PutLinkTest.php225
5 files changed, 1179 insertions, 0 deletions
diff --git a/tests/api/controllers/links/DeleteLinkTest.php b/tests/api/controllers/links/DeleteLinkTest.php
new file mode 100644
index 00000000..7d797137
--- /dev/null
+++ b/tests/api/controllers/links/DeleteLinkTest.php
@@ -0,0 +1,126 @@
1<?php
2
3
4namespace Shaarli\Api\Controllers;
5
6use Shaarli\Config\ConfigManager;
7use Slim\Container;
8use Slim\Http\Environment;
9use Slim\Http\Request;
10use Slim\Http\Response;
11
12class DeleteLinkTest extends \PHPUnit_Framework_TestCase
13{
14 /**
15 * @var string datastore to test write operations
16 */
17 protected static $testDatastore = 'sandbox/datastore.php';
18
19 /**
20 * @var string datastore to test write operations
21 */
22 protected static $testHistory = 'sandbox/history.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 \LinkDB instance.
36 */
37 protected $linkDB;
38
39 /**
40 * @var \History instance.
41 */
42 protected $history;
43
44 /**
45 * @var Container instance.
46 */
47 protected $container;
48
49 /**
50 * @var Links controller instance.
51 */
52 protected $controller;
53
54 /**
55 * Before each test, instantiate a new Api with its config, plugins and links.
56 */
57 public function setUp()
58 {
59 $this->conf = new ConfigManager('tests/utils/config/configJson');
60 $this->refDB = new \ReferenceLinkDB();
61 $this->refDB->write(self::$testDatastore);
62 $this->linkDB = new \LinkDB(self::$testDatastore, true, false);
63 $refHistory = new \ReferenceHistory();
64 $refHistory->write(self::$testHistory);
65 $this->history = new \History(self::$testHistory);
66 $this->container = new Container();
67 $this->container['conf'] = $this->conf;
68 $this->container['db'] = $this->linkDB;
69 $this->container['history'] = $this->history;
70
71 $this->controller = new Links($this->container);
72 }
73
74 /**
75 * After each test, remove the test datastore.
76 */
77 public function tearDown()
78 {
79 @unlink(self::$testDatastore);
80 @unlink(self::$testHistory);
81 }
82
83 /**
84 * Test DELETE link endpoint: the link should be removed.
85 */
86 public function testDeleteLinkValid()
87 {
88 $id = '41';
89 $this->assertTrue(isset($this->linkDB[$id]));
90 $env = Environment::mock([
91 'REQUEST_METHOD' => 'DELETE',
92 ]);
93 $request = Request::createFromEnvironment($env);
94
95 $response = $this->controller->deleteLink($request, new Response(), ['id' => $id]);
96 $this->assertEquals(204, $response->getStatusCode());
97 $this->assertEmpty((string) $response->getBody());
98
99 $this->linkDB = new \LinkDB(self::$testDatastore, true, false);
100 $this->assertFalse(isset($this->linkDB[$id]));
101
102 $historyEntry = $this->history->getHistory()[0];
103 $this->assertEquals(\History::DELETED, $historyEntry['event']);
104 $this->assertTrue(
105 (new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime']
106 );
107 $this->assertEquals($id, $historyEntry['id']);
108 }
109
110 /**
111 * Test DELETE link endpoint: reach not existing ID.
112 *
113 * @expectedException Shaarli\Api\Exceptions\ApiLinkNotFoundException
114 */
115 public function testDeleteLink404()
116 {
117 $id = -1;
118 $this->assertFalse(isset($this->linkDB[$id]));
119 $env = Environment::mock([
120 'REQUEST_METHOD' => 'DELETE',
121 ]);
122 $request = Request::createFromEnvironment($env);
123
124 $this->controller->deleteLink($request, new Response(), ['id' => $id]);
125 }
126}
diff --git a/tests/api/controllers/links/GetLinkIdTest.php b/tests/api/controllers/links/GetLinkIdTest.php
new file mode 100644
index 00000000..57528d5a
--- /dev/null
+++ b/tests/api/controllers/links/GetLinkIdTest.php
@@ -0,0 +1,132 @@
1<?php
2
3namespace Shaarli\Api\Controllers;
4
5use Shaarli\Config\ConfigManager;
6
7use Slim\Container;
8use Slim\Http\Environment;
9use Slim\Http\Request;
10use Slim\Http\Response;
11
12/**
13 * Class GetLinkIdTest
14 *
15 * Test getLink by ID API service.
16 *
17 * @see http://shaarli.github.io/api-documentation/#links-link-get
18 *
19 * @package Shaarli\Api\Controllers
20 */
21class GetLinkIdTest extends \PHPUnit_Framework_TestCase
22{
23 /**
24 * @var string datastore to test write operations
25 */
26 protected static $testDatastore = 'sandbox/datastore.php';
27
28 /**
29 * @var ConfigManager instance
30 */
31 protected $conf;
32
33 /**
34 * @var \ReferenceLinkDB instance.
35 */
36 protected $refDB = null;
37
38 /**
39 * @var Container instance.
40 */
41 protected $container;
42
43 /**
44 * @var Links controller instance.
45 */
46 protected $controller;
47
48 /**
49 * Number of JSON fields per link.
50 */
51 const NB_FIELDS_LINK = 9;
52
53 /**
54 * Before each test, instantiate a new Api with its config, plugins and links.
55 */
56 public function setUp()
57 {
58 $this->conf = new ConfigManager('tests/utils/config/configJson');
59 $this->refDB = new \ReferenceLinkDB();
60 $this->refDB->write(self::$testDatastore);
61
62 $this->container = new Container();
63 $this->container['conf'] = $this->conf;
64 $this->container['db'] = new \LinkDB(self::$testDatastore, true, false);
65 $this->container['history'] = null;
66
67 $this->controller = new Links($this->container);
68 }
69
70 /**
71 * After each test, remove the test datastore.
72 */
73 public function tearDown()
74 {
75 @unlink(self::$testDatastore);
76 }
77
78 /**
79 * Test basic getLink service: return link ID=41.
80 */
81 public function testGetLinkId()
82 {
83 // Used by index_url().
84 $_SERVER['SERVER_NAME'] = 'domain.tld';
85 $_SERVER['SERVER_PORT'] = 80;
86 $_SERVER['SCRIPT_NAME'] = '/';
87
88 $id = 41;
89 $env = Environment::mock([
90 'REQUEST_METHOD' => 'GET',
91 ]);
92 $request = Request::createFromEnvironment($env);
93
94 $response = $this->controller->getLink($request, new Response(), ['id' => $id]);
95 $this->assertEquals(200, $response->getStatusCode());
96 $data = json_decode((string) $response->getBody(), true);
97 $this->assertEquals(self::NB_FIELDS_LINK, count($data));
98 $this->assertEquals($id, $data['id']);
99
100 // Check link elements
101 $this->assertEquals('http://domain.tld/?WDWyig', $data['url']);
102 $this->assertEquals('WDWyig', $data['shorturl']);
103 $this->assertEquals('Link title: @website', $data['title']);
104 $this->assertEquals(
105 'Stallman has a beard and is part of the Free Software Foundation (or not). Seriously, read this. #hashtag',
106 $data['description']
107 );
108 $this->assertEquals('sTuff', $data['tags'][0]);
109 $this->assertEquals(false, $data['private']);
110 $this->assertEquals(
111 \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20150310_114651')->format(\DateTime::ATOM),
112 $data['created']
113 );
114 $this->assertEmpty($data['updated']);
115 }
116
117 /**
118 * Test basic getLink service: get non existent link => ApiLinkNotFoundException.
119 *
120 * @expectedException Shaarli\Api\Exceptions\ApiLinkNotFoundException
121 * @expectedExceptionMessage Link not found
122 */
123 public function testGetLink404()
124 {
125 $env = Environment::mock([
126 'REQUEST_METHOD' => 'GET',
127 ]);
128 $request = Request::createFromEnvironment($env);
129
130 $this->controller->getLink($request, new Response(), ['id' => -1]);
131 }
132}
diff --git a/tests/api/controllers/links/GetLinksTest.php b/tests/api/controllers/links/GetLinksTest.php
new file mode 100644
index 00000000..64f02774
--- /dev/null
+++ b/tests/api/controllers/links/GetLinksTest.php
@@ -0,0 +1,475 @@
1<?php
2namespace Shaarli\Api\Controllers;
3
4use Shaarli\Config\ConfigManager;
5
6use Slim\Container;
7use Slim\Http\Environment;
8use Slim\Http\Request;
9use Slim\Http\Response;
10
11/**
12 * Class GetLinksTest
13 *
14 * Test get Link list REST API service.
15 *
16 * @see http://shaarli.github.io/api-documentation/#links-links-collection-get
17 *
18 * @package Shaarli\Api\Controllers
19 */
20class GetLinksTest 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 * @var Links controller instance.
44 */
45 protected $controller;
46
47 /**
48 * Number of JSON field per link.
49 */
50 const NB_FIELDS_LINK = 9;
51
52 /**
53 * Before every test, instantiate a new Api with its config, plugins and links.
54 */
55 public function setUp()
56 {
57 $this->conf = new ConfigManager('tests/utils/config/configJson');
58 $this->refDB = new \ReferenceLinkDB();
59 $this->refDB->write(self::$testDatastore);
60
61 $this->container = new Container();
62 $this->container['conf'] = $this->conf;
63 $this->container['db'] = new \LinkDB(self::$testDatastore, true, false);
64 $this->container['history'] = null;
65
66 $this->controller = new Links($this->container);
67 }
68
69 /**
70 * After every test, remove the test datastore.
71 */
72 public function tearDown()
73 {
74 @unlink(self::$testDatastore);
75 }
76
77 /**
78 * Test basic getLinks service: returns all links.
79 */
80 public function testGetLinks()
81 {
82 // Used by index_url().
83 $_SERVER['SERVER_NAME'] = 'domain.tld';
84 $_SERVER['SERVER_PORT'] = 80;
85 $_SERVER['SCRIPT_NAME'] = '/';
86
87 $env = Environment::mock([
88 'REQUEST_METHOD' => 'GET',
89 ]);
90 $request = Request::createFromEnvironment($env);
91
92 $response = $this->controller->getLinks($request, new Response());
93 $this->assertEquals(200, $response->getStatusCode());
94 $data = json_decode((string) $response->getBody(), true);
95 $this->assertEquals($this->refDB->countLinks(), count($data));
96
97 // Check order
98 $order = [10, 11, 41, 8, 6, 7, 0, 1, 9, 4, 42];
99 $cpt = 0;
100 foreach ($data as $link) {
101 $this->assertEquals(self::NB_FIELDS_LINK, count($link));
102 $this->assertEquals($order[$cpt++], $link['id']);
103 }
104
105 // Check first element fields
106 $first = $data[2];
107 $this->assertEquals('http://domain.tld/?WDWyig', $first['url']);
108 $this->assertEquals('WDWyig', $first['shorturl']);
109 $this->assertEquals('Link title: @website', $first['title']);
110 $this->assertEquals(
111 'Stallman has a beard and is part of the Free Software Foundation (or not). Seriously, read this. #hashtag',
112 $first['description']
113 );
114 $this->assertEquals('sTuff', $first['tags'][0]);
115 $this->assertEquals(false, $first['private']);
116 $this->assertEquals(
117 \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20150310_114651')->format(\DateTime::ATOM),
118 $first['created']
119 );
120 $this->assertEmpty($first['updated']);
121
122 // Multi tags
123 $link = $data[3];
124 $this->assertEquals(7, count($link['tags']));
125
126 // Update date
127 $this->assertEquals(
128 \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20160803_093033')->format(\DateTime::ATOM),
129 $link['updated']
130 );
131 }
132
133 /**
134 * Test getLinks service with offset and limit parameter:
135 * limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC).
136 */
137 public function testGetLinksOffsetLimit()
138 {
139 $env = Environment::mock([
140 'REQUEST_METHOD' => 'GET',
141 'QUERY_STRING' => 'offset=3&limit=1'
142 ]);
143 $request = Request::createFromEnvironment($env);
144 $response = $this->controller->getLinks($request, new Response());
145 $this->assertEquals(200, $response->getStatusCode());
146 $data = json_decode((string) $response->getBody(), true);
147 $this->assertEquals(1, count($data));
148 $this->assertEquals(8, $data[0]['id']);
149 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
150 }
151
152 /**
153 * Test getLinks with limit=all (return all link).
154 */
155 public function testGetLinksLimitAll()
156 {
157 $env = Environment::mock([
158 'REQUEST_METHOD' => 'GET',
159 'QUERY_STRING' => 'limit=all'
160 ]);
161 $request = Request::createFromEnvironment($env);
162 $response = $this->controller->getLinks($request, new Response());
163 $this->assertEquals(200, $response->getStatusCode());
164 $data = json_decode((string) $response->getBody(), true);
165 $this->assertEquals($this->refDB->countLinks(), count($data));
166 // Check order
167 $order = [10, 11, 41, 8, 6, 7, 0, 1, 9, 4, 42];
168 $cpt = 0;
169 foreach ($data as $link) {
170 $this->assertEquals(self::NB_FIELDS_LINK, count($link));
171 $this->assertEquals($order[$cpt++], $link['id']);
172 }
173 }
174
175 /**
176 * Test getLinks service with offset and limit parameter:
177 * limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC).
178 */
179 public function testGetLinksOffsetTooHigh()
180 {
181 $env = Environment::mock([
182 'REQUEST_METHOD' => 'GET',
183 'QUERY_STRING' => 'offset=100'
184 ]);
185 $request = Request::createFromEnvironment($env);
186 $response = $this->controller->getLinks($request, new Response());
187 $this->assertEquals(200, $response->getStatusCode());
188 $data = json_decode((string) $response->getBody(), true);
189 $this->assertEmpty(count($data));
190 }
191
192 /**
193 * Test getLinks with visibility parameter set to all
194 */
195 public function testGetLinksVisibilityAll()
196 {
197 $env = Environment::mock(
198 [
199 'REQUEST_METHOD' => 'GET',
200 'QUERY_STRING' => 'visibility=all'
201 ]
202 );
203 $request = Request::createFromEnvironment($env);
204 $response = $this->controller->getLinks($request, new Response());
205 $this->assertEquals(200, $response->getStatusCode());
206 $data = json_decode((string)$response->getBody(), true);
207 $this->assertEquals($this->refDB->countLinks(), count($data));
208 $this->assertEquals(10, $data[0]['id']);
209 $this->assertEquals(41, $data[2]['id']);
210 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
211 }
212
213 /**
214 * Test getLinks with visibility parameter set to private
215 */
216 public function testGetLinksVisibilityPrivate()
217 {
218 $env = Environment::mock([
219 'REQUEST_METHOD' => 'GET',
220 'QUERY_STRING' => 'visibility=private'
221 ]);
222 $request = Request::createFromEnvironment($env);
223 $response = $this->controller->getLinks($request, new Response());
224 $this->assertEquals(200, $response->getStatusCode());
225 $data = json_decode((string) $response->getBody(), true);
226 $this->assertEquals($this->refDB->countPrivateLinks(), count($data));
227 $this->assertEquals(6, $data[0]['id']);
228 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
229 }
230
231 /**
232 * Test getLinks with visibility parameter set to public
233 */
234 public function testGetLinksVisibilityPublic()
235 {
236 $env = Environment::mock(
237 [
238 'REQUEST_METHOD' => 'GET',
239 'QUERY_STRING' => 'visibility=public'
240 ]
241 );
242 $request = Request::createFromEnvironment($env);
243 $response = $this->controller->getLinks($request, new Response());
244 $this->assertEquals(200, $response->getStatusCode());
245 $data = json_decode((string)$response->getBody(), true);
246 $this->assertEquals($this->refDB->countPublicLinks(), count($data));
247 $this->assertEquals(10, $data[0]['id']);
248 $this->assertEquals(41, $data[2]['id']);
249 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
250 }
251
252 /**
253 * Test getLinks service with offset and limit parameter:
254 * limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC).
255 */
256 public function testGetLinksSearchTerm()
257 {
258 // Only in description - 1 result
259 $env = Environment::mock([
260 'REQUEST_METHOD' => 'GET',
261 'QUERY_STRING' => 'searchterm=Tropical'
262 ]);
263 $request = Request::createFromEnvironment($env);
264 $response = $this->controller->getLinks($request, new Response());
265 $this->assertEquals(200, $response->getStatusCode());
266 $data = json_decode((string) $response->getBody(), true);
267 $this->assertEquals(1, count($data));
268 $this->assertEquals(1, $data[0]['id']);
269 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
270
271 // Only in tags - 1 result
272 $env = Environment::mock([
273 'REQUEST_METHOD' => 'GET',
274 'QUERY_STRING' => 'searchterm=tag3'
275 ]);
276 $request = Request::createFromEnvironment($env);
277 $response = $this->controller->getLinks($request, new Response());
278 $this->assertEquals(200, $response->getStatusCode());
279 $data = json_decode((string) $response->getBody(), true);
280 $this->assertEquals(1, count($data));
281 $this->assertEquals(0, $data[0]['id']);
282 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
283
284 // Multiple results (2)
285 $env = Environment::mock([
286 'REQUEST_METHOD' => 'GET',
287 'QUERY_STRING' => 'searchterm=stallman'
288 ]);
289 $request = Request::createFromEnvironment($env);
290 $response = $this->controller->getLinks($request, new Response());
291 $this->assertEquals(200, $response->getStatusCode());
292 $data = json_decode((string) $response->getBody(), true);
293 $this->assertEquals(2, count($data));
294 $this->assertEquals(41, $data[0]['id']);
295 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
296 $this->assertEquals(8, $data[1]['id']);
297 $this->assertEquals(self::NB_FIELDS_LINK, count($data[1]));
298
299 // Multiword - 2 results
300 $env = Environment::mock([
301 'REQUEST_METHOD' => 'GET',
302 'QUERY_STRING' => 'searchterm=stallman+software'
303 ]);
304 $request = Request::createFromEnvironment($env);
305 $response = $this->controller->getLinks($request, new Response());
306 $this->assertEquals(200, $response->getStatusCode());
307 $data = json_decode((string) $response->getBody(), true);
308 $this->assertEquals(2, count($data));
309 $this->assertEquals(41, $data[0]['id']);
310 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
311 $this->assertEquals(8, $data[1]['id']);
312 $this->assertEquals(self::NB_FIELDS_LINK, count($data[1]));
313
314 // URL encoding
315 $env = Environment::mock([
316 'REQUEST_METHOD' => 'GET',
317 'QUERY_STRING' => 'searchterm='. urlencode('@web')
318 ]);
319 $request = Request::createFromEnvironment($env);
320 $response = $this->controller->getLinks($request, new Response());
321 $this->assertEquals(200, $response->getStatusCode());
322 $data = json_decode((string) $response->getBody(), true);
323 $this->assertEquals(2, count($data));
324 $this->assertEquals(41, $data[0]['id']);
325 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
326 $this->assertEquals(8, $data[1]['id']);
327 $this->assertEquals(self::NB_FIELDS_LINK, count($data[1]));
328 }
329
330 public function testGetLinksSearchTermNoResult()
331 {
332 $env = Environment::mock([
333 'REQUEST_METHOD' => 'GET',
334 'QUERY_STRING' => 'searchterm=nope'
335 ]);
336 $request = Request::createFromEnvironment($env);
337 $response = $this->controller->getLinks($request, new Response());
338 $this->assertEquals(200, $response->getStatusCode());
339 $data = json_decode((string) $response->getBody(), true);
340 $this->assertEquals(0, count($data));
341 }
342
343 public function testGetLinksSearchTags()
344 {
345 // Single tag
346 $env = Environment::mock([
347 'REQUEST_METHOD' => 'GET',
348 'QUERY_STRING' => 'searchtags=dev',
349 ]);
350 $request = Request::createFromEnvironment($env);
351 $response = $this->controller->getLinks($request, new Response());
352 $this->assertEquals(200, $response->getStatusCode());
353 $data = json_decode((string) $response->getBody(), true);
354 $this->assertEquals(2, count($data));
355 $this->assertEquals(0, $data[0]['id']);
356 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
357 $this->assertEquals(4, $data[1]['id']);
358 $this->assertEquals(self::NB_FIELDS_LINK, count($data[1]));
359
360 // Multitag + exclude
361 $env = Environment::mock([
362 'REQUEST_METHOD' => 'GET',
363 'QUERY_STRING' => 'searchtags=stuff+-gnu',
364 ]);
365 $request = Request::createFromEnvironment($env);
366 $response = $this->controller->getLinks($request, new Response());
367 $this->assertEquals(200, $response->getStatusCode());
368 $data = json_decode((string) $response->getBody(), true);
369 $this->assertEquals(1, count($data));
370 $this->assertEquals(41, $data[0]['id']);
371 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
372
373 // wildcard: placeholder at the start
374 $env = Environment::mock([
375 'REQUEST_METHOD' => 'GET',
376 'QUERY_STRING' => 'searchtags=*Tuff',
377 ]);
378 $request = Request::createFromEnvironment($env);
379 $response = $this->controller->getLinks($request, new Response());
380 $this->assertEquals(200, $response->getStatusCode());
381 $data = json_decode((string) $response->getBody(), true);
382 $this->assertEquals(2, count($data));
383 $this->assertEquals(41, $data[0]['id']);
384
385 // wildcard: placeholder at the end
386 $env = Environment::mock([
387 'REQUEST_METHOD' => 'GET',
388 'QUERY_STRING' => 'searchtags=c*',
389 ]);
390 $request = Request::createFromEnvironment($env);
391 $response = $this->controller->getLinks($request, new Response());
392 $this->assertEquals(200, $response->getStatusCode());
393 $data = json_decode((string) $response->getBody(), true);
394 $this->assertEquals(4, count($data));
395 $this->assertEquals(6, $data[0]['id']);
396
397 // wildcard: placeholder at the middle
398 $env = Environment::mock([
399 'REQUEST_METHOD' => 'GET',
400 'QUERY_STRING' => 'searchtags=w*b',
401 ]);
402 $request = Request::createFromEnvironment($env);
403 $response = $this->controller->getLinks($request, new Response());
404 $this->assertEquals(200, $response->getStatusCode());
405 $data = json_decode((string) $response->getBody(), true);
406 $this->assertEquals(4, count($data));
407 $this->assertEquals(6, $data[0]['id']);
408
409 // wildcard: match all
410 $env = Environment::mock([
411 'REQUEST_METHOD' => 'GET',
412 'QUERY_STRING' => 'searchtags=*',
413 ]);
414 $request = Request::createFromEnvironment($env);
415 $response = $this->controller->getLinks($request, new Response());
416 $this->assertEquals(200, $response->getStatusCode());
417 $data = json_decode((string) $response->getBody(), true);
418 $this->assertEquals(\ReferenceLinkDB::$NB_LINKS_TOTAL, count($data));
419 $this->assertEquals(10, $data[0]['id']);
420 $this->assertEquals(41, $data[2]['id']);
421
422 // wildcard: optional ('*' does not need to expand)
423 $env = Environment::mock([
424 'REQUEST_METHOD' => 'GET',
425 'QUERY_STRING' => 'searchtags=*stuff*',
426 ]);
427 $request = Request::createFromEnvironment($env);
428 $response = $this->controller->getLinks($request, new Response());
429 $this->assertEquals(200, $response->getStatusCode());
430 $data = json_decode((string) $response->getBody(), true);
431 $this->assertEquals(2, count($data));
432 $this->assertEquals(41, $data[0]['id']);
433
434 // wildcard: exclusions
435 $env = Environment::mock([
436 'REQUEST_METHOD' => 'GET',
437 'QUERY_STRING' => 'searchtags=*a*+-*e*',
438 ]);
439 $request = Request::createFromEnvironment($env);
440 $response = $this->controller->getLinks($request, new Response());
441 $this->assertEquals(200, $response->getStatusCode());
442 $data = json_decode((string) $response->getBody(), true);
443 $this->assertEquals(1, count($data));
444 $this->assertEquals(41, $data[0]['id']); // finds '#hashtag' in descr.
445
446 // wildcard: exclude all
447 $env = Environment::mock([
448 'REQUEST_METHOD' => 'GET',
449 'QUERY_STRING' => 'searchtags=-*',
450 ]);
451 $request = Request::createFromEnvironment($env);
452 $response = $this->controller->getLinks($request, new Response());
453 $this->assertEquals(200, $response->getStatusCode());
454 $data = json_decode((string) $response->getBody(), true);
455 $this->assertEquals(0, count($data));
456 }
457
458 /**
459 * Test getLinks service with search tags+terms.
460 */
461 public function testGetLinksSearchTermsAndTags()
462 {
463 $env = Environment::mock([
464 'REQUEST_METHOD' => 'GET',
465 'QUERY_STRING' => 'searchterm=poke&searchtags=dev',
466 ]);
467 $request = Request::createFromEnvironment($env);
468 $response = $this->controller->getLinks($request, new Response());
469 $this->assertEquals(200, $response->getStatusCode());
470 $data = json_decode((string) $response->getBody(), true);
471 $this->assertEquals(1, count($data));
472 $this->assertEquals(0, $data[0]['id']);
473 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
474 }
475}
diff --git a/tests/api/controllers/links/PostLinkTest.php b/tests/api/controllers/links/PostLinkTest.php
new file mode 100644
index 00000000..5c2b5623
--- /dev/null
+++ b/tests/api/controllers/links/PostLinkTest.php
@@ -0,0 +1,221 @@
1<?php
2
3namespace Shaarli\Api\Controllers;
4
5use PHPUnit\Framework\TestCase;
6use Shaarli\Config\ConfigManager;
7use Slim\Container;
8use Slim\Http\Environment;
9use Slim\Http\Request;
10use Slim\Http\Response;
11use Slim\Router;
12
13/**
14 * Class PostLinkTest
15 *
16 * Test POST Link REST API service.
17 *
18 * @package Shaarli\Api\Controllers
19 */
20class PostLinkTest extends TestCase
21{
22 /**
23 * @var string datastore to test write operations
24 */
25 protected static $testDatastore = 'sandbox/datastore.php';
26
27 /**
28 * @var string datastore to test write operations
29 */
30 protected static $testHistory = 'sandbox/history.php';
31
32 /**
33 * @var ConfigManager instance
34 */
35 protected $conf;
36
37 /**
38 * @var \ReferenceLinkDB instance.
39 */
40 protected $refDB = null;
41
42 /**
43 * @var \History instance.
44 */
45 protected $history;
46
47 /**
48 * @var Container instance.
49 */
50 protected $container;
51
52 /**
53 * @var Links controller instance.
54 */
55 protected $controller;
56
57 /**
58 * Number of JSON field per link.
59 */
60 const NB_FIELDS_LINK = 9;
61
62 /**
63 * Before every test, instantiate a new Api with its config, plugins and links.
64 */
65 public function setUp()
66 {
67 $this->conf = new ConfigManager('tests/utils/config/configJson.json.php');
68 $this->refDB = new \ReferenceLinkDB();
69 $this->refDB->write(self::$testDatastore);
70
71 $refHistory = new \ReferenceHistory();
72 $refHistory->write(self::$testHistory);
73 $this->history = new \History(self::$testHistory);
74
75 $this->container = new Container();
76 $this->container['conf'] = $this->conf;
77 $this->container['db'] = new \LinkDB(self::$testDatastore, true, false);
78 $this->container['history'] = new \History(self::$testHistory);
79
80 $this->controller = new Links($this->container);
81
82 $mock = $this->createMock(Router::class);
83 $mock->expects($this->any())
84 ->method('relativePathFor')
85 ->willReturn('api/v1/links/1');
86
87 // affect @property-read... seems to work
88 $this->controller->getCi()->router = $mock;
89
90 // Used by index_url().
91 $this->controller->getCi()['environment'] = [
92 'SERVER_NAME' => 'domain.tld',
93 'SERVER_PORT' => 80,
94 'SCRIPT_NAME' => '/',
95 ];
96 }
97
98 /**
99 * After every test, remove the test datastore.
100 */
101 public function tearDown()
102 {
103 @unlink(self::$testDatastore);
104 @unlink(self::$testHistory);
105 }
106
107 /**
108 * Test link creation without any field: creates a blank note.
109 */
110 public function testPostLinkMinimal()
111 {
112 $env = Environment::mock([
113 'REQUEST_METHOD' => 'POST',
114 ]);
115
116 $request = Request::createFromEnvironment($env);
117
118 $response = $this->controller->postLink($request, new Response());
119 $this->assertEquals(201, $response->getStatusCode());
120 $this->assertEquals('api/v1/links/1', $response->getHeader('Location')[0]);
121 $data = json_decode((string) $response->getBody(), true);
122 $this->assertEquals(self::NB_FIELDS_LINK, count($data));
123 $this->assertEquals(43, $data['id']);
124 $this->assertRegExp('/[\w-_]{6}/', $data['shorturl']);
125 $this->assertEquals('http://domain.tld/?' . $data['shorturl'], $data['url']);
126 $this->assertEquals('?' . $data['shorturl'], $data['title']);
127 $this->assertEquals('', $data['description']);
128 $this->assertEquals([], $data['tags']);
129 $this->assertEquals(false, $data['private']);
130 $this->assertTrue(
131 new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
132 );
133 $this->assertEquals('', $data['updated']);
134
135 $historyEntry = $this->history->getHistory()[0];
136 $this->assertEquals(\History::CREATED, $historyEntry['event']);
137 $this->assertTrue(
138 (new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime']
139 );
140 $this->assertEquals(43, $historyEntry['id']);
141 }
142
143 /**
144 * Test link creation with all available fields.
145 */
146 public function testPostLinkFull()
147 {
148 $link = [
149 'url' => 'website.tld/test?foo=bar',
150 'title' => 'new entry',
151 'description' => 'shaare description',
152 'tags' => ['one', 'two'],
153 'private' => true,
154 ];
155 $env = Environment::mock([
156 'REQUEST_METHOD' => 'POST',
157 'CONTENT_TYPE' => 'application/json'
158 ]);
159
160 $request = Request::createFromEnvironment($env);
161 $request = $request->withParsedBody($link);
162 $response = $this->controller->postLink($request, new Response());
163
164 $this->assertEquals(201, $response->getStatusCode());
165 $this->assertEquals('api/v1/links/1', $response->getHeader('Location')[0]);
166 $data = json_decode((string) $response->getBody(), true);
167 $this->assertEquals(self::NB_FIELDS_LINK, count($data));
168 $this->assertEquals(43, $data['id']);
169 $this->assertRegExp('/[\w-_]{6}/', $data['shorturl']);
170 $this->assertEquals('http://' . $link['url'], $data['url']);
171 $this->assertEquals($link['title'], $data['title']);
172 $this->assertEquals($link['description'], $data['description']);
173 $this->assertEquals($link['tags'], $data['tags']);
174 $this->assertEquals(true, $data['private']);
175 $this->assertTrue(
176 new \DateTime('2 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
177 );
178 $this->assertEquals('', $data['updated']);
179 }
180
181 /**
182 * Test link creation with an existing link (duplicate URL). Should return a 409 HTTP error and the existing link.
183 */
184 public function testPostLinkDuplicate()
185 {
186 $link = [
187 'url' => 'mediagoblin.org/',
188 'title' => 'new entry',
189 'description' => 'shaare description',
190 'tags' => ['one', 'two'],
191 'private' => true,
192 ];
193 $env = Environment::mock([
194 'REQUEST_METHOD' => 'POST',
195 'CONTENT_TYPE' => 'application/json'
196 ]);
197
198 $request = Request::createFromEnvironment($env);
199 $request = $request->withParsedBody($link);
200 $response = $this->controller->postLink($request, new Response());
201
202 $this->assertEquals(409, $response->getStatusCode());
203 $data = json_decode((string) $response->getBody(), true);
204 $this->assertEquals(self::NB_FIELDS_LINK, count($data));
205 $this->assertEquals(7, $data['id']);
206 $this->assertEquals('IuWvgA', $data['shorturl']);
207 $this->assertEquals('http://mediagoblin.org/', $data['url']);
208 $this->assertEquals('MediaGoblin', $data['title']);
209 $this->assertEquals('A free software media publishing platform #hashtagOther', $data['description']);
210 $this->assertEquals(['gnu', 'media', 'web', '.hidden', 'hashtag'], $data['tags']);
211 $this->assertEquals(false, $data['private']);
212 $this->assertEquals(
213 \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20130614_184135'),
214 \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
215 );
216 $this->assertEquals(
217 \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20130615_184230'),
218 \DateTime::createFromFormat(\DateTime::ATOM, $data['updated'])
219 );
220 }
221}
diff --git a/tests/api/controllers/links/PutLinkTest.php b/tests/api/controllers/links/PutLinkTest.php
new file mode 100644
index 00000000..f276b4c1
--- /dev/null
+++ b/tests/api/controllers/links/PutLinkTest.php
@@ -0,0 +1,225 @@
1<?php
2
3
4namespace Shaarli\Api\Controllers;
5
6use Shaarli\Config\ConfigManager;
7use Slim\Container;
8use Slim\Http\Environment;
9use Slim\Http\Request;
10use Slim\Http\Response;
11
12class PutLinkTest extends \PHPUnit_Framework_TestCase
13{
14 /**
15 * @var string datastore to test write operations
16 */
17 protected static $testDatastore = 'sandbox/datastore.php';
18
19 /**
20 * @var string datastore to test write operations
21 */
22 protected static $testHistory = 'sandbox/history.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 \History instance.
36 */
37 protected $history;
38
39 /**
40 * @var Container instance.
41 */
42 protected $container;
43
44 /**
45 * @var Links controller instance.
46 */
47 protected $controller;
48
49 /**
50 * Number of JSON field per link.
51 */
52 const NB_FIELDS_LINK = 9;
53
54 /**
55 * Before every test, instantiate a new Api with its config, plugins and links.
56 */
57 public function setUp()
58 {
59 $this->conf = new ConfigManager('tests/utils/config/configJson.json.php');
60 $this->refDB = new \ReferenceLinkDB();
61 $this->refDB->write(self::$testDatastore);
62
63 $refHistory = new \ReferenceHistory();
64 $refHistory->write(self::$testHistory);
65 $this->history = new \History(self::$testHistory);
66
67 $this->container = new Container();
68 $this->container['conf'] = $this->conf;
69 $this->container['db'] = new \LinkDB(self::$testDatastore, true, false);
70 $this->container['history'] = new \History(self::$testHistory);
71
72 $this->controller = new Links($this->container);
73
74 // Used by index_url().
75 $this->controller->getCi()['environment'] = [
76 'SERVER_NAME' => 'domain.tld',
77 'SERVER_PORT' => 80,
78 'SCRIPT_NAME' => '/',
79 ];
80 }
81
82 /**
83 * After every test, remove the test datastore.
84 */
85 public function tearDown()
86 {
87 @unlink(self::$testDatastore);
88 @unlink(self::$testHistory);
89 }
90
91 /**
92 * Test link update without value: reset the link to default values
93 */
94 public function testPutLinkMinimal()
95 {
96 $env = Environment::mock([
97 'REQUEST_METHOD' => 'PUT',
98 ]);
99 $id = '41';
100 $request = Request::createFromEnvironment($env);
101
102 $response = $this->controller->putLink($request, new Response(), ['id' => $id]);
103 $this->assertEquals(200, $response->getStatusCode());
104 $data = json_decode((string) $response->getBody(), true);
105 $this->assertEquals(self::NB_FIELDS_LINK, count($data));
106 $this->assertEquals($id, $data['id']);
107 $this->assertEquals('WDWyig', $data['shorturl']);
108 $this->assertEquals('http://domain.tld/?WDWyig', $data['url']);
109 $this->assertEquals('?WDWyig', $data['title']);
110 $this->assertEquals('', $data['description']);
111 $this->assertEquals([], $data['tags']);
112 $this->assertEquals(false, $data['private']);
113 $this->assertEquals(
114 \DateTime::createFromFormat('Ymd_His', '20150310_114651'),
115 \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
116 );
117 $this->assertTrue(
118 new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['updated'])
119 );
120
121 $historyEntry = $this->history->getHistory()[0];
122 $this->assertEquals(\History::UPDATED, $historyEntry['event']);
123 $this->assertTrue(
124 (new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime']
125 );
126 $this->assertEquals($id, $historyEntry['id']);
127 }
128
129 /**
130 * Test link update with new values
131 */
132 public function testPutLinkWithValues()
133 {
134 $env = Environment::mock([
135 'REQUEST_METHOD' => 'PUT',
136 'CONTENT_TYPE' => 'application/json'
137 ]);
138 $id = 41;
139 $update = [
140 'url' => 'http://somewhere.else',
141 'title' => 'Le Cid',
142 'description' => 'Percé jusques au fond du cœur [...]',
143 'tags' => ['corneille', 'rodrigue'],
144 'private' => true,
145 ];
146 $request = Request::createFromEnvironment($env);
147 $request = $request->withParsedBody($update);
148
149 $response = $this->controller->putLink($request, new Response(), ['id' => $id]);
150 $this->assertEquals(200, $response->getStatusCode());
151 $data = json_decode((string) $response->getBody(), true);
152 $this->assertEquals(self::NB_FIELDS_LINK, count($data));
153 $this->assertEquals($id, $data['id']);
154 $this->assertEquals('WDWyig', $data['shorturl']);
155 $this->assertEquals('http://somewhere.else', $data['url']);
156 $this->assertEquals('Le Cid', $data['title']);
157 $this->assertEquals('Percé jusques au fond du cœur [...]', $data['description']);
158 $this->assertEquals(['corneille', 'rodrigue'], $data['tags']);
159 $this->assertEquals(true, $data['private']);
160 $this->assertEquals(
161 \DateTime::createFromFormat('Ymd_His', '20150310_114651'),
162 \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
163 );
164 $this->assertTrue(
165 new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['updated'])
166 );
167 }
168
169 /**
170 * Test link update with an existing URL: 409 Conflict with the existing link as body
171 */
172 public function testPutLinkDuplicate()
173 {
174 $link = [
175 'url' => 'mediagoblin.org/',
176 'title' => 'new entry',
177 'description' => 'shaare description',
178 'tags' => ['one', 'two'],
179 'private' => true,
180 ];
181 $env = Environment::mock([
182 'REQUEST_METHOD' => 'PUT',
183 'CONTENT_TYPE' => 'application/json'
184 ]);
185
186 $request = Request::createFromEnvironment($env);
187 $request = $request->withParsedBody($link);
188 $response = $this->controller->putLink($request, new Response(), ['id' => 41]);
189
190 $this->assertEquals(409, $response->getStatusCode());
191 $data = json_decode((string) $response->getBody(), true);
192 $this->assertEquals(self::NB_FIELDS_LINK, count($data));
193 $this->assertEquals(7, $data['id']);
194 $this->assertEquals('IuWvgA', $data['shorturl']);
195 $this->assertEquals('http://mediagoblin.org/', $data['url']);
196 $this->assertEquals('MediaGoblin', $data['title']);
197 $this->assertEquals('A free software media publishing platform #hashtagOther', $data['description']);
198 $this->assertEquals(['gnu', 'media', 'web', '.hidden', 'hashtag'], $data['tags']);
199 $this->assertEquals(false, $data['private']);
200 $this->assertEquals(
201 \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20130614_184135'),
202 \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
203 );
204 $this->assertEquals(
205 \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20130615_184230'),
206 \DateTime::createFromFormat(\DateTime::ATOM, $data['updated'])
207 );
208 }
209
210 /**
211 * Test link update on non existent link => ApiLinkNotFoundException.
212 *
213 * @expectedException Shaarli\Api\Exceptions\ApiLinkNotFoundException
214 * @expectedExceptionMessage Link not found
215 */
216 public function testGetLink404()
217 {
218 $env = Environment::mock([
219 'REQUEST_METHOD' => 'PUT',
220 ]);
221 $request = Request::createFromEnvironment($env);
222
223 $this->controller->putLink($request, new Response(), ['id' => -1]);
224 }
225}