Completed
Push — master ( b59d95...c30b72 )
by Robbie
10s
created

RestfulServerTest::testValidationErrorWithPOST()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 7
nc 1
nop 0
dl 0
loc 11
rs 9.4285
c 0
b 0
f 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\RestfulServer\Tests\Stubs\RestfulServerTestValidationFailure;
14
use SilverStripe\Security\Member;
15
use SilverStripe\Security\Security;
16
use SilverStripe\ORM\DataObject;
17
use SilverStripe\Dev\SapphireTest;
18
use SilverStripe\RestfulServer\DataFormatter\JSONDataFormatter;
19
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...
20
21
/**
22
 *
23
 * @todo Test Relation getters
24
 * @todo Test filter and limit through GET params
25
 * @todo Test DELETE verb
26
 *
27
 */
28
class RestfulServerTest extends SapphireTest
29
{
30
    protected static $fixture_file = 'RestfulServerTest.yml';
31
32
    protected $baseURI = 'http://www.fakesite.test';
33
34
    protected static $extra_dataobjects = [
35
        RestfulServerTestComment::class,
36
        RestfulServerTestSecretThing::class,
37
        RestfulServerTestPage::class,
38
        RestfulServerTestAuthor::class,
39
        RestfulServerTestAuthorRating::class,
40
    ];
41
42
    protected function urlSafeClassname($classname)
43
    {
44
        return str_replace('\\', '-', $classname);
45
    }
46
47
    protected function setUp()
48
    {
49
        parent::setUp();
50
        Director::config()->set('alternate_base_url', $this->baseURI);
51
        Security::setCurrentUser(null);
52
    }
53
54
    public function testApiAccess()
55
    {
56
        $comment1 = $this->objFromFixture(RestfulServerTestComment::class, 'comment1');
57
        $page1 = $this->objFromFixture(RestfulServerTestPage::class, 'page1');
58
59
        // normal GET should succeed with $api_access enabled
60
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
61
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $comment1->ID;
62
63
        $response = Director::test($url, null, null, 'GET');
64
        $this->assertEquals(200, $response->getStatusCode());
65
66
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
67
        $_SERVER['PHP_AUTH_PW'] = 'user';
68
69
        // even with logged in user a GET with $api_access disabled should fail
70
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestPage::class);
71
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $page1->ID;
72
        $response = Director::test($url, null, null, 'GET');
73
        $this->assertEquals(401, $response->getStatusCode());
74
75
        unset($_SERVER['PHP_AUTH_USER']);
76
        unset($_SERVER['PHP_AUTH_PW']);
77
    }
78
79
    public function testApiAccessBoolean()
80
    {
81
        $comment1 = $this->objFromFixture(RestfulServerTestComment::class, 'comment1');
82
83
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
84
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $comment1->ID;
85
        $response = Director::test($url, null, null, 'GET');
86
        $this->assertContains('<ID>', $response->getBody());
87
        $this->assertContains('<Name>', $response->getBody());
88
        $this->assertContains('<Comment>', $response->getBody());
89
        $this->assertContains('<Page', $response->getBody());
90
        $this->assertContains('<Author', $response->getBody());
91
    }
92
93
    public function testAuthenticatedGET()
94
    {
95
        $thing1 = $this->objFromFixture(RestfulServerTestSecretThing::class, 'thing1');
96
        $comment1 = $this->objFromFixture(RestfulServerTestComment::class, 'comment1');
97
98
        // @todo create additional mock object with authenticated VIEW permissions
99
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestSecretThing::class);
100
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $thing1->ID;
101
        $response = Director::test($url, null, null, 'GET');
102
        $this->assertEquals(401, $response->getStatusCode());
103
104
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
105
        $_SERVER['PHP_AUTH_PW'] = 'user';
106
107
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
108
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $comment1->ID;
109
        $response = Director::test($url, null, null, 'GET');
110
        $this->assertEquals(200, $response->getStatusCode());
111
112
        unset($_SERVER['PHP_AUTH_USER']);
113
        unset($_SERVER['PHP_AUTH_PW']);
114
    }
115
116
    public function testAuthenticatedPUT()
117
    {
118
        $comment1 = $this->objFromFixture(RestfulServerTestComment::class, 'comment1');
119
120
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
121
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $comment1->ID;
122
        $data = array('Comment' => 'created');
123
124
        $response = Director::test($url, $data, null, 'PUT');
125
        $this->assertEquals(401, $response->getStatusCode()); // Permission failure
126
127
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
128
        $_SERVER['PHP_AUTH_PW'] = 'editor';
129
        $response = Director::test($url, $data, null, 'PUT');
130
        $this->assertEquals(200, $response->getStatusCode()); // Success
131
132
        unset($_SERVER['PHP_AUTH_USER']);
133
        unset($_SERVER['PHP_AUTH_PW']);
134
    }
135
136
    public function testGETRelationshipsXML()
137
    {
138
        $author1 = $this->objFromFixture(RestfulServerTestAuthor::class, 'author1');
139
        $rating1 = $this->objFromFixture(RestfulServerTestAuthorRating::class, 'rating1');
140
        $rating2 = $this->objFromFixture(RestfulServerTestAuthorRating::class, 'rating2');
141
142
        // @todo should be set up by fixtures, doesn't work for some reason...
143
        $author1->Ratings()->add($rating1);
144
        $author1->Ratings()->add($rating2);
145
146
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthor::class);
147
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $author1->ID;
148
        $response = Director::test($url, null, null, 'GET');
149
        $this->assertEquals(200, $response->getStatusCode());
150
151
        $responseArr = Convert::xml2array($response->getBody());
152
        $xmlTagSafeClassName = $this->urlSafeClassname(RestfulServerTestAuthorRating::class);
153
        $ratingsArr = $responseArr['Ratings'][$xmlTagSafeClassName];
154
        $this->assertEquals(2, count($ratingsArr));
155
        $ratingIDs = array(
156
            (int)$ratingsArr[0]['@attributes']['id'],
157
            (int)$ratingsArr[1]['@attributes']['id']
158
        );
159
        $this->assertContains($rating1->ID, $ratingIDs);
160
        $this->assertContains($rating2->ID, $ratingIDs);
161
    }
162
163
    public function testGETManyManyRelationshipsXML()
164
    {
165
        // author4 has related authors author2 and author3
166
        $author2 = $this->objFromFixture(RestfulServerTestAuthor::class, 'author2');
167
        $author3 = $this->objFromFixture(RestfulServerTestAuthor::class, 'author3');
168
        $author4 = $this->objFromFixture(RestfulServerTestAuthor::class, 'author4');
169
170
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthor::class);
171
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $author4->ID . '/RelatedAuthors';
172
        $response = Director::test($url, null, null, 'GET');
173
        $this->assertEquals(200, $response->getStatusCode());
174
        $arr = Convert::xml2array($response->getBody());
175
        $xmlSafeClassName = $this->urlSafeClassname(RestfulServerTestAuthor::class);
176
        $authorsArr = $arr[$xmlSafeClassName];
177
178
        $this->assertEquals(2, count($authorsArr));
179
        $ratingIDs = array(
180
            (int)$authorsArr[0]['ID'],
181
            (int)$authorsArr[1]['ID']
182
        );
183
        $this->assertContains($author2->ID, $ratingIDs);
184
        $this->assertContains($author3->ID, $ratingIDs);
185
    }
186
187
    public function testPUTWithFormEncoded()
188
    {
189
        $comment1 = $this->objFromFixture(RestfulServerTestComment::class, 'comment1');
190
191
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
192
        $_SERVER['PHP_AUTH_PW'] = 'editor';
193
194
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
195
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $comment1->ID;
196
        $body = 'Name=Updated Comment&Comment=updated';
197
        $headers = array(
198
            'Content-Type' => 'application/x-www-form-urlencoded'
199
        );
200
        $response = Director::test($url, null, null, 'PUT', $body, $headers);
201
        $this->assertEquals(200, $response->getStatusCode()); // Success
202
        // Assumption: XML is default output
203
        $responseArr = Convert::xml2array($response->getBody());
204
        $this->assertEquals($comment1->ID, $responseArr['ID']);
205
        $this->assertEquals('updated', $responseArr['Comment']);
206
        $this->assertEquals('Updated Comment', $responseArr['Name']);
207
208
        unset($_SERVER['PHP_AUTH_USER']);
209
        unset($_SERVER['PHP_AUTH_PW']);
210
    }
211
212
    public function testPOSTWithFormEncoded()
213
    {
214
        $comment1 = $this->objFromFixture(RestfulServerTestComment::class, 'comment1');
215
216
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
217
        $_SERVER['PHP_AUTH_PW'] = 'editor';
218
219
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
220
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname";
221
        $body = 'Name=New Comment&Comment=created';
222
        $headers = array(
223
            'Content-Type' => 'application/x-www-form-urlencoded'
224
        );
225
        $response = Director::test($url, null, null, 'POST', $body, $headers);
226
        $this->assertEquals(201, $response->getStatusCode()); // Created
227
        // Assumption: XML is default output
228
        $responseArr = Convert::xml2array($response->getBody());
229
        $this->assertTrue($responseArr['ID'] > 0);
230
        $this->assertNotEquals($responseArr['ID'], $comment1->ID);
231
        $this->assertEquals('created', $responseArr['Comment']);
232
        $this->assertEquals('New Comment', $responseArr['Name']);
233
        $this->assertEquals(
234
            Controller::join_links($url, $responseArr['ID'] . '.xml'),
235
            $response->getHeader('Location')
236
        );
237
238
        unset($_SERVER['PHP_AUTH_USER']);
239
        unset($_SERVER['PHP_AUTH_PW']);
240
    }
241
242
    public function testPostWithoutBodyReturnsNoContent()
243
    {
244
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
245
        $_SERVER['PHP_AUTH_PW'] = 'editor';
246
247
        $url = "{$this->baseURI}/api/v1/" . RestfulServerTestComment::class;
248
        $response = Director::test($url, null, null, 'POST');
249
250
        $this->assertEquals('No Content', $response->getBody());
251
252
        unset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
253
    }
254
255
    public function testPUTwithJSON()
256
    {
257
        $comment1 = $this->objFromFixture(RestfulServerTestComment::class, 'comment1');
258
259
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
260
        $_SERVER['PHP_AUTH_PW'] = 'editor';
261
262
        // by acceptance mimetype
263
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
264
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $comment1->ID;
265
        $body = '{"Comment":"updated"}';
266
        $response = Director::test($url, null, null, 'PUT', $body, array(
267
            'Content-Type'=>'application/json',
268
            'Accept' => 'application/json'
269
        ));
270
        $this->assertEquals(200, $response->getStatusCode()); // Updated
271
        $obj = Convert::json2obj($response->getBody());
272
        $this->assertEquals($comment1->ID, $obj->ID);
273
        $this->assertEquals('updated', $obj->Comment);
274
275
        // by extension
276
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
277
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/{$comment1->ID}.json";
278
        $body = '{"Comment":"updated"}';
279
        $response = Director::test($url, null, null, 'PUT', $body);
280
        $this->assertEquals(200, $response->getStatusCode()); // Updated
281
        $this->assertEquals($url, $response->getHeader('Location'));
282
        $obj = Convert::json2obj($response->getBody());
283
        $this->assertEquals($comment1->ID, $obj->ID);
284
        $this->assertEquals('updated', $obj->Comment);
285
286
        unset($_SERVER['PHP_AUTH_USER']);
287
        unset($_SERVER['PHP_AUTH_PW']);
288
    }
289
290
    public function testPUTwithXML()
291
    {
292
        $comment1 = $this->objFromFixture(RestfulServerTestComment::class, 'comment1');
293
294
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
295
        $_SERVER['PHP_AUTH_PW'] = 'editor';
296
297
        // by mimetype
298
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
299
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $comment1->ID;
300
        $body = '<RestfulServerTestComment><Comment>updated</Comment></RestfulServerTestComment>';
301
        $response = Director::test($url, null, null, 'PUT', $body, array('Content-Type'=>'text/xml'));
302
        $this->assertEquals(200, $response->getStatusCode()); // Updated
303
        $obj = Convert::xml2array($response->getBody());
304
        $this->assertEquals($comment1->ID, $obj['ID']);
305
        $this->assertEquals('updated', $obj['Comment']);
306
307
        // by extension
308
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
309
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/{$comment1->ID}.xml";
310
        $body = '<RestfulServerTestComment><Comment>updated</Comment></RestfulServerTestComment>';
311
        $response = Director::test($url, null, null, 'PUT', $body);
312
        $this->assertEquals(200, $response->getStatusCode()); // Updated
313
        $this->assertEquals($url, $response->getHeader('Location'));
314
        $obj = Convert::xml2array($response->getBody());
315
        $this->assertEquals($comment1->ID, $obj['ID']);
316
        $this->assertEquals('updated', $obj['Comment']);
317
318
        unset($_SERVER['PHP_AUTH_USER']);
319
        unset($_SERVER['PHP_AUTH_PW']);
320
    }
321
322
    public function testHTTPAcceptAndContentType()
323
    {
324
        $comment1 = $this->objFromFixture(RestfulServerTestComment::class, 'comment1');
325
326
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
327
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $comment1->ID;
328
329
        $headers = array('Accept' => 'application/json');
330
        $response = Director::test($url, null, null, 'GET', null, $headers);
331
        $this->assertEquals(200, $response->getStatusCode()); // Success
332
        $obj = Convert::json2obj($response->getBody());
333
        $this->assertEquals($comment1->ID, $obj->ID);
334
        $this->assertEquals('application/json', $response->getHeader('Content-Type'));
335
    }
336
337
    public function testNotFound()
338
    {
339
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
340
        $_SERVER['PHP_AUTH_PW'] = 'user';
341
342
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
343
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/99";
344
        $response = Director::test($url, null, null, 'GET');
345
        $this->assertEquals(404, $response->getStatusCode());
346
347
        unset($_SERVER['PHP_AUTH_USER']);
348
        unset($_SERVER['PHP_AUTH_PW']);
349
    }
350
351
    public function testMethodNotAllowed()
352
    {
353
        $comment1 = $this->objFromFixture(RestfulServerTestComment::class, 'comment1');
354
355
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
356
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $comment1->ID;
357
        $response = Director::test($url, null, null, 'UNKNOWNHTTPMETHOD');
358
        $this->assertEquals(405, $response->getStatusCode());
359
    }
360
361
    public function testConflictOnExistingResourceWhenUsingPost()
362
    {
363
        $rating1 = $this->objFromFixture(RestfulServerTestAuthorRating::class, 'rating1');
364
365
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthorRating::class);
366
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $rating1->ID;
367
        $response = Director::test($url, null, null, 'POST');
368
        $this->assertEquals(409, $response->getStatusCode());
369
    }
370
371
    public function testUnsupportedMediaType()
372
    {
373
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
374
        $_SERVER['PHP_AUTH_PW'] = 'user';
375
376
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestComment::class);
377
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname";
378
        $data = "Comment||\/||updated"; // weird format
379
        $headers = array('Content-Type' => 'text/weirdformat');
380
        $response = Director::test($url, null, null, 'POST', $data, $headers);
381
        $this->assertEquals(415, $response->getStatusCode());
382
383
        unset($_SERVER['PHP_AUTH_USER']);
384
        unset($_SERVER['PHP_AUTH_PW']);
385
    }
386
387
    public function testXMLValueFormatting()
388
    {
389
        $rating1 = $this->objFromFixture(RestfulServerTestAuthorRating::class, 'rating1');
390
391
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthorRating::class);
392
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $rating1->ID;
393
        $response = Director::test($url, null, null, 'GET');
394
        $this->assertContains('<ID>' . $rating1->ID . '</ID>', $response->getBody());
395
        $this->assertContains('<Rating>' . $rating1->Rating . '</Rating>', $response->getBody());
396
    }
397
398
    public function testApiAccessFieldRestrictions()
399
    {
400
        $author1 = $this->objFromFixture(RestfulServerTestAuthor::class, 'author1');
401
        $rating1 = $this->objFromFixture(RestfulServerTestAuthorRating::class, 'rating1');
402
403
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthorRating::class);
404
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $rating1->ID;
405
        $response = Director::test($url, null, null, 'GET');
406
        $this->assertContains('<ID>', $response->getBody());
407
        $this->assertContains('<Rating>', $response->getBody());
408
        $this->assertContains('<Author', $response->getBody());
409
        $this->assertNotContains('<SecretField>', $response->getBody());
410
        $this->assertNotContains('<SecretRelation>', $response->getBody());
411
412
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthorRating::class);
413
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $rating1->ID . '?add_fields=SecretField,SecretRelation';
414
        $response = Director::test($url, null, null, 'GET');
415
        $this->assertNotContains(
416
            '<SecretField>',
417
            $response->getBody(),
418
            '"add_fields" URL parameter filters out disallowed fields from $api_access'
419
        );
420
        $this->assertNotContains(
421
            '<SecretRelation>',
422
            $response->getBody(),
423
            '"add_fields" URL parameter filters out disallowed relations from $api_access'
424
        );
425
426
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthorRating::class);
427
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $rating1->ID . '?fields=SecretField,SecretRelation';
428
        $response = Director::test($url, null, null, 'GET');
429
        $this->assertNotContains(
430
            '<SecretField>',
431
            $response->getBody(),
432
            '"fields" URL parameter filters out disallowed fields from $api_access'
433
        );
434
        $this->assertNotContains(
435
            '<SecretRelation>',
436
            $response->getBody(),
437
            '"fields" URL parameter filters out disallowed relations from $api_access'
438
        );
439
440
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthor::class);
441
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $author1->ID . '/Ratings';
442
        $response = Director::test($url, null, null, 'GET');
443
        $this->assertContains(
444
            '<Rating>',
445
            $response->getBody(),
446
            'Relation viewer shows fields allowed through $api_access'
447
        );
448
        $this->assertNotContains(
449
            '<SecretField>',
450
            $response->getBody(),
451
            'Relation viewer on has-many filters out disallowed fields from $api_access'
452
        );
453
    }
454
455
    public function testApiAccessRelationRestrictionsInline()
456
    {
457
        $author1 = $this->objFromFixture(RestfulServerTestAuthor::class, 'author1');
458
459
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthor::class);
460
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $author1->ID;
461
        $response = Director::test($url, null, null, 'GET');
462
        $this->assertNotContains('<RelatedPages', $response->getBody(), 'Restricts many-many with api_access=false');
463
        $this->assertNotContains('<PublishedPages', $response->getBody(), 'Restricts has-many with api_access=false');
464
    }
465
466
    public function testApiAccessRelationRestrictionsOnEndpoint()
467
    {
468
        $author1 = $this->objFromFixture(RestfulServerTestAuthor::class, 'author1');
469
470
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthor::class);
471
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $author1->ID . "/ProfilePage";
472
        $response = Director::test($url, null, null, 'GET');
473
        $this->assertEquals(404, $response->getStatusCode(), 'Restricts has-one with api_access=false');
474
475
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthor::class);
476
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $author1->ID . "/RelatedPages";
477
        $response = Director::test($url, null, null, 'GET');
478
        $this->assertEquals(404, $response->getStatusCode(), 'Restricts many-many with api_access=false');
479
480
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthor::class);
481
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $author1->ID . "/PublishedPages";
482
        $response = Director::test($url, null, null, 'GET');
483
        $this->assertEquals(404, $response->getStatusCode(), 'Restricts has-many with api_access=false');
484
    }
485
486
    public function testApiAccessWithPUT()
487
    {
488
        $rating1 = $this->objFromFixture(RestfulServerTestAuthorRating::class, 'rating1');
489
490
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthorRating::class);
491
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $rating1->ID;
492
        $data = array(
493
            'Rating' => '42',
494
            'WriteProtectedField' => 'haxx0red'
495
        );
496
        $response = Director::test($url, $data, null, 'PUT');
497
        // Assumption: XML is default output
498
        $responseArr = Convert::xml2array($response->getBody());
499
        $this->assertEquals(42, $responseArr['Rating']);
500
        $this->assertNotEquals('haxx0red', $responseArr['WriteProtectedField']);
501
    }
502
503
    public function testJSONDataFormatter()
504
    {
505
        $formatter = new JSONDataFormatter();
506
        $editor = $this->objFromFixture(Member::class, 'editor');
507
        $user = $this->objFromFixture(Member::class, 'user');
508
509
        // The DataFormatter performs canView calls
510
        // these are `Member`s so we need to be ADMIN types
511
        $this->logInWithPermission('ADMIN');
512
513
        $this->assertEquals(
514
            '{"FirstName":"Editor","Email":"[email protected]"}',
515
            $formatter->convertDataObject($editor, ["FirstName", "Email"]),
516
            "Correct JSON formatting with field subset"
517
        );
518
519
        $set = Member::get()
520
            ->filter('ID', [$editor->ID, $user->ID])
521
            ->sort('"Email" ASC'); // for sorting for postgres
522
        $this->assertEquals(
523
            '{"totalSize":null,"items":[{"FirstName":"Editor","Email":"[email protected]"},' .
524
                '{"FirstName":"User","Email":"[email protected]"}]}',
525
            $formatter->convertDataObjectSet($set, ["FirstName", "Email"]),
526
            "Correct JSON formatting on a dataobjectset with field filter"
527
        );
528
    }
529
530
    public function testApiAccessWithPOST()
531
    {
532
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestAuthorRating::class);
533
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/";
534
        $data = [
535
            'Rating' => '42',
536
            'WriteProtectedField' => 'haxx0red'
537
        ];
538
        $response = Director::test($url, $data, null, 'POST');
539
        // Assumption: XML is default output
540
        $responseArr = Convert::xml2array($response->getBody());
541
        $this->assertEquals(42, $responseArr['Rating']);
542
        $this->assertNotEquals('haxx0red', $responseArr['WriteProtectedField']);
543
    }
544
545
    public function testCanViewRespectedInList()
546
    {
547
        // Default content type
548
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestSecretThing::class);
549
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/";
550
        $response = Director::test($url, null, null, 'GET');
551
        $this->assertEquals(200, $response->getStatusCode());
552
        $this->assertNotContains('Unspeakable', $response->getBody());
553
554
        // JSON content type
555
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname.json";
556
        $response = Director::test($url, null, null, 'GET');
557
        $this->assertEquals(200, $response->getStatusCode());
558
        $this->assertNotContains('Unspeakable', $response->getBody());
559
        $responseArray = Convert::json2array($response->getBody());
560
        $this->assertSame(0, $responseArray['totalSize']);
561
562
        // With authentication
563
        $_SERVER['PHP_AUTH_USER'] = '[email protected]';
564
        $_SERVER['PHP_AUTH_PW'] = 'editor';
565
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestSecretThing::class);
566
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/";
567
        $response = Director::test($url, null, null, 'GET');
568
        $this->assertEquals(200, $response->getStatusCode());
569
        $this->assertContains('Unspeakable', $response->getBody());
570
        // Assumption: default formatter is XML
571
        $responseArray = Convert::xml2array($response->getBody());
572
        $this->assertEquals(1, $responseArray['@attributes']['totalSize']);
573
        unset($_SERVER['PHP_AUTH_USER']);
574
        unset($_SERVER['PHP_AUTH_PW']);
575
    }
576
577
    public function testValidationErrorWithPOST()
578
    {
579
        $urlSafeClassname = $this->urlSafeClassname(RestfulServerTestValidationFailure::class);
580
        $url = "{$this->baseURI}/api/v1/$urlSafeClassname/";
581
        $data = [
582
            'Content' => 'Test',
583
        ];
584
        $response = Director::test($url, $data, null, 'POST');
585
        // Assumption: XML is default output
586
        $responseArr = Convert::xml2array($response->getBody());
587
        $this->assertEquals('SilverStripe\\ORM\\ValidationException', $responseArr['type']);
588
    }
589
}
590