@ikonintegration/ikapi 4.0.1 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (236) hide show
  1. package/.eslintignore +3 -0
  2. package/.eslintrc.cjs +81 -0
  3. package/.github/workflows/npmpublish.yml +8 -19
  4. package/.github/workflows/prs.yml +12 -0
  5. package/README.md +89 -99
  6. package/dist/index.d.ts +16 -0
  7. package/dist/index.js +27 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/package-lock.json +11881 -0
  10. package/dist/package.json +81 -0
  11. package/dist/src/API/Request.d.ts +125 -0
  12. package/dist/src/API/Request.js +185 -0
  13. package/dist/src/API/Request.js.map +1 -0
  14. package/dist/src/API/Response.d.ts +188 -0
  15. package/dist/src/API/Response.js +270 -0
  16. package/dist/src/API/Response.js.map +1 -0
  17. package/dist/src/BaseEvent/DynamoTransaction.d.ts +70 -0
  18. package/dist/src/BaseEvent/DynamoTransaction.js +104 -0
  19. package/dist/src/BaseEvent/DynamoTransaction.js.map +1 -0
  20. package/dist/src/BaseEvent/EventProcessor.d.ts +58 -0
  21. package/dist/src/BaseEvent/EventProcessor.js +101 -0
  22. package/dist/src/BaseEvent/EventProcessor.js.map +1 -0
  23. package/dist/src/BaseEvent/Process.d.ts +50 -0
  24. package/dist/src/BaseEvent/Process.js +64 -0
  25. package/dist/src/BaseEvent/Process.js.map +1 -0
  26. package/dist/src/BaseEvent/StepTransaction.d.ts +23 -0
  27. package/dist/src/BaseEvent/StepTransaction.js +27 -0
  28. package/dist/src/BaseEvent/StepTransaction.js.map +1 -0
  29. package/dist/src/BaseEvent/Transaction.d.ts +149 -0
  30. package/dist/src/BaseEvent/Transaction.js +224 -0
  31. package/dist/src/BaseEvent/Transaction.js.map +1 -0
  32. package/dist/src/Cache/Redis.d.ts +29 -0
  33. package/dist/src/Cache/Redis.js +80 -0
  34. package/dist/src/Cache/Redis.js.map +1 -0
  35. package/dist/src/Cache/types.d.ts +31 -0
  36. package/dist/src/Cache/types.js +2 -0
  37. package/dist/src/Cache/types.js.map +1 -0
  38. package/dist/src/Config/Configuration.d.ts +123 -0
  39. package/dist/src/Config/Configuration.js +109 -0
  40. package/dist/src/Config/Configuration.js.map +1 -0
  41. package/dist/src/Config/EnvironmentVar.d.ts +74 -0
  42. package/dist/src/Config/EnvironmentVar.js +138 -0
  43. package/dist/src/Config/EnvironmentVar.js.map +1 -0
  44. package/dist/src/Crypto/Crypto.d.ts +45 -0
  45. package/dist/src/Crypto/Crypto.js +72 -0
  46. package/dist/src/Crypto/Crypto.js.map +1 -0
  47. package/dist/src/Database/Database.d.ts +21 -0
  48. package/dist/src/Database/Database.js +15 -0
  49. package/dist/src/Database/Database.js.map +1 -0
  50. package/dist/src/Database/DatabaseManager.d.ts +47 -0
  51. package/dist/src/Database/DatabaseManager.js +60 -0
  52. package/dist/src/Database/DatabaseManager.js.map +1 -0
  53. package/dist/src/Database/DatabaseTransaction.d.ts +101 -0
  54. package/dist/src/Database/DatabaseTransaction.js +126 -0
  55. package/dist/src/Database/DatabaseTransaction.js.map +1 -0
  56. package/dist/src/Database/index.d.ts +10 -0
  57. package/dist/src/Database/index.js +15 -0
  58. package/dist/src/Database/index.js.map +1 -0
  59. package/dist/src/Database/integrations/dynamo/DynamoDatabase.d.ts +35 -0
  60. package/dist/src/Database/integrations/dynamo/DynamoDatabase.js +59 -0
  61. package/dist/src/Database/integrations/dynamo/DynamoDatabase.js.map +1 -0
  62. package/dist/src/Database/integrations/kysely/KyselyDatabase.d.ts +66 -0
  63. package/dist/src/Database/integrations/kysely/KyselyDatabase.js +86 -0
  64. package/dist/src/Database/integrations/kysely/KyselyDatabase.js.map +1 -0
  65. package/dist/src/Database/integrations/kysely/KyselyTransaction.d.ts +70 -0
  66. package/dist/src/Database/integrations/kysely/KyselyTransaction.js +118 -0
  67. package/dist/src/Database/integrations/kysely/KyselyTransaction.js.map +1 -0
  68. package/dist/src/Database/integrations/pgsql/PostgresDatabase.d.ts +36 -0
  69. package/dist/src/Database/integrations/pgsql/PostgresDatabase.js +54 -0
  70. package/dist/src/Database/integrations/pgsql/PostgresDatabase.js.map +1 -0
  71. package/dist/src/Database/integrations/pgsql/PostgresTransaction.d.ts +63 -0
  72. package/dist/src/Database/integrations/pgsql/PostgresTransaction.js +61 -0
  73. package/dist/src/Database/integrations/pgsql/PostgresTransaction.js.map +1 -0
  74. package/dist/src/Database/types.d.ts +76 -0
  75. package/dist/src/Database/types.js +2 -0
  76. package/dist/src/Database/types.js.map +1 -0
  77. package/dist/src/Globals.d.ts +93 -0
  78. package/dist/src/Globals.js +99 -0
  79. package/dist/src/Globals.js.map +1 -0
  80. package/dist/src/Logger/Logger.d.ts +161 -0
  81. package/dist/src/Logger/Logger.js +299 -0
  82. package/dist/src/Logger/Logger.js.map +1 -0
  83. package/dist/src/Mailer/Mailer.d.ts +78 -0
  84. package/dist/src/Mailer/Mailer.js +182 -0
  85. package/dist/src/Mailer/Mailer.js.map +1 -0
  86. package/dist/src/Publisher/Publisher.d.ts +39 -0
  87. package/dist/src/Publisher/Publisher.js +77 -0
  88. package/dist/src/Publisher/Publisher.js.map +1 -0
  89. package/dist/src/Server/RouteResolver.d.ts +33 -0
  90. package/dist/src/Server/RouteResolver.js +100 -0
  91. package/dist/src/Server/RouteResolver.js.map +1 -0
  92. package/dist/src/Server/Router.d.ts +157 -0
  93. package/dist/src/Server/Router.js +32 -0
  94. package/dist/src/Server/Router.js.map +1 -0
  95. package/dist/src/Server/lib/ContainerServer.d.ts +42 -0
  96. package/dist/src/Server/lib/ContainerServer.js +66 -0
  97. package/dist/src/Server/lib/ContainerServer.js.map +1 -0
  98. package/dist/src/Server/lib/Server.d.ts +45 -0
  99. package/dist/src/Server/lib/Server.js +93 -0
  100. package/dist/src/Server/lib/Server.js.map +1 -0
  101. package/dist/src/Server/lib/container/GenericHandler.d.ts +9 -0
  102. package/dist/src/Server/lib/container/GenericHandler.js +82 -0
  103. package/dist/src/Server/lib/container/GenericHandler.js.map +1 -0
  104. package/dist/src/Server/lib/container/GenericHandlerEvent.d.ts +52 -0
  105. package/dist/src/Server/lib/container/GenericHandlerEvent.js +132 -0
  106. package/dist/src/Server/lib/container/GenericHandlerEvent.js.map +1 -0
  107. package/dist/src/Server/lib/container/HealthHandler.d.ts +9 -0
  108. package/dist/src/Server/lib/container/HealthHandler.js +19 -0
  109. package/dist/src/Server/lib/container/HealthHandler.js.map +1 -0
  110. package/dist/src/Server/lib/container/Proxy.d.ts +67 -0
  111. package/dist/src/Server/lib/container/Proxy.js +143 -0
  112. package/dist/src/Server/lib/container/Proxy.js.map +1 -0
  113. package/dist/src/Server/lib/container/Utils.d.ts +14 -0
  114. package/dist/src/Server/lib/container/Utils.js +37 -0
  115. package/dist/src/Server/lib/container/Utils.js.map +1 -0
  116. package/dist/src/Util/AsyncSingleton.d.ts +31 -0
  117. package/dist/src/Util/AsyncSingleton.js +83 -0
  118. package/dist/src/Util/AsyncSingleton.js.map +1 -0
  119. package/dist/src/Util/Utils.d.ts +61 -0
  120. package/dist/src/Util/Utils.js +147 -0
  121. package/dist/src/Util/Utils.js.map +1 -0
  122. package/dist/src/Validation/Validator.d.ts +17 -0
  123. package/dist/src/Validation/Validator.js +39 -0
  124. package/dist/src/Validation/Validator.js.map +1 -0
  125. package/dist/tsconfig.tsbuildinfo +1 -0
  126. package/index.ts +41 -0
  127. package/jest.config.ts +37 -0
  128. package/jest.smoke.config.ts +34 -0
  129. package/package.json +66 -22
  130. package/src/API/Request.ts +214 -0
  131. package/src/API/Response.ts +370 -0
  132. package/src/BaseEvent/DynamoTransaction.ts +175 -0
  133. package/src/BaseEvent/EventProcessor.ts +140 -0
  134. package/src/BaseEvent/Process.ts +78 -0
  135. package/src/BaseEvent/StepTransaction.ts +35 -0
  136. package/src/BaseEvent/Transaction.ts +323 -0
  137. package/src/Cache/Redis.ts +89 -0
  138. package/src/Cache/types.ts +33 -0
  139. package/src/Config/Configuration.ts +199 -0
  140. package/src/Config/EnvironmentVar.ts +142 -0
  141. package/src/Crypto/Crypto.ts +89 -0
  142. package/src/Database/Database.ts +22 -0
  143. package/src/Database/DatabaseManager.ts +67 -0
  144. package/src/Database/DatabaseTransaction.ts +170 -0
  145. package/src/Database/index.ts +27 -0
  146. package/src/Database/integrations/dynamo/DynamoDatabase.ts +58 -0
  147. package/src/Database/integrations/kysely/KyselyDatabase.ts +99 -0
  148. package/src/Database/integrations/kysely/KyselyTransaction.ts +172 -0
  149. package/src/Database/integrations/pgsql/PostgresDatabase.ts +56 -0
  150. package/src/Database/integrations/pgsql/PostgresTransaction.ts +87 -0
  151. package/src/Database/types.ts +85 -0
  152. package/src/Globals.ts +103 -0
  153. package/src/Logger/Logger.ts +363 -0
  154. package/src/Mailer/Mailer.ts +217 -0
  155. package/src/Publisher/Publisher.ts +96 -0
  156. package/src/Server/RouteResolver.ts +124 -0
  157. package/src/Server/Router.ts +200 -0
  158. package/src/Server/lib/ContainerServer.ts +65 -0
  159. package/src/Server/lib/Server.ts +109 -0
  160. package/src/Server/lib/container/GenericHandler.ts +76 -0
  161. package/src/Server/lib/container/GenericHandlerEvent.ts +154 -0
  162. package/src/Server/lib/container/HealthHandler.ts +11 -0
  163. package/src/Server/lib/container/Proxy.ts +172 -0
  164. package/src/Server/lib/container/Utils.ts +33 -0
  165. package/src/Util/AsyncSingleton.ts +86 -0
  166. package/src/Util/Utils.ts +131 -0
  167. package/src/Validation/Validator.ts +45 -0
  168. package/tests/API/Request.test.ts +273 -0
  169. package/tests/API/Response.test.ts +367 -0
  170. package/tests/BaseEvent/DynamoTransaction.test.ts +272 -0
  171. package/tests/BaseEvent/EventProcessor.test.ts +263 -0
  172. package/tests/BaseEvent/Process.test.ts +47 -0
  173. package/tests/BaseEvent/StepTransaction.test.ts +44 -0
  174. package/tests/BaseEvent/Transaction.test.ts +402 -0
  175. package/tests/Cache/Redis-client.test.ts +90 -0
  176. package/tests/Cache/Redis-cluster.test.ts +100 -0
  177. package/tests/Config/Config.test.ts +205 -0
  178. package/tests/Config/EnvironmentVar.test.ts +251 -0
  179. package/tests/Crypto/Crypto.test.ts +88 -0
  180. package/tests/Database/DatabaseManager.test.ts +79 -0
  181. package/tests/Database/integrations/dynamo/DynamoDatabase.test.ts +44 -0
  182. package/tests/Database/integrations/kysely/KyselyDatabase.test.ts +113 -0
  183. package/tests/Database/integrations/kysely/KyselyTransaction.test.ts +119 -0
  184. package/tests/Database/integrations/pg/PostgresDatabase.test.ts +76 -0
  185. package/tests/Database/integrations/pg/PostgresTransaction.test.ts +118 -0
  186. package/tests/Logger/Logger.test.ts +215 -0
  187. package/tests/Mailer/Mailer.test.ts +59 -0
  188. package/tests/Publisher/Publisher.test.ts +60 -0
  189. package/tests/Server/RouteResolver.test.ts +116 -0
  190. package/tests/Server/Router.test.ts +39 -0
  191. package/tests/Server/lib/ContainerServer.test.ts +531 -0
  192. package/tests/Server/lib/Server.test.ts +12 -0
  193. package/tests/Server/lib/container/GenericHandler.test.ts +131 -0
  194. package/tests/Server/lib/container/GenericHandlerEvent.test.ts +103 -0
  195. package/tests/Server/lib/container/HealthHandler.test.ts +30 -0
  196. package/tests/Server/lib/container/Proxy.test.ts +268 -0
  197. package/tests/Server/lib/container/Utils.test.ts +47 -0
  198. package/tests/Test.utils.ts +78 -0
  199. package/tests/Utils/Utils.test.ts +229 -0
  200. package/tests/Validation/Validator.test.ts +82 -0
  201. package/tsconfig.json +26 -0
  202. package/tsconfig.smoke.json +26 -0
  203. package/index.js +0 -88
  204. package/src/API/IKRequest.js +0 -52
  205. package/src/API/IKResponse.js +0 -119
  206. package/src/API/IKUtils.js +0 -51
  207. package/src/BaseEvent/IKProcess.js +0 -77
  208. package/src/BaseEvent/IKTransaction.js +0 -139
  209. package/src/Cache/Prototype/IKCache.js +0 -17
  210. package/src/Cache/Redis/IKRedis.js +0 -148
  211. package/src/Database/DDB/IKDB.js +0 -56
  212. package/src/Database/DDB/IKDBBaseExpression.js +0 -130
  213. package/src/Database/DDB/IKDBBaseQuery.js +0 -151
  214. package/src/Database/DDB/IKDBQueryBatchGet.js +0 -37
  215. package/src/Database/DDB/IKDBQueryBatchWrite.js +0 -64
  216. package/src/Database/DDB/IKDBQueryDelete.js +0 -34
  217. package/src/Database/DDB/IKDBQueryGet.js +0 -48
  218. package/src/Database/DDB/IKDBQueryPut.js +0 -87
  219. package/src/Database/DDB/IKDBQueryScan.js +0 -45
  220. package/src/Database/DDB/IKDBQueryTransactionalWrite.js +0 -69
  221. package/src/Database/DDB/IKDBQueryUpdate.js +0 -221
  222. package/src/Database/DDB/_IKDBQueryTransactionalRead.js +0 -46
  223. package/src/Database/PSQL/IKDB.js +0 -41
  224. package/src/Database/PSQL/IKDBBaseQuery.js +0 -26
  225. package/src/Database/Prototype/IKDB.js +0 -21
  226. package/src/Database/Prototype/IKDBBaseQuery.js +0 -14
  227. package/src/IKDynamoStream.js +0 -42
  228. package/src/IKEventProcessor.js +0 -42
  229. package/src/IKGlobals.js +0 -24
  230. package/src/IKRouter.js +0 -47
  231. package/src/IKStepTransaction.js +0 -14
  232. package/src/Logger/IKLogger.js +0 -136
  233. package/src/Mailer/IKMailer.js +0 -69
  234. package/src/Publisher/IKPublisher.js +0 -44
  235. package/src/Tracker/IKExecutionTracker.js +0 -79
  236. package/src/Validation/IKValidation.js +0 -76
@@ -0,0 +1,402 @@
1
+ import { jest } from '@jest/globals'
2
+ import { expect as c_expect } from 'chai'
3
+
4
+ import Response from '../../src/API/Response.js'
5
+ import Transaction from '../../src/BaseEvent/Transaction.js'
6
+ import type { DbConfig } from '../../src/Database/types.js'
7
+ import Globals from '../../src/Globals.js'
8
+ import { defaultHeaders, emptyEvent, observableContext } from '../Test.utils.js'
9
+
10
+ describe('Transaction success invocation path', () => {
11
+ test('Simple success', async () => {
12
+ const b = { name: '123' }
13
+ const context = observableContext()
14
+ const transaction = new Transaction<null, typeof b>(emptyEvent(), context)
15
+ const handlerResp = await transaction.execute(async () => {
16
+ return Response.SuccessResponse(b)
17
+ })
18
+ // check resp
19
+ c_expect(handlerResp).to.be.null
20
+ // ctx
21
+ expect(context.fail).not.toBeCalled()
22
+ expect(context.done).not.toBeCalled()
23
+ expect(context.succeed).toBeCalledWith({
24
+ statusCode: 200,
25
+ body: JSON.stringify(b),
26
+ headers: defaultHeaders,
27
+ })
28
+ })
29
+
30
+ test('Simple success - sync return', async () => {
31
+ const b = { name: '123' }
32
+ const context = observableContext()
33
+ const transaction = new Transaction<null, typeof b>(emptyEvent(), context, {
34
+ syncReturn: true,
35
+ })
36
+ const handlerResp = await transaction.execute(async () => {
37
+ return Response.SuccessResponse(b)
38
+ })
39
+ // check resp
40
+ c_expect(handlerResp).to.be.an.instanceof(Response)
41
+ c_expect(handlerResp?.getBody()).to.be.deep.equals(b)
42
+ c_expect(handlerResp?.getCode()).to.be.equals(200)
43
+ // ctx
44
+ expect(context.fail).not.toBeCalled()
45
+ expect(context.done).not.toBeCalled()
46
+ expect(context.succeed).not.toBeCalled()
47
+ })
48
+ })
49
+
50
+ describe('Transaction error invocation path without response', () => {
51
+ test('Not valid response returned success', async () => {
52
+ const b = {
53
+ err: Globals.ErrorResponseInvalidServerResponse,
54
+ rollback: true,
55
+ errCode: Globals.ErrorCode_APIError,
56
+ transactionID: '123',
57
+ }
58
+ const context = observableContext({ awsRequestId: '123' })
59
+ const transaction = new Transaction<null, typeof b>(emptyEvent(), context)
60
+ // @ts-expect-error
61
+ const handlerResp = await transaction.execute(async () => {
62
+ return null
63
+ })
64
+ // check resp
65
+ c_expect(handlerResp).to.be.null
66
+ // ctx
67
+ expect(context.fail).not.toBeCalled()
68
+ expect(context.done).not.toBeCalled()
69
+ expect(context.succeed).toBeCalledWith({
70
+ statusCode: 400,
71
+ body: JSON.stringify(b),
72
+ headers: defaultHeaders,
73
+ })
74
+ })
75
+
76
+ test('Not valid response returned success - sync return', async () => {
77
+ const b = {
78
+ err: Globals.ErrorResponseInvalidServerResponse,
79
+ rollback: true,
80
+ errCode: Globals.ErrorCode_APIError,
81
+ transactionID: '123',
82
+ }
83
+ const context = observableContext()
84
+ const transaction = new Transaction<null, typeof b>(
85
+ emptyEvent({
86
+ requestContext: { requestId: '123' },
87
+ }),
88
+ context,
89
+ {
90
+ syncReturn: true,
91
+ }
92
+ )
93
+ // @ts-expect-error
94
+ const handlerResp = await transaction.execute(async () => {
95
+ return null
96
+ })
97
+ // check resp
98
+ c_expect(handlerResp).to.be.an.instanceof(Response)
99
+ c_expect(handlerResp?.getBody()).to.be.deep.equals(b)
100
+ c_expect(handlerResp?.getCode()).to.be.equals(400)
101
+ // ctx
102
+ expect(context.fail).not.toBeCalled()
103
+ expect(context.done).not.toBeCalled()
104
+ expect(context.succeed).not.toBeCalled()
105
+ })
106
+ })
107
+
108
+ describe('Transaction error invocation path with non-Response class response', () => {
109
+ test('Not a response-class response returned success', async () => {
110
+ const b = {
111
+ err: Globals.ErrorResponseInvalidServerResponse,
112
+ rollback: true,
113
+ errCode: Globals.ErrorCode_APIError,
114
+ transactionID: 'unknown',
115
+ }
116
+ const b2 = { name: 'abc' }
117
+ const context = observableContext()
118
+ const transaction = new Transaction<null, null, typeof b2>(emptyEvent(), context)
119
+ const handlerResp = await transaction.execute(async () => {
120
+ return b2
121
+ })
122
+ // check resp
123
+ c_expect(handlerResp).to.be.null
124
+ // ctx
125
+ expect(context.fail).not.toBeCalled()
126
+ expect(context.done).not.toBeCalled()
127
+ expect(context.succeed).toBeCalledWith({
128
+ statusCode: 400,
129
+ body: JSON.stringify(b),
130
+ headers: defaultHeaders,
131
+ })
132
+ })
133
+
134
+ test('Not a response-class response returned success - sync return', async () => {
135
+ const b2 = { name: 'abc' }
136
+ const context = observableContext()
137
+ const transaction = new Transaction<null, null, typeof b2>(emptyEvent(), context, {
138
+ syncReturn: true,
139
+ })
140
+ const handlerResp = await transaction.execute(async () => {
141
+ return b2
142
+ })
143
+ // check resp
144
+ c_expect(handlerResp).to.be.deep.equals(b2)
145
+ // ctx
146
+ expect(context.fail).not.toBeCalled()
147
+ expect(context.done).not.toBeCalled()
148
+ expect(context.succeed).not.toBeCalled()
149
+ })
150
+ })
151
+
152
+ describe('Transaction error invocation path with exception', () => {
153
+ test('Transaction exception', async () => {
154
+ const b = {
155
+ err: Globals.ErrorResponseUnhandledError,
156
+ rollback: true,
157
+ errCode: Globals.ErrorCode_APIError,
158
+ transactionID: 'unknown',
159
+ }
160
+ const context = observableContext()
161
+ const transaction = new Transaction<null, null, null>(emptyEvent(), context)
162
+ const handlerResp = await transaction.execute(async () => {
163
+ throw new Error('Failed!')
164
+ })
165
+ // check resp
166
+ c_expect(handlerResp).to.be.null
167
+ // ctx
168
+ expect(context.fail).not.toBeCalled()
169
+ expect(context.done).not.toBeCalled()
170
+ expect(context.succeed).toBeCalledWith({
171
+ statusCode: 400,
172
+ body: JSON.stringify(b),
173
+ headers: defaultHeaders,
174
+ })
175
+ })
176
+
177
+ test('Transaction exception - sync return', async () => {
178
+ const b = {
179
+ err: Globals.ErrorResponseUnhandledError,
180
+ rollback: true,
181
+ errCode: Globals.ErrorCode_APIError,
182
+ transactionID: 'unknown',
183
+ }
184
+ const context = observableContext()
185
+ const transaction = new Transaction<null, null, null>(emptyEvent(), context, {
186
+ syncReturn: true,
187
+ })
188
+ const handlerResp = await transaction.execute(async () => {
189
+ throw new Error('Failed!')
190
+ })
191
+ // check resp
192
+ c_expect(handlerResp?.getBody()).to.be.deep.equals(b)
193
+ c_expect(handlerResp?.getCode()).to.be.equals(400)
194
+ // ctx
195
+ expect(context.fail).not.toBeCalled()
196
+ expect(context.done).not.toBeCalled()
197
+ expect(context.succeed).not.toBeCalled()
198
+ })
199
+
200
+ test('Transaction exception - sync return', async () => {
201
+ const context = observableContext()
202
+ const transaction = new Transaction<null, null, null>(emptyEvent(), context, {
203
+ throwOnErrors: true,
204
+ })
205
+ const error = new Error('Failed!')
206
+ let handlerResp: any = null,
207
+ err: any = null
208
+ try {
209
+ handlerResp = await transaction.execute(async () => {
210
+ throw error
211
+ })
212
+ } catch (e) {
213
+ err = e
214
+ }
215
+ // check resp
216
+ c_expect(handlerResp).to.be.null
217
+ c_expect(err).to.be.deep.equals(error)
218
+ // ctx
219
+ expect(context.fail).not.toBeCalled()
220
+ expect(context.done).not.toBeCalled()
221
+ expect(context.succeed).not.toBeCalled()
222
+ })
223
+ })
224
+
225
+ describe('Transaction - db integration', () => {
226
+ const testResources = () => {
227
+ const mockTrans = {
228
+ query: jest.fn(),
229
+ closeSuccess: jest.fn(),
230
+ closeFailure: jest.fn(),
231
+ }
232
+ const mockCreate = jest.fn(
233
+ () => ({ transaction: () => new Promise(resolve => resolve(mockTrans)) }) as any
234
+ )
235
+
236
+ const transaction = new Transaction(emptyEvent(), observableContext())
237
+ transaction['databaseManager'] = {
238
+ create: mockCreate,
239
+ } as any
240
+
241
+ return {
242
+ transaction,
243
+ mockCreate,
244
+ mockTrans,
245
+ }
246
+ }
247
+
248
+ const config = { username: 'test' } as DbConfig<'pg'>
249
+
250
+ test('Transaction provides dbTransaction and calls closeSuccess', async () => {
251
+ const { mockCreate, mockTrans, transaction } = testResources()
252
+
253
+ await transaction.execute(async () => {
254
+ const pgTransaction = await transaction.getDbTransaction(config)
255
+
256
+ pgTransaction.query('name')
257
+
258
+ return Response.SuccessResponse(null)
259
+ })
260
+ expect(mockCreate).toBeCalledWith(config)
261
+ expect(mockTrans.query).toBeCalledWith('name')
262
+ expect(mockTrans.closeSuccess).toBeCalled()
263
+ })
264
+
265
+ test('Errored transaction calls closeFailure', async () => {
266
+ const { mockCreate, transaction, mockTrans } = testResources()
267
+
268
+ await transaction.execute(async () => {
269
+ await transaction.getDbTransaction(config)
270
+ throw new Error('Something went wrong!')
271
+ return Response.SuccessResponse(null)
272
+ })
273
+
274
+ expect(mockCreate).toBeCalledWith(config)
275
+ expect(mockTrans.closeFailure).toBeCalled()
276
+ })
277
+ })
278
+
279
+ describe('Transaction response types', () => {
280
+ test('Non-response return', async () => {
281
+ const b = { name: '123' }
282
+ const b2 = {
283
+ err: Globals.ErrorResponseInvalidServerResponse,
284
+ rollback: true,
285
+ errCode: Globals.ErrorCode_APIError,
286
+ transactionID: 'unknown',
287
+ }
288
+ const context = observableContext()
289
+ const transaction = new Transaction<null, typeof b>(emptyEvent(), context)
290
+ // @ts-expect-error
291
+ const handlerResp = await transaction.execute(async () => {
292
+ return { d: 1 }
293
+ })
294
+ // check resp
295
+ c_expect(handlerResp).to.be.null
296
+ // ctx
297
+ expect(context.fail).not.toBeCalled()
298
+ expect(context.done).not.toBeCalled()
299
+ expect(context.succeed).toBeCalledWith({
300
+ statusCode: 400,
301
+ body: JSON.stringify(b2),
302
+ headers: defaultHeaders,
303
+ })
304
+ })
305
+
306
+ test('Null return', async () => {
307
+ const b = { name: '123' }
308
+ const b2 = {
309
+ err: Globals.ErrorResponseInvalidServerResponse,
310
+ rollback: true,
311
+ errCode: Globals.ErrorCode_APIError,
312
+ transactionID: 'unknown',
313
+ }
314
+ const context = observableContext()
315
+ const transaction = new Transaction<null, typeof b>(emptyEvent(), context)
316
+ // @ts-expect-error
317
+ const handlerResp = await transaction.execute(async () => {
318
+ return null
319
+ })
320
+ // check resp
321
+ c_expect(handlerResp).to.be.null
322
+ // ctx
323
+ expect(context.fail).not.toBeCalled()
324
+ expect(context.done).not.toBeCalled()
325
+ expect(context.succeed).toBeCalledWith({
326
+ statusCode: 400,
327
+ body: JSON.stringify(b2),
328
+ headers: defaultHeaders,
329
+ })
330
+ })
331
+
332
+ test('Undefined return', async () => {
333
+ const b = { name: '123' }
334
+ const b2 = {
335
+ err: Globals.ErrorResponseInvalidServerResponse,
336
+ rollback: true,
337
+ errCode: Globals.ErrorCode_APIError,
338
+ transactionID: 'unknown',
339
+ }
340
+ const context = observableContext()
341
+ const transaction = new Transaction<null, typeof b>(emptyEvent(), context)
342
+ // @ts-expect-error
343
+ const handlerResp = await transaction.execute(async () => {
344
+ return
345
+ })
346
+ // check resp
347
+ c_expect(handlerResp).to.be.null
348
+ // ctx
349
+ expect(context.fail).not.toBeCalled()
350
+ expect(context.done).not.toBeCalled()
351
+ expect(context.succeed).toBeCalledWith({
352
+ statusCode: 400,
353
+ body: JSON.stringify(b2),
354
+ headers: defaultHeaders,
355
+ })
356
+ })
357
+
358
+ test('Null inner-response return', async () => {
359
+ const b = { name: '123' }
360
+ const b2 = { transactionID: 'unknown' }
361
+ const context = observableContext()
362
+ const transaction = new Transaction<null, typeof b>(emptyEvent(), context)
363
+ // @ts-expect-error
364
+ const handlerResp = await transaction.execute(async () => {
365
+ return Response.SuccessResponse(null)
366
+ })
367
+ // check resp
368
+ c_expect(handlerResp).to.be.null
369
+ // ctx
370
+ expect(context.fail).not.toBeCalled()
371
+ expect(context.done).not.toBeCalled()
372
+ expect(context.succeed).toBeCalledWith({
373
+ statusCode: 200,
374
+ body: JSON.stringify(b2),
375
+ headers: defaultHeaders,
376
+ })
377
+ })
378
+
379
+ test('Wrong keys inner-response return', async () => {
380
+ const b = { name: '123' }
381
+ const b2 = {
382
+ notName: '123',
383
+ transactionID: 'unknown',
384
+ }
385
+ const context = observableContext()
386
+ const transaction = new Transaction<null, typeof b>(emptyEvent(), context)
387
+ // @ts-expect-error
388
+ const handlerResp = await transaction.execute(async () => {
389
+ return Response.SuccessResponse({ notName: '123' })
390
+ })
391
+ // check resp
392
+ c_expect(handlerResp).to.be.null
393
+ // ctx
394
+ expect(context.fail).not.toBeCalled()
395
+ expect(context.done).not.toBeCalled()
396
+ expect(context.succeed).toBeCalledWith({
397
+ statusCode: 200,
398
+ body: JSON.stringify(b2),
399
+ headers: defaultHeaders,
400
+ })
401
+ })
402
+ })
@@ -0,0 +1,90 @@
1
+ import { jest } from '@jest/globals'
2
+
3
+ import Redis from '../../src/Cache/Redis.js'
4
+
5
+ let _connectionId = 1
6
+
7
+ async function simpleRedisTest(config: any, concurrent?: boolean) {
8
+ const RedisMock = jest.fn(() => {
9
+ let opened = false
10
+ const connectionId = _connectionId++
11
+ return {
12
+ connectionId,
13
+ isOpen: () => opened,
14
+ close: () => (opened = false),
15
+ connect: jest.fn(() => {
16
+ opened = true
17
+ return {
18
+ mget: jest.fn(() => {
19
+ return true
20
+ }),
21
+ }
22
+ }),
23
+ } as any
24
+ })
25
+ Redis['ClientFactory'] = RedisMock
26
+ // Double call is intentional
27
+ const [provider, provider2] = concurrent
28
+ ? await Promise.all([Redis.connection(config), Redis.connection(config)])
29
+ : [await Redis.connection(config), await Redis.connection(config)]
30
+
31
+ // client checks
32
+ expect(RedisMock).toHaveBeenNthCalledWith(1, {
33
+ username: config.username,
34
+ ...(config.password ? { password: config.password } : {}),
35
+ disableOfflineQueue: true,
36
+ socket: {
37
+ host: config.hostname,
38
+ tls: config.enableTLS,
39
+ connectTimeout: 10000,
40
+ },
41
+ })
42
+ // Does not have double connection
43
+ expect(provider['connectionId']).toEqual(provider2['connectionId'])
44
+ expect(provider.connect).toHaveBeenCalledTimes(1)
45
+ expect(provider2.connect).toHaveBeenCalledTimes(1)
46
+ }
47
+
48
+ describe('Redis (client)', () => {
49
+ beforeEach(async () => {
50
+ // hack to close singleton connection
51
+ if (Redis['singleton'].getValue()) Redis['singleton'].clear()
52
+ })
53
+ test('Simple redis - do not connect twice', async () => {
54
+ await simpleRedisTest({
55
+ hostname: 'redis://localhost',
56
+ username: 'gabe',
57
+ password: 'mypassword',
58
+ enableTLS: true,
59
+ type: 'redis',
60
+ })
61
+ })
62
+ test('Simple redis (no SSL) - do not connect twice', async () => {
63
+ await simpleRedisTest({
64
+ hostname: 'redis://localhost',
65
+ username: 'gabe',
66
+ password: 'mypassword',
67
+ enableTLS: false,
68
+ type: 'redis',
69
+ })
70
+ })
71
+ test('Simple redis (passwordless) - do not connect twice', async () => {
72
+ await simpleRedisTest({
73
+ hostname: 'redis://localhost',
74
+ username: 'gabe',
75
+ enableTLS: false,
76
+ type: 'redis',
77
+ })
78
+ })
79
+ test('Concurrent redis - do not connect twice', async () => {
80
+ await simpleRedisTest(
81
+ {
82
+ hostname: 'redis://localhost',
83
+ username: 'gabe',
84
+ enableTLS: false,
85
+ type: 'redis',
86
+ },
87
+ true
88
+ )
89
+ })
90
+ })
@@ -0,0 +1,100 @@
1
+ import { jest } from '@jest/globals'
2
+
3
+ import Redis from '../../src/Cache/Redis.js'
4
+
5
+ let _connectionId = 1
6
+
7
+ async function simpleRedisTest(config: any, concurrent?: boolean) {
8
+ const RedisMock = jest.fn(() => {
9
+ let opened = false
10
+ const connectionId = _connectionId++
11
+ return {
12
+ connectionId,
13
+ isOpen: () => opened,
14
+ close: () => (opened = false),
15
+ connect: jest.fn(() => {
16
+ opened = true
17
+ return {
18
+ mget: jest.fn(() => {
19
+ return true
20
+ }),
21
+ }
22
+ }),
23
+ } as any
24
+ })
25
+ Redis['ClusterFactory'] = RedisMock
26
+ // Double call is intentional
27
+ const [provider, provider2] = concurrent
28
+ ? await Promise.all([Redis.connection(config), Redis.connection(config)])
29
+ : [await Redis.connection(config), await Redis.connection(config)]
30
+
31
+ // client checks
32
+ expect(RedisMock).toHaveBeenNthCalledWith(1, {
33
+ defaults: {
34
+ username: config.username,
35
+ ...(config.password ? { password: config.password } : {}),
36
+ socket: {
37
+ tls: config.enableTLS,
38
+ connectTimeout: 10000,
39
+ },
40
+ },
41
+ rootNodes: [
42
+ {
43
+ url: `redis://${config.username}:${config.username}@${config.hostname}:6379`,
44
+ disableOfflineQueue: true,
45
+ },
46
+ ],
47
+ })
48
+ // Does not have double connection
49
+ expect(provider['connectionId']).toEqual(provider2['connectionId'])
50
+ expect(provider.connect).toHaveBeenCalledTimes(1)
51
+ expect(provider2.connect).toHaveBeenCalledTimes(1)
52
+ }
53
+
54
+ describe('Redis (cluster)', () => {
55
+ beforeEach(async () => {
56
+ // hack to close singleton connection
57
+ if (Redis['singleton'].getValue()) Redis['singleton'].clear()
58
+ })
59
+ test('Simple redis - do not connect twice', async () => {
60
+ await simpleRedisTest({
61
+ hostname: 'redis://localhost',
62
+ username: 'gabe',
63
+ password: 'mypassword',
64
+ enableTLS: true,
65
+ clusterMode: true,
66
+ type: 'redis',
67
+ })
68
+ })
69
+ test('Simple redis (no SSL) - do not connect twice', async () => {
70
+ await simpleRedisTest({
71
+ hostname: 'redis://localhost',
72
+ username: 'gabe',
73
+ password: 'mypassword',
74
+ enableTLS: false,
75
+ clusterMode: true,
76
+ type: 'redis',
77
+ })
78
+ })
79
+ test('Simple redis (passwordless) - do not connect twice', async () => {
80
+ await simpleRedisTest({
81
+ hostname: 'redis://localhost',
82
+ username: 'gabe',
83
+ enableTLS: false,
84
+ clusterMode: true,
85
+ type: 'redis',
86
+ })
87
+ })
88
+ test('Concurrent redis - do not connect twice', async () => {
89
+ await simpleRedisTest(
90
+ {
91
+ hostname: 'redis://localhost',
92
+ username: 'gabe',
93
+ enableTLS: false,
94
+ clusterMode: true,
95
+ type: 'redis',
96
+ },
97
+ true
98
+ )
99
+ })
100
+ })