Completed
Push — master ( e5a757...47ec18 )
by Robbie
14s
created

RestfulServerTest::testNotFound()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 8

Duplication

Lines 12
Ratio 100 %

Importance

Changes 0
Metric Value
dl 12
loc 12
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 8
nc 1
nop 0
1
<?php
2
3
namespace SilverStripe\RestfulServer\Tests;
4
5
use SilverStripe\RestfulServer\Tests\Stubs\RestfulServerTestComment;
6
use SilverStripe\RestfulServer\Tests\Stubs\RestfulServerTestSecretThing;
7
use SilverStripe\RestfulServer\Tests\Stubs\RestfulServerTestPage;
8
use SilverStripe\RestfulServer\Tests\Stubs\RestfulServerTestAuthor;
9
use SilverStripe\RestfulServer\Tests\Stubs\RestfulServerTestAuthorRating;
10
use SilverStripe\Control\Director;
11
use SilverStripe\Core\Convert;
12
use SilverStripe\Control\Controller;
13
use SilverStripe\Security\Member;
14
use SilverStripe\Security\Security;
15
use SilverStripe\ORM\DataObject;
16
use SilverStripe\Dev\SapphireTest;
17
use SilverStripe\RestfulServer\DataFormatter\JSONDataFormatter;
18
use Page;
0 ignored issues
show
Bug introduced by
The type Page was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
20
/**
21
 *
22
 * @todo Test Relation getters
23
 * @todo Test filter and limit through GET params
24
 * @todo Test DELETE verb
25
 *
26
 */
27
class RestfulServerTest extends SapphireTest
28
{
29
    protected static $fixture_file = 'RestfulServerTest.yml';
30
31
    protected $baseURI = 'http://www.fakesite.test';
32
33
    protected static $extra_dataobjects = [
34
        RestfulServerTestComment::class,
35
        RestfulServerTestSecretThing::class,
36
        RestfulServerTestPage::class,
37
        RestfulServerTestAuthor::class,
38
        RestfulServerTestAuthorRating::class,
39
    ];
40
41
    protected function urlSafeClassname($classname)
42
    {
43
        return str_replace('\\', '-', $classname);
44
    }
45
46
    protected function setUp()
47
    {
48
        parent::setUp();
49
        Director::config()->set('alternate_base_url', $this->baseURI);
50
        Security::setCurrentUser(null);
51
    }
52
53 View Code Duplication
    public function testApiAccess()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
54
    {
55
        $comment1 = $this->objFromFixture(RestfulServerTestComment::class, 'comment1');
56
        $page1 = $this->objFromFixture(RestfulServerTestPage::class, 'page1');
57
58
        // normal GET should succeed with $api_access enabled
59
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
60
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $comment1->ID;
61
62
        $response = Director::test($url, null, null, 'GET');
63
        $this->assertEquals(200, $response->getStatusCode());
64
65
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
66
        $_SERVER['PHP_AUTH_PW'] = 'user';
67
68
        // even with logged in user a GET with $api_access disabled should fail
69
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestPage::class);
70
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $page1->ID;
71
        $response = Director::test($url, null, null, 'GET');
72
        $this->assertEquals(401, $response->getStatusCode());
73
74
        unset($_SERVER['PHP_AUTH_USER']);
75
        unset($_SERVER['PHP_AUTH_PW']);
76
    }
77
78
    public function testApiAccessBoolean()
79
    {
80
        $comment1 = $this->objFromFixture(RestfulServerTestComment::class, 'comment1');
81
82
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
83
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $comment1->ID;
84
        $response = Director::test($url, null, null, 'GET');
85
        $this->assertContains('<ID>', $response->getBody());
86
        $this->assertContains('<Name>', $response->getBody());
87
        $this->assertContains('<Comment>', $response->getBody());
88
        $this->assertContains('<Page', $response->getBody());
89
        $this->assertContains('<Author', $response->getBody());
90
    }
91
92 View Code Duplication
    public function testAuthenticatedGET()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
93
    {
94
        $thing1 = $this->objFromFixture(RestfulServerTestSecretThing::class, 'thing1');
95
        $comment1 = $this->objFromFixture(RestfulServerTestComment::class, 'comment1');
96
97
        // @todo create additional mock object with authenticated VIEW permissions
98
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestSecretThing::class);
99
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $thing1->ID;
100
        $response = Director::test($url, null, null, 'GET');
101
        $this->assertEquals(401, $response->getStatusCode());
102
103
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
104
        $_SERVER['PHP_AUTH_PW'] = 'user';
105
106
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
107
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $comment1->ID;
108
        $response = Director::test($url, null, null, 'GET');
109
        $this->assertEquals(200, $response->getStatusCode());
110
111
        unset($_SERVER['PHP_AUTH_USER']);
112
        unset($_SERVER['PHP_AUTH_PW']);
113
    }
114
115
    public function testAuthenticatedPUT()
116
    {
117
        $comment1 = $this->objFromFixture(RestfulServerTestComment::class, 'comment1');
118
119
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
120
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $comment1->ID;
121
        $data = array('Comment' => 'created');
122
123
        $response = Director::test($url, $data, null, 'PUT');
124
        $this->assertEquals(401, $response->getStatusCode()); // Permission failure
125
126
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
127
        $_SERVER['PHP_AUTH_PW'] = 'editor';
128
        $response = Director::test($url, $data, null, 'PUT');
129
        $this->assertEquals(200, $response->getStatusCode()); // Success
130
131
        unset($_SERVER['PHP_AUTH_USER']);
132
        unset($_SERVER['PHP_AUTH_PW']);
133
    }
134
135
    public function testGETRelationshipsXML()
136
    {
137
        $author1 = $this->objFromFixture(RestfulServerTestAuthor::class, 'author1');
138
        $rating1 = $this->objFromFixture(RestfulServerTestAuthorRating::class, 'rating1');
139
        $rating2 = $this->objFromFixture(RestfulServerTestAuthorRating::class, 'rating2');
140
141
        // @todo should be set up by fixtures, doesn't work for some reason...
142
        $author1->Ratings()->add($rating1);
143
        $author1->Ratings()->add($rating2);
144
145
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthor::class);
146
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $author1->ID;
147
        $response = Director::test($url, null, null, 'GET');
148
        $this->assertEquals(200, $response->getStatusCode());
149
150
        $responseArr = Convert::xml2array($response->getBody());
151
        $xmlTagSafeClassName = $this->urlSafeClassname(RestfulServerTestAuthorRating::class);
152
        $ratingsArr = $responseArr['Ratings'][$xmlTagSafeClassName];
153
        $this->assertEquals(2, count($ratingsArr));
154
        $ratingIDs = array(
155
            (int)$ratingsArr[0]['@attributes']['id'],
156
            (int)$ratingsArr[1]['@attributes']['id']
157
        );
158
        $this->assertContains($rating1->ID, $ratingIDs);
159
        $this->assertContains($rating2->ID, $ratingIDs);
160
    }
161
162
    public function testGETManyManyRelationshipsXML()
163
    {
164
        // author4 has related authors author2 and author3
165
        $author2 = $this->objFromFixture(RestfulServerTestAuthor::class, 'author2');
166
        $author3 = $this->objFromFixture(RestfulServerTestAuthor::class, 'author3');
167
        $author4 = $this->objFromFixture(RestfulServerTestAuthor::class, 'author4');
168
169
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthor::class);
170
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $author4->ID . '/RelatedAuthors';
171
        $response = Director::test($url, null, null, 'GET');
172
        $this->assertEquals(200, $response->getStatusCode());
173
        $arr = Convert::xml2array($response->getBody());
174
        $xmlSafeClassName = $this->urlSafeClassname(RestfulServerTestAuthor::class);
175
        $authorsArr = $arr[$xmlSafeClassName];
176
177
        $this->assertEquals(2, count($authorsArr));
178
        $ratingIDs = array(
179
            (int)$authorsArr[0]['ID'],
180
            (int)$authorsArr[1]['ID']
181
        );
182
        $this->assertContains($author2->ID, $ratingIDs);
183
        $this->assertContains($author3->ID, $ratingIDs);
184
    }
185
186
    public function testPUTWithFormEncoded()
187
    {
188
        $comment1 = $this->objFromFixture(RestfulServerTestComment::class, 'comment1');
189
190
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
191
        $_SERVER['PHP_AUTH_PW'] = 'editor';
192
193
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
194
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $comment1->ID;
195
        $body = 'Name=Updated Comment&Comment=updated';
196
        $headers = array(
197
            'Content-Type' => 'application/x-www-form-urlencoded'
198
        );
199
        $response = Director::test($url, null, null, 'PUT', $body, $headers);
200
        $this->assertEquals(200, $response->getStatusCode()); // Success
201
        // Assumption: XML is default output
202
        $responseArr = Convert::xml2array($response->getBody());
203
        $this->assertEquals($comment1->ID, $responseArr['ID']);
204
        $this->assertEquals('updated', $responseArr['Comment']);
205
        $this->assertEquals('Updated Comment', $responseArr['Name']);
206
207
        unset($_SERVER['PHP_AUTH_USER']);
208
        unset($_SERVER['PHP_AUTH_PW']);
209
    }
210
211
    public function testPOSTWithFormEncoded()
212
    {
213
        $comment1 = $this->objFromFixture(RestfulServerTestComment::class, 'comment1');
214
215
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
216
        $_SERVER['PHP_AUTH_PW'] = 'editor';
217
218
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
219
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname";
220
        $body = 'Name=New Comment&Comment=created';
221
        $headers = array(
222
            'Content-Type' => 'application/x-www-form-urlencoded'
223
        );
224
        $response = Director::test($url, null, null, 'POST', $body, $headers);
225
        $this->assertEquals(201, $response->getStatusCode()); // Created
226
        // Assumption: XML is default output
227
        $responseArr = Convert::xml2array($response->getBody());
228
        $this->assertTrue($responseArr['ID'] > 0);
229
        $this->assertNotEquals($responseArr['ID'], $comment1->ID);
230
        $this->assertEquals('created', $responseArr['Comment']);
231
        $this->assertEquals('New Comment', $responseArr['Name']);
232
        $this->assertEquals(
233
            Controller::join_links($url, $responseArr['ID'] . '.xml'),
234
            $response->getHeader('Location')
235
        );
236
237
        unset($_SERVER['PHP_AUTH_USER']);
238
        unset($_SERVER['PHP_AUTH_PW']);
239
    }
240
241 View Code Duplication
    public function testPostWithoutBodyReturnsNoContent()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
242
    {
243
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
244
        $_SERVER['PHP_AUTH_PW'] = 'editor';
245
246
        $url = "{$this->baseURI}/api/v1/" . RestfulServerTestComment::class;
247
        $response = Director::test($url, null, null, 'POST');
248
249
        $this->assertEquals('No Content', $response->getBody());
250
251
        unset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
252
    }
253
254
    public function testPUTwithJSON()
255
    {
256
        $comment1 = $this->objFromFixture(RestfulServerTestComment::class, 'comment1');
257
258
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
259
        $_SERVER['PHP_AUTH_PW'] = 'editor';
260
261
        // by acceptance mimetype
262
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
263
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $comment1->ID;
264
        $body = '{"Comment":"updated"}';
265
        $response = Director::test($url, null, null, 'PUT', $body, array(
266
            'Content-Type'=>'application/json',
267
            'Accept' => 'application/json'
268
        ));
269
        $this->assertEquals(200, $response->getStatusCode()); // Updated
270
        $obj = Convert::json2obj($response->getBody());
271
        $this->assertEquals($comment1->ID, $obj->ID);
272
        $this->assertEquals('updated', $obj->Comment);
273
274
        // by extension
275
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
276
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/{$comment1->ID}.json";
277
        $body = '{"Comment":"updated"}';
278
        $response = Director::test($url, null, null, 'PUT', $body);
279
        $this->assertEquals(200, $response->getStatusCode()); // Updated
280
        $this->assertEquals($url, $response->getHeader('Location'));
281
        $obj = Convert::json2obj($response->getBody());
282
        $this->assertEquals($comment1->ID, $obj->ID);
283
        $this->assertEquals('updated', $obj->Comment);
284
285
        unset($_SERVER['PHP_AUTH_USER']);
286
        unset($_SERVER['PHP_AUTH_PW']);
287
    }
288
289
    public function testPUTwithXML()
290
    {
291
        $comment1 = $this->objFromFixture(RestfulServerTestComment::class, 'comment1');
292
293
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
294
        $_SERVER['PHP_AUTH_PW'] = 'editor';
295
296
        // by mimetype
297
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
298
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $comment1->ID;
299
        $body = '<RestfulServerTestComment><Comment>updated</Comment></RestfulServerTestComment>';
300
        $response = Director::test($url, null, null, 'PUT', $body, array('Content-Type'=>'text/xml'));
301
        $this->assertEquals(200, $response->getStatusCode()); // Updated
302
        $obj = Convert::xml2array($response->getBody());
303
        $this->assertEquals($comment1->ID, $obj['ID']);
304
        $this->assertEquals('updated', $obj['Comment']);
305
306
        // by extension
307
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
308
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/{$comment1->ID}.xml";
309
        $body = '<RestfulServerTestComment><Comment>updated</Comment></RestfulServerTestComment>';
310
        $response = Director::test($url, null, null, 'PUT', $body);
311
        $this->assertEquals(200, $response->getStatusCode()); // Updated
312
        $this->assertEquals($url, $response->getHeader('Location'));
313
        $obj = Convert::xml2array($response->getBody());
314
        $this->assertEquals($comment1->ID, $obj['ID']);
315
        $this->assertEquals('updated', $obj['Comment']);
316
317
        unset($_SERVER['PHP_AUTH_USER']);
318
        unset($_SERVER['PHP_AUTH_PW']);
319
    }
320
321
    public function testHTTPAcceptAndContentType()
322
    {
323
        $comment1 = $this->objFromFixture(RestfulServerTestComment::class, 'comment1');
324
325
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
326
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $comment1->ID;
327
328
        $headers = array('Accept' => 'application/json');
329
        $response = Director::test($url, null, null, 'GET', null, $headers);
330
        $this->assertEquals(200, $response->getStatusCode()); // Success
331
        $obj = Convert::json2obj($response->getBody());
332
        $this->assertEquals($comment1->ID, $obj->ID);
333
        $this->assertEquals('application/json', $response->getHeader('Content-Type'));
334
    }
335
336 View Code Duplication
    public function testNotFound()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
337
    {
338
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
339
        $_SERVER['PHP_AUTH_PW'] = 'user';
340
341
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
342
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/99";
343
        $response = Director::test($url, null, null, 'GET');
344
        $this->assertEquals(404, $response->getStatusCode());
345
346
        unset($_SERVER['PHP_AUTH_USER']);
347
        unset($_SERVER['PHP_AUTH_PW']);
348
    }
349
350 View Code Duplication
    public function testMethodNotAllowed()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
351
    {
352
        $comment1 = $this->objFromFixture(RestfulServerTestComment::class, 'comment1');
353
354
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
355
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $comment1->ID;
356
        $response = Director::test($url, null, null, 'UNKNOWNHTTPMETHOD');
357
        $this->assertEquals(405, $response->getStatusCode());
358
    }
359
360 View Code Duplication
    public function testConflictOnExistingResourceWhenUsingPost()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
361
    {
362
        $rating1 = $this->objFromFixture(RestfulServerTestAuthorRating::class, 'rating1');
363
364
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthorRating::class);
365
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $rating1->ID;
366
        $response = Director::test($url, null, null, 'POST');
367
        $this->assertEquals(409, $response->getStatusCode());
368
    }
369
370
    public function testUnsupportedMediaType()
371
    {
372
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
373
        $_SERVER['PHP_AUTH_PW'] = 'user';
374
375
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
376
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname";
377
        $data = "Comment||\/||updated"; // weird format
378
        $headers = array('Content-Type' => 'text/weirdformat');
379
        $response = Director::test($url, null, null, 'POST', $data, $headers);
380
        $this->assertEquals(415, $response->getStatusCode());
381
382
        unset($_SERVER['PHP_AUTH_USER']);
383
        unset($_SERVER['PHP_AUTH_PW']);
384
    }
385
386
    public function testXMLValueFormatting()
387
    {
388
        $rating1 = $this->objFromFixture(RestfulServerTestAuthorRating::class, 'rating1');
389
390
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthorRating::class);
391
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $rating1->ID;
392
        $response = Director::test($url, null, null, 'GET');
393
        $this->assertContains('<ID>' . $rating1->ID . '</ID>', $response->getBody());
394
        $this->assertContains('<Rating>' . $rating1->Rating . '</Rating>', $response->getBody());
395
    }
396
397
    public function testApiAccessFieldRestrictions()
398
    {
399
        $author1 = $this->objFromFixture(RestfulServerTestAuthor::class, 'author1');
400
        $rating1 = $this->objFromFixture(RestfulServerTestAuthorRating::class, 'rating1');
401
402
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthorRating::class);
403
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $rating1->ID;
404
        $response = Director::test($url, null, null, 'GET');
405
        $this->assertContains('<ID>', $response->getBody());
406
        $this->assertContains('<Rating>', $response->getBody());
407
        $this->assertContains('<Author', $response->getBody());
408
        $this->assertNotContains('<SecretField>', $response->getBody());
409
        $this->assertNotContains('<SecretRelation>', $response->getBody());
410
411
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthorRating::class);
412
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $rating1->ID . '?add_fields=SecretField,SecretRelation';
413
        $response = Director::test($url, null, null, 'GET');
414
        $this->assertNotContains(
415
            '<SecretField>',
416
            $response->getBody(),
417
            '"add_fields" URL parameter filters out disallowed fields from $api_access'
418
        );
419
        $this->assertNotContains(
420
            '<SecretRelation>',
421
            $response->getBody(),
422
            '"add_fields" URL parameter filters out disallowed relations from $api_access'
423
        );
424
425
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthorRating::class);
426
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $rating1->ID . '?fields=SecretField,SecretRelation';
427
        $response = Director::test($url, null, null, 'GET');
428
        $this->assertNotContains(
429
            '<SecretField>',
430
            $response->getBody(),
431
            '"fields" URL parameter filters out disallowed fields from $api_access'
432
        );
433
        $this->assertNotContains(
434
            '<SecretRelation>',
435
            $response->getBody(),
436
            '"fields" URL parameter filters out disallowed relations from $api_access'
437
        );
438
439
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthor::class);
440
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $author1->ID . '/Ratings';
441
        $response = Director::test($url, null, null, 'GET');
442
        $this->assertContains(
443
            '<Rating>',
444
            $response->getBody(),
445
            'Relation viewer shows fields allowed through $api_access'
446
        );
447
        $this->assertNotContains(
448
            '<SecretField>',
449
            $response->getBody(),
450
            'Relation viewer on has-many filters out disallowed fields from $api_access'
451
        );
452
    }
453
454
    public function testApiAccessRelationRestrictionsInline()
455
    {
456
        $author1 = $this->objFromFixture(RestfulServerTestAuthor::class, 'author1');
457
458
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthor::class);
459
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $author1->ID;
460
        $response = Director::test($url, null, null, 'GET');
461
        $this->assertNotContains('<RelatedPages', $response->getBody(), 'Restricts many-many with api_access=false');
462
        $this->assertNotContains('<PublishedPages', $response->getBody(), 'Restricts has-many with api_access=false');
463
    }
464
465
    public function testApiAccessRelationRestrictionsOnEndpoint()
466
    {
467
        $author1 = $this->objFromFixture(RestfulServerTestAuthor::class, 'author1');
468
469
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthor::class);
470
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $author1->ID . "/ProfilePage";
471
        $response = Director::test($url, null, null, 'GET');
472
        $this->assertEquals(404, $response->getStatusCode(), 'Restricts has-one with api_access=false');
473
474
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthor::class);
475
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $author1->ID . "/RelatedPages";
476
        $response = Director::test($url, null, null, 'GET');
477
        $this->assertEquals(404, $response->getStatusCode(), 'Restricts many-many with api_access=false');
478
479
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthor::class);
480
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $author1->ID . "/PublishedPages";
481
        $response = Director::test($url, null, null, 'GET');
482
        $this->assertEquals(404, $response->getStatusCode(), 'Restricts has-many with api_access=false');
483
    }
484
485
    public function testApiAccessWithPUT()
486
    {
487
        $rating1 = $this->objFromFixture(RestfulServerTestAuthorRating::class, 'rating1');
488
489
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthorRating::class);
490
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $rating1->ID;
491
        $data = array(
492
            'Rating' => '42',
493
            'WriteProtectedField' => 'haxx0red'
494
        );
495
        $response = Director::test($url, $data, null, 'PUT');
496
        // Assumption: XML is default output
497
        $responseArr = Convert::xml2array($response->getBody());
498
        $this->assertEquals(42, $responseArr['Rating']);
499
        $this->assertNotEquals('haxx0red', $responseArr['WriteProtectedField']);
500
    }
501
502
    public function testJSONDataFormatter()
503
    {
504
        $formatter = new JSONDataFormatter();
505
        $editor = $this->objFromFixture(Member::class, 'editor');
506
        $user = $this->objFromFixture(Member::class, 'user');
507
508
        // The DataFormatter performs canView calls
509
        // these are `Member`s so we need to be ADMIN types
510
        $this->logInWithPermission('ADMIN');
511
512
        $this->assertEquals(
513
            '{"FirstName":"Editor","Email":"[email protected]"}',
514
            $formatter->convertDataObject($editor, ["FirstName", "Email"]),
515
            "Correct JSON formatting with field subset"
516
        );
517
518
        $set = Member::get()
519
            ->filter('ID', [$editor->ID, $user->ID])
520
            ->sort('"Email" ASC'); // for sorting for postgres
521
        $this->assertEquals(
522
            '{"totalSize":null,"items":[{"FirstName":"Editor","Email":"[email protected]"},' .
523
                '{"FirstName":"User","Email":"[email protected]"}]}',
524
            $formatter->convertDataObjectSet($set, ["FirstName", "Email"]),
525
            "Correct JSON formatting on a dataobjectset with field filter"
526
        );
527
    }
528
529
    public function testApiAccessWithPOST()
530
    {
531
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthorRating::class);
532
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/";
533
        $data = [
534
            'Rating' => '42',
535
            'WriteProtectedField' => 'haxx0red'
536
        ];
537
        $response = Director::test($url, $data, null, 'POST');
538
        // Assumption: XML is default output
539
        $responseArr = Convert::xml2array($response->getBody());
540
        $this->assertEquals(42, $responseArr['Rating']);
541
        $this->assertNotEquals('haxx0red', $responseArr['WriteProtectedField']);
542
    }
543
544
    public function testCanViewRespectedInList()
545
    {
546
        // Default content type
547
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestSecretThing::class);
548
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/";
549
        $response = Director::test($url, null, null, 'GET');
550
        $this->assertEquals(200, $response->getStatusCode());
551
        $this->assertNotContains('Unspeakable', $response->getBody());
552
553
        // JSON content type
554
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname.json";
555
        $response = Director::test($url, null, null, 'GET');
556
        $this->assertEquals(200, $response->getStatusCode());
557
        $this->assertNotContains('Unspeakable', $response->getBody());
558
        $responseArray = Convert::json2array($response->getBody());
559
        $this->assertSame(0, $responseArray['totalSize']);
560
561
        // With authentication
562
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
563
        $_SERVER['PHP_AUTH_PW'] = 'editor';
564
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestSecretThing::class);
565
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/";
566
        $response = Director::test($url, null, null, 'GET');
567
        $this->assertEquals(200, $response->getStatusCode());
568
        $this->assertContains('Unspeakable', $response->getBody());
569
        // Assumption: default formatter is XML
570
        $responseArray = Convert::xml2array($response->getBody());
571
        $this->assertEquals(1, $responseArray['@attributes']['totalSize']);
572
        unset($_SERVER['PHP_AUTH_USER']);
573
        unset($_SERVER['PHP_AUTH_PW']);
574
    }
575
}
576