@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,78 @@
|
|
|
1
|
+
// E2E test fixtures for the Aggregate E2E test.
|
|
2
|
+
// Contains specs, behavior, bus setup, and shared test data.
|
|
3
|
+
|
|
4
|
+
// ─────────────────────────────────────────────────────────────
|
|
5
|
+
// Simple Item aggregate spec
|
|
6
|
+
// ─────────────────────────────────────────────────────────────
|
|
7
|
+
|
|
8
|
+
module ItemSpec = {
|
|
9
|
+
module Id = Reventless.Id.String
|
|
10
|
+
let name = "TestItem"
|
|
11
|
+
|
|
12
|
+
@schema
|
|
13
|
+
type command = CreateItem({name: string})
|
|
14
|
+
|
|
15
|
+
@schema
|
|
16
|
+
type event = ItemCreated({name: string})
|
|
17
|
+
|
|
18
|
+
@schema
|
|
19
|
+
type error = AlreadyExists
|
|
20
|
+
|
|
21
|
+
let moduleUrl: string = %raw(`import.meta.url`)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ─────────────────────────────────────────────────────────────
|
|
25
|
+
// Item behavior: CreateItem → ItemCreated
|
|
26
|
+
// ─────────────────────────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
module ItemBehavior: ReventlessCore.Behavior.T with module Spec := ItemSpec = {
|
|
29
|
+
type state = bool // true = item exists
|
|
30
|
+
|
|
31
|
+
let initialState = false
|
|
32
|
+
|
|
33
|
+
let moduleUrl: string = %raw(`import.meta.url`)
|
|
34
|
+
|
|
35
|
+
let evolve = (_state, _event: ItemSpec.event) => true
|
|
36
|
+
|
|
37
|
+
let decide = (state, command: ItemSpec.command) =>
|
|
38
|
+
if state {
|
|
39
|
+
Error(ItemSpec.AlreadyExists)
|
|
40
|
+
} else {
|
|
41
|
+
switch command {
|
|
42
|
+
| ItemSpec.CreateItem({name}) => Ok([ItemSpec.ItemCreated({name: name})])
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ─────────────────────────────────────────────────────────────
|
|
48
|
+
// Isolated bus for the E2E test (shared across all tests here)
|
|
49
|
+
// ─────────────────────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
module Bus = LocalBus.Make()
|
|
52
|
+
|
|
53
|
+
// Capture events published to the aggregate's event topic.
|
|
54
|
+
// Topic name = Spec.name ++ "Aggr" ++ "EventTopic" = "TestItemAggrEventTopic"
|
|
55
|
+
let capturedEventCount: ref<int> = ref(0)
|
|
56
|
+
|
|
57
|
+
let _ = Bus.subscribeToEvents("TestItemAggrEventTopic", async (_, _, _) => {
|
|
58
|
+
capturedEventCount := capturedEventCount.contents + 1
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
// ─────────────────────────────────────────────────────────────
|
|
62
|
+
// Activate Pulumi mock mode (must be before any Component.make)
|
|
63
|
+
// ─────────────────────────────────────────────────────────────
|
|
64
|
+
|
|
65
|
+
let _ = TestRunner.setup()
|
|
66
|
+
|
|
67
|
+
// ─────────────────────────────────────────────────────────────
|
|
68
|
+
// Build the aggregate (creates Pulumi components + wires bus)
|
|
69
|
+
// ─────────────────────────────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
module ItemAggregateMaker = Aggregate_Builder.Make(Bus)
|
|
72
|
+
module ItemAgg = ItemAggregateMaker.Make(
|
|
73
|
+
ItemSpec,
|
|
74
|
+
ItemBehavior,
|
|
75
|
+
ReventlessInfra.NoEventMappings.Make(ItemSpec),
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
let agg = ItemAgg.make(~api=())
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as S from "sury/src/S.res.mjs";
|
|
4
|
+
import * as Id$Reventless from "@reventlessdev/reventless-spec/src/types/Id.res.mjs";
|
|
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 NoEventMappings$ReventlessInfra from "@reventlessdev/reventless-infra/src/types/NoEventMappings.res.mjs";
|
|
8
|
+
import * as Aggregate_Builder$ReventlessLocal from "../../../src/components/Aggregate_Builder.res.mjs";
|
|
9
|
+
|
|
10
|
+
let name = "TestItem";
|
|
11
|
+
|
|
12
|
+
let commandSchema = S.schema(s => ({
|
|
13
|
+
TAG: "CreateItem",
|
|
14
|
+
name: s.m(S.string)
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
let eventSchema = S.schema(s => ({
|
|
18
|
+
TAG: "ItemCreated",
|
|
19
|
+
name: s.m(S.string)
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
let errorSchema = S.literal("AlreadyExists");
|
|
23
|
+
|
|
24
|
+
let moduleUrl = import.meta.url;
|
|
25
|
+
|
|
26
|
+
function commandAuthorization(param) {
|
|
27
|
+
return "AllowAuthenticated";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let ItemSpec = {
|
|
31
|
+
Id: undefined,
|
|
32
|
+
name: name,
|
|
33
|
+
commandSchema: commandSchema,
|
|
34
|
+
eventSchema: eventSchema,
|
|
35
|
+
errorSchema: errorSchema,
|
|
36
|
+
moduleUrl: moduleUrl,
|
|
37
|
+
commandAuthorization: commandAuthorization
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
let moduleUrl$1 = import.meta.url;
|
|
41
|
+
|
|
42
|
+
function evolve(_state, _event) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function decide(state, command) {
|
|
47
|
+
if (state) {
|
|
48
|
+
return {
|
|
49
|
+
TAG: "Error",
|
|
50
|
+
_0: "AlreadyExists"
|
|
51
|
+
};
|
|
52
|
+
} else {
|
|
53
|
+
return {
|
|
54
|
+
TAG: "Ok",
|
|
55
|
+
_0: [{
|
|
56
|
+
TAG: "ItemCreated",
|
|
57
|
+
name: command.name
|
|
58
|
+
}]
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let ItemBehavior = {
|
|
64
|
+
initialState: false,
|
|
65
|
+
evolve: evolve,
|
|
66
|
+
decide: decide,
|
|
67
|
+
moduleUrl: moduleUrl$1
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
let Bus = LocalBus$ReventlessLocal.Make({});
|
|
71
|
+
|
|
72
|
+
let capturedEventCount = {
|
|
73
|
+
contents: 0
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
Bus.subscribeToEvents("TestItemAggrEventTopic", async (param, param$1, param$2) => {
|
|
77
|
+
capturedEventCount.contents = capturedEventCount.contents + 1 | 0;
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
TestRunner$ReventlessLocal.setup();
|
|
81
|
+
|
|
82
|
+
let ItemAggregateMaker = Aggregate_Builder$ReventlessLocal.Make(Bus);
|
|
83
|
+
|
|
84
|
+
let ItemAgg = ItemAggregateMaker.Make({
|
|
85
|
+
Id: Id$Reventless.$$String,
|
|
86
|
+
name: name,
|
|
87
|
+
eventSchema: eventSchema,
|
|
88
|
+
errorSchema: errorSchema,
|
|
89
|
+
commandSchema: commandSchema,
|
|
90
|
+
moduleUrl: moduleUrl,
|
|
91
|
+
commandAuthorization: commandAuthorization
|
|
92
|
+
})(ItemBehavior)(NoEventMappings$ReventlessInfra.Make({
|
|
93
|
+
name: name,
|
|
94
|
+
Id: Id$Reventless.$$String,
|
|
95
|
+
commandSchema: commandSchema
|
|
96
|
+
}));
|
|
97
|
+
|
|
98
|
+
let agg = ItemAgg.make(undefined, undefined);
|
|
99
|
+
|
|
100
|
+
export {
|
|
101
|
+
ItemSpec,
|
|
102
|
+
ItemBehavior,
|
|
103
|
+
Bus,
|
|
104
|
+
capturedEventCount,
|
|
105
|
+
ItemAggregateMaker,
|
|
106
|
+
ItemAgg,
|
|
107
|
+
agg,
|
|
108
|
+
}
|
|
109
|
+
/* commandSchema Not a pure module */
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// E2E test for reventless-local package.
|
|
2
|
+
// Verifies the full aggregate command → event flow using the in-memory bus.
|
|
3
|
+
|
|
4
|
+
open TestFixtures
|
|
5
|
+
open JestGlobals
|
|
6
|
+
open AggregateFixtures
|
|
7
|
+
|
|
8
|
+
describe("LocalBus", () => {
|
|
9
|
+
testPromise("publishes events to all subscribers", async () => {
|
|
10
|
+
module TestBus = LocalBus.Make()
|
|
11
|
+
let count: ref<int> = ref(0)
|
|
12
|
+
TestBus.subscribeToEvents("t1", async (_, _, _) => {
|
|
13
|
+
count := count.contents + 1
|
|
14
|
+
})
|
|
15
|
+
TestBus.subscribeToEvents("t1", async (_, _, _) => {
|
|
16
|
+
count := count.contents + 1
|
|
17
|
+
})
|
|
18
|
+
await TestBus.publishEvent("t1", "memory:InMemory", testMeta, JSON.Null)
|
|
19
|
+
expect(count.contents)->toBe(2)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
testPromise("dispatches commands to registered handler", async () => {
|
|
23
|
+
module TestBus = LocalBus.Make()
|
|
24
|
+
let received: ref<option<string>> = ref(None)
|
|
25
|
+
TestBus.registerCommandHandler("cmd1", async (json, _) => {
|
|
26
|
+
received := switch json {
|
|
27
|
+
| JSON.String(s) => Some(s)
|
|
28
|
+
| _ => None
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
await TestBus.dispatchCommand("cmd1", JSON.Encode.string("hello"))
|
|
32
|
+
expect(received.contents)->toEqual(Some("hello"))
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
testPromise("reset clears all handlers and subscribers", async () => {
|
|
36
|
+
module TestBus = LocalBus.Make()
|
|
37
|
+
let count: ref<int> = ref(0)
|
|
38
|
+
TestBus.subscribeToEvents("topic", async (_, _, _) => {
|
|
39
|
+
count := count.contents + 1
|
|
40
|
+
})
|
|
41
|
+
TestBus.reset()
|
|
42
|
+
// After reset, no subscribers — this just verifies no crash
|
|
43
|
+
expect(count.contents)->toBe(0)
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
describe("EventLogStorage_InMemory", () => {
|
|
48
|
+
testPromise("append stores events and replay returns them", async () => {
|
|
49
|
+
let opts: Pulumi.CustomResourceOptions.t = {}
|
|
50
|
+
let storage = EventLogStorage_InMemory.make(~name="test-log", ~opts)
|
|
51
|
+
let ops = await storage.operations->TestRunner.resolve
|
|
52
|
+
let _ = await ops.append(0, "agg-1", [JSON.Encode.string("e1"), JSON.Encode.string("e2")])
|
|
53
|
+
let events = await ops.replay("agg-1")
|
|
54
|
+
expect(events->Array.length)->toBe(2)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
testPromise("replay returns empty array for unknown aggregate id", async () => {
|
|
58
|
+
let opts: Pulumi.CustomResourceOptions.t = {}
|
|
59
|
+
let storage = EventLogStorage_InMemory.make(~name="test-log-2", ~opts)
|
|
60
|
+
let ops = await storage.operations->TestRunner.resolve
|
|
61
|
+
let events = await ops.replay("unknown-id")
|
|
62
|
+
expect(events->Array.length)->toBe(0)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
testPromise("multiple appends accumulate events", async () => {
|
|
66
|
+
let opts: Pulumi.CustomResourceOptions.t = {}
|
|
67
|
+
let storage = EventLogStorage_InMemory.make(~name="test-log-3", ~opts)
|
|
68
|
+
let ops = await storage.operations->TestRunner.resolve
|
|
69
|
+
let _ = await ops.append(0, "agg-2", [JSON.Encode.string("e1")])
|
|
70
|
+
let _ = await ops.append(1, "agg-2", [JSON.Encode.string("e2"), JSON.Encode.string("e3")])
|
|
71
|
+
let events = await ops.replay("agg-2")
|
|
72
|
+
expect(events->Array.length)->toBe(3)
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
describe("Aggregate E2E", () => {
|
|
77
|
+
// Resolve the Output chain before any test runs so bus wiring is complete.
|
|
78
|
+
let _ = beforeAllAsync(async () => {
|
|
79
|
+
let _ = await agg->ItemAgg.operations->TestRunner.resolve
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
let _ = beforeEach(() => {
|
|
83
|
+
capturedEventCount := 0
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
testPromise("CreateItem command produces ItemCreated event on event topic", async () => {
|
|
87
|
+
let ops = await agg->ItemAgg.operations->TestRunner.resolve
|
|
88
|
+
let commandJson =
|
|
89
|
+
ItemSpec.CreateItem({name: "Widget"})->ReventlessCore.Message.encode(ItemSpec.commandSchema)
|
|
90
|
+
await ops.publishJsons([
|
|
91
|
+
{
|
|
92
|
+
Reventless.Message.id: "item-1",
|
|
93
|
+
meta: testMeta,
|
|
94
|
+
commandJson: commandJson,
|
|
95
|
+
},
|
|
96
|
+
])
|
|
97
|
+
expect(capturedEventCount.contents)->toBe(1)
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
testPromise("second CreateItem for same id produces no events (AlreadyExists)", async () => {
|
|
101
|
+
// item-1 was already created in the previous test (same aggregate instance)
|
|
102
|
+
let ops = await agg->ItemAgg.operations->TestRunner.resolve
|
|
103
|
+
let commandJson =
|
|
104
|
+
ItemSpec.CreateItem({name: "Widget2"})->ReventlessCore.Message.encode(ItemSpec.commandSchema)
|
|
105
|
+
await ops.publishJsons([
|
|
106
|
+
{
|
|
107
|
+
Reventless.Message.id: "item-1",
|
|
108
|
+
meta: testMeta,
|
|
109
|
+
commandJson: commandJson,
|
|
110
|
+
},
|
|
111
|
+
])
|
|
112
|
+
// AlreadyExists error → no events generated → no bus publish
|
|
113
|
+
expect(capturedEventCount.contents)->toBe(0)
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
testPromise("CreateItem for new id produces event", async () => {
|
|
117
|
+
let ops = await agg->ItemAgg.operations->TestRunner.resolve
|
|
118
|
+
let commandJson =
|
|
119
|
+
ItemSpec.CreateItem({name: "NewItem"})->ReventlessCore.Message.encode(ItemSpec.commandSchema)
|
|
120
|
+
await ops.publishJsons([
|
|
121
|
+
{
|
|
122
|
+
Reventless.Message.id: "item-2",
|
|
123
|
+
meta: testMeta,
|
|
124
|
+
commandJson: commandJson,
|
|
125
|
+
},
|
|
126
|
+
])
|
|
127
|
+
expect(capturedEventCount.contents)->toBe(1)
|
|
128
|
+
})
|
|
129
|
+
})
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Message$ReventlessCore from "@reventlessdev/reventless-core/src/Message.res.mjs";
|
|
4
|
+
import * as LocalBus$ReventlessLocal from "../../../src/adapter/LocalBus.res.mjs";
|
|
5
|
+
import * as TestRunner$ReventlessLocal from "../../../src/test/TestRunner.res.mjs";
|
|
6
|
+
import * as TestFixtures$ReventlessLocal from "../../TestFixtures.res.mjs";
|
|
7
|
+
import * as AggregateFixtures$ReventlessLocal from "./AggregateFixtures.res.mjs";
|
|
8
|
+
import * as EventLogStorage_InMemory$ReventlessLocal from "../../../src/adapter/EventLog/EventLogStorage_InMemory.res.mjs";
|
|
9
|
+
|
|
10
|
+
globalThis.describe("LocalBus", () => {
|
|
11
|
+
globalThis.test("publishes events to all subscribers", async () => {
|
|
12
|
+
let TestBus = LocalBus$ReventlessLocal.Make({});
|
|
13
|
+
let count = {
|
|
14
|
+
contents: 0
|
|
15
|
+
};
|
|
16
|
+
TestBus.subscribeToEvents("t1", async (param, param$1, param$2) => {
|
|
17
|
+
count.contents = count.contents + 1 | 0;
|
|
18
|
+
});
|
|
19
|
+
TestBus.subscribeToEvents("t1", async (param, param$1, param$2) => {
|
|
20
|
+
count.contents = count.contents + 1 | 0;
|
|
21
|
+
});
|
|
22
|
+
await TestBus.publishEvent("t1", "memory:InMemory", TestFixtures$ReventlessLocal.testMeta, null);
|
|
23
|
+
globalThis.expect(count.contents).toBe(2);
|
|
24
|
+
});
|
|
25
|
+
globalThis.test("dispatches commands to registered handler", async () => {
|
|
26
|
+
let TestBus = LocalBus$ReventlessLocal.Make({});
|
|
27
|
+
let received = {
|
|
28
|
+
contents: undefined
|
|
29
|
+
};
|
|
30
|
+
TestBus.registerCommandHandler("cmd1", async (json, param) => {
|
|
31
|
+
let tmp;
|
|
32
|
+
tmp = typeof json === "string" ? json : undefined;
|
|
33
|
+
received.contents = tmp;
|
|
34
|
+
});
|
|
35
|
+
await TestBus.dispatchCommand("cmd1", "hello");
|
|
36
|
+
globalThis.expect(received.contents).toEqual("hello");
|
|
37
|
+
});
|
|
38
|
+
globalThis.test("reset clears all handlers and subscribers", async () => {
|
|
39
|
+
let TestBus = LocalBus$ReventlessLocal.Make({});
|
|
40
|
+
let count = {
|
|
41
|
+
contents: 0
|
|
42
|
+
};
|
|
43
|
+
TestBus.subscribeToEvents("topic", async (param, param$1, param$2) => {
|
|
44
|
+
count.contents = count.contents + 1 | 0;
|
|
45
|
+
});
|
|
46
|
+
TestBus.reset();
|
|
47
|
+
globalThis.expect(count.contents).toBe(0);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
globalThis.describe("EventLogStorage_InMemory", () => {
|
|
52
|
+
globalThis.test("append stores events and replay returns them", async () => {
|
|
53
|
+
let storage = EventLogStorage_InMemory$ReventlessLocal.make("test-log", {});
|
|
54
|
+
let ops = await TestRunner$ReventlessLocal.resolve(storage.operations);
|
|
55
|
+
await ops.append(0, "agg-1", [
|
|
56
|
+
"e1",
|
|
57
|
+
"e2"
|
|
58
|
+
]);
|
|
59
|
+
let events = await ops.replay("agg-1");
|
|
60
|
+
globalThis.expect(events.length).toBe(2);
|
|
61
|
+
});
|
|
62
|
+
globalThis.test("replay returns empty array for unknown aggregate id", async () => {
|
|
63
|
+
let storage = EventLogStorage_InMemory$ReventlessLocal.make("test-log-2", {});
|
|
64
|
+
let ops = await TestRunner$ReventlessLocal.resolve(storage.operations);
|
|
65
|
+
let events = await ops.replay("unknown-id");
|
|
66
|
+
globalThis.expect(events.length).toBe(0);
|
|
67
|
+
});
|
|
68
|
+
globalThis.test("multiple appends accumulate events", async () => {
|
|
69
|
+
let storage = EventLogStorage_InMemory$ReventlessLocal.make("test-log-3", {});
|
|
70
|
+
let ops = await TestRunner$ReventlessLocal.resolve(storage.operations);
|
|
71
|
+
await ops.append(0, "agg-2", ["e1"]);
|
|
72
|
+
await ops.append(1, "agg-2", [
|
|
73
|
+
"e2",
|
|
74
|
+
"e3"
|
|
75
|
+
]);
|
|
76
|
+
let events = await ops.replay("agg-2");
|
|
77
|
+
globalThis.expect(events.length).toBe(3);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
globalThis.describe("Aggregate E2E", () => {
|
|
82
|
+
globalThis.beforeAll(async () => {
|
|
83
|
+
await TestRunner$ReventlessLocal.resolve(AggregateFixtures$ReventlessLocal.ItemAgg.operations(AggregateFixtures$ReventlessLocal.agg));
|
|
84
|
+
});
|
|
85
|
+
globalThis.beforeEach(() => {
|
|
86
|
+
AggregateFixtures$ReventlessLocal.capturedEventCount.contents = 0;
|
|
87
|
+
});
|
|
88
|
+
globalThis.test("CreateItem command produces ItemCreated event on event topic", async () => {
|
|
89
|
+
let ops = await TestRunner$ReventlessLocal.resolve(AggregateFixtures$ReventlessLocal.ItemAgg.operations(AggregateFixtures$ReventlessLocal.agg));
|
|
90
|
+
let commandJson = Message$ReventlessCore.encode({
|
|
91
|
+
TAG: "CreateItem",
|
|
92
|
+
name: "Widget"
|
|
93
|
+
}, AggregateFixtures$ReventlessLocal.ItemSpec.commandSchema);
|
|
94
|
+
await ops.publishJsons([{
|
|
95
|
+
id: "item-1",
|
|
96
|
+
meta: TestFixtures$ReventlessLocal.testMeta,
|
|
97
|
+
commandJson: commandJson
|
|
98
|
+
}]);
|
|
99
|
+
globalThis.expect(AggregateFixtures$ReventlessLocal.capturedEventCount.contents).toBe(1);
|
|
100
|
+
});
|
|
101
|
+
globalThis.test("second CreateItem for same id produces no events (AlreadyExists)", async () => {
|
|
102
|
+
let ops = await TestRunner$ReventlessLocal.resolve(AggregateFixtures$ReventlessLocal.ItemAgg.operations(AggregateFixtures$ReventlessLocal.agg));
|
|
103
|
+
let commandJson = Message$ReventlessCore.encode({
|
|
104
|
+
TAG: "CreateItem",
|
|
105
|
+
name: "Widget2"
|
|
106
|
+
}, AggregateFixtures$ReventlessLocal.ItemSpec.commandSchema);
|
|
107
|
+
await ops.publishJsons([{
|
|
108
|
+
id: "item-1",
|
|
109
|
+
meta: TestFixtures$ReventlessLocal.testMeta,
|
|
110
|
+
commandJson: commandJson
|
|
111
|
+
}]);
|
|
112
|
+
globalThis.expect(AggregateFixtures$ReventlessLocal.capturedEventCount.contents).toBe(0);
|
|
113
|
+
});
|
|
114
|
+
globalThis.test("CreateItem for new id produces event", async () => {
|
|
115
|
+
let ops = await TestRunner$ReventlessLocal.resolve(AggregateFixtures$ReventlessLocal.ItemAgg.operations(AggregateFixtures$ReventlessLocal.agg));
|
|
116
|
+
let commandJson = Message$ReventlessCore.encode({
|
|
117
|
+
TAG: "CreateItem",
|
|
118
|
+
name: "NewItem"
|
|
119
|
+
}, AggregateFixtures$ReventlessLocal.ItemSpec.commandSchema);
|
|
120
|
+
await ops.publishJsons([{
|
|
121
|
+
id: "item-2",
|
|
122
|
+
meta: TestFixtures$ReventlessLocal.testMeta,
|
|
123
|
+
commandJson: commandJson
|
|
124
|
+
}]);
|
|
125
|
+
globalThis.expect(AggregateFixtures$ReventlessLocal.capturedEventCount.contents).toBe(1);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
/* Not a pure module */
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
// Unit tests for AutomationSlice_Callback (Plan 04 mixed-source shape) —
|
|
2
|
+
// exercises per-source decode dispatch, context plumbing, and toTags
|
|
3
|
+
// validation.
|
|
4
|
+
|
|
5
|
+
open JestGlobals
|
|
6
|
+
open AutomationSliceFixtures
|
|
7
|
+
|
|
8
|
+
module Callback = ReventlessCore.AutomationSlice_Callback.Make(
|
|
9
|
+
ShipOrderSpec,
|
|
10
|
+
ShipOrderAutomation,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
module SkipCallback = ReventlessCore.AutomationSlice_Callback.Make(
|
|
14
|
+
SkipProcessSpec,
|
|
15
|
+
SkipProcessAutomation,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
open ReventlessCore.AutomationSlice_Callback
|
|
19
|
+
|
|
20
|
+
describe("AutomationSlice Callback (mixed-source)", () => {
|
|
21
|
+
let _ = beforeEach(() => {
|
|
22
|
+
Callback.todoItems
|
|
23
|
+
->Dict.keysToArray
|
|
24
|
+
->Array.forEach(k => Callback.todoItems->Dict.delete(k))
|
|
25
|
+
SkipCallback.todoItems
|
|
26
|
+
->Dict.keysToArray
|
|
27
|
+
->Array.forEach(k => SkipCallback.todoItems->Dict.delete(k))
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
describe("Phase 1 — collect", () => {
|
|
31
|
+
testPromise("OrderPlaced JSON creates a pending TODO item", async () => {
|
|
32
|
+
let json = encodeShipOrderEvent(OrderPlaced({orderId: "ord-1", address: "123 Main St"}))
|
|
33
|
+
Callback.phase1([json], testContext)
|
|
34
|
+
let items = Callback.todoItems
|
|
35
|
+
expect(items->Dict.toArray->Array.length)->toBe(1)
|
|
36
|
+
let row = items->Dict.get("ord-1")->Option.getOrThrow
|
|
37
|
+
expect(row.status)->toBe(Pending)
|
|
38
|
+
expect(row.retryCount)->toBe(0)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
testPromise("duplicate OrderPlaced is idempotent", async () => {
|
|
42
|
+
let j1 = encodeShipOrderEvent(OrderPlaced({orderId: "ord-1", address: "123 Main St"}))
|
|
43
|
+
let j2 = encodeShipOrderEvent(OrderPlaced({orderId: "ord-1", address: "456 Oak Ave"}))
|
|
44
|
+
Callback.phase1([j1], testContext)
|
|
45
|
+
Callback.phase1([j2], testContext)
|
|
46
|
+
expect(Callback.todoItems->Dict.toArray->Array.length)->toBe(1)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
testPromise("multiple OrderPlaced events create multiple TODO items", async () => {
|
|
50
|
+
let j1 = encodeShipOrderEvent(OrderPlaced({orderId: "ord-1", address: "123 Main St"}))
|
|
51
|
+
let j2 = encodeShipOrderEvent(OrderPlaced({orderId: "ord-2", address: "456 Oak Ave"}))
|
|
52
|
+
Callback.phase1([j1, j2], testContext)
|
|
53
|
+
expect(Callback.todoItems->Dict.toArray->Array.length)->toBe(2)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
testPromise("ShipmentCreated does not create a TODO item", async () => {
|
|
57
|
+
let json = encodeShipOrderEvent(ShipmentCreated({orderId: "ord-1"}))
|
|
58
|
+
Callback.phase1([json], testContext)
|
|
59
|
+
expect(Callback.todoItems->Dict.toArray->Array.length)->toBe(0)
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
describe("Phase 1 — resolve", () => {
|
|
64
|
+
testPromise("ShipmentCreated marks pending TODO item as completed", async () => {
|
|
65
|
+
Callback.phase1(
|
|
66
|
+
[encodeShipOrderEvent(OrderPlaced({orderId: "ord-1", address: "123 Main St"}))],
|
|
67
|
+
testContext,
|
|
68
|
+
)
|
|
69
|
+
Callback.phase1(
|
|
70
|
+
[encodeShipOrderEvent(ShipmentCreated({orderId: "ord-1"}))],
|
|
71
|
+
testContext,
|
|
72
|
+
)
|
|
73
|
+
let row = Callback.todoItems->Dict.get("ord-1")->Option.getOrThrow
|
|
74
|
+
expect(row.status)->toBe(Completed)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
testPromise("ShipmentCreated for unknown id is a no-op", async () => {
|
|
78
|
+
Callback.phase1(
|
|
79
|
+
[encodeShipOrderEvent(ShipmentCreated({orderId: "unknown"}))],
|
|
80
|
+
testContext,
|
|
81
|
+
)
|
|
82
|
+
expect(Callback.todoItems->Dict.toArray->Array.length)->toBe(0)
|
|
83
|
+
})
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
describe("Phase 2 — process", () => {
|
|
87
|
+
testPromise("pending items produce commands via publishJsons", async () => {
|
|
88
|
+
Callback.phase1(
|
|
89
|
+
[encodeShipOrderEvent(OrderPlaced({orderId: "ord-1", address: "123 Main St"}))],
|
|
90
|
+
testContext,
|
|
91
|
+
)
|
|
92
|
+
let publishedCommands = ref([])
|
|
93
|
+
let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
|
|
94
|
+
publishedCommands := cmds
|
|
95
|
+
}
|
|
96
|
+
await Callback.phase2(mockPublish)
|
|
97
|
+
|
|
98
|
+
expect(publishedCommands.contents->Array.length)->toBe(1)
|
|
99
|
+
let cmd = publishedCommands.contents->Array.getUnsafe(0)
|
|
100
|
+
expect(cmd.id)->toBe("ord-1")
|
|
101
|
+
|
|
102
|
+
let row = Callback.todoItems->Dict.get("ord-1")->Option.getOrThrow
|
|
103
|
+
expect(row.status)->toBe(Processing)
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
testPromise("completed items are not processed", async () => {
|
|
107
|
+
Callback.phase1(
|
|
108
|
+
[encodeShipOrderEvent(OrderPlaced({orderId: "ord-1", address: "123 Main St"}))],
|
|
109
|
+
testContext,
|
|
110
|
+
)
|
|
111
|
+
Callback.phase1(
|
|
112
|
+
[encodeShipOrderEvent(ShipmentCreated({orderId: "ord-1"}))],
|
|
113
|
+
testContext,
|
|
114
|
+
)
|
|
115
|
+
let publishedCommands = ref([])
|
|
116
|
+
let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
|
|
117
|
+
publishedCommands := cmds
|
|
118
|
+
}
|
|
119
|
+
await Callback.phase2(mockPublish)
|
|
120
|
+
expect(publishedCommands.contents->Array.length)->toBe(0)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
testPromise("items where process returns None are skipped", async () => {
|
|
124
|
+
let json = encodeSkipProcessEvent(OrderPlaced({orderId: "ord-1"}))
|
|
125
|
+
SkipCallback.phase1([json], testContext)
|
|
126
|
+
let publishedCommands = ref([])
|
|
127
|
+
let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
|
|
128
|
+
publishedCommands := cmds
|
|
129
|
+
}
|
|
130
|
+
await SkipCallback.phase2(mockPublish)
|
|
131
|
+
expect(publishedCommands.contents->Array.length)->toBe(0)
|
|
132
|
+
let row = SkipCallback.todoItems->Dict.get("ord-1")->Option.getOrThrow
|
|
133
|
+
expect(row.status)->toBe(Pending)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
testPromise("empty TODO list produces no commands", async () => {
|
|
137
|
+
let publishedCommands = ref([])
|
|
138
|
+
let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
|
|
139
|
+
publishedCommands := cmds
|
|
140
|
+
}
|
|
141
|
+
await Callback.phase2(mockPublish)
|
|
142
|
+
expect(publishedCommands.contents->Array.length)->toBe(0)
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
testPromise("publishJsons failure marks items as Failed", async () => {
|
|
146
|
+
Callback.phase1(
|
|
147
|
+
[encodeShipOrderEvent(OrderPlaced({orderId: "ord-1", address: "123 Main St"}))],
|
|
148
|
+
testContext,
|
|
149
|
+
)
|
|
150
|
+
let failingPublish: ReventlessInfra.CommandTopic.publishJsons = async _cmds => {
|
|
151
|
+
JsError.throwWithMessage("publish failed")
|
|
152
|
+
}
|
|
153
|
+
await Callback.phase2(failingPublish)
|
|
154
|
+
let row = Callback.todoItems->Dict.get("ord-1")->Option.getOrThrow
|
|
155
|
+
expect(row.status)->toBe(Failed)
|
|
156
|
+
expect(row.retryCount)->toBe(1)
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
testPromise("failed items with retryCount < maxRetries are retried", async () => {
|
|
160
|
+
Callback.phase1(
|
|
161
|
+
[encodeShipOrderEvent(OrderPlaced({orderId: "ord-1", address: "123 Main St"}))],
|
|
162
|
+
testContext,
|
|
163
|
+
)
|
|
164
|
+
let failingPublish: ReventlessInfra.CommandTopic.publishJsons = async _cmds => {
|
|
165
|
+
JsError.throwWithMessage("publish failed")
|
|
166
|
+
}
|
|
167
|
+
await Callback.phase2(failingPublish)
|
|
168
|
+
let row1 = Callback.todoItems->Dict.get("ord-1")->Option.getOrThrow
|
|
169
|
+
expect(row1.retryCount)->toBe(1)
|
|
170
|
+
|
|
171
|
+
let publishedCommands = ref([])
|
|
172
|
+
let successPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
|
|
173
|
+
publishedCommands := cmds
|
|
174
|
+
}
|
|
175
|
+
await Callback.phase2(successPublish)
|
|
176
|
+
expect(publishedCommands.contents->Array.length)->toBe(1)
|
|
177
|
+
let row2 = Callback.todoItems->Dict.get("ord-1")->Option.getOrThrow
|
|
178
|
+
expect(row2.status)->toBe(Processing)
|
|
179
|
+
})
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
describe("full lifecycle", () => {
|
|
183
|
+
testPromise("collect → process → resolve completes the TODO item", async () => {
|
|
184
|
+
Callback.phase1(
|
|
185
|
+
[encodeShipOrderEvent(OrderPlaced({orderId: "ord-1", address: "123 Main St"}))],
|
|
186
|
+
testContext,
|
|
187
|
+
)
|
|
188
|
+
expect((Callback.todoItems->Dict.get("ord-1")->Option.getOrThrow).status)->toBe(Pending)
|
|
189
|
+
|
|
190
|
+
let publishedCommands = ref([])
|
|
191
|
+
let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
|
|
192
|
+
publishedCommands := cmds
|
|
193
|
+
}
|
|
194
|
+
await Callback.phase2(mockPublish)
|
|
195
|
+
expect(publishedCommands.contents->Array.length)->toBe(1)
|
|
196
|
+
expect((Callback.todoItems->Dict.get("ord-1")->Option.getOrThrow).status)->toBe(Processing)
|
|
197
|
+
|
|
198
|
+
Callback.phase1(
|
|
199
|
+
[encodeShipOrderEvent(ShipmentCreated({orderId: "ord-1"}))],
|
|
200
|
+
testContext,
|
|
201
|
+
)
|
|
202
|
+
expect((Callback.todoItems->Dict.get("ord-1")->Option.getOrThrow).status)->toBe(Completed)
|
|
203
|
+
|
|
204
|
+
let publishedCommands2 = ref([])
|
|
205
|
+
let mockPublish2: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
|
|
206
|
+
publishedCommands2 := cmds
|
|
207
|
+
}
|
|
208
|
+
await Callback.phase2(mockPublish2)
|
|
209
|
+
expect(publishedCommands2.contents->Array.length)->toBe(0)
|
|
210
|
+
})
|
|
211
|
+
})
|
|
212
|
+
})
|