123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521 |
- <?php
- namespace Tests\Api\v1\Controllers;
- use App\Api\v1\Controllers\GroupController;
- use App\Api\v1\Resources\GroupResource;
- use App\Listeners\DissociateTwofaccountFromGroup;
- use App\Listeners\ResetUsersPreference;
- use App\Models\Group;
- use App\Models\TwoFAccount;
- use App\Models\User;
- use App\Policies\GroupPolicy;
- use PHPUnit\Framework\Attributes\CoversClass;
- use PHPUnit\Framework\Attributes\Test;
- use Tests\FeatureTestCase;
- #[CoversClass(GroupController::class)]
- #[CoversClass(GroupResource::class)]
- #[CoversClass(ResetUsersPreference::class)]
- #[CoversClass(GroupPolicy::class)]
- #[CoversClass(Group::class)]
- #[CoversClass(DissociateTwofaccountFromGroup::class)]
- class GroupControllerTest extends FeatureTestCase
- {
- /**
- * @var \App\Models\User|\Illuminate\Contracts\Auth\Authenticatable
- */
- protected $user;
- protected $anotherUser;
- /**
- * @var App\Models\Group
- */
- protected $userGroupA;
- protected $userGroupB;
- protected $anotherUserGroupA;
- protected $anotherUserGroupB;
- /**
- * @var App\Models\TwoFAccount
- */
- protected $twofaccountA;
- protected $twofaccountB;
- protected $twofaccountC;
- protected $twofaccountD;
- private const NEW_GROUP_NAME = 'MyNewGroup';
- protected function setUp() : void
- {
- parent::setUp();
- $this->user = User::factory()->create();
- $this->userGroupA = Group::factory()->for($this->user)->create();
- $this->userGroupB = Group::factory()->for($this->user)->create();
- $this->twofaccountA = TwoFAccount::factory()->for($this->user)->create([
- 'group_id' => $this->userGroupA->id,
- ]);
- $this->twofaccountB = TwoFAccount::factory()->for($this->user)->create([
- 'group_id' => $this->userGroupA->id,
- ]);
- $this->anotherUser = User::factory()->create();
- $this->anotherUserGroupA = Group::factory()->for($this->anotherUser)->create();
- $this->anotherUserGroupB = Group::factory()->for($this->anotherUser)->create();
- $this->twofaccountC = TwoFAccount::factory()->for($this->anotherUser)->create([
- 'group_id' => $this->anotherUserGroupA->id,
- ]);
- $this->twofaccountD = TwoFAccount::factory()->for($this->anotherUser)->create([
- 'group_id' => $this->anotherUserGroupB->id,
- ]);
- }
- #[Test]
- public function test_index_returns_user_groups_only_with_pseudo_group()
- {
- $this->actingAs($this->user, 'api-guard')
- ->json('GET', '/api/v1/groups')
- ->assertOk()
- ->assertExactJson([
- '0' => [
- 'id' => 0,
- 'name' => 'All',
- 'twofaccounts_count' => 2,
- ],
- '1' => [
- 'id' => $this->userGroupA->id,
- 'name' => $this->userGroupA->name,
- 'twofaccounts_count' => 2,
- ],
- '2' => [
- 'id' => $this->userGroupB->id,
- 'name' => $this->userGroupB->name,
- 'twofaccounts_count' => 0,
- ],
- ]);
- }
- #[Test]
- public function test_orphan_groups_are_reassign_to_the_only_user()
- {
- config(['auth.defaults.guard' => 'reverse-proxy-guard']);
- $this->anotherUser->delete();
- $this->userGroupA->user_id = null;
- $this->userGroupA->save();
- $this->assertCount(1, User::all());
- $this->assertNull($this->userGroupA->user_id);
- $this->actingAs($this->user, 'reverse-proxy-guard')
- ->json('GET', '/api/v1/groups')
- ->assertOk();
- $this->userGroupA->refresh();
- $this->assertNotNull($this->userGroupA->user_id);
- }
- #[Test]
- public function test_store_returns_created_group_resource()
- {
- $this->actingAs($this->user, 'api-guard')
- ->json('POST', '/api/v1/groups', [
- 'name' => self::NEW_GROUP_NAME,
- ])
- ->assertCreated()
- ->assertJsonFragment([
- 'name' => self::NEW_GROUP_NAME,
- 'twofaccounts_count' => 0,
- ]);
- $this->assertDatabaseHas('groups', [
- 'name' => self::NEW_GROUP_NAME,
- 'user_id' => $this->user->id,
- ]);
- }
- #[Test]
- public function test_store_with_existing_group_name_returns_validation_error()
- {
- $this->actingAs($this->user, 'api-guard')
- ->json('POST', '/api/v1/groups', [
- 'name' => $this->userGroupA->name,
- ])
- ->assertStatus(422);
- }
- #[Test]
- public function test_store_with_all_group_name_returns_validation_error()
- {
- $this->actingAs($this->user, 'api-guard')
- ->json('POST', '/api/v1/groups', [
- 'name' => __('commons.all'),
- ])
- ->assertStatus(422);
- }
- #[Test]
- public function test_store_invalid_data_returns_validation_error()
- {
- $this->actingAs($this->user, 'api-guard')
- ->json('POST', '/api/v1/groups', [
- 'name' => null,
- ])
- ->assertStatus(422);
- }
- #[Test]
- public function test_show_returns_group_resource()
- {
- $group = Group::factory()->for($this->user)->create([
- 'name' => 'My group',
- ]);
- $response = $this->actingAs($this->user, 'api-guard')
- ->json('GET', '/api/v1/groups/' . $group->id)
- ->assertOk()
- ->assertJsonFragment([
- 'name' => 'My group',
- 'twofaccounts_count' => 0,
- ]);
- }
- #[Test]
- public function test_show_missing_group_returns_not_found()
- {
- $response = $this->actingAs($this->user, 'api-guard')
- ->json('GET', '/api/v1/groups/1000')
- ->assertNotFound()
- ->assertJsonStructure([
- 'message',
- ]);
- }
- #[Test]
- public function test_show_group_of_another_user_is_forbidden()
- {
- $response = $this->actingAs($this->anotherUser, 'api-guard')
- ->json('GET', '/api/v1/groups/' . $this->userGroupA->id)
- ->assertForbidden()
- ->assertJsonStructure([
- 'message',
- ]);
- }
- #[Test]
- public function test_show_missing_group_with_id_0_returns_the_virtual_all_group_resource()
- {
- $userTwofaccounts = $this->user->twofaccounts;
- $response = $this->actingAs($this->user, 'api-guard')
- ->json('GET', '/api/v1/groups/0')
- ->assertOk()
- ->assertJsonFragment([
- 'name' => __('commons.all'),
- 'twofaccounts_count' => $userTwofaccounts->count(),
- ]);
- }
- #[Test]
- public function test_update_returns_updated_group_resource()
- {
- $group = Group::factory()->for($this->user)->create();
- $response = $this->actingAs($this->user, 'api-guard')
- ->json('PUT', '/api/v1/groups/' . $group->id, [
- 'name' => 'name updated',
- ])
- ->assertOk()
- ->assertJsonFragment([
- 'name' => 'name updated',
- 'twofaccounts_count' => 0,
- ]);
- }
- #[Test]
- public function test_update_missing_group_returns_not_found()
- {
- $response = $this->actingAs($this->user, 'api-guard')
- ->json('PUT', '/api/v1/groups/1000', [
- 'name' => 'testUpdate',
- ])
- ->assertNotFound()
- ->assertJsonStructure([
- 'message',
- ]);
- }
- #[Test]
- public function test_update_with_invalid_data_returns_validation_error()
- {
- $group = Group::factory()->for($this->user)->create();
- $response = $this->actingAs($this->user, 'api-guard')
- ->json('PUT', '/api/v1/groups/' . $group->id, [
- 'name' => null,
- ])
- ->assertStatus(422);
- }
- #[Test]
- public function test_update_group_of_another_user_is_forbidden()
- {
- $response = $this->actingAs($this->anotherUser, 'api-guard')
- ->json('PUT', '/api/v1/groups/' . $this->userGroupA->id, [
- 'name' => 'name updated',
- ])
- ->assertForbidden()
- ->assertJsonStructure([
- 'message',
- ]);
- }
- #[Test]
- public function test_assign_accounts_returns_updated_group_resource()
- {
- $group = Group::factory()->for($this->user)->create();
- $accounts = TwoFAccount::factory()->count(2)->for($this->user)->create();
- $response = $this->actingAs($this->user, 'api-guard')
- ->json('POST', '/api/v1/groups/' . $group->id . '/assign', [
- 'ids' => [$accounts[0]->id, $accounts[1]->id],
- ])
- ->assertOk()
- ->assertExactJson([
- 'id' => $group->id,
- 'name' => $group->name,
- 'twofaccounts_count' => 2,
- ]);
- }
- #[Test]
- public function test_assign_accounts_to_missing_group_returns_not_found()
- {
- $accounts = TwoFAccount::factory()->count(2)->for($this->user)->create();
- $response = $this->actingAs($this->user, 'api-guard')
- ->json('POST', '/api/v1/groups/1000/assign', [
- 'ids' => [$accounts[0]->id, $accounts[1]->id],
- ])
- ->assertNotFound()
- ->assertJsonStructure([
- 'message',
- ]);
- }
- #[Test]
- public function test_assign_invalid_accounts_returns_validation_error()
- {
- $group = Group::factory()->for($this->user)->create();
- $accounts = TwoFAccount::factory()->count(2)->for($this->user)->create();
- $response = $this->actingAs($this->user, 'api-guard')
- ->json('POST', '/api/v1/groups/' . $group->id . '/assign', [
- 'ids' => 1,
- ])
- ->assertStatus(422);
- }
- #[Test]
- public function test_assign_to_group_of_another_user_is_forbidden()
- {
- $response = $this->actingAs($this->anotherUser, 'api-guard')
- ->json('POST', '/api/v1/groups/' . $this->userGroupA->id . '/assign', [
- 'ids' => [$this->twofaccountC->id, $this->twofaccountD->id],
- ])
- ->assertForbidden()
- ->assertJsonStructure([
- 'message',
- ]);
- }
- #[Test]
- public function test_assign_accounts_of_another_user_is_forbidden()
- {
- $response = $this->actingAs($this->user, 'api-guard')
- ->json('POST', '/api/v1/groups/' . $this->userGroupA->id . '/assign', [
- 'ids' => [$this->twofaccountC->id, $this->twofaccountD->id],
- ])
- ->assertForbidden()
- ->assertJsonStructure([
- 'message',
- ]);
- }
- #[Test]
- public function test_accounts_returns_twofaccounts_collection()
- {
- $response = $this->actingAs($this->user, 'api-guard')
- ->json('GET', '/api/v1/groups/' . $this->userGroupA->id . '/twofaccounts')
- ->assertOk()
- ->assertJsonCount(2)
- ->assertJsonStructure([
- '*' => [
- 'group_id',
- 'service',
- 'account',
- 'icon',
- 'otp_type',
- 'digits',
- 'algorithm',
- 'period',
- 'counter',
- ],
- ])
- ->assertJsonFragment([
- 'account' => $this->twofaccountA->account,
- ])
- ->assertJsonFragment([
- 'account' => $this->twofaccountB->account,
- ]);
- }
- #[Test]
- public function test_accounts_returns_twofaccounts_collection_with_secret()
- {
- $response = $this->actingAs($this->user, 'api-guard')
- ->json('GET', '/api/v1/groups/' . $this->userGroupA->id . '/twofaccounts?withSecret=1')
- ->assertOk()
- ->assertJsonCount(2)
- ->assertJsonStructure([
- '*' => [
- 'group_id',
- 'service',
- 'account',
- 'icon',
- 'secret',
- 'otp_type',
- 'digits',
- 'algorithm',
- 'period',
- 'counter',
- ],
- ]);
- }
- #[Test]
- public function test_accounts_of_missing_group_returns_not_found()
- {
- $response = $this->actingAs($this->user, 'api-guard')
- ->json('GET', '/api/v1/groups/1000/twofaccounts')
- ->assertNotFound()
- ->assertJsonStructure([
- 'message',
- ]);
- }
- #[Test]
- public function test_accounts_of_another_user_group_is_forbidden()
- {
- $response = $this->actingAs($this->anotherUser, 'api-guard')
- ->json('GET', '/api/v1/groups/' . $this->userGroupA->id . '/twofaccounts')
- ->assertForbidden()
- ->assertJsonStructure([
- 'message',
- ]);
- }
- #[Test]
- public function test_accounts_of_the_all_group_returns_user_twofaccounts_collection()
- {
- $response = $this->actingAs($this->user, 'api-guard')
- ->json('GET', '/api/v1/groups/0/twofaccounts')
- ->assertOk()
- ->assertJsonCount(2);
- }
- /**
- * test Group deletion via API
- */
- #[Test]
- public function test_destroy_group_returns_success()
- {
- $group = Group::factory()->for($this->user)->create();
- $this->actingAs($this->user, 'api-guard')
- ->json('DELETE', '/api/v1/groups/' . $group->id)
- ->assertNoContent();
- }
- /**
- * test Group deletion via API
- */
- #[Test]
- public function test_destroy_missing_group_returns_not_found()
- {
- $this->actingAs($this->user, 'api-guard')
- ->json('DELETE', '/api/v1/groups/1000')
- ->assertNotFound()
- ->assertJsonStructure([
- 'message',
- ]);
- }
- #[Test]
- public function test_destroy_group_of_another_user_is_forbidden()
- {
- $response = $this->actingAs($this->anotherUser, 'api-guard')
- ->json('DELETE', '/api/v1/groups/' . $this->userGroupA->id)
- ->assertForbidden()
- ->assertJsonStructure([
- 'message',
- ]);
- }
- #[Test]
- public function test_destroy_the_all_group_is_forbidden()
- {
- $response = $this->actingAs($this->anotherUser, 'api-guard')
- ->json('DELETE', '/api/v1/groups/0')
- ->assertForbidden()
- ->assertJsonStructure([
- 'message',
- ]);
- }
- #[Test]
- public function test_destroy_group_resets_user_preferences()
- {
- // Set the default group to a specific one
- $this->user['preferences->defaultGroup'] = $this->userGroupA->id;
- // Set the active group
- $this->user['preferences->activeGroup'] = $this->userGroupA->id;
- $this->user->save();
- $this->assertEquals($this->userGroupA->id, $this->user->preferences['defaultGroup']);
- $this->assertEquals($this->userGroupA->id, $this->user->preferences['activeGroup']);
- $this->actingAs($this->user, 'api-guard')
- ->json('DELETE', '/api/v1/groups/' . $this->userGroupA->id);
- $this->user->refresh();
- $this->assertEquals(0, $this->user->preferences['defaultGroup']);
- $this->assertEquals(0, $this->user->preferences['activeGroup']);
- }
- #[Test]
- public function test_twofaccount_is_released_on_group_destroy()
- {
- $this->actingAs($this->user, 'api-guard')
- ->json('DELETE', '/api/v1/groups/' . $this->userGroupA->id)
- ->assertNoContent();
- $this->twofaccountA->refresh();
- $this->twofaccountB->refresh();
- $this->assertNull($this->twofaccountA->group_id);
- $this->assertNull($this->twofaccountB->group_id);
- }
- }
|