proxygen
RequestContextTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2013-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <thread>
18 
19 #include <folly/Memory.h>
21 #include <folly/io/async/Request.h>
23 
24 using namespace folly;
25 
26 RequestToken testtoken("test");
27 
28 class TestData : public RequestData {
29  public:
30  explicit TestData(int data) : data_(data) {}
31  ~TestData() override {}
32 
33  bool hasCallback() override {
34  return true;
35  }
36 
37  void onSet() override {
38  set_++;
39  }
40 
41  void onUnset() override {
42  unset_++;
43  }
44 
45  int set_ = 0, unset_ = 0;
46  int data_;
47 };
48 
50  protected:
51  void SetUp() override {
52  // Make sure each test starts out using the default context, and not some
53  // other context left over by a previous test.
55 
56  // Make sure no data is set for the "test" key when we start. There could
57  // be left over data in the default context from a previous test. If we
58  // don't clear it out future calls to setContextData() won't actually work,
59  // and will reset the data to null instead of properly setting the new
60  // desired data.
61  //
62  // (All of the tests generally want the behavior of overwriteContextData()
63  // rather than setContextData(), but that method is private.)
64  //
65  // We ideally want to clear out data for any keys that may be set, not just
66  // the "test" key, but there also isn't a RequestContext API to do this.
67  clearData();
68  }
69 
71  auto* ctx = RequestContext::get();
72  EXPECT_TRUE(ctx != nullptr);
73  return *ctx;
74  }
75 
76  void setData(int data = 0, std::string key = "test") {
77  getContext().setContextData(key, std::make_unique<TestData>(data));
78  }
79 
80  bool hasData(std::string key = "test") {
81  return getContext().hasContextData(key);
82  }
83 
84  const TestData& getData(std::string key = "test") {
85  auto* ptr = dynamic_cast<TestData*>(getContext().getContextData(key));
86  EXPECT_TRUE(ptr != nullptr);
87  return *ptr;
88  }
89 
90  void clearData(std::string key = "test") {
91  getContext().clearContextData(key);
92  }
93 };
94 
96  EventBase base;
97 
98  // There should always be a default context with get()
99  EXPECT_TRUE(RequestContext::get() != nullptr);
100 
101  // but not with saveContext()
107 
108  EXPECT_EQ(nullptr, RequestContext::get()->getContextData("test"));
109 
110  RequestContext::get()->setContextData("test", std::make_unique<TestData>(10));
111  base.runInEventBaseThread([&]() {
112  EXPECT_TRUE(RequestContext::get() != nullptr);
113  auto data = dynamic_cast<TestData*>(
115  ->data_;
116  EXPECT_EQ(10, data);
117  base.terminateLoopSoon();
118  });
119  auto th = std::thread([&]() { base.loopForever(); });
120  th.join();
121  EXPECT_TRUE(RequestContext::get() != nullptr);
122  auto a =
123  dynamic_cast<TestData*>(RequestContext::get()->getContextData("test"));
124  auto data = a->data_;
125  EXPECT_EQ(10, data);
126 
127  RequestContext::setContext(std::shared_ptr<RequestContext>());
128  // There should always be a default context
129  EXPECT_TRUE(nullptr != RequestContext::get());
130 }
131 
134  setData(10);
135  {
137  EXPECT_FALSE(hasData());
138  setData(20);
139  EXPECT_EQ(20, getData().data_);
140  EXPECT_EQ(1, getData().set_);
141  EXPECT_EQ(0, getData().unset_);
142  }
143  EXPECT_EQ(10, getData().data_);
144  EXPECT_EQ(2, getData().set_);
145  EXPECT_EQ(1, getData().unset_);
146 }
147 
148 TEST_F(RequestContextTest, defaultContext) {
149  // Don't create a top level guard
150  setData(10);
151  {
153  EXPECT_FALSE(hasData());
154  }
155  EXPECT_EQ(10, getData().data_);
156  EXPECT_EQ(1, getData().set_);
157  EXPECT_EQ(0, getData().unset_);
158 }
159 
160 TEST_F(RequestContextTest, setIfAbsentTest) {
161  EXPECT_TRUE(RequestContext::get() != nullptr);
162 
163  RequestContext::get()->setContextData("test", std::make_unique<TestData>(10));
164  EXPECT_FALSE(RequestContext::get()->setContextDataIfAbsent(
165  "test", std::make_unique<TestData>(20)));
166  EXPECT_EQ(
167  10,
168  dynamic_cast<TestData*>(RequestContext::get()->getContextData(testtoken))
169  ->data_);
170 
171  EXPECT_TRUE(RequestContext::get()->setContextDataIfAbsent(
172  "test2", std::make_unique<TestData>(20)));
173  EXPECT_EQ(
174  20,
175  dynamic_cast<TestData*>(RequestContext::get()->getContextData("test2"))
176  ->data_);
177 
178  RequestContext::setContext(std::shared_ptr<RequestContext>());
179  EXPECT_TRUE(nullptr != RequestContext::get());
180 }
181 
182 TEST_F(RequestContextTest, testSetUnset) {
184  auto ctx1 = RequestContext::saveContext();
185  ctx1->setContextData("test", std::make_unique<TestData>(10));
186  auto testData1 = dynamic_cast<TestData*>(ctx1->getContextData("test"));
187 
188  // onSet called in setContextData
189  EXPECT_EQ(1, testData1->set_);
190 
191  // Override RequestContext
193  auto ctx2 = RequestContext::saveContext();
194  ctx2->setContextData(testtoken, std::make_unique<TestData>(20));
195  auto testData2 = dynamic_cast<TestData*>(ctx2->getContextData(testtoken));
196 
197  // onSet called in setContextData
198  EXPECT_EQ(1, testData2->set_);
199 
200  // Check ctx1->onUnset was called
201  EXPECT_EQ(1, testData1->unset_);
202 
204  EXPECT_EQ(2, testData1->set_);
205  EXPECT_EQ(1, testData1->unset_);
206  EXPECT_EQ(1, testData2->unset_);
207 
209  EXPECT_EQ(2, testData1->set_);
210  EXPECT_EQ(2, testData1->unset_);
211  EXPECT_EQ(2, testData2->set_);
212  EXPECT_EQ(1, testData2->unset_);
213 }
214 
215 TEST_F(RequestContextTest, deadlockTest) {
216  class DeadlockTestData : public RequestData {
217  public:
218  explicit DeadlockTestData(const std::string& val) : val_(val) {}
219 
220  ~DeadlockTestData() override {
222  val_, std::make_unique<TestData>(1));
223  }
224 
225  bool hasCallback() override {
226  return false;
227  }
228 
229  std::string val_;
230  };
231 
233  "test", std::make_unique<DeadlockTestData>("test2"));
235 }
236 
237 // A common use case is to use set/unset to maintain a thread global
238 // Regression test to ensure that unset is always called before set
239 TEST_F(RequestContextTest, sharedGlobalTest) {
240  static bool global = false;
241 
242  class GlobalTestData : public RequestData {
243  public:
244  void onSet() override {
245  ASSERT_FALSE(global);
246  global = true;
247  }
248 
249  void onUnset() override {
250  ASSERT_TRUE(global);
251  global = false;
252  }
253 
254  bool hasCallback() override {
255  return true;
256  }
257  };
258 
261  "test", std::make_unique<GlobalTestData>());
262  {
265  "test", std::make_unique<GlobalTestData>());
266  }
267 }
268 
269 TEST_F(RequestContextTest, ShallowCopyBasic) {
271  setData(123, "immutable");
272  EXPECT_EQ(123, getData("immutable").data_);
273  EXPECT_FALSE(hasData());
274 
275  {
277  EXPECT_EQ(123, getData("immutable").data_);
278  setData(789);
279  EXPECT_EQ(789, getData().data_);
280  }
281 
282  EXPECT_FALSE(hasData());
283  EXPECT_EQ(123, getData("immutable").data_);
284  EXPECT_EQ(1, getData("immutable").set_);
285  EXPECT_EQ(0, getData("immutable").unset_);
286 }
287 
288 TEST_F(RequestContextTest, ShallowCopyOverwrite) {
290  setData(123);
291  EXPECT_EQ(123, getData().data_);
292  {
294  "test", std::make_unique<TestData>(789));
295  EXPECT_EQ(789, getData().data_);
296  EXPECT_EQ(1, getData().set_);
297  EXPECT_EQ(0, getData().unset_);
298  }
299  EXPECT_EQ(123, getData().data_);
300  EXPECT_EQ(2, getData().set_);
301  EXPECT_EQ(1, getData().unset_);
302 }
303 
304 TEST_F(RequestContextTest, ShallowCopyDefaultContext) {
305  // Don't set global scope guard
306  setData(123);
307  EXPECT_EQ(123, getData().data_);
308  {
310  "test", std::make_unique<TestData>(789));
311  EXPECT_EQ(789, getData().data_);
312  }
313  EXPECT_EQ(123, getData().data_);
314  EXPECT_EQ(1, getData().set_);
315  EXPECT_EQ(0, getData().unset_);
316 }
317 
318 TEST_F(RequestContextTest, ShallowCopyClear) {
320  setData(123);
321  EXPECT_EQ(123, getData().data_);
322  {
324  EXPECT_EQ(123, getData().data_);
325  clearData();
326  setData(789);
327  EXPECT_EQ(789, getData().data_);
328  }
329  EXPECT_EQ(123, getData().data_);
330  EXPECT_EQ(2, getData().set_);
331  EXPECT_EQ(1, getData().unset_);
332 }
bool hasCallback() override
void * ptr
static std::shared_ptr< RequestContext > setContext(std::shared_ptr< RequestContext > ctx)
Definition: Request.cpp:227
void setContextData(const RequestToken &val, std::unique_ptr< RequestData > data)
Definition: Request.cpp:129
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
static void create()
Definition: Request.h:118
double val
Definition: String.cpp:273
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
void onUnset() override
static std::shared_ptr< RequestContext > saveContext()
Definition: Request.h:196
bool hasData(std::string key="test")
void terminateLoopSoon()
Definition: EventBase.cpp:493
constexpr auto data(C &c) -> decltype(c.data())
Definition: Access.h:71
void onSet() override
bool runInEventBaseThread(void(*fn)(T *), T *arg)
Definition: EventBase.h:794
void clearContextData(const RequestToken &val)
Definition: Request.cpp:176
~TestData() override
char a
void SimpleTest(std::shared_ptr< folly::Executor > const &parent)
RequestToken testtoken("test")
TEST_F(AsyncSSLSocketWriteTest, write_coalescing1)
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
RequestContext & getContext()
const char * string
Definition: Conv.cpp:212
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
void clearData(std::string key="test")
#define ASSERT_FALSE(condition)
Definition: gtest.h:1868
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
RequestData * getContextData(const RequestToken &val)
Definition: Request.cpp:151
#define ASSERT_TRUE(condition)
Definition: gtest.h:1865
static RequestContext * get()
Definition: Request.cpp:290
StringPiece data_
const TestData & getData(std::string key="test")
void setData(int data=0, std::string key="test")