GroupControllerTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. <?php
  2. namespace Tests\Api\v1\Controllers;
  3. use App\Models\Group;
  4. use App\Models\TwoFAccount;
  5. use App\Models\User;
  6. use Tests\FeatureTestCase;
  7. /**
  8. * @covers \App\Api\v1\Controllers\GroupController
  9. * @covers \App\Api\v1\Resources\GroupResource
  10. */
  11. class GroupControllerTest extends FeatureTestCase
  12. {
  13. /**
  14. * @var \App\Models\User|\Illuminate\Contracts\Auth\Authenticatable
  15. */
  16. protected $user, $anotherUser;
  17. /**
  18. * @var App\Models\Group
  19. */
  20. protected $userGroupA, $userGroupB, $anotherUserGroupA, $anotherUserGroupB;
  21. /**
  22. * @var App\Models\TwoFAccount
  23. */
  24. protected $twofaccountA, $twofaccountB, $twofaccountC, $twofaccountD;
  25. private const NEW_GROUP_NAME = 'MyNewGroup';
  26. /**
  27. * @test
  28. */
  29. public function setUp() : void
  30. {
  31. parent::setUp();
  32. $this->user = User::factory()->create();
  33. $this->userGroupA = Group::factory()->for($this->user)->create();
  34. $this->userGroupB = Group::factory()->for($this->user)->create();
  35. $this->twofaccountA = TwoFAccount::factory()->for($this->user)->create([
  36. 'group_id' => $this->userGroupA->id,
  37. ]);
  38. $this->twofaccountB = TwoFAccount::factory()->for($this->user)->create([
  39. 'group_id' => $this->userGroupA->id,
  40. ]);
  41. $this->anotherUser = User::factory()->create();
  42. $this->anotherUserGroupA = Group::factory()->for($this->anotherUser)->create();
  43. $this->anotherUserGroupB = Group::factory()->for($this->anotherUser)->create();
  44. $this->twofaccountC = TwoFAccount::factory()->for($this->anotherUser)->create([
  45. 'group_id' => $this->anotherUserGroupA->id,
  46. ]);
  47. $this->twofaccountD = TwoFAccount::factory()->for($this->anotherUser)->create([
  48. 'group_id' => $this->anotherUserGroupB->id,
  49. ]);
  50. }
  51. /**
  52. * @test
  53. */
  54. public function test_index_returns_user_groups_only_with_pseudo_group()
  55. {
  56. $this->actingAs($this->user, 'api-guard')
  57. ->json('GET', '/api/v1/groups')
  58. ->assertOk()
  59. ->assertExactJson([
  60. '0' => [
  61. 'id' => 0,
  62. 'name' => 'All',
  63. 'twofaccounts_count' => 2,
  64. ],
  65. '1' => [
  66. 'id' => $this->userGroupA->id,
  67. 'name' => $this->userGroupA->name,
  68. 'twofaccounts_count' => 2,
  69. ],
  70. '2' => [
  71. 'id' => $this->userGroupB->id,
  72. 'name' => $this->userGroupB->name,
  73. 'twofaccounts_count' => 0,
  74. ],
  75. ]);
  76. }
  77. /**
  78. * @test
  79. */
  80. public function test_store_returns_created_group_resource()
  81. {
  82. $this->actingAs($this->user, 'api-guard')
  83. ->json('POST', '/api/v1/groups', [
  84. 'name' => self::NEW_GROUP_NAME,
  85. ])
  86. ->assertCreated()
  87. ->assertJsonFragment([
  88. 'name' => self::NEW_GROUP_NAME,
  89. 'twofaccounts_count' => 0,
  90. ]);
  91. $this->assertDatabaseHas('groups', [
  92. 'name' => self::NEW_GROUP_NAME,
  93. 'user_id' => $this->user->id,
  94. ]);
  95. }
  96. /**
  97. * @test
  98. */
  99. public function test_store_invalid_data_returns_validation_error()
  100. {
  101. $this->actingAs($this->user, 'api-guard')
  102. ->json('POST', '/api/v1/groups', [
  103. 'name' => null,
  104. ])
  105. ->assertStatus(422);
  106. }
  107. /**
  108. * @test
  109. */
  110. public function test_show_returns_group_resource()
  111. {
  112. $group = Group::factory()->for($this->user)->create([
  113. 'name' => 'My group',
  114. ]);
  115. $response = $this->actingAs($this->user, 'api-guard')
  116. ->json('GET', '/api/v1/groups/' . $group->id)
  117. ->assertOk()
  118. ->assertJsonFragment([
  119. 'name' => 'My group',
  120. 'twofaccounts_count' => 0,
  121. ]);
  122. }
  123. /**
  124. * @test
  125. */
  126. public function test_show_missing_group_returns_not_found()
  127. {
  128. $response = $this->actingAs($this->user, 'api-guard')
  129. ->json('GET', '/api/v1/groups/1000')
  130. ->assertNotFound()
  131. ->assertJsonStructure([
  132. 'message',
  133. ]);
  134. }
  135. /**
  136. * @test
  137. */
  138. public function test_show_group_of_another_user_is_forbidden()
  139. {
  140. $response = $this->actingAs($this->anotherUser, 'api-guard')
  141. ->json('GET', '/api/v1/groups/' . $this->userGroupA->id)
  142. ->assertForbidden()
  143. ->assertJsonStructure([
  144. 'message',
  145. ]);
  146. }
  147. /**
  148. * @test
  149. */
  150. public function test_update_returns_updated_group_resource()
  151. {
  152. $group = Group::factory()->for($this->user)->create();
  153. $response = $this->actingAs($this->user, 'api-guard')
  154. ->json('PUT', '/api/v1/groups/' . $group->id, [
  155. 'name' => 'name updated',
  156. ])
  157. ->assertOk()
  158. ->assertJsonFragment([
  159. 'name' => 'name updated',
  160. 'twofaccounts_count' => 0,
  161. ]);
  162. }
  163. /**
  164. * @test
  165. */
  166. public function test_update_missing_group_returns_not_found()
  167. {
  168. $response = $this->actingAs($this->user, 'api-guard')
  169. ->json('PUT', '/api/v1/groups/1000', [
  170. 'name' => 'testUpdate',
  171. ])
  172. ->assertNotFound()
  173. ->assertJsonStructure([
  174. 'message',
  175. ]);
  176. }
  177. /**
  178. * @test
  179. */
  180. public function test_update_with_invalid_data_returns_validation_error()
  181. {
  182. $group = Group::factory()->for($this->user)->create();
  183. $response = $this->actingAs($this->user, 'api-guard')
  184. ->json('PUT', '/api/v1/groups/' . $group->id, [
  185. 'name' => null,
  186. ])
  187. ->assertStatus(422);
  188. }
  189. /**
  190. * @test
  191. */
  192. public function test_update_group_of_another_user_is_forbidden()
  193. {
  194. $response = $this->actingAs($this->anotherUser, 'api-guard')
  195. ->json('PUT', '/api/v1/groups/' . $this->userGroupA->id, [
  196. 'name' => 'name updated',
  197. ])
  198. ->assertForbidden()
  199. ->assertJsonStructure([
  200. 'message',
  201. ]);
  202. }
  203. /**
  204. * @test
  205. */
  206. public function test_assign_accounts_returns_updated_group_resource()
  207. {
  208. $group = Group::factory()->for($this->user)->create();
  209. $accounts = TwoFAccount::factory()->count(2)->for($this->user)->create();
  210. $response = $this->actingAs($this->user, 'api-guard')
  211. ->json('POST', '/api/v1/groups/' . $group->id . '/assign', [
  212. 'ids' => [$accounts[0]->id, $accounts[1]->id],
  213. ])
  214. ->assertOk()
  215. ->assertExactJson([
  216. 'id' => $group->id,
  217. 'name' => $group->name,
  218. 'twofaccounts_count' => 2,
  219. ]);
  220. }
  221. /**
  222. * @test
  223. */
  224. public function test_assign_accounts_to_missing_group_returns_not_found()
  225. {
  226. $accounts = TwoFAccount::factory()->count(2)->for($this->user)->create();
  227. $response = $this->actingAs($this->user, 'api-guard')
  228. ->json('POST', '/api/v1/groups/1000/assign', [
  229. 'ids' => [$accounts[0]->id, $accounts[1]->id],
  230. ])
  231. ->assertNotFound()
  232. ->assertJsonStructure([
  233. 'message',
  234. ]);
  235. }
  236. /**
  237. * @test
  238. */
  239. public function test_assign_invalid_accounts_returns_validation_error()
  240. {
  241. $group = Group::factory()->for($this->user)->create();
  242. $accounts = TwoFAccount::factory()->count(2)->for($this->user)->create();
  243. $response = $this->actingAs($this->user, 'api-guard')
  244. ->json('POST', '/api/v1/groups/' . $group->id . '/assign', [
  245. 'ids' => 1,
  246. ])
  247. ->assertStatus(422);
  248. }
  249. /**
  250. * @test
  251. */
  252. public function test_assign_to_group_of_another_user_is_forbidden()
  253. {
  254. $response = $this->actingAs($this->anotherUser, 'api-guard')
  255. ->json('POST', '/api/v1/groups/' . $this->userGroupA->id . '/assign', [
  256. 'ids' => [$this->twofaccountC->id, $this->twofaccountD->id],
  257. ])
  258. ->assertForbidden()
  259. ->assertJsonStructure([
  260. 'message',
  261. ]);
  262. }
  263. /**
  264. * @test
  265. */
  266. public function test_assign_accounts_of_another_user_is_forbidden()
  267. {
  268. $response = $this->actingAs($this->user, 'api-guard')
  269. ->json('POST', '/api/v1/groups/' . $this->userGroupA->id . '/assign', [
  270. 'ids' => [$this->twofaccountC->id, $this->twofaccountD->id],
  271. ])
  272. ->assertForbidden()
  273. ->assertJsonStructure([
  274. 'message',
  275. ]);
  276. }
  277. /**
  278. * @test
  279. */
  280. public function test_accounts_returns_twofaccounts_collection()
  281. {
  282. $response = $this->actingAs($this->user, 'api-guard')
  283. ->json('GET', '/api/v1/groups/' . $this->userGroupA->id . '/twofaccounts')
  284. ->assertOk()
  285. ->assertJsonCount(2)
  286. ->assertJsonStructure([
  287. '*' => [
  288. 'group_id',
  289. 'service',
  290. 'account',
  291. 'icon',
  292. 'otp_type',
  293. 'digits',
  294. 'algorithm',
  295. 'period',
  296. 'counter',
  297. ],
  298. ])
  299. ->assertJsonFragment([
  300. 'account' => $this->twofaccountA->account,
  301. ])
  302. ->assertJsonFragment([
  303. 'account' => $this->twofaccountB->account,
  304. ]);
  305. }
  306. /**
  307. * @test
  308. */
  309. public function test_accounts_returns_twofaccounts_collection_with_secret()
  310. {
  311. $response = $this->actingAs($this->user, 'api-guard')
  312. ->json('GET', '/api/v1/groups/' . $this->userGroupA->id . '/twofaccounts?withSecret=1')
  313. ->assertOk()
  314. ->assertJsonCount(2)
  315. ->assertJsonStructure([
  316. '*' => [
  317. 'group_id',
  318. 'service',
  319. 'account',
  320. 'icon',
  321. 'secret',
  322. 'otp_type',
  323. 'digits',
  324. 'algorithm',
  325. 'period',
  326. 'counter',
  327. ],
  328. ]);
  329. }
  330. /**
  331. * @test
  332. */
  333. public function test_accounts_of_missing_group_returns_not_found()
  334. {
  335. $response = $this->actingAs($this->user, 'api-guard')
  336. ->json('GET', '/api/v1/groups/1000/twofaccounts')
  337. ->assertNotFound()
  338. ->assertJsonStructure([
  339. 'message',
  340. ]);
  341. }
  342. /**
  343. * @test
  344. */
  345. public function test_accounts_of_another_user_group_is_forbidden()
  346. {
  347. $response = $this->actingAs($this->anotherUser, 'api-guard')
  348. ->json('GET', '/api/v1/groups/' . $this->userGroupA->id . '/twofaccounts')
  349. ->assertForbidden()
  350. ->assertJsonStructure([
  351. 'message',
  352. ]);
  353. }
  354. /**
  355. * test Group deletion via API
  356. *
  357. * @test
  358. */
  359. public function test_destroy_group_returns_success()
  360. {
  361. $group = Group::factory()->for($this->user)->create();
  362. $this->actingAs($this->user, 'api-guard')
  363. ->json('DELETE', '/api/v1/groups/' . $group->id)
  364. ->assertNoContent();
  365. }
  366. /**
  367. * test Group deletion via API
  368. *
  369. * @test
  370. */
  371. public function test_destroy_missing_group_returns_not_found()
  372. {
  373. $this->actingAs($this->user, 'api-guard')
  374. ->json('DELETE', '/api/v1/groups/1000')
  375. ->assertNotFound()
  376. ->assertJsonStructure([
  377. 'message',
  378. ]);
  379. }
  380. /**
  381. * @test
  382. */
  383. public function test_destroy_group_of_another_user_is_forbidden()
  384. {
  385. $response = $this->actingAs($this->anotherUser, 'api-guard')
  386. ->json('DELETE', '/api/v1/groups/'.$this->userGroupA->id)
  387. ->assertForbidden()
  388. ->assertJsonStructure([
  389. 'message',
  390. ]);
  391. }
  392. }