@friggframework/core 2.0.0--canary.549.a579cca.0 → 2.0.0--canary.549.70ef06a.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/assertions/jest.config.ts +7 -0
- package/database/jest.config.ts +7 -0
- package/database/models/WorkflowExecutionModel.ts +315 -0
- package/database/models/WorkflowModel.ts +129 -0
- package/jest-global-setup-noop.ts +3 -0
- package/jest-global-teardown-noop.ts +3 -0
- package/jest-resolver.ts +36 -0
- package/jest-setup.ts +2 -0
- package/jest-teardown.ts +2 -0
- package/jest.config.ts +20 -0
- package/package.json +8 -5
- package/src/application/commands/integration-commands.test.ts +158 -0
- package/src/application/commands/integration-commands.ts +20 -35
- package/src/core/Worker.test.ts +158 -0
- package/src/database/adapters/lambda-invoker.test.ts +104 -0
- package/src/database/encryption/encryption-schema-registry.test.ts +397 -0
- package/src/database/encryption/field-encryption-service.test.ts +511 -0
- package/src/database/encryption/mongo-decryption-fix-verification.test.ts +337 -0
- package/src/database/encryption/postgres-decryption-fix-verification.test.ts +335 -0
- package/src/database/encryption/postgres-relation-decryption.test.ts +205 -0
- package/src/database/encryption/prisma-encryption-extension.test.ts +433 -0
- package/src/database/prisma.test.ts +65 -0
- package/src/database/repositories/health-check-repository-mongodb.test.ts +178 -0
- package/src/database/repositories/health-check-repository-postgres.test.ts +94 -0
- package/src/database/repositories/migration-status-repository-s3.test.ts +150 -0
- package/src/database/use-cases/check-database-health-use-case.test.ts +131 -0
- package/src/database/use-cases/check-database-state-use-case.test.ts +131 -0
- package/src/database/use-cases/check-encryption-health-use-case.test.ts +183 -0
- package/src/database/use-cases/get-database-state-via-worker-use-case.test.ts +126 -0
- package/src/database/use-cases/get-migration-status-use-case.test.ts +160 -0
- package/src/database/use-cases/run-database-migration-use-case.test.ts +350 -0
- package/src/database/use-cases/trigger-database-migration-use-case.test.ts +256 -0
- package/src/database/utils/mongodb-collection-utils.test.ts +133 -0
- package/src/database/utils/mongodb-schema-init.test.ts +152 -0
- package/src/database/utils/prisma-runner.test.ts +513 -0
- package/src/database/utils/prisma-schema-parser.test.ts +283 -0
- package/src/declarations.d.ts +7 -0
- package/src/encrypt/Cryptor.test.ts +137 -0
- package/src/errors/base-error.test.ts +32 -0
- package/src/errors/fetch-error.test.ts +105 -0
- package/src/errors/halt-error.test.ts +11 -0
- package/src/errors/validation-errors.test.ts +122 -0
- package/src/handlers/auth-flow.integration.test.ts +149 -0
- package/src/handlers/integration-event-dispatcher.test.ts +211 -0
- package/src/handlers/routers/db-migration.test.ts +69 -0
- package/src/handlers/routers/health.test.ts +251 -0
- package/src/handlers/routers/health.ts +9 -12
- package/src/handlers/routers/integration-webhook-routers.test.ts +116 -0
- package/src/handlers/use-cases/check-integrations-health-use-case.test.ts +124 -0
- package/src/handlers/webhook-flow.integration.test.ts +318 -0
- package/src/handlers/workers/db-migration.test.ts +168 -0
- package/src/handlers/workers/db-migration.ts +11 -13
- package/src/handlers/workers/integration-defined-workers.test.ts +254 -0
- package/src/integrations/integration-base.module-keys.test.ts +204 -0
- package/{integrations/tests/doubles/config-capturing-integration.js → src/integrations/tests/doubles/config-capturing-integration.ts} +13 -13
- package/{integrations/tests/doubles/dummy-integration-class.js → src/integrations/tests/doubles/dummy-integration-class.ts} +21 -17
- package/{integrations/tests/doubles/test-integration-repository.js → src/integrations/tests/doubles/test-integration-repository.ts} +14 -13
- package/src/integrations/tests/integration-router-multi-auth.test.ts +531 -0
- package/src/integrations/tests/use-cases/create-integration.test.ts +131 -0
- package/src/integrations/tests/use-cases/delete-integration-for-user.test.ts +150 -0
- package/src/integrations/tests/use-cases/find-integration-context-by-external-entity-id.test.ts +92 -0
- package/src/integrations/tests/use-cases/get-integration-for-user.test.ts +150 -0
- package/src/integrations/tests/use-cases/get-integration-instance.test.ts +176 -0
- package/src/integrations/tests/use-cases/get-integrations-for-user.test.ts +176 -0
- package/src/integrations/tests/use-cases/get-possible-integrations.test.ts +188 -0
- package/src/integrations/tests/use-cases/update-integration-messages.test.ts +142 -0
- package/src/integrations/tests/use-cases/update-integration-status.test.ts +103 -0
- package/src/integrations/tests/use-cases/update-integration.test.ts +208 -0
- package/src/integrations/use-cases/create-process.test.ts +172 -0
- package/src/integrations/use-cases/get-process.test.ts +181 -0
- package/src/integrations/use-cases/load-integration-context-full.test.ts +316 -0
- package/src/integrations/use-cases/load-integration-context.test.ts +115 -0
- package/src/integrations/use-cases/update-process-metrics.test.ts +278 -0
- package/src/integrations/use-cases/update-process-state.test.ts +249 -0
- package/src/lambda/TimeoutCatcher.test.ts +69 -0
- package/src/logs/logger.test.ts +76 -0
- package/src/modules/module-hydration.test.ts +203 -0
- package/src/modules/module.ts +1 -1
- package/src/modules/requester/oauth-2.test.ts +425 -0
- package/src/modules/requester/requester.test.ts +28 -0
- package/{modules/test/mock-api/api.js → src/modules/test/mock-api/api.ts} +6 -8
- package/{modules/test/mock-api/definition.js → src/modules/test/mock-api/definition.ts} +13 -14
- package/{modules/test/mock-api/mocks/hubspot.js → src/modules/test/mock-api/mocks/hubspot.ts} +6 -8
- package/{modules/tests/doubles/test-module-factory.js → src/modules/tests/doubles/test-module-factory.ts} +2 -5
- package/{modules/tests/doubles/test-module-repository.js → src/modules/tests/doubles/test-module-repository.ts} +7 -7
- package/src/modules/tests/module-on-token-update.test.ts +125 -0
- package/src/queues/queuer-util.test.ts +131 -0
- package/{user/tests/doubles/test-user-repository.js → src/user/tests/doubles/test-user-repository.ts} +17 -15
- package/src/user/tests/use-cases/create-individual-user.test.ts +24 -0
- package/src/user/tests/use-cases/create-organization-user.test.ts +28 -0
- package/src/user/tests/use-cases/create-token-for-user-id.test.ts +18 -0
- package/src/user/tests/use-cases/get-user-from-adopter-jwt.test.ts +113 -0
- package/src/user/tests/use-cases/get-user-from-bearer-token.test.ts +64 -0
- package/src/user/tests/use-cases/get-user-from-x-frigg-headers.test.ts +440 -0
- package/src/user/tests/use-cases/login-user.test.ts +220 -0
- package/src/user/use-cases/authenticate-with-shared-secret.test.ts +127 -0
- package/src/websocket/repositories/websocket-connection-repository.test.ts +220 -0
- package/tsconfig.test.json +10 -0
- package/workflows/frigg-workflow.ts +322 -0
- package/workflows/index.ts +205 -0
- package/workflows/steps/fan-out-step.ts +275 -0
- package/workflows/steps/function-step.ts +174 -0
- package/workflows/steps/index.ts +30 -0
- package/workflows/steps/workflow-step.ts +115 -0
- package/workflows/use-cases/create-workflow.ts +332 -0
- package/workflows/use-cases/execute-workflow-step.ts +465 -0
- package/workflows/use-cases/execute-workflow.ts +403 -0
- package/workflows/workflow-execution-repository.ts +415 -0
- package/workflows/workflow-execution.ts +209 -0
- package/workflows/workflow-queue-service.ts +379 -0
- package/workflows/workflow-repository.ts +295 -0
- package/workflows/workflow.ts +117 -0
- package/application/commands/credential-commands.js +0 -245
- package/application/commands/entity-commands.js +0 -336
- package/application/commands/integration-commands.js +0 -210
- package/application/commands/scheduler-commands.js +0 -263
- package/application/commands/user-commands.js +0 -283
- package/application/index.js +0 -73
- package/assertions/get.js +0 -139
- package/assertions/index.js +0 -16
- package/assertions/jest.config.js +0 -5
- package/associations/association.js +0 -3
- package/core/Delegate.js +0 -29
- package/core/Worker.js +0 -72
- package/core/create-handler.js +0 -75
- package/core/index.js +0 -7
- package/core/load-installed-modules.js +0 -28
- package/core/secrets-to-env.js +0 -61
- package/credential/repositories/credential-repository-documentdb.js +0 -304
- package/credential/repositories/credential-repository-factory.js +0 -54
- package/credential/repositories/credential-repository-interface.js +0 -98
- package/credential/repositories/credential-repository-mongo.js +0 -269
- package/credential/repositories/credential-repository-postgres.js +0 -287
- package/credential/repositories/credential-repository.js +0 -300
- package/credential/use-cases/get-credential-for-user.js +0 -25
- package/credential/use-cases/update-authentication-status.js +0 -15
- package/database/adapters/lambda-invoker.js +0 -97
- package/database/config.js +0 -154
- package/database/documentdb-encryption-service.js +0 -330
- package/database/documentdb-utils.js +0 -136
- package/database/encryption/encryption-schema-registry.js +0 -272
- package/database/encryption/field-encryption-service.js +0 -226
- package/database/encryption/logger.js +0 -79
- package/database/encryption/prisma-encryption-extension.js +0 -222
- package/database/index.js +0 -25
- package/database/jest.config.js +0 -5
- package/database/prisma.js +0 -182
- package/database/repositories/health-check-repository-documentdb.js +0 -138
- package/database/repositories/health-check-repository-factory.js +0 -48
- package/database/repositories/health-check-repository-interface.js +0 -82
- package/database/repositories/health-check-repository-mongodb.js +0 -89
- package/database/repositories/health-check-repository-postgres.js +0 -82
- package/database/repositories/migration-status-repository-s3.js +0 -137
- package/database/use-cases/check-database-health-use-case.js +0 -29
- package/database/use-cases/check-database-state-use-case.js +0 -81
- package/database/use-cases/check-encryption-health-use-case.js +0 -83
- package/database/use-cases/get-database-state-via-worker-use-case.js +0 -61
- package/database/use-cases/get-migration-status-use-case.js +0 -93
- package/database/use-cases/run-database-migration-use-case.js +0 -139
- package/database/use-cases/test-encryption-use-case.js +0 -253
- package/database/use-cases/trigger-database-migration-use-case.js +0 -157
- package/database/utils/mongodb-collection-utils.js +0 -94
- package/database/utils/mongodb-schema-init.js +0 -108
- package/database/utils/prisma-runner.js +0 -477
- package/database/utils/prisma-schema-parser.js +0 -182
- package/encrypt/Cryptor.js +0 -102
- package/encrypt/aes.js +0 -27
- package/encrypt/index.js +0 -3
- package/errors/base-error.js +0 -3
- package/errors/client-safe-error.js +0 -3
- package/errors/fetch-error.js +0 -3
- package/errors/halt-error.js +0 -3
- package/errors/index.js +0 -14
- package/errors/validation-errors.js +0 -3
- package/handlers/app-definition-loader.js +0 -38
- package/handlers/app-handler-helpers.js +0 -57
- package/handlers/backend-utils.js +0 -186
- package/handlers/database-migration-handler.js +0 -227
- package/handlers/integration-event-dispatcher.js +0 -54
- package/handlers/routers/auth.js +0 -15
- package/handlers/routers/db-migration.handler.js +0 -29
- package/handlers/routers/db-migration.js +0 -326
- package/handlers/routers/health.js +0 -516
- package/handlers/routers/integration-defined-routers.js +0 -45
- package/handlers/routers/integration-webhook-routers.js +0 -67
- package/handlers/routers/user.js +0 -63
- package/handlers/routers/websocket.js +0 -57
- package/handlers/use-cases/check-external-apis-health-use-case.js +0 -81
- package/handlers/use-cases/check-integrations-health-use-case.js +0 -44
- package/handlers/workers/db-migration.js +0 -352
- package/handlers/workers/integration-defined-workers.js +0 -27
- package/index.js +0 -176
- package/infrastructure/scheduler/eventbridge-scheduler-adapter.js +0 -184
- package/infrastructure/scheduler/index.js +0 -33
- package/infrastructure/scheduler/mock-scheduler-adapter.js +0 -143
- package/infrastructure/scheduler/scheduler-service-factory.js +0 -73
- package/infrastructure/scheduler/scheduler-service-interface.js +0 -47
- package/integrations/index.js +0 -21
- package/integrations/integration-base.js +0 -535
- package/integrations/integration-router.js +0 -666
- package/integrations/options.js +0 -53
- package/integrations/repositories/integration-mapping-repository-documentdb.js +0 -280
- package/integrations/repositories/integration-mapping-repository-factory.js +0 -57
- package/integrations/repositories/integration-mapping-repository-interface.js +0 -106
- package/integrations/repositories/integration-mapping-repository-mongo.js +0 -161
- package/integrations/repositories/integration-mapping-repository-postgres.js +0 -227
- package/integrations/repositories/integration-mapping-repository.js +0 -156
- package/integrations/repositories/integration-repository-documentdb.js +0 -210
- package/integrations/repositories/integration-repository-factory.js +0 -51
- package/integrations/repositories/integration-repository-interface.js +0 -127
- package/integrations/repositories/integration-repository-mongo.js +0 -303
- package/integrations/repositories/integration-repository-postgres.js +0 -352
- package/integrations/repositories/process-repository-documentdb.js +0 -243
- package/integrations/repositories/process-repository-factory.js +0 -53
- package/integrations/repositories/process-repository-interface.js +0 -90
- package/integrations/repositories/process-repository-mongo.js +0 -190
- package/integrations/repositories/process-repository-postgres.js +0 -217
- package/integrations/use-cases/create-integration.js +0 -83
- package/integrations/use-cases/create-process.js +0 -128
- package/integrations/use-cases/delete-integration-for-user.js +0 -101
- package/integrations/use-cases/find-integration-context-by-external-entity-id.js +0 -72
- package/integrations/use-cases/get-integration-for-user.js +0 -78
- package/integrations/use-cases/get-integration-instance-by-definition.js +0 -67
- package/integrations/use-cases/get-integration-instance.js +0 -83
- package/integrations/use-cases/get-integrations-for-user.js +0 -88
- package/integrations/use-cases/get-possible-integrations.js +0 -27
- package/integrations/use-cases/get-process.js +0 -87
- package/integrations/use-cases/index.js +0 -19
- package/integrations/use-cases/load-integration-context.js +0 -71
- package/integrations/use-cases/update-integration-messages.js +0 -44
- package/integrations/use-cases/update-integration-status.js +0 -32
- package/integrations/use-cases/update-integration.js +0 -92
- package/integrations/use-cases/update-process-metrics.js +0 -201
- package/integrations/use-cases/update-process-state.js +0 -119
- package/integrations/utils/map-integration-dto.js +0 -38
- package/jest-global-setup-noop.js +0 -3
- package/jest-global-teardown-noop.js +0 -3
- package/jest-setup.js +0 -2
- package/jest-teardown.js +0 -2
- package/jest.config.js +0 -21
- package/lambda/TimeoutCatcher.js +0 -43
- package/lambda/index.js +0 -3
- package/logs/index.js +0 -7
- package/logs/logger.js +0 -65
- package/modules/ModuleConstants.js +0 -10
- package/modules/index.js +0 -15
- package/modules/module-factory.js +0 -56
- package/modules/module.js +0 -228
- package/modules/repositories/module-repository-documentdb.js +0 -335
- package/modules/repositories/module-repository-factory.js +0 -40
- package/modules/repositories/module-repository-interface.js +0 -129
- package/modules/repositories/module-repository-mongo.js +0 -408
- package/modules/repositories/module-repository-postgres.js +0 -453
- package/modules/repositories/module-repository.js +0 -345
- package/modules/requester/api-key.js +0 -52
- package/modules/requester/basic.js +0 -43
- package/modules/requester/oauth-2.js +0 -396
- package/modules/requester/requester.js +0 -167
- package/modules/use-cases/get-entities-for-user.js +0 -32
- package/modules/use-cases/get-entity-options-by-id.js +0 -71
- package/modules/use-cases/get-entity-options-by-type.js +0 -34
- package/modules/use-cases/get-module-instance-from-type.js +0 -31
- package/modules/use-cases/get-module.js +0 -74
- package/modules/use-cases/process-authorization-callback.js +0 -133
- package/modules/use-cases/refresh-entity-options.js +0 -72
- package/modules/use-cases/test-module-auth.js +0 -72
- package/modules/utils/map-module-dto.js +0 -18
- package/queues/index.js +0 -4
- package/queues/queuer-util.js +0 -66
- package/syncs/manager.js +0 -489
- package/syncs/repositories/sync-repository-documentdb.js +0 -240
- package/syncs/repositories/sync-repository-factory.js +0 -43
- package/syncs/repositories/sync-repository-interface.js +0 -109
- package/syncs/repositories/sync-repository-mongo.js +0 -239
- package/syncs/repositories/sync-repository-postgres.js +0 -319
- package/syncs/sync.js +0 -113
- package/token/repositories/token-repository-documentdb.js +0 -137
- package/token/repositories/token-repository-factory.js +0 -40
- package/token/repositories/token-repository-interface.js +0 -131
- package/token/repositories/token-repository-mongo.js +0 -219
- package/token/repositories/token-repository-postgres.js +0 -264
- package/token/repositories/token-repository.js +0 -219
- package/user/repositories/user-repository-documentdb.js +0 -441
- package/user/repositories/user-repository-factory.js +0 -52
- package/user/repositories/user-repository-interface.js +0 -201
- package/user/repositories/user-repository-mongo.js +0 -308
- package/user/repositories/user-repository-postgres.js +0 -360
- package/user/use-cases/authenticate-user.js +0 -127
- package/user/use-cases/authenticate-with-shared-secret.js +0 -48
- package/user/use-cases/create-individual-user.js +0 -61
- package/user/use-cases/create-organization-user.js +0 -47
- package/user/use-cases/create-token-for-user-id.js +0 -30
- package/user/use-cases/get-user-from-adopter-jwt.js +0 -149
- package/user/use-cases/get-user-from-bearer-token.js +0 -77
- package/user/use-cases/get-user-from-x-frigg-headers.js +0 -132
- package/user/use-cases/login-user.js +0 -122
- package/user/user.js +0 -125
- package/utils/backend-path.js +0 -6
- package/utils/index.js +0 -6
- package/websocket/repositories/websocket-connection-repository-documentdb.js +0 -119
- package/websocket/repositories/websocket-connection-repository-factory.js +0 -44
- package/websocket/repositories/websocket-connection-repository-interface.js +0 -106
- package/websocket/repositories/websocket-connection-repository-mongo.js +0 -156
- package/websocket/repositories/websocket-connection-repository-postgres.js +0 -196
- package/websocket/repositories/websocket-connection-repository.js +0 -161
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
jest.mock('../../database/config', () => {
|
|
2
|
+
const mockConfig = {
|
|
3
|
+
DB_TYPE: 'mongodb',
|
|
4
|
+
getDatabaseType: jest.fn(() => 'mongodb'),
|
|
5
|
+
PRISMA_LOG_LEVEL: 'error,warn',
|
|
6
|
+
PRISMA_QUERY_LOGGING: false,
|
|
7
|
+
};
|
|
8
|
+
return { __esModule: true, default: mockConfig, ...mockConfig };
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
jest.mock('../../integrations/repositories/integration-repository-factory', () => ({
|
|
12
|
+
createIntegrationRepository: jest.fn(() => ({
|
|
13
|
+
findIntegrationById: jest.fn(),
|
|
14
|
+
findIntegrationByUserId: jest.fn(),
|
|
15
|
+
findIntegrationsByUserId: jest.fn(),
|
|
16
|
+
createIntegration: jest.fn(),
|
|
17
|
+
updateIntegrationById: jest.fn(),
|
|
18
|
+
deleteIntegrationById: jest.fn(),
|
|
19
|
+
})),
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
jest.mock('../../modules/repositories/module-repository-factory', () => ({
|
|
23
|
+
createModuleRepository: jest.fn(() => ({})),
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
const mockFindExecute: any = jest.fn();
|
|
27
|
+
|
|
28
|
+
jest.mock('../../integrations/use-cases/find-integration-context-by-external-entity-id', () => {
|
|
29
|
+
return {
|
|
30
|
+
FindIntegrationContextByExternalEntityIdUseCase: jest
|
|
31
|
+
.fn()
|
|
32
|
+
.mockImplementation(() => ({
|
|
33
|
+
execute: mockFindExecute,
|
|
34
|
+
})),
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
import {
|
|
39
|
+
createIntegrationCommands,
|
|
40
|
+
findIntegrationContextByExternalEntityId,
|
|
41
|
+
} from './integration-commands';
|
|
42
|
+
import {
|
|
43
|
+
FindIntegrationContextByExternalEntityIdUseCase,
|
|
44
|
+
} from '../../integrations/use-cases/find-integration-context-by-external-entity-id';
|
|
45
|
+
import { DummyIntegration } from '../../integrations/tests/doubles/dummy-integration-class';
|
|
46
|
+
|
|
47
|
+
describe('integration commands', () => {
|
|
48
|
+
beforeEach(() => {
|
|
49
|
+
jest.clearAllMocks();
|
|
50
|
+
mockFindExecute.mockReset();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('requires an integrationClass when creating commands', () => {
|
|
54
|
+
expect(() => createIntegrationCommands({} as any)).toThrow(
|
|
55
|
+
'integrationClass is required',
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('creates use cases with default repositories', () => {
|
|
60
|
+
createIntegrationCommands({
|
|
61
|
+
integrationClass: DummyIntegration,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Verify that the use case is created with default repositories instantiated internally
|
|
65
|
+
expect(
|
|
66
|
+
FindIntegrationContextByExternalEntityIdUseCase,
|
|
67
|
+
).toHaveBeenCalledWith({
|
|
68
|
+
integrationRepository: expect.any(Object),
|
|
69
|
+
moduleRepository: expect.any(Object),
|
|
70
|
+
loadIntegrationContextUseCase: expect.any(Object),
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('returns context when findIntegrationContextByExternalEntityId succeeds', async () => {
|
|
75
|
+
const expectedContext = { record: { id: 'integration-1' } };
|
|
76
|
+
mockFindExecute.mockResolvedValue({ context: expectedContext });
|
|
77
|
+
const commands = createIntegrationCommands({
|
|
78
|
+
integrationClass: DummyIntegration,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const result = await commands.findIntegrationContextByExternalEntityId(
|
|
82
|
+
'ext-1',
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
expect(mockFindExecute).toHaveBeenCalledWith({
|
|
86
|
+
externalEntityId: 'ext-1',
|
|
87
|
+
});
|
|
88
|
+
expect(result).toEqual({ context: expectedContext });
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('maps known errors to status codes', async () => {
|
|
92
|
+
const error = Object.assign(new Error('Entity missing'), {
|
|
93
|
+
code: 'ENTITY_NOT_FOUND',
|
|
94
|
+
});
|
|
95
|
+
mockFindExecute.mockRejectedValue(error);
|
|
96
|
+
const commands = createIntegrationCommands({
|
|
97
|
+
integrationClass: DummyIntegration,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const result = await commands.findIntegrationContextByExternalEntityId(
|
|
101
|
+
'ext-1',
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
expect(result).toEqual({
|
|
105
|
+
error: 401,
|
|
106
|
+
reason: 'Entity missing',
|
|
107
|
+
code: 'ENTITY_NOT_FOUND',
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('delegates loadIntegrationContextById to the loader use case', async () => {
|
|
112
|
+
const commands = createIntegrationCommands({
|
|
113
|
+
integrationClass: DummyIntegration,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const result = await commands.loadIntegrationContextById('integration-1');
|
|
117
|
+
|
|
118
|
+
expect(result).toHaveProperty('error');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('exposes a one-off helper for finding integration context by external entity id', async () => {
|
|
122
|
+
const expectedContext = { record: { id: 'integration-1' } };
|
|
123
|
+
mockFindExecute.mockResolvedValue({ context: expectedContext });
|
|
124
|
+
|
|
125
|
+
const result = await findIntegrationContextByExternalEntityId({
|
|
126
|
+
integrationClass: DummyIntegration,
|
|
127
|
+
externalEntityId: 'ext-2',
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
expect(mockFindExecute).toHaveBeenCalledWith({
|
|
131
|
+
externalEntityId: 'ext-2',
|
|
132
|
+
});
|
|
133
|
+
expect(result).toEqual({ context: expectedContext });
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe('deleteIntegrationById', () => {
|
|
137
|
+
it('returns error if integrationId is missing', async () => {
|
|
138
|
+
const commands = createIntegrationCommands({
|
|
139
|
+
integrationClass: DummyIntegration,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const result = await commands.deleteIntegrationById(null as any);
|
|
143
|
+
|
|
144
|
+
expect(result).toHaveProperty('error');
|
|
145
|
+
expect(result.reason).toContain('integrationId is required');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('calls repository deleteIntegrationById', async () => {
|
|
149
|
+
const commands = createIntegrationCommands({
|
|
150
|
+
integrationClass: DummyIntegration,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const result = await commands.deleteIntegrationById('integration-123');
|
|
154
|
+
|
|
155
|
+
expect(result).toHaveProperty('error');
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
});
|
|
@@ -1,26 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const {
|
|
10
|
-
LoadIntegrationContextUseCase,
|
|
11
|
-
} = require('../../../integrations/use-cases/load-integration-context');
|
|
12
|
-
const {
|
|
13
|
-
FindIntegrationContextByExternalEntityIdUseCase,
|
|
14
|
-
} = require('../../../integrations/use-cases/find-integration-context-by-external-entity-id');
|
|
15
|
-
const {
|
|
16
|
-
GetIntegrationsForUser,
|
|
17
|
-
} = require('../../../integrations/use-cases/get-integrations-for-user');
|
|
18
|
-
const {
|
|
19
|
-
CreateIntegration,
|
|
20
|
-
} = require('../../../integrations/use-cases/create-integration');
|
|
21
|
-
const {
|
|
22
|
-
getModulesDefinitionFromIntegrationClasses,
|
|
23
|
-
} = require('../../../integrations/utils/map-integration-dto');
|
|
1
|
+
import { createIntegrationRepository } from '../../integrations/repositories/integration-repository-factory';
|
|
2
|
+
import { createModuleRepository } from '../../modules/repositories/module-repository-factory';
|
|
3
|
+
import { ModuleFactory } from '../../modules/module-factory';
|
|
4
|
+
import { LoadIntegrationContextUseCase } from '../../integrations/use-cases/load-integration-context';
|
|
5
|
+
import { FindIntegrationContextByExternalEntityIdUseCase } from '../../integrations/use-cases/find-integration-context-by-external-entity-id';
|
|
6
|
+
import { GetIntegrationsForUser } from '../../integrations/use-cases/get-integrations-for-user';
|
|
7
|
+
import { CreateIntegration } from '../../integrations/use-cases/create-integration';
|
|
8
|
+
import { getModulesDefinitionFromIntegrationClasses } from '../../integrations/utils/map-integration-dto';
|
|
24
9
|
|
|
25
10
|
export interface IntegrationClass {
|
|
26
11
|
name?: string;
|
|
@@ -84,7 +69,7 @@ function mapErrorToResponse(error: Error & { code?: string }): ErrorResponse {
|
|
|
84
69
|
};
|
|
85
70
|
}
|
|
86
71
|
|
|
87
|
-
export function createIntegrationCommands({ integrationClass }: { integrationClass: IntegrationClass }):
|
|
72
|
+
export function createIntegrationCommands({ integrationClass }: { integrationClass: IntegrationClass }): any {
|
|
88
73
|
if (!integrationClass) {
|
|
89
74
|
throw new Error('integrationClass is required');
|
|
90
75
|
}
|
|
@@ -94,41 +79,41 @@ export function createIntegrationCommands({ integrationClass }: { integrationCla
|
|
|
94
79
|
|
|
95
80
|
const moduleDefinitions = getModulesDefinitionFromIntegrationClasses([
|
|
96
81
|
integrationClass,
|
|
97
|
-
]);
|
|
82
|
+
] as any);
|
|
98
83
|
|
|
99
84
|
const moduleFactory = new ModuleFactory({
|
|
100
|
-
moduleRepository,
|
|
101
|
-
moduleDefinitions,
|
|
85
|
+
moduleRepository: moduleRepository as any,
|
|
86
|
+
moduleDefinitions: moduleDefinitions as any,
|
|
102
87
|
});
|
|
103
88
|
|
|
104
89
|
const loadIntegrationContextUseCase = new LoadIntegrationContextUseCase({
|
|
105
90
|
integrationRepository,
|
|
106
|
-
moduleRepository,
|
|
91
|
+
moduleRepository: moduleRepository as any,
|
|
107
92
|
moduleFactory,
|
|
108
93
|
});
|
|
109
94
|
|
|
110
95
|
const findByExternalEntityIdUseCase =
|
|
111
96
|
new FindIntegrationContextByExternalEntityIdUseCase({
|
|
112
97
|
integrationRepository,
|
|
113
|
-
moduleRepository,
|
|
98
|
+
moduleRepository: moduleRepository as any,
|
|
114
99
|
loadIntegrationContextUseCase: loadIntegrationContextUseCase,
|
|
115
100
|
});
|
|
116
101
|
|
|
117
102
|
const getIntegrationsForUserUseCase = new GetIntegrationsForUser({
|
|
118
103
|
integrationRepository,
|
|
119
|
-
integrationClasses: [integrationClass],
|
|
104
|
+
integrationClasses: [integrationClass] as any,
|
|
120
105
|
moduleFactory,
|
|
121
|
-
moduleRepository,
|
|
106
|
+
moduleRepository: moduleRepository as any,
|
|
122
107
|
});
|
|
123
108
|
|
|
124
109
|
const createIntegrationUseCase = new CreateIntegration({
|
|
125
110
|
integrationRepository,
|
|
126
|
-
integrationClasses: [integrationClass],
|
|
111
|
+
integrationClasses: [integrationClass] as any,
|
|
127
112
|
moduleFactory,
|
|
128
113
|
});
|
|
129
114
|
|
|
130
115
|
return {
|
|
131
|
-
async findIntegrationContextByExternalEntityId(externalEntityId: string) {
|
|
116
|
+
async findIntegrationContextByExternalEntityId(externalEntityId: string): Promise<any> {
|
|
132
117
|
try {
|
|
133
118
|
const { context } = await findByExternalEntityIdUseCase.execute(
|
|
134
119
|
{
|
|
@@ -167,7 +152,7 @@ export function createIntegrationCommands({ integrationClass }: { integrationCla
|
|
|
167
152
|
const integration = await createIntegrationUseCase.execute(
|
|
168
153
|
entityIds,
|
|
169
154
|
userId,
|
|
170
|
-
config
|
|
155
|
+
config as any
|
|
171
156
|
);
|
|
172
157
|
return integration;
|
|
173
158
|
} catch (error) {
|
|
@@ -177,7 +162,7 @@ export function createIntegrationCommands({ integrationClass }: { integrationCla
|
|
|
177
162
|
|
|
178
163
|
async updateIntegrationConfig({ integrationId, config }: UpdateIntegrationConfigParams) {
|
|
179
164
|
try {
|
|
180
|
-
const integration = await integrationRepository.updateIntegrationConfig(
|
|
165
|
+
const integration = await (integrationRepository as any).updateIntegrationConfig(
|
|
181
166
|
integrationId,
|
|
182
167
|
config
|
|
183
168
|
);
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Worker - AWS SDK v3 Migration
|
|
3
|
+
*
|
|
4
|
+
* Tests SQS Worker operations using aws-sdk-client-mock
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { mockClient } from 'aws-sdk-client-mock';
|
|
8
|
+
import { SQSClient, GetQueueUrlCommand, SendMessageCommand } from '@aws-sdk/client-sqs';
|
|
9
|
+
import { Worker } from './Worker';
|
|
10
|
+
|
|
11
|
+
describe('Worker - AWS SDK v3', () => {
|
|
12
|
+
let sqsMock: ReturnType<typeof mockClient>;
|
|
13
|
+
let worker: Worker;
|
|
14
|
+
const originalEnv = process.env;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
sqsMock = mockClient(SQSClient);
|
|
18
|
+
worker = new Worker();
|
|
19
|
+
jest.clearAllMocks();
|
|
20
|
+
process.env = { ...originalEnv, AWS_REGION: 'us-east-1' };
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
sqsMock.reset();
|
|
25
|
+
process.env = originalEnv;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('getQueueURL()', () => {
|
|
29
|
+
it('should get queue URL from SQS', async () => {
|
|
30
|
+
sqsMock.on(GetQueueUrlCommand).resolves({
|
|
31
|
+
QueueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789/test-queue',
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const result = await worker.getQueueURL({ QueueName: 'test-queue' });
|
|
35
|
+
|
|
36
|
+
expect(result).toBe('https://sqs.us-east-1.amazonaws.com/123456789/test-queue');
|
|
37
|
+
expect(sqsMock.calls()).toHaveLength(1);
|
|
38
|
+
|
|
39
|
+
const call = sqsMock.call(0);
|
|
40
|
+
expect(call.args[0].input).toMatchObject({
|
|
41
|
+
QueueName: 'test-queue',
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should handle queue not found error', async () => {
|
|
46
|
+
sqsMock.on(GetQueueUrlCommand).rejects(new Error('Queue does not exist'));
|
|
47
|
+
|
|
48
|
+
await expect(worker.getQueueURL({ QueueName: 'nonexistent-queue' }))
|
|
49
|
+
.rejects.toThrow('Queue does not exist');
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe('sendAsyncSQSMessage()', () => {
|
|
54
|
+
it('should send message and return MessageId', async () => {
|
|
55
|
+
sqsMock.on(SendMessageCommand).resolves({
|
|
56
|
+
MessageId: 'message-123',
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const params = {
|
|
60
|
+
QueueUrl: 'https://queue-url',
|
|
61
|
+
MessageBody: JSON.stringify({ test: 'data' }),
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const result = await worker.sendAsyncSQSMessage(params);
|
|
65
|
+
|
|
66
|
+
expect(result).toBe('message-123');
|
|
67
|
+
expect(sqsMock.calls()).toHaveLength(1);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should handle send errors', async () => {
|
|
71
|
+
sqsMock.on(SendMessageCommand).rejects(new Error('Send failed'));
|
|
72
|
+
|
|
73
|
+
const params = {
|
|
74
|
+
QueueUrl: 'https://queue-url',
|
|
75
|
+
MessageBody: 'test',
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
await expect(worker.sendAsyncSQSMessage(params)).rejects.toThrow('Send failed');
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('send()', () => {
|
|
83
|
+
it('should validate params and send message with delay', async () => {
|
|
84
|
+
sqsMock.on(SendMessageCommand).resolves({
|
|
85
|
+
MessageId: 'delayed-message-id',
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
worker._validateParams = jest.fn(); // Mock validation
|
|
89
|
+
|
|
90
|
+
const params = {
|
|
91
|
+
QueueUrl: 'https://queue-url',
|
|
92
|
+
data: 'test',
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const result = await worker.send(params, 5);
|
|
96
|
+
|
|
97
|
+
expect(worker._validateParams).toHaveBeenCalledWith(params);
|
|
98
|
+
expect(result).toBe('delayed-message-id');
|
|
99
|
+
|
|
100
|
+
const call = sqsMock.call(0);
|
|
101
|
+
expect((call.args[0].input as any).DelaySeconds).toBe(5);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should send message with zero delay by default', async () => {
|
|
105
|
+
sqsMock.on(SendMessageCommand).resolves({
|
|
106
|
+
MessageId: 'message-id',
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
worker._validateParams = jest.fn();
|
|
110
|
+
|
|
111
|
+
const params = {
|
|
112
|
+
QueueUrl: 'https://queue-url',
|
|
113
|
+
data: 'test',
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
await worker.send(params);
|
|
117
|
+
|
|
118
|
+
const call = sqsMock.call(0);
|
|
119
|
+
expect((call.args[0].input as any).DelaySeconds).toBe(0);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe('run()', () => {
|
|
124
|
+
it('should process SQS records', async () => {
|
|
125
|
+
worker._validateParams = jest.fn();
|
|
126
|
+
worker._run = jest.fn().mockResolvedValue(undefined);
|
|
127
|
+
|
|
128
|
+
const params = {
|
|
129
|
+
Records: [
|
|
130
|
+
{ body: JSON.stringify({ task: 'test-1' }) },
|
|
131
|
+
{ body: JSON.stringify({ task: 'test-2' }) },
|
|
132
|
+
],
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
await worker.run(params);
|
|
136
|
+
|
|
137
|
+
expect(worker._run).toHaveBeenCalledTimes(2);
|
|
138
|
+
expect(worker._run).toHaveBeenCalledWith({ task: 'test-1' }, {});
|
|
139
|
+
expect(worker._run).toHaveBeenCalledWith({ task: 'test-2' }, {});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should pass context to _run method', async () => {
|
|
143
|
+
worker._validateParams = jest.fn();
|
|
144
|
+
worker._run = jest.fn().mockResolvedValue(undefined);
|
|
145
|
+
|
|
146
|
+
const params = {
|
|
147
|
+
Records: [
|
|
148
|
+
{ body: JSON.stringify({ task: 'test' }) },
|
|
149
|
+
],
|
|
150
|
+
};
|
|
151
|
+
const context = { userId: '123' };
|
|
152
|
+
|
|
153
|
+
await worker.run(params, context);
|
|
154
|
+
|
|
155
|
+
expect(worker._run).toHaveBeenCalledWith({ task: 'test' }, context);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
});
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for LambdaInvoker
|
|
3
|
+
* Infrastructure layer - AWS Lambda invocation adapter
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { LambdaInvoker, LambdaInvocationError } from './lambda-invoker';
|
|
7
|
+
|
|
8
|
+
describe('LambdaInvoker', () => {
|
|
9
|
+
let invoker: LambdaInvoker;
|
|
10
|
+
let mockLambdaClient: { send: jest.Mock };
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
mockLambdaClient = {
|
|
14
|
+
send: jest.fn(),
|
|
15
|
+
};
|
|
16
|
+
invoker = new LambdaInvoker(mockLambdaClient as any);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe('invoke()', () => {
|
|
20
|
+
it('should invoke Lambda and return parsed result on success', async () => {
|
|
21
|
+
mockLambdaClient.send.mockResolvedValue({
|
|
22
|
+
Payload: Buffer.from(JSON.stringify({
|
|
23
|
+
statusCode: 200,
|
|
24
|
+
body: { upToDate: true, pendingMigrations: 0 },
|
|
25
|
+
})),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const result = await invoker.invoke('test-function', { action: 'checkStatus' });
|
|
29
|
+
|
|
30
|
+
expect(result).toEqual({ upToDate: true, pendingMigrations: 0 });
|
|
31
|
+
expect(mockLambdaClient.send).toHaveBeenCalledWith(
|
|
32
|
+
expect.objectContaining({
|
|
33
|
+
input: expect.objectContaining({
|
|
34
|
+
FunctionName: 'test-function',
|
|
35
|
+
InvocationType: 'RequestResponse',
|
|
36
|
+
Payload: JSON.stringify({ action: 'checkStatus' }),
|
|
37
|
+
}),
|
|
38
|
+
})
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should throw LambdaInvocationError on Lambda error status', async () => {
|
|
43
|
+
mockLambdaClient.send.mockResolvedValue({
|
|
44
|
+
Payload: Buffer.from(JSON.stringify({
|
|
45
|
+
statusCode: 500,
|
|
46
|
+
body: { error: 'Database connection failed' },
|
|
47
|
+
})),
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
await expect(invoker.invoke('test-function', {}))
|
|
51
|
+
.rejects
|
|
52
|
+
.toThrow(LambdaInvocationError);
|
|
53
|
+
|
|
54
|
+
await expect(invoker.invoke('test-function', {}))
|
|
55
|
+
.rejects
|
|
56
|
+
.toThrow(/test-function/);
|
|
57
|
+
|
|
58
|
+
await expect(invoker.invoke('test-function', {}))
|
|
59
|
+
.rejects
|
|
60
|
+
.toThrow(/Database connection failed/);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should throw LambdaInvocationError on malformed response', async () => {
|
|
64
|
+
mockLambdaClient.send.mockResolvedValue({
|
|
65
|
+
Payload: Buffer.from('not json'),
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
await expect(invoker.invoke('test-function', {}))
|
|
69
|
+
.rejects
|
|
70
|
+
.toThrow(LambdaInvocationError);
|
|
71
|
+
|
|
72
|
+
await expect(invoker.invoke('test-function', {}))
|
|
73
|
+
.rejects
|
|
74
|
+
.toThrow(/Failed to parse/);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should handle AWS SDK errors', async () => {
|
|
78
|
+
mockLambdaClient.send.mockRejectedValue(new Error('AccessDenied: User not authorized'));
|
|
79
|
+
|
|
80
|
+
await expect(invoker.invoke('test-function', {}))
|
|
81
|
+
.rejects
|
|
82
|
+
.toThrow('Failed to invoke Lambda test-function: AccessDenied: User not authorized');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should include function name in LambdaInvocationError', async () => {
|
|
86
|
+
mockLambdaClient.send.mockResolvedValue({
|
|
87
|
+
Payload: Buffer.from(JSON.stringify({
|
|
88
|
+
statusCode: 500,
|
|
89
|
+
body: { error: 'Test error' },
|
|
90
|
+
})),
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
await invoker.invoke('my-function-name', {});
|
|
95
|
+
fail('Should have thrown');
|
|
96
|
+
} catch (error: any) {
|
|
97
|
+
expect(error).toBeInstanceOf(LambdaInvocationError);
|
|
98
|
+
expect(error.functionName).toBe('my-function-name');
|
|
99
|
+
expect(error.statusCode).toBe(500);
|
|
100
|
+
expect(error.message).toContain('my-function-name');
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
});
|