API: changed date-format, camelCase instead of snake_case, null values, update and create for customer and project (#718)

This commit is contained in:
Kevin Papst
2019-04-24 18:13:33 +02:00
committed by GitHub
parent 215d4fc8bf
commit 460391136f
61 changed files with 2304 additions and 505 deletions

View File

@@ -171,6 +171,47 @@ abstract class APIControllerBaseTest extends ControllerBaseTest
);
}
/**
* @param string $role
* @param string $url
* @param array $data
*/
protected function assertEntityNotFoundForPatch(string $role, string $url, array $data)
{
$client = $this->getClientForAuthenticatedUser($role);
$this->request($client, $url, 'PATCH', [], json_encode($data));
$response = $client->getResponse();
$this->assertFalse($response->isSuccessful());
$expected = [
'code' => 404,
'message' => 'Not found'
];
$this->assertEquals(404, $client->getResponse()->getStatusCode());
$this->assertEquals(
$expected,
json_decode($client->getResponse()->getContent(), true)
);
}
/**
* @param Client $client
* @param string $url
* @param string $message
*/
protected function assertApiAccessDenied(Client $client, string $url, string $message)
{
$this->request($client, $url);
$response = $client->getResponse();
$this->assertFalse($response->isSuccessful());
$this->assertEquals(Response::HTTP_FORBIDDEN, $response->getStatusCode());
$expected = ['code' => Response::HTTP_FORBIDDEN, 'message' => $message];
$this->assertEquals($expected, json_decode($response->getContent(), true));
}
/**
* @param Response $response
* @param string[] $failedFields

View File

@@ -13,7 +13,6 @@ use App\Entity\Activity;
use App\Entity\Customer;
use App\Entity\Project;
use App\Entity\User;
use App\Repository\Query\VisibilityQuery;
use Symfony\Bundle\FrameworkBundle\Client;
use Symfony\Component\HttpFoundation\Response;
@@ -77,7 +76,7 @@ class ActivityControllerTest extends APIControllerBaseTest
for ($i = 0; $i < count($result); $i++) {
$activity = $result[$i];
$hasProject = $expected[$i][0];
$this->assertStructure($activity, $hasProject);
$this->assertStructure($activity, false);
if ($hasProject) {
$this->assertEquals($expected[$i][0], $activity['project']);
}
@@ -88,13 +87,13 @@ class ActivityControllerTest extends APIControllerBaseTest
{
yield ['/api/activities', [], [[false], [false], [true, 2], [true, 1], [true, 2]]];
yield ['/api/activities', ['globals' => 'true'], [[false], [false]]];
yield ['/api/activities', ['globals' => 'true', 'visible' => VisibilityQuery::SHOW_BOTH], [[false], [false], [false]]];
yield ['/api/activities', ['globals' => 'true', 'visible' => VisibilityQuery::SHOW_HIDDEN], [[false]]];
yield ['/api/activities', ['globals' => 'true', 'visible' => VisibilityQuery::SHOW_VISIBLE], [[false], [false]]];
yield ['/api/activities', ['globals' => 'true', 'visible' => 3], [[false], [false], [false]]];
yield ['/api/activities', ['globals' => 'true', 'visible' => '2'], [[false]]];
yield ['/api/activities', ['globals' => 'true', 'visible' => 1], [[false], [false]]];
yield ['/api/activities', ['project' => '1'], [[false], [false], [true, 1]]];
yield ['/api/activities', ['project' => '2', 'visible' => VisibilityQuery::SHOW_VISIBLE], [[false], [false], [true, 2], [true, 2]]];
yield ['/api/activities', ['project' => '2', 'visible' => VisibilityQuery::SHOW_BOTH], [[false], [false], [false], [true, 2], [true, 2], [true, 2]]];
yield ['/api/activities', ['project' => '2', 'visible' => VisibilityQuery::SHOW_HIDDEN], [[false], [true, 2]]];
yield ['/api/activities', ['project' => '2', 'visible' => 1], [[false], [false], [true, 2], [true, 2]]];
yield ['/api/activities', ['project' => '2', 'visible' => '3'], [[false], [false], [false], [true, 2], [true, 2], [true, 2]]];
yield ['/api/activities', ['project' => '2', 'visible' => 2], [[false], [true, 2]]];
}
public function testGetCollectionWithQuery()
@@ -123,10 +122,12 @@ class ActivityControllerTest extends APIControllerBaseTest
$result = json_decode($client->getResponse()->getContent(), true);
$this->assertIsArray($result);
$this->assertStructure($result, true);
}
$expectedKeys = ['id', 'name', 'comment', 'visible'];
$actual = array_keys($result);
$this->assertEquals($expectedKeys, $actual);
public function testNotFound()
{
$this->assertEntityNotFound(User::ROLE_USER, '/api/activities/2');
}
public function testPostAction()
@@ -134,7 +135,6 @@ class ActivityControllerTest extends APIControllerBaseTest
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$data = [
'name' => 'foo',
'customer' => 1,
'project' => 1,
'visible' => true
];
@@ -152,7 +152,6 @@ class ActivityControllerTest extends APIControllerBaseTest
$client = $this->getClientForAuthenticatedUser(User::ROLE_USER);
$data = [
'name' => 'foo',
'customer' => 1,
'project' => 1,
'visible' => true
];
@@ -164,18 +163,12 @@ class ActivityControllerTest extends APIControllerBaseTest
$this->assertEquals('User cannot create activities', $json['message']);
}
public function testNotFound()
{
$this->assertEntityNotFound(User::ROLE_USER, '/api/activities/2');
}
public function testPatchAction()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$data = [
'name' => 'foo',
'comment' => '',
'customer' => 1,
'project' => 1,
'visible' => true
];
@@ -195,11 +188,10 @@ class ActivityControllerTest extends APIControllerBaseTest
$data = [
'name' => 'foo',
'comment' => '',
'customer' => 1,
'project' => 1,
'visible' => true
];
$this->request($client, '/api/activities/15', 'PATCH', [], json_encode($data));
$this->request($client, '/api/activities/1', 'PATCH', [], json_encode($data));
$response = $client->getResponse();
$this->assertFalse($response->isSuccessful());
$this->assertEquals(Response::HTTP_FORBIDDEN, $response->getStatusCode());
@@ -207,13 +199,17 @@ class ActivityControllerTest extends APIControllerBaseTest
$this->assertEquals('User cannot update activity', $json['message']);
}
public function testPatchActionWithUnknownActivity()
{
$this->assertEntityNotFoundForPatch(User::ROLE_USER, '/api/activities/255', []);
}
public function testInvalidPatchAction()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$data = [
'name' => 'foo',
'customer' => 255,
'project' => 1,
'project' => 255,
'visible' => true
];
$this->request($client, '/api/activities/1', 'PATCH', [], json_encode($data));
@@ -225,10 +221,10 @@ class ActivityControllerTest extends APIControllerBaseTest
protected function assertStructure(array $result, $full = true)
{
$expectedKeys = ['id', 'name', 'visible'];
$expectedKeys = ['id', 'name', 'visible', 'project', 'hourlyRate', 'fixedRate'];
if ($full) {
$expectedKeys = ['id', 'name', 'visible', 'project'];
$expectedKeys = array_merge($expectedKeys, ['comment']);
}
$actual = array_keys($result);

View File

@@ -36,7 +36,7 @@ class ConfigurationControllerTest extends APIControllerBaseTest
protected function assertStructure(array $result)
{
$expectedKeys = ['date', 'date_time', 'duration', 'form_date', 'form_date_time', 'is24hours', 'time'];
$expectedKeys = ['date', 'dateTime', 'duration', 'formDate', 'formDateTime', 'is24hours', 'time'];
$actual = array_keys($result);
sort($actual);
sort($expectedKeys);

View File

@@ -10,6 +10,7 @@
namespace App\Tests\API;
use App\Entity\User;
use Symfony\Component\HttpFoundation\Response;
/**
* @coversDefaultClass \App\API\CustomerController
@@ -62,15 +63,113 @@ class CustomerControllerTest extends APIControllerBaseTest
$this->assertEntityNotFound(User::ROLE_USER, '/api/customers/2');
}
public function testPostAction()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$data = [
'name' => 'foo',
'visible' => true,
'country' => 'DE',
'currency' => 'EUR',
'timezone' => 'Europe/Berlin',
];
$this->request($client, '/api/customers', 'POST', [], json_encode($data));
$this->assertTrue($client->getResponse()->isSuccessful());
$result = json_decode($client->getResponse()->getContent(), true);
$this->assertIsArray($result);
$this->assertStructure($result);
$this->assertNotEmpty($result['id']);
}
public function testPostActionWithInvalidUser()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_USER);
$data = [
'name' => 'foo',
'visible' => true,
'country' => 'DE',
'currency' => 'EUR',
'timezone' => 'Europe/Berlin',
];
$this->request($client, '/api/customers', 'POST', [], json_encode($data));
$response = $client->getResponse();
$this->assertFalse($response->isSuccessful());
$this->assertEquals(Response::HTTP_FORBIDDEN, $response->getStatusCode());
$json = json_decode($response->getContent(), true);
$this->assertEquals('User cannot create customers', $json['message']);
}
public function testPatchAction()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$data = [
'name' => 'foo',
'comment' => '',
'visible' => true,
'country' => 'DE',
'currency' => 'EUR',
'timezone' => 'Europe/Berlin',
];
$this->request($client, '/api/customers/1', 'PATCH', [], json_encode($data));
$this->assertTrue($client->getResponse()->isSuccessful());
$result = json_decode($client->getResponse()->getContent(), true);
$this->assertIsArray($result);
$this->assertStructure($result);
$this->assertNotEmpty($result['id']);
}
public function testPatchActionWithInvalidUser()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_USER);
$data = [
'name' => 'foo',
'comment' => '',
'visible' => true,
'country' => 'DE',
'currency' => 'EUR',
'timezone' => 'Europe/Berlin',
];
$this->request($client, '/api/customers/1', 'PATCH', [], json_encode($data));
$response = $client->getResponse();
$this->assertFalse($response->isSuccessful());
$this->assertEquals(Response::HTTP_FORBIDDEN, $response->getStatusCode());
$json = json_decode($response->getContent(), true);
$this->assertEquals('User cannot update customer', $json['message']);
}
public function testPatchActionWithUnknownActivity()
{
$this->assertEntityNotFoundForPatch(User::ROLE_USER, '/api/customers/255', []);
}
public function testInvalidPatchAction()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$data = [
'name' => 'foo',
'visible' => true,
'country' => 'DE',
'currency' => 'XXX',
'timezone' => 'Europe/Berlin',
];
$this->request($client, '/api/customers/1', 'PATCH', [], json_encode($data));
$response = $client->getResponse();
$this->assertEquals(400, $response->getStatusCode());
$this->assertApiCallValidationError($response, ['currency']);
}
protected function assertStructure(array $result, $full = true)
{
$expectedKeys = ['id', 'name', 'visible'];
$expectedKeys = ['id', 'name', 'visible', 'hourlyRate', 'fixedRate'];
if ($full) {
$expectedKeys = [
'id', 'name', 'number', 'comment', 'visible', 'company', 'contact', 'address', 'country', 'currency',
'phone', 'fax', 'mobile', 'email', 'timezone'
];
$expectedKeys = array_merge($expectedKeys, [
'homepage', 'number', 'comment', 'company', 'contact', 'address', 'country', 'currency', 'phone', 'fax', 'mobile', 'email', 'timezone'
]);
}
$actual = array_keys($result);

View File

@@ -14,6 +14,7 @@ use App\Entity\Project;
use App\Entity\User;
use App\Repository\Query\VisibilityQuery;
use Symfony\Bundle\FrameworkBundle\Client;
use Symfony\Component\HttpFoundation\Response;
/**
* @coversDefaultClass \App\API\ProjectController
@@ -120,16 +121,107 @@ class ProjectControllerTest extends APIControllerBaseTest
$this->assertEntityNotFound(User::ROLE_USER, '/api/projects/2');
}
public function testPostAction()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$data = [
'name' => 'foo',
'customer' => 1,
'visible' => true,
'budget' => 0,
];
$this->request($client, '/api/projects', 'POST', [], json_encode($data));
$this->assertTrue($client->getResponse()->isSuccessful());
$result = json_decode($client->getResponse()->getContent(), true);
$this->assertIsArray($result);
$this->assertStructure($result);
$this->assertNotEmpty($result['id']);
}
public function testPostActionWithInvalidUser()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_USER);
$data = [
'name' => 'foo',
'customer' => 1,
'visible' => true
];
$this->request($client, '/api/projects', 'POST', [], json_encode($data));
$response = $client->getResponse();
$this->assertFalse($response->isSuccessful());
$this->assertEquals(Response::HTTP_FORBIDDEN, $response->getStatusCode());
$json = json_decode($response->getContent(), true);
$this->assertEquals('User cannot create projects', $json['message']);
}
public function testPatchAction()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$data = [
'name' => 'foo',
'comment' => '',
'customer' => 1,
'visible' => true
];
$this->request($client, '/api/projects/1', 'PATCH', [], json_encode($data));
$this->assertTrue($client->getResponse()->isSuccessful());
$result = json_decode($client->getResponse()->getContent(), true);
$this->assertIsArray($result);
$this->assertStructure($result);
$this->assertNotEmpty($result['id']);
}
public function testPatchActionWithInvalidUser()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_USER);
$data = [
'name' => 'foo',
'comment' => '',
'customer' => 1,
'visible' => true
];
$this->request($client, '/api/projects/1', 'PATCH', [], json_encode($data));
$response = $client->getResponse();
$this->assertFalse($response->isSuccessful());
$this->assertEquals(Response::HTTP_FORBIDDEN, $response->getStatusCode());
$json = json_decode($response->getContent(), true);
$this->assertEquals('User cannot update project', $json['message']);
}
public function testPatchActionWithUnknownActivity()
{
$this->assertEntityNotFoundForPatch(User::ROLE_USER, '/api/projects/255', []);
}
public function testInvalidPatchAction()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$data = [
'name' => 'foo',
'customer' => 255,
'visible' => true
];
$this->request($client, '/api/projects/1', 'PATCH', [], json_encode($data));
$response = $client->getResponse();
$this->assertEquals(400, $response->getStatusCode());
$this->assertApiCallValidationError($response, ['customer']);
}
protected function assertStructure(array $result, $full = true)
{
$expectedKeys = [
'id', 'name', 'comment', 'visible', 'budget', 'order_number', 'customer'
'id', 'name', 'visible', 'customer', 'hourlyRate', 'fixedRate'
];
if (!$full) {
$expectedKeys = [
'id', 'name', 'visible', 'customer'
];
if ($full) {
$expectedKeys = array_merge(
$expectedKeys,
['comment', 'budget', 'orderNumber']
);
}
$actual = array_keys($result);

View File

@@ -13,10 +13,10 @@ use App\Constants;
use App\Entity\User;
/**
* @coversDefaultClass \App\API\HealthcheckController
* @coversDefaultClass \App\API\StatusController
* @group integration
*/
class HealthcheckControllerTest extends APIControllerBaseTest
class StatusControllerTest extends APIControllerBaseTest
{
public function testIsSecure()
{

View File

@@ -24,7 +24,12 @@ class TimesheetControllerTest extends APIControllerBaseTest
{
public function setUp()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_USER);
$this->importFixtureForUser(User::ROLE_USER);
}
protected function importFixtureForUser(string $role)
{
$client = $this->getClientForAuthenticatedUser($role);
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
$fixture = new TimesheetFixtures();
@@ -32,8 +37,8 @@ class TimesheetControllerTest extends APIControllerBaseTest
->setFixedRate(true)
->setHourlyRate(true)
->setAmount(10)
->setUser($this->getUserByRole($em, User::ROLE_USER))
->setStartDate(new \DateTime('-10 days'))
->setUser($this->getUserByRole($em, $role))
->setStartDate((new \DateTime('-10 days'))->setTime(0, 0, 1))
->setAllowEmptyDescriptions(false)
;
$this->importFixture($em, $fixture);
@@ -132,6 +137,7 @@ class TimesheetControllerTest extends APIControllerBaseTest
'size' => 5,
'order' => 'DESC',
'orderBy' => 'rate',
'active' => 0,
'begin' => $begin->format('Y-m-d H:i:s'),
'end' => $end->format('Y-m-d H:i:s'),
'exported' => 0,
@@ -224,6 +230,29 @@ class TimesheetControllerTest extends APIControllerBaseTest
$this->assertDefaultStructure($result);
}
public function testGetEntityAccessDenied()
{
$this->importFixtureForUser(User::ROLE_ADMIN);
$client = $this->getClientForAuthenticatedUser(User::ROLE_USER);
$this->assertApiAccessDenied($client, '/api/timesheets/15', 'You are not allowed to view this timesheet');
}
public function testGetEntityAccessAllowedForAdmin()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$this->assertAccessIsGranted($client, '/api/timesheets/1');
$result = json_decode($client->getResponse()->getContent(), true);
$this->assertIsArray($result);
$this->assertDefaultStructure($result);
}
public function testGetEntityNotFound()
{
$this->assertEntityNotFound(User::ROLE_USER, '/api/timesheets/20');
}
public function testPostAction()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
@@ -265,8 +294,8 @@ class TimesheetControllerTest extends APIControllerBaseTest
$data = [
'activity' => $activity->getId(),
'project' => $project->getId(),
'begin' => (new \DateTime('- 8 hours'))->format('Y-m-d H:m'),
'end' => (new \DateTime())->format('Y-m-d H:m'),
'begin' => (new \DateTime('- 8 hours'))->format('Y-m-d H:m:s'),
'end' => (new \DateTime())->format('Y-m-d H:m:s'),
'description' => 'foo',
'fixedRate' => 2016,
'hourlyRate' => 127
@@ -303,19 +332,14 @@ class TimesheetControllerTest extends APIControllerBaseTest
$this->assertApiCallValidationError($client->getResponse(), ['activity']);
}
public function testNotFound()
{
$this->assertEntityNotFound(User::ROLE_USER, '/api/timesheets/20');
}
public function testPatchAction()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD);
$data = [
'activity' => 1,
'project' => 1,
'begin' => (new \DateTime('- 7 hours'))->format('Y-m-d H:m'),
'end' => (new \DateTime())->format('Y-m-d H:m'),
'begin' => (new \DateTime('- 7 hours'))->format('Y-m-d\TH:m'),
'end' => (new \DateTime())->format('Y-m-d\TH:m'),
'description' => 'foo',
'exported' => true,
];
@@ -349,8 +373,8 @@ class TimesheetControllerTest extends APIControllerBaseTest
$data = [
'activity' => 1,
'project' => 1,
'begin' => (new \DateTime('- 7 hours'))->format('Y-m-d H:m'),
'end' => (new \DateTime())->format('Y-m-d H:m'),
'begin' => (new \DateTime('- 7 hours'))->format('Y-m-d\TH:m:s'),
'end' => (new \DateTime())->format('Y-m-d\TH:m:s'),
'description' => 'foo',
'exported' => true,
];
@@ -359,7 +383,12 @@ class TimesheetControllerTest extends APIControllerBaseTest
$this->assertFalse($response->isSuccessful());
$this->assertEquals(Response::HTTP_FORBIDDEN, $response->getStatusCode());
$json = json_decode($response->getContent(), true);
$this->assertEquals('User cannot update timesheet', $json['message']);
$this->assertEquals('You are not allowed to update this timesheet', $json['message']);
}
public function testPatchActionWithUnknownTimesheet()
{
$this->assertEntityNotFoundForPatch(User::ROLE_USER, '/api/timesheets/255', []);
}
public function testInvalidPatchAction()
@@ -387,7 +416,7 @@ class TimesheetControllerTest extends APIControllerBaseTest
if ($full) {
$expectedKeys = array_merge($expectedKeys, [
'exported', 'fixed_rate', 'hourly_rate'
'exported', 'fixedRate', 'hourlyRate'
]);
}

View File

@@ -29,10 +29,40 @@ class UserControllerTest extends APIControllerBaseTest
$this->assertAccessIsGranted($client, '/api/users');
$result = json_decode($client->getResponse()->getContent(), true);
$this->assertIsArray($result);
$this->assertNotEmpty($result);
$this->assertEquals(5, count($result));
foreach ($result as $user) {
$this->assertStructure($user, false);
}
}
public function testGetCollectionWithQuery()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN);
$this->assertAccessIsGranted($client, '/api/users', 'GET', ['visible' => 2, 'orderBy' => 'email', 'order' => 'DESC']);
$result = json_decode($client->getResponse()->getContent(), true);
$this->assertIsArray($result);
$this->assertNotEmpty($result);
$this->assertEquals(1, count($result));
foreach ($result as $user) {
$this->assertStructure($user, false);
}
}
public function testGetCollectionWithQuery2()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN);
$this->assertAccessIsGranted($client, '/api/users', 'GET', ['visible' => 3, 'orderBy' => 'email', 'order' => 'DESC']);
$result = json_decode($client->getResponse()->getContent(), true);
$this->assertIsArray($result);
$this->assertNotEmpty($result);
$this->assertEquals(6, count($result));
$this->assertStructure($result[0], false);
foreach ($result as $user) {
$this->assertStructure($user, false);
}
}
public function testGetEntity()
@@ -50,12 +80,31 @@ class UserControllerTest extends APIControllerBaseTest
$this->assertEntityNotFound(User::ROLE_SUPER_ADMIN, '/api/users/99');
}
public function testGetEntityAccessDenied()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_USER);
$this->assertApiAccessDenied($client, '/api/users/4', 'You are not allowed to view this profile');
}
public function testGetEntityAccessAllowedForOwnProfile()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_USER);
$this->assertAccessIsGranted($client, '/api/users/2');
$result = json_decode($client->getResponse()->getContent(), true);
$this->assertIsArray($result);
$this->assertStructure($result);
}
protected function assertStructure(array $result, $full = true)
{
$expectedKeys = ['id', 'username', 'enabled', 'alias'];
if ($full) {
$expectedKeys = ['id', 'username', 'enabled', 'roles', 'alias', 'title', 'avatar'];
$expectedKeys = array_merge(
$expectedKeys,
['title', 'avatar', 'roles', 'language', 'timezone']
);
}
$actual = array_keys($result);