blob: 24fbf01aede43f94b94d70d5d51854127c463191 [file] [log] [blame]
Trent Apted4d207362018-08-15 23:48:151// Copyright 2018 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/observer_list_threadsafe.h"
6
7#include <memory>
8#include <vector>
9
10#include "base/bind.h"
11#include "base/compiler_specific.h"
12#include "base/location.h"
Hans Wennborgafeb3902020-06-17 14:42:2913#include "base/logging.h"
Trent Apted4d207362018-08-15 23:48:1514#include "base/memory/weak_ptr.h"
Trent Apted4d207362018-08-15 23:48:1515#include "base/run_loop.h"
16#include "base/sequenced_task_runner.h"
17#include "base/single_thread_task_runner.h"
18#include "base/synchronization/waitable_event.h"
19#include "base/task/post_task.h"
Gabriel Charette0bcc6ca2020-03-14 00:12:4420#include "base/task/thread_pool.h"
Gabriel Charetteeadf58862019-08-29 05:20:2721#include "base/task/thread_pool/thread_pool_instance.h"
Guido Urdanetaef4e91942020-11-09 15:06:2422#include "base/test/bind.h"
Gabriel Charettec7108742019-08-23 03:31:4023#include "base/test/task_environment.h"
Trent Apted4d207362018-08-15 23:48:1524#include "base/threading/platform_thread.h"
25#include "base/threading/thread_restrictions.h"
Lei Zhang52637ed2019-02-20 01:38:3726#include "base/threading/thread_task_runner_handle.h"
Trent Apted4d207362018-08-15 23:48:1527#include "build/build_config.h"
28#include "testing/gtest/include/gtest/gtest.h"
Anton Bikineev7dd58ad2021-05-18 01:01:3929#include "third_party/abseil-cpp/absl/types/optional.h"
Trent Apted4d207362018-08-15 23:48:1530
31namespace base {
32namespace {
33
34constexpr int kThreadRunTime = 2000; // ms to run the multi-threaded test.
35
36class Foo {
37 public:
38 virtual void Observe(int x) = 0;
39 virtual ~Foo() = default;
40 virtual int GetValue() const { return 0; }
41};
42
43class Adder : public Foo {
44 public:
45 explicit Adder(int scaler) : total(0), scaler_(scaler) {}
46 ~Adder() override = default;
47
48 void Observe(int x) override { total += x * scaler_; }
49 int GetValue() const override { return total; }
50
51 int total;
52
53 private:
54 int scaler_;
55};
56
57class AddInObserve : public Foo {
58 public:
59 explicit AddInObserve(ObserverListThreadSafe<Foo>* observer_list)
60 : observer_list(observer_list), to_add_() {}
61
62 void SetToAdd(Foo* to_add) { to_add_ = to_add; }
63
64 void Observe(int x) override {
65 if (to_add_) {
66 observer_list->AddObserver(to_add_);
67 to_add_ = nullptr;
68 }
69 }
70
71 ObserverListThreadSafe<Foo>* observer_list;
72 Foo* to_add_;
73};
74
Sami Kyostila21f4d4c2018-11-29 11:11:3675// A task for use in the ThreadSafeObserver test which will add and remove
Trent Apted4d207362018-08-15 23:48:1576// itself from the notification list repeatedly.
Sami Kyostila21f4d4c2018-11-29 11:11:3677class AddRemoveThread : public Foo {
Trent Apted4d207362018-08-15 23:48:1578 public:
Sami Kyostila21f4d4c2018-11-29 11:11:3679 AddRemoveThread(ObserverListThreadSafe<Foo>* list, bool notify)
Trent Apted4d207362018-08-15 23:48:1580 : list_(list),
Gabriel Charette0bcc6ca2020-03-14 00:12:4481 task_runner_(ThreadPool::CreateSingleThreadTaskRunner(
82 {},
Sami Kyostila21f4d4c2018-11-29 11:11:3683 SingleThreadTaskRunnerThreadMode::DEDICATED)),
Trent Apted4d207362018-08-15 23:48:1584 in_list_(false),
85 start_(Time::Now()),
Jeremy Roman577d88492019-07-05 14:30:2386 do_notifies_(notify) {
Sami Kyostila21f4d4c2018-11-29 11:11:3687 task_runner_->PostTask(
Trent Apted4d207362018-08-15 23:48:1588 FROM_HERE,
89 base::BindOnce(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr()));
Trent Apted4d207362018-08-15 23:48:1590 }
91
Sami Kyostila21f4d4c2018-11-29 11:11:3692 ~AddRemoveThread() override = default;
93
Trent Apted4d207362018-08-15 23:48:1594 // This task just keeps posting to itself in an attempt to race with the
95 // notifier.
96 void AddTask() {
Trent Apted4d207362018-08-15 23:48:1597 if ((Time::Now() - start_).InMilliseconds() > kThreadRunTime) {
98 VLOG(1) << "DONE!";
99 return;
100 }
101
102 if (!in_list_) {
103 list_->AddObserver(this);
104 in_list_ = true;
105 }
106
107 if (do_notifies_) {
108 list_->Notify(FROM_HERE, &Foo::Observe, 10);
109 }
110
Sami Kyostila21f4d4c2018-11-29 11:11:36111 ThreadTaskRunnerHandle::Get()->PostTask(
Trent Apted4d207362018-08-15 23:48:15112 FROM_HERE,
113 base::BindOnce(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr()));
114 }
115
Trent Apted4d207362018-08-15 23:48:15116 void Observe(int x) override {
Trent Apted4d207362018-08-15 23:48:15117 // If we're getting called after we removed ourselves from the list, that is
118 // very bad!
Alexander Timind1e773cb2018-10-26 14:19:03119 EXPECT_TRUE(in_list_);
Trent Apted4d207362018-08-15 23:48:15120
121 // This callback should fire on the appropriate thread
Sami Kyostila21f4d4c2018-11-29 11:11:36122 EXPECT_TRUE(task_runner_->BelongsToCurrentThread());
Trent Apted4d207362018-08-15 23:48:15123
124 list_->RemoveObserver(this);
125 in_list_ = false;
126 }
127
128 private:
129 ObserverListThreadSafe<Foo>* list_;
Sami Kyostila21f4d4c2018-11-29 11:11:36130 scoped_refptr<SingleThreadTaskRunner> task_runner_;
Trent Apted4d207362018-08-15 23:48:15131 bool in_list_; // Are we currently registered for notifications.
132 // in_list_ is only used on |this| thread.
133 Time start_; // The time we started the test.
134
Trent Apted4d207362018-08-15 23:48:15135 bool do_notifies_; // Whether these threads should do notifications.
Trent Apted4d207362018-08-15 23:48:15136
Jeremy Roman577d88492019-07-05 14:30:23137 base::WeakPtrFactory<AddRemoveThread> weak_factory_{this};
Trent Apted4d207362018-08-15 23:48:15138};
139
140} // namespace
141
142TEST(ObserverListThreadSafeTest, BasicTest) {
Eric Seckler3676f3c2021-04-27 14:32:38143 using List = ObserverListThreadSafe<Foo>;
Gabriel Charette694c3c332019-08-19 14:53:05144 test::TaskEnvironment task_environment;
Trent Apted4d207362018-08-15 23:48:15145
Eric Seckler3676f3c2021-04-27 14:32:38146 scoped_refptr<List> observer_list(new List);
Trent Apted4d207362018-08-15 23:48:15147 Adder a(1);
148 Adder b(-1);
149 Adder c(1);
150 Adder d(-1);
151
Eric Seckler3676f3c2021-04-27 14:32:38152 List::AddObserverResult result;
153
154 result = observer_list->AddObserver(&a);
155 EXPECT_EQ(result, List::AddObserverResult::kBecameNonEmpty);
156 result = observer_list->AddObserver(&b);
157 EXPECT_EQ(result, List::AddObserverResult::kWasAlreadyNonEmpty);
Trent Apted4d207362018-08-15 23:48:15158
159 observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
160 RunLoop().RunUntilIdle();
161
Eric Seckler3676f3c2021-04-27 14:32:38162 result = observer_list->AddObserver(&c);
163 EXPECT_EQ(result, List::AddObserverResult::kWasAlreadyNonEmpty);
164 result = observer_list->AddObserver(&d);
165 EXPECT_EQ(result, List::AddObserverResult::kWasAlreadyNonEmpty);
Trent Apted4d207362018-08-15 23:48:15166
167 observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
168 observer_list->RemoveObserver(&c);
169 RunLoop().RunUntilIdle();
170
171 EXPECT_EQ(20, a.total);
172 EXPECT_EQ(-20, b.total);
173 EXPECT_EQ(0, c.total);
174 EXPECT_EQ(-10, d.total);
175}
176
177TEST(ObserverListThreadSafeTest, RemoveObserver) {
Eric Seckler3676f3c2021-04-27 14:32:38178 using List = ObserverListThreadSafe<Foo>;
Gabriel Charette694c3c332019-08-19 14:53:05179 test::TaskEnvironment task_environment;
Trent Apted4d207362018-08-15 23:48:15180
Eric Seckler3676f3c2021-04-27 14:32:38181 scoped_refptr<List> observer_list(new List);
Trent Apted4d207362018-08-15 23:48:15182 Adder a(1), b(1);
183
184 // A workaround for the compiler bug. See http://crbug.com/121960.
185 EXPECT_NE(&a, &b);
186
Eric Seckler3676f3c2021-04-27 14:32:38187 List::RemoveObserverResult result;
188
Trent Apted4d207362018-08-15 23:48:15189 // Should do nothing.
Eric Seckler3676f3c2021-04-27 14:32:38190 result = observer_list->RemoveObserver(&a);
191 EXPECT_EQ(result, List::RemoveObserverResult::kWasOrBecameEmpty);
192 result = observer_list->RemoveObserver(&b);
193 EXPECT_EQ(result, List::RemoveObserverResult::kWasOrBecameEmpty);
Trent Apted4d207362018-08-15 23:48:15194
195 observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
196 RunLoop().RunUntilIdle();
197
198 EXPECT_EQ(0, a.total);
199 EXPECT_EQ(0, b.total);
200
201 observer_list->AddObserver(&a);
202
203 // Should also do nothing.
Eric Seckler3676f3c2021-04-27 14:32:38204 result = observer_list->RemoveObserver(&b);
205 EXPECT_EQ(result, List::RemoveObserverResult::kRemainsNonEmpty);
Trent Apted4d207362018-08-15 23:48:15206
207 observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
208 RunLoop().RunUntilIdle();
209
210 EXPECT_EQ(10, a.total);
211 EXPECT_EQ(0, b.total);
Eric Seckler3676f3c2021-04-27 14:32:38212
213 result = observer_list->RemoveObserver(&a);
214 EXPECT_EQ(result, List::RemoveObserverResult::kWasOrBecameEmpty);
Trent Apted4d207362018-08-15 23:48:15215}
216
Trent Apted4d207362018-08-15 23:48:15217class FooRemover : public Foo {
218 public:
219 explicit FooRemover(ObserverListThreadSafe<Foo>* list) : list_(list) {}
220 ~FooRemover() override = default;
221
222 void AddFooToRemove(Foo* foo) { foos_.push_back(foo); }
223
224 void Observe(int x) override {
225 std::vector<Foo*> tmp;
226 tmp.swap(foos_);
jdoerrie6c6229352018-10-22 15:55:43227 for (auto* it : tmp) {
228 list_->RemoveObserver(it);
Trent Apted4d207362018-08-15 23:48:15229 }
230 }
231
232 private:
233 const scoped_refptr<ObserverListThreadSafe<Foo>> list_;
234 std::vector<Foo*> foos_;
235};
236
237TEST(ObserverListThreadSafeTest, RemoveMultipleObservers) {
Gabriel Charette694c3c332019-08-19 14:53:05238 test::TaskEnvironment task_environment;
Trent Apted4d207362018-08-15 23:48:15239 scoped_refptr<ObserverListThreadSafe<Foo>> observer_list(
240 new ObserverListThreadSafe<Foo>);
241
242 FooRemover a(observer_list.get());
243 Adder b(1);
244
245 observer_list->AddObserver(&a);
246 observer_list->AddObserver(&b);
247
248 a.AddFooToRemove(&a);
249 a.AddFooToRemove(&b);
250
251 observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
252 RunLoop().RunUntilIdle();
253}
254
255// A test driver for a multi-threaded notification loop. Runs a number of
256// observer threads, each of which constantly adds/removes itself from the
257// observer list. Optionally, if cross_thread_notifies is set to true, the
258// observer threads will also trigger notifications to all observers.
259static void ThreadSafeObserverHarness(int num_threads,
260 bool cross_thread_notifies) {
Gabriel Charette694c3c332019-08-19 14:53:05261 test::TaskEnvironment task_environment;
Trent Apted4d207362018-08-15 23:48:15262
263 scoped_refptr<ObserverListThreadSafe<Foo>> observer_list(
264 new ObserverListThreadSafe<Foo>);
265 Adder a(1);
266 Adder b(-1);
267
268 observer_list->AddObserver(&a);
269 observer_list->AddObserver(&b);
270
Sami Kyostila21f4d4c2018-11-29 11:11:36271 std::vector<std::unique_ptr<AddRemoveThread>> threaded_observer;
Trent Apted4d207362018-08-15 23:48:15272 threaded_observer.reserve(num_threads);
Trent Apted4d207362018-08-15 23:48:15273 for (int index = 0; index < num_threads; index++) {
Sami Kyostila21f4d4c2018-11-29 11:11:36274 threaded_observer.push_back(std::make_unique<AddRemoveThread>(
275 observer_list.get(), cross_thread_notifies));
Trent Apted4d207362018-08-15 23:48:15276 }
277 ASSERT_EQ(static_cast<size_t>(num_threads), threaded_observer.size());
Trent Apted4d207362018-08-15 23:48:15278
279 Time start = Time::Now();
280 while (true) {
281 if ((Time::Now() - start).InMilliseconds() > kThreadRunTime)
282 break;
283
284 observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
285
286 RunLoop().RunUntilIdle();
287 }
288
Gabriel Charette694c3c332019-08-19 14:53:05289 task_environment.RunUntilIdle();
Trent Apted4d207362018-08-15 23:48:15290}
291
Wezc1143172019-01-21 18:05:41292TEST(ObserverListThreadSafeTest, CrossThreadObserver) {
Trent Apted4d207362018-08-15 23:48:15293 // Use 7 observer threads. Notifications only come from the main thread.
294 ThreadSafeObserverHarness(7, false);
295}
296
297TEST(ObserverListThreadSafeTest, CrossThreadNotifications) {
298 // Use 3 observer threads. Notifications will fire from the main thread and
299 // all 3 observer threads.
300 ThreadSafeObserverHarness(3, true);
301}
302
Sami Kyostila3f49cb572018-11-19 13:01:09303TEST(ObserverListThreadSafeTest, OutlivesTaskEnvironment) {
Anton Bikineev7dd58ad2021-05-18 01:01:39304 absl::optional<test::TaskEnvironment> task_environment(absl::in_place);
Trent Apted4d207362018-08-15 23:48:15305 scoped_refptr<ObserverListThreadSafe<Foo>> observer_list(
306 new ObserverListThreadSafe<Foo>);
307
308 Adder a(1);
309 observer_list->AddObserver(&a);
Gabriel Charette694c3c332019-08-19 14:53:05310 task_environment.reset();
Trent Apted4d207362018-08-15 23:48:15311 // Test passes if we don't crash here.
312 observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
313}
314
315namespace {
316
317class SequenceVerificationObserver : public Foo {
318 public:
319 explicit SequenceVerificationObserver(
320 scoped_refptr<SequencedTaskRunner> task_runner)
321 : task_runner_(std::move(task_runner)) {}
David Bienvenu5f4d4f032020-09-27 16:55:03322 SequenceVerificationObserver(const SequenceVerificationObserver&) = delete;
323 SequenceVerificationObserver& operator=(const SequenceVerificationObserver&) =
324 delete;
Trent Apted4d207362018-08-15 23:48:15325 ~SequenceVerificationObserver() override = default;
326
327 void Observe(int x) override {
328 called_on_valid_sequence_ = task_runner_->RunsTasksInCurrentSequence();
329 }
330
331 bool called_on_valid_sequence() const { return called_on_valid_sequence_; }
332
333 private:
334 const scoped_refptr<SequencedTaskRunner> task_runner_;
335 bool called_on_valid_sequence_ = false;
Trent Apted4d207362018-08-15 23:48:15336};
337
338} // namespace
339
340// Verify that observers are notified on the correct sequence.
341TEST(ObserverListThreadSafeTest, NotificationOnValidSequence) {
Gabriel Charette694c3c332019-08-19 14:53:05342 test::TaskEnvironment task_environment;
Trent Apted4d207362018-08-15 23:48:15343
Gabriel Charette0bcc6ca2020-03-14 00:12:44344 auto task_runner_1 = ThreadPool::CreateSequencedTaskRunner({});
345 auto task_runner_2 = ThreadPool::ThreadPool::CreateSequencedTaskRunner({});
Trent Apted4d207362018-08-15 23:48:15346
347 auto observer_list = MakeRefCounted<ObserverListThreadSafe<Foo>>();
348
349 SequenceVerificationObserver observer_1(task_runner_1);
350 SequenceVerificationObserver observer_2(task_runner_2);
351
Eric Seckler3676f3c2021-04-27 14:32:38352 task_runner_1->PostTask(
353 FROM_HERE,
354 BindOnce(base::IgnoreResult(&ObserverListThreadSafe<Foo>::AddObserver),
355 observer_list, Unretained(&observer_1)));
356 task_runner_2->PostTask(
357 FROM_HERE,
358 BindOnce(base::IgnoreResult(&ObserverListThreadSafe<Foo>::AddObserver),
359 observer_list, Unretained(&observer_2)));
Trent Apted4d207362018-08-15 23:48:15360
Gabriel Charette43fd3702019-05-29 16:36:51361 ThreadPoolInstance::Get()->FlushForTesting();
Trent Apted4d207362018-08-15 23:48:15362
363 observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
364
Gabriel Charette43fd3702019-05-29 16:36:51365 ThreadPoolInstance::Get()->FlushForTesting();
Trent Apted4d207362018-08-15 23:48:15366
367 EXPECT_TRUE(observer_1.called_on_valid_sequence());
368 EXPECT_TRUE(observer_2.called_on_valid_sequence());
369}
370
371// Verify that when an observer is added to a NOTIFY_ALL ObserverListThreadSafe
372// from a notification, it is itself notified.
373TEST(ObserverListThreadSafeTest, AddObserverFromNotificationNotifyAll) {
Gabriel Charette694c3c332019-08-19 14:53:05374 test::TaskEnvironment task_environment;
Trent Apted4d207362018-08-15 23:48:15375 auto observer_list = MakeRefCounted<ObserverListThreadSafe<Foo>>();
376
377 Adder observer_added_from_notification(1);
378
379 AddInObserve initial_observer(observer_list.get());
380 initial_observer.SetToAdd(&observer_added_from_notification);
381 observer_list->AddObserver(&initial_observer);
382
383 observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
384
385 base::RunLoop().RunUntilIdle();
386
387 EXPECT_EQ(1, observer_added_from_notification.GetValue());
388}
389
390namespace {
391
392class RemoveWhileNotificationIsRunningObserver : public Foo {
393 public:
394 RemoveWhileNotificationIsRunningObserver()
395 : notification_running_(WaitableEvent::ResetPolicy::AUTOMATIC,
396 WaitableEvent::InitialState::NOT_SIGNALED),
397 barrier_(WaitableEvent::ResetPolicy::AUTOMATIC,
398 WaitableEvent::InitialState::NOT_SIGNALED) {}
David Bienvenu5f4d4f032020-09-27 16:55:03399 RemoveWhileNotificationIsRunningObserver(
400 const RemoveWhileNotificationIsRunningObserver&) = delete;
401 RemoveWhileNotificationIsRunningObserver& operator=(
402 const RemoveWhileNotificationIsRunningObserver&) = delete;
Trent Apted4d207362018-08-15 23:48:15403 ~RemoveWhileNotificationIsRunningObserver() override = default;
404
405 void Observe(int x) override {
406 notification_running_.Signal();
407 ScopedAllowBaseSyncPrimitivesForTesting allow_base_sync_primitives;
408 barrier_.Wait();
409 }
410
411 void WaitForNotificationRunning() { notification_running_.Wait(); }
412 void Unblock() { barrier_.Signal(); }
413
414 private:
415 WaitableEvent notification_running_;
416 WaitableEvent barrier_;
Trent Apted4d207362018-08-15 23:48:15417};
418
419} // namespace
420
421// Verify that there is no crash when an observer is removed while it is being
422// notified.
423TEST(ObserverListThreadSafeTest, RemoveWhileNotificationIsRunning) {
424 auto observer_list = MakeRefCounted<ObserverListThreadSafe<Foo>>();
425 RemoveWhileNotificationIsRunningObserver observer;
426
427 WaitableEvent task_running(WaitableEvent::ResetPolicy::AUTOMATIC,
428 WaitableEvent::InitialState::NOT_SIGNALED);
429 WaitableEvent barrier(WaitableEvent::ResetPolicy::AUTOMATIC,
430 WaitableEvent::InitialState::NOT_SIGNALED);
431
432 // This must be after the declaration of |barrier| so that tasks posted to
Gabriel Charette52fa3ae2019-04-15 21:44:37433 // ThreadPool can safely use |barrier|.
Gabriel Charette694c3c332019-08-19 14:53:05434 test::TaskEnvironment task_environment;
Trent Apted4d207362018-08-15 23:48:15435
Gabriel Charette0bcc6ca2020-03-14 00:12:44436 ThreadPool::CreateSequencedTaskRunner({MayBlock()})
Etienne Pierre-Doray3879b052018-09-17 14:17:22437 ->PostTask(FROM_HERE,
Eric Seckler3676f3c2021-04-27 14:32:38438 base::BindOnce(base::IgnoreResult(
439 &ObserverListThreadSafe<Foo>::AddObserver),
Trent Apted4d207362018-08-15 23:48:15440 observer_list, Unretained(&observer)));
Gabriel Charette43fd3702019-05-29 16:36:51441 ThreadPoolInstance::Get()->FlushForTesting();
Trent Apted4d207362018-08-15 23:48:15442
443 observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
444 observer.WaitForNotificationRunning();
445 observer_list->RemoveObserver(&observer);
446
447 observer.Unblock();
448}
449
Etienne Bergeron3f80c2cf2021-03-22 17:32:14450TEST(ObserverListThreadSafeTest, AddRemoveWithPendingNotifications) {
451 test::TaskEnvironment task_environment;
452
453 scoped_refptr<ObserverListThreadSafe<Foo>> observer_list(
454 new ObserverListThreadSafe<Foo>);
455 Adder a(1);
456 Adder b(1);
457
458 observer_list->AddObserver(&a);
459 observer_list->AddObserver(&b);
460
461 // Remove observer `a` while there is a pending notification for observer `a`.
462 observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
463 observer_list->RemoveObserver(&a);
464 RunLoop().RunUntilIdle();
465 observer_list->AddObserver(&a);
466
467 EXPECT_EQ(0, a.total);
468 EXPECT_EQ(10, b.total);
469
470 // Remove and re-adding observer `a` while there is a pending notification for
471 // observer `a`. The notification to `a` must not be executed since it was
472 // sent before the removal of `a`.
473 observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
474 observer_list->RemoveObserver(&a);
475 observer_list->AddObserver(&a);
476 RunLoop().RunUntilIdle();
477
478 EXPECT_EQ(0, a.total);
479 EXPECT_EQ(20, b.total);
480
481 // Observer `a` and `b` are present and should both receive a notification.
482 observer_list->RemoveObserver(&a);
483 observer_list->AddObserver(&a);
484 observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
485 RunLoop().RunUntilIdle();
486
487 EXPECT_EQ(10, a.total);
488 EXPECT_EQ(30, b.total);
489}
490
Trent Apted4d207362018-08-15 23:48:15491// Same as ObserverListTest.Existing, but for ObserverListThreadSafe
492TEST(ObserverListThreadSafeTest, Existing) {
Gabriel Charette694c3c332019-08-19 14:53:05493 test::TaskEnvironment task_environment;
Trent Apted4d207362018-08-15 23:48:15494 scoped_refptr<ObserverListThreadSafe<Foo>> observer_list(
495 new ObserverListThreadSafe<Foo>(ObserverListPolicy::EXISTING_ONLY));
496 Adder a(1);
497 AddInObserve b(observer_list.get());
498 Adder c(1);
499 b.SetToAdd(&c);
500
501 observer_list->AddObserver(&a);
502 observer_list->AddObserver(&b);
503
504 observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
505 RunLoop().RunUntilIdle();
506
507 EXPECT_FALSE(b.to_add_);
508 // B's adder should not have been notified because it was added during
509 // notification.
510 EXPECT_EQ(0, c.total);
511
512 // Notify again to make sure b's adder is notified.
513 observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
514 RunLoop().RunUntilIdle();
515 EXPECT_EQ(1, c.total);
516}
517
Trent Apted4d207362018-08-15 23:48:15518} // namespace base