@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.
- package/.eslintignore +3 -0
- package/.eslintrc.cjs +81 -0
- package/.github/workflows/npmpublish.yml +8 -19
- package/.github/workflows/prs.yml +12 -0
- package/README.md +89 -99
- package/dist/index.d.ts +16 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/package-lock.json +11881 -0
- package/dist/package.json +81 -0
- package/dist/src/API/Request.d.ts +125 -0
- package/dist/src/API/Request.js +185 -0
- package/dist/src/API/Request.js.map +1 -0
- package/dist/src/API/Response.d.ts +188 -0
- package/dist/src/API/Response.js +270 -0
- package/dist/src/API/Response.js.map +1 -0
- package/dist/src/BaseEvent/DynamoTransaction.d.ts +70 -0
- package/dist/src/BaseEvent/DynamoTransaction.js +104 -0
- package/dist/src/BaseEvent/DynamoTransaction.js.map +1 -0
- package/dist/src/BaseEvent/EventProcessor.d.ts +58 -0
- package/dist/src/BaseEvent/EventProcessor.js +101 -0
- package/dist/src/BaseEvent/EventProcessor.js.map +1 -0
- package/dist/src/BaseEvent/Process.d.ts +50 -0
- package/dist/src/BaseEvent/Process.js +64 -0
- package/dist/src/BaseEvent/Process.js.map +1 -0
- package/dist/src/BaseEvent/StepTransaction.d.ts +23 -0
- package/dist/src/BaseEvent/StepTransaction.js +27 -0
- package/dist/src/BaseEvent/StepTransaction.js.map +1 -0
- package/dist/src/BaseEvent/Transaction.d.ts +149 -0
- package/dist/src/BaseEvent/Transaction.js +224 -0
- package/dist/src/BaseEvent/Transaction.js.map +1 -0
- package/dist/src/Cache/Redis.d.ts +29 -0
- package/dist/src/Cache/Redis.js +80 -0
- package/dist/src/Cache/Redis.js.map +1 -0
- package/dist/src/Cache/types.d.ts +31 -0
- package/dist/src/Cache/types.js +2 -0
- package/dist/src/Cache/types.js.map +1 -0
- package/dist/src/Config/Configuration.d.ts +123 -0
- package/dist/src/Config/Configuration.js +109 -0
- package/dist/src/Config/Configuration.js.map +1 -0
- package/dist/src/Config/EnvironmentVar.d.ts +74 -0
- package/dist/src/Config/EnvironmentVar.js +138 -0
- package/dist/src/Config/EnvironmentVar.js.map +1 -0
- package/dist/src/Crypto/Crypto.d.ts +45 -0
- package/dist/src/Crypto/Crypto.js +72 -0
- package/dist/src/Crypto/Crypto.js.map +1 -0
- package/dist/src/Database/Database.d.ts +21 -0
- package/dist/src/Database/Database.js +15 -0
- package/dist/src/Database/Database.js.map +1 -0
- package/dist/src/Database/DatabaseManager.d.ts +47 -0
- package/dist/src/Database/DatabaseManager.js +60 -0
- package/dist/src/Database/DatabaseManager.js.map +1 -0
- package/dist/src/Database/DatabaseTransaction.d.ts +101 -0
- package/dist/src/Database/DatabaseTransaction.js +126 -0
- package/dist/src/Database/DatabaseTransaction.js.map +1 -0
- package/dist/src/Database/index.d.ts +10 -0
- package/dist/src/Database/index.js +15 -0
- package/dist/src/Database/index.js.map +1 -0
- package/dist/src/Database/integrations/dynamo/DynamoDatabase.d.ts +35 -0
- package/dist/src/Database/integrations/dynamo/DynamoDatabase.js +59 -0
- package/dist/src/Database/integrations/dynamo/DynamoDatabase.js.map +1 -0
- package/dist/src/Database/integrations/kysely/KyselyDatabase.d.ts +66 -0
- package/dist/src/Database/integrations/kysely/KyselyDatabase.js +86 -0
- package/dist/src/Database/integrations/kysely/KyselyDatabase.js.map +1 -0
- package/dist/src/Database/integrations/kysely/KyselyTransaction.d.ts +70 -0
- package/dist/src/Database/integrations/kysely/KyselyTransaction.js +118 -0
- package/dist/src/Database/integrations/kysely/KyselyTransaction.js.map +1 -0
- package/dist/src/Database/integrations/pgsql/PostgresDatabase.d.ts +36 -0
- package/dist/src/Database/integrations/pgsql/PostgresDatabase.js +54 -0
- package/dist/src/Database/integrations/pgsql/PostgresDatabase.js.map +1 -0
- package/dist/src/Database/integrations/pgsql/PostgresTransaction.d.ts +63 -0
- package/dist/src/Database/integrations/pgsql/PostgresTransaction.js +61 -0
- package/dist/src/Database/integrations/pgsql/PostgresTransaction.js.map +1 -0
- package/dist/src/Database/types.d.ts +76 -0
- package/dist/src/Database/types.js +2 -0
- package/dist/src/Database/types.js.map +1 -0
- package/dist/src/Globals.d.ts +93 -0
- package/dist/src/Globals.js +99 -0
- package/dist/src/Globals.js.map +1 -0
- package/dist/src/Logger/Logger.d.ts +161 -0
- package/dist/src/Logger/Logger.js +299 -0
- package/dist/src/Logger/Logger.js.map +1 -0
- package/dist/src/Mailer/Mailer.d.ts +78 -0
- package/dist/src/Mailer/Mailer.js +182 -0
- package/dist/src/Mailer/Mailer.js.map +1 -0
- package/dist/src/Publisher/Publisher.d.ts +39 -0
- package/dist/src/Publisher/Publisher.js +77 -0
- package/dist/src/Publisher/Publisher.js.map +1 -0
- package/dist/src/Server/RouteResolver.d.ts +33 -0
- package/dist/src/Server/RouteResolver.js +100 -0
- package/dist/src/Server/RouteResolver.js.map +1 -0
- package/dist/src/Server/Router.d.ts +157 -0
- package/dist/src/Server/Router.js +32 -0
- package/dist/src/Server/Router.js.map +1 -0
- package/dist/src/Server/lib/ContainerServer.d.ts +42 -0
- package/dist/src/Server/lib/ContainerServer.js +66 -0
- package/dist/src/Server/lib/ContainerServer.js.map +1 -0
- package/dist/src/Server/lib/Server.d.ts +45 -0
- package/dist/src/Server/lib/Server.js +93 -0
- package/dist/src/Server/lib/Server.js.map +1 -0
- package/dist/src/Server/lib/container/GenericHandler.d.ts +9 -0
- package/dist/src/Server/lib/container/GenericHandler.js +82 -0
- package/dist/src/Server/lib/container/GenericHandler.js.map +1 -0
- package/dist/src/Server/lib/container/GenericHandlerEvent.d.ts +52 -0
- package/dist/src/Server/lib/container/GenericHandlerEvent.js +132 -0
- package/dist/src/Server/lib/container/GenericHandlerEvent.js.map +1 -0
- package/dist/src/Server/lib/container/HealthHandler.d.ts +9 -0
- package/dist/src/Server/lib/container/HealthHandler.js +19 -0
- package/dist/src/Server/lib/container/HealthHandler.js.map +1 -0
- package/dist/src/Server/lib/container/Proxy.d.ts +67 -0
- package/dist/src/Server/lib/container/Proxy.js +143 -0
- package/dist/src/Server/lib/container/Proxy.js.map +1 -0
- package/dist/src/Server/lib/container/Utils.d.ts +14 -0
- package/dist/src/Server/lib/container/Utils.js +37 -0
- package/dist/src/Server/lib/container/Utils.js.map +1 -0
- package/dist/src/Util/AsyncSingleton.d.ts +31 -0
- package/dist/src/Util/AsyncSingleton.js +83 -0
- package/dist/src/Util/AsyncSingleton.js.map +1 -0
- package/dist/src/Util/Utils.d.ts +61 -0
- package/dist/src/Util/Utils.js +147 -0
- package/dist/src/Util/Utils.js.map +1 -0
- package/dist/src/Validation/Validator.d.ts +17 -0
- package/dist/src/Validation/Validator.js +39 -0
- package/dist/src/Validation/Validator.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/index.ts +41 -0
- package/jest.config.ts +37 -0
- package/jest.smoke.config.ts +34 -0
- package/package.json +66 -22
- package/src/API/Request.ts +214 -0
- package/src/API/Response.ts +370 -0
- package/src/BaseEvent/DynamoTransaction.ts +175 -0
- package/src/BaseEvent/EventProcessor.ts +140 -0
- package/src/BaseEvent/Process.ts +78 -0
- package/src/BaseEvent/StepTransaction.ts +35 -0
- package/src/BaseEvent/Transaction.ts +323 -0
- package/src/Cache/Redis.ts +89 -0
- package/src/Cache/types.ts +33 -0
- package/src/Config/Configuration.ts +199 -0
- package/src/Config/EnvironmentVar.ts +142 -0
- package/src/Crypto/Crypto.ts +89 -0
- package/src/Database/Database.ts +22 -0
- package/src/Database/DatabaseManager.ts +67 -0
- package/src/Database/DatabaseTransaction.ts +170 -0
- package/src/Database/index.ts +27 -0
- package/src/Database/integrations/dynamo/DynamoDatabase.ts +58 -0
- package/src/Database/integrations/kysely/KyselyDatabase.ts +99 -0
- package/src/Database/integrations/kysely/KyselyTransaction.ts +172 -0
- package/src/Database/integrations/pgsql/PostgresDatabase.ts +56 -0
- package/src/Database/integrations/pgsql/PostgresTransaction.ts +87 -0
- package/src/Database/types.ts +85 -0
- package/src/Globals.ts +103 -0
- package/src/Logger/Logger.ts +363 -0
- package/src/Mailer/Mailer.ts +217 -0
- package/src/Publisher/Publisher.ts +96 -0
- package/src/Server/RouteResolver.ts +124 -0
- package/src/Server/Router.ts +200 -0
- package/src/Server/lib/ContainerServer.ts +65 -0
- package/src/Server/lib/Server.ts +109 -0
- package/src/Server/lib/container/GenericHandler.ts +76 -0
- package/src/Server/lib/container/GenericHandlerEvent.ts +154 -0
- package/src/Server/lib/container/HealthHandler.ts +11 -0
- package/src/Server/lib/container/Proxy.ts +172 -0
- package/src/Server/lib/container/Utils.ts +33 -0
- package/src/Util/AsyncSingleton.ts +86 -0
- package/src/Util/Utils.ts +131 -0
- package/src/Validation/Validator.ts +45 -0
- package/tests/API/Request.test.ts +273 -0
- package/tests/API/Response.test.ts +367 -0
- package/tests/BaseEvent/DynamoTransaction.test.ts +272 -0
- package/tests/BaseEvent/EventProcessor.test.ts +263 -0
- package/tests/BaseEvent/Process.test.ts +47 -0
- package/tests/BaseEvent/StepTransaction.test.ts +44 -0
- package/tests/BaseEvent/Transaction.test.ts +402 -0
- package/tests/Cache/Redis-client.test.ts +90 -0
- package/tests/Cache/Redis-cluster.test.ts +100 -0
- package/tests/Config/Config.test.ts +205 -0
- package/tests/Config/EnvironmentVar.test.ts +251 -0
- package/tests/Crypto/Crypto.test.ts +88 -0
- package/tests/Database/DatabaseManager.test.ts +79 -0
- package/tests/Database/integrations/dynamo/DynamoDatabase.test.ts +44 -0
- package/tests/Database/integrations/kysely/KyselyDatabase.test.ts +113 -0
- package/tests/Database/integrations/kysely/KyselyTransaction.test.ts +119 -0
- package/tests/Database/integrations/pg/PostgresDatabase.test.ts +76 -0
- package/tests/Database/integrations/pg/PostgresTransaction.test.ts +118 -0
- package/tests/Logger/Logger.test.ts +215 -0
- package/tests/Mailer/Mailer.test.ts +59 -0
- package/tests/Publisher/Publisher.test.ts +60 -0
- package/tests/Server/RouteResolver.test.ts +116 -0
- package/tests/Server/Router.test.ts +39 -0
- package/tests/Server/lib/ContainerServer.test.ts +531 -0
- package/tests/Server/lib/Server.test.ts +12 -0
- package/tests/Server/lib/container/GenericHandler.test.ts +131 -0
- package/tests/Server/lib/container/GenericHandlerEvent.test.ts +103 -0
- package/tests/Server/lib/container/HealthHandler.test.ts +30 -0
- package/tests/Server/lib/container/Proxy.test.ts +268 -0
- package/tests/Server/lib/container/Utils.test.ts +47 -0
- package/tests/Test.utils.ts +78 -0
- package/tests/Utils/Utils.test.ts +229 -0
- package/tests/Validation/Validator.test.ts +82 -0
- package/tsconfig.json +26 -0
- package/tsconfig.smoke.json +26 -0
- package/index.js +0 -88
- package/src/API/IKRequest.js +0 -52
- package/src/API/IKResponse.js +0 -119
- package/src/API/IKUtils.js +0 -51
- package/src/BaseEvent/IKProcess.js +0 -77
- package/src/BaseEvent/IKTransaction.js +0 -139
- package/src/Cache/Prototype/IKCache.js +0 -17
- package/src/Cache/Redis/IKRedis.js +0 -148
- package/src/Database/DDB/IKDB.js +0 -56
- package/src/Database/DDB/IKDBBaseExpression.js +0 -130
- package/src/Database/DDB/IKDBBaseQuery.js +0 -151
- package/src/Database/DDB/IKDBQueryBatchGet.js +0 -37
- package/src/Database/DDB/IKDBQueryBatchWrite.js +0 -64
- package/src/Database/DDB/IKDBQueryDelete.js +0 -34
- package/src/Database/DDB/IKDBQueryGet.js +0 -48
- package/src/Database/DDB/IKDBQueryPut.js +0 -87
- package/src/Database/DDB/IKDBQueryScan.js +0 -45
- package/src/Database/DDB/IKDBQueryTransactionalWrite.js +0 -69
- package/src/Database/DDB/IKDBQueryUpdate.js +0 -221
- package/src/Database/DDB/_IKDBQueryTransactionalRead.js +0 -46
- package/src/Database/PSQL/IKDB.js +0 -41
- package/src/Database/PSQL/IKDBBaseQuery.js +0 -26
- package/src/Database/Prototype/IKDB.js +0 -21
- package/src/Database/Prototype/IKDBBaseQuery.js +0 -14
- package/src/IKDynamoStream.js +0 -42
- package/src/IKEventProcessor.js +0 -42
- package/src/IKGlobals.js +0 -24
- package/src/IKRouter.js +0 -47
- package/src/IKStepTransaction.js +0 -14
- package/src/Logger/IKLogger.js +0 -136
- package/src/Mailer/IKMailer.js +0 -69
- package/src/Publisher/IKPublisher.js +0 -44
- package/src/Tracker/IKExecutionTracker.js +0 -79
- 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
|
+
})
|