@reventlessdev/reventless-local 3.0.0-alpha.113
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/CHANGELOG.md +1197 -0
- package/LICENSE +202 -0
- package/__mocks__/emptyModule.js +2 -0
- package/__mocks__/nodeSqlite.mjs +6 -0
- package/package.json +67 -0
- package/rescript.json +39 -0
- package/src/Platform.res +2162 -0
- package/src/Platform.res.mjs +3389 -0
- package/src/adapter/Api/LocalGraphQL_Adapter.res +29 -0
- package/src/adapter/Api/LocalGraphQL_Adapter.res.mjs +26 -0
- package/src/adapter/Api/LocalGraphQL_SubscriptionResolvers.res +146 -0
- package/src/adapter/Api/LocalGraphQL_SubscriptionResolvers.res.mjs +88 -0
- package/src/adapter/Auth/Auth_GraphqlContext.res +83 -0
- package/src/adapter/Auth/Auth_GraphqlContext.res.mjs +76 -0
- package/src/adapter/Auth/LocalAuth.res +239 -0
- package/src/adapter/Auth/LocalAuth.res.mjs +247 -0
- package/src/adapter/Auth/UserStore.res +134 -0
- package/src/adapter/Auth/UserStore.res.mjs +146 -0
- package/src/adapter/Backend.res +46 -0
- package/src/adapter/Backend.res.mjs +66 -0
- package/src/adapter/BackendState.res +34 -0
- package/src/adapter/BackendState.res.mjs +42 -0
- package/src/adapter/Cloner/LocalClonerRunner.res +13 -0
- package/src/adapter/Cloner/LocalClonerRunner.res.mjs +12 -0
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers_GraphQL.res +329 -0
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers_GraphQL.res.mjs +301 -0
- package/src/adapter/CommandGenerator/InboundTranslationResolvers_GraphQL.res +76 -0
- package/src/adapter/CommandGenerator/InboundTranslationResolvers_GraphQL.res.mjs +57 -0
- package/src/adapter/CommandGenerator/LocalCommandGeneratorResolvers.res +19 -0
- package/src/adapter/CommandGenerator/LocalCommandGeneratorResolvers.res.mjs +19 -0
- package/src/adapter/CommandTopic/LocalCommandTopicChannel.res +104 -0
- package/src/adapter/CommandTopic/LocalCommandTopicChannel.res.mjs +82 -0
- package/src/adapter/CommandTopic/LocalCommandTopicRemoteChannel.res +32 -0
- package/src/adapter/CommandTopic/LocalCommandTopicRemoteChannel.res.mjs +38 -0
- package/src/adapter/Counter/LocalCounterHandler.res +42 -0
- package/src/adapter/Counter/LocalCounterHandler.res.mjs +45 -0
- package/src/adapter/DcbEventLog/DcbEventLogStorage_InMemory.res +131 -0
- package/src/adapter/DcbEventLog/DcbEventLogStorage_InMemory.res.mjs +140 -0
- package/src/adapter/DcbEventLog/DcbEventLogStorage_Sqlite.res +334 -0
- package/src/adapter/DcbEventLog/DcbEventLogStorage_Sqlite.res.mjs +299 -0
- package/src/adapter/DomainGraphQL_Server.res +565 -0
- package/src/adapter/DomainGraphQL_Server.res.mjs +576 -0
- package/src/adapter/DomainMCP_Server.res +369 -0
- package/src/adapter/DomainMCP_Server.res.mjs +358 -0
- package/src/adapter/EventCollector/LocalEventCollectorChannel.res +87 -0
- package/src/adapter/EventCollector/LocalEventCollectorChannel.res.mjs +45 -0
- package/src/adapter/EventLog/EventLogStorage_InMemory.res +105 -0
- package/src/adapter/EventLog/EventLogStorage_InMemory.res.mjs +117 -0
- package/src/adapter/EventLog/EventLogStorage_Sqlite.res +145 -0
- package/src/adapter/EventLog/EventLogStorage_Sqlite.res.mjs +155 -0
- package/src/adapter/EventTopic/LocalEventTopicPublisher.res +36 -0
- package/src/adapter/EventTopic/LocalEventTopicPublisher.res.mjs +31 -0
- package/src/adapter/GraphQL_Server.res +6 -0
- package/src/adapter/GraphQL_Server.res.mjs +154 -0
- package/src/adapter/GraphQL_ServerInstance.res +310 -0
- package/src/adapter/GraphQL_ServerInstance.res.mjs +257 -0
- package/src/adapter/Heartbeat/LocalHeartbeatRunner.res +57 -0
- package/src/adapter/Heartbeat/LocalHeartbeatRunner.res.mjs +34 -0
- package/src/adapter/LocalBus.res +498 -0
- package/src/adapter/LocalBus.res.mjs +1011 -0
- package/src/adapter/LocalPluginSpec.res +16 -0
- package/src/adapter/LocalPluginSpec.res.mjs +33 -0
- package/src/adapter/LocalSideEffectHandler.res +44 -0
- package/src/adapter/LocalSideEffectHandler.res.mjs +34 -0
- package/src/adapter/MCP_Server.res +4 -0
- package/src/adapter/MCP_Server.res.mjs +67 -0
- package/src/adapter/MCP_ServerInstance.res +362 -0
- package/src/adapter/MCP_ServerInstance.res.mjs +313 -0
- package/src/adapter/PlatformGraphQL_Server.res +75 -0
- package/src/adapter/PlatformGraphQL_Server.res.mjs +84 -0
- package/src/adapter/PlatformMCP_Server.res +23 -0
- package/src/adapter/PlatformMCP_Server.res.mjs +46 -0
- package/src/adapter/QueryDb/QueryDbResolvers_GraphQL.res +793 -0
- package/src/adapter/QueryDb/QueryDbResolvers_GraphQL.res.mjs +569 -0
- package/src/adapter/QueryDb/QueryDbStorage_InMemory.res +242 -0
- package/src/adapter/QueryDb/QueryDbStorage_InMemory.res.mjs +241 -0
- package/src/adapter/QueryDb/QueryDbStorage_Sqlite.res +339 -0
- package/src/adapter/QueryDb/QueryDbStorage_Sqlite.res.mjs +318 -0
- package/src/adapter/QueryDb/SortKey_Filter.res +48 -0
- package/src/adapter/QueryDb/SortKey_Filter.res.mjs +46 -0
- package/src/adapter/QueryEngine/LocalQueryEngine.res +57 -0
- package/src/adapter/QueryEngine/LocalQueryEngine.res.mjs +56 -0
- package/src/adapter/Runtime/LocalAggregateRuntime_Builder.res +91 -0
- package/src/adapter/Runtime/LocalAggregateRuntime_Builder.res.mjs +50 -0
- package/src/adapter/Runtime/LocalEventCollectorRuntime_Builder.res +47 -0
- package/src/adapter/Runtime/LocalEventCollectorRuntime_Builder.res.mjs +37 -0
- package/src/adapter/Runtime/LocalPluginRuntime_Builder.res +11 -0
- package/src/adapter/Runtime/LocalPluginRuntime_Builder.res.mjs +30 -0
- package/src/adapter/Runtime/LocalRuntimeEnvironment.res +54 -0
- package/src/adapter/Runtime/LocalRuntimeEnvironment.res.mjs +40 -0
- package/src/adapter/Scheduler/LocalScheduledPublisher.res +102 -0
- package/src/adapter/Scheduler/LocalScheduledPublisher.res.mjs +84 -0
- package/src/adapter/SqliteDriver.res +52 -0
- package/src/adapter/SqliteDriver.res.mjs +76 -0
- package/src/adapter/SqliteDriver.resi +31 -0
- package/src/adapter/Task/LocalTaskBucket.res +75 -0
- package/src/adapter/Task/LocalTaskBucket.res.mjs +48 -0
- package/src/adapter/Task/TaskBucket_Sqlite.res +47 -0
- package/src/adapter/Task/TaskBucket_Sqlite.res.mjs +40 -0
- package/src/components/Aggregate_Builder.res +55 -0
- package/src/components/Aggregate_Builder.res.mjs +140 -0
- package/src/components/AutomationSlice_Builder.res +41 -0
- package/src/components/AutomationSlice_Builder.res.mjs +57 -0
- package/src/components/Counter_Builder.res +14 -0
- package/src/components/Counter_Builder.res.mjs +32 -0
- package/src/components/DcbEventLog_Builder.res +18 -0
- package/src/components/DcbEventLog_Builder.res.mjs +24 -0
- package/src/components/ExtensionPoint_Builder.res +25 -0
- package/src/components/ExtensionPoint_Builder.res.mjs +44 -0
- package/src/components/InboundTranslationSlice_Builder.res +34 -0
- package/src/components/InboundTranslationSlice_Builder.res.mjs +45 -0
- package/src/components/OutboundTranslationSlice_Builder.res +43 -0
- package/src/components/OutboundTranslationSlice_Builder.res.mjs +59 -0
- package/src/components/Plugin_Builder.res +37 -0
- package/src/components/Plugin_Builder.res.mjs +67 -0
- package/src/components/ReadModel_Builder.res +47 -0
- package/src/components/ReadModel_Builder.res.mjs +54 -0
- package/src/components/StateChangeSlice_Builder.res +19 -0
- package/src/components/StateChangeSlice_Builder.res.mjs +21 -0
- package/src/components/StateViewSlice_Builder.res +42 -0
- package/src/components/StateViewSlice_Builder.res.mjs +58 -0
- package/src/components/Task_Builder.res +28 -0
- package/src/components/Task_Builder.res.mjs +41 -0
- package/src/reexport/CommandTopic.res +3 -0
- package/src/reexport/CommandTopic.res.mjs +55 -0
- package/src/test/Mocks/MockDcbEventLogStorage.res +136 -0
- package/src/test/Mocks/MockDcbEventLogStorage.res.mjs +146 -0
- package/src/test/Mocks/MockEventLogStorage.res +57 -0
- package/src/test/Mocks/MockEventLogStorage.res.mjs +65 -0
- package/src/test/Mocks/MockPublisher.res +29 -0
- package/src/test/Mocks/MockPublisher.res.mjs +28 -0
- package/src/test/Mocks/MockQueryDbStorage.res +104 -0
- package/src/test/Mocks/MockQueryDbStorage.res.mjs +136 -0
- package/src/test/TestRunner.res +96 -0
- package/src/test/TestRunner.res.mjs +71 -0
- package/tests/SplitApiFixtures.res +84 -0
- package/tests/SplitApiFixtures.res.mjs +88 -0
- package/tests/SplitApiTest.res +102 -0
- package/tests/SplitApiTest.res.mjs +82 -0
- package/tests/TestFixtures.res +54 -0
- package/tests/TestFixtures.res.mjs +65 -0
- package/tests/adapter/BackendParityTest.res +94 -0
- package/tests/adapter/BackendParityTest.res.mjs +96 -0
- package/tests/adapter/CollectNEventsTest.res +82 -0
- package/tests/adapter/CollectNEventsTest.res.mjs +83 -0
- package/tests/adapter/CommandAuthorizationTest.res +200 -0
- package/tests/adapter/CommandAuthorizationTest.res.mjs +190 -0
- package/tests/adapter/CommandTopicChannelTest.res +174 -0
- package/tests/adapter/CommandTopicChannelTest.res.mjs +170 -0
- package/tests/adapter/CounterHandlerTest.res +113 -0
- package/tests/adapter/CounterHandlerTest.res.mjs +96 -0
- package/tests/adapter/DcbEventLogStorageSqliteTest.res +157 -0
- package/tests/adapter/DcbEventLogStorageSqliteTest.res.mjs +165 -0
- package/tests/adapter/DcbEventLogStorageTest.res +187 -0
- package/tests/adapter/DcbEventLogStorageTest.res.mjs +195 -0
- package/tests/adapter/EventCollectorChannelTest.res +166 -0
- package/tests/adapter/EventCollectorChannelTest.res.mjs +178 -0
- package/tests/adapter/EventLogStorageSqliteTest.res +105 -0
- package/tests/adapter/EventLogStorageSqliteTest.res.mjs +116 -0
- package/tests/adapter/EventTapTest.res +102 -0
- package/tests/adapter/EventTapTest.res.mjs +94 -0
- package/tests/adapter/EventTopicPublisherTest.res +76 -0
- package/tests/adapter/EventTopicPublisherTest.res.mjs +86 -0
- package/tests/adapter/GraphQL_SchemaInspectorTest.res +763 -0
- package/tests/adapter/GraphQL_SchemaInspectorTest.res.mjs +578 -0
- package/tests/adapter/GraphQL_SubscriptionResolversTest.res +161 -0
- package/tests/adapter/GraphQL_SubscriptionResolversTest.res.mjs +134 -0
- package/tests/adapter/HeartbeatRunnerTest.res +136 -0
- package/tests/adapter/HeartbeatRunnerTest.res.mjs +96 -0
- package/tests/adapter/LocalAuthHttpTest.res +224 -0
- package/tests/adapter/LocalAuthHttpTest.res.mjs +237 -0
- package/tests/adapter/LocalAuthLoginTest.res +180 -0
- package/tests/adapter/LocalAuthLoginTest.res.mjs +207 -0
- package/tests/adapter/LocalAuthTest.res +106 -0
- package/tests/adapter/LocalAuthTest.res.mjs +145 -0
- package/tests/adapter/LocalAuthUserStoreTest.res +172 -0
- package/tests/adapter/LocalAuthUserStoreTest.res.mjs +208 -0
- package/tests/adapter/LocalBusBoundedTest.res +157 -0
- package/tests/adapter/LocalBusBoundedTest.res.mjs +168 -0
- package/tests/adapter/LocalBusPubSubTest.res +81 -0
- package/tests/adapter/LocalBusPubSubTest.res.mjs +81 -0
- package/tests/adapter/QueryDbGsiTtlTest.res +268 -0
- package/tests/adapter/QueryDbGsiTtlTest.res.mjs +209 -0
- package/tests/adapter/QueryDbListResolverTest.res +361 -0
- package/tests/adapter/QueryDbListResolverTest.res.mjs +426 -0
- package/tests/adapter/QueryDbStorageSqliteTest.res +159 -0
- package/tests/adapter/QueryDbStorageSqliteTest.res.mjs +126 -0
- package/tests/adapter/QueryDbStorageTest.res +171 -0
- package/tests/adapter/QueryDbStorageTest.res.mjs +170 -0
- package/tests/adapter/QueryEngineTest.res +152 -0
- package/tests/adapter/QueryEngineTest.res.mjs +148 -0
- package/tests/adapter/ScheduledPublisherTest.res +199 -0
- package/tests/adapter/ScheduledPublisherTest.res.mjs +203 -0
- package/tests/adapter/SortKey_FilterTest.res +103 -0
- package/tests/adapter/SortKey_FilterTest.res.mjs +135 -0
- package/tests/adapter/SqliteDriverTest.res +86 -0
- package/tests/adapter/SqliteDriverTest.res.mjs +101 -0
- package/tests/adapter/TaskBucketSqliteTest.res +44 -0
- package/tests/adapter/TaskBucketSqliteTest.res.mjs +40 -0
- package/tests/adapter/TaskBucketTest.res +106 -0
- package/tests/adapter/TaskBucketTest.res.mjs +118 -0
- package/tests/components/aggregate/AggregateFixtures.res +78 -0
- package/tests/components/aggregate/AggregateFixtures.res.mjs +109 -0
- package/tests/components/aggregate/AggregateTest.res +129 -0
- package/tests/components/aggregate/AggregateTest.res.mjs +129 -0
- package/tests/components/automationslice/AutomationSliceCallbackTest.res +212 -0
- package/tests/components/automationslice/AutomationSliceCallbackTest.res.mjs +233 -0
- package/tests/components/automationslice/AutomationSliceFixtures.res +189 -0
- package/tests/components/automationslice/AutomationSliceFixtures.res.mjs +276 -0
- package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res +289 -0
- package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res.mjs +453 -0
- package/tests/components/automationslice/AutomationSliceSelfDeadlockTest.res +47 -0
- package/tests/components/automationslice/AutomationSliceSelfDeadlockTest.res.mjs +31 -0
- package/tests/components/automationslice/MixedSourceAutomationSliceFixtures.res +213 -0
- package/tests/components/automationslice/MixedSourceAutomationSliceFixtures.res.mjs +268 -0
- package/tests/components/automationslice/MixedSourceAutomationSliceTest.res +118 -0
- package/tests/components/automationslice/MixedSourceAutomationSliceTest.res.mjs +99 -0
- package/tests/components/commandgenerator/CommandGeneratorFixtures.res +73 -0
- package/tests/components/commandgenerator/CommandGeneratorFixtures.res.mjs +109 -0
- package/tests/components/commandgenerator/CommandGeneratorTest.res +43 -0
- package/tests/components/commandgenerator/CommandGeneratorTest.res.mjs +46 -0
- package/tests/components/commandtopic/CommandTopicFixtures.res +37 -0
- package/tests/components/commandtopic/CommandTopicFixtures.res.mjs +68 -0
- package/tests/components/commandtopic/CommandTopicStreamFixtures.res +43 -0
- package/tests/components/commandtopic/CommandTopicStreamFixtures.res.mjs +91 -0
- package/tests/components/commandtopic/CommandTopicStreamTest.res +30 -0
- package/tests/components/commandtopic/CommandTopicStreamTest.res.mjs +35 -0
- package/tests/components/commandtopic/CommandTopicTest.res +55 -0
- package/tests/components/commandtopic/CommandTopicTest.res.mjs +62 -0
- package/tests/components/counter/CounterFixtures.res +42 -0
- package/tests/components/counter/CounterFixtures.res.mjs +34 -0
- package/tests/components/counter/CounterTest.res +46 -0
- package/tests/components/counter/CounterTest.res.mjs +61 -0
- package/tests/components/dcb/DcbCrossPartitionFixtures.res +170 -0
- package/tests/components/dcb/DcbCrossPartitionFixtures.res.mjs +276 -0
- package/tests/components/dcb/DcbCrossPartitionReadTest.res +68 -0
- package/tests/components/dcb/DcbCrossPartitionReadTest.res.mjs +78 -0
- package/tests/components/dcb/DcbEventLogAppendStreamTest.res +72 -0
- package/tests/components/dcb/DcbEventLogAppendStreamTest.res.mjs +82 -0
- package/tests/components/dcb/DcbEventLogStreamTest.res +103 -0
- package/tests/components/dcb/DcbEventLogStreamTest.res.mjs +91 -0
- package/tests/components/dcb/DcbFixtures.res +145 -0
- package/tests/components/dcb/DcbFixtures.res.mjs +221 -0
- package/tests/components/dcb/DcbTest.res +55 -0
- package/tests/components/dcb/DcbTest.res.mjs +55 -0
- package/tests/components/eventcollector/EventCollectorFixtures.res +42 -0
- package/tests/components/eventcollector/EventCollectorFixtures.res.mjs +49 -0
- package/tests/components/eventcollector/EventCollectorTest.res +37 -0
- package/tests/components/eventcollector/EventCollectorTest.res.mjs +36 -0
- package/tests/components/eventlog/EventLogAppendStreamTest.res +93 -0
- package/tests/components/eventlog/EventLogAppendStreamTest.res.mjs +113 -0
- package/tests/components/eventlog/EventLogConflictTest.res +86 -0
- package/tests/components/eventlog/EventLogConflictTest.res.mjs +81 -0
- package/tests/components/eventlog/EventLogFixtures.res +52 -0
- package/tests/components/eventlog/EventLogFixtures.res.mjs +80 -0
- package/tests/components/eventlog/EventLogStreamTest.res +98 -0
- package/tests/components/eventlog/EventLogStreamTest.res.mjs +142 -0
- package/tests/components/eventlog/EventLogTest.res +53 -0
- package/tests/components/eventlog/EventLogTest.res.mjs +74 -0
- package/tests/components/eventtopic/EventTopicFixtures.res +47 -0
- package/tests/components/eventtopic/EventTopicFixtures.res.mjs +77 -0
- package/tests/components/eventtopic/EventTopicStreamFixtures.res +27 -0
- package/tests/components/eventtopic/EventTopicStreamFixtures.res.mjs +62 -0
- package/tests/components/eventtopic/EventTopicStreamTest.res +35 -0
- package/tests/components/eventtopic/EventTopicStreamTest.res.mjs +44 -0
- package/tests/components/eventtopic/EventTopicTest.res +35 -0
- package/tests/components/eventtopic/EventTopicTest.res.mjs +43 -0
- package/tests/components/extensionpoint/ExtensionPointFixtures.res +145 -0
- package/tests/components/extensionpoint/ExtensionPointFixtures.res.mjs +188 -0
- package/tests/components/extensionpoint/ExtensionPointTest.res +62 -0
- package/tests/components/extensionpoint/ExtensionPointTest.res.mjs +55 -0
- package/tests/components/heartbeat/HeartbeatFixtures.res +48 -0
- package/tests/components/heartbeat/HeartbeatFixtures.res.mjs +46 -0
- package/tests/components/heartbeat/HeartbeatTest.res +67 -0
- package/tests/components/heartbeat/HeartbeatTest.res.mjs +65 -0
- package/tests/components/inboundtranslationslice/InboundTranslationSliceCallbackTest.res +241 -0
- package/tests/components/inboundtranslationslice/InboundTranslationSliceCallbackTest.res.mjs +239 -0
- package/tests/components/inboundtranslationslice/InboundTranslationSliceFixtures.res +36 -0
- package/tests/components/inboundtranslationslice/InboundTranslationSliceFixtures.res.mjs +73 -0
- package/tests/components/outboundtranslationslice/OutboundTranslationSliceCallbackTest.res +191 -0
- package/tests/components/outboundtranslationslice/OutboundTranslationSliceCallbackTest.res.mjs +297 -0
- package/tests/components/outboundtranslationslice/OutboundTranslationSliceFixtures.res +78 -0
- package/tests/components/outboundtranslationslice/OutboundTranslationSliceFixtures.res.mjs +137 -0
- package/tests/components/querydb/QueryDbFixtures.res +39 -0
- package/tests/components/querydb/QueryDbFixtures.res.mjs +73 -0
- package/tests/components/querydb/QueryDbSubIdFixtures.res +44 -0
- package/tests/components/querydb/QueryDbSubIdFixtures.res.mjs +80 -0
- package/tests/components/querydb/QueryDbSubIdTest.res +104 -0
- package/tests/components/querydb/QueryDbSubIdTest.res.mjs +104 -0
- package/tests/components/querydb/QueryDbTest.res +81 -0
- package/tests/components/querydb/QueryDbTest.res.mjs +126 -0
- package/tests/components/readmodel/DcbReadModelE2EFixtures.res +215 -0
- package/tests/components/readmodel/DcbReadModelE2EFixtures.res.mjs +308 -0
- package/tests/components/readmodel/DcbReadModelE2ETest.res +45 -0
- package/tests/components/readmodel/DcbReadModelE2ETest.res.mjs +37 -0
- package/tests/components/readmodel/DcbReadModelTypoFailFastTest.res +88 -0
- package/tests/components/readmodel/DcbReadModelTypoFailFastTest.res.mjs +152 -0
- package/tests/components/readmodel/MixedSourceReadModelFixtures.res +181 -0
- package/tests/components/readmodel/MixedSourceReadModelFixtures.res.mjs +277 -0
- package/tests/components/readmodel/MixedSourceReadModelTest.res +61 -0
- package/tests/components/readmodel/MixedSourceReadModelTest.res.mjs +68 -0
- package/tests/components/readmodel/ReadModelFixtures.res +138 -0
- package/tests/components/readmodel/ReadModelFixtures.res.mjs +169 -0
- package/tests/components/readmodel/ReadModelTest.res +46 -0
- package/tests/components/readmodel/ReadModelTest.res.mjs +36 -0
- package/tests/components/scheduler/SchedulerFixtures.res +59 -0
- package/tests/components/scheduler/SchedulerFixtures.res.mjs +63 -0
- package/tests/components/scheduler/SchedulerTest.res +76 -0
- package/tests/components/scheduler/SchedulerTest.res.mjs +86 -0
- package/tests/components/sideeffecthandler/SideEffectHandlerFixtures.res +133 -0
- package/tests/components/sideeffecthandler/SideEffectHandlerFixtures.res.mjs +149 -0
- package/tests/components/sideeffecthandler/SideEffectHandlerTest.res +39 -0
- package/tests/components/sideeffecthandler/SideEffectHandlerTest.res.mjs +28 -0
- package/tests/components/stateviewslice/StateViewSliceFixtures.res +117 -0
- package/tests/components/stateviewslice/StateViewSliceFixtures.res.mjs +188 -0
- package/tests/components/stateviewslice/StateViewSliceSubIdFixtures.res +117 -0
- package/tests/components/stateviewslice/StateViewSliceSubIdFixtures.res.mjs +183 -0
- package/tests/components/stateviewslice/StateViewSliceSubIdTest.res +78 -0
- package/tests/components/stateviewslice/StateViewSliceSubIdTest.res.mjs +107 -0
- package/tests/components/stateviewslice/StateViewSliceTest.res +59 -0
- package/tests/components/stateviewslice/StateViewSliceTest.res.mjs +72 -0
- package/tests/components/task/TaskFixtures.res +87 -0
- package/tests/components/task/TaskFixtures.res.mjs +82 -0
- package/tests/components/task/TaskTest.res +98 -0
- package/tests/components/task/TaskTest.res.mjs +46 -0
- package/tests/plugin/PluginBehavior_GWT.res +146 -0
- package/tests/plugin/PluginBehavior_GWT.res.mjs +281 -0
- package/tests/plugin/Plugin_Fixtures.res +61 -0
- package/tests/plugin/Plugin_Fixtures.res.mjs +105 -0
- package/tests/plugin/PluginsProjection_GWT.res +95 -0
- package/tests/plugin/PluginsProjection_GWT.res.mjs +120 -0
- package/tests/plugin/UIFragmentRegistryProjection_GWT.res +72 -0
- package/tests/plugin/UIFragmentRegistryProjection_GWT.res.mjs +117 -0
- package/tests/setup/sqliteGlobal.cjs +12 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// Unit tests for LocalEventCollectorChannel.
|
|
2
|
+
// Verifies resource collection in make() and subscriber wiring in connect().
|
|
3
|
+
|
|
4
|
+
open JestGlobals
|
|
5
|
+
|
|
6
|
+
let _ = TestRunner.setup()
|
|
7
|
+
|
|
8
|
+
let testMeta: Reventless.Message.meta = {
|
|
9
|
+
service: "test",
|
|
10
|
+
time: "",
|
|
11
|
+
ip: "",
|
|
12
|
+
user: "test",
|
|
13
|
+
msgId: "",
|
|
14
|
+
correlationId: "",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// ─────────────────────────────────────────────────────────────
|
|
18
|
+
// Helper: build a minimal runtime with a completed handler Deferred
|
|
19
|
+
// ─────────────────────────────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
let makeRuntime = (
|
|
22
|
+
handler: LocalRuntimeEnvironment.handler,
|
|
23
|
+
): ReventlessCore.Runtime.environment<LocalRuntimeEnvironment.parts> => {
|
|
24
|
+
let handlerDeferred: Deferred.t<LocalRuntimeEnvironment.handler, unit> =
|
|
25
|
+
Deferred.make()->Effect.runSync
|
|
26
|
+
Deferred.succeed(handlerDeferred, handler)->Effect.runSync->ignore
|
|
27
|
+
{
|
|
28
|
+
parts: {
|
|
29
|
+
handlerDeferred,
|
|
30
|
+
subscriptionLatch: Effect.makeLatch(false)->Effect.runSync,
|
|
31
|
+
},
|
|
32
|
+
resources: [],
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
describe("LocalEventCollectorChannel", () => {
|
|
37
|
+
describe("make", () => {
|
|
38
|
+
testPromise("collects all event topic resources as channel resources", async () => {
|
|
39
|
+
module TestBus = LocalBus.Make()
|
|
40
|
+
module TestPublisher = LocalEventTopicPublisher.Make(TestBus)
|
|
41
|
+
module TestCollector = LocalEventCollectorChannel.Make(TestBus)
|
|
42
|
+
let pubA = TestPublisher.make(~name="topicA", ~storageResources=[], ~opts={})
|
|
43
|
+
let pubB = TestPublisher.make(~name="topicB", ~storageResources=[], ~opts={})
|
|
44
|
+
let eventTopics = Dict.fromArray([
|
|
45
|
+
("topicA", {ReventlessInfra.EventTopic.resources: pubA.resources}),
|
|
46
|
+
("topicB", {ReventlessInfra.EventTopic.resources: pubB.resources}),
|
|
47
|
+
])
|
|
48
|
+
let ch = TestCollector.make(~name="collector", ~eventTopics, ~opts={})
|
|
49
|
+
// Each publisher returns 1 resource, so 2 total
|
|
50
|
+
expect(ch.resources->Array.length)->toBe(2)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
testPromise("empty eventTopics produces empty resources", async () => {
|
|
54
|
+
module TestBus = LocalBus.Make()
|
|
55
|
+
module TestCollector = LocalEventCollectorChannel.Make(TestBus)
|
|
56
|
+
let ch = TestCollector.make(~name="collector", ~eventTopics=Dict.make(), ~opts={})
|
|
57
|
+
expect(ch.resources->Array.length)->toBe(0)
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
describe("connect", () => {
|
|
62
|
+
testPromise("subscribes to event topic; published events reach the handler", async () => {
|
|
63
|
+
module TestBus = LocalBus.Make()
|
|
64
|
+
module TestPublisher = LocalEventTopicPublisher.Make(TestBus)
|
|
65
|
+
module TestCollector = LocalEventCollectorChannel.Make(TestBus)
|
|
66
|
+
let received: ref<int> = ref(0)
|
|
67
|
+
let runtime = makeRuntime(async (_, _ctx) => {
|
|
68
|
+
received := received.contents + 1
|
|
69
|
+
})
|
|
70
|
+
let pub = TestPublisher.make(~name="eventA", ~storageResources=[], ~opts={})
|
|
71
|
+
let eventTopics = Dict.fromArray([
|
|
72
|
+
("eventA", {ReventlessInfra.EventTopic.resources: pub.resources}),
|
|
73
|
+
])
|
|
74
|
+
let ch = TestCollector.make(~name="collector", ~eventTopics, ~opts={})
|
|
75
|
+
let channelSpec: ReventlessCore.EventCollector_Adapter.channelSpec<JSON.t, unit, unit> = {
|
|
76
|
+
channel: ch,
|
|
77
|
+
eventTopics,
|
|
78
|
+
resources: [],
|
|
79
|
+
}
|
|
80
|
+
let _ = TestCollector.connect(
|
|
81
|
+
~name="collector",
|
|
82
|
+
~channelSpecs=[channelSpec],
|
|
83
|
+
~runtime,
|
|
84
|
+
~opts={},
|
|
85
|
+
)
|
|
86
|
+
// Await the subscriptionLatch — opens after Output.apply fires and subscription registers
|
|
87
|
+
await runtime.parts.subscriptionLatch->Latch.await_->Effect.runPromise
|
|
88
|
+
let publishFn = await pub.publishJson->TestRunner.resolve
|
|
89
|
+
await publishFn("svc", testMeta, JSON.Null)
|
|
90
|
+
expect(received.contents)->toBe(1)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
testPromise("multiple event topics all deliver to the same handler", async () => {
|
|
94
|
+
module TestBus = LocalBus.Make()
|
|
95
|
+
module TestPublisher = LocalEventTopicPublisher.Make(TestBus)
|
|
96
|
+
module TestCollector = LocalEventCollectorChannel.Make(TestBus)
|
|
97
|
+
let received: ref<int> = ref(0)
|
|
98
|
+
let runtime = makeRuntime(async (_, _) => {
|
|
99
|
+
received := received.contents + 1
|
|
100
|
+
})
|
|
101
|
+
let pub1 = TestPublisher.make(~name="topicX", ~storageResources=[], ~opts={})
|
|
102
|
+
let pub2 = TestPublisher.make(~name="topicY", ~storageResources=[], ~opts={})
|
|
103
|
+
let eventTopics = Dict.fromArray([
|
|
104
|
+
("topicX", {ReventlessInfra.EventTopic.resources: pub1.resources}),
|
|
105
|
+
("topicY", {ReventlessInfra.EventTopic.resources: pub2.resources}),
|
|
106
|
+
])
|
|
107
|
+
let ch = TestCollector.make(~name="collector", ~eventTopics, ~opts={})
|
|
108
|
+
let channelSpec: ReventlessCore.EventCollector_Adapter.channelSpec<JSON.t, unit, unit> = {
|
|
109
|
+
channel: ch,
|
|
110
|
+
eventTopics,
|
|
111
|
+
resources: [],
|
|
112
|
+
}
|
|
113
|
+
let _ = TestCollector.connect(
|
|
114
|
+
~name="collector",
|
|
115
|
+
~channelSpecs=[channelSpec],
|
|
116
|
+
~runtime,
|
|
117
|
+
~opts={},
|
|
118
|
+
)
|
|
119
|
+
// Wait for both subscriptions via the publish functions (each Output resolves per-topic)
|
|
120
|
+
let pub1Fn = await pub1.publishJson->TestRunner.resolve
|
|
121
|
+
let pub2Fn = await pub2.publishJson->TestRunner.resolve
|
|
122
|
+
await pub1Fn("svc", testMeta, JSON.Null)
|
|
123
|
+
await pub2Fn("svc", testMeta, JSON.Null)
|
|
124
|
+
expect(received.contents)->toBe(2)
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
testPromise("unresolved Deferred does not crash on event delivery", async () => {
|
|
128
|
+
module TestBus = LocalBus.Make()
|
|
129
|
+
module TestPublisher = LocalEventTopicPublisher.Make(TestBus)
|
|
130
|
+
module TestCollector = LocalEventCollectorChannel.Make(TestBus)
|
|
131
|
+
// Deferred left incomplete — bus callback starts a pending Effect (no crash)
|
|
132
|
+
let handlerDeferred: Deferred.t<LocalRuntimeEnvironment.handler, unit> =
|
|
133
|
+
Deferred.make()->Effect.runSync
|
|
134
|
+
let runtime: ReventlessCore.Runtime.environment<LocalRuntimeEnvironment.parts> = {
|
|
135
|
+
parts: {
|
|
136
|
+
handlerDeferred,
|
|
137
|
+
subscriptionLatch: Effect.makeLatch(false)->Effect.runSync,
|
|
138
|
+
},
|
|
139
|
+
resources: [],
|
|
140
|
+
}
|
|
141
|
+
let pub = TestPublisher.make(~name="noHandlerTopic", ~storageResources=[], ~opts={})
|
|
142
|
+
let eventTopics = Dict.fromArray([
|
|
143
|
+
("noHandlerTopic", {ReventlessInfra.EventTopic.resources: pub.resources}),
|
|
144
|
+
])
|
|
145
|
+
let ch = TestCollector.make(~name="collector", ~eventTopics, ~opts={})
|
|
146
|
+
let channelSpec: ReventlessCore.EventCollector_Adapter.channelSpec<JSON.t, unit, unit> = {
|
|
147
|
+
channel: ch,
|
|
148
|
+
eventTopics,
|
|
149
|
+
resources: [],
|
|
150
|
+
}
|
|
151
|
+
let _ = TestCollector.connect(
|
|
152
|
+
~name="collector",
|
|
153
|
+
~channelSpecs=[channelSpec],
|
|
154
|
+
~runtime,
|
|
155
|
+
~opts={},
|
|
156
|
+
)
|
|
157
|
+
await runtime.parts.subscriptionLatch->Latch.await_->Effect.runPromise
|
|
158
|
+
let publishFn = await pub.publishJson->TestRunner.resolve
|
|
159
|
+
// Fire-and-forget — the Deferred.await_ will stay pending
|
|
160
|
+
publishFn("svc", testMeta, JSON.Null)->ignore
|
|
161
|
+
expect(true)->toBe(true)
|
|
162
|
+
// Complete the Deferred to avoid open handle
|
|
163
|
+
Deferred.succeed(handlerDeferred, async (_, _) => ())->Effect.runSync->ignore
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
})
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Deferred from "effect/Deferred";
|
|
5
|
+
import * as LocalBus$ReventlessLocal from "../../src/adapter/LocalBus.res.mjs";
|
|
6
|
+
import * as TestRunner$ReventlessLocal from "../../src/test/TestRunner.res.mjs";
|
|
7
|
+
import * as LocalEventTopicPublisher$ReventlessLocal from "../../src/adapter/EventTopic/LocalEventTopicPublisher.res.mjs";
|
|
8
|
+
import * as LocalEventCollectorChannel$ReventlessLocal from "../../src/adapter/EventCollector/LocalEventCollectorChannel.res.mjs";
|
|
9
|
+
|
|
10
|
+
TestRunner$ReventlessLocal.setup();
|
|
11
|
+
|
|
12
|
+
let testMeta = {
|
|
13
|
+
service: "test",
|
|
14
|
+
time: "",
|
|
15
|
+
ip: "",
|
|
16
|
+
user: "test",
|
|
17
|
+
msgId: "",
|
|
18
|
+
correlationId: ""
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function makeRuntime(handler) {
|
|
22
|
+
let handlerDeferred = Effect.runSync(Deferred.make());
|
|
23
|
+
Effect.runSync(Deferred.succeed(handlerDeferred, handler));
|
|
24
|
+
return {
|
|
25
|
+
parts: {
|
|
26
|
+
handlerDeferred: handlerDeferred,
|
|
27
|
+
subscriptionLatch: Effect.runSync(Effect.makeLatch(false))
|
|
28
|
+
},
|
|
29
|
+
resources: []
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
globalThis.describe("LocalEventCollectorChannel", () => {
|
|
34
|
+
globalThis.describe("make", () => {
|
|
35
|
+
globalThis.test("collects all event topic resources as channel resources", async () => {
|
|
36
|
+
let TestBus = LocalBus$ReventlessLocal.Make({});
|
|
37
|
+
let TestPublisher = LocalEventTopicPublisher$ReventlessLocal.Make(TestBus);
|
|
38
|
+
let TestCollector = LocalEventCollectorChannel$ReventlessLocal.Make(TestBus);
|
|
39
|
+
let pubA = TestPublisher.make("topicA", [], {});
|
|
40
|
+
let pubB = TestPublisher.make("topicB", [], {});
|
|
41
|
+
let eventTopics = Object.fromEntries([
|
|
42
|
+
[
|
|
43
|
+
"topicA",
|
|
44
|
+
{
|
|
45
|
+
resources: pubA.resources
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
[
|
|
49
|
+
"topicB",
|
|
50
|
+
{
|
|
51
|
+
resources: pubB.resources
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
]);
|
|
55
|
+
let ch = TestCollector.make("collector", eventTopics, {});
|
|
56
|
+
globalThis.expect(ch.resources.length).toBe(2);
|
|
57
|
+
});
|
|
58
|
+
globalThis.test("empty eventTopics produces empty resources", async () => {
|
|
59
|
+
let TestBus = LocalBus$ReventlessLocal.Make({});
|
|
60
|
+
let TestCollector = LocalEventCollectorChannel$ReventlessLocal.Make(TestBus);
|
|
61
|
+
let ch = TestCollector.make("collector", {}, {});
|
|
62
|
+
globalThis.expect(ch.resources.length).toBe(0);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
globalThis.describe("connect", () => {
|
|
66
|
+
globalThis.test("subscribes to event topic; published events reach the handler", async () => {
|
|
67
|
+
let TestBus = LocalBus$ReventlessLocal.Make({});
|
|
68
|
+
let TestPublisher = LocalEventTopicPublisher$ReventlessLocal.Make(TestBus);
|
|
69
|
+
let TestCollector = LocalEventCollectorChannel$ReventlessLocal.Make(TestBus);
|
|
70
|
+
let received = {
|
|
71
|
+
contents: 0
|
|
72
|
+
};
|
|
73
|
+
let runtime = makeRuntime(async (param, _ctx) => {
|
|
74
|
+
received.contents = received.contents + 1 | 0;
|
|
75
|
+
});
|
|
76
|
+
let pub = TestPublisher.make("eventA", [], {});
|
|
77
|
+
let eventTopics = Object.fromEntries([[
|
|
78
|
+
"eventA",
|
|
79
|
+
{
|
|
80
|
+
resources: pub.resources
|
|
81
|
+
}
|
|
82
|
+
]]);
|
|
83
|
+
let ch = TestCollector.make("collector", eventTopics, {});
|
|
84
|
+
let channelSpec_resources = [];
|
|
85
|
+
let channelSpec = {
|
|
86
|
+
channel: ch,
|
|
87
|
+
eventTopics: eventTopics,
|
|
88
|
+
resources: channelSpec_resources
|
|
89
|
+
};
|
|
90
|
+
TestCollector.connect("collector", [channelSpec], runtime, {});
|
|
91
|
+
await Effect.runPromise(runtime.parts.subscriptionLatch.await);
|
|
92
|
+
let publishFn = await TestRunner$ReventlessLocal.resolve(pub.publishJson);
|
|
93
|
+
await publishFn("svc", testMeta, null);
|
|
94
|
+
globalThis.expect(received.contents).toBe(1);
|
|
95
|
+
});
|
|
96
|
+
globalThis.test("multiple event topics all deliver to the same handler", async () => {
|
|
97
|
+
let TestBus = LocalBus$ReventlessLocal.Make({});
|
|
98
|
+
let TestPublisher = LocalEventTopicPublisher$ReventlessLocal.Make(TestBus);
|
|
99
|
+
let TestCollector = LocalEventCollectorChannel$ReventlessLocal.Make(TestBus);
|
|
100
|
+
let received = {
|
|
101
|
+
contents: 0
|
|
102
|
+
};
|
|
103
|
+
let runtime = makeRuntime(async (param, param$1) => {
|
|
104
|
+
received.contents = received.contents + 1 | 0;
|
|
105
|
+
});
|
|
106
|
+
let pub1 = TestPublisher.make("topicX", [], {});
|
|
107
|
+
let pub2 = TestPublisher.make("topicY", [], {});
|
|
108
|
+
let eventTopics = Object.fromEntries([
|
|
109
|
+
[
|
|
110
|
+
"topicX",
|
|
111
|
+
{
|
|
112
|
+
resources: pub1.resources
|
|
113
|
+
}
|
|
114
|
+
],
|
|
115
|
+
[
|
|
116
|
+
"topicY",
|
|
117
|
+
{
|
|
118
|
+
resources: pub2.resources
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
]);
|
|
122
|
+
let ch = TestCollector.make("collector", eventTopics, {});
|
|
123
|
+
let channelSpec_resources = [];
|
|
124
|
+
let channelSpec = {
|
|
125
|
+
channel: ch,
|
|
126
|
+
eventTopics: eventTopics,
|
|
127
|
+
resources: channelSpec_resources
|
|
128
|
+
};
|
|
129
|
+
TestCollector.connect("collector", [channelSpec], runtime, {});
|
|
130
|
+
let pub1Fn = await TestRunner$ReventlessLocal.resolve(pub1.publishJson);
|
|
131
|
+
let pub2Fn = await TestRunner$ReventlessLocal.resolve(pub2.publishJson);
|
|
132
|
+
await pub1Fn("svc", testMeta, null);
|
|
133
|
+
await pub2Fn("svc", testMeta, null);
|
|
134
|
+
globalThis.expect(received.contents).toBe(2);
|
|
135
|
+
});
|
|
136
|
+
globalThis.test("unresolved Deferred does not crash on event delivery", async () => {
|
|
137
|
+
let TestBus = LocalBus$ReventlessLocal.Make({});
|
|
138
|
+
let TestPublisher = LocalEventTopicPublisher$ReventlessLocal.Make(TestBus);
|
|
139
|
+
let TestCollector = LocalEventCollectorChannel$ReventlessLocal.Make(TestBus);
|
|
140
|
+
let handlerDeferred = Effect.runSync(Deferred.make());
|
|
141
|
+
let runtime_parts = {
|
|
142
|
+
handlerDeferred: handlerDeferred,
|
|
143
|
+
subscriptionLatch: Effect.runSync(Effect.makeLatch(false))
|
|
144
|
+
};
|
|
145
|
+
let runtime_resources = [];
|
|
146
|
+
let runtime = {
|
|
147
|
+
parts: runtime_parts,
|
|
148
|
+
resources: runtime_resources
|
|
149
|
+
};
|
|
150
|
+
let pub = TestPublisher.make("noHandlerTopic", [], {});
|
|
151
|
+
let eventTopics = Object.fromEntries([[
|
|
152
|
+
"noHandlerTopic",
|
|
153
|
+
{
|
|
154
|
+
resources: pub.resources
|
|
155
|
+
}
|
|
156
|
+
]]);
|
|
157
|
+
let ch = TestCollector.make("collector", eventTopics, {});
|
|
158
|
+
let channelSpec_resources = [];
|
|
159
|
+
let channelSpec = {
|
|
160
|
+
channel: ch,
|
|
161
|
+
eventTopics: eventTopics,
|
|
162
|
+
resources: channelSpec_resources
|
|
163
|
+
};
|
|
164
|
+
TestCollector.connect("collector", [channelSpec], runtime, {});
|
|
165
|
+
await Effect.runPromise(runtime_parts.subscriptionLatch.await);
|
|
166
|
+
let publishFn = await TestRunner$ReventlessLocal.resolve(pub.publishJson);
|
|
167
|
+
publishFn("svc", testMeta, null);
|
|
168
|
+
globalThis.expect(true).toBe(true);
|
|
169
|
+
Effect.runSync(Deferred.succeed(handlerDeferred, async (param, param$1) => {}));
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
export {
|
|
175
|
+
testMeta,
|
|
176
|
+
makeRuntime,
|
|
177
|
+
}
|
|
178
|
+
/* Not a pure module */
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Round-trip test for EventLogStorage_Sqlite.
|
|
2
|
+
// Mirrors the shape of the Memory variant but uses an in-memory SQLite database.
|
|
3
|
+
|
|
4
|
+
open JestGlobals
|
|
5
|
+
|
|
6
|
+
let _ = TestRunner.setup()
|
|
7
|
+
let opts: Pulumi.CustomResourceOptions.t = {}
|
|
8
|
+
|
|
9
|
+
let makeFreshDb = () => SqliteDriver.openDb(~path=":memory:")
|
|
10
|
+
|
|
11
|
+
describe("EventLogStorage_Sqlite", () => {
|
|
12
|
+
testPromise("append + replay round-trips events in order", async () => {
|
|
13
|
+
module TestBus = LocalBus.Make()
|
|
14
|
+
module DbProvider = {
|
|
15
|
+
let db = makeFreshDb()
|
|
16
|
+
}
|
|
17
|
+
module Storage = EventLogStorage_Sqlite.Make(TestBus, DbProvider)
|
|
18
|
+
|
|
19
|
+
let s = Storage.make(~name="agg", ~opts)
|
|
20
|
+
let ops = await s.operations->TestRunner.resolve
|
|
21
|
+
|
|
22
|
+
let event1 = JSON.Encode.object(
|
|
23
|
+
Dict.fromArray([("tag", JSON.Encode.string("Created"))]),
|
|
24
|
+
)
|
|
25
|
+
let event2 = JSON.Encode.object(
|
|
26
|
+
Dict.fromArray([("tag", JSON.Encode.string("Renamed"))]),
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
let r1 = await ops.append(0, "id-1", [event1])
|
|
30
|
+
expect(r1)->toEqual(Ok())
|
|
31
|
+
|
|
32
|
+
let r2 = await ops.append(1, "id-1", [event2])
|
|
33
|
+
expect(r2)->toEqual(Ok())
|
|
34
|
+
|
|
35
|
+
let replayed = await ops.replay("id-1")
|
|
36
|
+
expect(replayed->Array.length)->toBe(2)
|
|
37
|
+
expect(replayed->Array.getUnsafe(0))->toEqual(event1)
|
|
38
|
+
expect(replayed->Array.getUnsafe(1))->toEqual(event2)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
testPromise("append detects concurrency conflicts via PK collision", async () => {
|
|
42
|
+
module TestBus = LocalBus.Make()
|
|
43
|
+
module DbProvider = {
|
|
44
|
+
let db = makeFreshDb()
|
|
45
|
+
}
|
|
46
|
+
module Storage = EventLogStorage_Sqlite.Make(TestBus, DbProvider)
|
|
47
|
+
|
|
48
|
+
let s = Storage.make(~name="agg", ~opts)
|
|
49
|
+
let ops = await s.operations->TestRunner.resolve
|
|
50
|
+
|
|
51
|
+
let e = JSON.Encode.object(Dict.fromArray([("t", JSON.Encode.string("X"))]))
|
|
52
|
+
let _ = await ops.append(0, "id-c", [e])
|
|
53
|
+
|
|
54
|
+
// Caller re-uses seqNr=0 — conflict.
|
|
55
|
+
let result = await ops.append(0, "id-c", [e])
|
|
56
|
+
switch result {
|
|
57
|
+
| Error(_) => expect(true)->toBe(true)
|
|
58
|
+
| Ok() => expect("expected conflict")->toBe("actual Ok")
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
testPromise("replay returns empty array for unknown id", async () => {
|
|
63
|
+
module TestBus = LocalBus.Make()
|
|
64
|
+
module DbProvider = {
|
|
65
|
+
let db = makeFreshDb()
|
|
66
|
+
}
|
|
67
|
+
module Storage = EventLogStorage_Sqlite.Make(TestBus, DbProvider)
|
|
68
|
+
|
|
69
|
+
let s = Storage.make(~name="agg", ~opts)
|
|
70
|
+
let ops = await s.operations->TestRunner.resolve
|
|
71
|
+
|
|
72
|
+
let replayed = await ops.replay("not-there")
|
|
73
|
+
expect(replayed->Array.length)->toBe(0)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
testPromise("events persist across a reopen of the database file", async () => {
|
|
77
|
+
let path = `/tmp/reventless-test-eventlog-${Float.toString(Date.now())}.db`
|
|
78
|
+
|
|
79
|
+
// Session 1: write
|
|
80
|
+
{
|
|
81
|
+
module TestBus = LocalBus.Make()
|
|
82
|
+
module DbProvider = {
|
|
83
|
+
let db = SqliteDriver.openDb(~path)
|
|
84
|
+
}
|
|
85
|
+
module Storage = EventLogStorage_Sqlite.Make(TestBus, DbProvider)
|
|
86
|
+
let s = Storage.make(~name="persist", ~opts)
|
|
87
|
+
let ops = await s.operations->TestRunner.resolve
|
|
88
|
+
let ev = JSON.Encode.object(Dict.fromArray([("v", JSON.Encode.int(42))]))
|
|
89
|
+
let _ = await ops.append(0, "id-p", [ev])
|
|
90
|
+
DbProvider.db->SqliteDriver.close
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Session 2: read back
|
|
94
|
+
module TestBus2 = LocalBus.Make()
|
|
95
|
+
module DbProvider2 = {
|
|
96
|
+
let db = SqliteDriver.openDb(~path)
|
|
97
|
+
}
|
|
98
|
+
module Storage2 = EventLogStorage_Sqlite.Make(TestBus2, DbProvider2)
|
|
99
|
+
let s2 = Storage2.make(~name="persist", ~opts)
|
|
100
|
+
let ops2 = await s2.operations->TestRunner.resolve
|
|
101
|
+
let replayed = await ops2.replay("id-p")
|
|
102
|
+
expect(replayed->Array.length)->toBe(1)
|
|
103
|
+
DbProvider2.db->SqliteDriver.close
|
|
104
|
+
})
|
|
105
|
+
})
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as LocalBus$ReventlessLocal from "../../src/adapter/LocalBus.res.mjs";
|
|
4
|
+
import * as TestRunner$ReventlessLocal from "../../src/test/TestRunner.res.mjs";
|
|
5
|
+
import * as SqliteDriver$ReventlessLocal from "../../src/adapter/SqliteDriver.res.mjs";
|
|
6
|
+
import * as EventLogStorage_Sqlite$ReventlessLocal from "../../src/adapter/EventLog/EventLogStorage_Sqlite.res.mjs";
|
|
7
|
+
|
|
8
|
+
TestRunner$ReventlessLocal.setup();
|
|
9
|
+
|
|
10
|
+
let opts = {};
|
|
11
|
+
|
|
12
|
+
function makeFreshDb() {
|
|
13
|
+
return SqliteDriver$ReventlessLocal.openDb(":memory:");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
globalThis.describe("EventLogStorage_Sqlite", () => {
|
|
17
|
+
globalThis.test("append + replay round-trips events in order", async () => {
|
|
18
|
+
let TestBus = LocalBus$ReventlessLocal.Make({});
|
|
19
|
+
let db = SqliteDriver$ReventlessLocal.openDb(":memory:");
|
|
20
|
+
let DbProvider = {
|
|
21
|
+
db: db
|
|
22
|
+
};
|
|
23
|
+
let Storage = EventLogStorage_Sqlite$ReventlessLocal.Make(TestBus)(DbProvider);
|
|
24
|
+
let s = Storage.make("agg", opts);
|
|
25
|
+
let ops = await TestRunner$ReventlessLocal.resolve(s.operations);
|
|
26
|
+
let event1 = Object.fromEntries([[
|
|
27
|
+
"tag",
|
|
28
|
+
"Created"
|
|
29
|
+
]]);
|
|
30
|
+
let event2 = Object.fromEntries([[
|
|
31
|
+
"tag",
|
|
32
|
+
"Renamed"
|
|
33
|
+
]]);
|
|
34
|
+
let r1 = await ops.append(0, "id-1", [event1]);
|
|
35
|
+
globalThis.expect(r1).toEqual({
|
|
36
|
+
TAG: "Ok",
|
|
37
|
+
_0: undefined
|
|
38
|
+
});
|
|
39
|
+
let r2 = await ops.append(1, "id-1", [event2]);
|
|
40
|
+
globalThis.expect(r2).toEqual({
|
|
41
|
+
TAG: "Ok",
|
|
42
|
+
_0: undefined
|
|
43
|
+
});
|
|
44
|
+
let replayed = await ops.replay("id-1");
|
|
45
|
+
globalThis.expect(replayed.length).toBe(2);
|
|
46
|
+
globalThis.expect(replayed[0]).toEqual(event1);
|
|
47
|
+
globalThis.expect(replayed[1]).toEqual(event2);
|
|
48
|
+
});
|
|
49
|
+
globalThis.test("append detects concurrency conflicts via PK collision", async () => {
|
|
50
|
+
let TestBus = LocalBus$ReventlessLocal.Make({});
|
|
51
|
+
let db = SqliteDriver$ReventlessLocal.openDb(":memory:");
|
|
52
|
+
let DbProvider = {
|
|
53
|
+
db: db
|
|
54
|
+
};
|
|
55
|
+
let Storage = EventLogStorage_Sqlite$ReventlessLocal.Make(TestBus)(DbProvider);
|
|
56
|
+
let s = Storage.make("agg", opts);
|
|
57
|
+
let ops = await TestRunner$ReventlessLocal.resolve(s.operations);
|
|
58
|
+
let e = Object.fromEntries([[
|
|
59
|
+
"t",
|
|
60
|
+
"X"
|
|
61
|
+
]]);
|
|
62
|
+
await ops.append(0, "id-c", [e]);
|
|
63
|
+
let result = await ops.append(0, "id-c", [e]);
|
|
64
|
+
if (result.TAG === "Ok") {
|
|
65
|
+
globalThis.expect("expected conflict").toBe("actual Ok");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
globalThis.expect(true).toBe(true);
|
|
69
|
+
});
|
|
70
|
+
globalThis.test("replay returns empty array for unknown id", async () => {
|
|
71
|
+
let TestBus = LocalBus$ReventlessLocal.Make({});
|
|
72
|
+
let db = SqliteDriver$ReventlessLocal.openDb(":memory:");
|
|
73
|
+
let DbProvider = {
|
|
74
|
+
db: db
|
|
75
|
+
};
|
|
76
|
+
let Storage = EventLogStorage_Sqlite$ReventlessLocal.Make(TestBus)(DbProvider);
|
|
77
|
+
let s = Storage.make("agg", opts);
|
|
78
|
+
let ops = await TestRunner$ReventlessLocal.resolve(s.operations);
|
|
79
|
+
let replayed = await ops.replay("not-there");
|
|
80
|
+
globalThis.expect(replayed.length).toBe(0);
|
|
81
|
+
});
|
|
82
|
+
globalThis.test("events persist across a reopen of the database file", async () => {
|
|
83
|
+
let path = `/tmp/reventless-test-eventlog-` + Date.now().toString() + `.db`;
|
|
84
|
+
let TestBus = LocalBus$ReventlessLocal.Make({});
|
|
85
|
+
let db = SqliteDriver$ReventlessLocal.openDb(path);
|
|
86
|
+
let DbProvider = {
|
|
87
|
+
db: db
|
|
88
|
+
};
|
|
89
|
+
let Storage = EventLogStorage_Sqlite$ReventlessLocal.Make(TestBus)(DbProvider);
|
|
90
|
+
let s = Storage.make("persist", opts);
|
|
91
|
+
let ops = await TestRunner$ReventlessLocal.resolve(s.operations);
|
|
92
|
+
let ev = Object.fromEntries([[
|
|
93
|
+
"v",
|
|
94
|
+
42
|
|
95
|
+
]]);
|
|
96
|
+
await ops.append(0, "id-p", [ev]);
|
|
97
|
+
SqliteDriver$ReventlessLocal.close(db);
|
|
98
|
+
let TestBus2 = LocalBus$ReventlessLocal.Make({});
|
|
99
|
+
let db$1 = SqliteDriver$ReventlessLocal.openDb(path);
|
|
100
|
+
let DbProvider2 = {
|
|
101
|
+
db: db$1
|
|
102
|
+
};
|
|
103
|
+
let Storage2 = EventLogStorage_Sqlite$ReventlessLocal.Make(TestBus2)(DbProvider2);
|
|
104
|
+
let s2 = Storage2.make("persist", opts);
|
|
105
|
+
let ops2 = await TestRunner$ReventlessLocal.resolve(s2.operations);
|
|
106
|
+
let replayed = await ops2.replay("id-p");
|
|
107
|
+
globalThis.expect(replayed.length).toBe(1);
|
|
108
|
+
return SqliteDriver$ReventlessLocal.close(db$1);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
export {
|
|
113
|
+
opts,
|
|
114
|
+
makeFreshDb,
|
|
115
|
+
}
|
|
116
|
+
/* Not a pure module */
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// Tests for the opt-in NDJSON domain-event tap (features plan Phase 9 — the VS
|
|
2
|
+
// Code local platform runner). The tap lives in LocalBus.publishEvent: when
|
|
3
|
+
// REVENTLESS_EVENT_TAP is set it emits one sentinel-prefixed JSON line per
|
|
4
|
+
// published event to stdout (console.log), with the event's real topic name and
|
|
5
|
+
// payload. Off by default so normal runs stay quiet.
|
|
6
|
+
|
|
7
|
+
open JestGlobals
|
|
8
|
+
|
|
9
|
+
let _ = TestRunner.setup()
|
|
10
|
+
|
|
11
|
+
let defaultMeta: Reventless.Message.meta = {
|
|
12
|
+
service: "test",
|
|
13
|
+
time: "",
|
|
14
|
+
ip: "",
|
|
15
|
+
user: "test",
|
|
16
|
+
msgId: "",
|
|
17
|
+
correlationId: "",
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@val external processEnv: Dict.t<string> = "process.env"
|
|
21
|
+
|
|
22
|
+
type consoleObj = {mutable log: string => unit}
|
|
23
|
+
@val external console: consoleObj = "console"
|
|
24
|
+
|
|
25
|
+
let sentinel = "@@RVLESS_EVT@@ "
|
|
26
|
+
|
|
27
|
+
// Run `fn` with console.log captured; returns every logged line, restoring the
|
|
28
|
+
// original console.log even if `fn` throws.
|
|
29
|
+
let captureLogs = async (fn: unit => promise<unit>): array<string> => {
|
|
30
|
+
let captured: array<string> = []
|
|
31
|
+
let original = console.log
|
|
32
|
+
console.log = s => captured->Array.push(s)
|
|
33
|
+
let result = try {
|
|
34
|
+
await fn()
|
|
35
|
+
Ok()
|
|
36
|
+
} catch {
|
|
37
|
+
| e => Error(e)
|
|
38
|
+
}
|
|
39
|
+
console.log = original
|
|
40
|
+
switch result {
|
|
41
|
+
| Ok() => captured
|
|
42
|
+
| Error(e) => throw(e)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let tapLines = (logs: array<string>): array<string> =>
|
|
47
|
+
logs->Array.filter(l => l->String.startsWith(sentinel))
|
|
48
|
+
|
|
49
|
+
describe("LocalBus event tap (Phase 9)", () => {
|
|
50
|
+
// Each test owns the env flag; always clear it afterwards so cases don't leak.
|
|
51
|
+
let clearEnv = () => processEnv->Dict.delete("REVENTLESS_EVENT_TAP")
|
|
52
|
+
|
|
53
|
+
testPromise("tap off → no sentinel line is emitted", async () => {
|
|
54
|
+
clearEnv()
|
|
55
|
+
module TestBus = LocalBus.MakeSilent()
|
|
56
|
+
let logs = await captureLogs(async () => {
|
|
57
|
+
await TestBus.publishEvent("SomeTopic", "svc", defaultMeta, JSON.parseOrThrow(`{"a":1}`))
|
|
58
|
+
})
|
|
59
|
+
expect(tapLines(logs)->Array.length)->toBe(0)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
testPromise("tap on → one well-formed line per published event", async () => {
|
|
63
|
+
processEnv->Dict.set("REVENTLESS_EVENT_TAP", "ndjson")
|
|
64
|
+
module TestBus = LocalBus.MakeSilent()
|
|
65
|
+
let logs = await captureLogs(async () => {
|
|
66
|
+
await TestBus.publishEvent(
|
|
67
|
+
"CatalogEventTopic",
|
|
68
|
+
"CatalogDcbEventLog",
|
|
69
|
+
defaultMeta,
|
|
70
|
+
JSON.parseOrThrow(`{"event":{"TAG":"ProductAdded","productId":"p-1"}}`),
|
|
71
|
+
)
|
|
72
|
+
await TestBus.publishEvent("OrderingEventTopic", "svc", defaultMeta, JSON.parseOrThrow(`{}`))
|
|
73
|
+
})
|
|
74
|
+
clearEnv()
|
|
75
|
+
let lines = tapLines(logs)
|
|
76
|
+
expect(lines->Array.length)->toBe(2)
|
|
77
|
+
|
|
78
|
+
// First line decodes to the expected envelope: event="domainEvent", the real
|
|
79
|
+
// topic name, and the payload passed to publishEvent (no topic-name guessing).
|
|
80
|
+
let first = lines->Array.getUnsafe(0)
|
|
81
|
+
let json =
|
|
82
|
+
first->String.slice(~start=sentinel->String.length, ~end=first->String.length)->JSON.parseOrThrow
|
|
83
|
+
let obj = json->JSON.Decode.object->Option.getOrThrow
|
|
84
|
+
expect(obj->Dict.get("event")->Option.flatMap(JSON.Decode.string))->toEqual(Some("domainEvent"))
|
|
85
|
+
expect(obj->Dict.get("topic")->Option.flatMap(JSON.Decode.string))->toEqual(
|
|
86
|
+
Some("CatalogEventTopic"),
|
|
87
|
+
)
|
|
88
|
+
expect(obj->Dict.get("seq")->Option.flatMap(JSON.Decode.float))->toEqual(Some(1.0))
|
|
89
|
+
expect(obj->Dict.get("payload")->Option.isSome)->toBe(true)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
testPromise("tap emits even when the topic has no subscribers", async () => {
|
|
93
|
+
processEnv->Dict.set("REVENTLESS_EVENT_TAP", "ndjson")
|
|
94
|
+
module TestBus = LocalBus.MakeSilent()
|
|
95
|
+
let logs = await captureLogs(async () => {
|
|
96
|
+
// No subscribeToEvents call — the tap fires before the subscriber-count gate.
|
|
97
|
+
await TestBus.publishEvent("Lonely", "svc", defaultMeta, JSON.Null)
|
|
98
|
+
})
|
|
99
|
+
clearEnv()
|
|
100
|
+
expect(tapLines(logs)->Array.length)->toBe(1)
|
|
101
|
+
})
|
|
102
|
+
})
|