1
0

UserRepositoryTest.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Tests\Repositories;
  4. use App\Repositories\UserRepository;
  5. use App\Tests\TestCase;
  6. /**
  7. * Covers the upsert + admin-promotion contract used by the auth flows.
  8. * Caller-side gating (R01-N03's BOOTSTRAP_ADMIN_* env-bootstrap) lives in
  9. * `AuthController` + `BootstrapAdmin`; this suite only pins the repo's
  10. * mechanical promoteToAdmin / forceAdmin behaviour.
  11. */
  12. final class UserRepositoryTest extends TestCase
  13. {
  14. public function testFirstUserBecomesAdminWhenPromoted(): void
  15. {
  16. $pdo = $this->makeDb();
  17. $users = new UserRepository($pdo);
  18. $this->assertSame(0, $users->count());
  19. $r = $users->upsertFromOidc(
  20. oid: 'oid-alice',
  21. email: 'alice@example.com',
  22. name: 'Alice',
  23. promoteToAdmin: true, // caller's decision — see BootstrapAdmin::matches
  24. );
  25. $this->assertTrue($r['user']->isAdmin);
  26. $this->assertNull($r['before']);
  27. }
  28. public function testSecondUserDoesNotBecomeAdmin(): void
  29. {
  30. $pdo = $this->makeDb();
  31. $users = new UserRepository($pdo);
  32. $users->upsertFromOidc('oid-alice', 'alice@x', 'Alice', true);
  33. // Caller passes promoteToAdmin=false because an admin already exists.
  34. $r2 = $users->upsertFromOidc('oid-bob', 'bob@x', 'Bob', false);
  35. $this->assertFalse($r2['user']->isAdmin);
  36. }
  37. public function testReLoginDoesNotRegressAdminStatus(): void
  38. {
  39. $pdo = $this->makeDb();
  40. $users = new UserRepository($pdo);
  41. $users->upsertFromOidc('oid-alice', 'alice@x', 'Alice', true);
  42. // simulate a later login: count > 0 so promoteToAdmin=false
  43. $r = $users->upsertFromOidc('oid-alice', 'alice@x', 'Alice', false);
  44. $this->assertTrue($r['user']->isAdmin, 're-login must not demote admin');
  45. $this->assertNotNull($r['before']);
  46. }
  47. public function testForceAdminPromotesEvenOnUpdate(): void
  48. {
  49. // Local-admin login path sets forceAdmin=true so a demoted user gets
  50. // promoted back on next sign-in.
  51. $pdo = $this->makeDb();
  52. $users = new UserRepository($pdo);
  53. $r1 = $users->upsertFromOidc('local:admin@x', 'admin@x', 'Admin', true, true);
  54. $this->assertTrue($r1['user']->isAdmin);
  55. // Manually demote.
  56. $pdo->exec('UPDATE users SET is_admin = 0 WHERE id = ' . $r1['user']->id);
  57. $r2 = $users->upsertFromOidc('local:admin@x', 'admin@x', 'Admin', false, true);
  58. $this->assertTrue($r2['user']->isAdmin, 'forceAdmin must re-promote on update');
  59. }
  60. public function testUpsertUpdatesEmailAndName(): void
  61. {
  62. $pdo = $this->makeDb();
  63. $users = new UserRepository($pdo);
  64. $users->upsertFromOidc('oid-alice', 'old@x', 'Old Name', true);
  65. $r = $users->upsertFromOidc('oid-alice', 'new@x', 'New Name', false);
  66. $this->assertSame('new@x', $r['user']->email);
  67. $this->assertSame('New Name', $r['user']->displayName);
  68. }
  69. public function testCountReflectsInsertedUsers(): void
  70. {
  71. $pdo = $this->makeDb();
  72. $users = new UserRepository($pdo);
  73. $this->assertSame(0, $users->count());
  74. $users->upsertFromOidc('oid-1', 'a@x', 'A', true);
  75. $this->assertSame(1, $users->count());
  76. $users->upsertFromOidc('oid-2', 'b@x', 'B', false);
  77. $this->assertSame(2, $users->count());
  78. // Re-upsert existing user shouldn't add a row.
  79. $users->upsertFromOidc('oid-1', 'a@x', 'A', false);
  80. $this->assertSame(2, $users->count());
  81. }
  82. // ------------------------------------------------------------------
  83. // Phase 9: users management page helpers
  84. // ------------------------------------------------------------------
  85. public function testAllReturnsEveryUserOrderedByEmail(): void
  86. {
  87. $pdo = $this->makeDb();
  88. $users = new UserRepository($pdo);
  89. $users->upsertFromOidc('oid-c', 'carol@x', 'Carol', true);
  90. $users->upsertFromOidc('oid-a', 'alice@x', 'Alice', false);
  91. $users->upsertFromOidc('oid-b', 'BOB@x', 'Bob', false);
  92. $all = $users->all();
  93. $this->assertCount(3, $all);
  94. $this->assertSame(['alice@x', 'BOB@x', 'carol@x'], array_map(fn($u) => $u->email, $all));
  95. }
  96. public function testCountAdmins(): void
  97. {
  98. $pdo = $this->makeDb();
  99. $users = new UserRepository($pdo);
  100. $this->assertSame(0, $users->countAdmins());
  101. $users->upsertFromOidc('oid-a', 'a@x', 'A', true);
  102. $this->assertSame(1, $users->countAdmins());
  103. $users->upsertFromOidc('oid-b', 'b@x', 'B', false);
  104. $this->assertSame(1, $users->countAdmins());
  105. $users->upsertFromOidc('oid-c', 'c@x', 'C', false, true); // forceAdmin
  106. $this->assertSame(2, $users->countAdmins());
  107. }
  108. public function testSetAdminTogglesAndReportsDiff(): void
  109. {
  110. $pdo = $this->makeDb();
  111. $users = new UserRepository($pdo);
  112. $users->upsertFromOidc('oid-a', 'a@x', 'A', true);
  113. $users->upsertFromOidc('oid-b', 'b@x', 'B', false);
  114. $bob = $users->findByOid('oid-b');
  115. $r = $users->setAdmin($bob->id, true);
  116. $this->assertFalse($r['before']->isAdmin);
  117. $this->assertTrue ($r['after']->isAdmin);
  118. $this->assertSame(2, $users->countAdmins());
  119. $r = $users->setAdmin($bob->id, false);
  120. $this->assertTrue ($r['before']->isAdmin);
  121. $this->assertFalse($r['after']->isAdmin);
  122. $this->assertSame(1, $users->countAdmins());
  123. }
  124. }