From 91e0b26eb77d60a5a2d057423053abf7af225f00 Mon Sep 17 00:00:00 2001 From: noear Date: Mon, 19 Dec 2022 12:43:45 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=8C=E6=88=90=20liteflow?= =?UTF-8?q?-solon-plugin=20=E9=80=82=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../solon/integration/XPluginImpl.java | 6 +- .../solon/SolonLiteflowComponentSupport.java | 2 +- .../com/yomahub/liteflow/test/BaseTest.java | 22 +++ .../AbsoluteConfigPathELSpringbootTest.java | 34 ++++ .../test/absoluteConfigPath/cmp/ACmp.java | 20 +++ .../test/absoluteConfigPath/cmp/BCmp.java | 21 +++ .../test/absoluteConfigPath/cmp/CCmp.java | 21 +++ .../asyncNode/AsyncNodeELSpringbootTest.java | 132 ++++++++++++++ .../liteflow/test/asyncNode/cmp/ACmp.java | 24 +++ .../liteflow/test/asyncNode/cmp/BCmp.java | 24 +++ .../liteflow/test/asyncNode/cmp/CCmp.java | 24 +++ .../liteflow/test/asyncNode/cmp/DCmp.java | 25 +++ .../liteflow/test/asyncNode/cmp/ECmp.java | 15 ++ .../liteflow/test/asyncNode/cmp/FCmp.java | 14 ++ .../liteflow/test/asyncNode/cmp/GCmp.java | 26 +++ .../liteflow/test/asyncNode/cmp/HCmp.java | 26 +++ .../liteflow/test/asyncNode/cmp/ICmp.java | 26 +++ .../liteflow/test/asyncNode/cmp/JCmp.java | 15 ++ .../asyncNode/exception/TestException.java | 4 + .../test/base/BaseELSpringbootTest.java | 58 +++++++ .../yomahub/liteflow/test/base/cmp/ACmp.java | 20 +++ .../yomahub/liteflow/test/base/cmp/BCmp.java | 21 +++ .../yomahub/liteflow/test/base/cmp/CCmp.java | 21 +++ .../yomahub/liteflow/test/base/cmp/DCmp.java | 21 +++ .../liteflow/test/base/cmp/ESwitchCmp.java | 20 +++ .../yomahub/liteflow/test/base/cmp/FCmp.java | 21 +++ .../liteflow/test/base/cmp/GSwitchCmp.java | 20 +++ .../yomahub/liteflow/test/base/cmp/HCmp.java | 21 +++ .../yomahub/liteflow/test/base/cmp/ICmp.java | 21 +++ .../yomahub/liteflow/test/base/cmp/JCmp.java | 21 +++ .../yomahub/liteflow/test/base/cmp/KCmp.java | 21 +++ .../yomahub/liteflow/test/base/cmp/MCmp.java | 21 +++ .../yomahub/liteflow/test/base/cmp/NCmp.java | 21 +++ .../yomahub/liteflow/test/base/cmp/PCmp.java | 21 +++ .../yomahub/liteflow/test/base/cmp/QCmp.java | 21 +++ .../yomahub/liteflow/test/base/cmp/RCmp.java | 21 +++ .../liteflow/test/base/cmp/XSwitchCmp.java | 20 +++ .../yomahub/liteflow/test/base/cmp/ZCmp.java | 21 +++ .../builder/BuilderELSpringbootTest1.java | 162 ++++++++++++++++++ .../builder/BuilderELSpringbootTest2.java | 34 ++++ .../liteflow/test/builder/cmp1/ACmp.java | 18 ++ .../liteflow/test/builder/cmp1/BCmp.java | 19 ++ .../liteflow/test/builder/cmp1/CCmp.java | 19 ++ .../liteflow/test/builder/cmp1/DCmp.java | 19 ++ .../liteflow/test/builder/cmp1/ECmp.java | 20 +++ .../liteflow/test/builder/cmp1/FCmp.java | 19 ++ .../liteflow/test/builder/cmp1/GCmp.java | 19 ++ .../liteflow/test/builder/cmp2/HCmp.java | 21 +++ .../liteflow/test/builder/cmp2/ICmp.java | 21 +++ .../liteflow/test/builder/cmp2/JCmp.java | 21 +++ .../test/cmpData/CmpDataELSpringbootTest.java | 38 ++++ .../liteflow/test/cmpData/cmp/ACmp.java | 21 +++ .../liteflow/test/cmpData/cmp/BCmp.java | 26 +++ .../liteflow/test/cmpData/cmp/CCmp.java | 21 +++ .../liteflow/test/cmpData/vo/User.java | 36 ++++ .../LiteflowRetryELSpringbootTest.java | 58 +++++++ .../liteflow/test/cmpRetry/cmp/ACmp.java | 20 +++ .../liteflow/test/cmpRetry/cmp/BCmp.java | 27 +++ .../liteflow/test/cmpRetry/cmp/CCmp.java | 24 +++ .../liteflow/test/cmpRetry/cmp/DCmp.java | 24 +++ .../liteflow/test/cmpRetry/cmp/ECmp.java | 24 +++ .../test/cmpStep/CmpStepELSpringbootTest.java | 71 ++++++++ .../liteflow/test/cmpStep/cmp/ACmp.java | 21 +++ .../liteflow/test/cmpStep/cmp/BCmp.java | 21 +++ .../liteflow/test/cmpStep/cmp/CCmp.java | 23 +++ .../liteflow/test/cmpStep/cmp/DCmp.java | 22 +++ .../liteflow/test/cmpStep/cmp/ECmp.java | 25 +++ .../LiteflowNodeELSpringbootTest.java | 28 +++ .../liteflow/test/comments/cmp/ACmp.java | 22 +++ .../liteflow/test/comments/cmp/BCmp.java | 23 +++ .../liteflow/test/comments/cmp/CCmp.java | 23 +++ .../complex/ComplexELSpringbootTest1.java | 42 +++++ .../liteflow/test/complex/cmp1/ACmp.java | 20 +++ .../liteflow/test/complex/cmp1/BCmp.java | 20 +++ .../liteflow/test/complex/cmp1/CCmp.java | 20 +++ .../liteflow/test/complex/cmp1/DCmp.java | 20 +++ .../liteflow/test/complex/cmp1/ECmp.java | 20 +++ .../liteflow/test/complex/cmp1/FCmp.java | 20 +++ .../liteflow/test/complex/cmp1/GCmp.java | 20 +++ .../liteflow/test/complex/cmp1/HCmp.java | 20 +++ .../liteflow/test/complex/cmp1/ICmp.java | 20 +++ .../liteflow/test/complex/cmp1/JCmp.java | 20 +++ .../liteflow/test/complex/cmp1/KCmp.java | 20 +++ .../liteflow/test/complex/cmp1/LCmp.java | 20 +++ .../liteflow/test/complex/cmp1/MCmp.java | 20 +++ .../liteflow/test/complex/cmp1/NCmp.java | 20 +++ .../liteflow/test/complex/cmp1/ZCmp.java | 20 +++ .../FlowExecutorELSpringbootTest.java | 79 +++++++++ .../liteflow/test/component/cmp1/ACmp.java | 26 +++ .../liteflow/test/component/cmp1/BCmp.java | 29 ++++ .../liteflow/test/component/cmp1/CCmp.java | 29 ++++ .../liteflow/test/component/cmp1/DCmp.java | 26 +++ .../liteflow/test/component/cmp1/ECmp.java | 24 +++ .../liteflow/test/component/cmp1/GCmp.java | 26 +++ .../liteflow/test/component/cmp1/HCmp.java | 20 +++ .../test/component/cmp2/FSwitchCmp.java | 22 +++ .../CustomNodesELSpringbootTest.java | 39 +++++ .../liteflow/test/customNodes/cmp/ACmp.java | 18 ++ .../liteflow/test/customNodes/cmp/BCmp.java | 25 +++ .../liteflow/test/customNodes/cmp/CCmp.java | 19 ++ .../liteflow/test/customNodes/cmp/DCmp.java | 19 ++ .../liteflow/test/customNodes/cmp/ECmp.java | 25 +++ .../liteflow/test/customNodes/cmp/FCmp.java | 19 ++ .../test/customNodes/domain/DemoDomain.java | 11 ++ .../CustomThreadExecutor1.java | 25 +++ .../CustomThreadExecutor2.java | 24 +++ .../CustomThreadExecutor3.java | 24 +++ .../CustomWhenThreadPoolELSpringbootTest.java | 70 ++++++++ .../test/customWhenThreadPool/cmp/ACmp.java | 20 +++ .../test/customWhenThreadPool/cmp/BCmp.java | 24 +++ .../test/customWhenThreadPool/cmp/CCmp.java | 24 +++ .../test/customWhenThreadPool/cmp/DCmp.java | 24 +++ .../test/customWhenThreadPool/cmp/ECmp.java | 24 +++ .../test/customWhenThreadPool/cmp/FCmp.java | 24 +++ .../test/event/EventELSpringbootTest.java | 59 +++++++ .../yomahub/liteflow/test/event/cmp/ACmp.java | 31 ++++ .../yomahub/liteflow/test/event/cmp/BCmp.java | 29 ++++ .../yomahub/liteflow/test/event/cmp/CCmp.java | 29 ++++ .../yomahub/liteflow/test/event/cmp/DCmp.java | 28 +++ .../yomahub/liteflow/test/event/cmp/ECmp.java | 29 ++++ .../exception/CustomStatefulException.java | 12 ++ .../exception/Exception1ELSpringBootTest.java | 60 +++++++ .../exception/Exception2ELSpringBootTest.java | 77 +++++++++ .../liteflow/test/exception/cmp/ACmp.java | 30 ++++ .../liteflow/test/exception/cmp/BCmp.java | 35 ++++ .../liteflow/test/exception/cmp/CCmp.java | 24 +++ .../liteflow/test/exception/cmp/DCmp.java | 27 +++ .../liteflow/test/exception/cmp/ECmp.java | 20 +++ .../liteflow/test/exception/cmp/FCmp.java | 31 ++++ .../liteflow/test/exception/cmp/GCmp.java | 24 +++ .../Executor2FutureELSpringbootTest.java | 36 ++++ .../test/execute2Future/cmp/ACmp.java | 20 +++ .../test/execute2Future/cmp/BCmp.java | 21 +++ .../test/execute2Future/cmp/CCmp.java | 21 +++ .../test/execute2Future/cmp/DCmp.java | 21 +++ .../GetChainNameELSpringbootTest.java | 55 ++++++ .../liteflow/test/getChainName/cmp/ACmp.java | 22 +++ .../liteflow/test/getChainName/cmp/BCmp.java | 23 +++ .../liteflow/test/getChainName/cmp/CCmp.java | 23 +++ .../liteflow/test/getChainName/cmp/DCmp.java | 23 +++ .../liteflow/test/getChainName/cmp/ECmp.java | 27 +++ .../liteflow/test/getChainName/cmp/FCmp.java | 23 +++ .../liteflow/test/getChainName/cmp/GCmp.java | 23 +++ .../liteflow/test/getChainName/cmp/HCmp.java | 24 +++ .../liteflow/test/getChainName/cmp/JCmp.java | 23 +++ .../liteflow/test/getChainName/cmp/KCmp.java | 23 +++ .../test/ifelse/IfELSpringbootTest.java | 81 +++++++++ .../liteflow/test/ifelse/cmp/ACmp.java | 21 +++ .../liteflow/test/ifelse/cmp/BCmp.java | 21 +++ .../liteflow/test/ifelse/cmp/CCmp.java | 21 +++ .../liteflow/test/ifelse/cmp/DCmp.java | 21 +++ .../liteflow/test/ifelse/cmp/X1Cmp.java | 19 ++ .../LiteflowComponentELSpringbootTest.java | 34 ++++ .../liteflow/test/lfCmpAnno/cmp/ACmp.java | 20 +++ .../liteflow/test/lfCmpAnno/cmp/BCmp.java | 21 +++ .../liteflow/test/lfCmpAnno/cmp/CCmp.java | 21 +++ .../liteflow/test/lfCmpAnno/cmp/DCmp.java | 21 +++ .../test/loop/LoopELSpringbootTest.java | 87 ++++++++++ .../yomahub/liteflow/test/loop/cmp/ACmp.java | 20 +++ .../yomahub/liteflow/test/loop/cmp/BCmp.java | 21 +++ .../yomahub/liteflow/test/loop/cmp/CCmp.java | 21 +++ .../yomahub/liteflow/test/loop/cmp/DCmp.java | 29 ++++ .../yomahub/liteflow/test/loop/cmp/ECmp.java | 31 ++++ .../yomahub/liteflow/test/loop/cmp/XCmp.java | 12 ++ .../yomahub/liteflow/test/loop/cmp/YCmp.java | 16 ++ .../yomahub/liteflow/test/loop/cmp/ZCmp.java | 21 +++ .../test/monitor/MonitorELSpringbootTest.java | 44 +++++ .../liteflow/test/monitor/cmp/ACmp.java | 28 +++ .../liteflow/test/monitor/cmp/BCmp.java | 28 +++ .../liteflow/test/monitor/cmp/CCmp.java | 28 +++ .../test/multiContext/CheckContext.java | 24 +++ .../MultiContextELSpringbootTest.java | 63 +++++++ .../test/multiContext/OrderContext.java | 36 ++++ .../liteflow/test/multiContext/cmp/ACmp.java | 24 +++ .../liteflow/test/multiContext/cmp/BCmp.java | 25 +++ .../liteflow/test/multiContext/cmp/CCmp.java | 24 +++ .../liteflow/test/multiContext/cmp/DCmp.java | 25 +++ .../liteflow/test/multiContext/cmp/ECmp.java | 20 +++ .../liteflow/test/multiContext/cmp/FCmp.java | 19 ++ .../LiteflowMultipleTypeELSpringbootTest.java | 37 ++++ .../liteflow/test/multipleType/cmp/ACmp.java | 20 +++ .../liteflow/test/multipleType/cmp/BCmp.java | 21 +++ .../liteflow/test/multipleType/cmp/CCmp.java | 21 +++ .../CustomerDefaultNodeExecutor.java | 18 ++ .../nodeExecutor/CustomerNodeExecutor.java | 19 ++ .../CustomerNodeExecutorAndCustomRetry.java | 28 +++ .../LiteflowNodeExecutorELSpringbootTest.java | 67 ++++++++ .../liteflow/test/nodeExecutor/cmp/ACmp.java | 22 +++ .../liteflow/test/nodeExecutor/cmp/BCmp.java | 27 +++ .../liteflow/test/nodeExecutor/cmp/CCmp.java | 29 ++++ .../liteflow/test/nodeExecutor/cmp/DCmp.java | 31 ++++ .../nullParam/NullParamELSpringbootTest.java | 36 ++++ .../liteflow/test/nullParam/cmp/ACmp.java | 22 +++ .../liteflow/test/nullParam/cmp/BCmp.java | 23 +++ .../liteflow/test/nullParam/cmp/CCmp.java | 22 +++ .../CustomParserJsonELSpringbootTest.java | 33 ++++ .../CustomParserXmlELSpringbootTest.java | 34 ++++ .../CustomParserYmlELSpringbootTest.java | 34 ++++ .../test/parsecustom/bean/TestBean.java | 11 ++ .../liteflow/test/parsecustom/cmp/ACmp.java | 26 +++ .../liteflow/test/parsecustom/cmp/BCmp.java | 21 +++ .../liteflow/test/parsecustom/cmp/CCmp.java | 21 +++ .../liteflow/test/parsecustom/cmp/DCmp.java | 21 +++ .../liteflow/test/parsecustom/cmp/ECmp.java | 20 +++ .../liteflow/test/parsecustom/cmp/FCmp.java | 21 +++ .../liteflow/test/parsecustom/cmp/GCmp.java | 21 +++ .../parser/CustomJsonFlowParser.java | 17 ++ .../parser/CustomXmlFlowParser.java | 22 +++ .../parser/CustomYmlFlowParser.java | 19 ++ .../parser/JsonParserELSpringbootTest.java | 31 ++++ .../SpringELSupportELSpringbootTest.java | 26 +++ .../parser/XmlParserELSpringbootTest.java | 31 ++++ .../parser/YmlParserELSpringbootTest.java | 31 ++++ .../liteflow/test/parser/cmp/ACmp.java | 20 +++ .../liteflow/test/parser/cmp/BCmp.java | 21 +++ .../liteflow/test/parser/cmp/CCmp.java | 21 +++ .../liteflow/test/parser/cmp/DCmp.java | 21 +++ .../liteflow/test/parser/cmp/ECmp.java | 20 +++ .../liteflow/test/parser/cmp/FCmp.java | 21 +++ .../liteflow/test/parser/cmp/GCmp.java | 21 +++ .../PreAndFinallyELSpringbootTest.java | 83 +++++++++ .../liteflow/test/preAndFinally/cmp/ACmp.java | 20 +++ .../liteflow/test/preAndFinally/cmp/BCmp.java | 21 +++ .../liteflow/test/preAndFinally/cmp/CCmp.java | 21 +++ .../liteflow/test/preAndFinally/cmp/DCmp.java | 22 +++ .../test/preAndFinally/cmp/Finally1Cmp.java | 20 +++ .../test/preAndFinally/cmp/Finally2Cmp.java | 20 +++ .../test/preAndFinally/cmp/Finally3Cmp.java | 30 ++++ .../test/preAndFinally/cmp/Pre1Cmp.java | 20 +++ .../test/preAndFinally/cmp/Pre2Cmp.java | 20 +++ .../PrivateDeliveryELSpringbootTest.java | 37 ++++ .../test/privateDelivery/cmp/ACmp.java | 29 ++++ .../test/privateDelivery/cmp/BCmp.java | 27 +++ .../test/privateDelivery/cmp/CCmp.java | 21 +++ .../test/privateDelivery/cmp/DCmp.java | 21 +++ .../RefreshRuleELSpringbootTest.java | 64 +++++++ .../liteflow/test/refreshRule/cmp/ACmp.java | 20 +++ .../liteflow/test/refreshRule/cmp/BCmp.java | 21 +++ .../liteflow/test/refreshRule/cmp/CCmp.java | 21 +++ .../test/reload/ReloadELSpringbootTest.java | 35 ++++ .../liteflow/test/reload/cmp/ACmp.java | 20 +++ .../liteflow/test/reload/cmp/BCmp.java | 21 +++ .../liteflow/test/reload/cmp/CCmp.java | 21 +++ .../RemoveChainELSpringbootTest.java | 37 ++++ .../liteflow/test/removeChain/cmp/ACmp.java | 20 +++ .../liteflow/test/removeChain/cmp/BCmp.java | 21 +++ .../liteflow/test/removeChain/cmp/CCmp.java | 21 +++ .../liteflow/test/removeChain/cmp/DCmp.java | 21 +++ .../LiteflowRequestIdELSpringbootTest.java | 32 ++++ .../liteflow/test/requestId/cmp/ACmp.java | 23 +++ .../liteflow/test/requestId/cmp/BCmp.java | 23 +++ .../config/CustomRequestIdGenerator.java | 18 ++ .../ImplicitSubFlowELSpringbootTest.java | 68 ++++++++ ...flowInDifferentConfigELSpringbootTest.java | 47 +++++ .../subflow/SubflowJsonELSpringBootTest.java | 34 ++++ .../subflow/SubflowXMLELSpringBootTest.java | 34 ++++ .../subflow/SubflowYmlELSpringBootTest.java | 34 ++++ .../liteflow/test/subflow/cmp1/ACmp.java | 13 ++ .../liteflow/test/subflow/cmp1/BCmp.java | 13 ++ .../liteflow/test/subflow/cmp1/CCmp.java | 13 ++ .../liteflow/test/subflow/cmp1/DCmp.java | 13 ++ .../liteflow/test/subflow/cmp1/ECmp.java | 14 ++ .../liteflow/test/subflow/cmp2/FCmp.java | 22 +++ .../liteflow/test/subflow/cmp2/GCmp.java | 28 +++ .../liteflow/test/subflow/cmp2/HCmp.java | 22 +++ .../liteflow/test/subflow/cmp2/MCmp.java | 18 ++ .../liteflow/test/subflow/cmp2/PCmp.java | 23 +++ .../liteflow/test/subflow/cmp2/QCmp.java | 31 ++++ .../yomahub/liteflow/test/subflow/cmp2/R.java | 12 ++ .../yomahub/liteflow/test/subflow/cmp2/S.java | 12 ++ .../SubstituteSpringbootTest.java | 46 +++++ .../test/substituteNode/cmp/ACmp.java | 20 +++ .../test/substituteNode/cmp/BCmp.java | 21 +++ .../test/substituteNode/cmp/CCmp.java | 21 +++ .../test/substituteNode/cmp/DCmp.java | 21 +++ .../test/substituteNode/cmp/SubCmp.java | 21 +++ .../switchcase/SwitchELSpringbootTest.java | 82 +++++++++ .../liteflow/test/switchcase/cmp/ACmp.java | 20 +++ .../liteflow/test/switchcase/cmp/BCmp.java | 21 +++ .../liteflow/test/switchcase/cmp/CCmp.java | 21 +++ .../liteflow/test/switchcase/cmp/DCmp.java | 21 +++ .../test/switchcase/cmp/ESwitchCmp.java | 20 +++ .../test/switchcase/cmp/FSwitchCmp.java | 20 +++ .../test/switchcase/cmp/GSwitchCmp.java | 20 +++ .../test/switchcase/cmp/HSwitchCmp.java | 20 +++ .../test/switchcase/cmp/ISwitchCmp.java | 20 +++ .../test/tag/NodeTagELSpringbootJsonTest.java | 64 +++++++ .../test/tag/NodeTagELSpringbootXmlTest.java | 73 ++++++++ .../yomahub/liteflow/test/tag/cmp/ACmp.java | 30 ++++ .../yomahub/liteflow/test/tag/cmp/B1Cmp.java | 23 +++ .../yomahub/liteflow/test/tag/cmp/BCmp.java | 24 +++ .../yomahub/liteflow/test/tag/cmp/CCmp.java | 24 +++ .../yomahub/liteflow/test/tag/cmp/DCmp.java | 21 +++ .../yomahub/liteflow/test/tag/cmp/ECmp.java | 21 +++ .../yomahub/liteflow/test/tag/cmp/FCmp.java | 25 +++ .../yomahub/liteflow/test/tag/cmp/GCmp.java | 20 +++ .../yomahub/liteflow/test/tag/cmp/HCmp.java | 27 +++ .../liteflow/test/useTTLInWhen/TestTL.java | 16 ++ .../UseTTLInWhenELSpringbootTest.java | 38 ++++ .../liteflow/test/useTTLInWhen/cmp/ACmp.java | 22 +++ .../liteflow/test/useTTLInWhen/cmp/BCmp.java | 26 +++ .../liteflow/test/useTTLInWhen/cmp/CCmp.java | 26 +++ .../liteflow/test/useTTLInWhen/cmp/DCmp.java | 26 +++ .../liteflow/test/useTTLInWhen/cmp/ECmp.java | 26 +++ .../liteflow/test/useTTLInWhen/cmp/FCmp.java | 26 +++ .../ValidateRuleELSpringbootTest.java | 38 ++++ .../liteflow/test/validateRule/cmp/ACmp.java | 20 +++ .../liteflow/test/validateRule/cmp/BCmp.java | 21 +++ .../liteflow/test/validateRule/cmp/CCmp.java | 21 +++ .../WhenTimeOutELSpringbootTest1.java | 39 +++++ .../WhenTimeOutELSpringbootTest2.java | 37 ++++ .../liteflow/test/whenTimeOut/cmp/ACmp.java | 20 +++ .../liteflow/test/whenTimeOut/cmp/BCmp.java | 26 +++ .../liteflow/test/whenTimeOut/cmp/CCmp.java | 26 +++ .../liteflow/test/whenTimeOut/cmp/DCmp.java | 26 +++ .../liteflow/test/whenTimeOut/cmp/ECmp.java | 26 +++ .../liteflow/test/whenTimeOut/cmp/FCmp.java | 26 +++ .../absoluteConfigPath/application.properties | 1 + .../resources/absoluteConfigPath/flow.el.xml | 7 + .../test/resources/aop/application.properties | 1 + .../src/test/resources/aop/flow.el.xml | 14 ++ .../asyncNode/application.properties | 1 + .../src/test/resources/asyncNode/flow.el.xml | 49 ++++++ .../resources/base/application.properties | 1 + .../src/test/resources/base/flow.el.xml | 54 ++++++ .../src/test/resources/base/img.png | Bin 0 -> 276050 bytes .../resources/cmpData/application.properties | 1 + .../src/test/resources/cmpData/flow.xml | 14 ++ .../resources/cmpRetry/application.properties | 3 + .../src/test/resources/cmpRetry/flow.el.xml | 18 ++ .../resources/cmpStep/application.properties | 1 + .../src/test/resources/cmpStep/flow.el.xml | 14 ++ .../resources/comments/application.properties | 1 + .../src/test/resources/comments/flow.el.xml | 18 ++ .../resources/complex/application1.properties | 1 + .../resources/complex/application2.properties | 1 + .../src/test/resources/complex/flow1.el.xml | 34 ++++ .../src/test/resources/complex/flow2.el.xml | 44 +++++ .../component/application.properties | 1 + .../src/test/resources/component/flow.el.xml | 30 ++++ .../customNodes/application.properties | 1 + .../test/resources/customNodes/flow.el.xml | 19 ++ .../application.properties | 1 + .../customWhenThreadPool/flow.el.xml | 12 ++ .../resources/event/application.properties | 1 + .../src/test/resources/event/flow.el.xml | 14 ++ .../exception/application.properties | 2 + .../resources/exception/flow-blank.el.xml | 5 + .../resources/exception/flow-exception.el.xml | 12 ++ .../src/test/resources/exception/flow.el.xml | 23 +++ .../execute2Future/application.properties | 1 + .../test/resources/execute2Future/flow.el.xml | 7 + .../getChainName/application.properties | 1 + .../test/resources/getChainName/flow.el.xml | 38 ++++ .../resources/ifelse/application.properties | 1 + .../src/test/resources/ifelse/flow.el.xml | 41 +++++ .../resources/lazy/application.properties | 1 + .../src/test/resources/lazy/flow.el.xml | 6 + .../lfCmpAnno/application.properties | 1 + .../src/test/resources/lfCmpAnno/flow.el.xml | 6 + .../resources/loop/application.properties | 1 + .../src/test/resources/loop/flow.xml | 42 +++++ .../resources/monitor/application.properties | 5 + .../src/test/resources/monitor/flow.el.xml | 7 + .../multiContext/application.properties | 1 + .../test/resources/multiContext/flow.el.xml | 10 ++ .../multipleType/application.properties | 2 + .../test/resources/multipleType/flow.el.xml | 6 + .../test/resources/multipleType/flow.el.yml | 4 + .../nodeExecutor/application.properties | 4 + .../test/resources/nodeExecutor/flow.el.xml | 18 ++ .../nullParam/application.properties | 1 + .../src/test/resources/nullParam/flow.el.xml | 6 + .../application-custom-json.properties | 1 + .../application-custom-xml.properties | 1 + .../application-custom-yml.properties | 1 + .../parser/application-json.properties | 1 + .../parser/application-springEL.properties | 1 + .../parser/application-xml.properties | 1 + .../parser/application-yml.properties | 1 + .../src/test/resources/parser/flow.el.json | 46 +++++ .../src/test/resources/parser/flow.el.xml | 20 +++ .../src/test/resources/parser/flow.el.yml | 22 +++ .../parser/subFoder1/subFoder2/flow1.el.xml | 20 +++ .../parser/subFoder1/subFoder2/flow2.el.xml | 7 + .../parser/subFoder1/subFoder2/flow3.el.xml | 6 + .../preAndFinally/application.properties | 1 + .../test/resources/preAndFinally/flow.el.xml | 31 ++++ .../privateDelivery/application.properties | 1 + .../resources/privateDelivery/flow.el.xml | 21 +++ .../refreshRule/application.properties | 1 + .../test/resources/refreshRule/flow.el.xml | 6 + .../resources/refreshRule/flow_update.el.xml | 6 + .../resources/reload/application.properties | 1 + .../src/test/resources/reload/flow.el.xml | 6 + .../removeChain/application.properties | 1 + .../test/resources/removeChain/flow.el.xml | 10 ++ .../requestId/application.properties | 2 + .../src/test/resources/requestId/flow.el.xml | 6 + .../subflow/application-implicit.properties | 1 + .../subflow/application-json.properties | 1 + ...plication-subInDifferentConfig1.properties | 1 + ...plication-subInDifferentConfig2.properties | 1 + .../subflow/application-xml.properties | 1 + .../subflow/application-yml.properties | 1 + .../resources/subflow/flow-implicit.el.xml | 26 +++ .../test/resources/subflow/flow-main.el.xml | 6 + .../test/resources/subflow/flow-sub1.el.xml | 6 + .../test/resources/subflow/flow-sub2.el.xml | 6 + .../test/resources/subflow/flow-sub2.el.yml | 4 + .../src/test/resources/subflow/flow.el.json | 22 +++ .../src/test/resources/subflow/flow.el.xml | 18 ++ .../src/test/resources/subflow/flow.el.yml | 10 ++ .../substituteNode/application.properties | 2 + .../test/resources/substituteNode/flow.el.xml | 14 ++ .../switchcase/application.properties | 1 + .../src/test/resources/switchcase/flow.el.xml | 53 ++++++ .../resources/tag/application-json.properties | 1 + .../resources/tag/application-xml.properties | 1 + .../src/test/resources/tag/flow.el.json | 22 +++ .../src/test/resources/tag/flow.el.xml | 22 +++ .../useTTLInWhen/application.properties | 2 + .../test/resources/useTTLInWhen/flow.el.xml | 6 + .../whenTimeOut/application1.properties | 2 + .../whenTimeOut/application2.properties | 2 + .../test/resources/whenTimeOut/flow1.el.xml | 6 + .../test/resources/whenTimeOut/flow2.el.xml | 6 + 427 files changed, 9581 insertions(+), 6 deletions(-) create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/BaseTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/AbsoluteConfigPathELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/AsyncNodeELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/ECmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/FCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/GCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/HCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/ICmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/JCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/exception/TestException.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/BaseELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/ESwitchCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/FCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/GSwitchCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/HCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/ICmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/JCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/KCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/MCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/NCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/PCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/QCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/RCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/XSwitchCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/ZCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/BuilderELSpringbootTest1.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/BuilderELSpringbootTest2.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/ECmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/FCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/GCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp2/HCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp2/ICmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp2/JCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpData/CmpDataELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpData/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpData/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpData/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpData/vo/User.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/LiteflowRetryELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/ECmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/CmpStepELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/cmp/ECmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/comments/LiteflowNodeELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/comments/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/comments/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/comments/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/ComplexELSpringbootTest1.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/ECmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/FCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/GCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/HCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/ICmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/JCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/KCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/LCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/MCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/NCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/ZCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/FlowExecutorELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/ECmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/GCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/HCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp2/FSwitchCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/CustomNodesELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/ECmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/FCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/domain/DemoDomain.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomThreadExecutor1.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomThreadExecutor2.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomThreadExecutor3.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomWhenThreadPoolELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/ECmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/FCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/EventELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/cmp/ECmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/CustomStatefulException.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/Exception1ELSpringBootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/Exception2ELSpringBootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/ECmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/FCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/GCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/execute2Future/Executor2FutureELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/execute2Future/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/execute2Future/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/execute2Future/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/execute2Future/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/GetChainNameELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/ECmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/FCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/GCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/HCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/JCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/KCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/IfELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/cmp/X1Cmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/LiteflowComponentELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/LoopELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/ECmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/XCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/YCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/ZCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitor/MonitorELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitor/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitor/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitor/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/CheckContext.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/MultiContextELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/OrderContext.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/ECmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/FCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multipleType/LiteflowMultipleTypeELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multipleType/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multipleType/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multipleType/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/CustomerDefaultNodeExecutor.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/CustomerNodeExecutor.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/CustomerNodeExecutorAndCustomRetry.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/LiteflowNodeExecutorELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nullParam/NullParamELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nullParam/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nullParam/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nullParam/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/CustomParserJsonELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/CustomParserXmlELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/CustomParserYmlELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/bean/TestBean.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/ECmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/FCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/GCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/parser/CustomJsonFlowParser.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/parser/CustomXmlFlowParser.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/parser/CustomYmlFlowParser.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/JsonParserELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/SpringELSupportELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/XmlParserELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/YmlParserELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/ECmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/FCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/GCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/PreAndFinallyELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/Finally1Cmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/Finally2Cmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/Finally3Cmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/Pre1Cmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/Pre2Cmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/privateDelivery/PrivateDeliveryELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/privateDelivery/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/privateDelivery/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/privateDelivery/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/privateDelivery/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/refreshRule/RefreshRuleELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/refreshRule/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/refreshRule/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/refreshRule/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/reload/ReloadELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/reload/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/reload/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/reload/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/removeChain/RemoveChainELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/removeChain/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/removeChain/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/removeChain/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/removeChain/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/requestId/LiteflowRequestIdELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/requestId/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/requestId/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/requestId/config/CustomRequestIdGenerator.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/ImplicitSubFlowELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/SubflowInDifferentConfigELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/SubflowJsonELSpringBootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/SubflowXMLELSpringBootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/SubflowYmlELSpringBootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp1/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp1/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp1/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp1/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp1/ECmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/FCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/GCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/HCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/MCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/PCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/QCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/R.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/S.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/SubstituteSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/SubCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/SwitchELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/ESwitchCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/FSwitchCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/GSwitchCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/HSwitchCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/ISwitchCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/NodeTagELSpringbootJsonTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/NodeTagELSpringbootXmlTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/B1Cmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/ECmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/FCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/GCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/HCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/TestTL.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/UseTTLInWhenELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/ECmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/FCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/validateRule/ValidateRuleELSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/validateRule/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/validateRule/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/validateRule/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/WhenTimeOutELSpringbootTest1.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/WhenTimeOutELSpringbootTest2.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/CCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/ECmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/FCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/absoluteConfigPath/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/absoluteConfigPath/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/aop/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/aop/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/asyncNode/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/asyncNode/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/base/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/base/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/base/img.png create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpData/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpData/flow.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpRetry/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpRetry/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpStep/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpStep/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/comments/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/comments/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/complex/application1.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/complex/application2.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/complex/flow1.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/complex/flow2.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/component/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/component/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/customNodes/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/customNodes/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/customWhenThreadPool/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/customWhenThreadPool/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/event/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/event/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/exception/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/exception/flow-blank.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/exception/flow-exception.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/exception/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/execute2Future/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/execute2Future/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/getChainName/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/getChainName/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/ifelse/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/ifelse/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/lazy/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/lazy/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/lfCmpAnno/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/lfCmpAnno/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/loop/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/loop/flow.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/monitor/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/monitor/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/multiContext/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/multiContext/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/multipleType/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/multipleType/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/multipleType/flow.el.yml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/nodeExecutor/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/nodeExecutor/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/nullParam/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/nullParam/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parsecustom/application-custom-json.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parsecustom/application-custom-xml.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parsecustom/application-custom-yml.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/application-json.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/application-springEL.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/application-xml.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/application-yml.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/flow.el.json create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/flow.el.yml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/subFoder1/subFoder2/flow1.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/subFoder1/subFoder2/flow2.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/subFoder1/subFoder2/flow3.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/preAndFinally/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/preAndFinally/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/privateDelivery/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/privateDelivery/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/refreshRule/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/refreshRule/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/refreshRule/flow_update.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/reload/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/reload/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/removeChain/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/removeChain/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/requestId/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/requestId/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-implicit.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-json.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-subInDifferentConfig1.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-subInDifferentConfig2.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-xml.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-yml.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow-implicit.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow-main.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow-sub1.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow-sub2.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow-sub2.el.yml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow.el.json create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow.el.yml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/substituteNode/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/substituteNode/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/switchcase/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/switchcase/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/tag/application-json.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/tag/application-xml.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/tag/flow.el.json create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/tag/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/useTTLInWhen/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/useTTLInWhen/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/whenTimeOut/application1.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/whenTimeOut/application2.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/whenTimeOut/flow1.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/whenTimeOut/flow2.el.xml diff --git a/liteflow-solon-plugin/src/main/java/com/yomahub/liteflow/solon/integration/XPluginImpl.java b/liteflow-solon-plugin/src/main/java/com/yomahub/liteflow/solon/integration/XPluginImpl.java index 146e5f222..2a7e58196 100644 --- a/liteflow-solon-plugin/src/main/java/com/yomahub/liteflow/solon/integration/XPluginImpl.java +++ b/liteflow-solon-plugin/src/main/java/com/yomahub/liteflow/solon/integration/XPluginImpl.java @@ -36,11 +36,7 @@ public class XPluginImpl implements Plugin { //订阅 NodeComponent 组件 context.subWrapsOfType(NodeComponent.class, bw -> { NodeComponent node1 = bw.raw(); - - if (Utils.isNotEmpty(bw.name())) { - node1.setName(bw.name()); - node1.setNodeId(bw.name()); - } + node1.setNodeId(bw.name()); FlowBus.addSpringScanNode(bw.name(), bw.raw()); }); diff --git a/liteflow-solon-plugin/src/main/java/com/yomahub/liteflow/spi/solon/SolonLiteflowComponentSupport.java b/liteflow-solon-plugin/src/main/java/com/yomahub/liteflow/spi/solon/SolonLiteflowComponentSupport.java index 92ac27a0b..ce5bd32a2 100644 --- a/liteflow-solon-plugin/src/main/java/com/yomahub/liteflow/spi/solon/SolonLiteflowComponentSupport.java +++ b/liteflow-solon-plugin/src/main/java/com/yomahub/liteflow/spi/solon/SolonLiteflowComponentSupport.java @@ -19,7 +19,7 @@ public class SolonLiteflowComponentSupport implements LiteflowComponentSupport { if (ObjectUtil.isNotNull(liteflowComponent)) { return liteflowComponent.name(); }else{ - return nodeComponent.getNodeId(); + return null; } } diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/BaseTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/BaseTest.java new file mode 100644 index 000000000..3b819688d --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/BaseTest.java @@ -0,0 +1,22 @@ +package com.yomahub.liteflow.test; + +import com.yomahub.liteflow.core.FlowInitHook; +import com.yomahub.liteflow.flow.FlowBus; +import com.yomahub.liteflow.property.LiteflowConfigGetter; +import com.yomahub.liteflow.spi.holder.SpiFactoryCleaner; +import com.yomahub.liteflow.thread.ExecutorHelper; +import org.junit.AfterClass; +import org.noear.solon.Solon; + +public class BaseTest { + + @AfterClass + public static void cleanScanCache(){ + //Solon.context().clear(); + FlowBus.cleanCache(); + ExecutorHelper.loadInstance().clearExecutorServiceMap(); + SpiFactoryCleaner.clean(); + LiteflowConfigGetter.clean(); + FlowInitHook.cleanHook(); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/AbsoluteConfigPathELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/AbsoluteConfigPathELSpringbootTest.java new file mode 100644 index 000000000..d1cf311ee --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/AbsoluteConfigPathELSpringbootTest.java @@ -0,0 +1,34 @@ +package com.yomahub.liteflow.test.absoluteConfigPath; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * springboot环境下异步线程超时日志打印测试 + * @author Bryan.Zhang + * @since 2.6.4 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/absoluteConfigPath/application.properties") +public class AbsoluteConfigPathELSpringbootTest extends BaseTest { + + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + @Inject + private FlowExecutor flowExecutor; + + @Test + public void testAbsoluteConfig() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/cmp/ACmp.java new file mode 100644 index 000000000..1df923f55 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/cmp/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.absoluteConfigPath.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/cmp/BCmp.java new file mode 100644 index 000000000..a300ebb89 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/cmp/BCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.absoluteConfigPath.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/cmp/CCmp.java new file mode 100644 index 000000000..c40931ddf --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/cmp/CCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.absoluteConfigPath.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/AsyncNodeELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/AsyncNodeELSpringbootTest.java new file mode 100644 index 000000000..d7ba24fb3 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/AsyncNodeELSpringbootTest.java @@ -0,0 +1,132 @@ +package com.yomahub.liteflow.test.asyncNode; + +import cn.hutool.core.collection.ListUtil; +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.BaseTest; +import com.yomahub.liteflow.test.asyncNode.exception.TestException; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * 测试隐式调用子流程 + * 单元测试 + * + * @author ssss + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/asyncNode/application.properties") +public class AsyncNodeELSpringbootTest extends BaseTest { + @Inject + private FlowExecutor flowExecutor; + + /***** + * 标准chain 嵌套选择 嵌套子chain进行执行 + * 验证了when情况下 多个node是并行执行 + * 验证了默认参数情况下 when可以加载执行 + * **/ + @Test + public void testAsyncFlow1() { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "it's a base request"); + Assert.assertTrue(response.isSuccess()); + System.out.println(response.getExecuteStepStr()); + } + + //这个和test1有点类似,只不过进一步验证了步骤 + @Test + public void testAsyncFlow2() { + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "it's a base request"); + Assert.assertTrue(ListUtil.toList("b==>j==>g==>f==>h","b==>j==>g==>h==>f", + "b==>j==>h==>g==>f","b==>j==>h==>f==>g", + "b==>j==>f==>h==>g","b==>j==>f==>g==>h" + ).contains(response.getExecuteStepStr())); + } + + //测试errorResume,默认的errorResume为false,这里测试默认的 + @Test + public void testAsyncFlow3_1() { + LiteflowResponse response = flowExecutor.execute2Resp("chain3-1", "it's a base request"); + Assert.assertFalse(response.isSuccess()); + Assert.assertEquals(response.getSlot().getException().getClass(), TestException.class); + } + + //测试errorResume,默认的errorResume为false,这里设置为true + @Test + public void testAsyncFlow3_2() { + LiteflowResponse response = flowExecutor.execute2Resp("chain3-2", "it's a base request"); + Assert.assertTrue(response.isSuccess()); + } + + //相同group的并行组,会合并,并且errorResume根据第一个when来,这里第一个when配置了不抛错 + @Test + public void testAsyncFlow4() { + LiteflowResponse response = flowExecutor.execute2Resp("chain4", "it's a base request"); + //因为不记录错误,所以最终结果是true + Assert.assertTrue(response.isSuccess()); + //因为是并行组,所以即便抛错了,其他组件也会执行,i在流程里配置了2遍,i抛错,但是也执行了2遍,这里验证下 + DefaultContext context = response.getFirstContextBean(); + Integer count = context.getData("count"); + Assert.assertEquals(new Integer(2), count); + //因为配置了不抛错,所以response里的cause应该为null + Assert.assertNull(response.getCause()); + } + + //相同group的并行组,会合并,并且errorResume根据第一个when来,这里第一个when配置了会抛错 + @Test + public void testAsyncFlow5() throws Exception { + LiteflowResponse response = flowExecutor.execute2Resp("chain5", "it's a base request"); + //整个并行组是报错的,所以最终结果是false + Assert.assertFalse(response.isSuccess()); + //因为是并行组,所以即便抛错了,其他组件也会执行,i在流程里配置了2遍,i抛错,但是也执行了2遍,这里验证下 + DefaultContext context = response.getFirstContextBean(); + Integer count = context.getData("count"); + Assert.assertEquals(new Integer(2), count); + //因为第一个when配置了会报错,所以response里的cause里应该会有TestException + Assert.assertEquals(TestException.class, response.getCause().getClass()); + } + + //不同group的并行组,不会合并,第一个when的errorResume是false,会抛错,那第二个when就不会执行 + @Test + public void testAsyncFlow6() throws Exception { + LiteflowResponse response = flowExecutor.execute2Resp("chain6", "it's a base request"); + //第一个when会抛错,所以最终结果是false + Assert.assertFalse(response.isSuccess()); + //因为是不同组并行组,第一组的when里的i就抛错了,所以i就执行了1遍 + DefaultContext context = response.getFirstContextBean(); + Integer count = context.getData("count"); + Assert.assertEquals(new Integer(1), count); + //第一个when会报错,所以最终response的cause里应该会有TestException + Assert.assertEquals(TestException.class, response.getCause().getClass()); + } + + //不同group的并行组,不会合并,第一个when的errorResume是true,不会报错,那第二个when还会继续执行,但是第二个when的errorResume是false,所以第二个when会报错 + @Test + public void testAsyncFlow7() throws Exception { + LiteflowResponse response = flowExecutor.execute2Resp("chain7", "it's a base request"); + //第二个when会抛错,所以最终结果是false + Assert.assertFalse(response.isSuccess()); + // 传递了slotIndex,则set的size==2 + DefaultContext context = response.getFirstContextBean(); + Integer count = context.getData("count"); + Assert.assertEquals(new Integer(2), count); + //第一个when会报错,所以最终response的cause里应该会有TestException + Assert.assertEquals(TestException.class, response.getCause().getClass()); + } + + //测试任意异步一个执行完即继续的场景 + //d g h并行,配置了any=true,其中d耗时1秒,g耗时0.5秒,其他都不设耗时 + //最终执行效果应该是h先返回,然后执行abc,最后gd + //这里要注意的是,由于step是先加入,所以step的打印顺序并不是这样的。但是实际执行是正确的 + @Test + public void testAsyncFlow8() throws Exception { + LiteflowResponse response = flowExecutor.execute2Resp("chain8", "it's a base request"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertTrue(response.isSuccess()); + Assert.assertTrue(context.getData("check").toString().startsWith("habc")); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/ACmp.java new file mode 100644 index 000000000..87c4da66a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/ACmp.java @@ -0,0 +1,24 @@ +package com.yomahub.liteflow.test.asyncNode.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + + +@Component("a") +public class ACmp extends NodeComponent { + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + synchronized (NodeComponent.class){ + if (context.hasData("check")){ + String str = context.getData("check"); + str += this.getNodeId(); + context.setData("check", str); + }else{ + context.setData("check", this.getNodeId()); + } + } + System.out.println("Acomp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/BCmp.java new file mode 100644 index 000000000..0e1f21f96 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/BCmp.java @@ -0,0 +1,24 @@ +package com.yomahub.liteflow.test.asyncNode.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + + +@Component("b") +public class BCmp extends NodeComponent { + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + synchronized (NodeComponent.class){ + if (context.hasData("check")){ + String str = context.getData("check"); + str += this.getNodeId(); + context.setData("check", str); + }else{ + context.setData("check", this.getNodeId()); + } + } + System.out.println("Bcomp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/CCmp.java new file mode 100644 index 000000000..e7b1174c2 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/CCmp.java @@ -0,0 +1,24 @@ +package com.yomahub.liteflow.test.asyncNode.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + + +@Component("c") +public class CCmp extends NodeComponent { + @Override + public void process() throws Exception { + DefaultContext context = this.getFirstContextBean(); + synchronized (NodeComponent.class){ + if (context.hasData("check")){ + String str = context.getData("check"); + str += this.getNodeId(); + context.setData("check", str); + }else{ + context.setData("check", this.getNodeId()); + } + } + System.out.println("Ccomp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/DCmp.java new file mode 100644 index 000000000..85dc9b63e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/DCmp.java @@ -0,0 +1,25 @@ +package com.yomahub.liteflow.test.asyncNode.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + + +@Component("d") +public class DCmp extends NodeComponent { + @Override + public void process() throws Exception { + Thread.sleep(1000); + DefaultContext context = this.getFirstContextBean(); + synchronized (NodeComponent.class){ + if (context.hasData("check")){ + String str = context.getData("check"); + str += this.getNodeId(); + context.setData("check", str); + }else{ + context.setData("check", this.getNodeId()); + } + } + System.out.println("Dcomp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/ECmp.java new file mode 100644 index 000000000..e69fc8fae --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/ECmp.java @@ -0,0 +1,15 @@ +package com.yomahub.liteflow.test.asyncNode.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; +import org.noear.solon.annotation.Component; + + +@Component("e") +public class ECmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + System.out.println("Ecomp executed!"); + return "g"; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/FCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/FCmp.java new file mode 100644 index 000000000..40a99b856 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/FCmp.java @@ -0,0 +1,14 @@ +package com.yomahub.liteflow.test.asyncNode.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + + +@Component("f") +public class FCmp extends NodeComponent { + + @Override + public void process() throws Exception { + System.out.println("Fcomp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/GCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/GCmp.java new file mode 100644 index 000000000..43ad1003b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/GCmp.java @@ -0,0 +1,26 @@ +package com.yomahub.liteflow.test.asyncNode.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + + +@Component("g") +public class GCmp extends NodeComponent { + + @Override + public void process() throws Exception { + Thread.sleep(500); + DefaultContext context = this.getFirstContextBean(); + synchronized (NodeComponent.class){ + if (context.hasData("check")){ + String str = context.getData("check"); + str += this.getNodeId(); + context.setData("check", str); + }else{ + context.setData("check", this.getNodeId()); + } + } + System.out.println("Gcomp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/HCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/HCmp.java new file mode 100644 index 000000000..bd35f6f61 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/HCmp.java @@ -0,0 +1,26 @@ +package com.yomahub.liteflow.test.asyncNode.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + + +@Component("h") +public class HCmp extends NodeComponent { + + @Override + public void process() throws Exception { + DefaultContext context = this.getFirstContextBean(); + synchronized (NodeComponent.class){ + if (context.hasData("check")){ + String str = context.getData("check"); + str += this.getNodeId(); + context.setData("check", str); + }else{ + context.setData("check", this.getNodeId()); + } + } + + System.out.println("Hcomp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/ICmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/ICmp.java new file mode 100644 index 000000000..27538bb56 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/ICmp.java @@ -0,0 +1,26 @@ +package com.yomahub.liteflow.test.asyncNode.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.asyncNode.exception.TestException; +import org.noear.solon.annotation.Component; + + +@Component("i") +public class ICmp extends NodeComponent { + + @Override + public void process() throws Exception { + DefaultContext context = this.getFirstContextBean(); + synchronized (ICmp.class){ + if (context.hasData("count")){ + Integer count = context.getData("count"); + context.setData("count", ++count); + } else{ + context.setData("count", 1); + } + } + System.out.println("Icomp executed! throw Exception!"); + throw new TestException(); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/JCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/JCmp.java new file mode 100644 index 000000000..b93fdaf92 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/JCmp.java @@ -0,0 +1,15 @@ +package com.yomahub.liteflow.test.asyncNode.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; +import org.noear.solon.annotation.Component; + + +@Component("j") +public class JCmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + System.out.println("Jcomp executed!"); + return "chain3"; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/exception/TestException.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/exception/TestException.java new file mode 100644 index 000000000..e786e9f86 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/asyncNode/exception/TestException.java @@ -0,0 +1,4 @@ +package com.yomahub.liteflow.test.asyncNode.exception; + +public class TestException extends Exception{ +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/BaseELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/BaseELSpringbootTest.java new file mode 100644 index 000000000..35d3c9c08 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/BaseELSpringbootTest.java @@ -0,0 +1,58 @@ +package com.yomahub.liteflow.test.base; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境EL常规的例子测试 + * @author Bryan.Zhang + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/base/application.properties") +public class BaseELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //最简单的情况 + @Test + public void testBase1() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + } + + //switch节点最简单的测试用例 + @Test + public void testBase2() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg"); + Assert.assertTrue(response.isSuccess()); + } + + //then,when,switch混用的稍微复杂点的用例,switch跳到一个then上 + @Test + public void testBase3() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg"); + Assert.assertTrue(response.isSuccess()); + } + + //一个非常复杂的例子,可以看base目录下的img.png这个图示 + @Test + public void testBase4() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg"); + Assert.assertTrue(response.isSuccess()); + } + + //用变量来声明短流程 + @Test + public void testBase5() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain5", "arg"); + Assert.assertTrue(response.isSuccess()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/ACmp.java new file mode 100644 index 000000000..4360b4cf9 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/BCmp.java new file mode 100644 index 000000000..e5ab1d4b6 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/BCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/CCmp.java new file mode 100644 index 000000000..6432e623b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/CCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/DCmp.java new file mode 100644 index 000000000..48bac4097 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/DCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("d") +public class DCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("DCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/ESwitchCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/ESwitchCmp.java new file mode 100644 index 000000000..82f1af154 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/ESwitchCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; +import org.noear.solon.annotation.Component; + +@Component("e") +public class ESwitchCmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + return "d"; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/FCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/FCmp.java new file mode 100644 index 000000000..ecf90ffbe --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/FCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("f") +public class FCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("FCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/GSwitchCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/GSwitchCmp.java new file mode 100644 index 000000000..52ac7d907 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/GSwitchCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; +import org.noear.solon.annotation.Component; + +@Component("g") +public class GSwitchCmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + return "then_1001"; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/HCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/HCmp.java new file mode 100644 index 000000000..24ed79f2f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/HCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("h") +public class HCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("HCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/ICmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/ICmp.java new file mode 100644 index 000000000..fa6dfa1b1 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/ICmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("i") +public class ICmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ICmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/JCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/JCmp.java new file mode 100644 index 000000000..9d3ca10ad --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/JCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("j") +public class JCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("JCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/KCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/KCmp.java new file mode 100644 index 000000000..1e92390da --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/KCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("k") +public class KCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("KCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/MCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/MCmp.java new file mode 100644 index 000000000..5297c5072 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/MCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("m") +public class MCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("MCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/NCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/NCmp.java new file mode 100644 index 000000000..7751181ba --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/NCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("n") +public class NCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("NCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/PCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/PCmp.java new file mode 100644 index 000000000..d3d93e283 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/PCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("p") +public class PCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("PCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/QCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/QCmp.java new file mode 100644 index 000000000..64130d2d8 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/QCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("q") +public class QCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("QCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/RCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/RCmp.java new file mode 100644 index 000000000..e278932e5 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/RCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("r") +public class RCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("RCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/XSwitchCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/XSwitchCmp.java new file mode 100644 index 000000000..60336ff02 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/XSwitchCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; +import org.noear.solon.annotation.Component; + +@Component("x") +public class XSwitchCmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + return "w01"; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/ZCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/ZCmp.java new file mode 100644 index 000000000..ba42dffc3 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/base/cmp/ZCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("z") +public class ZCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ZCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/BuilderELSpringbootTest1.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/BuilderELSpringbootTest1.java new file mode 100644 index 000000000..234ade252 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/BuilderELSpringbootTest1.java @@ -0,0 +1,162 @@ +package com.yomahub.liteflow.test.builder; + +import com.yomahub.liteflow.builder.LiteFlowNodeBuilder; +import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder; +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.enums.NodeTypeEnum; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import com.yomahub.liteflow.test.builder.cmp1.*; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; + +//基于builder模式的单元测试 +//这里只是最基本的builder模式的测试,只是为了验证在springboot模式下的正常性 +//更详细的builder模式测试用例会单独拉testcase去做 +@RunWith(SolonJUnit4ClassRunner.class) +public class BuilderELSpringbootTest1 extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //基于普通组件的builder模式测试 + @Test + public void testBuilder() throws Exception { + LiteFlowNodeBuilder.createNode().setId("a") + .setName("组件A") + .setType(NodeTypeEnum.COMMON) + .setClazz("com.yomahub.liteflow.test.builder.cmp1.ACmp") + .build(); + LiteFlowNodeBuilder.createNode().setId("b") + .setName("组件B") + .setType(NodeTypeEnum.COMMON) + .setClazz("com.yomahub.liteflow.test.builder.cmp1.BCmp") + .build(); + LiteFlowNodeBuilder.createNode().setId("c") + .setName("组件C") + .setType(NodeTypeEnum.COMMON) + .setClazz("com.yomahub.liteflow.test.builder.cmp1.CCmp") + .build(); + LiteFlowNodeBuilder.createNode().setId("d") + .setName("组件D") + .setType(NodeTypeEnum.COMMON) + .setClazz("com.yomahub.liteflow.test.builder.cmp1.DCmp") + .build(); + LiteFlowNodeBuilder.createNode().setId("e") + .setName("组件E") + .setType(NodeTypeEnum.SWITCH) + .setClazz("com.yomahub.liteflow.test.builder.cmp1.ECmp") + .build(); + LiteFlowNodeBuilder.createNode().setId("f") + .setName("组件F") + .setType(NodeTypeEnum.COMMON) + .setClazz("com.yomahub.liteflow.test.builder.cmp1.FCmp") + .build(); + LiteFlowNodeBuilder.createNode().setId("g") + .setName("组件G") + .setType(NodeTypeEnum.COMMON) + .setClazz("com.yomahub.liteflow.test.builder.cmp1.GCmp") + .build(); + + + LiteFlowChainELBuilder.createChain().setChainName("chain2").setEL( + "THEN(c, d)" + ).build(); + + LiteFlowChainELBuilder.createChain().setChainName("chain1").setEL( + "THEN(a, b, WHEN(SWITCH(e).to(f, g, chain2)))" + ).build(); + + LiteflowResponse response = flowExecutor.execute2Resp("chain1"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a[组件A]==>b[组件B]==>e[组件E]==>c[组件C]==>d[组件D]", response.getExecuteStepStr()); + } + + //基于普通组件的builder模式测试 + @Test + public void testBuilderForClassAndCode() throws Exception { + LiteFlowNodeBuilder.createNode().setId("a") + .setName("组件A") + .setType(NodeTypeEnum.COMMON) + .setClazz(ACmp.class) + .build(); + LiteFlowNodeBuilder.createNode().setId("b") + .setName("组件B") + .setType(NodeTypeEnum.COMMON) + .setClazz(BCmp.class) + .build(); + LiteFlowNodeBuilder.createNode().setId("c") + .setName("组件C") + .setType(NodeTypeEnum.COMMON) + .setClazz(CCmp.class) + .build(); + LiteFlowNodeBuilder.createNode().setId("d") + .setName("组件D") + .setType(NodeTypeEnum.COMMON) + .setClazz(DCmp.class) + .build(); + LiteFlowNodeBuilder.createNode().setId("e") + .setName("组件E") + .setType(NodeTypeEnum.SWITCH) + .setClazz(ECmp.class) + .build(); + LiteFlowNodeBuilder.createNode().setId("f") + .setName("组件F") + .setType(NodeTypeEnum.COMMON) + .setClazz(FCmp.class) + .build(); + LiteFlowNodeBuilder.createNode().setId("g") + .setName("组件G") + .setType(NodeTypeEnum.COMMON) + .setClazz(GCmp.class) + .build(); + + + LiteFlowChainELBuilder.createChain().setChainName("chain2").setEL( + "THEN(c, d)" + ).build(); + + LiteFlowChainELBuilder.createChain().setChainName("chain1").setEL( + "THEN(a, b, WHEN(SWITCH(e).to(f, g, chain2)))" + ).build(); + + LiteflowResponse response = flowExecutor.execute2Resp("chain1"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a[组件A]==>b[组件B]==>e[组件E]==>c[组件C]==>d[组件D]", response.getExecuteStepStr()); + } + + @Test + public void testBuilderForSameNodeMultiTimes() throws Exception { + LiteFlowNodeBuilder.createNode().setId("a1") + .setName("组件A1") + .setType(NodeTypeEnum.COMMON) + .setClazz(ACmp.class) + .build(); + LiteFlowNodeBuilder.createNode().setId("a2") + .setName("组件A2") + .setType(NodeTypeEnum.COMMON) + .setClazz(ACmp.class) + .build(); + LiteFlowNodeBuilder.createNode().setId("c1") + .setName("组件C1") + .setType(NodeTypeEnum.COMMON) + .setClazz(CCmp.class) + .build(); + LiteFlowNodeBuilder.createNode().setId("c2") + .setName("组件C2") + .setType(NodeTypeEnum.COMMON) + .setClazz(CCmp.class) + .build(); + + LiteFlowChainELBuilder.createChain().setChainName("chain1").setEL( + "THEN(a1,c2,a2,c1)" + ).build(); + + LiteflowResponse response = flowExecutor.execute2Resp("chain1"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a1[组件A1]==>c2[组件C2]==>a2[组件A2]==>c1[组件C1]", response.getExecuteStepStr()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/BuilderELSpringbootTest2.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/BuilderELSpringbootTest2.java new file mode 100644 index 000000000..7a706c858 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/BuilderELSpringbootTest2.java @@ -0,0 +1,34 @@ +package com.yomahub.liteflow.test.builder; + +import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder; +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; + +//基于builder模式的单元测试 +//这里测试的是通过spring去扫描,但是通过代码去构建chain的用例 +@RunWith(SolonJUnit4ClassRunner.class) +@Import(scanPackages = {"com.yomahub.liteflow.test.builder.cmp2"}) +public class BuilderELSpringbootTest2 extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //通过spring去扫描组件,通过代码去构建chain + @Test + public void testBuilder() throws Exception { + LiteFlowChainELBuilder.createChain().setChainName("chain1").setEL( + "THEN(h, i, j)" + ).build(); + + LiteflowResponse response = flowExecutor.execute2Resp("chain1"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("h==>i==>j", response.getExecuteStepStr()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/ACmp.java new file mode 100644 index 000000000..9fbbfba46 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/ACmp.java @@ -0,0 +1,18 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.builder.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; + +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/BCmp.java new file mode 100644 index 000000000..80568e476 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/BCmp.java @@ -0,0 +1,19 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.builder.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; + +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/CCmp.java new file mode 100644 index 000000000..595bc33b8 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/CCmp.java @@ -0,0 +1,19 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.builder.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; + +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/DCmp.java new file mode 100644 index 000000000..7ab4fee26 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/DCmp.java @@ -0,0 +1,19 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.builder.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; + +public class DCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("DCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/ECmp.java new file mode 100644 index 000000000..e30f7f831 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/ECmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.builder.cmp1; + +import com.yomahub.liteflow.core.NodeSwitchComponent; + +public class ECmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + System.out.println("ECmp executed!"); + return "chain2"; + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/FCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/FCmp.java new file mode 100644 index 000000000..6cd712581 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/FCmp.java @@ -0,0 +1,19 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.builder.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; + +public class FCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("FCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/GCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/GCmp.java new file mode 100644 index 000000000..577a21edc --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp1/GCmp.java @@ -0,0 +1,19 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.builder.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; + +public class GCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("GCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp2/HCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp2/HCmp.java new file mode 100644 index 000000000..4ce8c7d48 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp2/HCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.builder.cmp2; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("h") +public class HCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("HCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp2/ICmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp2/ICmp.java new file mode 100644 index 000000000..7f803a9fe --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp2/ICmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.builder.cmp2; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("i") +public class ICmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ICmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp2/JCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp2/JCmp.java new file mode 100644 index 000000000..78a8c0c89 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/builder/cmp2/JCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.builder.cmp2; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("j") +public class JCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("JCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpData/CmpDataELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpData/CmpDataELSpringbootTest.java new file mode 100644 index 000000000..e19d6d4f8 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpData/CmpDataELSpringbootTest.java @@ -0,0 +1,38 @@ +package com.yomahub.liteflow.test.cmpData; + +import cn.hutool.core.date.DateUtil; +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.BaseTest; +import com.yomahub.liteflow.test.cmpData.vo.User; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境EL常规的例子测试 + * @author Bryan.Zhang + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/cmpData/application.properties") +public class CmpDataELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //最简单的情况 + @Test + public void testCmpData() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + DefaultContext context = response.getFirstContextBean(); + User user = context.getData("user"); + Assert.assertEquals(27, user.getAge()); + Assert.assertEquals("jack", user.getName()); + Assert.assertEquals(0, user.getBirth().compareTo(DateUtil.parseDate("1995-10-01").toJdkDate())); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpData/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpData/cmp/ACmp.java new file mode 100644 index 000000000..9a1f091d9 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpData/cmp/ACmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.cmpData.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println(this.getCmpData(String.class)); + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpData/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpData/cmp/BCmp.java new file mode 100644 index 000000000..52e9aa0cf --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpData/cmp/BCmp.java @@ -0,0 +1,26 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.cmpData.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.cmpData.vo.User; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + User user = this.getCmpData(User.class); + DefaultContext context = this.getFirstContextBean(); + context.setData("user", user); + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpData/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpData/cmp/CCmp.java new file mode 100644 index 000000000..b164d7532 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpData/cmp/CCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.cmpData.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpData/vo/User.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpData/vo/User.java new file mode 100644 index 000000000..483a78dd6 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpData/vo/User.java @@ -0,0 +1,36 @@ +package com.yomahub.liteflow.test.cmpData.vo; + +import java.util.Date; + +public class User { + + private String name; + + private int age; + + private Date birth; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public Date getBirth() { + return birth; + } + + public void setBirth(Date birth) { + this.birth = birth; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/LiteflowRetryELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/LiteflowRetryELSpringbootTest.java new file mode 100644 index 000000000..9d26dcb56 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/LiteflowRetryELSpringbootTest.java @@ -0,0 +1,58 @@ +package com.yomahub.liteflow.test.cmpRetry; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.snack.ONode; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + + +/** + * 测试springboot下的节点执行器 + * @author Bryan.Zhang + * @since 2.5.10 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/cmpRetry/application.properties") +public class LiteflowRetryELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //全局重试配置测试 + @Test + public void testRetry1() { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + System.out.println(ONode.stringify(response)); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a==>b==>b==>b", response.getExecuteStepStr()); + } + + //单个组件重试配置测试 + @Test + public void testRetry2() { + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg"); + Assert.assertFalse(response.isSuccess()); + Assert.assertEquals("c==>c==>c==>c==>c==>c", response.getExecuteStepStr()); + } + + //单个组件指定异常,但抛出的并不是指定异常的场景测试 + @Test + public void testRetry3() { + LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg"); + Assert.assertFalse(response.isSuccess()); + } + + //单个组件指定异常重试,抛出的是指定异常或者 + @Test + public void testRetry4() { + LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg"); + Assert.assertFalse(response.isSuccess()); + Assert.assertEquals("e==>e==>e==>e==>e==>e", response.getExecuteStepStr()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/ACmp.java new file mode 100644 index 000000000..a1b1b3fb4 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.cmpRetry.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/BCmp.java new file mode 100644 index 000000000..3c50ded2d --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/BCmp.java @@ -0,0 +1,27 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.cmpRetry.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("b") +public class BCmp extends NodeComponent { + + private int flag = 0; + + @Override + public void process() { + System.out.println("BCmp executed!"); + if (flag < 2){ + flag++; + throw new RuntimeException("demo exception"); + } + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/CCmp.java new file mode 100644 index 000000000..89c59fba9 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/CCmp.java @@ -0,0 +1,24 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.cmpRetry.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.annotation.LiteflowRetry; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("c") +@LiteflowRetry(5) +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + throw new RuntimeException("demo exception"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/DCmp.java new file mode 100644 index 000000000..b9232e5ae --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/DCmp.java @@ -0,0 +1,24 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.cmpRetry.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.annotation.LiteflowRetry; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("d") +@LiteflowRetry(retry = 5, forExceptions = {NullPointerException.class}) +public class DCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("DCmp executed!"); + throw new RuntimeException("demo exception"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/ECmp.java new file mode 100644 index 000000000..ba3f92d65 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/ECmp.java @@ -0,0 +1,24 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.cmpRetry.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.annotation.LiteflowRetry; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("e") +@LiteflowRetry(retry = 5, forExceptions = {NullPointerException.class}) +public class ECmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ECmp executed!"); + throw new NullPointerException("demo null exception"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/CmpStepELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/CmpStepELSpringbootTest.java new file mode 100644 index 000000000..d28e207d2 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/CmpStepELSpringbootTest.java @@ -0,0 +1,71 @@ +package com.yomahub.liteflow.test.cmpStep; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.flow.entity.CmpStep; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +import java.util.HashSet; +import java.util.Map; +import java.util.Queue; +import java.util.Set; + +/** + * springboot环境step的测试例子 + * @author Bryan.Zhang + * @since 2.7.0 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/cmpStep/application.properties") +public class CmpStepELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //ab串行 + //cd并行,都抛错,其中c耗时2秒 + @Test + public void testStep1() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertFalse(response.isSuccess()); + Assert.assertTrue(response.getExecuteSteps().get("a").isSuccess()); + Assert.assertTrue(response.getExecuteSteps().get("b").isSuccess()); + Assert.assertFalse(response.getExecuteSteps().get("c").isSuccess()); + Assert.assertFalse(response.getExecuteSteps().get("d").isSuccess()); + Assert.assertTrue(response.getExecuteSteps().get("c").getTimeSpent() >= 2000); + Assert.assertEquals(RuntimeException.class, response.getExecuteSteps().get("c").getException().getClass()); + Assert.assertEquals(RuntimeException.class, response.getExecuteSteps().get("d").getException().getClass()); + } + + @Test + public void testStep2() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a==>b", response.getExecuteStepStrWithoutTime()); + } + + @Test + public void testStep3() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg"); + Assert.assertTrue(response.isSuccess()); + Map stepMap = response.getExecuteSteps(); + Assert.assertEquals(2, stepMap.size()); + Queue queue = response.getExecuteStepQueue(); + Assert.assertEquals(5, queue.size()); + + Set tagSet = new HashSet<>(); + response.getExecuteStepQueue().stream().filter( + cmpStep -> cmpStep.getNodeId().equals("a") + ).forEach(cmpStep -> tagSet.add(cmpStep.getTag())); + + Assert.assertEquals(3, tagSet.size()); + + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/cmp/ACmp.java new file mode 100644 index 000000000..b3f53165b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/cmp/ACmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.cmpStep.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() throws Exception{ + Thread.sleep(5000L); + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/cmp/BCmp.java new file mode 100644 index 000000000..48ecd7aad --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/cmp/BCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.cmpStep.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/cmp/CCmp.java new file mode 100644 index 000000000..2db8ed0d7 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/cmp/CCmp.java @@ -0,0 +1,23 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.cmpStep.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() throws Exception{ + System.out.println("CCmp executed!"); + Thread.sleep(2000); + throw new RuntimeException("test error c"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/cmp/DCmp.java new file mode 100644 index 000000000..a1330802d --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/cmp/DCmp.java @@ -0,0 +1,22 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.cmpStep.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("d") +public class DCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + throw new RuntimeException("test error d"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/cmp/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/cmp/ECmp.java new file mode 100644 index 000000000..70c596b71 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/cmpStep/cmp/ECmp.java @@ -0,0 +1,25 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.cmpStep.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("e") +public class ECmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ECmp executed!"); + } + + @Override + public boolean isAccess() { + return false; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/comments/LiteflowNodeELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/comments/LiteflowNodeELSpringbootTest.java new file mode 100644 index 000000000..6bdec3f9e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/comments/LiteflowNodeELSpringbootTest.java @@ -0,0 +1,28 @@ +package com.yomahub.liteflow.test.comments; + +import cn.hutool.core.collection.ListUtil; +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/comments/application.properties") +public class LiteflowNodeELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + // 测试注释 + @Test + public void testAsyncFlow1() { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "it's a base request"); + Assert.assertTrue(response.isSuccess()); + Assert.assertTrue(ListUtil.toList("a==>b==>c==>b","a==>b==>b==>c").contains(response.getExecuteStepStr())); + } +} \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/comments/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/comments/cmp/ACmp.java new file mode 100644 index 000000000..86a93c01a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/comments/cmp/ACmp.java @@ -0,0 +1,22 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.comments.cmp; + +import com.yomahub.liteflow.annotation.LiteflowMethod; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.enums.LiteFlowMethodEnum; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp{ + + @LiteflowMethod(LiteFlowMethodEnum.PROCESS) + public void process(NodeComponent bindCmp) { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/comments/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/comments/cmp/BCmp.java new file mode 100644 index 000000000..6d860cfeb --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/comments/cmp/BCmp.java @@ -0,0 +1,23 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.comments.cmp; + +import com.yomahub.liteflow.annotation.LiteflowMethod; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.enums.LiteFlowMethodEnum; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp{ + + @LiteflowMethod(LiteFlowMethodEnum.PROCESS) + public void process(NodeComponent bindCmp) { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/comments/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/comments/cmp/CCmp.java new file mode 100644 index 000000000..3652ceb9a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/comments/cmp/CCmp.java @@ -0,0 +1,23 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.comments.cmp; + +import com.yomahub.liteflow.annotation.LiteflowMethod; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.enums.LiteFlowMethodEnum; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp{ + + @LiteflowMethod(LiteFlowMethodEnum.PROCESS) + public void process(NodeComponent bindCmp) { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/ComplexELSpringbootTest1.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/ComplexELSpringbootTest1.java new file mode 100644 index 000000000..37c3ec699 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/ComplexELSpringbootTest1.java @@ -0,0 +1,42 @@ +package com.yomahub.liteflow.test.complex; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境EL复杂例子测试1 + * @author Bryan.Zhang + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/complex/application1.properties") +public class ComplexELSpringbootTest1 extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //测试复杂例子,优化前 + //案例来自于文档中 EL规则写法/复杂编排例子/复杂例子一 + //因为所有的组件都是空执行,你可以在组件里加上Thread.sleep来模拟业务耗时,再来看这个打出结果 + @Test + public void testComplex1_1() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1_1", "arg"); + Assert.assertTrue(response.isSuccess()); + } + + //测试复杂例子,优化后 + //案例来自于文档中 EL规则写法/复杂编排例子/复杂例子一 + //因为所有的组件都是空执行,你可以在组件里加上Thread.sleep来模拟业务耗时,再来看这个打出结果 + @Test + public void testComplex1_2() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1_2", "arg"); + Assert.assertTrue(response.isSuccess()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/ACmp.java new file mode 100644 index 000000000..46ffa923a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.complex.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("A") +public class ACmp extends NodeComponent { + + @Override + public void process() { + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/BCmp.java new file mode 100644 index 000000000..50ca54dbf --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/BCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.complex.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("B") +public class BCmp extends NodeComponent { + + @Override + public void process() { + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/CCmp.java new file mode 100644 index 000000000..d46c6d9f1 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/CCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.complex.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("C") +public class CCmp extends NodeComponent { + + @Override + public void process() { + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/DCmp.java new file mode 100644 index 000000000..64ac0e29c --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/DCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.complex.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("D") +public class DCmp extends NodeComponent { + + @Override + public void process() { + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/ECmp.java new file mode 100644 index 000000000..cb178ef97 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/ECmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.complex.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("E") +public class ECmp extends NodeComponent { + + @Override + public void process() { + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/FCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/FCmp.java new file mode 100644 index 000000000..bb5c8d109 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/FCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.complex.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("F") +public class FCmp extends NodeComponent { + + @Override + public void process() { + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/GCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/GCmp.java new file mode 100644 index 000000000..cc132b22c --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/GCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.complex.cmp1; + +import com.yomahub.liteflow.core.NodeSwitchComponent; +import org.noear.solon.annotation.Component; + +@Component("G") +public class GCmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + return "t1"; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/HCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/HCmp.java new file mode 100644 index 000000000..78e5d72c2 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/HCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.complex.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("H") +public class HCmp extends NodeComponent { + + @Override + public void process() { + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/ICmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/ICmp.java new file mode 100644 index 000000000..18bf8d677 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/ICmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.complex.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("I") +public class ICmp extends NodeComponent { + + @Override + public void process() { + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/JCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/JCmp.java new file mode 100644 index 000000000..7f7e952b1 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/JCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.complex.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("J") +public class JCmp extends NodeComponent { + + @Override + public void process() { + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/KCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/KCmp.java new file mode 100644 index 000000000..c8499e7a0 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/KCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.complex.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("K") +public class KCmp extends NodeComponent { + + @Override + public void process() { + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/LCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/LCmp.java new file mode 100644 index 000000000..467813cb1 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/LCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.complex.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("L") +public class LCmp extends NodeComponent { + + @Override + public void process() { + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/MCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/MCmp.java new file mode 100644 index 000000000..b0b0ec353 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/MCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.complex.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("M") +public class MCmp extends NodeComponent { + + @Override + public void process() { + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/NCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/NCmp.java new file mode 100644 index 000000000..5444a87e0 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/NCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.complex.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("N") +public class NCmp extends NodeComponent { + + @Override + public void process() { + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/ZCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/ZCmp.java new file mode 100644 index 000000000..aa8ab2164 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/complex/cmp1/ZCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.complex.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("Z") +public class ZCmp extends NodeComponent { + + @Override + public void process() { + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/FlowExecutorELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/FlowExecutorELSpringbootTest.java new file mode 100644 index 000000000..0ee04baea --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/FlowExecutorELSpringbootTest.java @@ -0,0 +1,79 @@ +package com.yomahub.liteflow.test.component; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 组件功能点测试 + * 单元测试 + * + * @author donguo.tao + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/component/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.component.cmp1","com.yomahub.liteflow.test.component.cmp2"}) +public class FlowExecutorELSpringbootTest extends BaseTest { + private static final Logger LOG = LoggerFactory.getLogger(FlowExecutorELSpringbootTest.class); + + @Inject + private FlowExecutor flowExecutor; + + //isAccess方法的功能测试 + @Test + public void testIsAccess() { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", 101); + Assert.assertTrue(response.isSuccess()); + Assert.assertNotNull(response.getSlot().getResponseData()); + } + + + //isContinueOnError方法的功能点测试 + @Test + public void testIsContinueOnError() throws Exception { + LiteflowResponse response = flowExecutor.execute2Resp("chain3", 0); + Assert.assertTrue(response.isSuccess()); + Assert.assertNull(response.getCause()); + } + + //isEnd方法的功能点测试 + @Test + public void testIsEnd() throws Exception { + LiteflowResponse response = flowExecutor.execute2Resp("chain4", 10); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("d",response.getExecuteStepStr()); + } + + //setIsEnd方法的功能点测试 + @Test + public void testSetIsEnd1() throws Exception { + LiteflowResponse response = flowExecutor.execute2Resp("chain5", 10); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("e",response.getExecuteStepStr()); + } + + //条件组件的功能点测试 + @Test + public void testNodeCondComponent() { + LiteflowResponse response = flowExecutor.execute2Resp("chain6", 0); + Assert.assertTrue(response.isSuccess()); + } + + //测试setIsEnd如果为true,continueError也为true,那不应该continue了 + @Test + public void testSetIsEnd2() throws Exception { + LiteflowResponse response = flowExecutor.execute2Resp("chain7", 10); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("g",response.getExecuteStepStr()); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/ACmp.java new file mode 100644 index 000000000..6c0ac6d4a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/ACmp.java @@ -0,0 +1,26 @@ +package com.yomahub.liteflow.test.component.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +import java.util.Objects; + + +@Component("a") +public class ACmp extends NodeComponent { + @Override + public void process() { + System.out.println("AComp executed!"); + this.getSlot().setResponseData("AComp executed!"); + } + + @Override + public boolean isAccess() { + Integer requestData = this.getRequestData(); + if (Objects.nonNull(requestData) && requestData > 100){ + return true; + } + System.out.println("AComp isAccess false."); + return false; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/BCmp.java new file mode 100644 index 000000000..9374c4a0e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/BCmp.java @@ -0,0 +1,29 @@ +package com.yomahub.liteflow.test.component.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +import java.util.Objects; + + +@Component("b") +public class BCmp extends NodeComponent { + @Override + public void process() { + System.out.println("BComp executed!"); + Integer requestData = this.getRequestData(); + Integer divisor = 130; + Integer result = divisor / requestData; + this.getSlot().setResponseData(result); + } + + @Override + public boolean isAccess() { + Integer requestData = this.getRequestData(); + if (Objects.nonNull(requestData)){ + return true; + } + return false; + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/CCmp.java new file mode 100644 index 000000000..d9f19f54d --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/CCmp.java @@ -0,0 +1,29 @@ +package com.yomahub.liteflow.test.component.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +import java.util.Objects; + + +@Component("c") +public class CCmp extends NodeComponent { + @Override + public void process() { + System.out.println("CComp executed!"); + Integer requestData = this.getRequestData(); + Integer divisor = 130; + Integer result = divisor / requestData; + this.getSlot().setResponseData(result); + System.out.println("responseData="+Integer.parseInt(this.getSlot().getResponseData())); + } + + @Override + public boolean isContinueOnError() { + Integer requestData = this.getRequestData(); + if (Objects.nonNull(requestData)){ + return true; + } + return false; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/DCmp.java new file mode 100644 index 000000000..e1471cd42 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/DCmp.java @@ -0,0 +1,26 @@ +package com.yomahub.liteflow.test.component.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +import java.util.Objects; + + +@Component("d") +public class DCmp extends NodeComponent { + @Override + public void process() throws Exception { + System.out.println("DComp executed!"); + } + + @Override + public boolean isEnd() { + //组件的process执行完之后才会执行isEnd + Object requestData = this.getSlot().getResponseData(); + if (Objects.isNull(requestData)){ + System.out.println("DComp flow isEnd, because of responseData is null."); + return true; + } + return false; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/ECmp.java new file mode 100644 index 000000000..3cf1ec009 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/ECmp.java @@ -0,0 +1,24 @@ +package com.yomahub.liteflow.test.component.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.util.JsonUtil; +import org.noear.solon.annotation.Component; + +import java.util.Objects; + + +@Component("e") +public class ECmp extends NodeComponent { + + @Override + public void process() throws Exception { + System.out.println("EComp executed!"); + Object responseData = this.getSlot().getResponseData(); + if (Objects.isNull(responseData)){ + System.out.println("EComp responseData flow must be set end ."); + //执行到某个条件时,手动结束流程。 + this.setIsEnd(true); + } + System.out.println("EComp responseData responseData=" + JsonUtil.toJsonString(responseData)); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/GCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/GCmp.java new file mode 100644 index 000000000..01c1fd2ef --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/GCmp.java @@ -0,0 +1,26 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.component.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("g") +public class GCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("GCmp executed!"); + this.setIsEnd(true); + } + + @Override + public boolean isContinueOnError() { + return true; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/HCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/HCmp.java new file mode 100644 index 000000000..8038b4228 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp1/HCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.component.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("h") +public class HCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("HCmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp2/FSwitchCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp2/FSwitchCmp.java new file mode 100644 index 000000000..e7093fd59 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/component/cmp2/FSwitchCmp.java @@ -0,0 +1,22 @@ +package com.yomahub.liteflow.test.component.cmp2; + +import com.yomahub.liteflow.core.NodeSwitchComponent; +import org.noear.solon.annotation.Component; + +import java.util.Objects; + + +@Component("f") +public class FSwitchCmp extends NodeSwitchComponent { + @Override + public String processSwitch() { + Integer requestData = this.getRequestData(); + if (Objects.isNull(requestData)){ + return "d"; + } else if(requestData == 0){ + return "c"; + } else { + return "b"; + } + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/CustomNodesELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/CustomNodesELSpringbootTest.java new file mode 100644 index 000000000..a9fbb3c1f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/CustomNodesELSpringbootTest.java @@ -0,0 +1,39 @@ +package com.yomahub.liteflow.test.customNodes; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * springboot环境下自定义声明节点的测试 + * 不通过spring扫描的方式,通过在配置文件里定义nodes的方式 + * @author Bryan.Zhang + * @since 2.6.4 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/customNodes/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.customNodes.domain"}) +public class CustomNodesELSpringbootTest extends BaseTest { + + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + @Inject + private FlowExecutor flowExecutor; + + @Test + public void testCustomNodes() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + response = flowExecutor.execute2Resp("chain2", "arg"); + Assert.assertTrue(response.isSuccess()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/ACmp.java new file mode 100644 index 000000000..d7cf0644f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/ACmp.java @@ -0,0 +1,18 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.customNodes.cmp; + +import com.yomahub.liteflow.core.NodeComponent; + +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/BCmp.java new file mode 100644 index 000000000..fbb6919dd --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/BCmp.java @@ -0,0 +1,25 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.customNodes.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.test.customNodes.domain.DemoDomain; +import org.noear.solon.annotation.Inject; + +public class BCmp extends NodeComponent { + + @Inject + private DemoDomain demoDomain; + + @Override + public void process() { + demoDomain.sayHi(); + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/CCmp.java new file mode 100644 index 000000000..9913ec102 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/CCmp.java @@ -0,0 +1,19 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.customNodes.cmp; + +import com.yomahub.liteflow.core.NodeComponent; + +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/DCmp.java new file mode 100644 index 000000000..cc6000418 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/DCmp.java @@ -0,0 +1,19 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.customNodes.cmp; + +import com.yomahub.liteflow.core.NodeComponent; + +public class DCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("DCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/ECmp.java new file mode 100644 index 000000000..9750ada04 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/ECmp.java @@ -0,0 +1,25 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.customNodes.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.test.customNodes.domain.DemoDomain; +import org.noear.solon.annotation.Inject; + +public class ECmp extends NodeComponent { + + @Inject + private DemoDomain demoDomain; + + @Override + public void process() { + demoDomain.sayHi(); + System.out.println("ECmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/FCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/FCmp.java new file mode 100644 index 000000000..de5c0820d --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/FCmp.java @@ -0,0 +1,19 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.customNodes.cmp; + +import com.yomahub.liteflow.core.NodeComponent; + +public class FCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("FCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/domain/DemoDomain.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/domain/DemoDomain.java new file mode 100644 index 000000000..d13d225dd --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customNodes/domain/DemoDomain.java @@ -0,0 +1,11 @@ +package com.yomahub.liteflow.test.customNodes.domain; + +import org.noear.solon.annotation.Component; + +@Component +public class DemoDomain { + + public void sayHi(){ + System.out.println("hi"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomThreadExecutor1.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomThreadExecutor1.java new file mode 100644 index 000000000..6f88c4cdd --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomThreadExecutor1.java @@ -0,0 +1,25 @@ +package com.yomahub.liteflow.test.customWhenThreadPool; + +import cn.hutool.core.util.ObjectUtil; +import com.yomahub.liteflow.property.LiteflowConfig; +import com.yomahub.liteflow.property.LiteflowConfigGetter; +import com.yomahub.liteflow.thread.ExecutorBuilder; + +import java.util.concurrent.ExecutorService; + +public class CustomThreadExecutor1 implements ExecutorBuilder { + + @Override + public ExecutorService buildExecutor() { + LiteflowConfig liteflowConfig = LiteflowConfigGetter.get(); + //只有在非spring的场景下liteflowConfig才会为null + if (ObjectUtil.isNull(liteflowConfig)) { + liteflowConfig = new LiteflowConfig(); + } + return buildDefaultExecutor( + liteflowConfig.getWhenMaxWorkers(), + liteflowConfig.getWhenMaxWorkers(), + liteflowConfig.getWhenQueueLimit(), + "customer-when-1-thead-"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomThreadExecutor2.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomThreadExecutor2.java new file mode 100644 index 000000000..7d45e4ad5 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomThreadExecutor2.java @@ -0,0 +1,24 @@ +package com.yomahub.liteflow.test.customWhenThreadPool; + +import cn.hutool.core.util.ObjectUtil; +import com.yomahub.liteflow.property.LiteflowConfig; +import com.yomahub.liteflow.property.LiteflowConfigGetter; +import com.yomahub.liteflow.thread.ExecutorBuilder; + +import java.util.concurrent.ExecutorService; + +public class CustomThreadExecutor2 implements ExecutorBuilder { + @Override + public ExecutorService buildExecutor() { + LiteflowConfig liteflowConfig = LiteflowConfigGetter.get(); + //只有在非spring的场景下liteflowConfig才会为null + if (ObjectUtil.isNull(liteflowConfig)) { + liteflowConfig = new LiteflowConfig(); + } + return buildDefaultExecutor( + liteflowConfig.getWhenMaxWorkers(), + liteflowConfig.getWhenMaxWorkers(), + liteflowConfig.getWhenQueueLimit(), + "customer-when-2-thead-"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomThreadExecutor3.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomThreadExecutor3.java new file mode 100644 index 000000000..875dc3d1d --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomThreadExecutor3.java @@ -0,0 +1,24 @@ +package com.yomahub.liteflow.test.customWhenThreadPool; + +import cn.hutool.core.util.ObjectUtil; +import com.yomahub.liteflow.property.LiteflowConfig; +import com.yomahub.liteflow.property.LiteflowConfigGetter; +import com.yomahub.liteflow.thread.ExecutorBuilder; + +import java.util.concurrent.ExecutorService; + +public class CustomThreadExecutor3 implements ExecutorBuilder { + @Override + public ExecutorService buildExecutor() { + LiteflowConfig liteflowConfig = LiteflowConfigGetter.get(); + //只有在非spring的场景下liteflowConfig才会为null + if (ObjectUtil.isNull(liteflowConfig)) { + liteflowConfig = new LiteflowConfig(); + } + return buildDefaultExecutor( + liteflowConfig.getWhenMaxWorkers(), + liteflowConfig.getWhenMaxWorkers(), + liteflowConfig.getWhenQueueLimit(), + "customer-when-3-thead-"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomWhenThreadPoolELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomWhenThreadPoolELSpringbootTest.java new file mode 100644 index 000000000..aebcda78c --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomWhenThreadPoolELSpringbootTest.java @@ -0,0 +1,70 @@ +package com.yomahub.liteflow.test.customWhenThreadPool; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * springboot环境下异步线程超时日志打印测试 + * + * @author Bryan.Zhang + * @since 2.6.4 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/customWhenThreadPool/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.customWhenThreadPool.cmp"}) +public class CustomWhenThreadPoolELSpringbootTest extends BaseTest { + + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + @Inject + private FlowExecutor flowExecutor; + + /** + * 测试全局线程池配置 + */ + @Test + public void testGlobalThreadPool() { + LiteflowResponse response = flowExecutor.execute2Resp("chain", "arg"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertTrue(response.isSuccess()); + Assert.assertTrue(context.getData("threadName").toString().startsWith("lf-when-thead")); + } + + /** + * 测试全局和when上自定义线程池-优先以when上为准 + */ + @Test + public void testGlobalAndCustomWhenThreadPool() { + LiteflowResponse response1 = flowExecutor.execute2Resp("chain1", "arg"); + DefaultContext context = response1.getFirstContextBean(); + Assert.assertTrue(response1.isSuccess()); + Assert.assertTrue(context.getData("threadName").toString().startsWith("customer-when-1-thead")); + } + + + /** + * when配置的线程池可以共用 + */ + @Test + public void testCustomWhenThreadPool() { + // 使用when - thread1 + testGlobalAndCustomWhenThreadPool(); + // chain配置同一个thead1 + LiteflowResponse response2 = flowExecutor.execute2Resp("chain2", "arg"); + DefaultContext context = response2.getFirstContextBean(); + Assert.assertTrue(response2.isSuccess()); + Assert.assertTrue(context.getData("threadName").toString().startsWith("customer-when-1-thead")); + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/ACmp.java new file mode 100644 index 000000000..69a33c52c --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.customWhenThreadPool.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/BCmp.java new file mode 100644 index 000000000..338b97cb4 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/BCmp.java @@ -0,0 +1,24 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.customWhenThreadPool.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + context.setData("threadName", Thread.currentThread().getName()); + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/CCmp.java new file mode 100644 index 000000000..3386e097f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/CCmp.java @@ -0,0 +1,24 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.customWhenThreadPool.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + context.setData("threadName", Thread.currentThread().getName()); + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/DCmp.java new file mode 100644 index 000000000..73f008713 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/DCmp.java @@ -0,0 +1,24 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.customWhenThreadPool.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("d") +public class DCmp extends NodeComponent { + + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + context.setData("threadName", Thread.currentThread().getName()); + System.out.println("DCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/ECmp.java new file mode 100644 index 000000000..7de55ccd3 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/ECmp.java @@ -0,0 +1,24 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.customWhenThreadPool.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("e") +public class ECmp extends NodeComponent { + + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + context.setData("threadName", Thread.currentThread().getName()); + System.out.println("ECmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/FCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/FCmp.java new file mode 100644 index 000000000..06f1b1637 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/FCmp.java @@ -0,0 +1,24 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.customWhenThreadPool.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("f") +public class FCmp extends NodeComponent { + + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + context.setData("threadName", Thread.currentThread().getName()); + System.out.println("FCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/EventELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/EventELSpringbootTest.java new file mode 100644 index 000000000..1ef31b69e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/EventELSpringbootTest.java @@ -0,0 +1,59 @@ +package com.yomahub.liteflow.test.event; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境事件回调测试 + * @author Bryan.Zhang + * @since 2.7.1 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/event/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.event.cmp"}) +public class EventELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //测试组件成功事件 + @Test + public void testEvent1() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("abc", context.getData("test")); + } + + //测试组件失败事件 + @Test + public void testEvent2() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertFalse(response.isSuccess()); + Assert.assertEquals(NullPointerException.class, response.getCause().getClass()); + Assert.assertEquals("ab", context.getData("test")); + Assert.assertEquals("error:d", context.getData("error")); + } + + //测试组件失败事件本身抛出异常 + @Test + public void testEvent3() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertFalse(response.isSuccess()); + Assert.assertEquals(NullPointerException.class, response.getCause().getClass()); + Assert.assertEquals("a", context.getData("test")); + Assert.assertEquals("error:e", context.getData("error")); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/cmp/ACmp.java new file mode 100644 index 000000000..bc9ab1469 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/cmp/ACmp.java @@ -0,0 +1,31 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.event.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + context.setData("test",""); + System.out.println("ACmp executed!"); + } + + @Override + public void onSuccess() throws Exception { + DefaultContext context = this.getFirstContextBean(); + String str = context.getData("test"); + str += this.getNodeId(); + context.setData("test", str); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/cmp/BCmp.java new file mode 100644 index 000000000..d6f69b7f5 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/cmp/BCmp.java @@ -0,0 +1,29 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.event.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + } + + @Override + public void onSuccess() throws Exception { + DefaultContext context = this.getFirstContextBean(); + String str = context.getData("test"); + str += this.getNodeId(); + context.setData("test", str); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/cmp/CCmp.java new file mode 100644 index 000000000..1ec09c253 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/cmp/CCmp.java @@ -0,0 +1,29 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.event.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + + @Override + public void onSuccess() throws Exception { + DefaultContext context = this.getFirstContextBean(); + String str = context.getData("test"); + str += this.getNodeId(); + context.setData("test", str); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/cmp/DCmp.java new file mode 100644 index 000000000..e57c0c9c3 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/cmp/DCmp.java @@ -0,0 +1,28 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.event.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("d") +public class DCmp extends NodeComponent { + + @Override + public void process() throws Exception{ + System.out.println("CCmp executed!"); + throw new NullPointerException(); + } + + @Override + public void onError() throws Exception { + DefaultContext context = this.getFirstContextBean(); + context.setData("error","error:"+this.getNodeId()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/cmp/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/cmp/ECmp.java new file mode 100644 index 000000000..e54b28a6d --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/event/cmp/ECmp.java @@ -0,0 +1,29 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.event.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("e") +public class ECmp extends NodeComponent { + + @Override + public void process() throws Exception{ + System.out.println("CCmp executed!"); + throw new NullPointerException(); + } + + @Override + public void onError() throws Exception { + DefaultContext context = this.getFirstContextBean(); + context.setData("error","error:"+this.getNodeId()); + throw new IllegalAccessException("错误事件回调本身抛出异常"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/CustomStatefulException.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/CustomStatefulException.java new file mode 100644 index 000000000..11441ab58 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/CustomStatefulException.java @@ -0,0 +1,12 @@ +package com.yomahub.liteflow.test.exception; + +import com.yomahub.liteflow.exception.LiteFlowException; + +/** + * 用户自定义带状态码的异常 + */ +public class CustomStatefulException extends LiteFlowException { + public CustomStatefulException(String code, String message) { + super(code, message); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/Exception1ELSpringBootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/Exception1ELSpringBootTest.java new file mode 100644 index 000000000..5441ca26c --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/Exception1ELSpringBootTest.java @@ -0,0 +1,60 @@ +package com.yomahub.liteflow.test.exception; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.exception.ChainDuplicateException; +import com.yomahub.liteflow.exception.ConfigErrorException; +import com.yomahub.liteflow.exception.FlowExecutorNotInitException; +import com.yomahub.liteflow.exception.FlowSystemException; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.property.LiteflowConfig; +import com.yomahub.liteflow.property.LiteflowConfigGetter; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; + +/** + * 流程执行异常 + * 单元测试 + * + * @author zendwang + */ +@RunWith(SolonJUnit4ClassRunner.class) +public class Exception1ELSpringBootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + /** + * 验证 chain 节点重复的异常 + */ + @Test(expected = ChainDuplicateException.class) + public void testChainDuplicateException() { + LiteflowConfig config = LiteflowConfigGetter.get(); + config.setRuleSource("exception/flow-exception.el.xml"); + flowExecutor.reloadRule(); + } + + @Test(expected = ConfigErrorException.class) + public void testConfigErrorException() { + flowExecutor.setLiteflowConfig(null); + flowExecutor.reloadRule(); + } + + @Test(expected = FlowExecutorNotInitException.class) + public void testFlowExecutorNotInitException() { + LiteflowConfig config = LiteflowConfigGetter.get(); + config.setRuleSource("error/flow.txt"); + flowExecutor.reloadRule(); + } + + @Test(expected = FlowExecutorNotInitException.class) + public void testNoConditionInChainException() throws Exception { + LiteflowConfig config = LiteflowConfigGetter.get(); + config.setRuleSource("exception/flow-blank.el.xml"); + flowExecutor.reloadRule(); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/Exception2ELSpringBootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/Exception2ELSpringBootTest.java new file mode 100644 index 000000000..0e844f81a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/Exception2ELSpringBootTest.java @@ -0,0 +1,77 @@ +package com.yomahub.liteflow.test.exception; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.exception.ChainNotFoundException; +import com.yomahub.liteflow.exception.FlowSystemException; +import com.yomahub.liteflow.exception.LiteFlowException; +import com.yomahub.liteflow.exception.NoSwitchTargetNodeException; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.core.AopContext; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * 流程执行异常 + * 单元测试 + * + * @author zendwang + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/exception/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.exception.cmp"}) +public class Exception2ELSpringBootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + @Inject + private AopContext context; + + @Test(expected = ChainNotFoundException.class) + public void testChainNotFoundException() throws Exception { + flowExecutor.execute("chain0", "it's a request"); + } + + @Test(expected = RuntimeException.class) + public void testComponentCustomException() throws Exception { + flowExecutor.execute("chain1", "exception"); + } + + @Test + public void testGetSlotFromResponseWhenException() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain4", "test"); + Assert.assertFalse(response.isSuccess()); + Assert.assertNotNull(response.getCause()); + Assert.assertNotNull(response.getSlot()); + } + + @Test(expected = NoSwitchTargetNodeException.class) + public void testNoTargetFindException() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain5", "test"); + Assert.assertFalse(response.isSuccess()); + throw response.getCause(); + } + + @Test + public void testInvokeCustomStatefulException() { + LiteflowResponse response = flowExecutor.execute2Resp("chain6", "custom-stateful-exception"); + Assert.assertFalse(response.isSuccess()); + Assert.assertEquals("300", response.getCode()); + Assert.assertNotNull(response.getCause()); + Assert.assertTrue(response.getCause() instanceof LiteFlowException); + Assert.assertNotNull(response.getSlot()); + } + + @Test + public void testNotInvokeCustomStatefulException() { + LiteflowResponse response = flowExecutor.execute2Resp("chain6", "test"); + Assert.assertTrue(response.isSuccess()); + Assert.assertNull(response.getCode()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/ACmp.java new file mode 100644 index 000000000..54110635d --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/ACmp.java @@ -0,0 +1,30 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.exception.cmp; + +import cn.hutool.core.util.StrUtil; +import com.yomahub.liteflow.core.NodeComponent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + private static final Logger LOG = LoggerFactory.getLogger(ACmp.class); + + @Override + public void process() { + String str = this.getRequestData(); + if(StrUtil.isNotBlank(str) && str.equals("exception")) { + throw new RuntimeException("chain execute execption"); + } + LOG.info("Acomp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/BCmp.java new file mode 100644 index 000000000..d09c1f110 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/BCmp.java @@ -0,0 +1,35 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.exception.cmp; + +import cn.hutool.core.util.StrUtil; +import com.yomahub.liteflow.core.NodeComponent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + private static final Logger LOG = LoggerFactory.getLogger(BCmp.class); + + @Override + public void process() throws InterruptedException { + String str = this.getRequestData(); + if(StrUtil.isNotBlank(str) && str.equals("when")) { + try { + LOG.info("Bcomp sleep begin"); + Thread.sleep(3000); + LOG.info("Bcomp sleep end"); + } catch (InterruptedException e) { + throw e; + } + } + LOG.info("Bcomp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/CCmp.java new file mode 100644 index 000000000..aec2f64b8 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/CCmp.java @@ -0,0 +1,24 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.exception.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + private static final Logger LOG = LoggerFactory.getLogger(CCmp.class); + + @Override + public void process() { + LOG.info("Ccomp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/DCmp.java new file mode 100644 index 000000000..b4ddc3cca --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/DCmp.java @@ -0,0 +1,27 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.exception.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.noear.solon.annotation.Component; + +@Component("d") +public class DCmp extends NodeComponent { + + private static final Logger LOG = LoggerFactory.getLogger(DCmp.class); + + @Override + public void process() { + if(1==1){ + int a = 1/0; + } + LOG.info("Dcomp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/ECmp.java new file mode 100644 index 000000000..a7443cd26 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/ECmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.exception.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; +import org.noear.solon.annotation.Component; + +@Component("e") +public class ECmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + return "a"; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/FCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/FCmp.java new file mode 100644 index 000000000..ca9ad3093 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/FCmp.java @@ -0,0 +1,31 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.exception.cmp; + +import cn.hutool.core.util.StrUtil; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.test.exception.CustomStatefulException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.noear.solon.annotation.Component; + +@Component("f") +public class FCmp extends NodeComponent { + + private static final Logger LOG = LoggerFactory.getLogger(FCmp.class); + + @Override + public void process() { + String str = this.getRequestData(); + if(StrUtil.isNotBlank(str) && str.equals("custom-stateful-exception")) { + throw new CustomStatefulException("300", "chain execute custom stateful execption"); + } + LOG.info("Fcomp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/GCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/GCmp.java new file mode 100644 index 000000000..82f53e5a6 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/exception/cmp/GCmp.java @@ -0,0 +1,24 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.exception.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.noear.solon.annotation.Component; + +@Component("g") +public class GCmp extends NodeComponent { + + private static final Logger LOG = LoggerFactory.getLogger(GCmp.class); + + @Override + public void process() { + LOG.info("Gcomp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/execute2Future/Executor2FutureELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/execute2Future/Executor2FutureELSpringbootTest.java new file mode 100644 index 000000000..36df494c7 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/execute2Future/Executor2FutureELSpringbootTest.java @@ -0,0 +1,36 @@ +package com.yomahub.liteflow.test.execute2Future; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; +import java.util.concurrent.Future; + +/** + * springboot环境执行返回future的例子 + * @author Bryan.Zhang + * @since 2.6.13 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/execute2Future/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.execute2Future.cmp"}) +public class Executor2FutureELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + @Test + public void testFuture() throws Exception{ + Future future = flowExecutor.execute2Future("chain1", "arg", DefaultContext.class); + LiteflowResponse response = future.get(); + Assert.assertTrue(response.isSuccess()); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/execute2Future/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/execute2Future/cmp/ACmp.java new file mode 100644 index 000000000..db0bc1f40 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/execute2Future/cmp/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.execute2Future.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/execute2Future/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/execute2Future/cmp/BCmp.java new file mode 100644 index 000000000..62edee831 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/execute2Future/cmp/BCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.execute2Future.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/execute2Future/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/execute2Future/cmp/CCmp.java new file mode 100644 index 000000000..26647a8b4 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/execute2Future/cmp/CCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.execute2Future.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/execute2Future/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/execute2Future/cmp/DCmp.java new file mode 100644 index 000000000..4ea514978 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/execute2Future/cmp/DCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.execute2Future.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("d") +public class DCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/GetChainNameELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/GetChainNameELSpringbootTest.java new file mode 100644 index 000000000..f8297a228 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/GetChainNameELSpringbootTest.java @@ -0,0 +1,55 @@ +package com.yomahub.liteflow.test.getChainName; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境获取ChainName的测试 + * @author Bryan.Zhang + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/getChainName/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.getChainName.cmp"}) +public class GetChainNameELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + @Test + public void testGetChainName1() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("sub1", context.getData("a")); + Assert.assertEquals("sub2", context.getData("b")); + Assert.assertEquals("sub3", context.getData("c")); + Assert.assertEquals("sub4", context.getData("d")); + } + + @Test + public void testGetChainName2() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("chain2", context.getData("g")); + Assert.assertEquals("sub1", context.getData("a")); + Assert.assertEquals("sub2", context.getData("b")); + Assert.assertEquals("sub3", context.getData("c")); + Assert.assertEquals("sub4", context.getData("d")); + Assert.assertEquals("sub5", context.getData("f")); + Assert.assertEquals("sub5_chain2", context.getData("e")); + Assert.assertEquals("sub6", context.getData("h")); + Assert.assertEquals("sub6", context.getData("j")); + Assert.assertNull(context.getData("k")); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/ACmp.java new file mode 100644 index 000000000..ff9961ecc --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/ACmp.java @@ -0,0 +1,22 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.getChainName.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + context.setData(this.getNodeId(), this.getCurrChainId()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/BCmp.java new file mode 100644 index 000000000..2dedf6480 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/BCmp.java @@ -0,0 +1,23 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.getChainName.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + context.setData(this.getNodeId(), this.getCurrChainId()); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/CCmp.java new file mode 100644 index 000000000..c882ac41f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/CCmp.java @@ -0,0 +1,23 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.getChainName.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + context.setData(this.getNodeId(), this.getCurrChainId()); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/DCmp.java new file mode 100644 index 000000000..b850219b7 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/DCmp.java @@ -0,0 +1,23 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.getChainName.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("d") +public class DCmp extends NodeComponent { + + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + context.setData(this.getNodeId(), this.getCurrChainId()); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/ECmp.java new file mode 100644 index 000000000..0117d51cf --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/ECmp.java @@ -0,0 +1,27 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.getChainName.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("e") +public class ECmp extends NodeComponent { + + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + if (context.hasData(this.getNodeId())){ + context.setData(this.getNodeId(), context.getData(this.getNodeId()) + "_" + this.getCurrChainId()); + }else{ + context.setData(this.getNodeId(), this.getCurrChainId()); + } + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/FCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/FCmp.java new file mode 100644 index 000000000..5209f45a7 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/FCmp.java @@ -0,0 +1,23 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.getChainName.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("f") +public class FCmp extends NodeComponent { + + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + context.setData(this.getNodeId(), this.getCurrChainId()); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/GCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/GCmp.java new file mode 100644 index 000000000..7bfa11d47 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/GCmp.java @@ -0,0 +1,23 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.getChainName.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("g") +public class GCmp extends NodeComponent { + + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + context.setData(this.getNodeId(), this.getCurrChainId()); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/HCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/HCmp.java new file mode 100644 index 000000000..b589b1c8b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/HCmp.java @@ -0,0 +1,24 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.getChainName.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("h") +public class HCmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + DefaultContext context = this.getFirstContextBean(); + context.setData(this.getNodeId(), this.getCurrChainId()); + return "j"; + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/JCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/JCmp.java new file mode 100644 index 000000000..58817da98 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/JCmp.java @@ -0,0 +1,23 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.getChainName.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("j") +public class JCmp extends NodeComponent { + + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + context.setData(this.getNodeId(), this.getCurrChainId()); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/KCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/KCmp.java new file mode 100644 index 000000000..132fbf532 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/getChainName/cmp/KCmp.java @@ -0,0 +1,23 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.getChainName.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("k") +public class KCmp extends NodeComponent { + + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + context.setData(this.getNodeId(), this.getCurrChainId()); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/IfELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/IfELSpringbootTest.java new file mode 100644 index 000000000..e7964b5a1 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/IfELSpringbootTest.java @@ -0,0 +1,81 @@ +package com.yomahub.liteflow.test.ifelse; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境EL常规的例子测试 + * @author Bryan.Zhang + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/ifelse/application.properties") +public class IfELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //IF只有2个参数 + @Test + public void testIf1() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("x1==>a==>b", response.getExecuteStepStrWithoutTime()); + } + + //IF只有3个参数 + @Test + public void testIf2() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("x1==>c==>d", response.getExecuteStepStrWithoutTime()); + } + + //IF有3个参数,进行嵌套 + @Test + public void testIf3() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("x1==>x1==>c==>c==>b", response.getExecuteStepStrWithoutTime()); + } + + //IF有2个参数,加上ELSE + @Test + public void testIf4() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("x1==>c==>d", response.getExecuteStepStrWithoutTime()); + } + + //IF有2个参数,ELSE里再嵌套一个IF + @Test + public void testIf5() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain5", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("x1==>x1==>c==>c==>b", response.getExecuteStepStrWithoutTime()); + } + + //标准的IF ELIF ELSE + @Test + public void testIf6() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain6", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("x1==>x1==>c==>c", response.getExecuteStepStrWithoutTime()); + } + + //IF ELIF... ELSE 的形式 + @Test + public void testIf7() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain7", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("x1==>x1==>x1==>x1==>d==>b==>a", response.getExecuteStepStrWithoutTime()); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/cmp/ACmp.java new file mode 100644 index 000000000..064ef462a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/cmp/ACmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.ifelse.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/cmp/BCmp.java new file mode 100644 index 000000000..70113316d --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/cmp/BCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.ifelse.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/cmp/CCmp.java new file mode 100644 index 000000000..00185a835 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/cmp/CCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.ifelse.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/cmp/DCmp.java new file mode 100644 index 000000000..097bed74a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/cmp/DCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.ifelse.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("d") +public class DCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("DCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/cmp/X1Cmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/cmp/X1Cmp.java new file mode 100644 index 000000000..157a41817 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/ifelse/cmp/X1Cmp.java @@ -0,0 +1,19 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.ifelse.cmp; + +import com.yomahub.liteflow.core.NodeIfComponent; +import org.noear.solon.annotation.Component; + +@Component("x1") +public class X1Cmp extends NodeIfComponent { + @Override + public boolean processIf() throws Exception { + return Boolean.parseBoolean(this.getTag()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/LiteflowComponentELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/LiteflowComponentELSpringbootTest.java new file mode 100644 index 000000000..6b9023572 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/LiteflowComponentELSpringbootTest.java @@ -0,0 +1,34 @@ +package com.yomahub.liteflow.test.lfCmpAnno; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + + +/** + * 测试@LiteflowComponent标注 + * @author Bryan.Zhang + * @since 2.5.10 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/lfCmpAnno/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.lfCmpAnno.cmp"}) +public class LiteflowComponentELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + @Test + public void testConfig() { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a[A组件]==>b[B组件]==>c[C组件]==>b[B组件]==>a[A组件]==>d", response.getExecuteStepStr()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/ACmp.java new file mode 100644 index 000000000..6c4fc23ad --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.lfCmpAnno.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent(id = "a", name = "A组件") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/BCmp.java new file mode 100644 index 000000000..991003cc4 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/BCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.lfCmpAnno.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent(id = "b", name = "B组件") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/CCmp.java new file mode 100644 index 000000000..1fbea2522 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/CCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.lfCmpAnno.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent(id = "c", name = "C组件") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/DCmp.java new file mode 100644 index 000000000..42efc228b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/DCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.lfCmpAnno.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("d") +public class DCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("DCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/LoopELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/LoopELSpringbootTest.java new file mode 100644 index 000000000..afd42ac7a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/LoopELSpringbootTest.java @@ -0,0 +1,87 @@ +package com.yomahub.liteflow.test.loop; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境EL循环的例子测试 + * @author Bryan.Zhang + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/loop/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.loop.cmp"}) +public class LoopELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //FOR循环数字直接在el中定义 + @Test + public void testLoop1() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("LOOP_2==>a==>b==>c==>a==>b==>c", response.getExecuteStepStr()); + } + + //FPR循环由For组件定义 + @Test + public void testLoop2() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("x==>a==>b==>c==>a==>b==>c==>a==>b==>c", response.getExecuteStepStr()); + } + + //FOR循环中加入BREAK组件 + @Test + public void testLoop3() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg"); + Assert.assertTrue(response.isSuccess()); + } + + //WHILE循环 + @Test + public void testLoop4() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("z==>a==>d==>z==>a==>d==>z==>a==>d==>z==>a==>d==>z==>a==>d==>z", response.getExecuteStepStr()); + } + + //WHILE循环加入BREAK + @Test + public void testLoop5() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain5", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("z==>a==>d==>y==>z==>a==>d==>y==>z==>a==>d==>y==>z==>a==>d==>y", response.getExecuteStepStr()); + } + + //测试FOR循环中的index + @Test + public void testLoop6() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain6", "arg"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("01234", context.getData("loop_e1")); + Assert.assertEquals("01234", context.getData("loop_e2")); + Assert.assertEquals("01234", context.getData("loop_e3")); + } + + //测试WHILE循环中的index + @Test + public void testLoop7() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain7", "arg"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("01234", context.getData("loop_e1")); + Assert.assertEquals("01234", context.getData("loop_e2")); + Assert.assertEquals("01234", context.getData("loop_e3")); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/ACmp.java new file mode 100644 index 000000000..0c31d13b3 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.loop.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/BCmp.java new file mode 100644 index 000000000..002e84eb5 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/BCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.loop.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/CCmp.java new file mode 100644 index 000000000..72c8f810f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/CCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.loop.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/DCmp.java new file mode 100644 index 000000000..f1a0d356c --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/DCmp.java @@ -0,0 +1,29 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.loop.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("d") +public class DCmp extends NodeComponent { + + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + String key = "test"; + if (context.hasData(key)){ + int count = context.getData(key); + context.setData(key, ++count); + }else{ + context.setData(key, 1); + } + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/ECmp.java new file mode 100644 index 000000000..da1c622d6 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/ECmp.java @@ -0,0 +1,31 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.loop.cmp; + +import cn.hutool.core.util.StrUtil; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +@Component("e") +public class ECmp extends NodeComponent { + + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + String key = StrUtil.format("{}_{}", "loop", this.getTag()); + if (context.hasData(key)){ + String loopStr = context.getData(key); + String loopStrReturn = StrUtil.format("{}{}", loopStr, this.getLoopIndex()); + context.setData(key, loopStrReturn); + }else{ + context.setData(key, this.getLoopIndex().toString()); + } + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/XCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/XCmp.java new file mode 100644 index 000000000..fa9fe7e5d --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/XCmp.java @@ -0,0 +1,12 @@ +package com.yomahub.liteflow.test.loop.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeForComponent; + +@LiteflowComponent("x") +public class XCmp extends NodeForComponent { + @Override + public int processFor() throws Exception { + return 3; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/YCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/YCmp.java new file mode 100644 index 000000000..95a744a5a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/YCmp.java @@ -0,0 +1,16 @@ +package com.yomahub.liteflow.test.loop.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeBreakComponent; +import com.yomahub.liteflow.core.NodeForComponent; +import com.yomahub.liteflow.slot.DefaultContext; + +@LiteflowComponent("y") +public class YCmp extends NodeBreakComponent { + @Override + public boolean processBreak() throws Exception { + DefaultContext context = this.getFirstContextBean(); + int count = context.getData("test"); + return count > 3; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/ZCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/ZCmp.java new file mode 100644 index 000000000..e5ef68dca --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/loop/cmp/ZCmp.java @@ -0,0 +1,21 @@ +package com.yomahub.liteflow.test.loop.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeBreakComponent; +import com.yomahub.liteflow.core.NodeWhileComponent; +import com.yomahub.liteflow.slot.DefaultContext; + +@LiteflowComponent("z") +public class ZCmp extends NodeWhileComponent { + @Override + public boolean processWhile() throws Exception { + DefaultContext context = this.getFirstContextBean(); + String key = "test"; + if (context.hasData(key)){ + int count = context.getData("test"); + return count < 5; + }else{ + return true; + } + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitor/MonitorELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitor/MonitorELSpringbootTest.java new file mode 100644 index 000000000..b2280db03 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitor/MonitorELSpringbootTest.java @@ -0,0 +1,44 @@ +package com.yomahub.liteflow.test.monitor; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.monitor.MonitorBus; +import com.yomahub.liteflow.spi.holder.ContextAwareHolder; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境最普通的例子测试 + * @author Bryan.Zhang + * @since 2.6.4 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/monitor/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.monitor.cmp"}) +public class MonitorELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + @Test + public void testMonitor() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + + Thread.sleep(10000); + } + + @AfterClass + public static void clean(){ + MonitorBus monitorBus = ContextAwareHolder.loadContextAware().getBean(MonitorBus.class); + monitorBus.closeScheduler(); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitor/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitor/cmp/ACmp.java new file mode 100644 index 000000000..765f5fd64 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitor/cmp/ACmp.java @@ -0,0 +1,28 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.monitor.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +import java.util.Random; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + try { + Thread.sleep(new Random().nextInt(2000)); + }catch (Exception e){ + e.printStackTrace(); + } + + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitor/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitor/cmp/BCmp.java new file mode 100644 index 000000000..1a9aa457f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitor/cmp/BCmp.java @@ -0,0 +1,28 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.monitor.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +import java.util.Random; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + try { + Thread.sleep(new Random().nextInt(2000)); + }catch (Exception e){ + e.printStackTrace(); + } + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitor/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitor/cmp/CCmp.java new file mode 100644 index 000000000..cc73e8728 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitor/cmp/CCmp.java @@ -0,0 +1,28 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.monitor.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +import java.util.Random; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + try { + Thread.sleep(new Random().nextInt(2000)); + }catch (Exception e){ + e.printStackTrace(); + } + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/CheckContext.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/CheckContext.java new file mode 100644 index 000000000..af8bfad4a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/CheckContext.java @@ -0,0 +1,24 @@ +package com.yomahub.liteflow.test.multiContext; + +public class CheckContext { + + private String sign; + + private int randomId; + + public String getSign() { + return sign; + } + + public void setSign(String sign) { + this.sign = sign; + } + + public int getRandomId() { + return randomId; + } + + public void setRandomId(int randomId) { + this.randomId = randomId; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/MultiContextELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/MultiContextELSpringbootTest.java new file mode 100644 index 000000000..5c1d43e9b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/MultiContextELSpringbootTest.java @@ -0,0 +1,63 @@ +package com.yomahub.liteflow.test.multiContext; + +import cn.hutool.core.date.DateUtil; +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.exception.NoSuchContextBeanException; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境最普通的例子测试 + * @author Bryan.Zhang + * @since 2.6.4 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/multiContext/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.multiContext.cmp"}) +public class MultiContextELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + @Test + public void testMultiContext1() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg", OrderContext.class, CheckContext.class); + OrderContext orderContext = response.getContextBean(OrderContext.class); + CheckContext checkContext = response.getContextBean(CheckContext.class); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("987XYZ", checkContext.getSign()); + Assert.assertEquals(95, checkContext.getRandomId()); + Assert.assertEquals("SO12345", orderContext.getOrderNo()); + Assert.assertEquals(2, orderContext.getOrderType()); + Assert.assertEquals(DateUtil.parseDate("2022-06-15"), orderContext.getCreateTime()); + } + + @Test(expected = NoSuchContextBeanException.class) + public void testMultiContext2() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg", OrderContext.class, CheckContext.class); + DefaultContext context = response.getContextBean(DefaultContext.class); + } + + @Test + public void testPassInitializedContextBean() throws Exception{ + OrderContext orderContext = new OrderContext(); + orderContext.setOrderNo("SO11223344"); + CheckContext checkContext = new CheckContext(); + checkContext.setSign("987654321d"); + LiteflowResponse response = flowExecutor.execute2Resp("chain2", null, orderContext, checkContext); + Assert.assertTrue(response.isSuccess()); + OrderContext context1 = response.getContextBean(OrderContext.class); + CheckContext context2 = response.getContextBean(CheckContext.class); + Assert.assertEquals("SO11223344", context1.getOrderNo()); + Assert.assertEquals("987654321d", context2.getSign()); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/OrderContext.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/OrderContext.java new file mode 100644 index 000000000..c477108b3 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/OrderContext.java @@ -0,0 +1,36 @@ +package com.yomahub.liteflow.test.multiContext; + +import java.util.Date; + +public class OrderContext { + + private String orderNo; + + private int orderType; + + private Date createTime; + + public String getOrderNo() { + return orderNo; + } + + public void setOrderNo(String orderNo) { + this.orderNo = orderNo; + } + + public int getOrderType() { + return orderType; + } + + public void setOrderType(int orderType) { + this.orderType = orderType; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/ACmp.java new file mode 100644 index 000000000..260fad4fa --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/ACmp.java @@ -0,0 +1,24 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.multiContext.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.test.multiContext.CheckContext; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + CheckContext checkContext = this.getContextBean(CheckContext.class); + checkContext.setSign("987XYZ"); + checkContext.setRandomId(95); + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/BCmp.java new file mode 100644 index 000000000..fea28b554 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/BCmp.java @@ -0,0 +1,25 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.multiContext.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.test.multiContext.OrderContext; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + //getContextBean无参方法是获取到第一个上下文 + OrderContext orderContext = this.getFirstContextBean(); + orderContext.setOrderNo("SO12345"); + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/CCmp.java new file mode 100644 index 000000000..5ae57e602 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/CCmp.java @@ -0,0 +1,24 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.multiContext.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.test.multiContext.OrderContext; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + OrderContext orderContext = this.getContextBean(OrderContext.class); + orderContext.setOrderType(2); + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/DCmp.java new file mode 100644 index 000000000..c2bf75200 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/DCmp.java @@ -0,0 +1,25 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.multiContext.cmp; + +import cn.hutool.core.date.DateUtil; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.test.multiContext.OrderContext; +import org.noear.solon.annotation.Component; + +@Component("d") +public class DCmp extends NodeComponent { + + @Override + public void process() { + OrderContext orderContext = this.getContextBean(OrderContext.class); + orderContext.setCreateTime(DateUtil.parseDate("2022-06-15")); + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/ECmp.java new file mode 100644 index 000000000..bb9ee5b89 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/ECmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.multiContext.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.test.multiContext.CheckContext; +import org.noear.solon.annotation.Component; + +@Component("e") +public class ECmp extends NodeComponent { + + @Override + public void process() { + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/FCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/FCmp.java new file mode 100644 index 000000000..720dd6263 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multiContext/cmp/FCmp.java @@ -0,0 +1,19 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.multiContext.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("f") +public class FCmp extends NodeComponent { + + @Override + public void process() { + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multipleType/LiteflowMultipleTypeELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multipleType/LiteflowMultipleTypeELSpringbootTest.java new file mode 100644 index 000000000..33e2af85f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multipleType/LiteflowMultipleTypeELSpringbootTest.java @@ -0,0 +1,37 @@ +package com.yomahub.liteflow.test.multipleType; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + + +/** + * 测试springboot下混合格式规则的场景 + * @author Bryan.Zhang + * @since 2.5.10 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/multipleType/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.multipleType.cmp"}) +public class LiteflowMultipleTypeELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + @Test + public void testMultipleType() { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a==>b==>c==>b==>a", response.getExecuteStepStr()); + response = flowExecutor.execute2Resp("chain3", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a==>b==>c", response.getExecuteStepStr()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multipleType/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multipleType/cmp/ACmp.java new file mode 100644 index 000000000..30c90df17 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multipleType/cmp/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.multipleType.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multipleType/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multipleType/cmp/BCmp.java new file mode 100644 index 000000000..f1c81dcdd --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multipleType/cmp/BCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.multipleType.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multipleType/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multipleType/cmp/CCmp.java new file mode 100644 index 000000000..61a3ad6d9 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/multipleType/cmp/CCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.multipleType.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/CustomerDefaultNodeExecutor.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/CustomerDefaultNodeExecutor.java new file mode 100644 index 000000000..9fb992248 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/CustomerDefaultNodeExecutor.java @@ -0,0 +1,18 @@ +package com.yomahub.liteflow.test.nodeExecutor; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.flow.executor.NodeExecutor; +import com.yomahub.liteflow.slot.DefaultContext; + +/** + * 自定义默认的节点执行器 + */ +public class CustomerDefaultNodeExecutor extends NodeExecutor { + @Override + public void execute(NodeComponent instance) throws Exception { + DefaultContext context = instance.getFirstContextBean(); + LOG.info("使用customerDefaultNodeExecutor进行执行"); + context.setData("customerDefaultNodeExecutor", this.getClass()); + super.execute(instance); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/CustomerNodeExecutor.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/CustomerNodeExecutor.java new file mode 100644 index 000000000..e4ef70e04 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/CustomerNodeExecutor.java @@ -0,0 +1,19 @@ +package com.yomahub.liteflow.test.nodeExecutor; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.flow.executor.NodeExecutor; +import com.yomahub.liteflow.slot.DefaultContext; + +/** + * 自定义节点执行器 + */ +public class CustomerNodeExecutor extends NodeExecutor { + @Override + public void execute(NodeComponent instance) throws Exception { + DefaultContext context = instance.getFirstContextBean(); + LOG.info("使用customerNodeExecutor进行执行"); + context.setData("customerNodeExecutor", this.getClass()); + super.execute(instance); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/CustomerNodeExecutorAndCustomRetry.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/CustomerNodeExecutorAndCustomRetry.java new file mode 100644 index 000000000..202005b10 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/CustomerNodeExecutorAndCustomRetry.java @@ -0,0 +1,28 @@ +package com.yomahub.liteflow.test.nodeExecutor; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.flow.executor.NodeExecutor; +import com.yomahub.liteflow.slot.DefaultContext; + +import java.util.concurrent.TimeUnit; + +/** + * 自定义节点执行器 + */ +public class CustomerNodeExecutorAndCustomRetry extends NodeExecutor { + @Override + public void execute(NodeComponent instance) throws Exception { + DefaultContext context = instance.getFirstContextBean(); + LOG.info("使用customerNodeExecutorAndCustomRetry进行执行"); + context.setData("customerNodeExecutorAndCustomRetry", this.getClass()); + super.execute(instance); + } + + @Override + protected void retry(NodeComponent instance, int currentRetryCount) throws Exception { + TimeUnit.MICROSECONDS.sleep(20L); + DefaultContext context = instance.getFirstContextBean(); + context.setData("retryLogic", this.getClass()); + super.retry(instance, currentRetryCount); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/LiteflowNodeExecutorELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/LiteflowNodeExecutorELSpringbootTest.java new file mode 100644 index 000000000..fcd2dcd42 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/LiteflowNodeExecutorELSpringbootTest.java @@ -0,0 +1,67 @@ +package com.yomahub.liteflow.test.nodeExecutor; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + + +/** + * 测试springboot下的组件重试 + * + * @author Bryan.Zhang + * @since 2.5.10 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/nodeExecutor/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.nodeExecutor.cmp"}) +public class LiteflowNodeExecutorELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + // 默认执行器测试 + @Test + public void testCustomerDefaultNodeExecutor() { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals(CustomerDefaultNodeExecutor.class, context.getData("customerDefaultNodeExecutor")); + Assert.assertEquals("a", response.getExecuteStepStr()); + } + + //默认执行器测试+全局重试配置测试 + @Test + public void testDefaultExecutorForRetry() { + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals(CustomerDefaultNodeExecutor.class, context.getData("customerDefaultNodeExecutor")); + Assert.assertEquals("b==>b==>b", response.getExecuteStepStr()); + } + + //自定义执行器测试 + @Test + public void testCustomerExecutor() { + LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("c", response.getExecuteStepStr()); + } + + //自定义执行器测试+全局重试配置测试 + @Test + public void testCustomExecutorForRetry() { + LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertFalse(response.isSuccess()); + Assert.assertEquals(CustomerNodeExecutorAndCustomRetry.class, context.getData("retryLogic")); + Assert.assertEquals("d==>d==>d==>d==>d==>d", response.getExecuteStepStr()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/ACmp.java new file mode 100644 index 000000000..8fd765bb1 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/ACmp.java @@ -0,0 +1,22 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * + * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.nodeExecutor.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/BCmp.java new file mode 100644 index 000000000..6e737879e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/BCmp.java @@ -0,0 +1,27 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.nodeExecutor.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("b") +public class BCmp extends NodeComponent { + + private int flag = 0; + + @Override + public void process() { + System.out.println("BCmp executed!"); + if (flag < 2){ + flag++; + throw new RuntimeException("demo exception"); + } + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/CCmp.java new file mode 100644 index 000000000..f800c08b2 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/CCmp.java @@ -0,0 +1,29 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.nodeExecutor.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.annotation.LiteflowRetry; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.flow.executor.NodeExecutor; +import com.yomahub.liteflow.test.nodeExecutor.CustomerNodeExecutor; + +@LiteflowComponent("c") +@LiteflowRetry(5) +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + + @Override + public Class getNodeExecutorClass() { + return CustomerNodeExecutor.class; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/DCmp.java new file mode 100644 index 000000000..bc99b47a9 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/DCmp.java @@ -0,0 +1,31 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * + * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.nodeExecutor.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.annotation.LiteflowRetry; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.flow.executor.NodeExecutor; +import com.yomahub.liteflow.test.nodeExecutor.CustomerNodeExecutorAndCustomRetry; + +@LiteflowComponent("d") +@LiteflowRetry(retry = 5, forExceptions = {NullPointerException.class}) +public class DCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("DCmp executed!"); + throw new NullPointerException("demo exception"); + } + + @Override + public Class getNodeExecutorClass() { + return CustomerNodeExecutorAndCustomRetry.class; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nullParam/NullParamELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nullParam/NullParamELSpringbootTest.java new file mode 100644 index 000000000..9975826b8 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nullParam/NullParamELSpringbootTest.java @@ -0,0 +1,36 @@ +package com.yomahub.liteflow.test.nullParam; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * 单元测试:传递null param导致NPE的优化代码 + * + * @author LeoLee + * @since 2.6.6 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/nullParam/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.nullParam.cmp"}) +public class NullParamELSpringbootTest { + + @Inject + private FlowExecutor flowExecutor; + + /** + * 支持无参的flow执行,以及param 为null时的异常抛出 + */ + @Test + public void testNullParam() throws Exception { + LiteflowResponse response = flowExecutor.execute2Resp("chain1"); + Assert.assertTrue(response.isSuccess()); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nullParam/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nullParam/cmp/ACmp.java new file mode 100644 index 000000000..5815b5840 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nullParam/cmp/ACmp.java @@ -0,0 +1,22 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.nullParam.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + System.out.println("get request data:" + this.getRequestData()); + this.getSlot().setInput("BCmp", "param for BCmp"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nullParam/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nullParam/cmp/BCmp.java new file mode 100644 index 000000000..c6e56be36 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nullParam/cmp/BCmp.java @@ -0,0 +1,23 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.nullParam.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + System.out.println("BCmp param:" + this.getSlot().getInput("BCmp")); + this.getSlot().setOutput("CCmp", "param for CCmp"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nullParam/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nullParam/cmp/CCmp.java new file mode 100644 index 000000000..e325d6b5f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/nullParam/cmp/CCmp.java @@ -0,0 +1,22 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.nullParam.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + System.out.println("CCmp param:" + this.getSlot().getOutput("CCmp")); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/CustomParserJsonELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/CustomParserJsonELSpringbootTest.java new file mode 100644 index 000000000..da23f0563 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/CustomParserJsonELSpringbootTest.java @@ -0,0 +1,33 @@ +package com.yomahub.liteflow.test.parsecustom; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境的自定义json parser单元测试 + * @author dongguo.tao + * @since 2.5.0 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/parsecustom/application-custom-json.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.parsecustom.cmp"}) +public class CustomParserJsonELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //测试springboot场景的自定义json parser + @Test + public void testJsonCustomParser() { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "args"); + Assert.assertTrue(response.isSuccess()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/CustomParserXmlELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/CustomParserXmlELSpringbootTest.java new file mode 100644 index 000000000..703441dfd --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/CustomParserXmlELSpringbootTest.java @@ -0,0 +1,34 @@ +package com.yomahub.liteflow.test.parsecustom; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境的自定义xml parser单元测试 + * 主要测试自定义配置源类是否能引入springboot中的其他依赖 + * @author bryan.zhang + * @since 2.5.7 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/parsecustom/application-custom-xml.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.parsecustom.cmp","com.yomahub.liteflow.test.parsecustom.bean"}) +public class CustomParserXmlELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //测试springboot场景的自定义json parser + @Test + public void testXmlCustomParser() { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "args"); + Assert.assertTrue(response.isSuccess()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/CustomParserYmlELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/CustomParserYmlELSpringbootTest.java new file mode 100644 index 000000000..e9e0474d0 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/CustomParserYmlELSpringbootTest.java @@ -0,0 +1,34 @@ +package com.yomahub.liteflow.test.parsecustom; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境的自定义yml parser单元测试 + * 主要测试自定义配置源类是否能引入springboot中的其他依赖 + * + * @author junjun + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/parsecustom/application-custom-yml.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.parsecustom.cmp","com.yomahub.liteflow.test.parsecustom.bean"}) +public class CustomParserYmlELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //测试springboot场景的自定义json parser + @Test + public void testYmlCustomParser() { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "args"); + Assert.assertTrue(response.isSuccess()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/bean/TestBean.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/bean/TestBean.java new file mode 100644 index 000000000..626505056 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/bean/TestBean.java @@ -0,0 +1,11 @@ +package com.yomahub.liteflow.test.parsecustom.bean; + +import org.noear.solon.annotation.Component; + +@Component +public class TestBean { + + public String returnXmlContent(){ + return "THEN(a,b,c,d)"; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/ACmp.java new file mode 100644 index 000000000..221d69b45 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/ACmp.java @@ -0,0 +1,26 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.parsecustom.cmp; + +import cn.hutool.core.util.StrUtil; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.exception.FlowSystemException; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + String str = this.getRequestData(); + if(StrUtil.isNotBlank(str) && str.equals("exception")) { + throw new FlowSystemException("chain execute execption"); + } + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/BCmp.java new file mode 100644 index 000000000..5a13ae561 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/BCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.parsecustom.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/CCmp.java new file mode 100644 index 000000000..96d576bb5 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/CCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.parsecustom.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/DCmp.java new file mode 100644 index 000000000..815e98311 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/DCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.parsecustom.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("d") +public class DCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("DCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/ECmp.java new file mode 100644 index 000000000..e4b612d72 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/ECmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.parsecustom.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; +import org.noear.solon.annotation.Component; + +@Component("e") +public class ECmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + return "g"; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/FCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/FCmp.java new file mode 100644 index 000000000..8e78f6e5c --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/FCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.parsecustom.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("f") +public class FCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("FCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/GCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/GCmp.java new file mode 100644 index 000000000..44ceaee45 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/cmp/GCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.parsecustom.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("g") +public class GCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("GCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/parser/CustomJsonFlowParser.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/parser/CustomJsonFlowParser.java new file mode 100644 index 000000000..42f5eeed5 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/parser/CustomJsonFlowParser.java @@ -0,0 +1,17 @@ +package com.yomahub.liteflow.test.parsecustom.parser; + +import com.yomahub.liteflow.parser.el.ClassJsonFlowELParser; + +/** + * 模拟用户自定义源解析 + * @author dongguo.tao + * @since 2.5.0 + */ +public class CustomJsonFlowParser extends ClassJsonFlowELParser { + @Override + public String parseCustom() { + //模拟自定义解析结果 + String content = "{\"flow\":{\"nodes\":{\"node\":[{\"id\":\"a\",\"class\":\"com.yomahub.liteflow.test.parsecustom.cmp.ACmp\"},{\"id\":\"b\",\"class\":\"com.yomahub.liteflow.test.parsecustom.cmp.BCmp\"},{\"id\":\"c\",\"class\":\"com.yomahub.liteflow.test.parsecustom.cmp.CCmp\"},{\"id\":\"d\",\"class\":\"com.yomahub.liteflow.test.parsecustom.cmp.DCmp\"},{\"id\":\"e\",\"class\":\"com.yomahub.liteflow.test.parsecustom.cmp.ECmp\"},{\"id\":\"f\",\"class\":\"com.yomahub.liteflow.test.parsecustom.cmp.FCmp\"},{\"id\":\"g\",\"class\":\"com.yomahub.liteflow.test.parsecustom.cmp.GCmp\"}]},\"chain\":[{\"name\":\"chain2\",\"value\":\"THEN(c, g, f)\"},{\"name\":\"chain1\",\"value\":\"THEN(a, c, WHEN(b, d, SWITCH(e).to(f, g), chain2))\"}]}}"; + return content; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/parser/CustomXmlFlowParser.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/parser/CustomXmlFlowParser.java new file mode 100644 index 000000000..4d16d1113 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/parser/CustomXmlFlowParser.java @@ -0,0 +1,22 @@ +package com.yomahub.liteflow.test.parsecustom.parser; + +import com.yomahub.liteflow.parser.el.ClassXmlFlowELParser; +import com.yomahub.liteflow.test.parsecustom.bean.TestBean; +import org.noear.solon.annotation.Inject; + +/** + * springboot环境的自定义xml parser单元测试 + * 主要测试自定义配置源类是否能引入springboot中的其他依赖 + * @author bryan.zhang + * @since 2.5.7 + */ +public class CustomXmlFlowParser extends ClassXmlFlowELParser { + + @Inject + private TestBean testBean; + + @Override + public String parseCustom() { + return testBean.returnXmlContent(); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/parser/CustomYmlFlowParser.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/parser/CustomYmlFlowParser.java new file mode 100644 index 000000000..3431a3d54 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parsecustom/parser/CustomYmlFlowParser.java @@ -0,0 +1,19 @@ +package com.yomahub.liteflow.test.parsecustom.parser; + +import com.yomahub.liteflow.parser.el.ClassYmlFlowELParser; + +/** + * 模拟用户自定义源解析 + * + * @author junjun + */ +public class CustomYmlFlowParser extends ClassYmlFlowELParser { + @Override + public String parseCustom() { + //模拟自定义解析结果 + return "flow:\n" + + " chain:\n" + + " - name: chain1\n" + + " value: \"THEN(a, b, c);\""; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/JsonParserELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/JsonParserELSpringbootTest.java new file mode 100644 index 000000000..4dbb84041 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/JsonParserELSpringbootTest.java @@ -0,0 +1,31 @@ +package com.yomahub.liteflow.test.parser; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * spring环境的json parser单元测试 + * @author Bryan.Zhang + * @since 2.5.0 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/parser/application-json.properties") +public class JsonParserELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //测试spring场景的json parser + @Test + public void testJsonParser() { + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg"); + Assert.assertTrue(response.isSuccess()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/SpringELSupportELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/SpringELSupportELSpringbootTest.java new file mode 100644 index 000000000..bec90fb64 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/SpringELSupportELSpringbootTest.java @@ -0,0 +1,26 @@ +package com.yomahub.liteflow.test.parser; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/parser/application-springEL.properties") +public class SpringELSupportELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //测试springEL的解析情况 + @Test + public void testSpringELParser() { + LiteflowResponse response = flowExecutor.execute2Resp("chain11", "arg"); + Assert.assertTrue(response.isSuccess()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/XmlParserELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/XmlParserELSpringbootTest.java new file mode 100644 index 000000000..62c52d462 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/XmlParserELSpringbootTest.java @@ -0,0 +1,31 @@ +package com.yomahub.liteflow.test.parser; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境的xml parser单元测试 + * @author Bryan.Zhang + * @since 2.5.0 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/parser/application-xml.properties") +public class XmlParserELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //测试无springboot场景的xml parser + @Test + public void testXmlParser() { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/YmlParserELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/YmlParserELSpringbootTest.java new file mode 100644 index 000000000..607c380b4 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/YmlParserELSpringbootTest.java @@ -0,0 +1,31 @@ +package com.yomahub.liteflow.test.parser; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot下的yml parser测试用例 + * @author Bryan.Zhang + * @since 2.5.0 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/parser/application-yml.properties") +public class YmlParserELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //测试无springboot场景的yml parser + @Test + public void testYmlParser() { + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg"); + Assert.assertTrue(response.isSuccess()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/ACmp.java new file mode 100644 index 000000000..1b348e25e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.parser.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/BCmp.java new file mode 100644 index 000000000..a09b82909 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/BCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.parser.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/CCmp.java new file mode 100644 index 000000000..4065e2649 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/CCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.parser.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/DCmp.java new file mode 100644 index 000000000..129310a73 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/DCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.parser.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("d") +public class DCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("DCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/ECmp.java new file mode 100644 index 000000000..8f95c0995 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/ECmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.parser.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; +import org.noear.solon.annotation.Component; + +@Component("e") +public class ECmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + return "g"; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/FCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/FCmp.java new file mode 100644 index 000000000..02c721a91 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/FCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.parser.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("f") +public class FCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("FCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/GCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/GCmp.java new file mode 100644 index 000000000..ba071705d --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/parser/cmp/GCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.parser.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("g") +public class GCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("GCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/PreAndFinallyELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/PreAndFinallyELSpringbootTest.java new file mode 100644 index 000000000..1e8f5dcf7 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/PreAndFinallyELSpringbootTest.java @@ -0,0 +1,83 @@ +package com.yomahub.liteflow.test.preAndFinally; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境下pre节点和finally节点的测试 + * @author Bryan.Zhang + * @since 2.6.4 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/preAndFinally/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.preAndFinally.cmp"}) +public class PreAndFinallyELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //测试普通的pre和finally节点 + @Test + public void testPreAndFinally1() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("p1==>p2==>a==>b==>c==>f1==>f2",response.getExecuteStepStr()); + } + + //测试pre和finally节点不放在开头和结尾的情况 + @Test + public void testPreAndFinally2() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("p1==>p2==>a==>b==>c==>f1==>f2",response.getExecuteStepStr()); + } + + //测试有节点报错是否还执行finally节点的情况,其中d节点会报错,但依旧执行f1,f2节点 + @Test + public void testPreAndFinally3() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg"); + Assert.assertFalse(response.isSuccess()); + Assert.assertEquals("p1==>p2==>a==>d==>f1==>f2", response.getExecuteStepStr()); + } + + //测试在finally节点里是否能获取exception + @Test + public void testPreAndFinally4() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertFalse(response.isSuccess()); + Assert.assertTrue(context.getData("hasEx")); + } + + //测试嵌套结构pre和finally是否在各自的chain里打出 + @Test + public void testPreAndFinally5() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain5", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("p1==>p2==>p1==>p2==>a==>b==>c==>f1==>f2==>f1", response.getExecuteStepStrWithoutTime()); + } + + //测试变量结构pre和finally是否在各自的chain里打出 + @Test + public void testPreAndFinally6() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain6", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("p1==>p2==>p1==>p2==>a==>b==>c==>f1==>f2==>f1", response.getExecuteStepStrWithoutTime()); + } + + //测试el整体结构的多重pre和finally + @Test + public void testPreAndFinally7() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain7", "arg"); + Assert.assertTrue(response.isSuccess()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/ACmp.java new file mode 100644 index 000000000..cc08cf0ed --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.preAndFinally.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/BCmp.java new file mode 100644 index 000000000..3da2f9598 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/BCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.preAndFinally.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/CCmp.java new file mode 100644 index 000000000..6cd93e2bb --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/CCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.preAndFinally.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/DCmp.java new file mode 100644 index 000000000..49a4515b6 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/DCmp.java @@ -0,0 +1,22 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.preAndFinally.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("d") +public class DCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + int i = 1/0; + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/Finally1Cmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/Finally1Cmp.java new file mode 100644 index 000000000..d7070796a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/Finally1Cmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.preAndFinally.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("f1") +public class Finally1Cmp extends NodeComponent { + + @Override + public void process() { + System.out.println("Finally1Cmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/Finally2Cmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/Finally2Cmp.java new file mode 100644 index 000000000..8931498a0 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/Finally2Cmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.preAndFinally.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("f2") +public class Finally2Cmp extends NodeComponent { + + @Override + public void process() { + System.out.println("Finally2Cmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/Finally3Cmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/Finally3Cmp.java new file mode 100644 index 000000000..6d6954cb3 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/Finally3Cmp.java @@ -0,0 +1,30 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.preAndFinally.cmp; + +import cn.hutool.core.util.ObjectUtil; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.slot.Slot; +import org.noear.solon.annotation.Component; + +@Component("f3") +public class Finally3Cmp extends NodeComponent { + + @Override + public void process() throws Exception{ + Slot slot = this.getSlot(); + DefaultContext context = slot.getFirstContextBean(); + if (ObjectUtil.isNull(slot.getException())){ + context.setData("hasEx", false); + }else{ + context.setData("hasEx", true); + } + System.out.println("Finally3Cmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/Pre1Cmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/Pre1Cmp.java new file mode 100644 index 000000000..0948ba805 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/Pre1Cmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.preAndFinally.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("p1") +public class Pre1Cmp extends NodeComponent { + + @Override + public void process() { + System.out.println("Pre1Cmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/Pre2Cmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/Pre2Cmp.java new file mode 100644 index 000000000..36e773230 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/preAndFinally/cmp/Pre2Cmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.preAndFinally.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("p2") +public class Pre2Cmp extends NodeComponent { + + @Override + public void process() { + System.out.println("Pre2Cmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/privateDelivery/PrivateDeliveryELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/privateDelivery/PrivateDeliveryELSpringbootTest.java new file mode 100644 index 000000000..154753040 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/privateDelivery/PrivateDeliveryELSpringbootTest.java @@ -0,0 +1,37 @@ +package com.yomahub.liteflow.test.privateDelivery; + +import cn.hutool.core.collection.ConcurrentHashSet; +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境下隐私投递的测试 + * @author Bryan.Zhang + * @since 2.5.0 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/privateDelivery/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.privateDelivery.cmp"}) +public class PrivateDeliveryELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + @Test + public void testPrivateDelivery() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + DefaultContext context = response.getFirstContextBean(); + ConcurrentHashSet set = context.getData("testSet"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals(100, set.size()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/privateDelivery/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/privateDelivery/cmp/ACmp.java new file mode 100644 index 000000000..c7cb8c9b3 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/privateDelivery/cmp/ACmp.java @@ -0,0 +1,29 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.privateDelivery.cmp; + +import cn.hutool.core.collection.ConcurrentHashSet; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; + +@LiteflowComponent("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + DefaultContext context = this.getFirstContextBean(); + context.setData("testSet", new ConcurrentHashSet<>()); + + for (int i = 0; i < 100; i++) { + this.sendPrivateDeliveryData("b",i+1); + } + } +} + diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/privateDelivery/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/privateDelivery/cmp/BCmp.java new file mode 100644 index 000000000..54cf4ce34 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/privateDelivery/cmp/BCmp.java @@ -0,0 +1,27 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.privateDelivery.cmp; + +import cn.hutool.core.collection.ConcurrentHashSet; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; + +@LiteflowComponent("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + Integer value = this.getPrivateDeliveryData(); + DefaultContext context = this.getFirstContextBean(); + ConcurrentHashSet testSet = context.getData("testSet"); + testSet.add(value); + } +} + diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/privateDelivery/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/privateDelivery/cmp/CCmp.java new file mode 100644 index 000000000..8d79eb1bc --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/privateDelivery/cmp/CCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.privateDelivery.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/privateDelivery/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/privateDelivery/cmp/DCmp.java new file mode 100644 index 000000000..a17ad9bb6 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/privateDelivery/cmp/DCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.privateDelivery.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("d") +public class DCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/refreshRule/RefreshRuleELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/refreshRule/RefreshRuleELSpringbootTest.java new file mode 100644 index 000000000..8ce615311 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/refreshRule/RefreshRuleELSpringbootTest.java @@ -0,0 +1,64 @@ +package com.yomahub.liteflow.test.refreshRule; + +import cn.hutool.core.io.resource.ResourceUtil; +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.enums.FlowParserTypeEnum; +import com.yomahub.liteflow.flow.FlowBus; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境下重新加载规则测试 + * @author Bryan.Zhang + * @since 2.6.4 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/refreshRule/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.refreshRule.cmp"}) +public class RefreshRuleELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //测试普通刷新流程的场景 + @Test + public void testRefresh1() throws Exception{ + String content = ResourceUtil.readUtf8Str("classpath: /refreshRule/flow_update.el.xml"); + FlowBus.refreshFlowMetaData(FlowParserTypeEnum.TYPE_EL_XML, content); + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + } + + //测试优雅刷新的场景 + @Test + public void testRefresh2() throws Exception{ + new Thread(() -> { + try { + Thread.sleep(3000L); + String content = ResourceUtil.readUtf8Str("classpath: /refreshRule/flow_update.el.xml"); + FlowBus.refreshFlowMetaData(FlowParserTypeEnum.TYPE_EL_XML, content); + } catch (Exception e) { + e.printStackTrace(); + } + + }).start(); + + for (int i = 0; i < 500; i++) { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + try { + Thread.sleep(10L); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/refreshRule/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/refreshRule/cmp/ACmp.java new file mode 100644 index 000000000..91745bc7b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/refreshRule/cmp/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.refreshRule.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/refreshRule/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/refreshRule/cmp/BCmp.java new file mode 100644 index 000000000..d4ca45b84 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/refreshRule/cmp/BCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.refreshRule.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/refreshRule/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/refreshRule/cmp/CCmp.java new file mode 100644 index 000000000..6c3ab8d87 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/refreshRule/cmp/CCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.refreshRule.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/reload/ReloadELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/reload/ReloadELSpringbootTest.java new file mode 100644 index 000000000..eeecbe21a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/reload/ReloadELSpringbootTest.java @@ -0,0 +1,35 @@ +package com.yomahub.liteflow.test.reload; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境下重新加载规则测试 + * @author Bryan.Zhang + * @since 2.5.0 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/reload/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.reload.cmp"}) +public class ReloadELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //用reloadRule去重新加载,这里如果配置是放在本地。如果想修改,则要去修改target下面的flow.xml + //这里的测试,手动打断点然后去修改,是ok的。但是整个测试,暂且只是为了测试这个功能是否能正常运行 + @Test + public void testReload() throws Exception{ + flowExecutor.reloadRule(); + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/reload/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/reload/cmp/ACmp.java new file mode 100644 index 000000000..b73b7ce3e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/reload/cmp/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.reload.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/reload/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/reload/cmp/BCmp.java new file mode 100644 index 000000000..0022141b8 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/reload/cmp/BCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.reload.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/reload/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/reload/cmp/CCmp.java new file mode 100644 index 000000000..a884a5b77 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/reload/cmp/CCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.reload.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/removeChain/RemoveChainELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/removeChain/RemoveChainELSpringbootTest.java new file mode 100644 index 000000000..4e7e0a36a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/removeChain/RemoveChainELSpringbootTest.java @@ -0,0 +1,37 @@ +package com.yomahub.liteflow.test.removeChain; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.FlowBus; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境最普通的例子测试 + * @author Bryan.Zhang + * @since 2.6.4 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/removeChain/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.removeChain.cmp"}) +public class RemoveChainELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + @Test + public void testRemoveChain() throws Exception{ + LiteflowResponse response1 = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response1.isSuccess()); + FlowBus.removeChain("chain1"); + LiteflowResponse response2 = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertFalse(response2.isSuccess()); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/removeChain/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/removeChain/cmp/ACmp.java new file mode 100644 index 000000000..e94e9d435 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/removeChain/cmp/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.removeChain.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/removeChain/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/removeChain/cmp/BCmp.java new file mode 100644 index 000000000..9417467ca --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/removeChain/cmp/BCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.removeChain.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/removeChain/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/removeChain/cmp/CCmp.java new file mode 100644 index 000000000..7b3c1b728 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/removeChain/cmp/CCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.removeChain.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/removeChain/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/removeChain/cmp/DCmp.java new file mode 100644 index 000000000..c29670603 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/removeChain/cmp/DCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.removeChain.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("d") +public class DCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/requestId/LiteflowRequestIdELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/requestId/LiteflowRequestIdELSpringbootTest.java new file mode 100644 index 000000000..8f2f682fa --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/requestId/LiteflowRequestIdELSpringbootTest.java @@ -0,0 +1,32 @@ +package com.yomahub.liteflow.test.requestId; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * @author tangkc + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/requestId/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.requestId.cmp"}) +public class LiteflowRequestIdELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + @Test + public void testRequestId() throws Exception { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("1", response.getRequestId()); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/requestId/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/requestId/cmp/ACmp.java new file mode 100644 index 000000000..75a277d17 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/requestId/cmp/ACmp.java @@ -0,0 +1,23 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * + * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.requestId.cmp; + +import com.yomahub.liteflow.annotation.LiteflowMethod; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.enums.LiteFlowMethodEnum; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp { + + @LiteflowMethod(LiteFlowMethodEnum.PROCESS) + public void process(NodeComponent bindCmp) { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/requestId/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/requestId/cmp/BCmp.java new file mode 100644 index 000000000..c325a0fc8 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/requestId/cmp/BCmp.java @@ -0,0 +1,23 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.requestId.cmp; + +import com.yomahub.liteflow.annotation.LiteflowMethod; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.enums.LiteFlowMethodEnum; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp{ + + @LiteflowMethod(LiteFlowMethodEnum.PROCESS) + public void process(NodeComponent bindCmp) { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/requestId/config/CustomRequestIdGenerator.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/requestId/config/CustomRequestIdGenerator.java new file mode 100644 index 000000000..fcaa9e84b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/requestId/config/CustomRequestIdGenerator.java @@ -0,0 +1,18 @@ +package com.yomahub.liteflow.test.requestId.config; + +import com.yomahub.liteflow.flow.id.RequestIdGenerator; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author tangkc + */ +public class CustomRequestIdGenerator implements RequestIdGenerator { + + private final AtomicInteger atomicInteger = new AtomicInteger(0); + + @Override + public String generate() { + return atomicInteger.incrementAndGet() + ""; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/ImplicitSubFlowELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/ImplicitSubFlowELSpringbootTest.java new file mode 100644 index 000000000..2ccd18509 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/ImplicitSubFlowELSpringbootTest.java @@ -0,0 +1,68 @@ +package com.yomahub.liteflow.test.subflow; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +import java.util.HashSet; +import java.util.Set; + +/** + * 测试隐式调用子流程 + * 单元测试 + * + * @author justin.xu + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/subflow/application-implicit.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.subflow.cmp2"}) +public class ImplicitSubFlowELSpringbootTest extends BaseTest { + @Inject + private FlowExecutor flowExecutor; + + public static final Set RUN_TIME_SLOT = new HashSet<>(); + + //这里GCmp中隐式的调用chain4,从而执行了h,m + @Test + public void testImplicitSubFlow1() { + LiteflowResponse response = flowExecutor.execute2Resp("chain3", "it's a request"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("f==>g==>h==>m", response.getExecuteStepStr()); + + // 传递了slotIndex,则set的size==1 + Assert.assertEquals(1, RUN_TIME_SLOT.size()); + // set中第一次设置的requestId和response中的requestId一致 + Assert.assertTrue(RUN_TIME_SLOT.contains(response.getSlot().getRequestId())); + //requestData的取值正确 + Assert.assertEquals("it's implicit subflow.", context.getData("innerRequest")); + } + + //在p里多线程调用q 10次,每个q取到的参数都是不同的。 + @Test + public void testImplicitSubFlow2() { + LiteflowResponse response = flowExecutor.execute2Resp("c1", "it's a request"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertTrue(response.isSuccess()); + + Set set = context.getData("test"); + + //requestData的取值正确 + Assert.assertEquals(10, set.size()); + } + + @Test + public void testImplicitSubFlow3() { + LiteflowResponse response = flowExecutor.execute2Resp("chain_r", "it's a request"); + Assert.assertTrue(response.isSuccess()); + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/SubflowInDifferentConfigELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/SubflowInDifferentConfigELSpringbootTest.java new file mode 100644 index 000000000..be7023a69 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/SubflowInDifferentConfigELSpringbootTest.java @@ -0,0 +1,47 @@ +package com.yomahub.liteflow.test.subflow; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.exception.MultipleParsersException; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.property.LiteflowConfig; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.core.AopContext; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * 测试主流程与子流程在不同的配置文件的场景 + * + * @author Bryan.Zhang + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource("classpath:/subflow/application-subInDifferentConfig1.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.subflow.cmp1","com.yomahub.liteflow.test.subflow.cmp2"}) +public class SubflowInDifferentConfigELSpringbootTest extends BaseTest { + @Inject + private FlowExecutor flowExecutor; + + //是否按照流程定义配置执行 + @Test + public void testExplicitSubFlow1() { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "it's a request"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a==>b==>b==>a==>e==>d", response.getExecuteStepStr()); + } + + @Inject + private AopContext context; + + //主要测试有不同的配置类型后会不会报出既定的错误 + @Test(expected = MultipleParsersException.class) + public void testExplicitSubFlow2() { + LiteflowConfig config = context.getBean(LiteflowConfig.class); + config.setRuleSource("subflow/flow-main.el.xml,subflow/flow-sub1.el.xml,subflow/flow-sub2.el.yml"); + flowExecutor.reloadRule(); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/SubflowJsonELSpringBootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/SubflowJsonELSpringBootTest.java new file mode 100644 index 000000000..be0bf2a6b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/SubflowJsonELSpringBootTest.java @@ -0,0 +1,34 @@ +package com.yomahub.liteflow.test.subflow; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * 测试显示调用子流程(json) + * 单元测试 + * + * @author justin.xu + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/subflow/application-json.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.subflow.cmp1"}) +public class SubflowJsonELSpringBootTest extends BaseTest { + @Inject + private FlowExecutor flowExecutor; + + //是否按照流程定义配置执行 + @Test + public void testExplicitSubFlow() { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "it's a request"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a==>b==>c==>b==>a==>e==>d", response.getExecuteStepStr()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/SubflowXMLELSpringBootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/SubflowXMLELSpringBootTest.java new file mode 100644 index 000000000..6e7be89c7 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/SubflowXMLELSpringBootTest.java @@ -0,0 +1,34 @@ +package com.yomahub.liteflow.test.subflow; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * 测试显示调用子流程(xml) + * 单元测试 + * + * @author justin.xu + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/subflow/application-xml.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.subflow.cmp1"}) +public class SubflowXMLELSpringBootTest extends BaseTest { + @Inject + private FlowExecutor flowExecutor; + + //是否按照流程定义配置执行 + @Test + public void testExplicitSubFlow() { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "it's a request"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a==>b==>c==>b==>a==>e==>d", response.getExecuteStepStr()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/SubflowYmlELSpringBootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/SubflowYmlELSpringBootTest.java new file mode 100644 index 000000000..e8eedb6f3 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/SubflowYmlELSpringBootTest.java @@ -0,0 +1,34 @@ +package com.yomahub.liteflow.test.subflow; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * 测试显示调用子流程(yml) + * 单元测试 + * + * @author justin.xu + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/subflow/application-yml.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.subflow.cmp1"}) +public class SubflowYmlELSpringBootTest extends BaseTest { + @Inject + private FlowExecutor flowExecutor; + + //是否按照流程定义配置执行 + @Test + public void testExplicitSubFlowYml() { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "it's a request"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a==>b==>c==>b==>a==>e==>d", response.getExecuteStepStr()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp1/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp1/ACmp.java new file mode 100644 index 000000000..ab9dc3778 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp1/ACmp.java @@ -0,0 +1,13 @@ +package com.yomahub.liteflow.test.subflow.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + + +@Component("a") +public class ACmp extends NodeComponent { + @Override + public void process() { + System.out.println("Acomp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp1/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp1/BCmp.java new file mode 100644 index 000000000..12d89ef12 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp1/BCmp.java @@ -0,0 +1,13 @@ +package com.yomahub.liteflow.test.subflow.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + + +@Component("b") +public class BCmp extends NodeComponent { + @Override + public void process() { + System.out.println("Bcomp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp1/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp1/CCmp.java new file mode 100644 index 000000000..fb874d46a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp1/CCmp.java @@ -0,0 +1,13 @@ +package com.yomahub.liteflow.test.subflow.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + + +@Component("c") +public class CCmp extends NodeComponent { + @Override + public void process() throws Exception { + System.out.println("Ccomp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp1/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp1/DCmp.java new file mode 100644 index 000000000..de14ae6dc --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp1/DCmp.java @@ -0,0 +1,13 @@ +package com.yomahub.liteflow.test.subflow.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + + +@Component("d") +public class DCmp extends NodeComponent { + @Override + public void process() throws Exception { + System.out.println("Dcomp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp1/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp1/ECmp.java new file mode 100644 index 000000000..dc5270361 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp1/ECmp.java @@ -0,0 +1,14 @@ +package com.yomahub.liteflow.test.subflow.cmp1; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + + +@Component("e") +public class ECmp extends NodeComponent { + + @Override + public void process() throws Exception { + System.out.println("Ecomp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/FCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/FCmp.java new file mode 100644 index 000000000..d17c6b162 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/FCmp.java @@ -0,0 +1,22 @@ +package com.yomahub.liteflow.test.subflow.cmp2; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +import static com.yomahub.liteflow.test.subflow.ImplicitSubFlowELSpringbootTest.RUN_TIME_SLOT; + + +@Component("f") +public class FCmp extends NodeComponent { + @Override + public void process() throws Exception { + + RUN_TIME_SLOT.add(this.getSlot().getRequestId()); + + DefaultContext context = this.getFirstContextBean(); + context.setData("innerRequestData", "inner request"); + + System.out.println("Fcomp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/GCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/GCmp.java new file mode 100644 index 000000000..6bd525396 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/GCmp.java @@ -0,0 +1,28 @@ +package com.yomahub.liteflow.test.subflow.cmp2; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; +import org.noear.solon.annotation.Inject; + +import static com.yomahub.liteflow.test.subflow.ImplicitSubFlowELSpringbootTest.RUN_TIME_SLOT; + + +@Component("g") +public class GCmp extends NodeComponent { + + @Inject + private FlowExecutor flowExecutor; + + @Override + public void process() throws Exception { + + RUN_TIME_SLOT.add(this.getSlot().getRequestId()); + + System.out.println("Gcmp executed!"); + + + + this.invoke("chain4", "it's implicit subflow."); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/HCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/HCmp.java new file mode 100644 index 000000000..8825af58a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/HCmp.java @@ -0,0 +1,22 @@ +package com.yomahub.liteflow.test.subflow.cmp2; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +import static com.yomahub.liteflow.test.subflow.ImplicitSubFlowELSpringbootTest.RUN_TIME_SLOT; + + +@Component("h") +public class HCmp extends NodeComponent { + @Override + public void process() throws Exception { + String requestData = this.getSubChainReqData(); + DefaultContext context = this.getFirstContextBean(); + context.setData("innerRequest", requestData); + + RUN_TIME_SLOT.add(this.getSlot().getRequestId()); + + System.out.println("Hcomp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/MCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/MCmp.java new file mode 100644 index 000000000..967d22a41 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/MCmp.java @@ -0,0 +1,18 @@ +package com.yomahub.liteflow.test.subflow.cmp2; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +import static com.yomahub.liteflow.test.subflow.ImplicitSubFlowELSpringbootTest.RUN_TIME_SLOT; + + +@Component("m") +public class MCmp extends NodeComponent { + @Override + public void process() throws Exception { + + RUN_TIME_SLOT.add(this.getSlot().getRequestId()); + + System.out.println("Mcomp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/PCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/PCmp.java new file mode 100644 index 000000000..f4e0a08e4 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/PCmp.java @@ -0,0 +1,23 @@ +package com.yomahub.liteflow.test.subflow.cmp2; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; +import org.noear.solon.annotation.Inject; + +@Component("p") +public class PCmp extends NodeComponent { + + @Inject + private FlowExecutor flowExecutor; + + @Override + public void process() throws Exception { + int slotIndex = this.getSlotIndex(); + for (int i = 0; i < 10; i++) { + int finalI = i; + new Thread(() -> flowExecutor.invoke2RespInAsync("c2", "it's implicit subflow " + finalI, slotIndex)).start(); + } + Thread.sleep(1000); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/QCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/QCmp.java new file mode 100644 index 000000000..3cae2456b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/QCmp.java @@ -0,0 +1,31 @@ +package com.yomahub.liteflow.test.subflow.cmp2; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.noear.solon.annotation.Component; + +import java.util.HashSet; +import java.util.Set; + +import static com.yomahub.liteflow.test.subflow.ImplicitSubFlowELSpringbootTest.RUN_TIME_SLOT; + + +@Component("q") +public class QCmp extends NodeComponent { + @Override + public void process() throws Exception { + String requestData = this.getSubChainReqDataInAsync(); + DefaultContext context = this.getFirstContextBean(); + + synchronized (QCmp.class){ + if (context.hasData("test")){ + Set set = context.getData("test"); + set.add(requestData); + }else{ + Set set = new HashSet<>(); + set.add(requestData); + context.setData("test", set); + } + } + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/R.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/R.java new file mode 100644 index 000000000..804bba47b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/R.java @@ -0,0 +1,12 @@ +package com.yomahub.liteflow.test.subflow.cmp2; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("r") +public class R extends NodeComponent { + @Override + public void process() throws Exception { + this.invoke2Resp("chain_s",""); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/S.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/S.java new file mode 100644 index 000000000..fbaf1dc9f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/subflow/cmp2/S.java @@ -0,0 +1,12 @@ +package com.yomahub.liteflow.test.subflow.cmp2; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("s") +public class S extends NodeComponent { + @Override + public void process() throws Exception { + throw new RuntimeException("test"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/SubstituteSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/SubstituteSpringbootTest.java new file mode 100644 index 000000000..9150ceb68 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/SubstituteSpringbootTest.java @@ -0,0 +1,46 @@ +package com.yomahub.liteflow.test.substituteNode; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境EL替补节点的测试 + * @author Bryan.Zhang + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/substituteNode/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.substituteNode.cmp"}) +public class SubstituteSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //最简单的情况 + @Test + public void testSub1() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + } + + //有替补节点 + @Test + public void testSub2() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg"); + Assert.assertTrue(response.isSuccess()); + } + + //测试特殊命名的节点 + @Test + public void testSub3() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg"); + Assert.assertTrue(response.isSuccess()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/ACmp.java new file mode 100644 index 000000000..d5e1044b9 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.substituteNode.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/BCmp.java new file mode 100644 index 000000000..7bfec97e7 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/BCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.substituteNode.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/CCmp.java new file mode 100644 index 000000000..040bbcbca --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/CCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.substituteNode.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/DCmp.java new file mode 100644 index 000000000..14aa20e9c --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/DCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.substituteNode.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("88-ffc") +public class DCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("DCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/SubCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/SubCmp.java new file mode 100644 index 000000000..776a5b4cf --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/SubCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.substituteNode.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("sub") +public class SubCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("SubCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/SwitchELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/SwitchELSpringbootTest.java new file mode 100644 index 000000000..7d22b45a1 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/SwitchELSpringbootTest.java @@ -0,0 +1,82 @@ +package com.yomahub.liteflow.test.switchcase; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境EL常规的例子测试 + * @author Bryan.Zhang + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource("classpath:/switchcase/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.switchcase.cmp"}) +public class SwitchELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + //2022-07-12 switch 异常错误.c.y.l.builder.el.operator.ToOperator : parameter error + //run QlExpress Exception at line 1 : + // switch().to(): 只有一个node时出错 + @Test + public void testSwitch1() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a==>e==>d==>b", response.getExecuteStepStr()); + } + + @Test + public void testSwitch2() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a==>e==>d",response.getExecuteStepStr()); + } + + @Test + public void testSwitch3() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a==>f==>b",response.getExecuteStepStr()); + } + + //根据tag来跳转,指定哪个组件的tag + @Test + public void testSwitch4() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a==>g==>d",response.getExecuteStepStr()); + } + + //tag的跳转 + @Test + public void testSwitch5() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain5", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a==>h==>b",response.getExecuteStepStr()); + } + + //相同组件的tag的跳转 + @Test + public void testSwitch6() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain6", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a==>h==>b",response.getExecuteStepStr()); + } + + //switch增加default选项 + @Test + public void testSwitch7() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain7", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a==>i==>d",response.getExecuteStepStr()); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/ACmp.java new file mode 100644 index 000000000..6472afd9c --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.switchcase.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/BCmp.java new file mode 100644 index 000000000..235d238ef --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/BCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.switchcase.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/CCmp.java new file mode 100644 index 000000000..be70b9f98 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/CCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.switchcase.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/DCmp.java new file mode 100644 index 000000000..0016737e3 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/DCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.switchcase.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("d") +public class DCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("DCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/ESwitchCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/ESwitchCmp.java new file mode 100644 index 000000000..880ff15f8 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/ESwitchCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.switchcase.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; +import org.noear.solon.annotation.Component; + +@Component("e") +public class ESwitchCmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + return "d"; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/FSwitchCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/FSwitchCmp.java new file mode 100644 index 000000000..7711e26be --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/FSwitchCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.switchcase.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; +import org.noear.solon.annotation.Component; + +@Component("f") +public class FSwitchCmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + return ":td"; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/GSwitchCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/GSwitchCmp.java new file mode 100644 index 000000000..063deb49d --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/GSwitchCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.switchcase.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; +import org.noear.solon.annotation.Component; + +@Component("g") +public class GSwitchCmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + return "d:td"; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/HSwitchCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/HSwitchCmp.java new file mode 100644 index 000000000..d316518bb --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/HSwitchCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.switchcase.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; +import org.noear.solon.annotation.Component; + +@Component("h") +public class HSwitchCmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + return "tag:td"; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/ISwitchCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/ISwitchCmp.java new file mode 100644 index 000000000..c462ffecc --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/ISwitchCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Tingliang Wang + * @email bytlwang@126.com + * @Date 2022/12/09 + */ +package com.yomahub.liteflow.test.switchcase.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; +import org.noear.solon.annotation.Component; + +@Component("i") +public class ISwitchCmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + return "a"; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/NodeTagELSpringbootJsonTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/NodeTagELSpringbootJsonTest.java new file mode 100644 index 000000000..bc615e3bf --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/NodeTagELSpringbootJsonTest.java @@ -0,0 +1,64 @@ +package com.yomahub.liteflow.test.tag; + +import cn.hutool.core.collection.ConcurrentHashSet; +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境下隐私投递的测试 + * @author Bryan.Zhang + * @since 2.5.0 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/tag/application-json.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.tag.cmp"}) +public class NodeTagELSpringbootJsonTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + @Test + public void testTag1() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("123",context.getData("test")); + } + + @Test + public void testTag2() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a==>a==>a==>c==>e", response.getExecuteStepStr()); + } + + //测试多线程when情况下的tag取值是否正确 + //这里循环多次的原因是,因为when多线程,有时候因为凑巧,可能正确。所以多次情况下在2.6.4版本肯定出错 + @Test + public void testTag3() throws Exception{ + for (int i = 0; i < 50; i++) { + LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertTrue(response.isSuccess()); + ConcurrentHashSet testSet = context.getData("test"); + Assert.assertEquals(3, testSet.size()); + } + } + + //测试tag是否能在isAccess中起效 + @Test + public void testTag4() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("g", response.getExecuteStepStr()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/NodeTagELSpringbootXmlTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/NodeTagELSpringbootXmlTest.java new file mode 100644 index 000000000..ffa92937a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/NodeTagELSpringbootXmlTest.java @@ -0,0 +1,73 @@ +package com.yomahub.liteflow.test.tag; + +import cn.hutool.core.collection.ConcurrentHashSet; +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * springboot环境下隐私投递的测试 + * @author Bryan.Zhang + * @since 2.5.0 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/tag/application-xml.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.tag.cmp"}) +public class NodeTagELSpringbootXmlTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + @Test + public void testTag1() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("123",context.getData("test")); + } + + @Test + public void testTag2() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a==>a==>a==>c==>e", response.getExecuteStepStr()); + } + + //测试多线程when情况下的tag取值是否正确 + //这里循环多次的原因是,因为when多线程,有时候因为凑巧,可能正确。所以多次情况下在2.6.4版本肯定出错 + @Test + public void testTag3() throws Exception{ + for (int i = 0; i < 50; i++) { + LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertTrue(response.isSuccess()); + ConcurrentHashSet testSet = context.getData("test"); + Assert.assertEquals(3, testSet.size()); + } + } + + //测试tag是否能在isAccess中起效 + @Test + public void testTag4() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("g", response.getExecuteStepStr()); + } + + //测试tag是否能在WHEN中起效果 + @Test + public void testTag5() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain5", "arg"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("1",context.getData("test")); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/ACmp.java new file mode 100644 index 000000000..6c092f862 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/ACmp.java @@ -0,0 +1,30 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.tag.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; + +@LiteflowComponent("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + String testKey = "test"; + + DefaultContext context = this.getFirstContextBean(); + if (context.getData(testKey) == null){ + context.setData(testKey,this.getTag()); + }else{ + String s = context.getData(testKey); + s += this.getTag(); + context.setData(testKey, s); + } + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/B1Cmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/B1Cmp.java new file mode 100644 index 000000000..4e4aba1fc --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/B1Cmp.java @@ -0,0 +1,23 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.tag.cmp; + +import cn.hutool.core.collection.ConcurrentHashSet; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; + +@LiteflowComponent("b1") +public class B1Cmp extends NodeComponent { + + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + context.setData("test",new ConcurrentHashSet()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/BCmp.java new file mode 100644 index 000000000..fbc4732d2 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/BCmp.java @@ -0,0 +1,24 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.tag.cmp; + +import cn.hutool.core.collection.ConcurrentHashSet; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; + +@LiteflowComponent("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + ConcurrentHashSet testSet = context.getData("test"); + testSet.add(this.getTag()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/CCmp.java new file mode 100644 index 000000000..ceedd8abe --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/CCmp.java @@ -0,0 +1,24 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.tag.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeSwitchComponent; + +@LiteflowComponent("c") +public class CCmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + if(this.getTag().equals("2")){ + return "e"; + }else{ + return "d"; + } + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/DCmp.java new file mode 100644 index 000000000..572980b78 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/DCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.tag.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("d") +public class DCmp extends NodeComponent { + + @Override + public void process() { + System.out.println(this.getTag()); + System.out.println("DCmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/ECmp.java new file mode 100644 index 000000000..11ee96c8a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/ECmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.tag.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("e") +public class ECmp extends NodeComponent { + + @Override + public void process() { + System.out.println(this.getTag()); + System.out.println("ECmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/FCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/FCmp.java new file mode 100644 index 000000000..2f670578e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/FCmp.java @@ -0,0 +1,25 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.tag.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("f") +public class FCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("FCmp executed!"); + } + + @Override + public boolean isAccess() { + return Boolean.parseBoolean(this.getTag()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/GCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/GCmp.java new file mode 100644 index 000000000..f6180b563 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/GCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.tag.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("g") +public class GCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("GCmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/HCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/HCmp.java new file mode 100644 index 000000000..cbdb66e19 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/tag/cmp/HCmp.java @@ -0,0 +1,27 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.tag.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; + +@LiteflowComponent("h") +public class HCmp extends NodeComponent { + + @Override + public void process() { + } + + @Override + public boolean isAccess() { + DefaultContext context = this.getFirstContextBean(); + context.setData("test",this.getTag()); + return true; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/TestTL.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/TestTL.java new file mode 100644 index 000000000..fee0055e5 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/TestTL.java @@ -0,0 +1,16 @@ +package com.yomahub.liteflow.test.useTTLInWhen; + +import com.alibaba.ttl.TransmittableThreadLocal; + +public class TestTL { + + public static ThreadLocal tl = new TransmittableThreadLocal<>(); + + public static String get(){ + return tl.get(); + } + + public static void set(String value){ + tl.set(value); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/UseTTLInWhenELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/UseTTLInWhenELSpringbootTest.java new file mode 100644 index 000000000..c395a2173 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/UseTTLInWhenELSpringbootTest.java @@ -0,0 +1,38 @@ +package com.yomahub.liteflow.test.useTTLInWhen; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +/** + * 在when异步节点的情况下去拿ThreadLocal里的测试场景 + * @author Bryan.Zhang + * @since 2.6.3 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource(value = "classpath:/useTTLInWhen/application.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.useTTLInWhen.cmp"}) +public class UseTTLInWhenELSpringbootTest extends BaseTest { + + @Inject + private FlowExecutor flowExecutor; + + @Test + public void testUseTTLInWhen() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertEquals("hello,b", context.getData("b")); + Assert.assertEquals("hello,c", context.getData("c")); + Assert.assertEquals("hello,d", context.getData("d")); + Assert.assertEquals("hello,e", context.getData("e")); + Assert.assertEquals("hello,f", context.getData("f")); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/ACmp.java new file mode 100644 index 000000000..8fda6d42d --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/ACmp.java @@ -0,0 +1,22 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.useTTLInWhen.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.test.useTTLInWhen.TestTL; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + TestTL.set("hello"); + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/BCmp.java new file mode 100644 index 000000000..cde0d3de0 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/BCmp.java @@ -0,0 +1,26 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.useTTLInWhen.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.useTTLInWhen.TestTL; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + String value = TestTL.get(); + DefaultContext context = this.getFirstContextBean(); + context.setData(this.getNodeId(),value+",b"); + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/CCmp.java new file mode 100644 index 000000000..71f308853 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/CCmp.java @@ -0,0 +1,26 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.useTTLInWhen.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.useTTLInWhen.TestTL; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + String value = TestTL.get(); + DefaultContext context = this.getFirstContextBean(); + context.setData(this.getNodeId(),value+",c"); + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/DCmp.java new file mode 100644 index 000000000..a6aafe5bd --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/DCmp.java @@ -0,0 +1,26 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.useTTLInWhen.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.useTTLInWhen.TestTL; +import org.noear.solon.annotation.Component; + +@Component("d") +public class DCmp extends NodeComponent { + + @Override + public void process() { + String value = TestTL.get(); + DefaultContext context = this.getFirstContextBean(); + context.setData(this.getNodeId(),value+",d"); + System.out.println("DCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/ECmp.java new file mode 100644 index 000000000..fd96f5bdd --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/ECmp.java @@ -0,0 +1,26 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.useTTLInWhen.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.useTTLInWhen.TestTL; +import org.noear.solon.annotation.Component; + +@Component("e") +public class ECmp extends NodeComponent { + + @Override + public void process() { + String value = TestTL.get(); + DefaultContext context = this.getFirstContextBean(); + context.setData(this.getNodeId(),value+",e"); + System.out.println("ECmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/FCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/FCmp.java new file mode 100644 index 000000000..490abfbfc --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/useTTLInWhen/cmp/FCmp.java @@ -0,0 +1,26 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.useTTLInWhen.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.useTTLInWhen.TestTL; +import org.noear.solon.annotation.Component; + +@Component("f") +public class FCmp extends NodeComponent { + + @Override + public void process() { + String value = TestTL.get(); + DefaultContext context = this.getFirstContextBean(); + context.setData(this.getNodeId(),value+",f"); + System.out.println("FCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/validateRule/ValidateRuleELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/validateRule/ValidateRuleELSpringbootTest.java new file mode 100644 index 000000000..c7ae3ed48 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/validateRule/ValidateRuleELSpringbootTest.java @@ -0,0 +1,38 @@ +package com.yomahub.liteflow.test.validateRule; + +import com.yomahub.liteflow.builder.LiteFlowNodeBuilder; +import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder; +import com.yomahub.liteflow.enums.NodeTypeEnum; +import com.yomahub.liteflow.test.BaseTest; +import com.yomahub.liteflow.test.validateRule.cmp.ACmp; +import com.yomahub.liteflow.test.validateRule.cmp.BCmp; +import com.yomahub.liteflow.test.validateRule.cmp.CCmp; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.test.SolonJUnit4ClassRunner; + +@RunWith(SolonJUnit4ClassRunner.class) +public class ValidateRuleELSpringbootTest extends BaseTest { + + @Test + public void testChainELExpressValidate() { + LiteFlowNodeBuilder.createNode().setId("a") + .setName("组件A") + .setType(NodeTypeEnum.COMMON) + .setClazz(ACmp.class) + .build(); + LiteFlowNodeBuilder.createNode().setId("b") + .setName("组件B") + .setType(NodeTypeEnum.COMMON) + .setClazz(BCmp.class) + .build(); + LiteFlowNodeBuilder.createNode().setId("c") + .setName("组件C") + .setType(NodeTypeEnum.COMMON) + .setClazz(CCmp.class) + .build(); + Assert.assertFalse(LiteFlowChainELBuilder.validate("THEN(a, b, h)")); + Assert.assertTrue(LiteFlowChainELBuilder.validate("THEN(a, b, c)")); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/validateRule/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/validateRule/cmp/ACmp.java new file mode 100644 index 000000000..2f094dbc7 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/validateRule/cmp/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.validateRule.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/validateRule/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/validateRule/cmp/BCmp.java new file mode 100644 index 000000000..893ac079d --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/validateRule/cmp/BCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.validateRule.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/validateRule/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/validateRule/cmp/CCmp.java new file mode 100644 index 000000000..af891c1cc --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/validateRule/cmp/CCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.validateRule.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/WhenTimeOutELSpringbootTest1.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/WhenTimeOutELSpringbootTest1.java new file mode 100644 index 000000000..9a771ae0f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/WhenTimeOutELSpringbootTest1.java @@ -0,0 +1,39 @@ +package com.yomahub.liteflow.test.whenTimeOut; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.exception.WhenTimeoutException; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * springboot环境下异步线程超时日志打印测试 + * @author Bryan.Zhang + * @since 2.6.4 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource("classpath:/whenTimeOut/application1.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.whenTimeOut.cmp"}) +public class WhenTimeOutELSpringbootTest1 extends BaseTest { + + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + @Inject + private FlowExecutor flowExecutor; + + //其中b和c在when情况下超时,所以抛出了WhenTimeoutException这个错 + @Test + public void testWhenTimeOut() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertFalse(response.isSuccess()); + Assert.assertEquals(WhenTimeoutException.class, response.getCause().getClass()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/WhenTimeOutELSpringbootTest2.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/WhenTimeOutELSpringbootTest2.java new file mode 100644 index 000000000..05326f62c --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/WhenTimeOutELSpringbootTest2.java @@ -0,0 +1,37 @@ +package com.yomahub.liteflow.test.whenTimeOut; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Import; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * springboot环境下异步线程超时日志打印测试 + * @author Bryan.Zhang + * @since 2.6.4 + */ +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource("classpath:/whenTimeOut/application2.properties") +@Import(scanPackages = {"com.yomahub.liteflow.test.whenTimeOut.cmp"}) +public class WhenTimeOutELSpringbootTest2 extends BaseTest { + + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + @Inject + private FlowExecutor flowExecutor; + + //其中d,e,f都sleep 4秒,其中def是不同的组,超时设置5秒 + @Test + public void testWhenTimeOut() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/ACmp.java new file mode 100644 index 000000000..e6d2d17c9 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.whenTimeOut.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/BCmp.java new file mode 100644 index 000000000..73c63b847 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/BCmp.java @@ -0,0 +1,26 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.whenTimeOut.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + try { + Thread.sleep(4000); + }catch (Exception ignored){ + + } + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/CCmp.java new file mode 100644 index 000000000..0e58e3ccd --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/CCmp.java @@ -0,0 +1,26 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.whenTimeOut.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + try { + Thread.sleep(3500); + }catch (Exception ignored){ + + } + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/DCmp.java new file mode 100644 index 000000000..b4a87faec --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/DCmp.java @@ -0,0 +1,26 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.whenTimeOut.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("d") +public class DCmp extends NodeComponent { + + @Override + public void process() { + try { + Thread.sleep(4000); + }catch (Exception ignored){ + + } + System.out.println("DCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/ECmp.java new file mode 100644 index 000000000..122930c71 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/ECmp.java @@ -0,0 +1,26 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.whenTimeOut.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("e") +public class ECmp extends NodeComponent { + + @Override + public void process() { + try { + Thread.sleep(4000); + }catch (Exception ignored){ + + } + System.out.println("ECmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/FCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/FCmp.java new file mode 100644 index 000000000..9eb2243a4 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/whenTimeOut/cmp/FCmp.java @@ -0,0 +1,26 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.whenTimeOut.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +@Component("f") +public class FCmp extends NodeComponent { + + @Override + public void process() { + try { + Thread.sleep(4000); + }catch (Exception ignored){ + + } + System.out.println("FCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/absoluteConfigPath/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/absoluteConfigPath/application.properties new file mode 100644 index 000000000..348a63af9 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/absoluteConfigPath/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=/usr/local/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/absoluteConfigPath/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/absoluteConfigPath/flow.el.xml new file mode 100644 index 000000000..0d670c770 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/absoluteConfigPath/flow.el.xml @@ -0,0 +1,7 @@ + + + + + WHEN(a,b,c); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/aop/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/aop/application.properties new file mode 100644 index 000000000..0a8873bf3 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/aop/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=aop/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/aop/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/aop/flow.el.xml new file mode 100644 index 000000000..8b89951a2 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/aop/flow.el.xml @@ -0,0 +1,14 @@ + + + + THEN(a,b,c,d,e); + + + + THEN(a,b,c,WHEN(d,e)); + + + + THEN(a,b,c,f); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/asyncNode/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/asyncNode/application.properties new file mode 100644 index 000000000..69053aff5 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/asyncNode/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=asyncNode/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/asyncNode/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/asyncNode/flow.el.xml new file mode 100644 index 000000000..06373bb2f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/asyncNode/flow.el.xml @@ -0,0 +1,49 @@ + + + + + THEN( + a,b,c, + WHEN(d, SWITCH(e).to(f,g)), + chain2 + ); + + + + + THEN(b, SWITCH(j).to(a, chain3)); + + + + WHEN(g, f, h); + + + + THEN(WHEN(f, g, i), WHEN(h)); + + + + THEN(WHEN(f, g, i).ignoreError(true), WHEN(h)); + + + + THEN(a, b, c, WHEN(d, i, g, i, h).ignoreError(true)); + + + + THEN(a, b, c, WHEN(d, i, g, i, h)); + + + + THEN(a, b, c, WHEN(d, i), WHEN(g, i, h).ignoreError(true)); + + + + THEN(a, b, c, WHEN(d, i).ignoreError(true), WHEN(g, i, h)); + + + + THEN(WHEN(d, g, h).any(true), THEN(a, b, c)); + + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/base/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/base/application.properties new file mode 100644 index 000000000..1f5b49a07 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/base/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=base/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/base/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/base/flow.el.xml new file mode 100644 index 000000000..af69a1c64 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/base/flow.el.xml @@ -0,0 +1,54 @@ + + + + + THEN(a,b,WHEN(c,d)); + + + + THEN( + a,b, + SWITCH(e).to(d,f) + ); + + + + THEN( + a, + WHEN( + c, + SWITCH(g).to(b, d, THEN(h,i).id("then_1001")) + ) + ); + + + + THEN( + a,b, + WHEN( + THEN(c, WHEN(j,k)), + d, + THEN(h, i) + ), + SWITCH(x).to( + m, + n, + WHEN(q, THEN(p, r)).id("w01") + ), + z + ); + + + + t1 = THEN(c, WHEN(j,k)); + w1 = WHEN(q, THEN(p, r)).id("w01"); + t2 = THEN(h, i); + + THEN( + a,b, + WHEN(t1, d, t2 ), + SWITCH(x).to(m, n, w1), + z + ); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/base/img.png b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/base/img.png new file mode 100644 index 0000000000000000000000000000000000000000..b6dc946ac229120c7d0ec25f5bfc04dd5dfd66f9 GIT binary patch literal 276050 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
4BtUUul%QZ`fZ-_M$lI>i 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

H4eU9@HnwIex*?3g5!rzH ztO=(NUogI^6qKD*QVQ-x4HnWUp+^j2fiYuuZpFF}e^IA`l8CtU8WNPlZtj|0Iwq=MY!nl@ajk@UO#deQj zBQ>Sb$w$$preemcJ;kQ7QK8sOn?F%szUG4NRXS|Ybb!cc1+xzmgwI5ZGWtjik@P}f zgo4k}8viG|=nQ!SOb&bcQg!R^VXJZMqu%7!09-?-CI-RnHlBGG@jVGwUo*a$(LLpT zM{vO6qBHBj=)PJ<#J;w{>eP-t+ywOM#?R{Ci7Hi-k8YlQ!aba+I{e}`Xa3+XS8}H!$ATq!9 z$z|K_x9Q(>v`Pup3aH>?-11xYQ%4`(UlHMhJ(7FakeXMJjc!W>!}Sxl%6q9fIt+Ji z_KLjg8bs^@jG24M#QY^LU?xE%UmO7MGTZgt^yKAEcvY1V+wl43@Zb z)psSm)T|2m_D=V?MtU)B{B?oDLm+EPP+#P|{X)dYr4VsfJRR*jSDi325?#VA)?G6% z=zZJukSG%m`_Scm7aJ&Dl^)+RU88xS_aL&akwT}}&HTd-G)uhAV<~#~9K-9{meGm2 z=9Muh7wHz79mniIXCfqI|82fD_0{#|^Os+hRggLb%T9QA%4+GIQWK}WawDyYTg&a+ zS2GN20iOC`WxtJGWd>(Zy0s9lYm4UcF5YW23hjZkrTy11)2Ntv4rZ-_-d=1lEw!9P zFUKJ3VNY&WJDYypVqLfSa`T*RF{t@VvvV-Vt=oiEBY@vlaJj|-1cDUzc+LF>NJ2i=Nn7J`6E;J9y z_dr79G)xgb;MNV@|3Rxe{aCNNx96{UH#=P3_e5#}LFSeHZ7Z~*dafaz{zl(Kh4r_+ zz%ey=O+2Scth24dcIgaySB9C_qBm?zLFTvx+qk(ce6_6qs^OSn|iQizEZ_)^{e5R zB4uy8J^xf{t7mkmfBgHCA&TVS!*O4StuVcEoA=IDI`A2B90{=P$PA;qJFjiYp`qV7 z@mvJnoq$p7Ag4ck_H6?ft3#-H#bh3!T!%1Smtn16{rR;WIUjU zW%&$Xf$SHB^{Y(o3sJeU`Sq*Ep+QrEZm&Yp+tAgjm9Gx%iX(QH@`DV9oG#@%(e>K5 zV(0d5)X3{{&|OS2SWFTxl%go(Xfv)TJUQWesXV%5hysq6WRb+7v-PW{`L?p-Pt0pY zg+oxqhpfPjcX@$|Cxx##Ttwth{IaEHpQb^OaGj9db@M)}nHZE~clhqvo>&ams--lo z8hVF;TzJZM9c^a`p^TOL_S6$v4;}Vq9B*PfD|#^SiqBA+e!W91D%-Bn%GP&(BxNbQOpM*-)XiL~aiQ->DY7b-9PUDe`kgu}wcBNM8s`sM zH%{M0$uQ*4*1n+>ob;i)+_oan(^|DEl($ttDt%%boc>_!M}A}vD{ueUKIr~2{o)$2 z(j7i(X1oXXKh@#iMackm9J5@1$VwChcdwXAI?7|qF6_gJTi za`e<%+S1d~7kb5c69w%zWcv?VHSajUQZgY^E8rEkTtyLZGVo#*(2ff&Q%M zVQ0AA9Amb#Cft=fbVz>5?*KYx=kmAm;Ttx6+uVibP6Va1;E>-F7pa8lf%`#syCc_N zISquJ;?)gZo6Rv>Dh{o*92(3)zdK(QgW3@U2a~rAOI@m3Hk{qLUokI20xg*)bth$8 zEe{G@I8ycPC>lK99jOv1XluttDJv?x8uHYPlC~7a9BG_z>iqHGb*g(SnMxxjqLAR0 zaX|1gM3G*t6=F^R@{mLF2jL&_TYnDZQItOec{7$Z$i~j`s$H*&q6Au+^#DtTk_5WK zYMW@GU|xN5TFxV>Omu^n3r-S!@vw2wuHge{TeXCjd&O2mb2f#XdiO*zLrJ(g;cdn|Q^4u0Lzr%4ClafFG} z#fE(4ZM-BefzCx&T69=Rpf{OxcA8;=HZ^014O{h!cQ^mCQf)(bQ2<;ds6_4WNYD&@ z2~8;|Na~(GQlKsBD7)jJBiIHfh4i~D0x8(GkgE<4FuTF!sC+02waxcff5Wo4&& zsh~WC+QrwOK>}8m%s`CuvH-UFH5_C?CkmtxVhfbZ2f)qm|?b5=NG`5 zZG|sT{ivM^XAR^Ho@K@|TvZR5J|4mjBg7 zQD~u=!J%!_EJlFdvc()z_3Fs~?gLoFqMYNrpafY>n9C29kVlZ5$()fQLr-< zt!@Y&Dl?;R@WLoG5X>0?%yex0aR-Dqc=`J;z3;1}OUEJe#{2710*1;?W+;hD9gJ_^ zA%D|w2HuR;pCRCX^_k$U%s!UNEN#c)KLH33K_X_#`%c#sDNhDe+)$anMCt6>*JvNT zW^C{O>S8I`^@hllM9q%978s4qzuf=o26AJM-*|EBpX zD5QId+|ye^YZ}NHwIZkU)_%BbHisfHXIZDx7I~o|A4K$@n_*ssnqgXRnqef4BH>_$ zc*CdW#|7ZU2Cr?j+`40yqrt136^DyKB_95}c&L6#pcNKtfXe^$z;4Lb?{lE+lwS`~ zxSwhieqy3#_Z5!#VyL2V1Lf`i&5)>(A!S{|g2SOjE$G=P%rFU}Cn-LFPnF_Uc+x$W z-#4!HYu&Kj*g)z0DCU0W7UHIKzzfCs_|1KWTS_Yfk+oPN_$MMD0zjQo?mET-gmI~q zx%9XD1b_nAVQyQe(t4PQO>4+FLuC9@_S$-kPnn zo+Nupc*FA!%Oatb_aZCjB+xpyCD0QV4p-cDX3u(v=}A3we1E`{mF0`$Pc&<~wz~3q zLZhU3*>$q$f)A3skP(4TDPMzE#@MIW+0l-84EBcM^C9^ZF;6Q0tgTzUKYbz;cgsU9 z|IPW42Fg!T!;gD6J{9`vN!a~xm+OFHvjH|4 z45qJN%Nt8v&9)_VSA3BlAqCA9A9rlko39xE-u+s}!yOp{F;zendee6*076hk+VwmE zI?D$4SlhE2U6T2L8HDD?tuU@GJ;$W2Cngex%2Fk8z68I>mgUd=fy#T@S$H2tK#8&i zI}wxU*7>hsYu$rsKrAfod_h;p@b$NFw>l*MLTX}J;l*!oi#C43yg(5-jtKl>X&15f z0*Fe!!iZMjf*&hpY54+>#NR?xjZau0PTut8JaHMk%C|y%Vd1SdqmysJ)5pAEvuQrDosknkT=O}%2a)H+J~t@VXoh#(jD3oR zUvDE=e1tGV6T1F%nj6I7*6q02mpcma_$EA=1X=;Y_jS>$!ut2jFt>Vk|E##!*}*&m zeZ8+7Qm_$a8Yl&iJb+t&pv=}1qtYn&fJ4z^`^)*`_iPTs=8f~{SdpZII3%b3X`^F`edAYG$Ld@p0 zv}-=}GG0qrUp;CkpUkGCr)Lmpc*$Ys4k^id8u0-`p5g!Dot9oO6w^u8LE+FrWxl<* z;=Zk4p}=dee}~R+&PunzE3$Zi?~0Mpqva2t4EVf~G5ZYV47XA9Dfg>Tg1Sl*O3n!W z9SBFNAa-`WP(~KUQBfyIO$d}u3Va0*>+ah%LQ5ygtP`aYd=(r8oXE+=dM0jh4bvIj zj)ki3+r$TuTcZF(`^?y=H-y_|~WNzY1GPeX>iTCdJI zH7D%<1S^sD;L@}=OEEXnDGFmN&E;lq&q zZEka2kw{@L2^mwfQh8|ksC#h7$5ItL`Rk=qapMDY`&mCAUhadEVYDd z>PN?#$AhRZK+^#IpS@$cL(A5yjFna^ZB~PK6C>sf4R_$jv3P6l*UN(&gpbR|{! zuY6M6aGRq6bW(-7JbM0%;~M4$j4bP1rcXCrx!q$2 zrs`9BD(^d$)!Oxh1@$X0b}D}auGkMdL?ETd5Qatn?7hW5*f7N0GcFcCQ`@j# z78>Pobfm?67-L$EC~~57yk?qTsPj!G2Y_9=t$j***lkPa+QqH*x>R*DUE@F72)t0t z{n$1RPGh~cvpl0+UeCKdtLl)E7u8=fDbmAiSDO{+ihLl{b$4@OD-@!DV$+Hk*hnQR z*|Nrx(x~BcA7Rq*f)$gyOR(^I#Z@%}O;>bmS$u64iT(7tpLBOF{NUqy6be%94|12Pqb%R6@L=nJLHU)K*m zIHg6IRm~Ywa_qQur8+||J%DeK3c(qj*Gp7&C%1j?Zlqguk}exvq2?L)grll8?0zIQ zU5xGaosvgI?x{3FKY7TL!KBcL9|Hk{NJ9wFPZ10r*kdTylPOBHI{ zkbVi|p;pE7>2@7Welh0*+_=&P%)6qzqhE@U}=k5s?ZYP zsbjP3HtK`O8aXw6wd$HXw-?^{v|^jZidGSi6VLiRPE~}*S8Pb1N%z9T-xV~1$L0J4 z72vmkm1;JZKnVSvDrDf@w)u+Ah<;D`RUxS9DXUBY{$o-yFO58h_l>MGxoGQ0Dq5Qb z3nw?ra*Wma4l_~?O)@MX^gtFA&N<6GK`W9)R}1L7`crI^&~nQJZI*jDVDQ||BT-0u zhtxSH&TX&ciGdFLpbLhrk=(nHnX`@)obXL-q*>{Z{@dmjmybZNHt$rIELV?jBw*Kw zKem?(q2E5bT=_PRH^$^%-;#^kQhFjJu$!dvMHpr7rr<#*5ohG)Yqa`9@v$zl z6O1+*Tbt(SsNU9H{Gy*MC*V9{vK0@7;sm&)Z)4>IU~yfVu0`5IIZy0mo` zuGXjZmi`ENmA2!CYn1(us`Xfgw(j!ZAF0@;8`XVzOOwmnn3eHTW zZg%#=2Cyk^u5M1s%}T&_hpaZ8$s(}uO-l4#1Fbv4t)v$#Lv`31+;c_}I0sjJEpdesW@2vg4TC@opzNI#;^WKOVmnCrlKj1T+d= ztA+M{W^J)Y$@DcS{M(r+)5tT2C7~4x9o2P{-|%aE6(e7M@Dz+f>FOqdM(i2pCyHU9D6Qc?vRa2!)bCx?FZ~12m#^47(Ux$v+2202rSdVTzvZ{8-ML5g67im)5S93q4db4v?10{t$T>} z(lgCT>cqf`pTf1Z>1{$NR8USCt3azHd1o`jcIBo=Xin!85F}@FrC!o`VB7a2IFz7I zV!w=|!>FpX64sgB$euA;jp6g+j(Wx9e20eg%#r014Ajiov!=u&;`j| zAwT3~q0LZh=#cr;A7!XxGO@l+1NwbZLw3scASnx8Y~8ZR^#yuEr!H>nX&9>b^DKvQ zyu^BwIWpy;k>`W`H$A_Ss>AK=EHBD1($u3pZ155wTT2|WwM^fIdBMNo^VZP$umyIz z3T?c4yuAs@d49bYb>;Y#dn-zHmABBuPI}16(5}9YC9uAGsT~6%;m&PkrppJiu4H8e z*6ifCvw|%UjrCxV#4_!Bn<+~K?`&*;(rdoFfoqtvJx_2-NCk=vzj5%Sc8nkrwY;gk zp|UZPEpr1$&)G<%eaVFW+-P@3Ay*O;LL6(_T0mirw0W?JJTa{Wj^|s#0Z=QLeY~R? z$Tno=lsCFJQOvc9zPWpqvjU6~ffg0I9XEIxzm_K-;Hf6=m-M3SE*kx`jNrmn_h9&a zbjcbuc#0203OiPGmdwbb>p6+jy>&~t8EhqeAThBprPBtvbstQG9RGBOdUqVY5Mr0I z7g_+w=`>}wF7qRHu?tJ!PR>1=*DHrP!>nz7e6|`$owT&HON;M0GOF3VmVn^gEclGb zvODVhm4n^)`~`j79N5EaN>t`dupla)Ni;Jqm!+ z(}@B+$z{vL3arTu5j;8P%*o~!ym5ym(MWZpqn$k5uv7(GD501efYeS1HV0{7*S1xL z8wV&v8RMIGYHMr9easy9=D}DtMS}>ZTZ?z&yw>S)U*7y_5>EsczHGQ%9w&>?GbPhx zvE~;ND;w^3Hn9hx^mi)R)YS)t)>W?QO_Jf4c}NFGG_l+3hH9n}j(R!sqb1dag(qgX>8;ZZY2;B69%%@WmEHl5I(~2^Q-ieT&U4Hk)usj% zDJ_{Y><_zLdE}djq82*dS&eM6Dv^TGk%Ecm!J51h`Mw4;LEUzaA~PR7JJ>jBJ^Ej% z8AwVdXf8Gv(1iyOXI%OdGbiVT$k0E9#xl*;Vi#(yI($S-XCkjnSt(=u|dNFzuCp zrTfLebW^7s{#qyLrZ*eczjwop(R9-pRM7qUG4F(u=MJ8dwrbBVro;K&A;$LNt{~iQ z213t^8R?vnH|H(pD}wwDf3~m}mBKah=C%-uNex(4o8#^IerrA=BhKzCmcxFuvLyc7 z_j>py8bA%1_x2e>mO?pEkaHJM+{o&)E zT>`+r`S@DO+_&RA_{rVYeS+ zcY1b#LS3*bX19rXs^DvCm-yMGT-|YcEynivERv)%&veISzS!j)V5!6>(r{Kzau`>e z?b!4Y!K(gj;ll}`s~II_LvRAkk_J{+FRpr%EN{|+L*MlK@*MhR0tq;*yZnL@5#jcL zb*Qc+TXz9r4*SormcF`9C?!$)ff;J4I{xz`V-eU2yH@+F*)pq#ry}gSgXcwDm0=X5 z-5R?5L>C0=fs~@InZ`K;=lF=IoLg{fNCiEcc7|+NpK+f}>|25l`Um_x0v>a2P=cEAp$yj%N5NJa%A$FeL99zHcPi*nG*-pZM(FFRd6d1 z58p$k+Ml5LT)Ro0%sP(|8bUJ2WhOYCXCBQoOg8uhdK35h9S4;9YF?-t2^hk3{DNC z1A|p1`W}9Yv?rd}run*d<|n%s+7BS@9GpbZnFKjLe+dnk45CGAJJaCxAo|xIA&p)@ zN|~ka8~C6!n&L@y!P>34d$%ee$j^%tqF8A{A|hR){zzK*pq77BWKE1%C3eAQ^*j}3 zQl8Chu{X|vJRw|1D>APyt}l<>+>AP#-m~rt4SZEJvsbb2V5MZ4v`x)2BizUeu({o*l%w8@1 z3;~(eO2sEFOT+5zhfI)8XAbzXoke83;0Z11q{D4LXh(#Ed{CL0|CGG&N&Pd7FdST% zV@$Rs69}>{m(2^-_T`S1mpo;t%q3Z!aG6kZ2~ZG^)NpN$ROAvp{(Q@2!^jN+&r?iZ ze+hZ$RjTS)fBk%vnCpQ8C^*cnp42d5V?{1OIvg4?vUyiYxJ2KRB6H*kHeax;8Yaz+ z1!|eT?`c?=o0=-r>Qt=|AvOjCVRv0qh0o@NG-SK@!i^F6l8bSx`Fw7Qp*R1>G7L{4a#pw>aBQaRm7-p!7pQ{u&6>&J+j2W`% z#sQJvsq?C%*f*9k?L&E2v2BiylE5=%LS3Xi)&R4QT7$b-E^py$5dl!*DYpBG3f##p zeEm@9;i1qQ_N>2ZW7A23!H5wRdu`bypI{T6N9+R-q6bXb}Se^$1|c;JE2Be zl8Zet?OGi;x0f#Gu>lsitE%-6yyytq3jM{A1M*4!h>zL$YV%b|`qP^h0yA^>=fP0a z@;1BB#}N?~lu{xXc|`g&>4@rB(!Gn!ZEpekt7~GD9n*!)@5@x=+9L88dE{oc0kYG7 zY>Iym?WATo>$e43YPamP$!htau0XMz^cYZ}F@C}sd=jxxw$a=ZEdCrcD$m9EMe2jE z8(!xNp{FZafsr592V!ru?Ps{a!lk0PWJ}cUC28HCHI@(!5EK%<$v2g21e{S}J)fzq zD4E9x4jiz@^##!>$diy`GCOz}@Q47Sd|QjdP+3J!cc|H*R2=~h%^3WqJwRFhY1K(Z z%>6?E1QmfYi!baPjA>%nvPJtbl+I%ybh#;nI?D1NtAxLNJeFHpT)uJdsHD6g9Zsi1 zaD@M7zF`}eDVshxDTAshi(e>AL~>gPC)IZGHFoBMn!Rs&U*?8&eLtLplK=XjRX*uP zno)NL-?@2u1~jp#KiIZLO9*wnC#WtXxzj~i{$K04c$n*-5e)ZAu0tl3j)MbDsDen5 zQQStKz~Fk=M`z-NS{L2%)-Rb@=3OU1wD@PuR-z&tt0D9_^`C8VCuIq&A2xerm&3Ur zUvNcSc-J3=G6+&(294GHe+N=5ttFpf7E-_U!bE*6Xh%K!&SGaTj)V%&1B7Hf8-Se& z829sayjs-J;yh>Vw+F;qzc08f?!TnzrN38jO~wN4-5aX*?Y8rv55RV z>WwTG*43UOgTA-7{@qn1 zaBp}T#>vtuL;Ddt_6ah8dtAX~T%ixtQGE~=@{Wk1+tNnI#L+@@aj^&HJO~_J0kH>W z!6g_V)3K#cHD`C)m%sRuzZ6R`J3(OFEp#K&OyJ5T1M#S?a@bx=jO-5(7_aS84y1v8L>jD6y2rxnWw4VkgSw1vR|+8swBZpY{6O)aXmtML z-nH!Y_-5}q5=sw-4yGU_!VEb;@#$Jiy%4ZPgXC`ByPK}~U)-?-l7?Bt4=O!5B{N;H zeyngvPqX4mtn1F04ft`A%TB8~~Vz+Jy zC@NOO2B$|%Pn8aw;JbO!L-)F=(U*~DO|p-JHO~051uMnJE2n>=i5KyQ+Q>IFZ8>6< zBU;9hJJYbs(2L)BL1tAO&t5 z`JlG;Y@`$&&Ri#qs@w|G)r9CrYmOVPv0`XUIp8+Wy4k%inCvHny4n-T?T%J@REYOv zbq6z$oq1K%kFlWl{O|(r-kp^_j5kwiwbPo{1bQ8>39BTbNqAlpDq)aX#>x}3^msCj zKEMUS=PGodynrks9-zg%xG8Vs9$cgm_Fsv=4m#Z=M;~kdwMYwlbR(0pYrmAzr!S<}Dl zM3}Fcl$Kw66rlE13h(~PgCTDMzW<_1tN0pXpz%id3r&#yG%TgtwJU3N@u=ALVR+x9 zx7=^Uyz*t?o0lFd6+8g6>k^kREAAVD*XR1Z^95vu4MFv6wp?MJ!!FzKXnm(uJhD$h zSA~&(PNf_9IP%CyukWhqCf$)M^KW+k2!rIpR&ZO@W#6qBQ7v;|jY0%0{};QkROw3a z)EDBxt#fs~fhCSk`zo7gcqr3gcH5SryRb8iwqMEdM&eGXKJZ_=39s23oYL5tdv1?r zpDMr*$Zst!!&)f<%a@LJJa(0(U!qRW7gu6xv-BtQZod0&-{=%|ajli~eF<>qQMH=&MC>^T-#PqC{}`hi$eL{MIN6C${&Ab z1%YZYi03u$i;0;Evokf*WiC@hDhVNLi4$7H+6L|$j|UN*4qFpC$3}m$N>#h_B5YlX z^;nmMKxg?ro7bc5!V}!YsUFC(v7@vt+*p-_@|g5nxAMwCjRl}BO*$I2Dh1pqvD-eV zpm?nm&-PcFzcb)1P6SjQmr#enQe-W~}E+4WwW7jip<2uJXu2(qZf? z99kZgOV157*j#;|?|{@%i?hkpPvaWf>pd(vjiTDxS-@iTTLUdDf;#XKG_s)j)Y}-9 z%Q7-=uR`ZpY&piIeC+n&J4!J#km&01y+>=D-AYr({&yVT_bxDEVZfl80Xto2g%scj zkI*+g(sAK!NJNA(breH=I3-v(i{f-NFETc1Rv>Zlowzyh8dCkl*+tEDtHyagd)KLs zQpb?m&p2jB^V+-5#8N;M|Hfhk2%Q76vcJLG(zc#7_CVvdrENzrRm|0KO~EKqGC4z@ zR6r=bJlEB?nKOtdbF;73q+etwlCfg<`3Zu}_r=OA7>zWp;x;8NOy&+D^`d3<`Br<~ zX5z{vYg~zFo%2J>3$0GTF`RwMKSITX&&$2zn7FM8(JJ3GPP|2?dSffnmCodYZwO&x3Y?C>Mhmy502IVwEB{Kz`mkkKRqs zB4ys$Yo+OQME;L{D#TK+X&U`EBoIsJ!j}|n1`Igf{q{ToVtoz2+bw=U!5w98?DzI6 z-2V|LyJ6|TU2+403j!^K8a%VZ5X}azUt_1;dxFmx#!2K=o-p01%kJKnPF3zY?8)@; z64;0eRtnUR<&)m@BTeM=&vt|*7bvM*P6##r`+Eo~1Q0+j>At56tm>KyEe+n#5q5rH z*p9JTY-T@}VmsgYsiSy~z@&K!w&iLSfy4*F-#L1dyAII2_5UR$PHW~qp-a+-+cTEB z%+FxCy2Td_!tLLSmtn|Pne7rl6zCNeSO}~mQa%FS*?>*%u zOQ>!SxIyf{5t3`;B9p~jNmv5o!}N9HDw`64WW7LdSLOz>1oQ9eAeCUF#Az+di^ZF- zA?h?s3x1%3P%ne9Y||axAMRMk|7Lpmtx55slo4P3ggo&L2Zy5~e@71eTADg<`|z9E zk7lakJ34iWW|{$074#PZf1rD`&1-knqO$xG#(R5Z$#5R`Na@Y9^p7 zoYQ5;{CC_extJKS6a~-)Z7R1Eu}#sGd+{}L=6IqtnNckUkI5J1#bA26FTQ7eV{%b3 z+ZN5u%}vv9cgvQ@;#%j&DwONBab;d(n$=D<*ahu1W(*7rVEA1HsTKEaa`(FYlF+oJ z@h7c0oAYhit&UbDyqTTdBoMeewDDSUKhdA{J!Z0`1=MjKnRNi`l{a4z8Ml-J5G7_V z0ns3^Y)?`Y4NmuBs@Jy}EV|g#kP6%H>genGBbKRacdn{O^}92d%q9Y@A#T}w$&=DX z?saD-5{h**C0`~Sx9(8xzM zghl(0;Kp%X^rP>RW>L-JP@hWn!t3iUQ!f+=UsnV8`>aN??IfBLX?-Gj$>+{A-_uR{ zf<1*@_}nu7#c4<1c~f-fbyW@e_XSg8&9NIIsEDgXlr);}F1a zNxD}E)DChg?WqGdQffEsmkHl)M5>ShP!XPI*C}fX{_do4!cI*rHu5GqQlJtnwBV3= zDyG~0os!)+`!4dP{+C4i5|fZoWXYQg9v(RaB(;Zs!tlUmxBX7Z4r&O0C^Z$`%6HQj zJE&{~lnO#!WindW9)km6B`n={9mpEX9f-m3Z(^fg4{sn|5KpuOGf3Tl0r=H+fdI93 zN1{yibx-0VB_49gcpXE@=WD7rnZLcpFt6|zLA`F9;4tV11Z6DfE!QYDN!MPU8RCog$Siu3e6}=(iyZeJo>wo_yh7uT|2JXe0+n!9639tV_ zeQs(%+n@{(n}(G^4FCI*a>AFb!J+3el#mEX&2x*1Jy7nhgU@P>NZZs`Tmp+el(MHN z`5HD+r&%lE<}_XO!C`ZGA$P<;5!>Hz0FiRNc z+Jp0-OAs)(7Gt^*@!AhLf$e(a6;fpK4VtMh8Ly#+gvYN8jYlRx5#Qk6+BR+VmWq0? zg`3REMNUCtU<`Ls)(;{m4yW-dwk5ZSCmqVMH|oQeYi(kPo@=RWqLrDp$w%ihBk)d{ zFJA%{fVlU89|-&GlvXQ!L$fH$mam}#5fhcUAz($`*m~R1F8o801g}0o)tWxd|6r3b zOBT?ty#}W!C^rgm5JNKwiAuCxRKLv4R7JNa`c3m^sg^JuLuWm3*@DMYs@4>zYi)f@ zWPQq`5T@y@n1?@6128eaUn4)n2mfHt|%h z!ys~*fUkHkEy`=@{s3AnezohUGx!=nRL5C=DGpDK5ViPW;jP)cd=AVztA^=m_LILD zh>WbWIOa(qXTBo>ff%b_e7}pjcZy}wW|(d36|7a295|qN*`4^prfZ5&Z zB41nh;b2X;b)+h(Cqb^gSvt&Ie#ZDbqJwMsye)c`_%>0Iy%iiv`P z4Z`ziT7Bs};*6v}zzNDt>10?6m#F*9OwmQa^i*Al7J;gV+I;q z+jA}fl$tg8k``kHsJfQ_`e=Sjx-z6Y=`KFg!j(iA&fMCHgo*ccVO;EJ=-gtX%bb~5 z?P8K%8y4;+(E}db&#q7_MZH zP|S)lH)IqaCko_3ooXHVe6|)EMA3Q;SnTh@5}hqd)vdp(v?}&M0t5BLr&qBc79>A= zWYjkuCwZ+B0jam8Tm69KdQrnTwdQ0pFg$wx1!q7_#CaMg%a@_(%JAykoywg$+MCo0 zH!DuFqu~zqf2ltjbntg2ho!)hgC8NPs!S0xKVoJ0#*w0U?bqC@<#%w#O_O%(>H4sPg`v62#^K&#k+?pc3d=Er~_z&yV;{ZsGjoIa_bL2S8 zu&b!US0+5Y#6*j6kx3K=*jb}vwy{Mc40+QbQD~a0xj}9*j@YjIkhtjCnF^Qi2u`{% zu-y;C*V0aH4A@ghe#uxbgV1p_yZEKWPrE$TAK0=RuG8Jtj40;qtV+zNlV&~XeC3zM zec4F;FAjGeI@Ia&IEi6s|3Lg=q5ef%#Te2yjuxt@+9}h!O{v6T9b#9Y77{5{yKG`U z8$u6v6$WdVxj;aKn^m2pJ2m^6kl^b|<4vXIeBFm{51XAkc)L(PjEZ^o^pT)Zy2R%5 zhp$47Mw7fQN!6C3B>x@UE4Pc+?7g1U?llOvi(<+!$#jZejT);ss~?$wc=|QwAdLMq za{aiyZ3seX`OcXjf|4Hf^X-guf*G22HDnP`wTHtCe<(N?DdvK zK5<~pDIDD@N%!f+!u4#5QK_zl4h)`$^J8=tKCAVdc(umU`qXUv&8^XUTtAy_)s5;0 z{I~_z64#a*@LS)85Hy{nf|FaU0KG{&4ureVsvI9z&u2SkD0%A&+Gi`k)YI`lsjQz4 z_F4IMp)w?zXtFE6z@BJxenB(Lg zlz(A#*MjGl$458xpmQ@bj^tL9tfn#(r{xw!S|U6)_N)!gc+M#SzHUq8)mcuBxPd+g z*?+p9B9)#(o+}KZ8Z>lo$)WG}^rMgej$i&CBDds2g_fIhvviybQk#n0J+h~_-T1*@ z{v_Sz)#rLf?vl3k2TWxXC8nbcHv&u#0V z46Rkikv^=@h%B|BBZ!Oi@4y)wlT(`TudC_0oSSKnwm@DnF}EJ{B?gA*i_u9WQ@-3zdUqAWb@i26y%(m+uX3d*+p{#(r5uF z=NnWKAh&1Zd;b$35A`MpR?Zy8Zv((7)ez19FL$k})rFR>ZG%F@cVhXFM-dAV>(4K| zBf@2*99+c6#2PSt9B}NRRtw^rBN+Pp_5#iH2Yb{%>`bo2dUnwjH5)m1O@(s!N<@iq z8KYaR3w}uOm7X=6;Wl7HKC&dXG{7u-(gEIHgnqNF}&cz7*j%rZ( z<2z#JV-B&S>}7w5g+yrFuh`w+VGC|)s-yXvH0K9zcaxA{2^deT9Iz##3dFO2q&HrI zZl01E_xgZS?2)ejetUcAJAjsC=Zv_dsn4 z{69Y2XEXFbKsTu%w;Ljg=sM+ou6O3+3j-JE)5?A7lFpW2Ms{QyRcgf8?q?4TQI1!Z zf}6SbU+&mzwg)oY7+pIBJ)~r|D2wq3p8l5-40_%I*Hx5LoBWenRwafesByMAMqY(oG&SCb0-?k47*YqXdGIJL;V_a8BU zfq)2)emz&28;r2HRkUcB<2xH4!SF=V4zfS@0-&4(8S-x<_FLow`^n8*u}us;%3X47 zXHKgKI7R9PG7mFx_~9T7{Y!;OjuRJwS`Wy5SLP)wR7dcQ4X=lNZ5>gjK{c(aVE}*Q!OCJO3GZyHhvPM0oleOH$05(!pO;Tp-|A*wK8wc z3kV2+evuhMORq(WnJ>=t#KN@Y>t8P)-)f?#2klwWmEx9M{ zksx3D8P9MOu%TJNPpplFq*qU3x)Fq`qAEAN10@@#GVIEsWU0!_Hgr$dGck!Px?O-8 z_7RW7zM_qnnRC?x%@pk{s{BrZ+zQ%0W^Kd!p$x>MmP@2nn`XXWk$K}VqP(l?rrDsn z(|@J2f*gxVqn8K_2r+0ldU44c0r_%}Gu)l}yRdB0ScG;(TF&}C{UUwPVw-Mu9`UL9 ztBeGuXl=!;qJ3{W?iGYv&{hpC7l~=!EW4ZTMh48T6IwgVyiZ46T_Zx(&{<4Tsr*^2 zeC2Z5+JJV2Sl`!NN%DIj5`Lp(1D1FNBsPS+mKGlX)g}EhsB##wGcQL7(=ulusNy!Z zL~1*&)djEV(uIYruHQ4AuC0RTw0NBX#;5{W6ugHp=L{L=bjxdP;E6y8=|cRsUvqf>>4tk_L&@6oX>esCv8I3E z9)7yd){sf-Ojhxn@&-O0kLJWm*IxcP>y@a$ZhE`aD?;mM8WDo zYNnvI9&ff%4HtecAue0T3jVI6dFNg9Wivor^>3H5nuV6fd7YO+c>hQkFUK$Cy{cvt zy$#Xv=+Ea^(`t;?SjD0r9z(^Pc6I5nA;57Da*}8<*?(ILz^j)X$wXX=E&dKsB7~Y% zK#xN%?V18YH|dk|Jga9n$%QQ#M8f|zf0TZ^%UyFGh-RVh9@)8E0(ESnO~I4XYfOQ6JxUKKJ;Xgg<0~UsiYUC=Q|jLrBCwMDUmDf#saQKk$0-M6nc` zp)hC+=)nl%&GzmoDllg+s%|kXbd_=KE;(1P;|4dP;`(N^1uXwRzg)Du;GCss7(ECn z-~Ddyy1E+{ae{eUnf8_Uqu)Ju8*G1rC|IiW1^fJ1#ALsxMf)dI%zu8t?DwJur>}&o zK8J!zUw2hMLqdQzm+W3H<-;|XUFe>!8>Z?%dX;^p^AD2zf6Dm%$=jCFO$rB&5280^ z1?l##JO5a9{bu(GBTtyE%ydAWH#RQVQz%c>aBG6}gca09c2Oyh()J&;Uh+U6WJc-p zI$Ll#%#ht=Op_edGiTFj5xGh)+id0#!n?(JDb3-#SdE(Dxyw3OSlC%@t zAbu-pwnhb3ch)p%mi5GWsz%%ZVEpsv8}`5sjN)r!bT?IWjQ3TCW^CqG<_p>5jisr@ zF?>2t!R6h+w+wkZk4P_nNh>!18ISKLBU_kQ=U@gLM17+f zEi(hJga%iHUt%b;R59>#mMeE4uCr#Bi8vYn%qY@(31Q+=#n`<0%{k{Cm7 zI3pzmj%S2bp=ERgm3>%9xl9ANi#BF6I!Gbew|Vm?Dm;L5*9LvPy9z?0P(EXEx>urM z;Cgwl+YTe6Y(aNf0wZY5b6X@yFfihjQR2Vxj7x%?t1bB>K^9*{WE z-A($6^Xti|PyOF@;M9uA902c#M|D69`UeQz9sTe$dzh`=d-j)ypzJtNE z6S%&(Z9=HrZbMEHW{G;7((KonJr*yG5Kk~KB?XZ>40G$9L!f$Xa0VOCoJTNh0G0l} zI0gJGzBHs$XYNxyp_s!Vp^1&Zo#;X(#v+pg!8|n7IGly(C;95|BPAz|wOQ1X&!o)KgK$A7dFBAal?yfo;i`w&0p>swzw;5w;f?7WC1dp?}bnKzadK9PWB2J~C%eOR4 zHz9ddb{`T6q>0ET1x@~ymkUz#!R7`wQZL;uxk`|45J+c2`WLCaodcR>|Hs@8q`Las z&QC%L+w-!a0uL1Kv5(lmHX(&y`VoF9XK}WFEc(s<$4+UCQ(!$5E4}Yj%skn=S)}O! z%*z$YeXH4O&u_?SMEV|_2NvhboxMV+93S_Y4kJ_3IFY>brc9;m6?@m+=YYhN?+p1M zKq2%u(z2G6^d?BGQvn1nzz9oUT!Z&@w+v+Vj8%oylu);w7HHCy7uhl z=1G1;^1#=x&%V#7digr1fVTMqPYt~Z23sUHzTdmw4Q2B!dBXcb%$1^{u6bIedaSPj z+_!(I(W?yp!DgVZ&f#p0?4PvEN#m?{ux~CooAa_(AoIsURG$;YD&qnm*XTZ+;Qy+B z_JY>eVCHYa-0Uq@V$K<2DfwI$QxsN6ARh#W7QAWQvfgaE-_n`9B7ZYEjK=8RU|3GX z{wAyHGG-;De+^Fb_I#`9VGk(Sf-m+?kH!Ij`_Xv&Ii-poYZNkT4hEY1L2L6(B+`Ew zcJS$Iy52X@U-kIcDnooHOFKh`K#o_t$5u&4Atgb~sdR5eV? z(TfmsKaRWr-qX%8DkF4xH2rZo?YJT3KgP2=j>NXp(UqQYXK{W2W8 z%G}?Kp3pmJbXLhSD+-HjQH=FvKTGAjFF+p2-mw6~R`9eSqeue;QtehN zjD-}&q{9G0)i+|wrI5nke82Wpn(=a3`7y8A;$iEPki((vC{60QJsiKRSbAsi0IRX! zPPqi4?r%nW4dI*EvO4ggq4eO1-b^QiIuA2D>|zip8T&DF!1Be##U42?zDpgyS^~@! z#2dmS(XM|6(%Qt%US1@jKBiuN4I13Bus-VBk?hHWXE0Zeg;@q|s+iCXvFtbPJKq_?_`lPE><{%klNfY(N-_z# zS-tO~RLIkEJVD5MI1Mi+l4^^%Kpjsaan&yesnx+u;F3)+wL$p4fkv2KvGu-BDY@38{(5bSkr6M)Uz3}As57V zg^nM>5VKmoYUlg4X<0oW9<;7#Ni#zxW%LfKmboeE!-T>fGB79QAcUA$HyT2(K#>3V zD|U+nbcrHV1I&TE`Tgl`hzZzMYZyCy{*v_bH!f}Ko;jXh^%gU}Sd6Q9MqO|Tsc>4a zZk<>$0xyK-01(a|8^QN6t1i_K$i@AxW7 z_l77-5D2Fc9(0F)y>3k`IPOmhDyjvPZ3SIUbZ*QbU|Jm9lA~J zi`e;34_IEUJumc}53SoRn_0%jwTnq4ieRU0meALA=XSlm{<>@16Y4|n*=@=@9MTon z$9si?lZE~171j|O#L^w5j==QGbR*4J%IP9Ll)eO0lp z)Q%^{W_ z2v;~xn%%o@cf%h4xcCs->WNFfR`*+8n;rY=$ivtTUa*$~Ug58h@lL{;1i7o>Qi1OykJNrw*AM;tSDA zmoMovGl5poz5KUIdYWfEFG%-%jJ!E87GYCilQl3A0Szksn(SiDms1T!ADoq74)(Nv z$X~o+3=_EYAC8SRjE|lyjQ31$r-QqrseV@{tuHlKvqAotuYM|RnI0A%uhOq(Mhzaf zXg$uuJ-$8>OBBGW9*U6S@4SxQwCR4J$evqd_W`P?ss>leHP5T+O}9h3E%KKBw6D)D z|I;ZtW=FaO#tDXjv4qT@?Id42No>xg($_f5FxKG6j5Q8j0UG&xD{OK-#Ie>R+HS4z z0`)&U`+SI9txPJ`zuC-*do#rfXQvUB!-#tMru2@^lR1eO6-KE8c8!gFGXw=g?AvU0 z3lbw+ir#RCubRbP+9Inxf@XVfJDUvZ)!AQ+Z)uya`hvY0{Os8e|AQCuLoj{3Y9fI^ zNKex{Y1B>9w$M#`A=(4N6^na@O9M5k;s=dREsp!EH{P|Q`1 zP-JUOPtoj7Wuko!yzu3FauKRR7X^K3+lHn(H+mR(PXc=7LODv}Jxwl+i89f)gn%n2 zIi-Y|dC}wJoBV?|kCtqVI`4Xd?)uJ1b$+5~r5<_Js{gzb`v~|lcQo7ggw>MWsPh#s zI)1im*lW#)ZnD*{wNUc66G#!ym9-%8KJ&+Dtw~}hPA7Y&UV1IcKk11Hq@2uc=~PkH zvT)tjd-meduOF6oOr3%D;p9U3$kEE&yW@U6a~M(6d)jIX&x}Va`gYY83cs*p!_$`H znbas>j!->|$hf$)ga;TpT^F~40)gGTckdlI>FQ3majnNM)aHjL@?|S)6?hXb3rPzY zk=;)5n4VA^%W6@l9b3h3H+|Tro-D#R#$vA`RH9PNs?ULW8+yeea)B{9GRoK4`;*dp z5lOE$irok~&BfeYIxvtA%@!Q?EIc!}R_eYx{iM0A-c9d&TY9b{PpEC8>-N9*h)T$A zbNR~gYBE16`bwT*6_NI7C;iO5DUz!dzbemZ=IF_`b!0n>$Oz5G9K*tU^i}_P9}{^i zspCCm$cUO05>fLwas_)UKcFb|E{fw2yyF_G?;-@(sovqfN8ivoT`Fia6+u1c!8yA% zou@+4g$E-9L2;FS1KI-nj_4cpwUeSQS0|;omidg#<_$ToJ&&$29;6HCx0^K85auwo5`SYBm%1oO-3r{7MF6is0#Sc^8y6R} zu9b(7-MUJQhKo1}^jaBLZLd!BSCpidSsm)nEa~xft8M$-F5B1_TisHw^ob%P%ie>1 zfD0H`UYtHS$o4^9Ge?xJyd2NRV!bs*z*U5gzzLW(Ee(#j1f;p^uQ6xip*Jua>cjn)Vc zX<-?&70|J;pz9wn_{E}Jtj1z-hM~u$UeazU(nw zY-eun&%(VWeIA}~C!I4Q6ph8J23Whk5|kiHv9qUPjC(}MZh4n4E4}7M`v=N?3T^fk zpcns(E8-6GUtSSqFQibaYNn^OKRIR{xv*X~mFuyX>o04HUy4HZK*x{Fia($9V3aOD zeVB>eW!g4z+ymQMr2oVlc8-viE4yGLRJ<_M*%@Qpu>9TC`t~!sMhoX#9E;gutNt=Y zQNHu?ctLc-&0%N$*A=rZ3xhA(T?Ly{-(wD*B@i*_oB0d(j~;XeI3xds==sicEhSMm zFSGn$^z~0oVg^0-{1QX?#z}EU&;zsm*sw(p4Ni&SHs8`8t%A!F5e-xK&19>+-`fBCqQWQmx`*EO&%3jra9`)xHt(M+T>e%24Y-;LOED* z<=c7Qid@VSfWoJ`L>cOCCh;hd>rH&HYT!wqv8^H)>k5>+wmg<5k9qmxE+U)iVfZ28 zc|CJak$(C`I1$#CkB=h%R#e0|_NeEvJbg2ICZ!TtS$A>In;x)`-8LUW>k{bBQ6(?X zJw98?B0EAywDI3a|Ak$u_^L+K$cTj+7fJ3&2x+J(8`skDq^8i6lHY6{+18Q1oiPbk zEYHPg8+&{4duj~$rVNwNzH2d1;^Kw!a{Zx0@KaD3x}VU@mh~k=tYfb8kkz#yutINm#@;ieT%L&d0_K>;HS>5ExCla7ox6|p1ij|{9-vjQZtw8 zD`rxik9{{gG-#9m=#zQ=vvyJ)WuZmNK!IR9M^LPBuHud>!(h@J#eA9;OhO9h_>ajs zMJ%Q{@Lw)e~!$?kn=D zMj#zfUsvpHHFr6go%n#>0JxgGmSGE}GjJ0B{^tw~dBe$t#bU^vKQmEy&>PBd7<)^pY^+KjSJmz+vUq`QSa4loyQ|A4vKv~Bja2IPREv$Ywy-}6 z4yHY5itq-`o|v8Z&&sf-f2>6@voOXFvm8WP1wy9!TWGjcYVhct)63r@J=Ssd%ALL? zbsbHrnOsNB;A~b#`Lb#34sAAQD|IW&Y?gntMe4^#@oE(%CNhfxiV2zl&c+_ZyeHA@*?SbH_V`5n=s}sNKFY%V>sz`hLcc_W_20bJV%jY$ zXQ4a$i$R!k@#!BQ$xzAKsU7|*&leaCs>dU!1NS`zQExe&8^R7=XB-&pjk%Ajux3%~ z&04fC#(!PpBR&6N-n>H*Fu@A9L8C8?lPmBWt&1H4k@<%#)#$=Pz&>8udrt)lW&-+L93MHW4yE zx<&3J13o?RyoO+2I#O2E*0H{-dkT$Jbit9`@PFYMj}|;Fhv7f`nXDUS$n%!F1s9pN zN1(0`%QJbcB3V1ne6(2R*4g3dcG5)$G|8NErt@I@eO$C-xq9-*aJvKAzoSyGxcXvt zZe^`nb=ytXqfjmJ<@C@As}JV(M(2t?$aAL7$;djqO!Y81r7ckzB#T)WAcuSuS}}A( zFKUOq{@YVaYxK@-W|N$q_{9{%NKSXy4CH?MwGo>WH|$5I%<>vH^Cm2xFg%WI)g=tD zn`B&=@RGK_8HlH!3J~6Bs(F@GSTbNpY^&+1fok}_USKn4-EN~{LAU3x9I+hn+nnQ3p+z(AYeh8_mDk>GYYe9drCO4r637?1RPdOnv;0+}^+18sbKvnKo}= zMx7xBiR`;YcFTU|b-&B&jpp?md8t_&j+J%T>(l;X4pzZKk96}|E|u!{Dpv6*E1G%R z<+3C*qF(5K9y!=8tXTeXVc=EVoR3+Is$_<&Me8X-{LtkFm$s{S`bDQCKLur=1FZ zMAJgo*}HjkX4Ij*Jj#;3D^k=I=~{jn!$}?5dJ|iHDcyU!2(A72^WyfuxrX?A^v)-* z42bQIMb@MWl#gLj*zT9i>A+loB9-2uR09??{v0Yv=*# zQUs}?2%(1_AcVX-=-fNM@4YkPT65R?$E-0TaLzva?EQH@PuVVeT>5>#UA!nD&kI>^ zdCiSGZrMcL+f2@MWEYh>KJFsq$&?)c92#jLk7Z`L6k2L#;Wp~6ku01wlajRDODP;R z#j;V&lrCJk|F1h)2Y;jfu$*w=hNRuLBIBpnGN?@;P%SvqQ)Yet@)AYfZ!P)i@0&0B z&0{D#)>vUakTv(*&LB~qqfwY03JPx@2C75vW_p4RAzc?B%@&-Qeea8Kk=VE!cyIK( zw=**>Nei3Lr1UiIX8kp6;^f^uY$_MF1Qc$ETdGoLX7@Fz87Hes*e#7>k?eloqDO2C zxd#Svq}Y*Nvj&iFIa1lXK^8=~Rb@Kfxm&es+(J+&v3?cd|O?CEy?=i_S}A>Gc#xVN-l-ve{d%wVAGQQ7FZM~JWR89T#V|1_r46iVZn>7 zGB!EFdBqVo!Ow2Fbf2B;>Su~Z+~)jeeH0NJ1Q>(w5c zf!+=(7($4e<8jVO>FBMqEx_FLxc)GWt}XCe%y0D1m-rMo&8S-p65RDp%tlpgzwlr7 z7d65Wx8(MnWc_{+GEqNY_Kvb*^Kl<-)GTqfZ01290_!B;=K8oUI&$ya`bJw5rj#8c zD*h0q$}(=vOV?;4c%{9dL&U6Q!9n!uo|_z^J!!Gs<4w!RBT8v8>=j#2L6iQ*GbiK* zy_WWaJHFfp82@@>H2$59@u~Yg8LHJ4+6k0P2W9O>j#SP3Iqy9iiKuS@IxbhQ!qbG0 zSN;lMXTMUW3m^A4bCEAYHR!{-TcsCoMJ~kiTq`y~Lzy8wymovt*6S`eq*m`& z09ggpOy)O{4r*!x9<=}v6(@L6O<+f|RPL<6L3cmmOx=gQK7S49^L_)+KW3|pqWIC` zk*!}{4R~)r`((-xz-W4@kxB;Itbs#89MjWHLTBb@V;dSU0br%Acvy62V8xG(^8HA* zT8bB{CB$26;IkUsYOIHq2Fc8Zn)U;b7mhS~B8%-H;SiIVea?1iO82sal_ychg|8`b zpCNV4yL@y9Ca{j4SGAXqO*_t+rVuHJH>q+L_Xi1u;RcSgKFkC)ZuQ6gBn*lo!HiC@ z6@ez_%6U?yS)i3C27dqfD!BE-I3W+fWBh=daO9=v>t(mI%Z{mRIk{9Ey$^+wpvw7a z_W%mw1tsW$H0jgKMQ`c4B@Q|g!*N!e383LbZ!xOIrUQ=?qh;mQY`C=5k^{i3OCd1R zQ`Obi8^hs!NLA@0)s`Im{QS%QU+>BCc%L|eTxa1({h+2&b{iDmNOtgN(xvtIv{{kv z_g~PA$MU=rg7qQvnXOHE>A7>pl)23H=Zp^KLW3q(*C(x&DmUAp3#6MVzNPl9Yh@EJ zas`>Kj|FfxtzZY_Wf=wUpf`JgtV`J39@d(RBw+nX`I$sLz#fEPG5xHaUmV`IDk}|j z2YoGWC4emN2e?G$44bG+2!T5vvTuBjXu?5$UW%{tHf&{FGN+uJUi}Y;3 z*95O1D~+c8HYnZpItZ-P?O;<6{8^{&a*k$1N$(zC77Fn*aI1`LOq%;D`kEjzUlGi3 zS=mhDS&Iw&XYP}5)oltN#Cb3^6!B+~L{Mp`M^@I79{N|-P76}IIc3T{;9aB8)SDf& zyF;`bjrQ3mbb8GJvOemfE}k4GIcz|;UY|2NJ8MlUh>mmk`1pjkuXIC5m#+>z79Mv3 zbfVTzB^i-^;Fp<}kT_D$YtOs5p^z(6U`~=cU5;z|_F{|@J|5r=t0iV@36PkcA4DVL zRiwzne|?7bJwMM#P-wqnE(`xjL^72sbg-5h6oZxnce{_ESdcOe4QKtzk`(EEeuO0T zj6v}O6Sj_d7VX+7CHd4>P zn4PZ%eq;?`GRlsO-Fqpm{r2r2 zJx`O+`X5jDUr)5a8FZZQHr zWEB|v5n6c%PX?;fzXT&eKiWiP8}v2Yf6qife?!4wIZ>I(XRR|>=N`=PY@chC_fz*0 zd`fO=;Z|-!{=2$!XVZiadHo7h{BK?XT0=;T@Iq|~-G)c4m{WqRmrO4vh$&3wT2iWj zTO|+-{2J~2k1ouI!Zd6vM~cSm)_`U<%cUdxD6UNeF*N$y0#tc&SIca@25ikfbg(=U zVm36oq*Et-JLH?R)XNW(fNG-6{Cl#k;?eGVDkMI14f3YnHs+HgpUUIomDrF=I{Z`< zyIa=QRAvSxLi|{Hi(g%B74htAyXxZsD{}RJ(pDds%xIH6yuizN1o;o|7bg5bgTK-ER_?j)!ms+dSbi!7+_6*^fvlSn&# zAH03-6}XPQGcD5pPiJ?v&XIDF1Jsr}i#YP_2Ykpf5?Pa&%p?xkN>xEtGLb%|6>>4M zG&u-lk+$!34IUM?1!>oejPhr$$F%S7uRr94_yz=ksIfeU zT<_DbMy?qc7)-FIeh5>czi}GA$PX?tKg%vaq07fX^hYHODyitPpLe{|VpdZbR@mI) zkU`>et~Wojrpb@ChU7;+qt55men9BayzSu98*UBt(7a%}$ot_4l7q7*)qORZL^kCs zEQyQyb6NskZ%av>d*&1cGnJ1apst#Tl9FU@^Yp{$i!BK+m1+_h|1|C!0z7w)cW{v6ZI zh*4Z?hE}k!$DZqkw$5vIQS6a~yp&?My87i-vD4lSK<=UI{!uAzdJo%$^CZaNE-l^a z{7(Gm-OD127H9n2wH|fruaejVq?Tj+@gH9UweX(!6rl-L+9R{=Usy>O3J+)yn({KD zhZm(ZzvmwH_Fj+gYFaFM@@@$i$1}JiYtI{=cG*#{wkEy9>Xbkv*pZs&ieWRxX+6)w@2&qv% zXg5bgM&?3x_vZCS?(SN!I`Bn6poP${)}`Hrf(zg_|j~3Ll-)?;+@opj&!V7n_*cO@&6ra2<=Uo0V5PIZEKrz^%-?;T+YbNtpEoJSj2x6H26-HOta27|@VS;xZO@>b@^mjcD@x(2@Lu z)fX*T;pN#>D&F|JZJ>K3?u#W5_Gzq5NIX0=$;sB@A5c{7Li9TG+8?#c{yM3w*prP+ za4#UPpUYeIhjmOEO32i368HKIIP#klTWyWtgYc`uA}rM!mUc`RAjcsFgzdFxLc}dt zvAah`Mbs_gxVBM$VTEjIw7rLa7jv?e9TUwC5B-mB7Z)ID>fo+f*^Zrg0weOR9`yfG zIn1?s(6{JjyN;1jGs8Z(#)!_hmXk)N*n-hrwC0Xz(ed0TW~;*z)_~l$``v@Mprdln zC3Htmfml%SP&jX?Z( z^VEIsF6y*yRtLV$Z$LDdK}I%K4rHjBC&-8}k&#ye$@ODUXOa92mFwxf*iN~$R5%?3 z_Si~i{N6NzFta1JONb*I@i`<+b$T1UTu|8Qnw`BcPMQ<{{KMw9OO03fqhtMPpdSl9a4+wv0)kSkI{F?}QetCf)kr!IM3|TUfKr-egcIjFnRzk6 zrVn1v-bIYU1+`JM-Eh^J)aQ&pMH3RmHiVMeX$}69wXeGm1?yDNvlB6?nF9Jcp9!4% zDClW6@5vlcwTijAn}WRiXsPq__kC^R;c7wS=x_BxoAu7?HwqtGKAkl-jnC*Qt7|!C zx$otyeJNtOf5{4hEgL1HCNqqC9A8s#cp= za8;?wP9IUv?iU@ogxz=KM4VM)&#Dz}-@OWHI`HE8TFLC}bkk)#lBNPz@{*i-pWT2& zQhdB;Sa`p&qa%=Bz1huNKU!Ltkl_U(K|n&tmwRy>xuJORdi#=8VJq=Opocai1{%lW7iqtKjLOVQ-2A zRSHc_6(ys}IWd>>N`RshfwHX7( zqF#z`@xy+>?XhMN@+|+8xoxQ$`^@UN5Mf!BqMR#`iDpTaLgm5!3c$oY=^f~}K6X^l z`Z(jS-)$fP@TO2l5QNPM^R~vbLFxnL6i&+JZgBLb;54F!HD&ojW^*vb1qLcXG~AS> zX(YWb&<@qmg=@9#cr%Mc1sa{0t%?*)nHlwI3O`*KZGV=XnLQm2A=Mum+W%~KB3I*w zsxIXK(E7-ASRu~GmfZ;iT$es#LJ~+L=2VoDQ9%rEe<>mZ^@eNYP?qavW^p&mBHy-p z(8YKXQQ@@TF-Y(l)&J!rDwIF#$DT&iSDPE%tzV__uX>fGF9 zG6LfEzqrd!!V6z&y1Md$1kLQc{cFzF4i0W4)(%?S7_HjEDd@()bWS@s#^@QxYJnXq z?tr=y*RfweXRwB!w`>`OK03EQ!<_HETAtt zXkT`B>npM?!03682sxedB!5ckBkNi5C&n=em6VM|n%Q zv7l-0K?B0_GI6!3%tihJ#CH&$>Ocp9MinOInp&vF&c4`0;}BQh6RI4!L^<@VoLlr% zV}ZCMI$K^%$q4;L{woq=hntY@3d~h1|CR|0(SqLh1~_3a2~2>l_K@Q}Ss?W}2`WRA z8R`C`q)SW_VmbrY2iN>lcGbhW%u?$>-<0Z#Vy1IG7ow&0LlZ^ANwxhrO>5YP)Wz;r zr}yz47du8WqyS_wvBs9n1re@6&xr&=FA5Y=U59D$O|tVquY3<;eAYzGP7wPiSO@4t z8@Al+i_lsNOaatI_PRPK>gn>e!94Cx-{KQ^KBI>180k@Bcm;u7nclJuB}A0KiS#)O z6Fm|!DAV~S4r_Zp;;mO>jasIkirxF#M9x9M%Cs@9+(}b&Di1iw?J>R>tmB%hi8G43 z5$JQY;OFOt%Ectk5zB5+8J~5q_*{P%)W3GE_%eAD9Rh}F9SkndGi~=25=5_v2C8S# zHGhDzO=bW#{kYf1M)eaYBH!JnU|kk>KwcUEtcKYq_!*ovEeYK9@>6nyM*-BNn&?L> z)rFTyvc8vc6f>)JI%mp`@bHl!y4^)>HkEOq({)i4<;Q`(KS-InGu?`bR)! z1@{eNcsZFRrNI601v%uydvHZv)o~{=6?b=LAmCgQf6mhjGk?s}@`s0ha63TJ<=WoG zx=crTV9jXKZzP>{?epPdo3-Z}bIBLz2ydvA4>R_rz_r$#9epY=-rOm4GFv=g6?cfX z+1{=&Zi=++=q|00g7^t8l!F2Mqay~+5Nr#fpFDR(DLcbKyMW|mOX1D*Y=%+x17l5{ZxA}WmW@B? z9OJ*-X3I}IU=0uoFfF9pQMR|<=1eG1T(-7y#6;YHZdv$eD&5I|isPk+FpUc;TRg{r zC+Y~X9=>x)J31>hmC2QfoB#g2Bj~D;K9zrE>gU(BXYbvG&4!JW__e>$tPRK<6fX)x zlR(yaqR_|OuH+?g#Pmd_=@-Ry?mFN|iu-f*UDwbtJm>(I3XjvG!S zo==j;Z(ustIJaM~ z6MIoLDv8DqNeI!9hl*v64J;ek;B9ab?%os@xw@87&lT42=lz>n&U6A zhtiCAQ_w6%1~2*rD2x592&~YU#=yVl*gSo9Z={O@2u{w`F~HSz>8;cUlxt)Cgg1qz z65F9&)H>?0*_D#jE^zi>$ts}<<)U!CQmjDl44sB8yR5{;w@L(xsc5b$rhNhCFyjdR!DC&9PPJUWgIfI93e*KtngoI{AmXNQ*QA|sIzOUpo`F5H%(nE%vzaY&l+wbg_G}ADekTh03F?&9ciSm;- z#RrE&?*+NmnrM2XC@$}!Eq^78ud8qXA-akfzB-LqR!_#r!Vh_Vuy%$9MoUQ&32)>OZ%cTKYg;5IOTOn@wC$-i>n_x1 ziJ!AY&n=V^*KZf@{Zi|8P=V+vep3wQAo_wh#!52RwJ*pDwfk#ty@WjGIYVFf=0-0D zYbX(4B{y&h#~MG=9f+k&lslVRby3{mUS~kPMku z+;vU^1|8K{1*@3SbI?P11-9x|yTV0`j5p#iK!Bj#eUP(Ni(((Sh44^Xq;*Yr&Fy4j znCYMvCE*)|i>}gWgkf&g0qR2oVib-sTtkI^>kM~79K0Fg z<1bVSoJuAW)5f-=Tn>puu1pPs|BQ~_pQT#LWy*NrgIm4@fCl@cI@y?nl# z89hjUu(Nr{sq^Wz+4l=!KTaIc#w7$BIGT?r2GM$H!NeKF4F5rE8^!=KFay*Lb0U0& zSjqA<`SNi2Y(Z*MQ0_qjDI z0^1%9WPpGR=D>d9O`yEsvv2&2=a$x9ryB`QRQ|G7ItB)HbhJKaYh$aZ0bZf(KFIh} zUq%A3;;juTfQEFm^Lu-U4t?piuLJ)|bp>fO!4KsA zN)yfJ(WAe^SXSHaFqR)HZh=vV=o7ip2ErUZjaE*3k4lcux-_a%j5l-OWT;2%BL|(j z{Kcrw`de64wy{+{_d4lyfx0&K?GXUl)KnfNTe`}^=17Ec{_0B!()a<&m4rk|f8~0e zDh%iseSm;ZsJ!}zO%2#ub~*rnzY}`))4C=r3mb2C{rOGY6{;LR0O5`+i-fbF?f_?v z3pM@x=Ra*ht}?RF?d^2i(pcbzMu{B;q+|M)f&HJ=fj^{dm_R7^cN`nnMegsi#HG4g z#NF6NAc5_e2)Dm41amqBdM;YPy)-}x!CFfP$zE@tM~xJ9o6+>o2QlI((K4nhHF zp*=-m_G_wrtEK36l7t)LYi<)@l})qnuk$#5N2;g7w*EEj_N3Q2!44}izHMNe=Gx!P z4FR!u{wJ@ShX1BYsp(RN4PhSFWit`lwYC(j*l(QFPE$dI;e@G5Rbu`T{T{Chn@Zt{ zXpt|S!EGFsa=}P9i@PVb=7Ww-H{m!IdWS5UsPFz#4*w_3S7DIV3ocfwRZYY`k|N^b zxyYM0IJft+pI@cO&yxAaMp>mZFQ_{m9Rj;EYe@S&cmGo8UM}kAxFEqZybN@XZz|W= z0(EyIT>nTX&41O`Pu6_=J>yyIs7t?fOrfo?w$x`VNWig;xfUKH1ZDiL zs;2aLjqT7cZUr7b{-VmDt$&+1AKTvM=y6K|uX+p|8fAt)fcJ zl0n6qHD`~fYA3vzec_qY!-nq&9?%!}e-hm?*LyrE4dx2+N$?UIcaQN#sy{X;O1B-9 z_QbUe&VWO9tl3#wk@ItfomFO%C@)~D7qFR0hlnmgqhqs0fsu(JbB@A+=DC*LiTo%a zqltQcgwA>N=)4o|#3kgH{~Bo_e&1XAcPwRqzY1bdE3`Pp-qRBe<$TYycPW${*i)Ug z1h|0P4^OA#aa~6JoL_*t)vp+xaxNbVRp0FNg>f1tA|rb}$!*p>SS7=pSrOzzgKgJtq@RnvfAL&Y$nukKDKG4;bf&$|C6fY& z>IY0Uot+qLQiMY^gIkwd<0ocU)#R?Z_GvFt14)CbIO4Qu05BDOoVXu6rg?mE&XIWm zh}%sOy^CE=Q!`Uv=0lfE9}qTsHfA0h0eFocACo~v1u2<`jgJ?1&t56X#cd8ZZ&g>X zBXI_qPH)4nxa_F{Nj;C*gG03byKjv1EGq7Id}BbQ|CkFR&^{&y$cHFL4-iZA4JIA| zyAwgE0KT#C!?rJ06=hO?xd7r&YHT6!*-Ivxh#dYn!Vy7r;tEDOxHlBBbk{_)_%ix5 zQz&7cc4bNv__xj?R!$kdF2zJYqkf^aWpY(`!*LtVD)>D!*h=4=@Fv{iQ#CIGRjy4U zAkQLQ{d?w$7NnH<7FPnCNj5ovh@;)YNhVj~Lp2gg0D|-H*$UB2DJAI%hfDe|i zx#3bjCXGc{8zmMeY(=2-ZU zc6wA6+jV5 zJvlksVhF+?>mi~y)pB;?gVLL4;zJ<2Ptp>Tq`WYoQmr&K|>NtyX>+0x}9Xt9C zgt^rIy+sS!H!8_^RARkqAV-2*Nxr9l=mAwuxv($c)Tu7}?R~AUZQCxgeB)d76yJOZ z^3D0?TKbCb4TV-*lQB<`>T)SyLCszMa*hPq%Df!OkEeHi5A^_hsT0LqY zK(fKm@ceMqxW)hBs_`@Xi4Ibx_T5s14q-`{Lnpvvh)!#@XzlP20OeREFFQIjxRBT?!bH)qLwQQ?!EgOU^g18+f4wpIP z^o6S`CNzs-ioo;hLlKhC=Qt)iA2AVW7}9GEx&J@`gJQy+kx|9cB5V!DDsNaM^`ivA}#X+Q&H;fZQB*4`CrY$G*sDy z7pmvC9COF`Kh)>q^cM6vtx-M;*A}*OGGT#35yO*oBook2oP^xiJNOe01F&(=E`XAe zUK>u&5{-n9`e9d=d4{&CO*1`yKVs zdwmm%Ac>Y48L!b7+5QCifU{@7XLC86Zr(7b%BhESXwraA_?;-e zcy7eg7#&;2Jad`V#n*8|(B$Gp`%bHNX#se@@`Uda&$(!Lm;r<>WUNKYVR&;UwfhTa z10NoOapNo7UXKrW%s@pcv2CTSLuNBntYokj!6XPvY*j{@WC&YUxvx}zGw5?TUXN`U za*MJpPmL3{ygIkFtZk%ieB6WQnbY8gcuv61eDUE5FIG3eoJWfUhW*Ue_}cALaE{c|_|{c^ z7xo_>NMBQhO@rd8NMc07Ws)5Y5WdG2!^baud%wzvI;n3TKuL-$BsuADYzq?-g2#EW zB7uaPaXK!c`)Dq53s}*5Qy4w>_NXW-dgJ54$jHPb6hD>DPGUm~v;+jDZ-79)OZ$0$ z1=BHKZ58VY?dIYz+vw{VFhGjI z&Zobra1^1_z{$<`Z}N2==681T?`sq07b;cG(6FQTCz9J>MXz~(sFE{qQ!5xMCQ z)qgXRNwXGhJ-pI67)6fv^k~Y=J=d8}D8?As+RClY9Hi}VeRCLh?8C!ij7#{GWv6Uw zC3+r+THph?)o)V8@Fni1)8Bhcx-O8CE z-}9s!`{DSap@|%d;QH5RCa0ty^;W@IHmbj`+x(Xicuv_&RKSoT70DFj zyQV1jq6uAj8kcR|atzmkFf_~5xZ63?Q(E7|54kt7l@WWQ5FxHd%FYQoDwBJdk9)X| z)#}-J&&@}SR0ErYr056in24H2kZjsok*%$Ub8Z-wGn*vs*t~PANt>;F0k+Q+J7hN zVuPQGBZUj-??F?>n`|8Y@HiI(l}2`qD3tlR&FVvIYbw70j47qZO^~ejBfoSf(Cj}V zG;t^`w$G9R>s1F^L;JavI$9HNH+t5KJDX~;xg2ob-Vi8#n(E+asHoWc<(97Q=wf}O zsy}o2h5-Nv3ii1}4PR56GBNtVQukyfH+N6XdC2-12NMIE2XkQP@FgV|T5U!~T{v&e zBPK!}^$mw*t|KSpDaaz_CaKi_O{gY!gRh? z0BL=#hShLdt`V_P62;x-Ub`aoUwxUI4}jD5Hz;Nvkid!;Pe*)aqKf)B_H0Zdntd3@ zTKP;0VSj?H{;iY}TQcMq?o3$_l#*+#XdggUh^;Igau;%0v#}|L*w5P`)2R@Df7aMIc8wpSl?qtY$%Q>w-LFv;y{0Rg8;~$Hd@{a{(4{Z)#Ky5+ z&iPg(CR#2%0X78%%0%l2qJ9O=c+tn1Nc}mrWB4gK-&xhz32wrAXPe zwDz~5vkm;hpJqR@(&;ap=dB2^L)(ZEo}*G*|FOxX@m%#p#YR@Yp-%RwIY3;X^*-HDEQXd_Yt&Uk^opk(~I;qnwp>WAk)7_tBnUMK(!aXCi(> zi#7q5J(HiAz%Cn5L^#IC4Y@zyECJ$Hq*!vtDiErR-qwGK4H4J9rGEz-VqkX$-h=T$ED}C?z(lP02?DD9;8gS`{c8F6MGLo~pjjemn`b{j z`2g>EJ7S9N-H<-~9`h623~z#)qT*v_PG~onR%uAiviTCngRak9hhJ>?zU)Bk1wpJ! z`43}ym+~_omyK%tJ<3)4O8ZecvzW205lgfS$RQK>h2x|{w?fKiHk#jwH;jlz3o8bc^i2%tz|CNrVKw-4w@jocY|jS zJ?&D0d!HygIUQMV@JkC#q5@lGpwahIbV7GWImLKwj&P>K;Aj(txnqvmQt+h^Y0EW{ zJZB>=N4N-RY<(ltOLWAV`Hn1CwnhrPi9`=IG<>S(&Ry!qOZ!mVhBSA4xh*QF(BC_KMz58_ngguu84&~b!`>XM5B8{ zuMq1JeFY@p7lF{$@x%$iU$**S_fW3p6-2T8NPB}1?FX$L*2g&OeZUjXRWDS)NHdM! zazdrKy5h=${hN7*5MR@U<*z1z#Ki=E8s3nm<+h}?puu_w zPenC&t95+bJ%|g^3<8e2Z2FAHar!Hr(HU3$1OKXdj6VN+&0`Q?1@d_WPuJ0sKOr7B zIOJO-RXNb?TGbInK>;F}=5qG&1O6D`O(0#DfAg<&8+VlZj=VML6_d(;h}V06vcZa- zG`@*iW#}CPGY1_hBK2D@Eq}2+{|j(9*oRQRme=*p3pWa1NWQ-Q(t6k_;fz%oIillk z-grhSBWidt<;6@Biu{`MdR_RWrJy8rv?w$e!xj?pvDF9Kin|R8U&s@EssM@inx*Bb znHd)#MK5npZH#M7W-I7XqSnk}URg`eJ8pS_1aUv1j;doAnt|ntb<_Z@hxcfuE0c}# zl$d}+;3nZ#9gDMJqA_|hnOkxlGh9-qr44&998mJ}Hhy}KVdB?q|HMxZ#k)#JGlR~D z7Oa{1E?B)$MU5*F>XE7@Eg zcUDFX!F8GFE^;I!GvRE0UZWONy#CLfBa%*HWn(Z>6Wx$<{@D5~CV2x!3<7Z4RZVN{ zvf(T2R%f)aw(+5(6Xj-nS8PB?Ix|ne@)j0>@po^t4KX_|u>D!h1TiHuxExNL#~KZT z7-l3M*EuvB;J>i(I8+Sd-V#12gje^M7<$?tYS>N#GMsUe{^)l|szIO^yh5yz_>RfD zQ(%B$5ueE2z!IbC=C>hpO_aLxjy(e7naWqu+W`oHF;RKEBW^yHBp_^o+TYzS={1cZ z%f)Z77i$rto?JU>+SAH#JP4X}5jP-%_y3-I-4Q%5;>Nxm-!$$6NxWT-1onj4Z=wL$ zr>2v1^FZIMnLni?b{aHzk_y!{ z;&f>}tZp9`?qyZJ0(mQ=`JgB-$0`FQMYGGm7Osh!t_2uW(6%~R0@gA07cV|fGl1xL zORJnwz3^`deeEW!BPoW7LFD3p@pD(M@RIUSL7GvBclll)Yd^x-3~(JZNYNbfj*M=l zFo4gDmRzZfmbURz8=f3-ZoQ_wS7>x#+72Qd)BN zjNb+xv1=3phr?FohI2AO&@dxCK-pw1Q8O(%GL?z$>>S<-x?2VJdGN zRO~!uYJ9_9^@Q1-Yc8P_8xytm*LCI|Nl0oUpl=TV>*}lw}sQ}JraD=K}U}m@qgPW5gE% zQq`!C1fZkl{q@#mf+Fu!7bT^#sCO1M3ivtAGXnPXriqv_%ZrNb)$x`fQ@!B73F-We zuokfI0+;ema=vW91V2^Q`$GmaI{c%qv6qy&EW-~OdezIHUI1ILYHT-8c=n0K^>%Hg zJ5Be~g?6QX14&aPL*6srRFDlXPt5O8XbVT*2aF=coJMK4SZft8<9}ycNrxN!P8`no z&ap2kc^I-FS}CiTOek^6hXN!aP?E2)es$Z(9ToWU-C`o>Zwje-Dd5MDw3iO8;Oo73rLjsfT^? z#V0Naa^89qw$X871={xdbAXZ@TJ`TRCfJ)|Jd`5jBCr`#dfw8E z;~UP&OFQI0LImwBUQMe?1ISJN-6*+!>ic#^@Sp*v4Ww8!r7OY5fuNt6@7 zIVDpq^Px^PH3A<7Z*LL&+&EHe0wpq5+{U{-z;_12Q^lK7c#C9UR0F5DffLGtffV-$;m{vxpF3wC(D+mw zRp?U3+T5TC57QbZ0S*+N0i*(b?eN*wqTp`l9{HfNDDDYrSSjaKk6KV0@LZB1uY?7bt2I&GHCJSV^djA$B!tq1gAy zGH;+3_N6{{HX!j0)Hzg5?y8rXa>mCDA*7cUGiyA6C8c9ewTJ`IeQkqf#an+KNHM`3 zIMDa>ui?PAMySKK^ICbWoPV4}G;z#!lKXTZ#VgATi+kydA4$rOFdQZ)CwH~vI(gyq zht1?8q z#B?-wB}+;gMSlO9uau;zg8)&|TE_IDRSbE}fpKu|9K_O!jEX9*9aWw7wmAr7m0}bU zCTimp#(lINeJ@&x8&L+6eeJ$23K+JuE? zx~eOUHUha&IQ3oK_6&t5#FWJUa{uX z$z^xw>k^cY^qj7zS1Whs5&m`Fpc>`_;z?sO-hQjY4Ho&)hCET9F0HwXm*=6BA^k#-G3$oiD$ALIySVpUFJ#Fnk*s0j+g4B4d)VR0ATEEfVeR|! z*%<^6Y_QaNCQQ{L-2Cm!NLg6I#|0CfRx#3;S4~Gz&?9-vG`_|3h@U47OV7CIYp3sx zO|B>`#h~KJ$@B=)XmPHNZhu~Fc($-7Iw+WCCU+=LKGF<|Ij7av0Jhvr=ebK%*Pv~SH90dyX%&coApSWhFXox-h#D$A=)`z%ow z#IKp}r@XW%_@3j;hRiZ9n-(pd6RV13J?qX%*x&%VR9F^>1u3Cy4B z6RibDDP6vqn!wJdc)cEwA~sZaKrCT&E1>? zl@+cnS-qKq&dEca+1dy+9)Wk6RO$~ygqJE0a1{_{F?zS=&(XHMT=v{-#yh8q^Q#%U zf7_S{Kaj+dICW*c_UOH&>LI)MZ-h2m+E-hLdphH3HAAA9uO_I^XXfcHC3@w3BP@kc z#WTXQoclA8O0;((b5YwV#>Ft_L_QPk0ZTXL>MiP}@*Hp^AY4b@tawiFMVjl>TfEiE zSLLrc*|;IansFCS^XCf<=jfhqgdF2w)GQo2W=_-B&Ti}NR3}#X%_01;1DDCEXHMZZ z`)22zxA-@%&E}fp2G6Nw7T6amgAG2<%qh@r9;X68{a%_-P+xZ~ zYI=rAHhSx$3BIJ>_p}eSFeUa8dae3J=4OFfkMFa7v!nlazO3?@uN!bsA=gNA$Yaz6 zJk;VWdgP-U?sKwdx485Y%#M4vdo?b9CR65TX zF0nxVRPfVc`8fCXgGf)dlQ!216r3hLH$i>E+zvA4(=d6raBjs+mP{OTyTX(>H04U( zZdZLE&ZcV52fupubBW{6*zx0=z1FQ>;%MD)S5uKyYdv_+yoQxz6gt;1I@0lMUS0(J zQ%K)X@WO3ziBC_b2qP2Sac6YV=@^{YKTvF+_SDA!1Er0mK@<>%VPfsNo~ zKK?v-elp>UXV;=Mt9v_)^&Ju!H!>M7tvTQy_TXA}%;#6k@NN5trzFs3r|y_}ZbXG% zp=#16bagghV%Gyj2m)Ub^xJ`M(i6V?G<{gJcKg+@acdIWr}~&^7`@;4g*QL09h$dD zkPgN8Kzz#8@o^{oEgcs-4NUMh?Rk#H$I7Ya==#INFavR;ul=8y$1i_MeGgfsuNVk+ zn4YE%I%U?PPw$e&{wc<)>!F^Utn9<<@!w0Dg1p4?^Y=9!9xv!U%cY`@On3=ajPVYi znLP|X)+&7qE!QAFRuMWBIi9p&o`rHOz*&XO`|bxjsN zw93ZC1^N64kL_yryH+~SYdrST=pT`5KwG+1h0!QN zeY+Cn9Hm&^eohQWKXF4Y6^mj3jpD9Rrq$jHWKoprQ{AF_-%7i#ufS*ve ze0jI%MM$D@n{5SaX!2qKtr*U+YO}MZ=F_*B0>x(n(e^RPatEbMak^`(!2(;|lsa(8tNe4^f~ z+e&_n(Jv4j5h^G+nSYQvv#w;|{lhG^Oei=~cGD;bpIE47Pz>QU%U^}0!8JnX%$YP# z=MXod_Cv zXZk7-RwIHRWQqyQ{zkWkUbQH($%h5=GSrxMpB=b*zcW?AN-}gJyTQN5zZ83TDw7LU zW?a3mv=FH&z~=1uoF{8;>BYJ`Q}frim0!fX+B0#nW)l5Fo2el~+M|i;7Bcl`&^$b3 z1J4z6iavp|UE;yDhXv!AAJ%!_-|Y>uDPO#`WS`(ov02KWgK+XMx(`kyntf+pFuu|m z-*)@Ncy2U9XS`_q)6Mn93PX9{tK;t{Rbo7=Uha$2G&$ch6R*(^PJkk}EOZ)AZQu5< z=sAi+>N&y$4%=6iyi>t(@0)qB%CI(izOY5`dR5=_MFx5;UY=kr4W?ujjf0&YunDW3 z1)A543-XN$?B_D=GFNVjWG#QaW`o*UgcI~+IR~%20A~QxQ*qQ}NtJ-iLdgLKvYo)x z$F!fZcU^QnR~$k@iV_Ph(NpbL5s-SYT-5jD-99$+Oz~C~D3Za6i8Jx4^Wj4#q2pJJ zvVhQUaZT4B8yC`p#3Q8lFW`b7Lh0U|#{^-YCPP zu?=$}=le2p&P$v^7galevN~kMu94VzjzR1qEKKVIhz)}gbuZti?w%UVyL*35&iUx4 zs62m~W5zWD2H}+m@md)&%#{-P~kAI-j-OZ?1SzpavY=lLM9|1B!;ynS@RV#(Pw-pvU!;|-t`w?vYBotjFL^< zk#y)mr~ZG$eRWur+uApZfHcxd8k96hNlGaKg0uodN{2KIB`QdWph!zgNh>wL5W)}w z0s?}h4xJ-0bbM>Tz4v*~>)zY_o%3DaUwBE(%=4^gt^5Af&F!_@C{bH|up!a|9otT~ z-fod^5#gnx;O1_tvWU}Tzyo7*2HjC=6Ud%3^WFkAP8o5LuUH*Rm*HJvbkz&fMMZf(T&ksk=xC6li~4 ziuDV$yWKbWvi{-mibRx$W_d+kUa{!?&v#5M?6~kkFE%vS^n-lh{(iQ0dvHfC>(Z-d zt(f#wE`K=96QIzcLqEti(EiFv@yctmb)TI}B^hw|BA@s@ImY3$BlTB(P-muvhZV>D z_hZk6Dp~8-=#~1SAHGmajj$B3LEbgQ>M0uJEzmX8)SAj)%UjD8q7g3} zhp6%RvgN(BVYH)_N`1NRPLC6=n=ZgNL!G{4DKE{K8@`e=-))p1*uD*#j)xDY1lnQ6 z22dx%R8uEO6}sB^mZN$VR-7hk4C)ykE(P9xvZ?xyx@&_}bn8Rl$q5zmbse}8hTT>y z3tcr4%8$H^E8j?9LVJFlR^5f936A?6Vx}qFA;xU=H&4i$#3_|Q*lQY!4r(eqqDNFF zrg;$h9ByH5PK8=0?YE+2bWzVaYUPQf4&;@%OhG2T?j`|(3AFC z-HA+^*x07C@s@}feMhP!@&Tv0d+8HHwusN-sFx_|ix%!fUHZlj@9Y;3c876xGgcl) z1h;YPclP(~o#M;yue#2_at_FL-?#4fxUROD7WLUFj$@O`t37E6e6kV7qtT*^2kc)C zUDli0ZO8`>*F_IlpwW{pc8C+}->=biuMyYhGdVikj7e;viP|EO++QBGd=rFgW59@}Y>@ikHz&a#^#1(;lF2-d zsAi>Uq^e*h#YlaY{b(z5j-UGd3E|272_y)`hU%qt zyVRczQ*52MxSHJ*6^;SIy)lZ}vuIIM+& z+I~)>Cz$`!yDt|oH>3V*uNvFL_eQJHje2ZTy)i5ufB>ft$8`CyCT!^-1GG83zF!g= z>w4uEMBCvF^(p78_#$kfcwJ$wjg2$P$U3scd~zzbv%e{3*g^T}!gSOva=6DR!&%he zlk1Eu?qG`bc^QZ6E%#!lrcEQyRUGaN;N*2IfRIlPrtRR_DnA8>@wS0!HQ&2_MO7*} zp1Ac(k*>eG`^B|b#0n!J9uwK z4_hRr8pArAe?M7bKmGE_LI`Gc0Fg#u5^BVx+iY$ zl-j5HA^HN?vcQ~pm#4JD1{bdu?YKM8(rky83~!>6o(A0xEeQtKZl6^0HIZgnfdJlT zICIdX)T;tfES1q0nQaua&l~7yaOxlVQb^lJxZ$RJ4DU7KVOKQl;;xw7z@BEPTwud# z=fCYRUD_LsPa+7LSal33@!!|)WAb(VguBD!Q;a1j$;S-PkChu?mzn7~-05&0rz2(T z#)g};{QY;3^_z7?V=XI5ku7XXUEn+Q_-w(FX!M)W*$byP6lSz_sfaW)&A`)t*}VzQ zzb>Wdc#>gyWz@Y(@^*FDaNF)}`azD0qLqtGszV$bCL3UWq*sQ)`iPIR7S|)i?RYs< zt-ibT=7^8WTZcyemN&k+86(2Or*PWu#kiQj){%E*5y+~S!ajl#k03{7yPQ)!sMQVh zLLqO?e+Wn_nl9lys>*n&YUK$0raHaK zcF92-kZcOLE@Z8T{G``3UGj1Y2wh0ji~srra%teIASQ6~r+rvbtPv0E&`|%W z7K(yEST@VWodYy)NnY-q#ps2nZFPyrwCnky*kI=hGJ@V&v`4Y;EF$f~pDJ&kg(f;3 zuwMpYlB}!(XN6`?Zkc>sU_12K`$lRbeubJJBo3+OzahQ_E4b)b%Mvu{s{=z~5$Q@K zr5IsZiJ`Sh&>O=F<8q`S%S;FAlJO}Tm4D43Bbv9L}<#Qu?^`+VQJcPWr zcgV!uIIHW`2M6vBRu{vN4|eu!3!g9L7(TVsM_BnjqU|ydlM-*U(@~+5V~Ixu1Wi1P zvd_^h&&-FeN{VGEQ-=kBUcdf=1t-Z<5fL_*tEmMI=3S&~TYyMR=9G2l3IGRn&0EM7 zMt`3|h7S{C8)Zcyxdc%>n`2&`q)O+#+Hp}I!Ca`dmgPt|V?L{W%{RJ;j!5_PD5x8M7Q&J~Ws?-IwStJ=lYRNLAh9*>at zVvBkc(te)ar(Q}@T77XX)qypo)G^~!|XNSyajr@?cD!dZXQVM%*pjZMvt*Fevy zl_B)DNKa4hQ{(-Y(i;tZ<@Rl>4cZZ5LygGnhN+E3=mIyo7P>0FJlDOKtCkBne^o0Y zbg)M8nn~D*n#Cjyp7T;GQZ&!ZaPS$3AbinPVSQcTcKsJ1A;(G41yh(GQks74xjymD z75VVv>Xd0s=Ka|uuXv(N8xfE*Qy;*jb2{Y-U1KS}lW6_)uCNjUDQ{hC#DVU7KRBq@BarAi zHT51BKKCgafUg;20RblhMPk3a=H#WJjsvBvp%9=?2?86RR9*VX30U z6LXe*e(Hnmb2pyjloWCZ0Gug$3dL%FfDcL=?b|GKIOX1(&5TW7deL6( zp!b}}r4fCg?(ulN(9XOg6u)B-|;W7Zg=T6;={fG|fT2KE4 zLk}uSJluhNZarz~upz~oh^vKFZ@{(5OS?u?U`U51Z{s8~FRIj73UNT1)>(;&}_07)=+Y-W4akry44vl zEel#On96qPb93Egf-BeM@V@y2;%giWgol&D@z2o-re|%`1IS=}yolhG=nZR%EtBnw z9Y-(cyV}CVlRCW{O-{w53rhAE=^n1GeIejQM{0e&yKSFi>Ue?KGG)+EQJ-BOVhOA` zEiQ0jN7#{?7%KWQQ(2*RE;}q>+2Ni;Y$Hiq;+FytlTQ13XfN>E9iDzY^v>a+YoDV1 zL`Xa0*`PYpONmFTW3RVIctdtT>N-)=P5R4b86_yDLrS^To!km983<`&mzc)*Jd+pq>abT%kW7a zp$E+n8~$}{JCh~cS8G?t@+OwOUz)s89oV3A)RH6P81>rqI=w5q{A3xAi9E?;ock&Y zrt5kDaPHK1f_DZwPU%~0+lg_ZxU2nFz&!c3foI?_vmWW`XE~>KRf&Ofwgcj<)Wo)l z+Nj%?jQ7BTraD@6RSxzHv7STwU<=UQ+6ta^v{JX{`2yMgqR;3rVZ*c|I!tetWFh{d zg|}`Ax#q1?5DE=^xwA)LP=?3EHRM=zXHILFYjZ)yvB>J`LVixt?8N@Z>YFs57ou8f zO}1N{mrhH{Emx~`UJK}IosM4tqr?s2irjK^gH=$s(xkyy=R=P%H{Cwr^@9)MwcVfn zc9&oiEEOK@6l$#YpE}aZ&(v9?$j`1d)il<1P+e%YTjS`FcrD?t=H{v zAC?~JGrH4y(bUtYX1%J8!=PeD&0hl*J2FkF)PVF>mXxjr%XKCL@~YRcgc1%GMgC{o zTE{5x4**`L{P6{o?IbW>p@iwb-_S^<5f(KkpoTBu5RS*c!7OkzKlpCj^KZ{D0Kf#4 zwVWBqdPPdSbgxryozk%)l_mSg4jkl7QaL!!X*qq}KdW<^iqkdrMk3jho1xpasv0FZ z!tp5Gn_7PN9|Zi^EQM!PV}Gz&CqvmrI_?S20rCZhb+$|mv!Y`mJ`t-Wg1Z|blJ@pE zjRa{k^^>i^amn!^X8&ipJcGL zmUPa~k*+K9K}i>P{$wJ;WSK?QO3~&_%|lm3Fe;r>$18RYN>5 zdHb2!@q?^qiSKjRX6w#p^(?QJGo|py4Y*(x+0z)1G03e|#Jl$jwGI|_=`QW&Q6>qE38JX zxpK};<;Inku%tsjkkOh#e^@EXS89?mbnB}J=+Oj@%0yyTyn9(^C zri}X7d1YUP=EPFNxT^LS-Zxhil2Pz&Ol`JJ*D~zEfr{LL@r0Mbj*%z-Ji~1p!;XRH z70cgu&>=y8?5@MJLQ%&EyDdJR&gRSeupk@Ans4GHIBhpDjPyyZ`&% z+Aqmsus+X7h&ieoWQzde&RX8EC|2w=k%wfq-^&n9ou+Q3lf6NO*O82knkbevFe}xi z3o9v5ze5P+!~lbUbH0~<9k4NoHW0c7Htg=Oun=A-hX3TLx5n^trdQZ}&E5`G zZ8DQ5FG?WitRzn!N^Oe-WhsSXzv~pk>LpvlE;WBKRsLL>al_7qWb%YOXqn`r2wSGD z7GOr?f~(2a?VEK*?jHk|Hb-LxMW2RmZ;GQRjVt!P;`OX<>3v)rVR7GEiGc01Z|aZl zZ_*gMPIif4g0&xOHB6U%^W5QczhQ1pSP}B5^P&H-iF|7hG zJ578m0vmH$4$pTU0eZ^3g)CZJh05001BSD1 zuprEl_ycm)YT-D{+m zTu6)=A6CkwhGL^TO|OH5_Ft~G!LN*pj2JUJo6I9#XYn!gg0ZnS3z(bcXmE!L&s+tK z4vFdV<+;l%?Cy=)&mCOdA9hyTqeBER9PW?X_(0)yEt+b1--1I!u?2VKcSU&OqYweU zqP5;^8I0sZgVADDbJ|{Zy6j7CPk5<1vwalf54Qt+pVN+MP!OS(7aUvR9)M$7g!_XV z6^9788O1Zx0uuW`mnm5>_GU~M%CHfw>V(A)yBB69H8*J>{$jXzKXx-@Inm*=K7IYB z>}Jl1!hOI3xaR>#7NzWj6&T{_fWHsx%uc?%v#_9DbUJZ%=c5}8zbZmf=V@QxOKuWZ z6B1lF&&EB-nd1LZKUc~8qfR&;pyUThdS&w=HTWU=;$f_pK3h}c^*wItOcQ;OYW$1s z4qYfVg1^c-Do6Z+z|H_O&Afm z;QG2CPP^(mVv8$Ko}4D9_^F_wrYwBp@0a$OpB_|t1}w=(M8}uen%9D z5doh{&@Ixpf)F83M{@Yo--s4_w8xA{8Pw>RPnDaUH1F^-ZZ0?4li+tP8Hb`OGmO37 zb~^jFhrO7sT-OjfrMae*qQfc<6@E!LVq*)pmRtESAvo4^{+wFy%%fmpd!ca|J94v1 zX2GnfPKWlHx=7k@XQo@5B3mL=rjUm-$On7(OB7b4?XH81dwMa?{01Xztg!At=uXUd z@)_$;>@Be?=Y{gzqiK|!n8(TkqB;9_FY?yC7{29GYnMm6YJJ$TxNBRJdxwhlLF0_O zfmbGN>{8<-cNtH)!ejv+5rGb(^@GWB-j#+Qh|WJ;$9JyeM<#%=!#X$A6rVnPko;7S ziV!)5-4=-6n)$eGaeVWNerZwy3?6@l6La!epCg;Zu76E!Rl3+8t78 zqu3;FNnzfxS!mJr4k?tPMJ zdTYaI|E}HkSb=E^)8VD8N#D^*3Cqe6SKG1pT#g>U+xaYA^q*Ty)C}SH+7zwj$b zY;q4ngr3!We~7P?K92~fR1c7Ry`kMO6n#hbdj2x+k&FQY4XOmt9aPWLfV#14iR{FP#9_Gwo zZ(I!OPT|P zbytw52w&9yHP{qzjl3nHHd0-SJa_0LG0?;0)4Q;mnGiOGT+Rf|lQuR%#Ohb;+Hav5{ zEnK?0Dpc_b0`+7r4d&Kxe13u_!hQmPA_7HQCW_i&*jCvhV>v_3FGu{VSs05fs`&*E z1$%+#F2m}26?5vQYCN(Y=o@+-D21%}z8oH1=~Q;Q-zU%;T%bi?e{jt)%79KxYi?XR z+BV+8iFy1%3*U7^U0;31*vi>Q`#t~wbDhXCXAp!s)QSzPUGwvBhwm1~MUKNYq)+kh zX}vAn8v%+PPQ9_suaD;Aa_xnTxDl5Uudi4Zh98XXmbIxp z(QzGM+$@j&M)HtEXaTcVFLqHvz2YTlvakXAg1ol7_7sXU^%H8r@YRukwd+I32lH-x zLM-KDyS*b6D_)AQJHXDlT>aszmYQBWS|5m(RAR*x5(wMix z_#@H~;7g*TBBP!mI8E!%s1~sB;9BD0*-(!*jgkpO?2X1^Eb)zx;vv)pcg}8#jM}{i zX(KY@)8}q8B@VUuy)PDsg~Y@SXQl%h^%B(d($eH(iqN6(c-jlOOAiU7Z$G=wL1LV} zF}58w@?CaiWH)j~>X=c^{J?--ZJwiWku)5t9#9+CIeO;7d$&6EZcg0Yv#2R1@x{7A zMpuZNmqj+;ns{*D6i+@C#_W3*f;n$GXWER+727-TYG*I^=9uzj zl2rDGZ4vzVC1bc{(o^n4QY(+~H3KfRGOJ9kedH9iV1KbLy&egJUIV0RWI1;(s>wP# z%-4CG`Bf;kKsWaJhBUWg%4Qp=Li0P}ejgxKjulMyTH4qF-es8@vzrSaH>$C4FN1J|4;j?|H^o(QO z)n+y-h6#=T;PHt!q6eEB3*v<2Ycl8=dC60NKVjt{F^}5Dbw&gLLXYYf3B57+($YM~ z$`BBZ2_3F5rEkB~d?{uZ6vE&&MO7vh#Pwy*{~%(vYR3lqInWG+V)JP?gxHBr4}#a5 zUVNv}i6@;CMB&tyaJcIaI%X+#b^2DHm9QSm5B5P$@a$U8Js*al_4oFZgLQ{Vix<&f zn06v*eRj@LTu>Y+>Wa?@qYgQc-fJ*m3E9`wOh;AJX{!}A76)DtFGA7HPis`SeluX`)4i z)4Q#TFq>?H58jSmj_?H`wDfo5x3_jPW8a`|I@j3PtV*3H7&+^9xT5w(HE*f8ov%$F(DJ7NmaoU}l=ZA9L1~du``L?*VOt%}j7@;?)$YaCizMXOD zPv;wUN%;B)Gv8DD>ojAhN#N)FJ2ai3_r`{a;iW@PZcE~8nJ_1p(iXY7ndqG-_-n0^ z2T$Bo`L%|REO1(ECbh>CZKDB)+f4j57U2SgoqQ!x`sKj^*O|0KLgYQ*=$L@kz+8_y z9|q`je6Z$p_q(pp{cU?g=LV~mjm60Jiv3OhFospfPRnTL#AX{?#N)nn2iY|#igr*T z0PV|^s$%c@(Du#(zB?FH5S0d5#m05uOipg;Jy4DbUi@Mi=4*y9Tc2rpT%)vjxR26y z%0%z+hIPbShAhU`aaHMzW0$XU}E~#rH_PaMw1ya}DXDTXY-2LM6C5wELbgeIWo(zOL`;*46|| znDvyYc_VI#Dx+hkILs{%78(jJR9Mivha5b^CDAd=XG8hU=;~?DR2^sC18(m!|1eun|P0Bf&3M2eZgBJ?$U0bIkyi_L0unjpNsKtMocI zRBz-%!E7IDYCI$i2k@Dn15d#7YtvZ%Uhs6xM$@fl5&95*8vm$3Yxk~QH79SbY^}@x zR#13AyjZbKH0!eljvacJb#2HMTS&X=eYwK3JzZ7x?|rp9wk{r-^cFeAiY zBr(jA*q$-g_UtTvx6}5N5-Jv~l{d-Ur{5WxjDBqA5&YbVKKFr?-e{ypHGG*eUQ;?7 z%4IBjFOkoy_tXy>5F_YZ(D-#4Fc*w($XAzeRTpTHF(9iSFR(YXu}Yhc$>HmM5khb} zT=i^;8S~$Zka(u~0r&(Y8Bc^$3_LlSqXl)Av$@9)YjX^X)%zISbF8*IED`H6<}ZgH zC!9Wu``xb^usmasd&Qr*4cOlrT~&MfEo<1I?ZPWG5NlwunjNY3^D=2Dm{ z0?gdvk4tCyE?#v5VboIr~Z;Mg0cmlf#4-)x_DbxOr?AxjnI^Q;fU9=t)H zdL>uQxe_Z8P%1Rkc+}y~!GOYUV3ueLoa!U|Xk(T}BXWJv!Q~FHQ8=4`jsf!p9pN^< zj?8K>(BS|s3XEEBWz=J;U#}*i{c@(D&Y0)&+%h${(Ltz{*cw-l^N_Wv)zVcrxx1wf zA*IvNEoL)D2jr?lq2DZHc&M;>YuKBocBx8OJ|$Gh+X&)Hn|9udegRsQf*8o&<2g7= z_bqV}&)turnyx-GS9=bT$~Lsgg|}(uU?sNi+OyWklv|z~%L1L)w9v0$&U_Y<%-Dn8N9Cns z5zsN{8gN)}ZRnpUn%ddEqlB`#>%{O75^GCvyr|fYC@6fX`6F;` zArWK5g3TiioR5DAos13ikl!+mOHwc*$h11ZjcwqRSobaOl_22Q7+~?!cSLjF!Vh}*|+xO*zv8^8%@qj*DZV^e1&zGEGTha&*@Rl zc0JyOcT9mNh&W2`r&(3+IhWuKUmV7|?}_x=O7hU|!Y(~SiCccK>;aUd>)0HsHt?xs z_~z4Pt>NsUtFDOQ)R?o-6+`w4hZmk|tfA-2KtVHfu;?`tV#vT?Dsd2?%b_}U<@nj7~3wXqWFo|a^tAM%HBa8lBj#mccm=J%>ywu{ zz{64Vb)wz|&Z9@bi$nMn16fOP)`=EFJF7;DWq}HFMP1HjFwL_tVDp{mgGbmsjo%k8@Q(|>ui!F#yR8w=b`c?pdOyz zxy19wa>!f%uz-5)qdh)OId1Y@8;PKp@;;X+zyJ2$1(%((rjwbm{oaDR>DkT}jWNn} zW6rq|j%6tl)9-;VNxO%0m}H3T8E^6ys%DP$UYwced6nrfJIPID({#AxUAE?LC_~hN zGMYyQ_2Ri|(Pc9R``5u4vNrI0MI2B%8Hpm-2ElVp1H0Ma&~ z%Ms?OX|4c&cPUWU%xRfFR{JJ_&L(~8tlJ-}23)K0Yl|0kAtYQMGpe%XfpH15wMfke zMojFOi+Kj9wYLYN?>OG&`V_q>V~knSEAShDsAB2@b5PjYy1s^g{p~J8aeBcE+ zqJ)832(ztxKi*cdhzY0%$nBe76YGzi^&)-J7GXKL|B6K4E;rRUFReoBKG-GSm;^EU z>6Px!49E{u6zODbgYJ*AG+-}|@f@}IxR2&yl(galx2eEe_P1UWhmIK@?q$;!6cz29 z8a99)sWoq9n>rcZq^sJRa8|`|&_A?GZv0Jb@Itc~P4KKy!bP*ISDj71O`L+eW8~`~ zj~0WT0F*5`a%?T@8;m2v zxC~;{VK$5I;o1ahCoh%b`;gYjMgs|TQfL6|w+W-m@msjemE4?|&`k5mK*APKCmm+& zP2X=|)^+R=iTA2ESI^+*lDXf|{(o~z@Q_Hn2KNhb!i7EU;mKtsrKnd&$^& zI+D*5f$^X~zqH&f>VOb%ItF%Ig+vV zo`|boZk5p^9yVtII|JF@hztL{vZTTZvkg)E%@4s9>(y~=fDCiF`lpqz(=88hsQkMM zoNM{W#qu!iu@)-8liW0e<{Im=Lh1~Cy=`1%T+m;8nf~A1&#W&lU$^^h5u6JmieTp` z4A?s#sAZCxsd`1oGHPI`3b+EyFg&5@Uz1dZ9cBQGc8API&xK|JA8ZsMFQPKt*ok|k z?KiL2lt9D}_R~OCu*ZI} z>odb@m+cB*|Fu0Ni4?loMi&=SzQH~f-toG|h&FacmoEP-CH!BuJ*nSy{RY$gG{=J0 zk8=Qbx3>Nn?v4-}1$wrh_!{%?WIUm|%zw7zoDF;3CRXUlRbbF3671`a!$+Jr`Paz8 z074=QoK-WA#-7s{k-J^@(Yr$Lou8v$rL{ih5+P$-+K_OqC-0AA1sUZ@c}gQv$Yla+->jKwDg1Ei}FhkaZJJVXo8mzP7`Go1>V|S;bDWzLe!YrSgFCr z<)rj{$8rAv4g!qY0W7k1N%G%nG_bv2rXIKg-d2;_X&^7-I6lrWN*yjgwym6sp&4R~ zLE~tB>HSMZe^gu_`eU9!BC!;zumV%V=_phU6 zV9*xlRF$PIH?y|ERJHXvWR{XNMKAHn$5t`>oc* zv;)hOGj2~9Sm&kpOm0`)Pn(5Jkd#;&xtduP8gXzyg~q@~%d4xa2OV7I6946B1HJL} z`HjUy$bh#aM(0z3QF#2;$K25_hK{+fjmySt zq(d-^hSzl`XJ9Hp7F1Er3kX;X=CbOIx;#i9`0ciXON6fS!7GU{@DeND@=f)=c?urg zd!#RgY>5`C#XO?fDg|YI3OWmM!O)BJ6vlH*F&>tlj9p|$i6*vYSyl_J`QCcO(xT~r%)HR!*d%YYB*(HmT8POWgpXk131PH&ZfNB(nI;@2aO zzig2(O)sd82nnA?Kutb?JOHp2O3gArstbX0b(+4I&_KEL?C-@dMlnCzH!XhzIviD_ zzdfn0D=o*L_D5keZyKxyHEiL^23r9K^!QwP-+~Wa!uV;EilCTc9q6--cg!?QDY5%% zP717qHoa9T*W|u#B2zHX$0|H$5$vLh^7C3Ab{xqGL_QD)b$QBf z1~WaLwKxpgf){xFl$Dl#OZ;uS0iuK>m-lZO0RL_RxMM&c{Dexw1wYl}!8slF9ewzd zlL0=Yzy$RPX(tTrG{34~xF3+>0#Kht%%}PjGw<;MsHX#etNJa*E!P}=^VvtNPfa|k_ z;wB~OUn*86=A}f_&#Ft}?fgBJ|6|n{KsQypf(wTob&mo*besK0KV^Q{D>5vWfk()m z0H!9dm>g+jFt{W2|E-VGiF}aYV%*5;L`Hx$%kn@Bw_B4rF&s*i%61}%+NN>UF4n5S z`%Z^+_j#LzL^-Di4}PV%0?tagE@`It!;-m(Izh`<=gSXQV@>Z*-R$w+90lx8R}LdK z`#Iwzb^03-h_XMe@&Cl}{PT_o1Z3#UA?tU-LCG3lDN06#bv4}!Z_?I9xq4objF?|b zbVi1qr1EbxTF13lj2uY*ShfUkS|9hF7nHbFh1IuINQtQPD=OY;mI5QN66wSL=6jC; zLP5VM(Hm4J%}rNL`puX@uVUQ&VlMaz<$LejT>*Ug>Xekf)F3<0j&2Vvz~0w?dlHtV z=6e$;$rAH&2Q_us&OMV9J_}{1#QTI($nvLU*^_@zmc0YH>5W0Uh-@pKxi-N0d_7`>gpBP_%UbhFj zkVu@N!V|8&Od{Y-ka~lR>g3xuGQe{j>P>PbC>i_L5ELE5q9#`ZcP|G4)A)=cxI>{f zSw?Gr2@gtuk{*J-NV}jj#I2>rI4pf*2)IJqA;CVD9VH3%Q`Vj{?+;VPu}w#b$U;U zBGFVfW}UzX=CVl7lgQ7vdWOch@4j8RFXt3-QsqX?gfFem>Hk{kuI~n4waBqWgs1Z) z%V9MV5KEw6)^lt0R0*sce2r3@o@S3M(qFF8OkGb16}c4(@!8Z|5Gux4VE{OpNU?R> z@)*|rp`*_S6wdPVAGjdLF@nPg_y(3jx$cGE5jzY!u_E4Z9o{eHc>niW=p^3Z2W{Ss zSVEwK0_t~yW8WeE{&pil!5s=3yuMf1ahlA@W~rGtXFJ6n$X)||4Salr9L*<#3fMIJ z_}{_gD~6zKld6NCcbAnr{5mAN-FBBuO<6CWqRHGl-;0K$rb6+_2i7K-!X$Uo>BP&P z)!a!KtTXZzhO}%hb054C1+~6ZIK(0U;NYYqxHLR1v2=iR7)|!=U4WvNfV6+=*m}VA zv0V!ewAx-7?yD` zghc>9aHBU_PK9Degb6`Eo><3af91kF&yac$L3j$9llIUg5E)jjH2Gr39J^=M)I>+g zLRri3flIE2i|Os$RR!M5&IZt)@0d<+|8-dyL>Ch7mis^hP!-9MPW_lZj~E&@z!8h- zxoW)&)sPq-1Ee}6V`VtjoS#REoth^F0~k_VUw|+aEDO|$J?WlN?t~a#-31m3@)k+F z`Y^W*kfc9mw5Q=Z?iw}g4GJM4361qTSMv&D>GIGzyGjN;`Hs-E-s^Cl%^R54serul z#`J{``z7(%p@!fEe;A7HqI`Bps!UgQWj0@)hH_?uo&*>)#=U63FM+vgPQGvHYwEKB zP_vUS!c9H*!JD}l1Nm-2W|8$Dq9d*YVYWIVz^am&i0);`6Pizwcz1zuwSW`K1Sfo9 z5}1J4<8_gvaiY*E5YLz_@NQ+&g~32YEb?FY(aT) zl;jooTdDnPNnRM86RFfCok9Z;Nz^D7;2`TT3FNbjJSTfv4sVL; zB=FL2gMA1a&rcQ!(n1I^!qK0{=lrBk5nUF&H*4l>s!b;Ip>74TmMzU)ekfb`&MrPj za?7}6+kc<8WNKqL$|MkzS+L+WlXtHwHsCUItJ}?^&t|Z$@n8IGcixDmLP;)x_!6ty z03f#7OZH=mqIqHxX!T1_{k?w9VM>R#X1YZAaYuj7t3@>$#N00d8JE5m$|-*c?A&m} zQPc5cCw`!J!Ib~}K&oa6j3dDzxw(%$oELOL{AIrNG-AO?cECUy+4rLC(6a5x^jK4a z+u#Y@GXE|1?B7Uf!{q08w2BD-#j>EG=}d4looEIf8T7_^ zZCXG)JE@(hVFE)jw{eH$%`|l^6p4t4K!)JOUjxkFK}J5Rw$denGz1Fn?3DA05a<_! zGWMf~^lj(gtnxq6fBk%wPeTFU3MHZJ5Q~)ND7k#HiGqxcf~tk$jEIn>c2Pi3R*X75 z^WS)TexpqmqQ@0FxQiD$E1I6x#1`X+LhPkrc7lIHp#WCWQ{QXb5J4RnsWzqGVL8SyVn_Mf6_e-aV$bIJi^h^2Xc3_v1f3{I)z z1dvPOtskm71$^CSC;7T|-z<*R>06*EJ%(P8^kVqL_+~ z4|{d@%(~7k@LvFV-u$6p(tE}92vUvd9en%4=mfzZIh6wHz~f$lhWe^+--7cvCc*TG z1dt>HggdAu$p;MIK)@gUtwAY*=J}3&eSdN$5wd^()em`&7JN&p68zzB;??sAv5(QQ z4-w_Z{&a#Ms=MzB@9Uj+@jMUwK4S)_=24$-Y0K2V!p5r-?f%1){_Weh^iBI0gu?>^ z*|&=Si6tE%%}HADqn7HoclqPZ9)AIa1h}ONych-njj<#D0ha?97o%?iV^WJcz>9-2 zFmpaoZT5X$$&m~6y~mLxN6Ggo_^z|L=j+z%9;$})GF<`M5z>Gq7aji0^0px9!1#bY(IKTwi20>O)@1amPr#DWdhS$-bk4 zO;fc=$JJ}pdkhVWv1M0fKW-QLQPX0$A@prtzeAnfnub6eo?|cnXAwB~p)km(Sp#ro zbLh=tlDV3MK^>tDhM+xsC^JSTw=H=({aetGc1db(rgoo5X)uF0iH{SONT4|E{N+@aZLc{_VTwT*y6P$V1`xf7e#tzp^_}=v6nKHs1%V@aROo{`e3rk!(34}r zL=zMTvx(z>l;czHW!cuNMlRkyZduelk62OgNLP|vEBgJzV44a9>J(7rZ90~9(P5%? zj-R9NP7fhRCFx8a1n3yRJ@Vv>KeA>e9wa5Vd*duj^8t!!$9z0wC+^-t>pipYeXezW(K?0>lY95LH~`9{zscB02rv&>08bDvt_ESY#gGC>}^h; zUndEM;>%0of--F$HG5bUWbse9b4)!BHvR9ITG`#am-Y7MH`1^jkT(JM8AVsrCFZ>( zCP3|mBn{OXUh&`QO?PM`zg=zhe9&*)w@tu6{6D@!oyhvNyn#?%$d@=yk}G*g8Hp|# z!BJjdz*3~xx@(3kyh z1ebtiGRr(QFLfE9KdTC1ii>J1XA5hBu>+Ep%Dq~Exco{#x8db;&%|#n=H_anCWhvs zKujd$4;pF!2avu0q$9fXRo>9Z42?fNZBoYVm8XUSnKd~41{jHW#a-MRRTj2M%%-1nJ^Yn-=8 z(0h0oAur4cVy5_EZnh21x{y;;;`~A^tWINdvt)v+Qawc4TcZ2xuQz3O5#waLQ~XKK zB8qq|#FnXiKK;vMhp}t^3F-5*050G$)+uTOoA!VU(6P~ixPk^5DxCE6YdSP|?_d35 zJ*%USYHcqH#<-;br2ug?@GkIy-*Pqb_kDA!e1CYHI>WIxSIR}rFbSBaJ>)BV>J~tJ z)idCOz~n1KXuI@l{S#*oo{f;exb+?2+8wRlbPS%K`~YOmUDa2fHE!`0imJWd(YpT_ zf+y-f>7R9XCczc~1k*P}JNZa>?ZZTO=EE)gJ8#|h(}^+qc7thcF!1c9*g7)>>*43>?q z`a_8e^RI;|rMn+txsW~RWP3-yNg(yFTf#rgc;vcFGAoAnw!pAw@8oo`EST%e7a2~7 zyRvJdm-ctsl;7h|hrI_zP1o?GQdJC-_=FsJ%Lia4ff~zPNxuIu$FNfU-h@+2h&9Zh#SiAU@ybO$eA4C1bb=fSHFvh(Efv&I z5+_OPn)k-yyMD_z=t!)WHqeDg0!z>tG0$vwu_b z_P6UVuMBKnxe^>?_Uty!DXaOt&lUI8qo#n2J=K`4!k!|$JvQ%KWbwXe;g>G|Ym0Qe zHCeX+fX50;9y(A6lb^X4n~NWZH-&Dc!CYVvlSy+d%K*x=e;PL1iIfq@SGU!_;-e0} z8W6RXD=0jAElNg%%ZHM&_l=rGks?m~O&#l4*5S-xFle)Y&|DV+`eXsWFy}UMA!~;h zeC3^P$j8q?5_txlu)H2^8)j#6tZXpu49ukod~g&9-EkBMt$#enBul1eIt`n=^Gw#; z`G3_K9EFlE{2Vv@Stz+hF0!7Jouq!TB~mu-Iu_2!y$D@%GfhRXvDQs&o_mLcCj|X{ zCa7B=*e{ zoQ^i@kDIhPN$MX%%2gJ}45DU>Z^9gY4;xoON92Au15FY~yfp z@d*?rtzWyPz~4R0nf0l(O_Y7OBM|W)E;=M&7=SxgASaiDj+lXRleSyogk*l?yh8Uw zMqK;!Ea7$fzl+1jvxsSF2)x(JNzwdHc)vEoYI{{aRg|KXX8DMb7-0Bw%N=c=xp z*lHo34#QoYX0(bvw0yTR+2m}1?S z3tC#&DTRmcfQ13kd8T|A=&g#HkuA~S2dYd-A7ffqz>)m!<*|suC@Nv;x{{e=W67K( zT!t6!ew5HuX?PXW{=vk_R%q`7XNVVRZ_UEa!bO#kjf5haS5d2Dja(!uBt$v)>ebp^ zoOI~6ot%sZrW35Z@KvYCXNc_tA=y);`HR~#G{l^*$%77&2-B8}5dG467DYQQV{w+b;*B z?77>*mX?6yF)EpS(8G{anv1oa{_x9-(oPjUd#P{NtABLtK;a3yo_-ACzy6N7Z>j0_vg zOx0rt(5`S>0HQ$#;{i%B0evjJo)J3TKC#^n6OovQMta-vyi?LWx}Q$Z)@~Q^j*r9A zJ!B7z&)PeD1hs)p%ks z4&$n$-gC;+sqmEyw$N`0=lJ;kD?lq^>eSoZw3wDKOsrhO6;)?b)eQ=K7F*+FC33m)Ol$2zN zQ1Sy)i-vJa*Y_4J(>K08>X(vr3|->X&D{+99DNlRxIFrpytH1+Ian?biv*8~Zm>K% zv{U+G0m7`Tx~5mkFzIVL3vTdDcfjX4F91)G5&`why*K|e11n49&_wNj$}zv`u#i8}Ci+14zAZjyc$cy{Uj#~`(zc&A zbTwHjb_SVl5;#vs`FU^g?b%I%df~imX;wBDkoG2ezk}a~@ll~|q4sc5`2I$b5!c2y zCEwXm3d!xq_5$7{L{hs3@B2Ywh0RGLLn~Un&4;uvHf=nIF8LptjF#-|ycSI@ZQp-z z=*BOjdYXulYoL*_Z4*=ackUW9M(uSB*z)AXIS-c~AZbFCtqtC4p_%K26Bm&1756U= zARXLB#CiB#EQETFyT`#o`Gc^FiBnN(N~ti0{|8vYRdiJDzxvvMl_L~$1xGdCPo2B@ z8x}WJkCeK;`SQEc4;&{T6QFFPN7u3b$5l@1I?_L`ff;?kzyVIh@4T~O4@@2d*(&4R z)4<0K#xdg|2dZ{9vqkHL6urwzL@S3>R55NOfRcdLd!6-Bg{U@6$xwpA>q_G zmT>aSA>?Z;oQxI6EaOZ}*8n5aIAP!(A7|z8{0kRr0)b0@+BG}>UHg)}@>>P(c9;Bv zv!>dYX6Qxd+4)NylH#n|D1F_XghN8?IB`Q%%FoV3Jj5(3y>b;5a{*K5cItcGd2MbJ zC$9n8DR-$`uL)$I*;Q|jnFlA~{+>Ea?ZDpIn&KiuYOht{`8?rN<>tqfoNv&pj#Wy1 zW=Woj>l@3tiN0evcD4t?+4!^v`u^MPptb`psf0Y10I!SP6LMvV|A)BmjEXAFx<(OE zkitL`3J@`XWXTdmC1((j98{8kNG`Gnv_usNl5>tqh9X*^k|~lz0ZD~`2t@%!_@0aQ z^h{6pwDZo)`hMYJVb#4)+-IM?&jBgsU{OPj7a}&Q<*!JC-HB{6f%giUjk2wmznZdG zYAd5uON3gp$P7-{|3k4c&~@WSn-(XvCNK$k!Aw6muVx>Gg#&0^rJq9B45#<59m1~Q`kr0eKI&XPCE3NX`npo4sj&JQ z58pN2UQvNy!cR6^qjPUvZ(EiNObK3w^M_F7`&j*n)#wk~Fi>s4xo6=G7n(ad3UXi1Ed0%#%f$F8+MY#|ct4$BV>200&Js(y!aD|Qse06x4zReF=iFLPE)O#{uc zjZZt?t$05A#E(`%f0Ba#ZEQfHIwys+nnOcCq}NW8gw3FRB&1Pa7` zthvpX^hmzx_?!B<_u0k*ErKL+%-0WvZC@zrd2~brvIaM`%QNVq9f8mwlRbIJE zybcd9$n%EAp;HJJ1UItl3DcDPBts z<2Pv+css<~g<*AHFA1tyX`w?;UmO(s4hvcv#im0?`>tE!J7yCsw zP}0cd#>p8|8^$rgC4OS90^J*n19op8ztwR#cSk$9#yq+Br2T6l9uh)C$<&LS0Pfi2 z6do#KAsx{tFJ|ovO4N$nAG(qaWNEZC(jrqp7Z8Zl6oc z@^jz7pzQ5CUA;8{ewR*iyTqy=qXxsoh;h}Y;yQHUswG=ddO_AOmiD2E{p&TFjCn8I z^tIqRmCwEJ&eHx<^=ibVYyy+N8Bgk#0BXU zy3%$j6XUEJh0R&nw@FHbK2gC9Ss(N*GQbT>FY2=oXXKxXb%SH8i37Ds=zWpOUb-bg<-z2FH zf7d!iuv+YT>|)2XuGzsn(dMgUh4}F!Zh$6tf;ZoY@*#_e-;DAL4Gl(&GpoTH97PEQ zCmt{b`Eq{Z#J*~gN6l3v*ax`V6G(fx%T!PB%ZIW>Px+jdi>t>LyqyocUiXk`rc)#w z78bg&^oEkSe0M$TX^tVytrF{L=`5nBJi`PUr+o*X2%A6nh|~2mZ2pARfe%Rt>3G=o zIbn9%Gx(Nz_8xWKAqlRNVuw`{LGKK`IR@M9>nHaaWS~V8+0-)S17<&?7>?Ax zp?O#j)cofXz&Me^xTvl1^L2N$;4C4Kg@_;%CZ9=mMVaYIj$eB$;r&>q9lDRhQEA$A zv1ax@zNi~4mJEZm2j4Mh?0M}TJimu72(<2Eik(SW@Dz)gDQs-4OI&Bj0hXjMNgNN5 z#C`Q6hd z6J%$@1C(!5z5R(G!Xp0Cw^Ia!!GWs1qJ{hiLsZnb?f5}RCryw7v=6z#*LDMqM{u_p z`1yH?ErgUE^g>nweHc6~c)v+pFrSkKJ~p zSz#gKSjQ5d)XoC@z>4Yy)k~L7b)9ueQ~L%EXwx4oP7CTvol=E6%zSG?&QePv43Y$7RUS2RIxDbBdo`5Dz(3&7FL&(@DsUz1!=K)R)vPeSF5AytRClN^aE2~C zKZOxm5w+QfO9e9w?trmqgD7}#mpGPhczj3}O?j@r+~CnFmMK!c~?P{f#Da~o<{yxOjl1(vTH5dsR$ z5?FusNi@yo9(#87cJd&-Mc1OGKkZbh6#LIkU4 zkY;eIK~p81(}#v^3)F?>X%ib(4Xa}Dzh%S(mf>Tt3=iHR*x5JuR?SO(DcKErO!rn3O(|1{pqV}u}(;p`?JZ5W=)q4&{!vxo=vOwCBo&??(;ICWbBppPvPFF zp<7nq)bZZaaG+(D@E&t=Ol}gpW(scPj|S96FF0T1caf43=GhQ?CbB)^g2kjB32W{u zAQ$CcJlx*@*o;&DpYCXbPo}Ghoj*Onu~QA6xUnP(kj=@!vcQb{d>D9=uTDfNay=n> zimfKR-zRBueX1o>Afbq#k1=wJK>4)bF|I=Pr=%fAhsKv*oYooD5e-o*(%b%azVVJV z`+BOwleLYW#Ww5W&FK%|59)@PQwE_UKh|)q6=8wsu`I?_rE?WgY+zHhRcg><2JA3) z!<+Pscp9a=y~gWhb^`3xj?7)+akNXrm4@Z)jhe283fRXE^%(ad06d$U5sY7n`)Y*D zLp;nrm>szu@K)FcIcFHFne-IbdI(FbwR|Rtg$?$_#!6m@P5-j-25WoY5Y3E)n_AWJ zdRHDYiM>jJKJ03De%MOgRM2N3#j>=*h05ykO08MmMxxGM0Pg#>t@EpFW3>&;_1lp9 z9+A4rtW?B^BBV0C14~sWhSte*8+~uie_D3}Ya0t{`)e7z$-LIpA+g89A4x$Ru>Z9+ zRXSc`ITUeuMq*V?%>Q&DA(a)w#8p`l8R>P#5?=8Nd0OPAm1RmU-F98do7!m2qHCAJ9i0*eS%v z5d-zZbl6VO`-ST>VyB@aS81LrL5qb0X6)!A7Xoi!d3=_cm;_D6U*S0a;O#qKdYN(| zZa%)7W*BlK{rvo=Yc!0ENhM^4`TjeC;9_BVNxP{SRD z5xjnH^ucV_PD}OCeOOspytR_P?RT%VEHXBlJ*B0h)}MBK=aQAknqR4Q!pPgczWgD% z{yVg~$N<{$_4`($8#-2-gWeg-)`cm@9qalSX9Ws1!6%H0>6NRtl{j(>f&fiI#4dYbG>{qsHtztKOUEIs|+a{}#TF z9&8YwP)E{;aeu3*S6h?2yl9<{&2<>hyyjF1n;nuv@$RgnQIFq0CgR)7t8ubFFLpEu zi>qG*wau~}+KrsgDt+>zD5NVanjFJ^VB2vI|#Lr07Tlf>RvuvpmN!{tmG?PX-Ed3wE)#@Z>C^=Y!)6cs6Vcfq z$>lW_GscC~e4FbK`(=sEwBOwN#5GTvRUiMSJh#wQ3JX3MyNsl~uq3TPlR>lajJZlY zidw_t?8@ZbCq$jR$QJJ{g^ybd>aAggdMbXPn%fenelu&cKQDuQN3N$*c7&0Hx*4NO z&A-uEDefsa_EPc9lb%y6;t7}B5eq)Uwsmd~yluxYw}mT9;za5)lCRRPsP=1%=a0uso#z47; z$!AI8B_R@K;`H`DU9;7b^0BRDEeA-4UnfcVEV1=^0O;*x_se}Z3xsF8+4m!s+)RAy z>!T1hm~$IPh5EGpTK2-`bk1%&dGC5R4FBv-bD#@;40pkrfL-_I2&pyG-B7FAK%9z3 z*KO@Z)uue03@-H%89B0Kust>zdAwh-Sr+lWIwQ;8=%f7=)n!3_%?NfwTPI z=J=oR6=+c{MEGLFIQDrnZ0}Ax^~hwPEuFsol}aCYP=Q;74c5V zzYg=nXL-H{SAjf99wO-9u(T&Dv7G!B|Ld>Hb|cb$6=Rw8 z?~7!}^bu#5MvyWpT`&1_SCz3ijX_kj>fU2gR`1DH%a#2-{;|Mv-V0D5sXki*T~Z(< z8(;X-ICd&wxec1je*{VF;IESfPmK#RG^oo4NQV6>UOeKGOZI`!SW-CVJ2`NNdy)^{hz zzKyM@HOGyolM-&NaV0-ZG(@VFkPd|9)?)UoIWXeq6bNn1Wue89(Qfu5K(9qt{aIv# z5*Y(`-|yp6VYBN~{r>#KiuMG-u*JjIIz7MVW=bnuq=W4B-GVY1`qPa3>87^>N|t>143M=82vru>(k1Mzmhv7DR}dco$}iJjwH|EMOL(+`ovT zu{`0z-?w_m*5~Fno;W++^?z^1PdlIArFj%=3VhK7Lv_FVOeGflSA_;#A z$ZOG_ZW+Z`D+avj0a$-j0v!boRK(v5WpvK?{3%Ho%GcxdtfYnmJM7$FaBGH)YcbGCg&1oFFtipv9praQ@AQjb z=_$5*3<}@rzo~@IKaCy77wW)r_!@(XXW~X6+A%HP#1!T!IL-ww_>@YJjcE4Li(?zHd3sfsGzdG$$GoP02$ zXWtmQ=(P^K!2&ogipfWcX9-R-9}94PJLSXmQ>RJKMG`r#xjoun&&L1K+J8kwyj&x} z3ZsyL8J9|4eFSbSUhFz-zR5@K4b`DcN-LYTg$EW7M6NIsKYUSn-PQh{oW3z%!-jM8 z%Z4d{R6-DAz0uUiJ9R;k&;;iAif}_CLq8OwHu!^e6vJ_(I9NvA>#-68H_*Y#e#owi zo^I9ww{Z_w@``%jX{ao~@%RbLx%qiI?V`wdeDH)P^xst=Kx!N+>??u!@(+-iA7on? zpMGE65zWCa*Ql-ST;xiD`xl*gfP{+NAGuyE&J?0f9oMZFyilxa!wk6x?p z1tcYHWcNo0=Qz?a~||Ra2(#QsP8ev z%H(_ID^!2el0W{1Zg+3ka{aI!fSsS#0IUSitnwswdjkm_uf0%|@xE~i+1?M01a##k zLe#VcLZSW(6p()BsiEJod*o#gatPPDO2``vBZO<=?4A8!7oADEU3bpj(q8f+2?5RZ zZvQDs8S1iV&~c`o$22*oc(x(0h@XBH_$*;J&3?HR#TTilDFxyfb&}u@hA`1H8<^p#c_2Z^+B9 zmKs0cD!9sYc-7BeKyKnI23E)*GVI_$)A^KYSOI+wXyEgMizjC$&IfZ#A;olVA|YR* zd;EC?XkOIU8>K*fLE7FJuf_tC?dUPIW@k8RmU*A-2jGMiHBMcO=7;#%m%Nyemjj5PZ4?0iTNYq zXp@Gq8(q)SDoAl!6ubtG9hQ>qkC|DNnB>_g7-ESv=vVAbWg{p1>&cz}(vAHGV+XeApXCI=&IBaH?~_al zpcC-oRD%`5c`V=q>QD#;ciK_z8CCN_ZE8|oU56_oIX{tK`hExc(pRsDBR3@1^d{t$ zf~nC%)lM5s4gp+TQY39v^(`LXCTD20;q1dNp8c8t)A5ev1Lk<>8I{(-vrD;%76c^w;^<{OAw3v4rm> ztLFA8Bi2Sd|(oLB*`T| znlVT(>H7)5ULClx@y~>i&T}6k`-F|@HV^SK;;GaZY_&eFPLiV=d(`m7LC_iaXu0Uu$oIbmrk(B2C1|~4 z7Y|92<2mzMTkib1&ShMAtV9%rGjr0Bm+e-wqgwS(tk&>SkHvsDCX6T{a}HuwcT z2Hrjau7>}`YF7gtY@-B{g^~wpxzQxp6M#!-xAgxIM0j5}Md(oj-A@HglI!DJgkl*d z2f)rS#;tJ;{m-74oeh@H@=8mVOKOxine>pDSX@qp%NtHAV_GIfp1!ob@TTiBa=ytq zRSC{tXu?p3RDNo_Qx*EWabkUZc80H6R#Q=>iz+JryI0^t`Qn#rlC<(&pJ)}iy%4bV zNDON%Iq6!-QQvKe0VWIUE)6pceFq=Ef1RcN9$)J?J{90HN(_TH ztV@Y7xHgFAn?7_sbs8W70BnCH3jQoM68|HK!JkkwU=lo@4CH$T3D_Wf!+4kv8}G!S zo{o&H^$jGl?bS0ERWM;=31hV8S@MN_x^CQv!s6n~D8NvUPfp&w z8+w4+$*6V?Fg-1@;kTTDXfP87h3_1ndjW-utk}S&sQ$bNqNggN&uQm6(mGs5ucLF( zri^;5NHr;@;YFrr#mmrOxXrY>pGVGiZ_pwZrrVa;dUDIex=6 z>+9EnpSC{>7fD4-8#in@e@umqkB={%^hl-Loim%ypFckfGA<-Fo_Oco$7L1T3YwK3 z0A9<6jhB@0aDlr3h!}0uif%w(`0fBktLxlVMcft{$IYkpl|D4N`p9_C15-7PFI8}& zy$`pBh~HrR2W0*Cv=Bt1{vcTX_5&afCL@UX*Cw%EA09FIyVSsstbxDbCKO0Ph_wna zd1m`7ZT>-aVYBmKg!pjpKw2q{IgQuDaY8Ye5O7up`kao(Z(BA8Z~1QA#hlw=^goQO z=T10D#cXS{Bx*%^diny-D64|0tA9=%0O}bO11CT|yu8ccDcB0AcObkDlscO&(LaW_ zA^8y5Ev`h=No?vhCBTW4B#~v=6$l7g_aaumy`zO<6bTFf=^*`qv{01lfs!CS1m+O7r@G}+m$b)j;E=ra z#Aho? z6_YV{b(uh;k-J%xz?|`$j_aTGLEpJ3Qm8d9X5k6o8c2?~8*Ul>FK<<2ET$=z(2^(l zZpWcFdy>_&1OrUm8l)*g-J{APKx*=H7Zq`TP3Br^FgR$HMW5>`i$!kWu>ZTu73>+@ zmo_^eXw&NHE(<>y6&i(l!gNEoPGescKwAc`8z)au^x zzX30AsEOsNE)1j{b3AoUj)LgXmZ8;(qBL0ykZ!D(N&#lt=%=pJFxydCrC_SXg(tM( z5{XAaZ_*tCY;CwWmV#{5gV$!SMbHv}g!CFH&-7Dw)4#>rIkc2Yfh;D-4czB3r8v@V z`nFm}l}7BDGV9$SLICWkh--f;FH*DADv{FSwg$S{SgxAVj#TD6*zc5K>}MuvZCgLbN(M^;R`^x7X||M@dVS8=khfd(mp>$3)ex$)v|H6I-Mb%7J}&vN2jl z!zU}k%tHTz2|+`t$A)bzs7(7xN|u_CM1ynzd$gFr_l{k%%!k< zERtOSsZsbZ%)}l)u@?Z{^t4<+>@Y!q1l9TRoh7@Gz;s9;Xt_x4B};FfkO2l`zdLaL z(~u53?C!BJdsJg8$MN^SCN(3kh9BI*4_#N4=l)C)Ouga=rG0-VXU!BV=*ApSri%8- zm9vsp<&zyR_;Q}0pyFuh%KXWdV;xGrIXnomrEaUHR$|j9h6e}D8PypuRjs;&p{)!G zW6?&+f&C&RW3lYjg~b!>I>~SL2kSGf?BY}KjIvamhLz8p#r7^EIoRwhfkxoJe*^bT28O@H-dit@7!*_c!!OtwK+%}_e#BMP7lwfC^%$5RYiY1mE zuGu9;WherW7>-&362kyd!>UZe52X162ex=jtv~np6&J25M>nL>f9r1p7ivK6U{+Vd zWMo6^lz!i06od~84R<>Kf!}`(;OC8jILhGPWK)BvL+-jM`gL3eP$#rqI|`EOZI+4t zB5w@#7+AGwak?XF@FBOG!Gt$%+}OU%sWtG{O)~j_!f!~XIgPE(03pY~{NKp@2YqoI z5cdvP|5U`1P2obY*lFnJ9kwsx8ERQg7RcsiO004&Y^q_&MHOVLZ-%zg%Oog7_v+}; zDP=E-*E-7^ckE(O_^A_7Yc-$zX6A{Kz*h+HAshU&sc|2_BWE2;C<^*)+yk@6g6Kd4 zik^?d#9}!^)155rbp9eNe=~3m%wBk*uL!o63gqRT>g5f`OO%VOPc{J_E*E?V?rgBWwghDDZj*3w! ze1$E#nUFbyI=>#@4)n7*1)@ zB?M7nl!z7TP>%4hbttOYxV`T;@||C&_Veqbkmls-WwCWy2c83-zTrtW^`%<}@|?Vd z1dEmA_xhdV`3Gv3Oqarj{|U7}gh+@O|9fRCpjp_B?&v!-D6-uJ>UpZm$^%r~%*T4C ze75hf!{A%||2F~6e~ZLNPeCfv%V3~iJSPOO!r&YWr|hVb&61my<&w}9($fmBa)8c> z=_OydbtqW5e$Cd!;t5w_1M_4k(SY%j9pAdww_{p=#904rrXFZyk@t0(G~mTqr?0S` zdDGzOlnVRkF2M8v%V3e<+0o(%6cmLm#|4ieaP;O?Yue&~8v6KU zRS*^Rc}(d+YPGTl5`okP;~Xx#K@h2!=}(%o6oNx*+9i4Fpgw)=%&5?<{KlY8k113T zzZJSRXYJ`ZXrvNIlCWzvBtQ8D-SJ=j<{w_MieYrzu;N1Q&Wp`X4uo#2H3E zoEckfDC+0elkB)0FUeu&PPb%jC7&oq{2=4uOaVn%w;pSH@joUA$KC$W=<~;NILmOj zt7$(il#d0}j(dS`FRQ9l1nFtcrZnT(=)zf7Ccn_b&yD|r^7X5Xx^V+DjP1VZF0#Z( zlS~-2l8new$z6Q8E5EA9ReCY9eY#O(B|URGJPYL6(+4zE`f(#L7#DZM6&H3RWhGK7 z3x=2lv#!E7(fM{9X5q2oEOuQA^;Up_ti3C00CJoBg$|D_N2u6o z_b3M6BFO5pN7RRa3~1>Q*>~=>y}zu1Czg;MOWNbJslsaQk}dRh*G^CKZ8kHiuTU4J z)L9p$CFT`nrVul*h}cTAbaDU{w1Kw4E##nK9#5KzxFzFlD()d-+r2AT;AW#mJE7(* z@7g^6IM^+T9Q06I&FiYhSPic(8eNWgeu{PzGst&zF5rkjmaDsb`R%rGpzm)Su}$;C z&}v_ihsVbEI&_hHVDtL6N*uDW1}nXToX7z4M7c3-{p)_XaRm)Oy|!ZKkos-ir%`zp zt#%BKds^Gq`=hT8X0HSf_BIUGN#k2vEV8O$8M8bCR2H7CBBgi8{pe!k8+k_fw2-`+ zGOgKb`EMe62uZ0__fmrw9!5@Z05e5rnq`z-6;`BAhb6bPc6W*I|&y`f&3fdNcnxaRMd7wIzfHAHNmrOOYWnrnp|g$?$2P1?I?r`eBvf9OR>>Au9$T zSKf4$J0O)h!IKsFDW88}$KLOUQRY(xgpD_3=dl1aOCx#1UjfyNy3SfF{2JMT9;Sew z${;1jW+dD0<5erfq8_&5T}0KK3VT~7D!43%^hW87josjVeBZ_rEx9301JY>s3jYqi zUgONHvBZWBMieh$iRd!C<~sjX(Xjt)?EGRDC|0I4o2DHTAc&Nso7!|13!>!Z4zm7| z5xwpiTllqogg~cEqL=QPY0_T)Vj)@-U#;mq^Rhxs!}qe1hw{RH-UV?wjjxKK zO9QAwo(cVKQ?<_fGxspno2H&i50xVenG{`{pH|@lwZ&f;lIqPBmRSeu_VF*(Odh>P zz;Q;dXQ)oVGIy=f(^71y?`Dxa1;M3&07rWQ@4iVKHCzwWA$07MjQCI@vG3MWb*{sK z|MCj^D^tpePhH-Lv>2t!@v>=MVp(0yE$t0jQ@7`if7yGkHoP@tR=S($zF<7*Wn90t z>py;W=!!5km(XSWb~bh$jmAGsjhekJOkEB<4l)XMWiOj(*Pfzfz8wra$R43Y3=Ri- z1r!;AP(?r!d1w3nCE?oBIvVl8kZuhS`~ATaZXm>EUx)fbXmb^6Yk_$89pa7Y^SWA@ z!;nq&`0mC#UndsW=Wm|FAggl7`Wlm1Dgj=z+-%pkscSZhxqi0c*)}1Sgnh~DOPz#= zA=`&9(NWYhkS2nnH0j?AH)-P!7J!nPo{^Cn$h91ljJ`bY20uGuO|mjARKl$$B=+oW z&S&`(v`ZB2CC%Em0wQp0_=JrYSRy<_iTJ)O3w;A-k52Lasu?LG9oN>iR+ z%8G!gTAJp*N-48GbA~?YseWzDaOcjsrLl4)@7WU}n3FbJGY0RgGFy}6+=(krx4ik{ z`b`e&7JPhRcoOd^@&vr)eK&t?jH? zdN`JT5mkKLg~JURU+!Z(o2I0+El#6B&n&%ePbs8O!t2_<>fY~Au>}a=jc^Z5qlwWh zi2|9Tn69h!^{>1bf#{tgvC(KpYT}G1S3j0c9mm+^!2bYf3VlUr5qTizHIMQv{~o~p z>ewl*fpThtFB^d7pmAhG{~+F$1(X-a&_Ny_S|oP8bJF;S5KW=J_QCgL*muR2#sH5_7l1S6|!v>eU8AYl5^RKpufn7^IgCIwq4Pd$$3ml!_ z{N!)<=|Sm15b|f=90uw+5OYq^UHze*lPcP}U-cuXhJw!t<5K9+fiR13Vkb&KyDW!{ zckAt$98k~Ha=s34`T6N(i$P3(>2yVXhHueme!Z`u)ohw%F}78rXCgDeUW|uZ(q_di zT%fM(P+=Io*Jrie0L z?Ua*JNIhua95G(!J>rZ3tSQ#evn+Ar*hdE}b@o~iTei$@4Po$1?BT}am(}NbGx~xp zgGpL5W7vxN9M&0Q6iKKN7n;|)G}`1YQ}ffk*&TJT{2I1`{tAkkc*HR1%4;3B{+_Q$UHWX=1A|Dlv#ifEmIVH08~QnWkU14G3F+wymkS_oyWydGjvGyC z@>23@R z+Q1y-)}m2`gmkM3*0#;a)nx14A!B3B2`n4_Aw9A4a_RQ~_}b7$_lYNisw6lArhh`gByd_>OOMB0rr`1YGt2$hd?+#vYzt$yQ<0?kQF%aCh?D1I* znY|XGDnucEEjm$~{h{%C^TJBX?(Xirz%X(Amyjs}$Em%?-i0v?42f#+81)hPL3qRA z>ia>Aqd4HLMQ^_}wLrpZL4kqP?kA})s=P(^zY>$GouJdB)%koDMI`n*RTVCz{|G*; zY{q#%w8|C7FR0P>K8s?d?e)ET__-!62rMiVP^s(8^UZ4fX0=KMZrdK1Ihn=@dz%^s zh|@VBC%_NuU$yAgL8l>2^X~~6NR_4p-qAPA5-6sd2nJ4BXh^KClyAf?<9IWR*EJ#rCk8!&$324SC%#H}JiLF|W`%7(FZ6*Y zd!5_fMg>~OI&SZ%M5-3*kiPjmeQn;|Am)s;nNqYxSCY|d@}yHWA|g4{`EPogj#XCd ze=B@#7N%=2S;kt)n7}B;c6KJYes_-%aca8C^xMOYPPQfi%*Ng{BVzrD*X&D9_Hj|Y zp`qS}H4QCzB?j|)catppepH&I(=lehe6!gpdaq5B-3JTiw^m{M%Pv1AgUZw23IPxt zFi`%@CvjkH_k8!$&gV{DI5+cA)e{ygU*x69j7d_Yu1l&2_w^Kz5^jFX^b+7JZTagO z3(}mhko-Fud?;%6XhC?tr(k%nTb2Xdf>h*R zSKjN7?;Yz%=d=f5Ugugbvd9B!AJHgV=A++zFor=ac+wu`!r;F>N4k5GcZ}=IKpWppLXZN<* z%=-jA4PDyg44Xyk3S(*k`Ce3j7hc5En+;W3%^>8wIXNS@w~XWKM@NW9%*LxdvDp7a z9AO!w>73{!Ko4iE5a&2P@>xXaTCU7JA7bP~p z)~-$kOWr-yqEw3CqPD5RMmf2h zw==nsaaV}H`MLX*c$pP`BX&JI4ccI zTz`SWzOq<#&jjBhZ-cmAM{@=<3I`YV=fVOsVC+E#;%d#dcO+l`WyR^>t0-s9P8!C`If!+(I z)jECz!E?&FVNwh5<$kF(s;~**5X`tQ;$^!xE7%q$mYq#x32rB5kElpIE~y zlqRGa<7KX1cHDuvzl@f?0IbQnp4&JRBF*u1s<@fkH%xiTO zAjJbcJMTR9`=g2(BJn?8F+&rsQ{lx-k4B3~%2E(kBetD*lJjbe%nfZ8m&WpaJo}zL z_62I=G#S_lFjazoJynulDj6@~R&Sx{Tjq8Ep@FgNa{$D{Cayj!XW3Rv0{_5dEv%3& zb{z;()R!NV&UfFmAMN8zcf(7rjCl9`?TRUVY%sM(tM?AE zQg|4~Zjx?Xmy)=_nm|GxvBhn=t7%-ThVUTNwP+b^Xi>|-Wr9637#y8nOOhV6lop~6b^WJVxoZ4PQ z5<4fmfveXS|B}l!)$7%#w`=?N>K2Q*M#77`gcTkZ&$9v3nBEV&(?i!D&W9xyVz*VBwQ^jYAWw+NXx);{ zunxbkWx#rBA$Kh0M40)YWwU3SOI=*dfEC@qxtQ^4ew0tmdfYZ5mOi)w;1iF<`nl>w zbdLQqGde*~#_WXlbZ)88GcOT_`<2$TA-5qHIiV3=cdK^G#ztT_Wa!(P5d{#X)?O1| zH}O=#M{}@ocISDeCTm_3Q@@B5VRTD>uyl<5n;z>GlT{_p&vgR>--w9z zp}$<$yku1P^cGV7wt;@T>bjRVx% zP^QxGlUtfoOGr#^DpQTcsikf7nT0yvB2O`no27MgVx=`jDt3%_Y6SR4)pTe^ikVRB zxejdj+E#|a5d}AEEx77XVV9Qx&kK9cDE1UFF6~6xRv4HVQ~TtHT=9>hrW(Ak_z`z3 zb?@Q{KhOPH4gt?Q$slPc7VxRpEhveUUbj+Zpz<25~!= zx#UTYxL)E$MIA>qgiROw&ypH&;fAJvjphT?;gZqEW>;NR$d?dbcreIW zS}{8$CrL6;y%8mM3^ncJqsMNdMFRN7XHk42_ZDFu_>tq`m?w@N>uIzTrN-h;-pdZ9 zb{_g`Dy+6|mI=81DlX41UhfxdkSbQXOd)+f-Z?hW^ypZQ`gklQao>v9Af+~Nc98_; zScB@Vm9K*dH!rzcmSkFWs>6L20&YD6r6@)wlr_f0z{Gsgzf5VHnk868?!UFAkaYY) z=f^O4M2Yluvy^VXMRCU!`XlIS;&2JuJR;GnR z*tfZ_7vifqk$ef`Rx4~p7t*dOD@wzR)oes&ugzICHcHw3L#eofDqTWT6bWph1u!;Ebgk-Y>3lA{S@h#KL{va$$TT3rhZ3mJBptLeYau-#yV z(IC+mhj!xx(eGmU`@GT7Ib@{NT>8&wn}^RO2!>a4AwxiElE{wT@P<)bjPkKrKE?H& zR*6JKVsxJ(M^-HdkI`ILR)GZmtWwTe%gPzWp&frl5T!aAJUV`}XLEn|4fmX9WASc# z#efiZlwEk%lh7{!$&$D7RmQV0v58< zT{ashE?L7UitkhWLLXUtDHl)*xC*?k_1pK1jBHykU!{<0>S#CU*YJ+35Z~UX;PK4~ z`Km~rIJU>-{ZXpRv$Ov{#t(o%*LmjZ#|blra%I2=QpBI^H8pXc?6F7Eo?sXc%C9A} z{3p^N8A3jV$7d~)lvdU^mP!{_B^HQ`LO)v7Z6UGIEh%CR#67H~TPzBKF&xqy;k@2iFxft$E}-k zgpv~zM$N@F;Jzhyk1u&GWV}#$br$jR11K*U*4rQ(wXpPlK87`;C*(m-ytZLRQe$t- zVtgJE@$V}vf^B16e@6fO&sORC#!t*32jucVO}-%uc%{P9W67jPsuG1BB}@I4O7+dF z83&@k3N4+OWE~o32(QuCYitEd^nM*ED6J2wa+TZ-TNGaGXetP%Qk&ZsNowgSxu!qf zc(!(TBXyz9wPa5k-!K>fLPHz;26?<3zMr3y-if=s(BkXmn5-8>jtV5Fr@i-U#0LiS z@}>w(;c~d zzzvlN`LOZtj1VW(RoOMg^KSB7e8x%=gZJ$k+A*3aH@PN{jUC!q((5I9&hyA*BCja& zT#y==jtU{4=adep#xXMl&k`uMZ3$a11$n%9wL^~Q*;67TQ(LT=C#+4W(FXEZXBztYf(|@A%XMC2_mmLvm@i*+ zE5c%_F0S?ZrQx<0Apo0wc9E<-Nkwc>KTT=W6Z5J`n2@&z2=LlGL~2f?onEB;!bsoW zWt?LeKPbDPDa!pNngb*Uc~b@lOqN$(Zij&MqaoimHD@Y)Tl8Yr8y?HtuF_9msty_}k2Zd0P|98#8~K=%m3{pb;arfn$~w;4U^B!3Na|B(T*dr54xy|I zBX_GTr^an3#M6YhQ27D8w>^rx zG$f@axhRusBf{wZAi&EQZGIZ3xGO%xS
RXFlFii3CMxs$g7Zc@LM2c-h~wc~@j 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 literal 0 HcmV?d00001 diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpData/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpData/application.properties new file mode 100644 index 000000000..2bb38b038 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpData/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=cmpData/flow.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpData/flow.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpData/flow.xml new file mode 100644 index 000000000..e5328cddc --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpData/flow.xml @@ -0,0 +1,14 @@ + + + + sql = "select * from member t + where t.id=10001"; + cmpData = '{"name":"jack","age":27,"birth":"1995-10-01"}'; + + THEN( + a.data(sql), + b.data(cmpData), + c + ); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpRetry/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpRetry/application.properties new file mode 100644 index 000000000..9dc00f45e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpRetry/application.properties @@ -0,0 +1,3 @@ +liteflow.rule-source=cmpRetry/flow.el.xml +liteflow.retry-count=3 +liteflow.slot-size=512 \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpRetry/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpRetry/flow.el.xml new file mode 100644 index 000000000..3aea68da5 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpRetry/flow.el.xml @@ -0,0 +1,18 @@ + + + + THEN(a, b); + + + + THEN(c); + + + + THEN(d); + + + + THEN(e); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpStep/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpStep/application.properties new file mode 100644 index 000000000..7c7eabe1b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpStep/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=cmpStep/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpStep/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpStep/flow.el.xml new file mode 100644 index 000000000..e4a1e577a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/cmpStep/flow.el.xml @@ -0,0 +1,14 @@ + + + + THEN(a.tag("A"), b.tag("B"), WHEN(c.tag("C"), d.tag("D"))); + + + + THEN(WHEN(e, a).any(true), b); + + + + THEN(a.tag("a1"), b, a.tag("a2"), a.tag("a3"), b); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/comments/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/comments/application.properties new file mode 100644 index 000000000..83a0815d2 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/comments/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=comments/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/comments/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/comments/flow.el.xml new file mode 100644 index 000000000..e4aecb451 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/comments/flow.el.xml @@ -0,0 +1,18 @@ + + + + // 单行注释 + THEN( + // 单行注释 + a, + b, + WHEN( + /** + * 多行注释 + **/ + c, + b + ) + ); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/complex/application1.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/complex/application1.properties new file mode 100644 index 000000000..8375bd39a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/complex/application1.properties @@ -0,0 +1 @@ +liteflow.rule-source=complex/flow1.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/complex/application2.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/complex/application2.properties new file mode 100644 index 000000000..9485d5aaa --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/complex/application2.properties @@ -0,0 +1 @@ +liteflow.rule-source=complex/flow2.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/complex/flow1.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/complex/flow1.el.xml new file mode 100644 index 000000000..8c7e721ec --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/complex/flow1.el.xml @@ -0,0 +1,34 @@ + + + + THEN( + A, + WHEN( + THEN(B, C), + THEN(D, E, F), + THEN( + SWITCH(G).to( + THEN(H, I, WHEN(J, K)).id("t1"), + THEN(L, M).id("t2") + ), + N + ) + ), + Z + ); + + + + item1 = THEN(B, C); + item2 = THEN(D, E, F); + item3_1 = THEN(H, I, WHEN(J, K)).id("t1"); + item3_2 = THEN(L, M).id("t2"); + item3 = THEN(SWITCH(G).to(item3_1, item3_2), N); + + THEN( + A, + WHEN(item1, item2, item3), + Z + ); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/complex/flow2.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/complex/flow2.el.xml new file mode 100644 index 000000000..cdeebfff6 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/complex/flow2.el.xml @@ -0,0 +1,44 @@ + + + + THEN( + A, + SWITCH(B).to( + THEN(D, E, F).id("t1"), + THEN( + C, + WHEN( + THEN( + SWITCH(G).to(THEN(H, I).id("t2"), J), + K + ), + THEN(L, M) + ) + ).id("t3") + ), + Z + ); + + + + item1 = THEN(D, E, F).id("t1"); + + item2_1 = THEN( + SWITCH(G).to( + THEN(H, I).id("t2"), + J + ), + K + ); + + item2_2 = THEN(L, M); + + item2 = THEN(C, WHEN(item2_1, item2_2)).id("t3"); + + THEN( + A, + SWITCH(B).to(item1, item2), + Z + ); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/component/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/component/application.properties new file mode 100644 index 000000000..f353e04e7 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/component/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=component/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/component/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/component/flow.el.xml new file mode 100644 index 000000000..6f2261684 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/component/flow.el.xml @@ -0,0 +1,30 @@ + + + + THEN(a); + + + + THEN(b); + + + + THEN(c); + + + + THEN(a, d, c); + + + + THEN(a, e, c); + + + + SWITCH(f).to(d, c, b); + + + + THEN(g, h); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/customNodes/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/customNodes/application.properties new file mode 100644 index 000000000..07a0213a4 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/customNodes/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=customNodes/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/customNodes/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/customNodes/flow.el.xml new file mode 100644 index 000000000..58ca6778f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/customNodes/flow.el.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + WHEN(a, b, c); + + + + WHEN(d, e, f); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/customWhenThreadPool/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/customWhenThreadPool/application.properties new file mode 100644 index 000000000..57f18618a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/customWhenThreadPool/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=customWhenThreadPool/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/customWhenThreadPool/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/customWhenThreadPool/flow.el.xml new file mode 100644 index 000000000..048cdff97 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/customWhenThreadPool/flow.el.xml @@ -0,0 +1,12 @@ + + + + WHEN(a, b); + + + WHEN(c, d).threadPool("com.yomahub.liteflow.test.customWhenThreadPool.CustomThreadExecutor1"); + + + WHEN(e, f).threadPool("com.yomahub.liteflow.test.customWhenThreadPool.CustomThreadExecutor1"); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/event/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/event/application.properties new file mode 100644 index 000000000..a2f4251d8 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/event/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=event/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/event/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/event/flow.el.xml new file mode 100644 index 000000000..310346b4e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/event/flow.el.xml @@ -0,0 +1,14 @@ + + + + THEN(a, b, c); + + + + THEN(a, b, d); + + + + THEN(a, e, b); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/exception/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/exception/application.properties new file mode 100644 index 000000000..63d6aa6ca --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/exception/application.properties @@ -0,0 +1,2 @@ +liteflow.rule-source=exception/flow.el.xml +liteflow.when-max-wait-seconds=1 \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/exception/flow-blank.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/exception/flow-blank.el.xml new file mode 100644 index 000000000..3f0ad68e5 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/exception/flow-blank.el.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/exception/flow-exception.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/exception/flow-exception.el.xml new file mode 100644 index 000000000..f88a6f727 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/exception/flow-exception.el.xml @@ -0,0 +1,12 @@ + + + + THEN(a, b, c); + + + + THEN(a, b, c); + + + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/exception/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/exception/flow.el.xml new file mode 100644 index 000000000..255a8b8d0 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/exception/flow.el.xml @@ -0,0 +1,23 @@ + + + + THEN(a, b, c); + + + + THEN(a, WHEN(b, c).ignoreError(false)); + + + + THEN(c, d); + + + + SWITCH(e).to(b, c); + + + + THEN(f, g); + + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/execute2Future/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/execute2Future/application.properties new file mode 100644 index 000000000..21b2b3fa5 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/execute2Future/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=execute2Future/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/execute2Future/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/execute2Future/flow.el.xml new file mode 100644 index 000000000..47cf69680 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/execute2Future/flow.el.xml @@ -0,0 +1,7 @@ + + + + THEN(a, b, WHEN(c, d)); + + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/getChainName/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/getChainName/application.properties new file mode 100644 index 000000000..14cfce7c5 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/getChainName/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=getChainName/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/getChainName/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/getChainName/flow.el.xml new file mode 100644 index 000000000..6c033d839 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/getChainName/flow.el.xml @@ -0,0 +1,38 @@ + + + + WHEN(sub1, sub2, sub3, sub4); + + + + THEN(a); + + + + THEN(b); + + + + THEN(c); + + + + THEN(d); + + + + THEN(e, f); + + + + SWITCH(h).to(j, k); + + + + THEN( + g, + WHEN(sub1, WHEN(sub2, sub3)), + sub4, sub5, e, sub6 + ); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/ifelse/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/ifelse/application.properties new file mode 100644 index 000000000..efbbddb30 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/ifelse/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=ifelse/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/ifelse/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/ifelse/flow.el.xml new file mode 100644 index 000000000..b2a805b0c --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/ifelse/flow.el.xml @@ -0,0 +1,41 @@ + + + + IF(x1.tag("true"), THEN(a, b)); + + + + IF(x1.tag("false"), THEN(a, b), THEN(c, d)); + + + + item_inner = THEN(c,c,b); + item = IF(x1.tag("false"), a, item_inner); + IF( + x1.tag("false"), + a, + item + ); + + + + IF(x1.tag("false"), THEN(a, b)).ELSE(THEN(c, d)); + + + + item = IF(x1.tag("false"), a, THEN(c, c, b)); + + IF(x1.tag("false"), THEN(a, b)).ELSE(item); + + + + IF(x1.tag("false"), THEN(a, b)).ELIF(x1.tag("true"), THEN(c, c)).ELSE(d); + + + + IF(x1.tag("false"), a).ELIF(x1.tag("false"), b) + .ELIF(x1.tag("false"), c) + .ELIF(x1.tag("false"), d) + .ELSE(THEN(d, b, a)); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/lazy/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/lazy/application.properties new file mode 100644 index 000000000..50e059c5e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/lazy/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=lazy/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/lazy/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/lazy/flow.el.xml new file mode 100644 index 000000000..049210cf4 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/lazy/flow.el.xml @@ -0,0 +1,6 @@ + + + + THEN(a, b, c); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/lfCmpAnno/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/lfCmpAnno/application.properties new file mode 100644 index 000000000..0bc99b5a3 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/lfCmpAnno/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=lfCmpAnno/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/lfCmpAnno/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/lfCmpAnno/flow.el.xml new file mode 100644 index 000000000..872026cf1 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/lfCmpAnno/flow.el.xml @@ -0,0 +1,6 @@ + + + + THEN(a, b, THEN(c, b, a, d)); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/loop/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/loop/application.properties new file mode 100644 index 000000000..7189d4569 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/loop/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=loop/flow.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/loop/flow.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/loop/flow.xml new file mode 100644 index 000000000..7bb3b9280 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/loop/flow.xml @@ -0,0 +1,42 @@ + + + + FOR(2).DO(THEN(a,b,c)); + + + + FOR(x).DO(THEN(a,b,c)); + + + + FOR(10).DO(THEN(a,b,d)).BREAK(y); + + + + WHILE(z).DO(THEN(a,d)); + + + + WHILE(z).DO(THEN(a,d)).BREAK(y); + + + + FOR(5).DO( + WHEN( + THEN(a,e.tag("e1")), + THEN(c,e.tag("e2")), + THEN(b,e.tag("e3")) + ) + ); + + + + WHILE(z).DO( + WHEN( + THEN(d, e.tag("e1")), + THEN(a, e.tag("e2")), + THEN(c, e.tag("e3")) + ) + ); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/monitor/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/monitor/application.properties new file mode 100644 index 000000000..42c3065ef --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/monitor/application.properties @@ -0,0 +1,5 @@ +liteflow.rule-source=monitor/flow.el.xml +liteflow.monitor.enable-log=true +liteflow.monitor.queue-limit=200 +liteflow.monitor.delay=5000 +liteflow.monitor.period=5000 \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/monitor/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/monitor/flow.el.xml new file mode 100644 index 000000000..0cbf0f2ed --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/monitor/flow.el.xml @@ -0,0 +1,7 @@ + + + + THEN(a, WHEN(b, c)); + + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/multiContext/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/multiContext/application.properties new file mode 100644 index 000000000..cac2dda98 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/multiContext/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=multiContext/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/multiContext/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/multiContext/flow.el.xml new file mode 100644 index 000000000..85e5ecf43 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/multiContext/flow.el.xml @@ -0,0 +1,10 @@ + + + + THEN(a, b, WHEN(c, d)); + + + + THEN(e, f); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/multipleType/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/multipleType/application.properties new file mode 100644 index 000000000..8f9ac4539 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/multipleType/application.properties @@ -0,0 +1,2 @@ +liteflow.support-multiple-type=true +liteflow.rule-source=multipleType/flow.el.xml,multipleType/flow.el.yml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/multipleType/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/multipleType/flow.el.xml new file mode 100644 index 000000000..e57552e35 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/multipleType/flow.el.xml @@ -0,0 +1,6 @@ + + + + THEN(a, b, THEN(c, b, a)); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/multipleType/flow.el.yml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/multipleType/flow.el.yml new file mode 100644 index 000000000..34946d48b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/multipleType/flow.el.yml @@ -0,0 +1,4 @@ +flow: + chain: + - name: chain3 + value: "THEN(a, b, c);" diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/nodeExecutor/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/nodeExecutor/application.properties new file mode 100644 index 000000000..6a26de74b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/nodeExecutor/application.properties @@ -0,0 +1,4 @@ +liteflow.rule-source=nodeExecutor/flow.el.xml +liteflow.retry-count=3 +liteflow.slot-size=512 +liteflow.node-executor-class=com.yomahub.liteflow.test.nodeExecutor.CustomerDefaultNodeExecutor \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/nodeExecutor/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/nodeExecutor/flow.el.xml new file mode 100644 index 000000000..a92b50eb7 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/nodeExecutor/flow.el.xml @@ -0,0 +1,18 @@ + + + + THEN(a); + + + + THEN(b); + + + + THEN(c); + + + + THEN(d); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/nullParam/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/nullParam/application.properties new file mode 100644 index 000000000..a52633f8c --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/nullParam/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=nullParam/flow.el.xml diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/nullParam/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/nullParam/flow.el.xml new file mode 100644 index 000000000..b12156bd1 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/nullParam/flow.el.xml @@ -0,0 +1,6 @@ + + + + THEN(a, b, WHEN(c)); + + diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parsecustom/application-custom-json.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parsecustom/application-custom-json.properties new file mode 100644 index 000000000..27607f630 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parsecustom/application-custom-json.properties @@ -0,0 +1 @@ +liteflow.rule-source=el_json:com.yomahub.liteflow.test.parsecustom.parser.CustomJsonFlowParser \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parsecustom/application-custom-xml.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parsecustom/application-custom-xml.properties new file mode 100644 index 000000000..cd30a8f09 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parsecustom/application-custom-xml.properties @@ -0,0 +1 @@ +liteflow.rule-source=el_xml:com.yomahub.liteflow.test.parsecustom.parser.CustomXmlFlowParser \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parsecustom/application-custom-yml.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parsecustom/application-custom-yml.properties new file mode 100644 index 000000000..c8e50b4f1 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parsecustom/application-custom-yml.properties @@ -0,0 +1 @@ +liteflow.rule-source=el_yml:com.yomahub.liteflow.test.parsecustom.parser.CustomYmlFlowParser \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/application-json.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/application-json.properties new file mode 100644 index 000000000..89b7d642b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/application-json.properties @@ -0,0 +1 @@ +liteflow.rule-source=parser/flow.el.json \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/application-springEL.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/application-springEL.properties new file mode 100644 index 000000000..2175bdfaf --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/application-springEL.properties @@ -0,0 +1 @@ +liteflow.rule-source=parser/**/*.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/application-xml.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/application-xml.properties new file mode 100644 index 000000000..c0b83943a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/application-xml.properties @@ -0,0 +1 @@ +liteflow.rule-source=parser/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/application-yml.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/application-yml.properties new file mode 100644 index 000000000..233b9f810 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/application-yml.properties @@ -0,0 +1 @@ +liteflow.rule-source=parser/flow.el.yml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/flow.el.json b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/flow.el.json new file mode 100644 index 000000000..ffb87b5e3 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/flow.el.json @@ -0,0 +1,46 @@ +{ + "flow": { + "nodes": { + "node": [ + { + "id": "a", + "class": "com.yomahub.liteflow.test.parser.cmp.ACmp" + }, + { + "id": "b", + "class": "com.yomahub.liteflow.test.parser.cmp.BCmp" + }, + { + "id": "c", + "class": "com.yomahub.liteflow.test.parser.cmp.CCmp" + }, + { + "id": "d", + "class": "com.yomahub.liteflow.test.parser.cmp.DCmp" + }, + { + "id": "e", + "class": "com.yomahub.liteflow.test.parser.cmp.ECmp" + }, + { + "id": "f", + "class": "com.yomahub.liteflow.test.parser.cmp.FCmp" + }, + { + "id": "g", + "class": "com.yomahub.liteflow.test.parser.cmp.GCmp" + } + ] + }, + "chain": [ + { + "name": "chain2", + "value": "THEN(c,g,f);" + }, + { + "name": "chain1", + "value": "THEN(a,c,WHEN(b,d,SWITCH(e).to(f,g)), chain2);" + } + ] + } +} \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/flow.el.xml new file mode 100644 index 000000000..1e3bc2989 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/flow.el.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + THEN(a, c, WHEN(b, d, SWITCH(e).to(f,g)), chain2); + + + + THEN(c, g, f); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/flow.el.yml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/flow.el.yml new file mode 100644 index 000000000..d84d0acb9 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/flow.el.yml @@ -0,0 +1,22 @@ +flow: + nodes: + node: + - id: a + class: com.yomahub.liteflow.test.parser.cmp.ACmp + - id: b + class: com.yomahub.liteflow.test.parser.cmp.BCmp + - id: c + class: com.yomahub.liteflow.test.parser.cmp.CCmp + - id: d + class: com.yomahub.liteflow.test.parser.cmp.DCmp + - id: e + class: com.yomahub.liteflow.test.parser.cmp.ECmp + - id: f + class: com.yomahub.liteflow.test.parser.cmp.FCmp + - id: g + class: com.yomahub.liteflow.test.parser.cmp.GCmp + chain: + - name: chain1 + value: "THEN(a, c, WHEN(b, d, SWITCH(e).to(f, g)), chain2);" + - name: chain2 + value: "THEN(c, g, f);" diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/subFoder1/subFoder2/flow1.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/subFoder1/subFoder2/flow1.el.xml new file mode 100644 index 000000000..ae66b3c19 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/subFoder1/subFoder2/flow1.el.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + THEN(a, c, WHEN(b, d, SWITCH(e).to(f,g)), chain2) + + + + THEN(c, g, f) + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/subFoder1/subFoder2/flow2.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/subFoder1/subFoder2/flow2.el.xml new file mode 100644 index 000000000..fa15c1865 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/subFoder1/subFoder2/flow2.el.xml @@ -0,0 +1,7 @@ + + + + + THEN(a, c, WHEN(b, d, SWITCH(e).to(f, g)), chain2) + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/subFoder1/subFoder2/flow3.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/subFoder1/subFoder2/flow3.el.xml new file mode 100644 index 000000000..6d5223279 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/parser/subFoder1/subFoder2/flow3.el.xml @@ -0,0 +1,6 @@ + + + + THEN(c, g, f) + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/preAndFinally/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/preAndFinally/application.properties new file mode 100644 index 000000000..b7c8f05df --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/preAndFinally/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=preAndFinally/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/preAndFinally/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/preAndFinally/flow.el.xml new file mode 100644 index 000000000..4d7fcfe53 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/preAndFinally/flow.el.xml @@ -0,0 +1,31 @@ + + + + THEN(PRE(p1, p2), THEN(a, b, c), FINALLY(f1, f2)); + + + + THEN(a, PRE(p1, p2), FINALLY(f1, f2), THEN(b, c)); + + + + THEN(PRE(p1, p2), THEN(a, d, c), FINALLY(f1, f2)); + + + + THEN(a, d, c, FINALLY(f3)); + + + + THEN(PRE(p1, p2), chain1, FINALLY(f1)); + + + + c1 = THEN(PRE(p1, p2), THEN(a, b, c), FINALLY(f1, f2)); + THEN(PRE(p1, p2), c1, FINALLY(f1)); + + + + THEN(a, b, THEN(PRE(p1), FINALLY(f1), c), PRE(p2), FINALLY(f2)); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/privateDelivery/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/privateDelivery/application.properties new file mode 100644 index 000000000..7c19a9c06 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/privateDelivery/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=privateDelivery/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/privateDelivery/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/privateDelivery/flow.el.xml new file mode 100644 index 000000000..6458ae5bd --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/privateDelivery/flow.el.xml @@ -0,0 +1,21 @@ + + + + THEN( + a, + WHEN( + b,b,b,b,b,b,b,b,b,b, + b,b,b,b,b,b,b,b,b,b, + b,b,b,b,b,b,b,b,b,b, + b,b,b,b,b,b,b,b,b,b, + b,b,b,b,b,b,b,b,b,b, + b,b,b,b,b,b,b,b,b,b, + b,b,b,b,b,b,b,b,b,b, + b,b,b,b,b,b,b,b,b,b, + b,b,b,b,b,b,b,b,b,b, + b,b,b,b,b,b,b,b,b,b + ), + c + ); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/refreshRule/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/refreshRule/application.properties new file mode 100644 index 000000000..d9ce5b748 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/refreshRule/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=refreshRule/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/refreshRule/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/refreshRule/flow.el.xml new file mode 100644 index 000000000..049210cf4 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/refreshRule/flow.el.xml @@ -0,0 +1,6 @@ + + + + THEN(a, b, c); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/refreshRule/flow_update.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/refreshRule/flow_update.el.xml new file mode 100644 index 000000000..5333b7e2d --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/refreshRule/flow_update.el.xml @@ -0,0 +1,6 @@ + + + + THEN(c, b, a); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/reload/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/reload/application.properties new file mode 100644 index 000000000..cdde88c73 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/reload/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=reload/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/reload/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/reload/flow.el.xml new file mode 100644 index 000000000..049210cf4 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/reload/flow.el.xml @@ -0,0 +1,6 @@ + + + + THEN(a, b, c); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/removeChain/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/removeChain/application.properties new file mode 100644 index 000000000..3c8c78694 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/removeChain/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=removeChain/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/removeChain/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/removeChain/flow.el.xml new file mode 100644 index 000000000..a18cec10a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/removeChain/flow.el.xml @@ -0,0 +1,10 @@ + + + + THEN(a, b, WHEN(c, d)); + + + + THEN(a, b, c, d); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/requestId/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/requestId/application.properties new file mode 100644 index 000000000..601cc9417 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/requestId/application.properties @@ -0,0 +1,2 @@ +liteflow.rule-source=requestId/flow.el.xml +liteflow.request-id-generator-class=com.yomahub.liteflow.test.requestId.config.CustomRequestIdGenerator \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/requestId/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/requestId/flow.el.xml new file mode 100644 index 000000000..3f1a585ab --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/requestId/flow.el.xml @@ -0,0 +1,6 @@ + + + + THEN(a, b); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-implicit.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-implicit.properties new file mode 100644 index 000000000..424d7cb10 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-implicit.properties @@ -0,0 +1 @@ +liteflow.rule-source=subflow/flow-implicit.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-json.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-json.properties new file mode 100644 index 000000000..4a247cadf --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-json.properties @@ -0,0 +1 @@ +liteflow.rule-source=subflow/flow.el.json \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-subInDifferentConfig1.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-subInDifferentConfig1.properties new file mode 100644 index 000000000..9006564d9 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-subInDifferentConfig1.properties @@ -0,0 +1 @@ +liteflow.rule-source=subflow/flow-main.el.xml,subflow/flow-sub1.el.xml,subflow/flow-sub2.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-subInDifferentConfig2.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-subInDifferentConfig2.properties new file mode 100644 index 000000000..a0d247d83 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-subInDifferentConfig2.properties @@ -0,0 +1 @@ +liteflow.rule-source=subflow/flow-main.el.xml,subflow/flow-sub1.el.xml,subflow/flow-sub2.el.yml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-xml.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-xml.properties new file mode 100644 index 000000000..95b534046 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-xml.properties @@ -0,0 +1 @@ +liteflow.rule-source=subflow/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-yml.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-yml.properties new file mode 100644 index 000000000..3c2295809 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/application-yml.properties @@ -0,0 +1 @@ +liteflow.rule-source=subflow/flow.el.yml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow-implicit.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow-implicit.el.xml new file mode 100644 index 000000000..3974e2116 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow-implicit.el.xml @@ -0,0 +1,26 @@ + + + + THEN(f, g); + + + + THEN(h, m); + + + + THEN(p); + + + + THEN(q); + + + + THEN(r); + + + + THEN(s); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow-main.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow-main.el.xml new file mode 100644 index 000000000..0310bbf15 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow-main.el.xml @@ -0,0 +1,6 @@ + + + + THEN(a, b, chain2); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow-sub1.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow-sub1.el.xml new file mode 100644 index 000000000..829886d02 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow-sub1.el.xml @@ -0,0 +1,6 @@ + + + + THEN(b, a, chain3); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow-sub2.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow-sub2.el.xml new file mode 100644 index 000000000..63676b2b3 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow-sub2.el.xml @@ -0,0 +1,6 @@ + + + + THEN(e, d); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow-sub2.el.yml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow-sub2.el.yml new file mode 100644 index 000000000..3d652cf48 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow-sub2.el.yml @@ -0,0 +1,4 @@ +flow: + chain: + - name: chain3 + value: "THEN(e, d);" \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow.el.json b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow.el.json new file mode 100644 index 000000000..a92a77b90 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow.el.json @@ -0,0 +1,22 @@ +{ + "flow": { + "chain": [ + { + "name": "chain3", + "value": "THEN(e,d);" + }, + { + "name": "chain2", + "value": "THEN(b, a, chain3);" + }, + { + "name": "chain1", + "value": "THEN(a, b, c, chain2);" + }, + { + "name": "c", + "value": "THEN(d, e);" + } + ] + } +} \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow.el.xml new file mode 100644 index 000000000..dac14dbca --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow.el.xml @@ -0,0 +1,18 @@ + + + + THEN(a, b, c, chain2); + + + + THEN(d, e); + + + + THEN(b, a, chain3); + + + + THEN(e, d); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow.el.yml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow.el.yml new file mode 100644 index 000000000..cc8f056df --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/subflow/flow.el.yml @@ -0,0 +1,10 @@ +flow: + chain: + - name: chain3 + value: "THEN(e, d);" + - name: chain1 + value: "THEN(a, b, c, chain2);" + - name: c + value: "THEN(d, e);" + - name: chain2 + value: "THEN(b, a, chain3);" \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/substituteNode/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/substituteNode/application.properties new file mode 100644 index 000000000..35bdc3a1e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/substituteNode/application.properties @@ -0,0 +1,2 @@ +liteflow.rule-source=substituteNode/flow.el.xml +liteflow.substitute-cmp-class=com.yomahub.liteflow.test.substituteNode.cmp.SubCmp \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/substituteNode/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/substituteNode/flow.el.xml new file mode 100644 index 000000000..7730921b9 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/substituteNode/flow.el.xml @@ -0,0 +1,14 @@ + + + + THEN(node("a"), node("b"), node("c")); + + + + THEN(node("a"), node("b"), node("93-nodeTEST")); + + + + THEN(a, b, node("88-ffc")); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/switchcase/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/switchcase/application.properties new file mode 100644 index 000000000..25c6c15d8 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/switchcase/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=switchcase/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/switchcase/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/switchcase/flow.el.xml new file mode 100644 index 000000000..ee853dd0b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/switchcase/flow.el.xml @@ -0,0 +1,53 @@ + + + + THEN( + a, + SWITCH(e).to(d), + b + ); + + + + THEN( + a, + SWITCH(e).to(b, d) + ); + + + + THEN( + a, + SWITCH(f).to(b.tag("td"), d) + ); + + + + THEN( + a, + SWITCH(g).to(b.tag("td"), d.tag("td")) + ); + + + + THEN( + a, + SWITCH(h).to(b.tag("td"), d.tag("td")) + ); + + + + THEN( + a, + SWITCH(h).to(b.tag("td"), b.tag("xx")) + ); + + + + THEN( + a, + SWITCH(i).to(b, c).DEFAULT(d) + ); + + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/tag/application-json.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/tag/application-json.properties new file mode 100644 index 000000000..d85de7220 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/tag/application-json.properties @@ -0,0 +1 @@ +liteflow.rule-source=tag/flow.el.json \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/tag/application-xml.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/tag/application-xml.properties new file mode 100644 index 000000000..9f7c2b81e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/tag/application-xml.properties @@ -0,0 +1 @@ +liteflow.rule-source=tag/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/tag/flow.el.json b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/tag/flow.el.json new file mode 100644 index 000000000..cca9b2c58 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/tag/flow.el.json @@ -0,0 +1,22 @@ +{ + "flow": { + "chain": [ + { + "name": "chain1", + "value": "THEN(a.tag(\"1\"), a.tag(\"2\"), a.tag(\"3\"));" + }, + { + "name": "chain2", + "value": "THEN(a.tag(\"1\"), a.tag(\"2\"), a.tag(\"3\"), SWITCH(c.tag(\"2\")).to(d.tag(\"5\"), e.tag(\"6\")));" + }, + { + "name": "chain3", + "value": "THEN(b1, WHEN(b.tag(\"1\"), b.tag(\"2\"), b.tag(\"3\")));" + }, + { + "name": "chain4", + "value": "THEN(f.tag(\"false\"), g);" + } + ] + } +} \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/tag/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/tag/flow.el.xml new file mode 100644 index 000000000..f6a02ef81 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/tag/flow.el.xml @@ -0,0 +1,22 @@ + + + + THEN(a.tag("1"), a.tag("2"), a.tag("3")); + + + + THEN(a.tag("1"), a.tag("2"), a.tag("3"), SWITCH(c.tag("2")).to(d.tag("5"), e.tag("6"))); + + + + THEN(b1, WHEN(b.tag("1"), b.tag("2"), b.tag("3"))); + + + + THEN(f.tag("false"), g); + + + + WHEN(h.tag("1")); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/useTTLInWhen/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/useTTLInWhen/application.properties new file mode 100644 index 000000000..ba675ca9b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/useTTLInWhen/application.properties @@ -0,0 +1,2 @@ +liteflow.rule-source=useTTLInWhen/flow.el.xml +liteflow.when-max-workers=2 \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/useTTLInWhen/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/useTTLInWhen/flow.el.xml new file mode 100644 index 000000000..736d9e72d --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/useTTLInWhen/flow.el.xml @@ -0,0 +1,6 @@ + + + + THEN(a, WHEN(b, c, d, e, f)); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/whenTimeOut/application1.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/whenTimeOut/application1.properties new file mode 100644 index 000000000..1c75edbd0 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/whenTimeOut/application1.properties @@ -0,0 +1,2 @@ +liteflow.rule-source=whenTimeOut/flow1.el.xml +liteflow.when-max-wait-seconds=3 \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/whenTimeOut/application2.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/whenTimeOut/application2.properties new file mode 100644 index 000000000..2d4ea8b30 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/whenTimeOut/application2.properties @@ -0,0 +1,2 @@ +liteflow.rule-source=whenTimeOut/flow2.el.xml +liteflow.when-max-wait-seconds=5 \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/whenTimeOut/flow1.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/whenTimeOut/flow1.el.xml new file mode 100644 index 000000000..85378915f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/whenTimeOut/flow1.el.xml @@ -0,0 +1,6 @@ + + + + WHEN(a, b, c); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/whenTimeOut/flow2.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/whenTimeOut/flow2.el.xml new file mode 100644 index 000000000..641ed9faf --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/whenTimeOut/flow2.el.xml @@ -0,0 +1,6 @@ + + + + THEN(WHEN(d), WHEN(e), WHEN(f)); + + \ No newline at end of file