assertEquals($response->getStatusCode(), 200); $_SERVER['PHP_AUTH_USER'] = 'user@test.com'; $_SERVER['PHP_AUTH_PW'] = 'user'; // even with logged in user a GET with $api_access disabled should fail $url = "/api/v1/RestfulServerTest_Page/1"; $response = Director::test($url, null, null, 'GET'); $this->assertEquals($response->getStatusCode(), 401); unset($_SERVER['PHP_AUTH_USER']); unset($_SERVER['PHP_AUTH_PW']); } public function testApiAccessBoolean() { $url = "/api/v1/RestfulServerTest_Comment/1"; $response = Director::test($url, null, null, 'GET'); $this->assertContains('', $response->getBody()); $this->assertContains('', $response->getBody()); $this->assertContains('', $response->getBody()); $this->assertContains('getBody()); $this->assertContains('getBody()); } public function testAuthenticatedGET() { // @todo create additional mock object with authenticated VIEW permissions $url = "/api/v1/RestfulServerTest_SecretThing/1"; $response = Director::test($url, null, null, 'GET'); $this->assertEquals($response->getStatusCode(), 401); $_SERVER['PHP_AUTH_USER'] = 'user@test.com'; $_SERVER['PHP_AUTH_PW'] = 'user'; $url = "/api/v1/RestfulServerTest_Comment/1"; $response = Director::test($url, null, null, 'GET'); $this->assertEquals($response->getStatusCode(), 200); unset($_SERVER['PHP_AUTH_USER']); unset($_SERVER['PHP_AUTH_PW']); } public function testAuthenticatedPUT() { $url = "/api/v1/RestfulServerTest_Comment/1"; $data = array('Comment' => 'created'); $response = Director::test($url, $data, null, 'PUT'); $this->assertEquals($response->getStatusCode(), 401); // Permission failure $_SERVER['PHP_AUTH_USER'] = 'editor@test.com'; $_SERVER['PHP_AUTH_PW'] = 'editor'; $response = Director::test($url, $data, null, 'PUT'); $this->assertEquals($response->getStatusCode(), 200); // Success unset($_SERVER['PHP_AUTH_USER']); unset($_SERVER['PHP_AUTH_PW']); } public function testGETRelationshipsXML() { $author1 = $this->objFromFixture('RestfulServerTest_Author', 'author1'); $rating1 = $this->objFromFixture('RestfulServerTest_AuthorRating', 'rating1'); $rating2 = $this->objFromFixture('RestfulServerTest_AuthorRating', 'rating2'); // @todo should be set up by fixtures, doesn't work for some reason... $author1->Ratings()->add($rating1); $author1->Ratings()->add($rating2); $url = "/api/v1/RestfulServerTest_Author/" . $author1->ID; $response = Director::test($url, null, null, 'GET'); $this->assertEquals($response->getStatusCode(), 200); $responseArr = Convert::xml2array($response->getBody()); $ratingsArr = $responseArr['Ratings']['RestfulServerTest_AuthorRating']; $this->assertEquals(count($ratingsArr), 2); $this->assertEquals($ratingsArr[0]['@attributes']['id'], $rating1->ID); $this->assertEquals($ratingsArr[1]['@attributes']['id'], $rating2->ID); } public function testGETManyManyRelationshipsXML() { // author4 has related authors author2 and author3 $author2 = $this->objFromFixture('RestfulServerTest_Author', 'author2'); $author3 = $this->objFromFixture('RestfulServerTest_Author', 'author3'); $author4 = $this->objFromFixture('RestfulServerTest_Author', 'author4'); $url = "/api/v1/RestfulServerTest_Author/" . $author4->ID . '/RelatedAuthors'; $response = Director::test($url, null, null, 'GET'); $this->assertEquals($response->getStatusCode(), 200); $arr = Convert::xml2array($response->getBody()); $authorsArr = $arr['RestfulServerTest_Author']; $this->assertEquals(count($authorsArr), 2); $this->assertEquals($authorsArr[0]['ID'], $author2->ID); $this->assertEquals($authorsArr[1]['ID'], $author3->ID); } public function testPUTWithFormEncoded() { $_SERVER['PHP_AUTH_USER'] = 'editor@test.com'; $_SERVER['PHP_AUTH_PW'] = 'editor'; $url = "/api/v1/RestfulServerTest_Comment/1"; $body = 'Name=Updated Comment&Comment=updated'; $headers = array( 'Content-Type' => 'application/x-www-form-urlencoded' ); $response = Director::test($url, null, null, 'PUT', $body, $headers); $this->assertEquals($response->getStatusCode(), 200); // Success // Assumption: XML is default output $responseArr = Convert::xml2array($response->getBody()); $this->assertEquals($responseArr['ID'], 1); $this->assertEquals($responseArr['Comment'], 'updated'); $this->assertEquals($responseArr['Name'], 'Updated Comment'); unset($_SERVER['PHP_AUTH_USER']); unset($_SERVER['PHP_AUTH_PW']); } public function testPOSTWithFormEncoded() { $_SERVER['PHP_AUTH_USER'] = 'editor@test.com'; $_SERVER['PHP_AUTH_PW'] = 'editor'; $url = "/api/v1/RestfulServerTest_Comment"; $body = 'Name=New Comment&Comment=created'; $headers = array( 'Content-Type' => 'application/x-www-form-urlencoded' ); $response = Director::test($url, null, null, 'POST', $body, $headers); $this->assertEquals($response->getStatusCode(), 201); // Created // Assumption: XML is default output $responseArr = Convert::xml2array($response->getBody()); $this->assertEquals($responseArr['ID'], 2); $this->assertEquals($responseArr['Comment'], 'created'); $this->assertEquals($responseArr['Name'], 'New Comment'); unset($_SERVER['PHP_AUTH_USER']); unset($_SERVER['PHP_AUTH_PW']); } public function testPUTwithJSON() { $_SERVER['PHP_AUTH_USER'] = 'editor@test.com'; $_SERVER['PHP_AUTH_PW'] = 'editor'; // by mimetype $url = "/api/v1/RestfulServerTest_Comment/1"; $body = '{"Comment":"updated"}'; $response = Director::test($url, null, null, 'PUT', $body, array('Content-Type'=>'application/json')); $this->assertEquals($response->getStatusCode(), 200); // Updated $obj = Convert::json2obj($response->getBody()); $this->assertEquals($obj->ID, 1); $this->assertEquals($obj->Comment, 'updated'); // by extension $url = "/api/v1/RestfulServerTest_Comment/1.json"; $body = '{"Comment":"updated"}'; $response = Director::test($url, null, null, 'PUT', $body); $this->assertEquals($response->getStatusCode(), 200); // Updated $obj = Convert::json2obj($response->getBody()); $this->assertEquals($obj->ID, 1); $this->assertEquals($obj->Comment, 'updated'); unset($_SERVER['PHP_AUTH_USER']); unset($_SERVER['PHP_AUTH_PW']); } public function testPUTwithXML() { $_SERVER['PHP_AUTH_USER'] = 'editor@test.com'; $_SERVER['PHP_AUTH_PW'] = 'editor'; // by mimetype $url = "/api/v1/RestfulServerTest_Comment/1"; $body = 'updated'; $response = Director::test($url, null, null, 'PUT', $body, array('Content-Type'=>'text/xml')); $this->assertEquals($response->getStatusCode(), 200); // Updated $obj = Convert::xml2array($response->getBody()); $this->assertEquals($obj['ID'], 1); $this->assertEquals($obj['Comment'], 'updated'); // by extension $url = "/api/v1/RestfulServerTest_Comment/1.xml"; $body = 'updated'; $response = Director::test($url, null, null, 'PUT', $body); $this->assertEquals($response->getStatusCode(), 200); // Updated $obj = Convert::xml2array($response->getBody()); $this->assertEquals($obj['ID'], 1); $this->assertEquals($obj['Comment'], 'updated'); unset($_SERVER['PHP_AUTH_USER']); unset($_SERVER['PHP_AUTH_PW']); } public function testHTTPAcceptAndContentType() { $url = "/api/v1/RestfulServerTest_Comment/1"; $headers = array('Accept' => 'application/json'); $response = Director::test($url, null, null, 'GET', null, $headers); $this->assertEquals($response->getStatusCode(), 200); // Success $obj = Convert::json2obj($response->getBody()); $this->assertEquals($obj->ID, 1); $this->assertEquals($response->getHeader('Content-Type'), 'application/json'); } public function testNotFound(){ $_SERVER['PHP_AUTH_USER'] = 'user@test.com'; $_SERVER['PHP_AUTH_PW'] = 'user'; $url = "/api/v1/RestfulServerTest_Comment/99"; $response = Director::test($url, null, null, 'GET'); $this->assertEquals($response->getStatusCode(), 404); unset($_SERVER['PHP_AUTH_USER']); unset($_SERVER['PHP_AUTH_PW']); } public function testMethodNotAllowed() { $url = "/api/v1/RestfulServerTest_Comment/1"; $response = Director::test($url, null, null, 'UNKNOWNHTTPMETHOD'); $this->assertEquals($response->getStatusCode(), 405); } public function testConflictOnExistingResourceWhenUsingPost() { $rating1 = $this->objFromFixture('RestfulServerTest_AuthorRating', 'rating1'); $url = "/api/v1/RestfulServerTest_AuthorRating/" . $rating1->ID; $response = Director::test($url, null, null, 'POST'); $this->assertEquals($response->getStatusCode(), 409); } public function testUnsupportedMediaType() { $_SERVER['PHP_AUTH_USER'] = 'user@test.com'; $_SERVER['PHP_AUTH_PW'] = 'user'; $url = "/api/v1/RestfulServerTest_Comment"; $data = "Comment||\/||updated"; // weird format $headers = array('Content-Type' => 'text/weirdformat'); $response = Director::test($url, null, null, 'POST', $data, $headers); $this->assertEquals($response->getStatusCode(), 415); unset($_SERVER['PHP_AUTH_USER']); unset($_SERVER['PHP_AUTH_PW']); } public function testXMLValueFormatting() { $rating1 = $this->objFromFixture('RestfulServerTest_AuthorRating','rating1'); $url = "/api/v1/RestfulServerTest_AuthorRating/" . $rating1->ID; $response = Director::test($url, null, null, 'GET'); $this->assertContains('' . $rating1->ID . '', $response->getBody()); $this->assertContains('' . $rating1->Rating . '', $response->getBody()); } public function testApiAccessFieldRestrictions() { $rating1 = $this->objFromFixture('RestfulServerTest_AuthorRating','rating1'); $url = "/api/v1/RestfulServerTest_AuthorRating/" . $rating1->ID; $response = Director::test($url, null, null, 'GET'); $this->assertContains('', $response->getBody()); $this->assertContains('', $response->getBody()); $this->assertContains('getBody()); $this->assertNotContains('', $response->getBody()); $this->assertNotContains('', $response->getBody()); $url = "/api/v1/RestfulServerTest_AuthorRating/" . $rating1->ID . '?add_fields=SecretField,SecretRelation'; $response = Director::test($url, null, null, 'GET'); $this->assertNotContains('', $response->getBody(), '"add_fields" URL parameter filters out disallowed fields from $api_access' ); $this->assertNotContains('', $response->getBody(), '"add_fields" URL parameter filters out disallowed relations from $api_access' ); $url = "/api/v1/RestfulServerTest_AuthorRating/" . $rating1->ID . '?fields=SecretField,SecretRelation'; $response = Director::test($url, null, null, 'GET'); $this->assertNotContains('', $response->getBody(), '"fields" URL parameter filters out disallowed fields from $api_access' ); $this->assertNotContains('', $response->getBody(), '"fields" URL parameter filters out disallowed relations from $api_access' ); } public function testApiAccessRelationRestrictions() { $author1 = $this->objFromFixture('RestfulServerTest_Author','author1'); $url = "/api/v1/RestfulServerTest_Author/" . $author1->ID; $response = Director::test($url, null, null, 'GET'); $this->assertNotContains('getBody()); $this->assertNotContains('getBody()); } public function testApiAccessWithPUT() { $rating1 = $this->objFromFixture('RestfulServerTest_AuthorRating','rating1'); $url = "/api/v1/RestfulServerTest_AuthorRating/" . $rating1->ID; $data = array( 'Rating' => '42', 'WriteProtectedField' => 'haxx0red' ); $response = Director::test($url, $data, null, 'PUT'); // Assumption: XML is default output $responseArr = Convert::xml2array($response->getBody()); $this->assertEquals($responseArr['Rating'], 42); $this->assertNotEquals($responseArr['WriteProtectedField'], 'haxx0red'); } public function testApiAccessWithPOST() { $url = "/api/v1/RestfulServerTest_AuthorRating"; $data = array( 'Rating' => '42', 'WriteProtectedField' => 'haxx0red' ); $response = Director::test($url, $data, null, 'POST'); // Assumption: XML is default output $responseArr = Convert::xml2array($response->getBody()); $this->assertEquals($responseArr['Rating'], 42); $this->assertNotEquals($responseArr['WriteProtectedField'], 'haxx0red'); } } /** * Everybody can view comments, logged in members in the "users" group can create comments, * but only "editors" can edit or delete them. * */ class RestfulServerTest_Comment extends DataObject implements PermissionProvider,TestOnly { static $api_access = true; static $db = array( "Name" => "Varchar(255)", "Comment" => "Text" ); static $has_one = array( 'Page' => 'RestfulServerTest_Page', 'Author' => 'RestfulServerTest_Author', ); public function providePermissions(){ return array( 'EDIT_Comment' => 'Edit Comment Objects', 'CREATE_Comment' => 'Create Comment Objects', 'DELETE_Comment' => 'Delete Comment Objects', ); } public function canView($member = null) { return true; } public function canEdit($member = null) { return Permission::checkMember($member, 'EDIT_Comment'); } public function canDelete($member = null) { return Permission::checkMember($member, 'DELETE_Comment'); } public function canCreate($member = null) { return Permission::checkMember($member, 'CREATE_Comment'); } } class RestfulServerTest_SecretThing extends DataObject implements TestOnly,PermissionProvider{ static $api_access = true; static $db = array( "Name" => "Varchar(255)", ); public function canView($member = null) { return Permission::checkMember($member, 'VIEW_SecretThing'); } public function providePermissions(){ return array( 'VIEW_SecretThing' => 'View Secret Things', ); } } class RestfulServerTest_Page extends DataObject implements TestOnly { static $api_access = false; static $db = array( 'Title' => 'Text', 'Content' => 'HTMLText', ); static $has_one = array( 'Author' => 'RestfulServerTest_Author', ); static $has_many = array( 'TestComments' => 'RestfulServerTest_Comment' ); static $belongs_many_many = array( 'RelatedAuthors' => 'RestfulServerTest_Author', ); } class RestfulServerTest_Author extends DataObject implements TestOnly { static $api_access = true; static $db = array( 'Name' => 'Text', ); static $many_many = array( 'RelatedPages' => 'RestfulServerTest_Page', 'RelatedAuthors' => 'RestfulServerTest_Author', ); static $has_many = array( 'PublishedPages' => 'RestfulServerTest_Page', 'Ratings' => 'RestfulServerTest_AuthorRating', ); public function canView($member = null) { return true; } } class RestfulServerTest_AuthorRating extends DataObject implements TestOnly { static $api_access = array( 'view' => array( 'Rating', 'WriteProtectedField', 'Author' ), 'edit' => array( 'Rating' ) ); static $db = array( 'Rating' => 'Int', 'SecretField' => 'Text', 'WriteProtectedField' => 'Text' ); static $has_one = array( 'Author' => 'RestfulServerTest_Author', 'SecretRelation' => 'RestfulServerTest_Author', ); public function canView($member = null) { return true; } public function canEdit($member = null) { return true; } public function canCreate($member = null) { return true; } } ?>