Explorar el Código

Add PSProcessProviderBaseTest (basic)

Dalibor Votruba hace 1 año
padre
commit
fa2c057616

+ 16 - 0
qdr.fnd.core.pqueue.test/Process/Mock/PsProcessProviderBaseMock.cs

@@ -9,5 +9,21 @@ namespace qdr.fnd.core.pqueue.test.Process.Mock
         public PsProcessProviderBaseMock(ProcessDoneCallback processDoneCallback, ProcessStdOutputCallback processStdOutputCallback, string itemId, TypedArgument[] arguments, ILogger logger) : base(processDoneCallback, processStdOutputCallback, itemId, arguments, logger)
         {
         }
+
+        public void TestOnProcessError(Exception exception)
+        {
+            var task = base.OnProcessError(exception);
+            task.Wait();
+        }
+
+        public TValue? TestGetArgumentValue<TValue>(string name)
+        {
+            return base.GetArgumentValue<TValue>(name);
+        }
+
+        public bool TestContainsArgument(string name)
+        {
+            return base.ContainsArgument(name);
+        }
     }
 }

+ 125 - 0
qdr.fnd.core.pqueue.test/Process/PsProcessProviderBaseTest.cs

@@ -0,0 +1,125 @@
+using Newtonsoft.Json.Linq;
+using NUnit.Framework.Interfaces;
+using qdr.fnd.core.pqueue.Enums;
+using qdr.fnd.core.pqueue.Process;
+using qdr.fnd.core.pqueue.test.Mocks;
+using qdr.fnd.core.pqueue.test.Process.Mock;
+using Quadarax.Foundation.Core.Data;
+using System.Collections.Concurrent;
+
+namespace qdr.fnd.core.pqueue.test.Process
+{
+    internal class PsProcessProviderBaseTest
+    {
+
+        private IDictionary<string, List<string>> _stdOutPool;
+        private IDictionary<string, List<Tuple<PsStatusEnum, string>>> _statusDonePool;
+        
+        [SetUp]
+        public void Setup()
+        {
+            _stdOutPool = new ConcurrentDictionary<string, List<string>>();
+            _statusDonePool = new ConcurrentDictionary<string, List<Tuple<PsStatusEnum, string>>>();
+        }
+
+        [Test(TestOf=typeof(PsProcessProviderBase))]
+        public void ConstructorOk()
+        {
+            var args = PsProcessProviderBaseMock.CreateArguments().ToArray();
+            var process = CreateProcess(args);
+            Assert.IsFalse(process.IsRunning);
+            Assert.That(args, Is.EquivalentTo(process.Arguments.Values));
+        }
+
+        [Test(TestOf=typeof(PsProcessProviderBase))]
+        public void ConstructorFail()
+        {
+            var args = PsProcessProviderBaseMock.CreateArguments().ToArray();
+            var itemId = "a";
+            Assert.Throws<ArgumentNullException>(() => new PsProcessProviderBaseMock(null!, OnProcessStdOut,itemId, args, new LoggerMock()));
+            Assert.Throws<ArgumentNullException>(() => new PsProcessProviderBaseMock(OnProcessDone, null!,itemId, args, new LoggerMock()));
+            Assert.Throws<ArgumentNullException>(() => new PsProcessProviderBaseMock(OnProcessDone, OnProcessStdOut,null!, args, new LoggerMock()));
+            Assert.Throws<ArgumentNullException>(() => new PsProcessProviderBaseMock(OnProcessDone, OnProcessStdOut,string.Empty, args, new LoggerMock()));
+            Assert.Throws<ArgumentNullException>(() => new PsProcessProviderBaseMock(OnProcessDone, OnProcessStdOut,itemId, null!, new LoggerMock()));
+        }
+
+        [Test(TestOf=typeof(PsProcessProviderBase))]
+        public void OnProcessErrorOk()
+        {
+            var testMessage = "Test";
+            var args = PsProcessProviderBaseMock.CreateArguments().ToArray();
+            var process = CreateProcess(args);
+            process.TestOnProcessError(new Exception(testMessage));
+            Assert.That(_stdOutPool.ContainsKey(process.ItemId), Is.True);
+            Assert.That(_stdOutPool[process.ItemId].Contains(testMessage), Is.True);
+        }
+
+        [Test(TestOf=typeof(PsProcessProviderBase))]
+        public void OnProcessErrorFail()
+        {
+            var args = PsProcessProviderBaseMock.CreateArguments().ToArray();
+            var process = CreateProcess(args);
+
+            var ex = Assert.Throws<AggregateException>(()=>process.TestOnProcessError(null!));
+            Assert.That(ex.InnerExceptions.Any(e => e is ArgumentNullException), Is.True);
+        }
+
+        [Test(TestOf=typeof(PsProcessProviderBase))]
+        public void GetArgumentValueOk()
+        {
+            var value = "a";
+            var args = PsProcessProviderBaseMock.CreateArguments().ToArray();
+            args.Where(x=>x.Name == PsProcessProviderBase.CS_ARG_RESULT_TEXT).First().Value = value;
+            var process = CreateProcess(args);
+            Assert.That(process.TestGetArgumentValue<string>(PsProcessProviderBase.CS_ARG_RESULT_TEXT), Is.EqualTo(value));
+        }
+
+        [Test(TestOf=typeof(PsProcessProviderBase))]
+        public void GetArgumentValueFail()
+        {
+            var args = PsProcessProviderBaseMock.CreateArguments().ToArray();
+            var process = CreateProcess(args);
+            Assert.Throws<ArgumentNullException>(() => process.TestGetArgumentValue<string>(null!));
+            Assert.Throws<ArgumentNullException>(() => process.TestGetArgumentValue<string>(string.Empty));
+            Assert.That(process.TestGetArgumentValue<string>("a"), Is.Null);
+        }
+
+        [Test(TestOf=typeof(PsProcessProviderBase))]
+        public void ContainsArgumentOk()
+        {
+            var args = PsProcessProviderBaseMock.CreateArguments().ToArray();
+            var process = CreateProcess(args);
+            Assert.That(process.TestContainsArgument(PsProcessProviderBase.CS_ARG_RESULT_TEXT), Is.True);
+            Assert.That(process.TestContainsArgument("a"), Is.False);
+        }
+
+        [Test(TestOf=typeof(PsProcessProviderBase))]
+        public void ContainsArgumentFail()
+        {
+            var args = PsProcessProviderBaseMock.CreateArguments().ToArray();
+            var process = CreateProcess(args);
+            Assert.Throws<ArgumentNullException>(() => process.TestContainsArgument(string.Empty));
+            Assert.Throws<ArgumentNullException>(() => process.TestContainsArgument(null!));
+        }
+
+        private PsProcessProviderBaseMock CreateProcess(TypedArgument[] args)
+        {
+            var itemId = "a";
+            return new PsProcessProviderBaseMock(OnProcessDone, OnProcessStdOut, itemId, args, new LoggerMock());
+        }
+
+        private void OnProcessStdOut(string itemId, string message)
+        {
+            TestContext.WriteLine($"#StdOut: ItemId={itemId}; message='{message}'");
+            _stdOutPool.TryAdd(itemId, new List<string>());
+            _stdOutPool[itemId].Add(message);
+        }
+
+        private void OnProcessDone(string itemId, PsStatusEnum newStatus, string message)
+        {
+            TestContext.WriteLine($"#StaChg: ItemId={itemId}; newStatus={newStatus}; message='{message}'");
+            _statusDonePool.TryAdd(itemId, new List<Tuple<PsStatusEnum, string>>());
+            _statusDonePool[itemId].Add(new Tuple<PsStatusEnum, string>(newStatus, message));
+        }
+    }
+}

+ 29 - 2
qdr.fnd.core.pqueue/Process/IPsProcessProvider.cs

@@ -1,9 +1,36 @@
-namespace qdr.fnd.core.pqueue.Process
+using Quadarax.Foundation.Core.Data;
+
+namespace qdr.fnd.core.pqueue.Process
 {
     public interface IPsProcessProvider : IDisposable
     {
+
+        /// <summary>
+        /// Collection (dictionary) of running arguments for the process.
+        /// </summary>
+        IDictionary<string, TypedArgument> Arguments { get; }
+        /// <summary>
+        /// Flag signalizes if the process is running.
+        /// </summary>
+        bool IsRunning { get; }
+        /// <summary>
+        /// Working/processing item identifier. Points to <see cref="PsQueueItem.Id"/>."/>
+        /// </summary>
+        string ItemId { get; }
+
+        /// <summary>
+        /// Validates the process arguments. Throws <see cref="PsProcessProviderException"/> if validation fails.
+        /// </summary>
         void Validate();
-        Task Start();
+        /// <summary>
+        /// Starts the process. Throws <see cref="PsProcessProviderException"/> if the process is already running.
+        /// </summary>
+        void Start();
+
+        /// <summary>
+        /// Stops the process. Throws <see cref="PsProcessProviderException"/> if the process is not running.
+        /// </summary>
         void Stop();
+
     }
 }

+ 61 - 29
qdr.fnd.core.pqueue/Process/PsProcessProviderBase.cs

@@ -64,47 +64,40 @@ namespace qdr.fnd.core.pqueue.Process
             OnValidate();
         }
         /// <inheritdoc />
-        public async Task Start()
+        public void Start()
         {
             if (IsRunning)
                 throw new PsProcessProviderException(PsProcessProviderException.ErrorCodes.ProcessProviderIsRunning, GetType().Name, ItemId);
 
             Validate();
-            var dtStart = DateTime.Now;
             IsRunning = true;
             var timeout = GetArgumentValue<TimeSpan>(CS_ARG_PROCESS_TIMEOUT);
-            try
-            {
-                await OnProcess().TimeoutAfter(timeout).ContinueWith(task =>
-                {
-                    Log.Log(LogSeverityEnum.Info, $"Provider for ItemId='{ItemId}' done. Duration {(DateTime.Now - dtStart).ToReadableString()}.");
-                    if (ProcessDoneCallback != null)
-                        ProcessDoneCallback(ItemId, PsStatusEnum.DoneOk, "Succesfuly done.");
-                });
-                
-            }
-            catch (Exception e)
-            {
-                await OnProcessError(e).ContinueWith(task =>
-                {
-                    Log.Log(LogSeverityEnum.Error, $"Provider running failed. Duration {(DateTime.Now - dtStart).ToReadableString()}.", e);
-                    if (ProcessDoneCallback != null)
-                        ProcessDoneCallback(ItemId, PsStatusEnum.DoneFailed, e.Message);
-                });
-            }
-            finally
-            {
-                IsRunning = false;
-            }
+            Task.Factory.StartNew(()=>StartInternal(timeout), _cancelationToken!.Token);
         }
 
         /// <inheritdoc />
-        public async void Stop()
+        public void Stop()
         {
-               if (!IsRunning)
-                throw new PsProcessProviderException(PsProcessProviderException.ErrorCodes.ProcessProviderNotRunning, GetType().Name, ItemId);
+            if (!IsRunning)
+            throw new PsProcessProviderException(PsProcessProviderException.ErrorCodes.ProcessProviderNotRunning, GetType().Name, ItemId);
+   
+            _cancelationToken?.Cancel();
+            IsRunning = false;
+        }
 
-               //TODO: stops here
+        /// <summary>
+        /// Generates all arguments collection
+        /// </summary>
+        /// <returns>Full scoped arguments collection</returns>
+        public static IEnumerable<TypedArgument> CreateArguments()
+        {
+            var list = new List<TypedArgument>
+            {
+                new TypedArgument(CS_ARG_RESULT_CODE, typeof(long), true),
+                new TypedArgument(CS_ARG_RESULT_TEXT, typeof(string), true),
+                new TypedArgument(CS_ARG_PROCESS_TIMEOUT, typeof(TimeSpan), false)
+            };
+            return list;
         }
         #endregion
 
@@ -112,12 +105,18 @@ namespace qdr.fnd.core.pqueue.Process
         #region *** Protected Operations ***
         protected TValue? GetArgumentValue<TValue>(string name)
         {
+            if (string.IsNullOrEmpty(name))
+                throw new ArgumentNullException(nameof(name));
+
             if (Arguments.TryGetValue(name, out var arg))
                 return arg.GetTypedValue<TValue>();
             return default;
         }
         protected bool ContainsArgument(string name)
         {
+            if (string.IsNullOrEmpty(name))
+                throw new ArgumentNullException(nameof(name));
+
             return Arguments.ContainsKey(name);
         }
 
@@ -132,6 +131,9 @@ namespace qdr.fnd.core.pqueue.Process
         }
         protected virtual async Task OnProcessError(Exception exception)
         {
+            if (exception == null)
+                throw new ArgumentNullException(nameof(exception));
+
             if (ProcessStdOutputCallback != null)
                 ProcessStdOutputCallback(ItemId, exception.Message);
 
@@ -150,6 +152,36 @@ namespace qdr.fnd.core.pqueue.Process
             ProcessDoneCallback = null!;
             ProcessStdOutputCallback = null!;
         }
+
+        
+        private async Task StartInternal(TimeSpan timeout)
+        {
+            var dtStart = DateTime.Now;
+            try
+            {
+                await OnProcess().TimeoutAfter(timeout).ContinueWith(task =>
+                {
+                    Log.Log(LogSeverityEnum.Info, $"Provider for ItemId='{ItemId}' done. Duration {(DateTime.Now - dtStart).ToReadableString()}.");
+                    if (ProcessDoneCallback != null)
+                        ProcessDoneCallback(ItemId, PsStatusEnum.DoneOk, "Succesfuly done.");
+                    IsRunning = false;
+                });
+                
+            }
+            catch (Exception e)
+            {
+                await OnProcessError(e).ContinueWith(task =>
+                {
+                    Log.Log(LogSeverityEnum.Error, $"Provider running failed. Duration {(DateTime.Now - dtStart).ToReadableString()}.", e);
+                    if (ProcessDoneCallback != null)
+                        ProcessDoneCallback(ItemId, PsStatusEnum.DoneFailed, e.Message);
+                    IsRunning = false;
+                });
+            }
+        }
+
+        
+
         #endregion
 
     }

+ 7 - 0
qdr.fnd.core.pqueue/Process/PsProcessProviderDummy.cs

@@ -22,6 +22,13 @@ namespace qdr.fnd.core.pqueue.Process
         #endregion
 
         #region *** Overrides ***
+        public new static IEnumerable<TypedArgument> CreateArguments()
+        {
+            var list = new List<TypedArgument>(PsProcessProviderBase.CreateArguments());
+            list.Add(new TypedArgument(CS_ARG_INPUT_TEXT, typeof(string), true));
+            return list;    
+        }
+
         protected override void OnValidate()
         {
             base.OnValidate();