]> git.immae.eu Git - github/shaarli/Shaarli.git/blob - tests/api/controllers/links/PostLinkTest.php
Merge pull request #1525 from ArthurHoaro/feature/rest-api-bookmark-dates
[github/shaarli/Shaarli.git] / tests / api / controllers / links / PostLinkTest.php
1 <?php
2
3 namespace Shaarli\Api\Controllers;
4
5 use Shaarli\Bookmark\Bookmark;
6 use Shaarli\Bookmark\BookmarkFileService;
7 use Shaarli\Config\ConfigManager;
8 use Shaarli\History;
9 use Shaarli\TestCase;
10 use Slim\Container;
11 use Slim\Http\Environment;
12 use Slim\Http\Request;
13 use Slim\Http\Response;
14 use Slim\Router;
15
16 /**
17 * Class PostLinkTest
18 *
19 * Test POST Link REST API service.
20 *
21 * @package Shaarli\Api\Controllers
22 */
23 class PostLinkTest extends TestCase
24 {
25 /**
26 * @var string datastore to test write operations
27 */
28 protected static $testDatastore = 'sandbox/datastore.php';
29
30 /**
31 * @var string datastore to test write operations
32 */
33 protected static $testHistory = 'sandbox/history.php';
34
35 /**
36 * @var ConfigManager instance
37 */
38 protected $conf;
39
40 /**
41 * @var \ReferenceLinkDB instance.
42 */
43 protected $refDB = null;
44
45 /**
46 * @var BookmarkFileService instance.
47 */
48 protected $bookmarkService;
49
50 /**
51 * @var HistoryController instance.
52 */
53 protected $history;
54
55 /**
56 * @var Container instance.
57 */
58 protected $container;
59
60 /**
61 * @var Links controller instance.
62 */
63 protected $controller;
64
65 /**
66 * Number of JSON field per link.
67 */
68 const NB_FIELDS_LINK = 9;
69
70 /**
71 * Before every test, instantiate a new Api with its config, plugins and bookmarks.
72 */
73 protected function setUp(): void
74 {
75 $this->conf = new ConfigManager('tests/utils/config/configJson');
76 $this->conf->set('resource.datastore', self::$testDatastore);
77 $this->refDB = new \ReferenceLinkDB();
78 $this->refDB->write(self::$testDatastore);
79 $refHistory = new \ReferenceHistory();
80 $refHistory->write(self::$testHistory);
81 $this->history = new History(self::$testHistory);
82 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true);
83
84 $this->container = new Container();
85 $this->container['conf'] = $this->conf;
86 $this->container['db'] = $this->bookmarkService;
87 $this->container['history'] = $this->history;
88
89 $this->controller = new Links($this->container);
90
91 $mock = $this->createMock(Router::class);
92 $mock->expects($this->any())
93 ->method('relativePathFor')
94 ->willReturn('api/v1/bookmarks/1');
95
96 // affect @property-read... seems to work
97 $this->controller->getCi()->router = $mock;
98
99 // Used by index_url().
100 $this->controller->getCi()['environment'] = [
101 'SERVER_NAME' => 'domain.tld',
102 'SERVER_PORT' => 80,
103 'SCRIPT_NAME' => '/',
104 ];
105 }
106
107 /**
108 * After every test, remove the test datastore.
109 */
110 protected function tearDown(): void
111 {
112 @unlink(self::$testDatastore);
113 @unlink(self::$testHistory);
114 }
115
116 /**
117 * Test link creation without any field: creates a blank note.
118 */
119 public function testPostLinkMinimal()
120 {
121 $env = Environment::mock([
122 'REQUEST_METHOD' => 'POST',
123 ]);
124
125 $request = Request::createFromEnvironment($env);
126
127 $response = $this->controller->postLink($request, new Response());
128 $this->assertEquals(201, $response->getStatusCode());
129 $this->assertEquals('api/v1/bookmarks/1', $response->getHeader('Location')[0]);
130 $data = json_decode((string) $response->getBody(), true);
131 $this->assertEquals(self::NB_FIELDS_LINK, count($data));
132 $this->assertEquals(43, $data['id']);
133 $this->assertRegExp('/[\w_-]{6}/', $data['shorturl']);
134 $this->assertEquals('http://domain.tld/shaare/' . $data['shorturl'], $data['url']);
135 $this->assertEquals('/shaare/' . $data['shorturl'], $data['title']);
136 $this->assertEquals('', $data['description']);
137 $this->assertEquals([], $data['tags']);
138 $this->assertEquals(true, $data['private']);
139 $this->assertTrue(
140 new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
141 );
142 $this->assertEquals('', $data['updated']);
143
144 $historyEntry = $this->history->getHistory()[0];
145 $this->assertEquals(History::CREATED, $historyEntry['event']);
146 $this->assertTrue(
147 (new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime']
148 );
149 $this->assertEquals(43, $historyEntry['id']);
150 }
151
152 /**
153 * Test link creation with all available fields.
154 */
155 public function testPostLinkFull()
156 {
157 $link = [
158 'url' => 'website.tld/test?foo=bar',
159 'title' => 'new entry',
160 'description' => 'shaare description',
161 'tags' => ['one', 'two'],
162 'private' => true,
163 'created' => '2015-05-05T12:30:00+03:00',
164 'updated' => '2016-06-05T14:32:10+03:00',
165 ];
166 $env = Environment::mock([
167 'REQUEST_METHOD' => 'POST',
168 'CONTENT_TYPE' => 'application/json'
169 ]);
170
171 $request = Request::createFromEnvironment($env);
172 $request = $request->withParsedBody($link);
173 $response = $this->controller->postLink($request, new Response());
174
175 $this->assertEquals(201, $response->getStatusCode());
176 $this->assertEquals('api/v1/bookmarks/1', $response->getHeader('Location')[0]);
177 $data = json_decode((string) $response->getBody(), true);
178 $this->assertEquals(self::NB_FIELDS_LINK, count($data));
179 $this->assertEquals(43, $data['id']);
180 $this->assertRegExp('/[\w_-]{6}/', $data['shorturl']);
181 $this->assertEquals('http://' . $link['url'], $data['url']);
182 $this->assertEquals($link['title'], $data['title']);
183 $this->assertEquals($link['description'], $data['description']);
184 $this->assertEquals($link['tags'], $data['tags']);
185 $this->assertEquals(true, $data['private']);
186 $this->assertSame($link['created'], $data['created']);
187 $this->assertSame($link['updated'], $data['updated']);
188 }
189
190 /**
191 * Test link creation with an existing link (duplicate URL). Should return a 409 HTTP error and the existing link.
192 */
193 public function testPostLinkDuplicate()
194 {
195 $link = [
196 'url' => 'mediagoblin.org/',
197 'title' => 'new entry',
198 'description' => 'shaare description',
199 'tags' => ['one', 'two'],
200 'private' => true,
201 ];
202 $env = Environment::mock([
203 'REQUEST_METHOD' => 'POST',
204 'CONTENT_TYPE' => 'application/json'
205 ]);
206
207 $request = Request::createFromEnvironment($env);
208 $request = $request->withParsedBody($link);
209 $response = $this->controller->postLink($request, new Response());
210
211 $this->assertEquals(409, $response->getStatusCode());
212 $data = json_decode((string) $response->getBody(), true);
213 $this->assertEquals(self::NB_FIELDS_LINK, count($data));
214 $this->assertEquals(7, $data['id']);
215 $this->assertEquals('IuWvgA', $data['shorturl']);
216 $this->assertEquals('http://mediagoblin.org/', $data['url']);
217 $this->assertEquals('MediaGoblin', $data['title']);
218 $this->assertEquals('A free software media publishing platform #hashtagOther', $data['description']);
219 $this->assertEquals(['gnu', 'media', 'web', '.hidden', 'hashtag'], $data['tags']);
220 $this->assertEquals(false, $data['private']);
221 $this->assertEquals(
222 \DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20130614_184135'),
223 \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
224 );
225 $this->assertEquals(
226 \DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20130615_184230'),
227 \DateTime::createFromFormat(\DateTime::ATOM, $data['updated'])
228 );
229 }
230 }