roles.test.ts 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import { afterAll, beforeAll, expect, test } from 'vitest'
  2. import pgMeta from '../src/index'
  3. import { cleanupRoot, createTestDatabase } from './db/utils'
  4. beforeAll(async () => {
  5. // Any global setup if needed
  6. })
  7. afterAll(async () => {
  8. await cleanupRoot()
  9. })
  10. const withTestDatabase = (
  11. name: string,
  12. fn: (db: Awaited<ReturnType<typeof createTestDatabase>>) => Promise<void>
  13. ) => {
  14. test(name, async () => {
  15. const db = await createTestDatabase()
  16. try {
  17. await fn(db)
  18. } finally {
  19. await db.cleanup()
  20. }
  21. })
  22. }
  23. withTestDatabase('list roles', async ({ executeQuery }) => {
  24. const { sql, zod } = await pgMeta.roles.list()
  25. const res = zod.parse(await executeQuery(sql))
  26. let role = res.find(({ name }) => name === 'postgres')
  27. expect(role).toMatchInlineSnapshot(
  28. { activeConnections: expect.any(Number), id: expect.any(Number) },
  29. `
  30. {
  31. "activeConnections": Any<Number>,
  32. "canBypassRls": true,
  33. "canCreateDb": true,
  34. "canCreateRole": true,
  35. "canLogin": true,
  36. "config": {},
  37. "connectionLimit": 100,
  38. "id": Any<Number>,
  39. "inheritRole": true,
  40. "isReplicationRole": true,
  41. "isSuperuser": true,
  42. "name": "postgres",
  43. "validUntil": null,
  44. }
  45. `
  46. )
  47. // pg_monitor is a predefined role. `includeDefaultRoles` defaults to false,
  48. // so it shouldn't be included in the result.
  49. role = res.find(({ name }) => name === 'pg_monitor')
  50. expect(role).toMatchInlineSnapshot(`undefined`)
  51. })
  52. withTestDatabase('list roles w/ default roles', async ({ executeQuery }) => {
  53. const { sql, zod } = await pgMeta.roles.list({ includeDefaultRoles: true })
  54. const res = zod.parse(await executeQuery(sql))
  55. const role = res.find(({ name }) => name === 'pg_monitor')
  56. expect(role).toMatchInlineSnapshot(
  57. {
  58. activeConnections: expect.any(Number),
  59. id: expect.any(Number),
  60. },
  61. `
  62. {
  63. "activeConnections": Any<Number>,
  64. "canBypassRls": false,
  65. "canCreateDb": false,
  66. "canCreateRole": false,
  67. "canLogin": false,
  68. "config": {},
  69. "connectionLimit": 100,
  70. "id": Any<Number>,
  71. "inheritRole": true,
  72. "isReplicationRole": false,
  73. "isSuperuser": false,
  74. "name": "pg_monitor",
  75. "validUntil": null,
  76. }
  77. `
  78. )
  79. })
  80. withTestDatabase('retrieve, create, update, delete roles', async ({ executeQuery }) => {
  81. // Create role
  82. const { sql: createSql } = pgMeta.roles.create({
  83. name: 'r1',
  84. isSuperuser: true,
  85. canCreateDb: true,
  86. canCreateRole: true,
  87. inheritRole: false,
  88. canLogin: true,
  89. isReplicationRole: true,
  90. canBypassRls: true,
  91. connectionLimit: 100,
  92. validUntil: '2020-01-01T00:00:00.000Z',
  93. config: { search_path: 'extension, public' },
  94. })
  95. await executeQuery(createSql)
  96. // Retrieve the created role using list
  97. const { sql: listSql, zod: listZod } = await pgMeta.roles.list()
  98. const roles = listZod.parse(await executeQuery(listSql))
  99. const createdRole = roles.find((role) => role.name === 'r1')
  100. expect(createdRole).toMatchInlineSnapshot(
  101. { id: expect.any(Number), activeConnections: expect.any(Number) },
  102. `
  103. {
  104. "activeConnections": Any<Number>,
  105. "canBypassRls": true,
  106. "canCreateDb": true,
  107. "canCreateRole": true,
  108. "canLogin": true,
  109. "config": {
  110. "search_path": ""extension, public"",
  111. },
  112. "connectionLimit": 100,
  113. "id": Any<Number>,
  114. "inheritRole": false,
  115. "isReplicationRole": true,
  116. "isSuperuser": true,
  117. "name": "r1",
  118. "validUntil": "2020-01-01 00:00:00+00",
  119. }
  120. `
  121. )
  122. // Remove role
  123. const { sql: removeSql } = pgMeta.roles.remove({ id: createdRole!.id })
  124. await executeQuery(removeSql)
  125. // Create a new role for update test
  126. const { sql: createNewSql } = pgMeta.roles.create({
  127. name: 'r1',
  128. })
  129. await executeQuery(createNewSql)
  130. // Get the role ID for update
  131. const { sql: getIdSql, zod: getIdZod } = await pgMeta.roles.list()
  132. const roleForUpdate = getIdZod
  133. .parse(await executeQuery(getIdSql))
  134. .find((role) => role.name === 'r1')
  135. // Update role with ISO string date
  136. const { sql: updateSql } = pgMeta.roles.update(
  137. { id: roleForUpdate!.id },
  138. {
  139. name: 'rr',
  140. isSuperuser: true,
  141. canCreateDb: true,
  142. canCreateRole: true,
  143. inheritRole: false,
  144. canLogin: true,
  145. isReplicationRole: true,
  146. canBypassRls: true,
  147. connectionLimit: 100,
  148. validUntil: '2020-01-01T00:00:00.000Z',
  149. }
  150. )
  151. await executeQuery(updateSql)
  152. // Verify update using retrieve
  153. const { sql: retrieveUpdatedSql, zod: retrieveZod } = pgMeta.roles.retrieve({
  154. id: roleForUpdate!.id,
  155. })
  156. const updatedRole = retrieveZod.parse((await executeQuery(retrieveUpdatedSql))[0])
  157. expect(updatedRole).toMatchInlineSnapshot(
  158. { id: expect.any(Number), activeConnections: expect.any(Number) },
  159. `
  160. {
  161. "activeConnections": Any<Number>,
  162. "canBypassRls": true,
  163. "canCreateDb": true,
  164. "canCreateRole": true,
  165. "canLogin": true,
  166. "config": {},
  167. "connectionLimit": 100,
  168. "id": Any<Number>,
  169. "inheritRole": false,
  170. "isReplicationRole": true,
  171. "isSuperuser": true,
  172. "name": "rr",
  173. "validUntil": "2020-01-01 00:00:00+00",
  174. }
  175. `
  176. )
  177. // Create role with config
  178. const { sql: createConfigSql } = pgMeta.roles.create({
  179. name: 'config_role',
  180. config: { search_path: 'public', log_statement: 'all' },
  181. })
  182. await executeQuery(createConfigSql)
  183. // Verify config role using list
  184. const { sql: listConfigSql, zod: listConfigZod } = await pgMeta.roles.list()
  185. const configRole = listConfigZod
  186. .parse(await executeQuery(listConfigSql))
  187. .find((role) => role.name === 'config_role')
  188. expect(configRole).toMatchInlineSnapshot(
  189. { id: expect.any(Number), activeConnections: expect.any(Number) },
  190. `
  191. {
  192. "activeConnections": Any<Number>,
  193. "canBypassRls": false,
  194. "canCreateDb": false,
  195. "canCreateRole": false,
  196. "canLogin": false,
  197. "config": {
  198. "log_statement": "all",
  199. "search_path": "public",
  200. },
  201. "connectionLimit": 100,
  202. "id": Any<Number>,
  203. "inheritRole": true,
  204. "isReplicationRole": false,
  205. "isSuperuser": false,
  206. "name": "config_role",
  207. "validUntil": null,
  208. }
  209. `
  210. )
  211. // Remove role and verify it's gone
  212. const { sql: finalRemoveSql } = pgMeta.roles.remove({ id: configRole!.id })
  213. await executeQuery(finalRemoveSql)
  214. const { sql: finalListSql, zod: finalListZod } = await pgMeta.roles.list()
  215. const finalRoles = finalListZod.parse(await executeQuery(finalListSql))
  216. expect(finalRoles.find((role) => role.name === 'config_role')).toBeUndefined()
  217. })