/Flower.Processing.Tests/ProcessBuilderTests.cs

http://flower.codeplex.com · C# · 1535 lines · 1402 code · 118 blank · 15 comment · 19 complexity · ae7023b4f24a66df756d41a420e97d35 MD5 · raw file

Large files are truncated click here to view the full file

  1. /*
  2. Copyright 2012 Dmitry Bratus
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. using System;
  14. using System.Collections.Generic;
  15. using System.Linq;
  16. using System.Runtime.Serialization;
  17. using System.Text;
  18. using System.Threading;
  19. using Flower.Client;
  20. using Flower.Directory.Host.Default;
  21. using Flower.Directory.Management;
  22. using Flower.Logging;
  23. using Flower.Services;
  24. using Flower.Services.Data;
  25. using Flower.Testing;
  26. using NUnit.Framework;
  27. using Flower.Workflow;
  28. using Flower.Processing.Interruptions;
  29. using SortOrder = Flower.Workflow.SortOrder;
  30. using Flower.Directory.Util;
  31. using Flower.Directory.Host;
  32. using Spring.Context.Support;
  33. using Spring.Context;
  34. using System.Threading.Tasks;
  35. #pragma warning disable 0649
  36. namespace Flower.Processing.Tests
  37. {
  38. [TestFixture]
  39. public class ProcessBuilderTests
  40. {
  41. private static readonly Log Log = LogManager.CreateLog(typeof(ProcessBuilderTests).Name);
  42. private IApplicationContext _appContext;
  43. private const int POS1 = 1;
  44. private const int POS2 = 1 << 1;
  45. private const int POS3 = 1 << 2;
  46. private const int POS4 = 1 << 3;
  47. private const int POS5 = 1 << 4;
  48. private const int POS6 = 1 << 5;
  49. private const int POS7 = 1 << 6;
  50. private const int POS8 = 1 << 7;
  51. private const int POS9 = 1 << 8;
  52. private const int POS10 = 1 << 9;
  53. #region Setup
  54. public IDirectory CreateDirectory()
  55. {
  56. var dir = (IDirectory)_appContext.GetObject("directory");
  57. return dir;
  58. }
  59. private class Service
  60. {
  61. public int ReturnOne() { return 1; }
  62. }
  63. private IFlowerClient _flowerClient;
  64. [TestFixtureSetUp]
  65. public void Setup()
  66. {
  67. _appContext = new XmlApplicationContext("Flower.Directory.Host.config");
  68. _flowerClient = new FlowerClient(CreateDirectory());
  69. }
  70. [TestFixtureTearDown]
  71. public void TearDown()
  72. {
  73. _flowerClient.Dispose();
  74. }
  75. #endregion
  76. #region If
  77. [DataContract]
  78. private class IfProcess : Workflow.Process, IProcessDefinition
  79. {
  80. public bool Cond;
  81. public int Pos1;
  82. public int Pos2;
  83. public int Pos3;
  84. public void DefineProcess(IProcessBuilder bld)
  85. {
  86. bld
  87. .Exec(_ => { Pos1 = POS1; })
  88. .If(_ => Cond)
  89. .Exec(_ => { Pos2 = POS2; })
  90. .End()
  91. .Exec(_ => { Pos3 = POS3; });
  92. }
  93. public void DefineLocalSets(ISetsBuilder bld)
  94. {
  95. }
  96. }
  97. [Test]
  98. public void If()
  99. {
  100. var prc = new Processor("Test", _flowerClient);
  101. var proc = new IfProcess { Cond = false };
  102. prc.Init("PID", proc);
  103. Assert.IsTrue(prc.Execute() is Finish);
  104. Assert.IsTrue((proc.Pos1 | proc.Pos2 | proc.Pos3) == (POS1 | POS3));
  105. proc = new IfProcess { Cond = true };
  106. prc.Init("PID", proc);
  107. Assert.IsTrue(prc.Execute() is Finish);
  108. Assert.IsTrue((proc.Pos1 | proc.Pos2 | proc.Pos3) == (POS1 | POS2 | POS3));
  109. }
  110. [DataContract]
  111. private class IfElseProcess : Workflow.Process, IProcessDefinition
  112. {
  113. public bool Cond;
  114. public int Pos1;
  115. public int Pos2;
  116. public int Pos3;
  117. public int Pos4;
  118. public void DefineProcess(IProcessBuilder bld)
  119. {
  120. bld
  121. .Exec(_ => { Pos1 = POS1; })
  122. .If(_ => Cond)
  123. .Exec(_ => { Pos2 = POS2; })
  124. .Else()
  125. .Exec(_ => { Pos3 = POS3; })
  126. .End()
  127. .Exec(_ => { Pos4 = POS4; });
  128. }
  129. public void DefineLocalSets(ISetsBuilder bld)
  130. {
  131. }
  132. }
  133. [Test]
  134. public void IfElse()
  135. {
  136. var prc = new Processor("Test", _flowerClient);
  137. var proc = new IfElseProcess { Cond = false };
  138. prc.Init("PID", proc);
  139. Assert.IsTrue(prc.Execute() is Finish);
  140. Assert.IsTrue((proc.Pos1 | proc.Pos2 | proc.Pos3 | proc.Pos4) == (POS1 | POS3 | POS4));
  141. proc = new IfElseProcess { Cond = true };
  142. prc.Init("PID", proc);
  143. Assert.IsTrue(prc.Execute() is Finish);
  144. Assert.IsTrue((proc.Pos1 | proc.Pos2 | proc.Pos3 | proc.Pos4) == (POS1 | POS2 | POS4));
  145. }
  146. [DataContract]
  147. private class IfElseIfElseProcess : Workflow.Process, IProcessDefinition
  148. {
  149. public bool Cond1;
  150. public bool Cond2;
  151. public int Pos1;
  152. public int Pos2;
  153. public int Pos3;
  154. public int Pos4;
  155. public int Pos5;
  156. public void DefineProcess(IProcessBuilder bld)
  157. {
  158. bld
  159. .Exec(_ => { Pos1 = POS1; })
  160. .If(_ => Cond1)
  161. .Exec(_ => { Pos2 = POS2; })
  162. .ElseIf(_ => Cond2)
  163. .Exec(_ => { Pos3 = POS3; })
  164. .Else()
  165. .Exec(_ => { Pos4 = POS4; })
  166. .End()
  167. .Exec(_ => { Pos5 = POS5; });
  168. }
  169. public void DefineLocalSets(ISetsBuilder bld)
  170. {
  171. }
  172. }
  173. [Test]
  174. public void IfElseIfElse()
  175. {
  176. var prc = new Processor("Test", _flowerClient);
  177. var proc = new IfElseIfElseProcess { Cond1 = false, Cond2 = false };
  178. prc.Init("PID", proc);
  179. Assert.IsTrue(prc.Execute() is Finish);
  180. Assert.IsTrue((proc.Pos1 | proc.Pos2 | proc.Pos3 | proc.Pos4 | proc.Pos5) == (POS1 | POS4 | POS5));
  181. proc = new IfElseIfElseProcess { Cond1 = false, Cond2 = true };
  182. prc.Init("PID", proc);
  183. Assert.IsTrue(prc.Execute() is Finish);
  184. Assert.IsTrue((proc.Pos1 | proc.Pos2 | proc.Pos3 | proc.Pos4 | proc.Pos5) == (POS1 | POS3 | POS5));
  185. proc = new IfElseIfElseProcess { Cond1 = true, Cond2 = false };
  186. prc.Init("PID", proc);
  187. Assert.IsTrue(prc.Execute() is Finish);
  188. Assert.IsTrue((proc.Pos1 | proc.Pos2 | proc.Pos3 | proc.Pos4 | proc.Pos5) == (POS1 | POS2 | POS5));
  189. proc = new IfElseIfElseProcess { Cond1 = true, Cond2 = true };
  190. prc.Init("PID", proc);
  191. Assert.IsTrue(prc.Execute() is Finish);
  192. Assert.IsTrue((proc.Pos1 | proc.Pos2 | proc.Pos3 | proc.Pos4 | proc.Pos5) == (POS1 | POS2 | POS5));
  193. }
  194. #endregion
  195. #region While
  196. [DataContract]
  197. private class WhileProcess : Workflow.Process, IProcessDefinition
  198. {
  199. public int Iterations;
  200. public int Cnt;
  201. public int Pos1;
  202. public int Pos2;
  203. public void DefineProcess(IProcessBuilder bld)
  204. {
  205. bld
  206. .Exec(_ => { Pos1 = POS1; })
  207. .While(_ => Cnt < Iterations)
  208. .Exec(_ => { Cnt++; })
  209. .End()
  210. .Exec(_ => { Pos2 = POS2; });
  211. }
  212. public void DefineLocalSets(ISetsBuilder bld)
  213. {
  214. }
  215. }
  216. [Test]
  217. public void While()
  218. {
  219. var prc = new Processor("Test", _flowerClient);
  220. var proc = new WhileProcess { Iterations = 3 };
  221. prc.Init("PID", proc);
  222. Assert.IsTrue(prc.Execute() is Finish);
  223. Assert.IsTrue(proc.Cnt == proc.Iterations);
  224. Assert.IsTrue((proc.Pos1 | proc.Pos2) == (POS1 | POS2));
  225. }
  226. [DataContract]
  227. private class WhileContinueBreakProcess : Workflow.Process, IProcessDefinition
  228. {
  229. public int Iterations;
  230. public int Cnt;
  231. public int Pos1;
  232. public int Pos2;
  233. public int Pos3;
  234. public void DefineProcess(IProcessBuilder bld)
  235. {
  236. bld
  237. .Exec(_ => { Pos1 = POS1; })
  238. .While(_ => true)
  239. .If(_ => Cnt == Iterations)
  240. .Break()
  241. .Else()
  242. .Exec(_ => { Cnt++; })
  243. .Continue()
  244. .Exec(_ => { Pos2 = POS2; })
  245. .End()
  246. .End()
  247. .Exec(_ => { Pos3 = POS3; });
  248. }
  249. public void DefineLocalSets(ISetsBuilder bld)
  250. {
  251. }
  252. }
  253. [Test]
  254. public void WhileContinueBreak()
  255. {
  256. var prc = new Processor("Test", _flowerClient);
  257. var proc = new WhileContinueBreakProcess { Iterations = 3 };
  258. prc.Init("PID", proc);
  259. Assert.IsTrue(prc.Execute() is Finish);
  260. Assert.IsTrue(proc.Cnt == proc.Iterations);
  261. Assert.IsTrue((proc.Pos1 | proc.Pos2 | proc.Pos3) == (POS1 | POS3));
  262. }
  263. #endregion
  264. #region For
  265. [DataContract]
  266. private class ForProcess : Workflow.Process, IProcessDefinition
  267. {
  268. public int Iterations;
  269. public int Pos1;
  270. public int Pos2;
  271. public int Pos3;
  272. public int I;
  273. public void DefineProcess(IProcessBuilder bld)
  274. {
  275. bld
  276. .Exec(_ => { Pos1 = POS1; })
  277. .For(_ => { I = 0; }, _ => I < Iterations, _ => { I++; })
  278. .Exec(_ => { Pos2 = POS2; })
  279. .End()
  280. .Exec(_ => { Pos3 = POS3; });
  281. }
  282. public void DefineLocalSets(ISetsBuilder bld)
  283. {
  284. }
  285. }
  286. [Test]
  287. public void For()
  288. {
  289. var prc = new Processor("Test", _flowerClient);
  290. var proc = new ForProcess { Iterations = 3 };
  291. prc.Init("PID", proc);
  292. Assert.IsTrue(prc.Execute() is Finish);
  293. Assert.IsTrue(proc.I == proc.Iterations);
  294. Assert.IsTrue((proc.Pos1 | proc.Pos2 | proc.Pos3) == (POS1 | POS2 | POS3));
  295. }
  296. [DataContract]
  297. private class ForBreakContinueProcess : Workflow.Process, IProcessDefinition
  298. {
  299. public int Iterations;
  300. public int Cnt;
  301. public int Pos1;
  302. public int Pos2;
  303. public int Pos3;
  304. public void DefineProcess(IProcessBuilder bld)
  305. {
  306. bld
  307. .Exec(_ => { Pos1 = POS1; })
  308. .For(_ => { }, _ => true, _ => { })
  309. .If(_ => Cnt == Iterations)
  310. .Break()
  311. .Else()
  312. .Exec(_ => { Cnt++; })
  313. .Continue()
  314. .Exec(_ => { Pos2 = POS2; })
  315. .End()
  316. .End()
  317. .Exec(_ => { Pos3 = POS3; });
  318. }
  319. public void DefineLocalSets(ISetsBuilder bld)
  320. {
  321. }
  322. }
  323. [Test]
  324. public void ForContinueBreak()
  325. {
  326. var prc = new Processor("Test", _flowerClient);
  327. var proc = new ForBreakContinueProcess { Iterations = 3 };
  328. prc.Init("PID", proc);
  329. Assert.IsTrue(prc.Execute() is Finish);
  330. Assert.IsTrue(proc.Cnt == proc.Iterations);
  331. Assert.IsTrue((proc.Pos1 | proc.Pos2 | proc.Pos3) == (POS1 | POS3));
  332. }
  333. #endregion
  334. #region Try Catch
  335. [DataContract]
  336. private class TryCatchProcess : Workflow.Process, IProcessDefinition
  337. {
  338. public int passed;
  339. private readonly Exception _exception;
  340. public TryCatchProcess(Exception exception)
  341. {
  342. _exception = exception;
  343. }
  344. public void DefineProcess(IProcessBuilder bld)
  345. {
  346. bld
  347. .Exec(_ => { passed = 0; })
  348. .Exec(_ => { passed |= POS1; })
  349. .Try()
  350. .Exec(_ => { passed |= POS2; })
  351. .If(_ => _exception != null)
  352. .Throw(_ => _exception)
  353. .End()
  354. .Catch<InvalidOperationException>((ctx, ex) => {})
  355. .Exec(_ => { passed |= POS3; })
  356. .Catch<ArgumentException>((ctx, ex) => { })
  357. .Exec(_ => { passed |= POS4; })
  358. .Catch<Exception>((ctx, ex) => { })
  359. .Exec(_ => { passed |= POS5; })
  360. .Finally()
  361. .Exec(_ => { passed |= POS6; })
  362. .End()
  363. .Exec(_ => { passed |= POS7; });
  364. }
  365. public void DefineLocalSets(ISetsBuilder bld)
  366. {
  367. }
  368. }
  369. [Test]
  370. public void TryCatch()
  371. {
  372. var dir = CreateDirectory();
  373. string pid;
  374. new DirectoryBuilder(dir)
  375. .Root("/Processors")
  376. .Processor("Proc1", (string)null)
  377. .Folder("Running")
  378. .Process
  379. (
  380. typeof(TryCatchProcess).AssemblyQualifiedName,
  381. out pid
  382. ).End()
  383. .End()
  384. .Folder("Pending").End()
  385. .Folder("Suspended").End()
  386. .End()
  387. .End();
  388. using (var cli = new FlowerClient(dir))
  389. {
  390. var prc = new Processor("Test", cli);
  391. var proc = new TryCatchProcess(null);
  392. prc.Init(pid, proc);
  393. Assert.IsTrue(prc.Execute() is Finish);
  394. Assert.AreEqual
  395. (
  396. POS1 |
  397. POS2 |
  398. POS6 |
  399. POS7,
  400. proc.passed
  401. );
  402. prc = new Processor("Test", cli);
  403. proc = new TryCatchProcess(new InvalidOperationException());
  404. prc.Init(pid, proc);
  405. Assert.IsTrue(prc.Execute() is Finish);
  406. Assert.AreEqual
  407. (
  408. POS1 |
  409. POS2 |
  410. POS3 |
  411. POS6 |
  412. POS7,
  413. proc.passed
  414. );
  415. prc = new Processor("Test", cli);
  416. proc = new TryCatchProcess(new ArgumentException());
  417. prc.Init(pid, proc);
  418. Assert.IsTrue(prc.Execute() is Finish);
  419. Assert.AreEqual
  420. (
  421. POS1 |
  422. POS2 |
  423. POS4 |
  424. POS6 |
  425. POS7,
  426. proc.passed
  427. );
  428. prc = new Processor("Test", cli);
  429. proc = new TryCatchProcess(new IndexOutOfRangeException());
  430. prc.Init(pid, proc);
  431. Assert.IsTrue(prc.Execute() is Finish);
  432. Assert.AreEqual
  433. (
  434. POS1 |
  435. POS2 |
  436. POS5 |
  437. POS6 |
  438. POS7,
  439. proc.passed
  440. );
  441. }
  442. }
  443. #endregion
  444. #region Invoke
  445. [DataContract]
  446. private class InvokeProcess : Workflow.Process, IProcessDefinition
  447. {
  448. public int retvalDynamic;
  449. public int retvalInjected;
  450. [Service("Test/Service")]
  451. private Service service;
  452. public void DefineProcess(IProcessBuilder bld)
  453. {
  454. bld
  455. .Invoke<Service>(_ => "/Services/Test/Service", (_, svc) => { retvalDynamic = svc.ReturnOne(); })
  456. .Invoke(service, (_, svc) => { retvalInjected = svc.ReturnOne(); });
  457. }
  458. public void DefineLocalSets(ISetsBuilder bld)
  459. {
  460. }
  461. }
  462. private static readonly string TEST_SERVICE_CONTAINER =
  463. @"<objects xmlns=""http://www.springframework.net"">" +
  464. @" <object id=""Service"" type=""" + typeof(Service).AssemblyQualifiedName + @""" />" +
  465. @"</objects>";
  466. [Test]
  467. public void Invoke()
  468. {
  469. var dir = CreateDirectory();
  470. string pid;
  471. new DirectoryBuilder(dir)
  472. .Root("/Services")
  473. .ServiceContainer("Test", TEST_SERVICE_CONTAINER).End()
  474. .End()
  475. .Root("/Processors")
  476. .Processor("Proc1", (string)null)
  477. .Folder("Running")
  478. .Process
  479. (
  480. typeof(InvokeProcess).AssemblyQualifiedName,
  481. out pid
  482. ).End()
  483. .End()
  484. .Folder("Pending").End()
  485. .Folder("Suspended").End()
  486. .End()
  487. .End();
  488. using (var cli = new FlowerClient(dir))
  489. {
  490. var proc = new InvokeProcess();
  491. var prc = new Processor("Proc1", cli);
  492. prc.Init(pid, proc);
  493. Assert.IsTrue(prc.Execute() is Finish);
  494. Assert.IsTrue(proc.retvalDynamic == 1);
  495. Assert.IsTrue(proc.retvalInjected == 1);
  496. Assert.IsTrue(dir.CountChildren(pid, DirectoryEntryTypes.State) == 2);
  497. }
  498. }
  499. #endregion
  500. #region Lock/Unlock
  501. [DataContract]
  502. private class LockUnlockProcess : Workflow.Process, IProcessDefinition
  503. {
  504. public const string RES1 = "/Sets/Shared/Resource1/Root";
  505. public const string RES2 = "/Sets/Shared/Resource2/Root";
  506. public static readonly string[] Resources = new string[] { RES1, RES2 };
  507. public bool FirstLockFailed;
  508. public void DefineProcess(IProcessBuilder bld)
  509. {
  510. bld
  511. .Lock
  512. (
  513. _ => new[] { RES1 },
  514. ctx => ctx.Pid,
  515. _ => false,
  516. (ctx, failures) => { FirstLockFailed = true; }
  517. )
  518. .Lock
  519. (
  520. _ => new[] { RES2 },
  521. ctx => ctx.Pid,
  522. _ => true
  523. )
  524. .Unlock(_ => Resources, ctx => ctx.Pid);
  525. }
  526. public void DefineLocalSets(ISetsBuilder bld)
  527. {
  528. }
  529. }
  530. [Test]
  531. public void LockUnlock()
  532. {
  533. var dir = CreateDirectory();
  534. string pid;
  535. new DirectoryBuilder(dir)
  536. .Root("/Sets/Shared")
  537. .Set("Resource1", typeof(int).FullName, 0).End()
  538. .Set("Resource2", typeof(int).FullName, 0)
  539. .Folder("Root")
  540. .Message("X", BlobFormat.TextXml, 1).End()
  541. .End()
  542. .End()
  543. .End()
  544. .Root("/Processors")
  545. .Processor("Proc1", (string)null)
  546. .Folder("Running")
  547. .Process
  548. (
  549. typeof(LockUnlockProcess).FullName,
  550. out pid
  551. ).End()
  552. .End()
  553. .Folder("Waiting").End()
  554. .Folder("Pending").End()
  555. .End()
  556. .End();
  557. using (var cli = new FlowerClient(dir))
  558. {
  559. var proc = new LockUnlockProcess();
  560. var prc = new Processor("Proc1", cli);
  561. prc.Init(pid, proc);
  562. Assert.IsTrue(prc.Execute() is Waiting);
  563. Assert.IsFalse(dir.Exists("/Processors/Proc1/Running/" + pid, DateTime.MinValue));
  564. Assert.IsTrue(dir.Exists("/Processors/Proc1/Waiting/" + pid, DateTime.MinValue));
  565. prc.Client.Unlock(new[] { LockUnlockProcess.RES2 }, "X");
  566. Assert.IsFalse(dir.Exists("/Processors/Proc1/Waiting/" + pid, DateTime.MinValue));
  567. Assert.IsTrue(dir.Exists("/Processors/Proc1/Pending/" + pid, DateTime.MinValue));
  568. Assert.IsTrue(prc.Execute() is Finish);
  569. }
  570. }
  571. #endregion
  572. #region Enqueue/Dequeue
  573. [DataContract]
  574. private class EnqueueDequeueProcess : Workflow.Process, IProcessDefinition
  575. {
  576. public const string SRC = "/Sets/Shared/Src";
  577. public const string DEST = "/Sets/Shared/Dest";
  578. private int i;
  579. private int message;
  580. public void DefineProcess(IProcessBuilder bld)
  581. {
  582. bld
  583. .For(_ => { i = 0; }, _ => i < 10, _ => { ++i; })
  584. .Dequeue<int>(_ => SRC, (ctx, msg) => { message = msg; })
  585. .Enqueue(_ => DEST, _ => message, _ => MessageFormat.BinXml)
  586. .End();
  587. }
  588. public void DefineLocalSets(ISetsBuilder bld)
  589. {
  590. }
  591. }
  592. [Test]
  593. public void EnqueueDequeue()
  594. {
  595. var dir = CreateDirectory();
  596. string pid;
  597. new DirectoryBuilder(dir)
  598. .Root("/Sets/Shared")
  599. .Set("Src", typeof(int).FullName, 0).End()
  600. .Set("Dest", typeof(int).FullName, 5).End()
  601. .End()
  602. .Root("/Processors")
  603. .Processor("Proc1", (string)null)
  604. .Folder("Running")
  605. .Process
  606. (
  607. typeof(LockUnlockProcess).FullName,
  608. out pid
  609. ).End()
  610. .End()
  611. .Folder("Waiting").End()
  612. .Folder("Pending").End()
  613. .End()
  614. .End();
  615. using (var cli = new FlowerClient(dir))
  616. {
  617. var proc = new EnqueueDequeueProcess();
  618. var prc = new Processor("Proc1", cli);
  619. prc.Init(pid, proc);
  620. Assert.IsTrue(prc.Execute() is Waiting);
  621. Assert.IsFalse(dir.Exists("/Processors/Proc1/Running/" + pid, DateTime.MinValue));
  622. Assert.IsTrue(dir.Exists("/Processors/Proc1/Waiting/" + pid, DateTime.MinValue));
  623. for (int i = 0; i < 10; i++)
  624. {
  625. Assert.IsTrue(cli.PutMessage(EnqueueDequeueProcess.SRC, i.ToString(), i, BlobFormat.BinXml));
  626. }
  627. dir.Move(pid, "/Processors/Proc1/Running");
  628. Assert.IsTrue(prc.Execute() is Waiting);
  629. Assert.IsFalse(dir.Exists("/Processors/Proc1/Running/" + pid, DateTime.MinValue));
  630. Assert.IsTrue(dir.Exists("/Processors/Proc1/Waiting/" + pid, DateTime.MinValue));
  631. Assert.AreEqual(5, dir.CountChildren(EnqueueDequeueProcess.DEST, DirectoryEntryTypes.Message));
  632. var messages = dir.GetChildren(EnqueueDequeueProcess.DEST, DirectoryEntryTypes.Message, SortProperty.Default, Services.Data.SortOrder.Asc, 0, long.MaxValue);
  633. foreach(var msg in messages)
  634. {
  635. cli.RemoveMessage(msg.Id);
  636. }
  637. Assert.AreEqual(0, dir.CountChildren(EnqueueDequeueProcess.DEST, DirectoryEntryTypes.Message));
  638. dir.Move(pid, "/Processors/Proc1/Running");
  639. Assert.IsTrue(prc.Execute() is Finish);
  640. Assert.AreEqual(5, dir.CountChildren(EnqueueDequeueProcess.DEST, DirectoryEntryTypes.Message));
  641. }
  642. }
  643. #endregion
  644. #region ForEach
  645. [DataContract]
  646. private class ForEachProcess : Workflow.Process, IProcessDefinition
  647. {
  648. public const string SET = "/Sets/Shared/Messages";
  649. private int i;
  650. public int sum;
  651. private int item;
  652. private string itemName;
  653. public void DefineProcess(IProcessBuilder bld)
  654. {
  655. bld
  656. .For(_ => { i = 0; }, _ => i < 8, _ => { i++; })
  657. .Enqueue(_ => SET, _ => i.ToString(), _ => 1 << i, _ => MessageFormat.BinXml)
  658. .End()
  659. .Exec(_ => { sum = 0; })
  660. .ForEach
  661. (
  662. _ => SET,
  663. _ => MessageProperty.Default,
  664. _ => SortOrder.Asc,
  665. _ => 100,
  666. _ => false,
  667. (string _, int itm) => { item = itm; }
  668. )
  669. .Exec(_ => { sum = sum | item; })
  670. .End()
  671. .Breakpoint("First sum")
  672. .ForEach
  673. (
  674. _ => SET,
  675. _ => MessageProperty.Default,
  676. _ => SortOrder.Asc,
  677. _ => 100,
  678. _ => false,
  679. (string itmName, int itm) => { item = itm; itemName = itmName; }
  680. )
  681. .UpdateCurrent(_ => itemName, _ => item << 8, _ => MessageFormat.BinXml)
  682. .End()
  683. .ForEach
  684. (
  685. _ => SET,
  686. _ => MessageProperty.Default,
  687. _ => SortOrder.Asc,
  688. _ => 100,
  689. _ => false,
  690. (string _, int itm) => { item = itm; }
  691. )
  692. .Exec(_ => { sum = sum | item; })
  693. .End()
  694. .Breakpoint("Second sum")
  695. .ForEach
  696. (
  697. _ => SET,
  698. _ => MessageProperty.Default,
  699. _ => SortOrder.Asc,
  700. _ => 100,
  701. _ => false,
  702. (string _, int itm) => { item = itm; }
  703. )
  704. .If(_ => item < 0x1000)
  705. .RemoveCurrent()
  706. .End()
  707. .End()
  708. .Exec(_ => { sum = 0; })
  709. .ForEach
  710. (
  711. _ => SET,
  712. _ => MessageProperty.Default,
  713. _ => SortOrder.Asc,
  714. _ => 100,
  715. _ => false,
  716. (string _, int itm) => { item = itm; }
  717. )
  718. .Exec(_ => { sum = sum | item; })
  719. .End()
  720. .Breakpoint("Third sum");
  721. }
  722. public void DefineLocalSets(ISetsBuilder bld)
  723. {
  724. }
  725. }
  726. [Test]
  727. public void ForEach()
  728. {
  729. var dir = CreateDirectory();
  730. string pid;
  731. new DirectoryBuilder(dir)
  732. .Root("/Sets/Shared")
  733. .Set("Messages", typeof(int).FullName, 0).End()
  734. .End()
  735. .Root("/Processors")
  736. .Processor("Proc1", (string)null)
  737. .Folder("Running")
  738. .Process
  739. (
  740. typeof(LockUnlockProcess).FullName,
  741. out pid
  742. ).End()
  743. .Folder("Waiting").End()
  744. .Folder("Pending").End()
  745. .End()
  746. .End();
  747. using (var cli = new FlowerClient(dir))
  748. {
  749. var proc = new ForEachProcess();
  750. var prc = new Processor("Proc1", cli, null, new Processor.Settings { EmitBreakpoints = true });
  751. prc.Init(pid, proc);
  752. Assert.IsTrue(prc.Execute() is Breakpoint);
  753. Assert.AreEqual(0xFF, proc.sum);
  754. Assert.IsTrue(prc.Execute() is Breakpoint);
  755. Assert.AreEqual(0xFFFF, proc.sum);
  756. Assert.IsTrue(prc.Execute() is Breakpoint);
  757. Assert.AreEqual(0xF000, proc.sum);
  758. }
  759. }
  760. [DataContract]
  761. private class ForEachWaitingProcess : Workflow.Process, IProcessDefinition
  762. {
  763. public const string SET = "/Sets/Shared/Messages";
  764. public int sum;
  765. private int item;
  766. public void DefineProcess(IProcessBuilder bld)
  767. {
  768. bld
  769. .Exec(_ => { sum = 0; })
  770. .ForEach
  771. (
  772. _ => SET,
  773. _ => MessageProperty.Default,
  774. _ => SortOrder.Asc,
  775. _ => 100,
  776. _ => true,
  777. (string _, int itm) => { item = itm; }
  778. )
  779. .Exec(_ => { sum = sum | item; })
  780. .End();
  781. }
  782. public void DefineLocalSets(ISetsBuilder bld)
  783. {
  784. }
  785. }
  786. [Test]
  787. public void ForEachWaiting()
  788. {
  789. var dir = CreateDirectory();
  790. string pid;
  791. new DirectoryBuilder(dir)
  792. .Root("/Sets/Shared")
  793. .Set("Messages", typeof(int).FullName, 0).End()
  794. .End()
  795. .RegisterProcessor("Proc1")
  796. .Root("/Processors/Proc1/Running")
  797. .Process
  798. (
  799. typeof(LockUnlockProcess).FullName,
  800. out pid
  801. ).End()
  802. .End();
  803. using (var cli = new FlowerClient(dir))
  804. {
  805. var proc = new ForEachWaitingProcess();
  806. var prc = new Processor("Proc1", cli);
  807. prc.Init(pid, proc);
  808. Assert.IsTrue(prc.Execute() is Waiting);
  809. for (int i = 0; i < 8; i++)
  810. {
  811. prc.Client.PutMessage(ForEachWaitingProcess.SET, i.ToString(), 1 << i, BlobFormat.BinXml);
  812. }
  813. dir.Move(pid, "/Processors/Proc1/Running");
  814. Assert.IsTrue(prc.Execute() is Waiting);
  815. Assert.AreEqual(0xFF, proc.sum);
  816. proc.sum = 0;
  817. for (int i = 8; i < 16; i++)
  818. {
  819. prc.Client.PutMessage(ForEachWaitingProcess.SET, i.ToString(), 1 << i, BlobFormat.BinXml);
  820. }
  821. dir.Move(pid, "/Processors/Proc1/Running");
  822. Assert.IsTrue(prc.Execute() is Waiting);
  823. Assert.AreEqual(0xFF00, proc.sum);
  824. }
  825. }
  826. #endregion
  827. #region WaitUntil
  828. [DataContract]
  829. private class WaitUntilProcess : Workflow.Process, IProcessDefinition
  830. {
  831. public DateTime start;
  832. public bool finished;
  833. public void DefineProcess(IProcessBuilder bld)
  834. {
  835. bld
  836. .WaitUntil(_ => start + TimeSpan.FromSeconds(1), _ => { finished = true; });
  837. }
  838. public void DefineLocalSets(ISetsBuilder bld)
  839. {
  840. }
  841. }
  842. [Test]
  843. public void WaitUntil()
  844. {
  845. var dir = CreateDirectory();
  846. string pid;
  847. new DirectoryBuilder(dir)
  848. .Root("/Processors")
  849. .Processor("Proc1", (string)null)
  850. .Folder("Running")
  851. .Process
  852. (
  853. typeof(LockUnlockProcess).FullName,
  854. out pid
  855. ).End()
  856. .Folder("Suspended").End()
  857. .End()
  858. .End();
  859. using (var cli = new FlowerClient(dir))
  860. {
  861. var proc = new WaitUntilProcess { start = DateTime.Now };
  862. var prc = new Processor("Proc1", cli);
  863. prc.Init(pid, proc);
  864. Assert.IsTrue(prc.Execute() is Suspention);
  865. Assert.AreEqual(1, cli.Directory.CountChildren("/Processors/Proc1/Suspended", DirectoryEntryTypes.Link));
  866. Thread.Sleep(2000);
  867. Assert.IsTrue(prc.Execute() is Finish);
  868. }
  869. }
  870. #endregion
  871. #region StartProcess/WaitProcess
  872. [DataContract]
  873. public class EmptyWorkflow : Workflow.Process, IWorkflow<int, int>
  874. {
  875. public void DefineLocalSets(ISetsBuilder bld)
  876. {
  877. }
  878. public int Initialize(IInitializationContext context, int arg)
  879. {
  880. return arg + 1;
  881. }
  882. public void DefineProcess(IProcessBuilder bld)
  883. {
  884. }
  885. }
  886. [DataContract]
  887. public class StartProcessWaitProcessProcess : Workflow.Process, IProcessDefinition
  888. {
  889. private const string WORKFLOW = "/Workflows/Empty";
  890. public string pid;
  891. public int startResult;
  892. public void DefineProcess(IProcessBuilder bld)
  893. {
  894. bld
  895. .StartProcess<int, int>
  896. (
  897. _ => WORKFLOW,
  898. _ => 1,
  899. (_, p, result) =>
  900. {
  901. pid = p;
  902. startResult = result;
  903. }
  904. )
  905. .JoinProcess(_ => pid, null);
  906. }
  907. public void DefineLocalSets(ISetsBuilder bld)
  908. {
  909. }
  910. }
  911. [Test]
  912. public void StartProcessWaitProcess()
  913. {
  914. var dir = CreateDirectory();
  915. string pid;
  916. new DirectoryBuilder(dir)
  917. .Root("/Workflows")
  918. .Workflow("Empty", typeof(EmptyWorkflow).AssemblyQualifiedName, null).End()
  919. .End()
  920. .RegisterProcessor("Proc1")
  921. .Root("/Processors/Proc1/Running")
  922. .Process
  923. (
  924. typeof(LockUnlockProcess).FullName,
  925. out pid
  926. ).End()
  927. .End();
  928. using (var cli = new FlowerClient(dir))
  929. {
  930. var proc = new StartProcessWaitProcessProcess();
  931. var prc = new Processor("Proc1", cli);
  932. prc.Init(pid, proc);
  933. Assert.IsTrue(prc.Execute() is Waiting);
  934. Assert.AreEqual(2, proc.startResult);
  935. cli
  936. .CreateScript()
  937. .SetText("__changeProcessStatus($in.pid, 'Finished');")
  938. .AddParameter("pid", proc.pid)
  939. .Execute();
  940. Assert.IsTrue(prc.Execute() is Finish);
  941. }
  942. }
  943. #endregion
  944. #region WaitAny
  945. [DataContract]
  946. private class WaitAnyProcess : Workflow.Process, IProcessDefinition
  947. {
  948. public const string GET_SET = "/Sets/Shared/Get";
  949. public const string PUT_SET = "/Sets/Shared/Put";
  950. public const string ENQUEUE_SET = "/Sets/Shared/Enqueue";
  951. public const string LOCK_SET = "/Sets/Shared/Lock";
  952. private const string WORKFLOW = "/Workflows/Empty";
  953. public DateTime waitUntil;
  954. public int count;
  955. public string pid;
  956. private int iterationsCount;
  957. public void DefineProcess(IProcessBuilder bld)
  958. {
  959. bld
  960. .Exec(_ =>
  961. {
  962. count = 0;
  963. iterationsCount = 0;
  964. waitUntil = DateTime.Now + TimeSpan.FromDays(1);
  965. })
  966. .StartProcess<int, int>
  967. (
  968. _ => WORKFLOW,
  969. _ => 1,
  970. (ctx, p, result) => { pid = p; }
  971. )
  972. .While(_ => count != (1 | 2 | 4 | 8 | 16 | 32) && iterationsCount <= 6)
  973. .WaitAny()
  974. .Enqueue(_ => PUT_SET, _ => "Msg", _ => 1, _ => MessageFormat.BinXml, _ => { count = count | 1; })
  975. .Enqueue(_ => ENQUEUE_SET, _ => 1, _ => MessageFormat.BinXml, _ => { count = count | 2; })
  976. .Dequeue<int>(_ => GET_SET, (_, msg) => { count = count | 4; })
  977. .Lock
  978. (
  979. _ => new[] { LOCK_SET },
  980. _ => ((count & 8) == 0) ? "Proc1" : "Proc2",
  981. _ => true,
  982. (_, failures) => { if (failures.Length == 0) count = count | 8; }
  983. )
  984. .JoinProcess(_ => pid, _ => { count = count | 16; })
  985. .WaitUntil(_ => waitUntil, _ => { count = count | 32; })
  986. .End()
  987. .If(_ => (count & 16) != 0)
  988. .StartProcess<int, int>
  989. (
  990. _ => WORKFLOW,
  991. _ => 1,
  992. (_, p, result) => { pid = p; }
  993. )
  994. .End()
  995. .Exec(_ => { ++iterationsCount; })
  996. .End();
  997. }
  998. public void DefineLocalSets(ISetsBuilder bld)
  999. {
  1000. }
  1001. }
  1002. [Test]
  1003. public void WaitAny()
  1004. {
  1005. var dir = CreateDirectory();
  1006. string pid;
  1007. new DirectoryBuilder(dir)
  1008. .Root("/Workflows")
  1009. .Workflow("Empty", typeof(EmptyWorkflow).AssemblyQualifiedName, null).End()
  1010. .End()
  1011. .Root("/Sets/Shared")
  1012. .Set("Get", typeof(int).FullName, 0).End()
  1013. .Set("Put", typeof(int).FullName, 1)
  1014. .Message("Msg", BlobFormat.BinXml, 1).End()
  1015. .End()
  1016. .Set("Enqueue", typeof(int).FullName, 1)
  1017. .Message("Msg", BlobFormat.BinXml, 1).End()
  1018. .End()
  1019. .Set("Lock", typeof(int).FullName, 1)
  1020. .Message("Owner", BlobFormat.BinXml, 1).End()
  1021. .End()
  1022. .End()
  1023. .RegisterProcessor("Proc1")
  1024. .Root("/Processors/Proc1/Running")
  1025. .Process
  1026. (
  1027. typeof(LockUnlockProcess).FullName,
  1028. out pid
  1029. ).End()
  1030. .End();
  1031. using (var cli = new FlowerClient(dir))
  1032. {
  1033. var proc = new WaitAnyProcess();
  1034. var prc = new Processor("Proc1", cli);
  1035. prc.Init(pid, proc);
  1036. var suspention = prc.Execute() as Suspention;
  1037. Assert.IsTrue(suspention != null && !suspention.Stop);
  1038. Assert.IsTrue(prc.Execute() is Waiting);
  1039. Assert.IsTrue(dir.CountChildren(WaitAnyProcess.GET_SET + "/GetWaiters", DirectoryEntryTypes.Link) > 0);
  1040. cli.PutMessage(WaitAnyProcess.GET_SET, "Msg", 1, BlobFormat.BinXml);
  1041. dir.Move(pid, "/Processors/Proc1/Running");
  1042. foreach (var suspentionLink in dir.GetChildren("/Processors/Proc1/Suspended", DirectoryEntryTypes.Link, SortProperty.Default, Services.Data.SortOrder.Asc, 0, long.MaxValue))
  1043. {
  1044. dir.Remove(suspentionLink.Id);
  1045. }
  1046. suspention = prc.Execute() as Suspention;
  1047. Assert.IsTrue(suspention != null && !suspention.Stop);
  1048. Assert.IsTrue(prc.Execute() is Waiting);
  1049. cli.RemoveMessage("/Sets/Shared/Put/Msg");
  1050. dir.Move(pid, "/Processors/Proc1/Running");
  1051. foreach (var suspentionLink in dir.GetChildren("/Processors/Proc1/Suspended", DirectoryEntryTypes.Link, SortProperty.Default, Services.Data.SortOrder.Asc, 0, long.MaxValue))
  1052. {
  1053. dir.Remove(suspentionLink.Id);
  1054. }
  1055. suspention = prc.Execute() as Suspention;
  1056. Assert.IsTrue(suspention != null && !suspention.Stop);
  1057. Assert.IsTrue(prc.Execute() is Waiting);
  1058. cli.RemoveMessage("/Sets/Shared/Enqueue/Msg");
  1059. dir.Move(pid, "/Processors/Proc1/Running");
  1060. foreach (var suspentionLink in dir.GetChildren("/Processors/Proc1/Suspended", DirectoryEntryTypes.Link, SortProperty.Default, Services.Data.SortOrder.Asc, 0, long.MaxValue))
  1061. {
  1062. dir.Remove(suspentionLink.Id);
  1063. }
  1064. suspention = prc.Execute() as Suspention;
  1065. Assert.IsTrue(suspention != null && !suspention.Stop);
  1066. Assert.IsTrue(prc.Execute() is Waiting);
  1067. cli.RemoveMessage("/Sets/Shared/Lock/Owner");
  1068. dir.Move(pid, "/Processors/Proc1/Running");
  1069. foreach (var suspentionLink in dir.GetChildren("/Processors/Proc1/Suspended", DirectoryEntryTypes.Link, SortProperty.Default, Services.Data.SortOrder.Asc, 0, long.MaxValue))
  1070. {
  1071. dir.Remove(suspentionLink.Id);
  1072. }
  1073. suspention = prc.Execute() as Suspention;
  1074. Assert.IsTrue(suspention != null && !suspention.Stop);
  1075. Assert.IsTrue(prc.Execute() is Waiting);
  1076. cli
  1077. .CreateScript()
  1078. .SetText("__changeProcessStatus($in.pid, 'Finished');")
  1079. .AddParameter("pid", proc.pid)
  1080. .Execute();
  1081. dir.Move(pid, "/Processors/Proc1/Running");
  1082. foreach (var suspentionLink in dir.GetChildren("/Processors/Proc1/Suspended", DirectoryEntryTypes.Link, SortProperty.Default, Services.Data.SortOrder.Asc, 0, long.MaxValue))
  1083. {
  1084. dir.Remove(suspentionLink.Id);
  1085. }
  1086. suspention = prc.Execute() as Suspention;
  1087. Assert.IsTrue(suspention != null && !suspention.Stop);
  1088. Assert.IsTrue(prc.Execute() is Waiting);
  1089. dir.Move(pid, "/Processors/Proc1/Running");
  1090. foreach (var suspentionLink in dir.GetChildren("/Processors/Proc1/Suspended", DirectoryEntryTypes.Link, SortProperty.Default, Services.Data.SortOrder.Asc, 0, long.MaxValue))
  1091. {
  1092. dir.Remove(suspentionLink.Id);
  1093. }
  1094. proc.waitUntil = DateTime.Now;
  1095. Assert.IsTrue(prc.Execute() is Finish);
  1096. Assert.AreEqual(1 | 2 | 4 | 8 | 16 | 32, proc.count);
  1097. }
  1098. }
  1099. #endregion
  1100. #region Breakpoint
  1101. [DataContract]
  1102. private class BreakpointProcess : Workflow.Process, IProcessDefinition
  1103. {
  1104. public int Pos1;
  1105. public int Pos2;
  1106. public void DefineProcess(IProcessBuilder bld)
  1107. {
  1108. bld
  1109. .Exec(_ => { Pos1 = POS1; })
  1110. .Breakpoint("break")
  1111. .Exec(_ => { Pos2 = POS2; });
  1112. }
  1113. public void DefineLocalSets(ISetsBuilder bld)
  1114. {
  1115. }
  1116. }
  1117. [Test]
  1118. public void Breakpoint()
  1119. {
  1120. var proc = new BreakpointProcess();
  1121. var prc = new Processor("Test", _flowerClient, null, new Processor.Settings { EmitBreakpoints = true });
  1122. prc.Init("PID", proc);
  1123. var bp = prc.Execute() as Breakpoint;
  1124. Assert.IsTrue(bp != null);
  1125. Assert.IsTrue(bp.Name == "break");
  1126. Assert.IsTrue(prc.Execute() is Finish);
  1127. }
  1128. #endregion
  1129. #region Save/Load process
  1130. [DataContract]
  1131. private class SaveLoadProcessProcess : Workflow.Process, IWorkflow<object, object>
  1132. {
  1133. [DataMember]
  1134. public int counter;
  1135. public void DefineLocalSets(ISetsBuilder bld)
  1136. {
  1137. }
  1138. public object Initialize(IInitializationContext context, object arg)
  1139. {
  1140. return null;
  1141. }
  1142. public void DefineProcess(IProcessBuilder bld)
  1143. {
  1144. bld
  1145. .Breakpoint("Break1")
  1146. .Exec(_ => { counter = 0; })
  1147. .ExecAndSave(_ => { counter++; })
  1148. .Breakpoint("Break2")
  1149. .ExecAndSave(_ => { counter++; });
  1150. }
  1151. }
  1152. [Test]
  1153. public void SaveLoadProcess()
  1154. {
  1155. var dir = CreateDirectory();
  1156. string pid;
  1157. new DirectoryBuilder(dir)
  1158. .Root("/Processors")
  1159. .Processor("Proc", (string)null)
  1160. .Folder("Running")
  1161. .Process
  1162. (
  1163. typeof(SaveLoadProcessProcess).AssemblyQualifiedName,
  1164. out pid
  1165. )
  1166. .End()
  1167. .End()
  1168. .End()
  1169. .End();
  1170. using (var cli = new FlowerClient(dir))
  1171. {
  1172. var prc = new SaveLoadProcessProcess();
  1173. var proc = new Processor("Proc", cli, null, new Processor.Settings { EmitBreakpoints = true });
  1174. proc.Init(pid, prc);
  1175. Assert.IsTrue(proc.Execute() is Breakpoint);
  1176. proc.SaveState(false);
  1177. proc = new Processor("Proc", cli, null, new Processor.Settings { EmitBreakpoints = true });
  1178. proc.LoadProcess(pid);
  1179. prc = (SaveLoadProcessProcess)proc.State;
  1180. Assert.IsTrue(proc.Execute() is Breakpoint);
  1181. Assert.AreEqual(1, prc.counter);
  1182. proc.SaveState(false);
  1183. proc = new Processor("Proc", cli, null, new Processor.Settings { EmitBreakpoints = true });
  1184. proc.LoadProcess(pid);
  1185. prc = (SaveLoadProcessProcess)proc.State;
  1186. Assert.AreEqual(1, prc.counter);
  1187. Assert.IsTrue(proc.Execute() is Finish);
  1188. Assert.AreEqual(2, prc.counter);
  1189. }
  1190. }
  1191. #endregion
  1192. #region ExecAsync
  1193. [DataContract]