OSDN Git Service

na-get-lib,新構造タスクのキャンセル処理を修正。
[applistation/AppliStation.git] / test-na-get-lib / NaGetTaskSet2Test.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Threading;
4 using NUnit.Framework;
5 using NaGet.SubCommands.SubTask;
6 using NaGet.Tasks;
7
8 using NaGet.SubCommands;
9
10 namespace test_na_get_lib
11 {
12         [TestFixture]
13         public class NaGetTaskSet2Test
14         {
15                 [Test]
16                 public void SubTasks()
17                 {
18                         IList<string> subTaskMsgs = new string[]{"0", "1", "2"};
19                         IList<NaGetSubTask> subTasks = new NaGetSubTask[] {
20                                 new FunctionalSubTask(null, null),
21                                 new FunctionalSubTask(null, null),
22                                 new FunctionalSubTask(null, null),
23                         };
24                         ATaskSetForTest task = new ATaskSetForTest(subTaskMsgs, subTasks);
25                         
26                         Assert.AreEqual(subTaskMsgs, task.TaskSetNames);
27                 }
28                 
29                 [Test]
30                 public void NotifyGoToNextSubTask()
31                 {
32                         ATaskSetForTest task = null;
33                         IList<NaGetSubTask> subTasks = null;
34                         
35                         IList<string> subTaskMsgs = new string[]{"0", "1", "2"};
36                         int blockCount = 0;
37                         Action<object>[] funcs = new Action<object>[] {
38                                 delegate (object arg) {
39                                         blockCount ++;
40                                         Assert.AreEqual(0, task.CurrentTaskSetIndex);
41                                         Assert.IsTrue(task.Running);
42                                         Assert.IsTrue(subTasks[0].Running);
43                                         Assert.IsFalse(subTasks[1].Running);
44                                 },
45                                 delegate (object arg) {
46                                         blockCount ++;
47                                         Assert.IsTrue(task.Running);
48                                         Assert.IsTrue(subTasks[0].Done);
49                                         Assert.IsTrue(subTasks[1].Running);
50                                         Assert.IsFalse(subTasks[2].Running);
51                                 },
52                                 delegate (object arg) {
53                                         blockCount ++;
54                                         Assert.IsTrue(task.Running);
55                                         Assert.IsTrue(subTasks[1].Done);
56                                         Assert.IsTrue(subTasks[2].Running);
57                                 }
58                         };
59                         subTasks = new NaGetSubTask[] {
60                                 new FunctionalSubTask(funcs[0], null),
61                                 new FunctionalSubTask(funcs[1], null),
62                                 new FunctionalSubTask(funcs[2], null),
63                         };
64                         task = new ATaskSetForTest(subTaskMsgs, subTasks);
65                         blockCount = 0;
66                         task.Run();
67                         Assert.IsTrue(task.Done);
68                         Assert.IsTrue(subTasks[0].Done);
69                         Assert.IsTrue(subTasks[1].Done);
70                         Assert.IsTrue(subTasks[2].Done);
71                         Assert.AreEqual(3, blockCount);
72                 }
73                 
74                 [Test]
75                 public void NotifyGoToSubTask()
76                 {
77                         ATaskSetForTest task = null;
78                         IList<NaGetSubTask> subTasks = null;
79                         
80                         IList<string> subTaskMsgs = new string[]{"0", "1"};
81                         List<int> blockPass = new List<int>();
82                         Action<object>[] funcs = new Action<object>[] {
83                                 delegate (object arg) {
84                                         blockPass.Add(0);
85                                         Assert.AreEqual(0, task.CurrentTaskSetIndex);
86                                         Assert.IsTrue(task.Running);
87                                         Assert.IsTrue(subTasks[0].Running);
88                                         Assert.IsFalse(subTasks[1].Running);
89                                 },
90                                 delegate (object arg) {
91                                         blockPass.Add(1);
92                                         Assert.IsTrue(task.Running);
93                                         Assert.IsTrue(subTasks[0].Done);
94                                         Assert.IsTrue(subTasks[1].Running);
95                                         
96                                         if (blockPass.Count < 6) {
97                                                 throw new JumpTaskException(0);
98                                         }
99                                 }
100                         };
101                         subTasks = new NaGetSubTask[] {
102                                 new FunctionalSubTask(funcs[0], null),
103                                 new FunctionalSubTask(funcs[1], null),
104                         };
105                         task = new ATaskSetForTest(subTaskMsgs, subTasks);
106                         blockPass.Clear();
107                         task.Run();
108                         Assert.IsTrue(task.Done);
109                         Assert.AreEqual(new int[]{0, 1, 0, 1, 0, 1}, blockPass.ToArray());
110                 }
111                 
112                 [Test]
113                 public void TaskEventRaised()
114                 {
115                         ATaskSetForTest task = null;
116                         IList<string> subTaskMsgs = new string[]{"0", "1"};
117                         IList<NaGetSubTask> subTasks = null;
118                         List<TaskEventArgs> taskEventList = new List<TaskEventArgs>();
119                         List<TaskEventArgs> subtaskEventList = new List<TaskEventArgs>();
120                         
121                         Action<ASubTaskForEventTest> subTaskBody = delegate(ASubTaskForEventTest subTask) {
122                                 subTask.RaiseTaskSetEventExt(TaskEventType.STARTED,     "S", -1);
123                                 subTask.RaiseTaskSetEventExt(TaskEventType.INFO,                "I", 0);
124                                 subTask.RaiseTaskSetEventExt(TaskEventType.PING,                "P", 50);
125                                 subTask.RaiseTaskSetEventExt(TaskEventType.WARNING,     "W", 75);
126                                 subTask.RaiseTaskSetEventExt(TaskEventType.COMPLETED,"C", 100);
127                         };
128                         subTasks = new NaGetSubTask[] {
129                                 new ASubTaskForEventTest(subTaskBody),
130                                 new ASubTaskForEventTest(subTaskBody),
131                         };
132                         task = new ATaskSetForTest(subTaskMsgs, subTasks);
133                         
134                         EventHandler<TaskEventArgs> taskEventHandler = delegate(object sender, TaskEventArgs e) {
135                                 Assert.AreEqual(task, sender);
136                                 taskEventList.Add(e);
137                         };
138                         EventHandler<TaskEventArgs> subtaskEventHandler = delegate(object sender, TaskEventArgs e) {
139                                 Assert.AreEqual(subTasks[task.CurrentTaskSetIndex], sender);
140                                 subtaskEventList.Add(e);
141                         };
142                         
143                         // イベントをフックしているときの動作確認
144                         
145                         task.TaskEventRaised += taskEventHandler;
146                         task.SubTaskEventRaised += subtaskEventHandler;
147                         
148                         taskEventList.Clear();
149                         subtaskEventList.Clear();
150                         task.Run();
151                         Assert.IsTrue(task.Done);
152                         
153                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.STARTED,                   "", 0),                 taskEventList[0]);
154                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.STARTED_SUBTASK,   "0", 0),                taskEventList[1]);
155                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.PING,                              null, 0),               taskEventList[2]);
156                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.PING,                              null, 25),              taskEventList[3]);
157                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.PING,                              null, 37.5f),   taskEventList[4]);
158                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.PING,                              null, 50),              taskEventList[5]);
159                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.COMPLETED_SUBTASK,"0", 50),                taskEventList[6]);
160                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.STARTED_SUBTASK,   "1", 50),               taskEventList[7]);
161                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.PING,                              null, 50),              taskEventList[8]);
162                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.PING,                              null, 75),              taskEventList[9]);
163                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.PING,                              null, 87.5f),   taskEventList[10]);
164                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.PING,                              null, 100),     taskEventList[11]);
165                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.COMPLETED_SUBTASK,"1", 100),               taskEventList[12]);
166                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.COMPLETED,         "", 100),               taskEventList[13]);
167                         Assert.AreEqual(14, taskEventList.Count);
168                         
169                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.STARTED,   "S", -1),       subtaskEventList[0]);
170                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.INFO,              "I", 0),        subtaskEventList[1]);
171                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.PING,              "P", 50),       subtaskEventList[2]);
172                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.WARNING,   "W", 75),       subtaskEventList[3]);
173                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.COMPLETED,"C", 100),       subtaskEventList[4]);
174                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.STARTED,   "S", -1),       subtaskEventList[5]);
175                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.INFO,              "I", 0),        subtaskEventList[6]);
176                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.PING,              "P", 50),       subtaskEventList[7]);
177                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.WARNING,   "W", 75),       subtaskEventList[8]);
178                         AreSameTaskEventArgs(new TaskEventArgs(TaskEventType.COMPLETED,"C", 100),       subtaskEventList[9]);
179                         Assert.AreEqual(10, subtaskEventList.Count);
180                         
181                         // イベントをフックしていないときの動作確認
182                         
183                         task.TaskEventRaised -= taskEventHandler;
184                         task.SubTaskEventRaised -= subtaskEventHandler;
185                         
186                         taskEventList.Clear();
187                         subtaskEventList.Clear();
188                         task.Run();
189                         Assert.IsTrue(task.Done);
190                 }
191                 
192                 [Test]
193                 public void Cancel()
194                 {
195                         ATaskSetForTest task = null;
196                         IList<string> subTaskMsgs = new string[]{"0"};
197                         IList<NaGetSubTask> subTasks = null;
198                         
199                         Action<ASubTaskForEventTest> subTaskBody = delegate(ASubTaskForEventTest subTask) {
200                                 subTask.RaiseTaskSetEventExt(TaskEventType.STARTED,     "S", 0);
201                                 Thread.Sleep(50);
202                                 subTask.RaiseTaskSetEventExt(TaskEventType.COMPLETED,"C", 100);
203                         };
204                         bool? cancelRetVal = null;
205                         ParameterizedThreadStart cancelThread = new ParameterizedThreadStart(
206                                 delegate (object param) {
207                                         Thread.Sleep((int) param);
208                                         cancelRetVal = task.Cancel();
209                                 }
210                         );
211                         
212                         // キャンセル無効なときはキャンセル処理は行われない。
213                         
214                         subTasks = new NaGetSubTask[] { new ASubTaskForEventTest(subTaskBody) };
215                         task = new ATaskSetForTest(subTaskMsgs, subTasks);
216                         task._Cancelable = false;
217                         cancelRetVal = null;
218                         (new Thread(cancelThread)).Start((object) 10);
219                         task.Run();
220                         Assert.AreEqual(false, cancelRetVal);
221                         Assert.IsTrue(task.Done);
222                         Assert.IsFalse(task.Cancelable);
223                         
224                         // すでに終了しているものにはキャンセルはできない
225                         Assert.IsFalse(task.Cancel());
226                         
227                         // キャンセル有効なときでキャンセルするとき
228                         subTasks = new NaGetSubTask[] { new ASubTaskForEventTest(subTaskBody) };
229                         task = new ATaskSetForTest(subTaskMsgs, subTasks);
230                         task._Cancelable = true;
231                         cancelRetVal = null;
232                         (new Thread(cancelThread)).Start((object) 10);
233                         task.Run();
234                         Assert.AreEqual(true, cancelRetVal);
235                         Assert.IsTrue(task.Cancelled);
236                         Assert.IsFalse(task.Cancelable);
237                         Assert.IsTrue(task.Done);
238                         
239                         // すでにキャンセルしているものにはキャンセルはできない
240                         Assert.IsFalse(task.Cancel());
241                         
242                         // キャンセルトリガの挙動確認
243                         bool cancelBlockPassed = false;
244                         subTasks = new NaGetSubTask[] { new ASubTaskForEventTest(subTaskBody) };
245                         task = new ATaskSetForTest(subTaskMsgs, subTasks);
246                         task._Cancelable = true;
247                         task.OnCancelCalled += delegate(object arg) {
248                                 Assert.IsFalse(task.Cancelled);
249                                 Assert.IsTrue(task.Running);
250                                 Assert.IsFalse(task.Cancelable);
251                                 Assert.IsFalse(task.Cancel());
252                                 
253                                 ASubTaskForEventTest subTask = ((ASubTaskForEventTest) subTasks[0]);
254                                 Assert.IsFalse(subTask.Cancelled);
255                                 Assert.IsTrue(subTask.Running);
256                                 Assert.IsFalse(subTask.Cancelable);
257                                 Assert.IsFalse(subTask.Cancel());
258                                 
259                                 cancelBlockPassed = true;
260                         };
261                         ((ASubTaskForEventTest) subTasks[0])._Cancelable = true;
262                         cancelRetVal = null;
263                         (new Thread(cancelThread)).Start((object) 10);
264                         task.Run();
265                         Assert.AreEqual(true, cancelRetVal);
266                         Assert.IsTrue(task.Cancelled);
267                         Assert.IsFalse(task.Cancelable);
268                         Assert.IsTrue(task.Done);
269                         Assert.IsTrue(((ASubTaskForEventTest) subTasks[0]).Cancelled);
270                         Assert.IsFalse(((ASubTaskForEventTest) subTasks[0]).Cancelable);
271                         Assert.IsTrue(cancelBlockPassed);
272                 }
273                 
274                 [Test]
275                 public void RaiseTaskSetQueryEvent()
276                 {
277                         IList<string> subTaskMsgs = new string[]{"0"};
278                         ATaskSetForTest task = null;
279                         Action<object> subTaskBody = null;
280                         IList<NaGetSubTask> subTasks = null;
281                         bool blockPassed = false;
282                         
283                         subTaskBody = delegate (object arg) {
284                                 NaGetTaskQueryResult ret;
285                                 ret = task.RaiseTaskSetQueryEventExt("#1", NaGetTaskQueryResult.CONTINUE);
286                                 Assert.AreEqual(NaGetTaskQueryResult.CANCELED_AUTOMATICALLY, ret);
287                                 
288                                 blockPassed = true;
289                         };
290                         subTasks = new NaGetSubTask[] {
291                                 new FunctionalSubTask(subTaskBody, null),
292                         };
293                         task = new ATaskSetForTest(subTaskMsgs, subTasks);
294                         task.Run();
295                         Assert.IsTrue(task.Done);
296                         Assert.IsTrue(blockPassed);
297                         
298                         
299                         subTaskBody = delegate (object arg) {
300                                 NaGetTaskQueryResult ret;
301                                 ret = task.RaiseTaskSetQueryEventExt("#1", NaGetTaskQueryResult.CONTINUE);
302                                 Assert.AreEqual(NaGetTaskQueryResult.CONTINUE, ret);
303                                 ret = task.RaiseTaskSetQueryEventExt("#2", (NaGetTaskQueryResult.RETRY | NaGetTaskQueryResult.CANCEL));
304                                 Assert.AreEqual(NaGetTaskQueryResult.RETRY, ret);
305                                 
306                                 blockPassed = true;
307                         };
308                         subTasks = new NaGetSubTask[] {
309                                 new FunctionalSubTask(subTaskBody, null),
310                         };
311                         task = new ATaskSetForTest(subTaskMsgs, subTasks);
312                         task.TaskQueryRaised += delegate (object sender, NaGetTaskQueryArgs e) {
313                                 if (e.Message == "#1") {
314                                         Assert.AreEqual(NaGetTaskQueryResult.CONTINUE, e.SelectionFlag);
315                                         return NaGetTaskQueryResult.CONTINUE;
316                                 } else {
317                                         Assert.AreEqual((NaGetTaskQueryResult.RETRY | NaGetTaskQueryResult.CANCEL), e.SelectionFlag);
318                                         return NaGetTaskQueryResult.RETRY;
319                                 }
320                         };
321                         task.Run();
322                         Assert.IsTrue(task.Done);
323                         Assert.IsTrue(blockPassed);
324                 }
325                 
326                 private void AreSameTaskEventArgs(TaskEventArgs expected, TaskEventArgs actual)
327                 {
328                         string expectedLabel= string.Format("[type={0}, message=\"{1}\", percent={2}%]", expected.Type, expected.TaskMessage, expected.ProgressPercent);
329                         string actualLabel      = string.Format("[type={0}, message=\"{1}\", percent={2}%]", actual.Type, actual.TaskMessage, actual.ProgressPercent);
330                         string failtureMsg = string.Format("Expected: {0}\tBut was: {1}", expectedLabel, actualLabel);
331                         
332                         Assert.AreEqual(expected.Type, actual.Type, failtureMsg);
333                         Assert.AreEqual(expected.TaskMessage, actual.TaskMessage, failtureMsg);
334                         Assert.AreEqual(expected.ProgressPercent, actual.ProgressPercent, failtureMsg);
335                 }
336                 
337                 #region テスト用派生クラス
338                 
339                 private class JumpTaskException : Exception
340                 {
341                         public int subTaskId = -1;
342                         
343                         /// <summary>
344                         /// コンストラクタ
345                         /// </summary>
346                         /// <param name="id">ジャンプ先のサブタスクID</param>
347                         public JumpTaskException(int id)
348                         {
349                                 subTaskId = id;
350                         }
351                 }
352                 
353                 private class ATaskSetForTest : NaGetTaskSet2
354                 {
355                         public event Action<object> OnCancelCalled;
356                         
357                         public ATaskSetForTest(IList<string> subTaskMsgs, IList<NaGetSubTask> subTasks)
358                         {
359                                 initSubTask();
360                                 Assert.IsTrue(subTaskMsgs.Count == subTasks.Count);
361                                 
362                                 for (int i = 0; i < subTaskMsgs.Count; i++) {
363                                         registSubTask(subTaskMsgs[i], subTasks[i]);
364                                 }
365                                 
366                                 this.onCancelCalled += new Action<object>(delegate (object arg) {
367                                                                                 if (OnCancelCalled != null) {
368                                                                                                                                 OnCancelCalled(arg);
369                                                                                                                         }
370                                                                           });
371                         }
372                         
373                         public override void Run()
374                         {
375                                 NotifyStarted();
376                                 RaiseTaskSetEvent(TaskEventType.STARTED, string.Empty);
377                                 try {
378                                         while (hasMoreSubTask) {
379                                                 try {
380                                                         RaiseTaskSetEvent(TaskEventType.STARTED_SUBTASK, currentSubTaskName);
381                                                         currentSubTask.Run();
382                                                         RaiseTaskSetEvent(TaskEventType.COMPLETED_SUBTASK, currentSubTaskName);
383                                                         
384                                                         NotifyGoToNextSubTask();
385                                                 } catch (JumpTaskException ex) {
386                                                         NotifyGoToSubTask(ex.subTaskId);
387                                                 }
388                                         }
389                                 } finally {
390                                         if (cancelCalled) {
391                                                 NotifyCancelled();
392                                                 RaiseTaskSetEvent(TaskEventType.CANCELED, string.Empty);
393                                         } else {
394                                                 NotifyCompleted();
395                                                 RaiseTaskSetEvent(TaskEventType.COMPLETED, string.Empty);
396                                         }
397                                 }
398                         }
399                         
400                         private bool cancelable = false;
401                         
402                         public override bool Cancelable {
403                                 get { return cancelable && !cancelCalled && !isCancelled; }
404                         }
405                         
406                         public virtual bool _Cancelable {
407                                 set { cancelable = value; }
408                         }
409                         
410                         public NaGetTaskQueryResult RaiseTaskSetQueryEventExt(string message, NaGetTaskQueryResult selection)
411                         {
412                                 return RaiseTaskSetQueryEvent(message, selection);
413                         }
414                 }
415                 
416                 private class ASubTaskForEventTest : NaGetSubTask
417                 {
418                         private Action<ASubTaskForEventTest> func = null;
419                         
420                         public ASubTaskForEventTest(Action<ASubTaskForEventTest> func)
421                         {
422                                 this.func = func;
423                         }
424                         
425                         public void RaiseTaskSetEventExt(TaskEventType type, string message, float percent)
426                         {
427                                 RaiseTaskSetEvent(type, message, percent);
428                         }
429                         
430                         public override void Run()
431                         {
432                                 NotifyStarted();
433                                 try {
434                                         this.func(this);
435                                 } finally {
436                                         if (cancelCalled) {
437                                                 NotifyCancelled();
438                                         } else {
439                                                 NotifyCompleted();
440                                         }
441                                 }
442                         }
443                         
444                         private bool cancelable = false;
445                         
446                         public override bool Cancelable {
447                                 get { return cancelable && !cancelCalled && !Cancelled; }
448                         }
449                         
450                         public virtual bool _Cancelable {
451                                 set { cancelable = value; }
452                         }
453                         
454                         private bool cancelCalled = true;
455                         
456                         public override bool Cancel()
457                         {
458                                 if (Cancelable) {
459                                         cancelCalled = true;
460                                         return true;
461                                 } else {
462                                         return base.Cancel();
463                                 }
464                         }
465                 }
466                 
467                 #endregion
468                 
469         }
470 }