xref: /aosp_15_r20/external/cronet/net/base/test_completion_callback_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2011 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Illustrates how to use net::TestCompletionCallback.
6 
7 #include "net/base/test_completion_callback.h"
8 
9 #include "base/check_op.h"
10 #include "base/functional/bind.h"
11 #include "base/location.h"
12 #include "base/memory/raw_ptr.h"
13 #include "base/notreached.h"
14 #include "base/task/single_thread_task_runner.h"
15 #include "net/base/completion_once_callback.h"
16 #include "net/test/test_with_task_environment.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "testing/platform_test.h"
19 
20 namespace net {
21 
22 namespace {
23 
24 const int kMagicResult = 8888;
25 
CallClosureAfterCheckingResult(base::OnceClosure closure,bool * did_check_result,int result)26 void CallClosureAfterCheckingResult(base::OnceClosure closure,
27                                     bool* did_check_result,
28                                     int result) {
29   DCHECK_EQ(result, kMagicResult);
30   *did_check_result = true;
31   std::move(closure).Run();
32 }
33 
34 // ExampleEmployer is a toy version of HostResolver
35 // TODO: restore damage done in extracting example from real code
36 // (e.g. bring back real destructor, bring back comments)
37 class ExampleEmployer {
38  public:
39   ExampleEmployer();
40   ExampleEmployer(const ExampleEmployer&) = delete;
41   ExampleEmployer& operator=(const ExampleEmployer&) = delete;
42   ~ExampleEmployer();
43 
44   // Posts to the current thread a task which itself posts |callback| to the
45   // current thread. Returns true on success
46   bool DoSomething(CompletionOnceCallback callback);
47 
48  private:
49   class ExampleWorker;
50   friend class ExampleWorker;
51   scoped_refptr<ExampleWorker> request_;
52 };
53 
54 // Helper class; this is how ExampleEmployer schedules work.
55 class ExampleEmployer::ExampleWorker
56     : public base::RefCountedThreadSafe<ExampleWorker> {
57  public:
ExampleWorker(ExampleEmployer * employer,CompletionOnceCallback callback)58   ExampleWorker(ExampleEmployer* employer, CompletionOnceCallback callback)
59       : employer_(employer), callback_(std::move(callback)) {}
60   void DoWork();
61   void DoCallback();
62  private:
63   friend class base::RefCountedThreadSafe<ExampleWorker>;
64 
65   ~ExampleWorker() = default;
66 
67   // Only used on the origin thread (where DoSomething was called).
68   raw_ptr<ExampleEmployer> employer_;
69   CompletionOnceCallback callback_;
70   // Used to post ourselves onto the origin thread.
71   const scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_ =
72       base::SingleThreadTaskRunner::GetCurrentDefault();
73 };
74 
DoWork()75 void ExampleEmployer::ExampleWorker::DoWork() {
76   // In a real worker thread, some work would be done here.
77   // Pretend it is, and send the completion callback.
78   origin_task_runner_->PostTask(
79       FROM_HERE, base::BindOnce(&ExampleWorker::DoCallback, this));
80 }
81 
DoCallback()82 void ExampleEmployer::ExampleWorker::DoCallback() {
83   // Running on the origin thread.
84 
85   // Drop the employer_'s reference to us.  Do this before running the
86   // callback since the callback might result in the employer being
87   // destroyed.
88   employer_->request_ = nullptr;
89 
90   std::move(callback_).Run(kMagicResult);
91 }
92 
93 ExampleEmployer::ExampleEmployer() = default;
94 
95 ExampleEmployer::~ExampleEmployer() = default;
96 
DoSomething(CompletionOnceCallback callback)97 bool ExampleEmployer::DoSomething(CompletionOnceCallback callback) {
98   DCHECK(!request_.get()) << "already in use";
99 
100   request_ = base::MakeRefCounted<ExampleWorker>(this, std::move(callback));
101 
102   if (!base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
103           FROM_HERE, base::BindOnce(&ExampleWorker::DoWork, request_))) {
104     NOTREACHED();
105     request_ = nullptr;
106     return false;
107   }
108 
109   return true;
110 }
111 
112 }  // namespace
113 
114 class TestCompletionCallbackTest : public PlatformTest,
115                                    public WithTaskEnvironment {};
116 
TEST_F(TestCompletionCallbackTest,Simple)117 TEST_F(TestCompletionCallbackTest, Simple) {
118   ExampleEmployer boss;
119   TestCompletionCallback callback;
120   bool queued = boss.DoSomething(callback.callback());
121   EXPECT_TRUE(queued);
122   int result = callback.WaitForResult();
123   EXPECT_EQ(result, kMagicResult);
124 }
125 
TEST_F(TestCompletionCallbackTest,Closure)126 TEST_F(TestCompletionCallbackTest, Closure) {
127   ExampleEmployer boss;
128   TestClosure closure;
129   bool did_check_result = false;
130   CompletionOnceCallback completion_callback =
131       base::BindOnce(&CallClosureAfterCheckingResult, closure.closure(),
132                      base::Unretained(&did_check_result));
133   bool queued = boss.DoSomething(std::move(completion_callback));
134   EXPECT_TRUE(queued);
135 
136   EXPECT_FALSE(did_check_result);
137   closure.WaitForResult();
138   EXPECT_TRUE(did_check_result);
139 }
140 
141 // TODO: test deleting ExampleEmployer while work outstanding
142 
143 }  // namespace net
144