Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / base / task_unittest.cc
1 /*
2  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10
11 #if defined(WEBRTC_POSIX)
12 #include <sys/time.h>
13 #endif  // WEBRTC_POSIX
14
15 // TODO: Remove this once the cause of sporadic failures in these
16 // tests is tracked down.
17 #include <iostream>
18
19 #if defined(WEBRTC_WIN)
20 #include "webrtc/base/win32.h"
21 #endif  // WEBRTC_WIN 
22
23 #include "webrtc/base/common.h"
24 #include "webrtc/base/gunit.h"
25 #include "webrtc/base/logging.h"
26 #include "webrtc/base/task.h"
27 #include "webrtc/base/taskrunner.h"
28 #include "webrtc/base/thread.h"
29 #include "webrtc/base/timeutils.h"
30 #include "webrtc/test/testsupport/gtest_disable.h"
31
32 namespace rtc {
33
34 static int64 GetCurrentTime() {
35   return static_cast<int64>(Time()) * 10000;
36 }
37
38 // feel free to change these numbers.  Note that '0' won't work, though
39 #define STUCK_TASK_COUNT 5
40 #define HAPPY_TASK_COUNT 20
41
42 // this is a generic timeout task which, when it signals timeout, will
43 // include the unique ID of the task in the signal (we don't use this
44 // in production code because we haven't yet had occasion to generate
45 // an array of the same types of task)
46
47 class IdTimeoutTask : public Task, public sigslot::has_slots<> {
48  public:
49   explicit IdTimeoutTask(TaskParent *parent) : Task(parent) {
50     SignalTimeout.connect(this, &IdTimeoutTask::OnLocalTimeout);
51   }
52
53   sigslot::signal1<const int> SignalTimeoutId;
54   sigslot::signal1<const int> SignalDoneId;
55
56   virtual int ProcessStart() {
57     return STATE_RESPONSE;
58   }
59
60   void OnLocalTimeout() {
61     SignalTimeoutId(unique_id());
62   }
63
64  protected:
65   virtual void Stop() {
66     SignalDoneId(unique_id());
67     Task::Stop();
68   }
69 };
70
71 class StuckTask : public IdTimeoutTask {
72  public:
73   explicit StuckTask(TaskParent *parent) : IdTimeoutTask(parent) {}
74   virtual int ProcessStart() {
75     return STATE_BLOCKED;
76   }
77 };
78
79 class HappyTask : public IdTimeoutTask {
80  public:
81   explicit HappyTask(TaskParent *parent) : IdTimeoutTask(parent) {
82     time_to_perform_ = rand() % (STUCK_TASK_COUNT / 2);
83   }
84   virtual int ProcessStart() {
85     if (ElapsedTime() > (time_to_perform_ * 1000 * 10000))
86       return STATE_RESPONSE;
87     else
88       return STATE_BLOCKED;
89   }
90
91  private:
92   int time_to_perform_;
93 };
94
95 // simple implementation of a task runner which uses Windows'
96 // GetSystemTimeAsFileTime() to get the current clock ticks
97
98 class MyTaskRunner : public TaskRunner {
99  public:
100   virtual void WakeTasks() { RunTasks(); }
101   virtual int64 CurrentTime() {
102     return GetCurrentTime();
103   }
104
105   bool timeout_change() const {
106     return timeout_change_;
107   }
108
109   void clear_timeout_change() {
110     timeout_change_ = false;
111   }
112  protected:
113   virtual void OnTimeoutChange() {
114     timeout_change_ = true;
115   }
116   bool timeout_change_;
117 };
118
119 //
120 // this unit test is primarily concerned (for now) with the timeout
121 // functionality in tasks.  It works as follows:
122 //
123 //   * Create a bunch of tasks, some "stuck" (ie., guaranteed to timeout)
124 //     and some "happy" (will immediately finish).
125 //   * Set the timeout on the "stuck" tasks to some number of seconds between
126 //     1 and the number of stuck tasks
127 //   * Start all the stuck & happy tasks in random order
128 //   * Wait "number of stuck tasks" seconds and make sure everything timed out
129
130 class TaskTest : public sigslot::has_slots<> {
131  public:
132   TaskTest() {}
133
134   // no need to delete any tasks; the task runner owns them
135   ~TaskTest() {}
136
137   void Start() {
138     // create and configure tasks
139     for (int i = 0; i < STUCK_TASK_COUNT; ++i) {
140       stuck_[i].task_ = new StuckTask(&task_runner_);
141       stuck_[i].task_->SignalTimeoutId.connect(this,
142                                                &TaskTest::OnTimeoutStuck);
143       stuck_[i].timed_out_ = false;
144       stuck_[i].xlat_ = stuck_[i].task_->unique_id();
145       stuck_[i].task_->set_timeout_seconds(i + 1);
146       LOG(LS_INFO) << "Task " << stuck_[i].xlat_ << " created with timeout "
147                    << stuck_[i].task_->timeout_seconds();
148     }
149
150     for (int i = 0; i < HAPPY_TASK_COUNT; ++i) {
151       happy_[i].task_ = new HappyTask(&task_runner_);
152       happy_[i].task_->SignalTimeoutId.connect(this,
153                                                &TaskTest::OnTimeoutHappy);
154       happy_[i].task_->SignalDoneId.connect(this,
155                                             &TaskTest::OnDoneHappy);
156       happy_[i].timed_out_ = false;
157       happy_[i].xlat_ = happy_[i].task_->unique_id();
158     }
159
160     // start all the tasks in random order
161     int stuck_index = 0;
162     int happy_index = 0;
163     for (int i = 0; i < STUCK_TASK_COUNT + HAPPY_TASK_COUNT; ++i) {
164       if ((stuck_index < STUCK_TASK_COUNT) &&
165           (happy_index < HAPPY_TASK_COUNT)) {
166         if (rand() % 2 == 1) {
167           stuck_[stuck_index++].task_->Start();
168         } else {
169           happy_[happy_index++].task_->Start();
170         }
171       } else if (stuck_index < STUCK_TASK_COUNT) {
172         stuck_[stuck_index++].task_->Start();
173       } else {
174         happy_[happy_index++].task_->Start();
175       }
176     }
177
178     for (int i = 0; i < STUCK_TASK_COUNT; ++i) {
179       std::cout << "Stuck task #" << i << " timeout is " <<
180           stuck_[i].task_->timeout_seconds() << " at " <<
181           stuck_[i].task_->timeout_time() << std::endl;
182     }
183
184     // just a little self-check to make sure we started all the tasks
185     ASSERT_EQ(STUCK_TASK_COUNT, stuck_index);
186     ASSERT_EQ(HAPPY_TASK_COUNT, happy_index);
187
188     // run the unblocked tasks
189     LOG(LS_INFO) << "Running tasks";
190     task_runner_.RunTasks();
191
192     std::cout << "Start time is " << GetCurrentTime() << std::endl;
193
194     // give all the stuck tasks time to timeout
195     for (int i = 0; !task_runner_.AllChildrenDone() && i < STUCK_TASK_COUNT;
196          ++i) {
197       Thread::Current()->ProcessMessages(1000);
198       for (int j = 0; j < HAPPY_TASK_COUNT; ++j) {
199         if (happy_[j].task_) {
200           happy_[j].task_->Wake();
201         }
202       }
203       LOG(LS_INFO) << "Polling tasks";
204       task_runner_.PollTasks();
205     }
206
207     // We see occasional test failures here due to the stuck tasks not having
208     // timed-out yet, which seems like it should be impossible. To help track
209     // this down we have added logging of the timing information, which we send
210     // directly to stdout so that we get it in opt builds too.
211     std::cout << "End time is " << GetCurrentTime() << std::endl;
212   }
213
214   void OnTimeoutStuck(const int id) {
215     LOG(LS_INFO) << "Timed out task " << id;
216
217     int i;
218     for (i = 0; i < STUCK_TASK_COUNT; ++i) {
219       if (stuck_[i].xlat_ == id) {
220         stuck_[i].timed_out_ = true;
221         stuck_[i].task_ = NULL;
222         break;
223       }
224     }
225
226     // getting a bad ID here is a failure, but let's continue
227     // running to see what else might go wrong
228     EXPECT_LT(i, STUCK_TASK_COUNT);
229   }
230
231   void OnTimeoutHappy(const int id) {
232     int i;
233     for (i = 0; i < HAPPY_TASK_COUNT; ++i) {
234       if (happy_[i].xlat_ == id) {
235         happy_[i].timed_out_ = true;
236         happy_[i].task_ = NULL;
237         break;
238       }
239     }
240
241     // getting a bad ID here is a failure, but let's continue
242     // running to see what else might go wrong
243     EXPECT_LT(i, HAPPY_TASK_COUNT);
244   }
245
246   void OnDoneHappy(const int id) {
247     int i;
248     for (i = 0; i < HAPPY_TASK_COUNT; ++i) {
249       if (happy_[i].xlat_ == id) {
250         happy_[i].task_ = NULL;
251         break;
252       }
253     }
254
255     // getting a bad ID here is a failure, but let's continue
256     // running to see what else might go wrong
257     EXPECT_LT(i, HAPPY_TASK_COUNT);
258   }
259
260   void check_passed() {
261     EXPECT_TRUE(task_runner_.AllChildrenDone());
262
263     // make sure none of our happy tasks timed out
264     for (int i = 0; i < HAPPY_TASK_COUNT; ++i) {
265       EXPECT_FALSE(happy_[i].timed_out_);
266     }
267
268     // make sure all of our stuck tasks timed out
269     for (int i = 0; i < STUCK_TASK_COUNT; ++i) {
270       EXPECT_TRUE(stuck_[i].timed_out_);
271       if (!stuck_[i].timed_out_) {
272         std::cout << "Stuck task #" << i << " timeout is at "
273             << stuck_[i].task_->timeout_time() << std::endl;        
274       }
275     }
276
277     std::cout.flush();
278   }
279
280  private:
281   struct TaskInfo {
282     IdTimeoutTask *task_;
283     bool timed_out_;
284     int xlat_;
285   };
286
287   MyTaskRunner task_runner_;
288   TaskInfo stuck_[STUCK_TASK_COUNT];
289   TaskInfo happy_[HAPPY_TASK_COUNT];
290 };
291
292 TEST(start_task_test, Timeout) {
293   TaskTest task_test;
294   task_test.Start();
295   task_test.check_passed();
296 }
297
298 // Test for aborting the task while it is running
299
300 class AbortTask : public Task {
301  public:
302   explicit AbortTask(TaskParent *parent) : Task(parent) {
303     set_timeout_seconds(1);
304   }
305
306   virtual int ProcessStart() {
307     Abort();
308     return STATE_NEXT;
309   }
310  private:
311   DISALLOW_EVIL_CONSTRUCTORS(AbortTask);
312 };
313
314 class TaskAbortTest : public sigslot::has_slots<> {
315  public:
316   TaskAbortTest() {}
317
318   // no need to delete any tasks; the task runner owns them
319   ~TaskAbortTest() {}
320
321   void Start() {
322     Task *abort_task = new AbortTask(&task_runner_);
323     abort_task->SignalTimeout.connect(this, &TaskAbortTest::OnTimeout);
324     abort_task->Start();
325
326     // run the task
327     task_runner_.RunTasks();
328   }
329
330  private:
331   void OnTimeout() {
332     FAIL() << "Task timed out instead of aborting.";
333   }
334
335   MyTaskRunner task_runner_;
336   DISALLOW_EVIL_CONSTRUCTORS(TaskAbortTest);
337 };
338
339 TEST(start_task_test, Abort) {
340   TaskAbortTest abort_test;
341   abort_test.Start();
342 }
343
344 // Test for aborting a task to verify that it does the Wake operation
345 // which gets it deleted.
346
347 class SetBoolOnDeleteTask : public Task {
348  public:
349   SetBoolOnDeleteTask(TaskParent *parent, bool *set_when_deleted)
350     : Task(parent),
351       set_when_deleted_(set_when_deleted) {
352     EXPECT_TRUE(NULL != set_when_deleted);
353     EXPECT_FALSE(*set_when_deleted);
354   }
355
356   virtual ~SetBoolOnDeleteTask() {
357     *set_when_deleted_ = true;
358   }
359
360   virtual int ProcessStart() {
361     return STATE_BLOCKED;
362   }
363
364  private:
365   bool* set_when_deleted_;
366   DISALLOW_EVIL_CONSTRUCTORS(SetBoolOnDeleteTask);
367 };
368
369 class AbortShouldWakeTest : public sigslot::has_slots<> {
370  public:
371   AbortShouldWakeTest() {}
372
373   // no need to delete any tasks; the task runner owns them
374   ~AbortShouldWakeTest() {}
375
376   void Start() {
377     bool task_deleted = false;
378     Task *task_to_abort = new SetBoolOnDeleteTask(&task_runner_, &task_deleted);
379     task_to_abort->Start();
380
381     // Task::Abort() should call TaskRunner::WakeTasks(). WakeTasks calls
382     // TaskRunner::RunTasks() immediately which should delete the task.
383     task_to_abort->Abort();
384     EXPECT_TRUE(task_deleted);
385
386     if (!task_deleted) {
387       // avoid a crash (due to referencing a local variable)
388       // if the test fails.
389       task_runner_.RunTasks();
390     }
391   }
392
393  private:
394   void OnTimeout() {
395     FAIL() << "Task timed out instead of aborting.";
396   }
397
398   MyTaskRunner task_runner_;
399   DISALLOW_EVIL_CONSTRUCTORS(AbortShouldWakeTest);
400 };
401
402 TEST(start_task_test, AbortShouldWake) {
403   AbortShouldWakeTest abort_should_wake_test;
404   abort_should_wake_test.Start();
405 }
406
407 // Validate that TaskRunner's OnTimeoutChange gets called appropriately
408 //  * When a task calls UpdateTaskTimeout
409 //  * When the next timeout task time, times out
410 class TimeoutChangeTest : public sigslot::has_slots<> {
411  public:
412   TimeoutChangeTest()
413     : task_count_(ARRAY_SIZE(stuck_tasks_)) {}
414
415   // no need to delete any tasks; the task runner owns them
416   ~TimeoutChangeTest() {}
417
418   void Start() {
419     for (int i = 0; i < task_count_; ++i) {
420       stuck_tasks_[i] = new StuckTask(&task_runner_);
421       stuck_tasks_[i]->set_timeout_seconds(i + 2);
422       stuck_tasks_[i]->SignalTimeoutId.connect(this,
423                                                &TimeoutChangeTest::OnTimeoutId);
424     }
425
426     for (int i = task_count_ - 1; i >= 0; --i) {
427       stuck_tasks_[i]->Start();
428     }
429     task_runner_.clear_timeout_change();
430
431     // At this point, our timeouts are set as follows
432     // task[0] is 2 seconds, task[1] at 3 seconds, etc.
433
434     stuck_tasks_[0]->set_timeout_seconds(2);
435     // Now, task[0] is 2 seconds, task[1] at 3 seconds...
436     // so timeout change shouldn't be called.
437     EXPECT_FALSE(task_runner_.timeout_change());
438     task_runner_.clear_timeout_change();
439
440     stuck_tasks_[0]->set_timeout_seconds(1);
441     // task[0] is 1 seconds, task[1] at 3 seconds...
442     // The smallest timeout got smaller so timeout change be called.
443     EXPECT_TRUE(task_runner_.timeout_change());
444     task_runner_.clear_timeout_change();
445
446     stuck_tasks_[1]->set_timeout_seconds(2);
447     // task[0] is 1 seconds, task[1] at 2 seconds...
448     // The smallest timeout is still 1 second so no timeout change.
449     EXPECT_FALSE(task_runner_.timeout_change());
450     task_runner_.clear_timeout_change();
451
452     while (task_count_ > 0) {
453       int previous_count = task_count_;
454       task_runner_.PollTasks();
455       if (previous_count != task_count_) {
456         // We only get here when a task times out.  When that
457         // happens, the timeout change should get called because
458         // the smallest timeout is now in the past.
459         EXPECT_TRUE(task_runner_.timeout_change());
460         task_runner_.clear_timeout_change();
461       }
462       Thread::Current()->socketserver()->Wait(500, false);
463     }
464   }
465
466  private:
467   void OnTimeoutId(const int id) {
468     for (int i = 0; i < ARRAY_SIZE(stuck_tasks_); ++i) {
469       if (stuck_tasks_[i] && stuck_tasks_[i]->unique_id() == id) {
470         task_count_--;
471         stuck_tasks_[i] = NULL;
472         break;
473       }
474     }
475   }
476
477   MyTaskRunner task_runner_;
478   StuckTask* (stuck_tasks_[3]);
479   int task_count_;
480   DISALLOW_EVIL_CONSTRUCTORS(TimeoutChangeTest);
481 };
482
483 TEST(start_task_test, TimeoutChange) {
484   TimeoutChangeTest timeout_change_test;
485   timeout_change_test.Start();
486 }
487
488 class DeleteTestTaskRunner : public TaskRunner {
489  public:
490   DeleteTestTaskRunner() {
491   }
492   virtual void WakeTasks() { }
493   virtual int64 CurrentTime() {
494     return GetCurrentTime();
495   }
496  private:
497   DISALLOW_EVIL_CONSTRUCTORS(DeleteTestTaskRunner);
498 };
499
500 TEST(unstarted_task_test, DeleteTask) {
501   // This test ensures that we don't
502   // crash if a task is deleted without running it.
503   DeleteTestTaskRunner task_runner;
504   HappyTask* happy_task = new HappyTask(&task_runner);
505   happy_task->Start();
506
507   // try deleting the task directly
508   HappyTask* child_happy_task = new HappyTask(happy_task);
509   delete child_happy_task;
510
511   // run the unblocked tasks
512   task_runner.RunTasks();
513 }
514
515 TEST(unstarted_task_test, DoNotDeleteTask1) {
516   // This test ensures that we don't
517   // crash if a task runner is deleted without
518   // running a certain task.
519   DeleteTestTaskRunner task_runner;
520   HappyTask* happy_task = new HappyTask(&task_runner);
521   happy_task->Start();
522
523   HappyTask* child_happy_task = new HappyTask(happy_task);
524   child_happy_task->Start();
525
526   // Never run the tasks
527 }
528
529 TEST(unstarted_task_test, DoNotDeleteTask2) {
530   // This test ensures that we don't
531   // crash if a taskrunner is delete with a
532   // task that has never been started.
533   DeleteTestTaskRunner task_runner;
534   HappyTask* happy_task = new HappyTask(&task_runner);
535   happy_task->Start();
536
537   // Do not start the task.
538   // Note: this leaks memory, so don't do this.
539   // Instead, always run your tasks or delete them.
540   new HappyTask(happy_task);
541
542   // run the unblocked tasks
543   task_runner.RunTasks();
544 }
545
546 }  // namespace rtc