blob: 4e601b074236e883ade2c940bed98a3e8d032d09 [file] [log] [blame]
[email protected]399ed422012-12-27 19:58:001// 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 "base/sequence_checker_impl.h"
6
7#include <cstddef>
8
9#include "base/bind.h"
10#include "base/compiler_specific.h"
11#include "base/location.h"
12#include "base/memory/ref_counted.h"
13#include "base/message_loop.h"
14#include "base/sequenced_task_runner.h"
15#include "base/threading/thread.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18namespace base {
19
20namespace {
21
22// Implementation of SequencedTaskRunner that lets us control what
23// RunsTasksOnCurrentThread() returns.
24class FakeTaskRunner : public SequencedTaskRunner {
25 public:
26 FakeTaskRunner() : runs_tasks_on_current_thread_(false) {}
27
28 void SetRunsTasksOnCurrentThread(bool runs_tasks_on_current_thread) {
29 runs_tasks_on_current_thread_ = runs_tasks_on_current_thread;
30 }
31
32 // SequencedTaskRunner implementation.
33 virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
34 const Closure& task,
35 TimeDelta delay) OVERRIDE {
36 ADD_FAILURE();
37 return false;
38 }
39
40 virtual bool PostNonNestableDelayedTask(
41 const tracked_objects::Location& from_here,
42 const Closure& task,
43 TimeDelta delay) OVERRIDE {
44 ADD_FAILURE();
45 return false;
46 }
47
48 virtual bool RunsTasksOnCurrentThread() const OVERRIDE {
49 return runs_tasks_on_current_thread_;
50 }
51
52 protected:
53 virtual ~FakeTaskRunner() {}
54
55 private:
56 bool runs_tasks_on_current_thread_;
57};
58
59class SequenceCheckerImplTest : public ::testing::Test {
60};
61
62// Create a SequenceCheckerImpl with a SequencedTaskRunner and make
63// sure that CalledOnValidSequence() returns what that SequencedTaskRunner
64// returns for RunsTasksOnCurrentThread().
65TEST_F(SequenceCheckerImplTest, CalledOnValidSequenceNonNull) {
66 const scoped_refptr<FakeTaskRunner> fake_sequenced_task_runner(
67 new FakeTaskRunner());
68
69 const SequenceCheckerImpl sequence_checker_impl(fake_sequenced_task_runner);
70 EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence());
71
72 fake_sequenced_task_runner->SetRunsTasksOnCurrentThread(true);
73 EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence());
74
75 fake_sequenced_task_runner->SetRunsTasksOnCurrentThread(false);
76 EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence());
77}
78
79void ExpectCalledOnValidSequence(
80 const tracked_objects::Location& location,
81 const SequenceCheckerImpl* sequence_checker_impl,
82 bool expected_value) {
83 EXPECT_EQ(expected_value, sequence_checker_impl->CalledOnValidSequence())
84 << location.ToString();
85}
86
87// Create a SequenceCheckerImpl with no SequencedTaskRunner and make
88// sure that CalledOnValidSequence() behaves like
89// ThreadChecker::CalledOnValidThread().
90TEST_F(SequenceCheckerImplTest, CalledOnValidSequenceNull) {
91 const SequenceCheckerImpl sequence_checker_impl(NULL);
92 EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence());
93
94 {
95 Thread thread("thread 1");
96 ASSERT_TRUE(thread.Start());
97 thread.message_loop()->PostTask(
98 FROM_HERE, Bind(&ExpectCalledOnValidSequence,
99 FROM_HERE,
100 Unretained(&sequence_checker_impl),
101 false));
102 }
103
104 EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence());
105}
106
107// Create a SequenceCheckerImpl with a SequencedTaskRunner and switch
108// it to another one. CalledOnValidSequence() should return what its
109// underlying SequencedTaskRunner returns for
110// RunsTasksOnCurrentThread().
111TEST_F(SequenceCheckerImplTest, ChangeSequenceNonNull) {
112 const scoped_refptr<FakeTaskRunner> fake_sequenced_task_runner1(
113 new FakeTaskRunner());
114
115 const scoped_refptr<FakeTaskRunner> fake_sequenced_task_runner2(
116 new FakeTaskRunner());
117
118 SequenceCheckerImpl sequence_checker_impl(fake_sequenced_task_runner1);
119 EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence());
120
121 fake_sequenced_task_runner2->SetRunsTasksOnCurrentThread(true);
122 EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence());
123
124 sequence_checker_impl.ChangeSequence(fake_sequenced_task_runner2);
125 EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence());
126
127 sequence_checker_impl.ChangeSequence(fake_sequenced_task_runner1);
128 EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence());
129}
130
131// Create a SequenceCheckerImpl with a SequencedTaskRunner and switch
132// it to a NULL one. CalledOnValidSequence() should then behave like
133// ThreadChecker::CalledOnValidThread().
134TEST_F(SequenceCheckerImplTest, ChangeSequenceNull) {
135 const scoped_refptr<FakeTaskRunner> fake_sequenced_task_runner(
136 new FakeTaskRunner());
137
138 SequenceCheckerImpl sequence_checker_impl(fake_sequenced_task_runner);
139 EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence());
140
141 sequence_checker_impl.ChangeSequence(NULL);
142 // Binds to current thread.
143 EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence());
144 {
145 Thread thread("thread 1");
146 ASSERT_TRUE(thread.Start());
147 thread.message_loop()->PostTask(
148 FROM_HERE, Bind(&ExpectCalledOnValidSequence,
149 FROM_HERE,
150 Unretained(&sequence_checker_impl),
151 false));
152 }
153
154 EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence());
155
156 sequence_checker_impl.ChangeSequence(NULL);
157 // Binds to worker thread.
158 {
159 Thread thread("thread 2");
160 ASSERT_TRUE(thread.Start());
161 thread.message_loop()->PostTask(
162 FROM_HERE, Bind(&ExpectCalledOnValidSequence,
163 FROM_HERE,
164 Unretained(&sequence_checker_impl),
165 true));
166 }
167 EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence());
168}
169
170// Create a SequenceCheckerImpl with the current thread's task runner
171// and switch it to other task runners. CalledOnValidSequence() should
172// return true only when it's on the correct thread.
173TEST_F(SequenceCheckerImplTest, MultipleThreads) {
174 MessageLoop loop;
175
176 SequenceCheckerImpl sequence_checker_impl(loop.message_loop_proxy());
177 EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence());
178
179 {
180 Thread thread("thread 1");
181 ASSERT_TRUE(thread.Start());
182 thread.message_loop()->PostTask(
183 FROM_HERE, Bind(&ExpectCalledOnValidSequence,
184 FROM_HERE,
185 Unretained(&sequence_checker_impl),
186 false));
187 thread.message_loop()->PostTask(
188 FROM_HERE, Bind(&SequenceCheckerImpl::ChangeSequence,
189 Unretained(&sequence_checker_impl),
190 thread.message_loop_proxy()));
191 thread.message_loop()->PostTask(
192 FROM_HERE, Bind(&ExpectCalledOnValidSequence,
193 FROM_HERE,
194 Unretained(&sequence_checker_impl),
195 true));
196 }
197
198 EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence());
199
200 sequence_checker_impl.ChangeSequence(loop.message_loop_proxy());
201 EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence());
202
203 {
204 Thread thread("thread 2");
205 ASSERT_TRUE(thread.Start());
206 thread.message_loop()->PostTask(
207 FROM_HERE, Bind(&ExpectCalledOnValidSequence,
208 FROM_HERE,
209 Unretained(&sequence_checker_impl),
210 false));
211 }
212
213 EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence());
214}
215
216} // namespace
217
218} // namespace base