1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ppapi/tests/test_message_loop.h"
6
7#include "ppapi/c/pp_macros.h"
8#include "ppapi/cpp/core.h"
9#include "ppapi/cpp/logging.h"
10#include "ppapi/cpp/message_loop.h"
11#include "ppapi/cpp/module.h"
12#include "ppapi/tests/testing_instance.h"
13#include "ppapi/utility/threading/simple_thread.h"
14
15REGISTER_TEST_CASE(MessageLoop);
16
17TestMessageLoop::TestMessageLoop(TestingInstance* instance)
18    : TestCase(instance),
19      param_(kInvalid),
20      callback_factory_(this),
21      main_loop_task_ran_(instance->pp_instance()) {
22}
23
24TestMessageLoop::~TestMessageLoop() {
25}
26
27void TestMessageLoop::RunTests(const std::string& filter) {
28  RUN_TEST(Basics, filter);
29  RUN_TEST(Post, filter);
30}
31
32std::string TestMessageLoop::TestBasics() {
33  // The main thread message loop should be valid, and equal to the "current"
34  // one.
35  ASSERT_NE(0, pp::MessageLoop::GetForMainThread().pp_resource());
36  ASSERT_EQ(pp::MessageLoop::GetForMainThread().pp_resource(),
37            pp::MessageLoop::GetCurrent().pp_resource());
38
39  // We shouldn't be able to attach a new loop to the main thread.
40  pp::MessageLoop loop(instance_);
41  ASSERT_EQ(PP_ERROR_INPROGRESS, loop.AttachToCurrentThread());
42
43  // Nested loops aren't allowed.
44  ASSERT_EQ(PP_ERROR_INPROGRESS,
45            pp::MessageLoop::GetForMainThread().Run());
46
47  // We can't run on a loop that isn't attached to a thread.
48  ASSERT_EQ(PP_ERROR_WRONG_THREAD, loop.Run());
49
50  PASS();
51}
52
53std::string TestMessageLoop::TestPost() {
54  // Make sure we can post a task from the main thread back to the main thread.
55  pp::MessageLoop::GetCurrent().PostWork(callback_factory_.NewCallback(
56      &TestMessageLoop::SetParamAndQuitTask, kMainToMain));
57  main_loop_task_ran_.Wait();
58  ASSERT_EQ(param_, kMainToMain);
59  main_loop_task_ran_.Reset();
60
61  pp::SimpleThread thread(instance_);
62  // Post a task before the thread is started, to make sure it is run.
63  // TODO(dmichael): CompletionCallbackFactory is not 100% thread safe for
64  // posting tasks to a thread other than where the factory was created. It
65  // should be OK for this test, since we know that the
66  // CompletionCallbackFactory and its target object outlive all callbacks. But
67  // developers are likely to misuse CompletionCallbackFactory. Maybe we should
68  // make it safe to use a callback on another thread?
69  thread.message_loop().PostWork(callback_factory_.NewCallback(
70      &TestMessageLoop::EchoParamToMainTask, kBeforeStart));
71  ASSERT_TRUE(thread.Start());
72  main_loop_task_ran_.Wait();
73  ASSERT_EQ(param_, kBeforeStart);
74  main_loop_task_ran_.Reset();
75
76  // Now post another one after start. This is the more normal case.
77
78  // Nested loops aren't allowed.
79  ASSERT_EQ(PP_ERROR_INPROGRESS,
80            pp::MessageLoop::GetForMainThread().Run());
81  thread.message_loop().PostWork(callback_factory_.NewCallback(
82      &TestMessageLoop::EchoParamToMainTask, kAfterStart));
83  main_loop_task_ran_.Wait();
84  ASSERT_EQ(param_, kAfterStart);
85  main_loop_task_ran_.Reset();
86
87  // Quit and join the thread.
88  ASSERT_TRUE(thread.Join());
89
90  PASS();
91}
92
93void TestMessageLoop::SetParamAndQuitTask(int32_t result, TestParam param) {
94  PP_DCHECK(result == PP_OK);
95  param_ = param;
96  main_loop_task_ran_.Signal();
97}
98
99void TestMessageLoop::EchoParamToMainTask(int32_t result, TestParam param) {
100  PP_DCHECK(result == PP_OK);
101  pp::MessageLoop::GetForMainThread().PostWork(
102      callback_factory_.NewCallback(
103          &TestMessageLoop::SetParamAndQuitTask, param));
104}
105
106