proxygen
GenericFilterTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree. An additional grant
7  * of patent rights can be found in the PATENTS file in the same directory.
8  *
9  */
10 #include <deque>
11 #include <folly/Memory.h>
14 #include <map>
16 #include <stdlib.h>
17 
18 using namespace folly;
19 using namespace proxygen;
20 using namespace testing;
21 
22 using std::unique_ptr;
23 
24 namespace detail {
25 
26 // This is defined in boost 1.53, but we only have 1.51 so far
27 
28 template <typename T>
29 T* get_pointer(const unique_ptr<T>& ptr) {
30  return ptr.get();
31 }
32 
33 template <typename T>
35  return ptr;
36 }
37 
38 }
39 
41  public:
42  class Callback {
43  public:
44  virtual ~Callback() {}
45  virtual void onA() = 0;
46  };
47  virtual ~TesterInterface() {}
48  virtual void setCallback(Callback* cb) = 0;
49  virtual void doA() = 0;
50 };
51 
52 class MockTester: public TesterInterface {
53  public:
54  Callback* cb_{nullptr};
55  void setCallback(Callback* cb) override {
56  cb_ = cb;
57  }
58  MOCK_METHOD0(doA, void());
59 };
60 
62  public:
63  MOCK_METHOD0(onA, void());
64 };
65 
66 template<bool Owned>
67 class TestFilter: public GenericFilter<TesterInterface,
68  TesterInterface::Callback,
69  &TesterInterface::setCallback,
70  Owned> {
71  public:
75  &TesterInterface::setCallback,
76  Owned>(true, true) {}
77 
78  TestFilter(bool calls, bool callbacks):
81  &TesterInterface::setCallback,
82  Owned>(calls, callbacks) {}
83 
85  this->setCallbackInternal(cb);
86  }
87  void doA() override {
88  do_++;
89  this->call_->doA();
90  }
91  void onA() override {
92  on_++;
93  this->callback_->onA();
94  }
95  uint32_t do_{0};
96  uint32_t on_{0};
97  uint32_t id_{idCounter_++};
99 };
100 template<bool Owned>
102 
103 template<bool Owned>
104 class TestFilterNoCallback: public TestFilter<Owned> {
105  public:
106  TestFilterNoCallback(): TestFilter<Owned>(true, false) {}
107 };
108 
109 template<bool Owned>
110 class TestFilterNoCall: public TestFilter<Owned> {
111  public:
112  TestFilterNoCall(): TestFilter<Owned>(false, true) {}
113 };
114 
115 template<bool Owned>
117  public:
118  TestFilterNoCallbackNoCall(): TestFilter<Owned>(false, false) {}
119 };
120 
121 template<bool Owned>
122 typename std::enable_if<Owned, unique_ptr<MockTester>>::type getTester() {
123  return std::make_unique<MockTester>();
124 }
125 
126 template<bool Owned>
128  return new MockTester();
129 }
130 
131 template<bool Owned>
133  public:
134  void basicTest();
135 
136  void testFilters(const std::deque<TestFilter<Owned>*>& filters,
137  MockTesterCallback* expectedCb);
138 
139  void SetUp() override {
140  chain_ = std::make_unique<
144  Owned>>(getTester<Owned>());
145  chain().setCallback(&callback_);
146  actor_ = CHECK_NOTNULL(static_cast<MockTester*>(chain_->call()));
147  }
151  return *chain_;
152  }
153 
154  template<typename FilterT>
156  return new FilterT();
157  }
158 
159  template<typename FilterT>
160  typename std::enable_if<Owned, unique_ptr<FilterT>>::type getFilter() {
161  return std::make_unique<FilterT>();
162  }
163 
164  template<typename FilterT>
165  void addFilterToChain(std::deque<TestFilter<Owned>*>& refs) {
166  auto f = getFilter<FilterT>();
167  refs.push_front(::detail::get_pointer(f));
168  chain().addFilters(std::move(f));
169  }
170 
171  std::deque<TestFilter<Owned>*> getRandomFilters(unsigned num) {
172  std::deque<TestFilter<Owned>*> filters;
173  srand(0);
174  for (unsigned i = 0; i < num; ++i) {
175  auto r = rand() % 4;
176  if (r == 0) {
177  addFilterToChain<TestFilter<Owned>>(filters);
178  } else if (r == 1) {
179  addFilterToChain<TestFilterNoCall<Owned>>(filters);
180  } else if (r == 2) {
181  addFilterToChain<TestFilterNoCallback<Owned>>(filters);
182  } else if (r == 3) {
183  addFilterToChain<TestFilterNoCallbackNoCall<Owned>>(filters);
184  }
185  basicTest();
186  }
187  return filters;
188  }
189 
191  unique_ptr<FilterChain<TesterInterface, TesterInterface::Callback,
192  TestFilter<Owned>,
194  MockTester* actor_{nullptr};
195 };
196 
197 template<bool Owned>
199  InSequence enforceOrder;
200 
201  // Test call side
202  EXPECT_CALL(*actor_, doA());
203  chain()->doA();
204 
205  // Now poke the callback side
206  EXPECT_CALL(callback_, onA());
207  CHECK_NOTNULL(actor_->cb_);
208  actor_->cb_->onA();
209 }
210 
211 template<bool Owned> void GenericFilterTest<Owned>::testFilters(
212  const std::deque<TestFilter<Owned>*>& filters,
213  MockTesterCallback* expectedCb) {
214  for (auto f: filters) {
215  f->do_ = 0;
216  f->on_ = 0;
217  }
218  // Call
219  EXPECT_CALL(*actor_, doA());
220  chain()->doA();
221  // Callback
222  if (expectedCb) {
223  EXPECT_CALL(*expectedCb, onA());
224  CHECK_NOTNULL(actor_->cb_);
225  actor_->cb_->onA();
226  }
227  for (auto f: filters) {
228  if (f->kWantsCalls_) {
229  EXPECT_EQ(f->do_, 1);
230  } else {
231  EXPECT_EQ(f->do_, 0);
232  }
233  if (f->kWantsCallbacks_) {
234  EXPECT_EQ(f->on_, expectedCb ? 1 : 0);
235  } else {
236  EXPECT_EQ(f->on_, 0);
237  }
238  }
239 }
240 
243 
245  basicTest();
246 }
247 
248 TEST_F(OwnedGenericFilterTest, SingleElemChain) {
249  auto filterUnique = std::make_unique<TestFilter<true>>();
250  auto filter = filterUnique.get();
251  chain().addFilters(std::move(filterUnique));
252  EXPECT_EQ(filter->do_, 0);
253  EXPECT_EQ(filter->on_, 0);
254  basicTest();
255  EXPECT_EQ(filter->do_, 1);
256  EXPECT_EQ(filter->on_, 1);
257 }
258 
259 TEST_F(OwnedGenericFilterTest, MultiElemChain) {
260  auto f1 = std::make_unique<TestFilter<true>>();
261  auto f2 = std::make_unique<TestFilter<true>>();
262  auto f3 = std::make_unique<TestFilter<true>>();
263  TestFilter<true>* fp1 = f1.get();
264  TestFilter<true>* fp2 = f2.get();
265  TestFilter<true>* fp3 = f3.get();
266  chain().addFilters(std::move(f1), std::move(f2), std::move(f3));
267  basicTest();
268  EXPECT_EQ(fp1->do_, 1);
269  EXPECT_EQ(fp1->on_, 1);
270  EXPECT_EQ(fp2->do_, 1);
271  EXPECT_EQ(fp2->on_, 1);
272  EXPECT_EQ(fp3->do_, 1);
273  EXPECT_EQ(fp3->on_, 1);
274 }
275 
276 TEST_F(OwnedGenericFilterTest, MultiElemMultiAdd) {
277  std::deque<TestFilter<true>*> filters;
278  for (unsigned i = 0; i < 10; ++i) {
279  auto filter = std::make_unique<TestFilter<true>>();
280  filters.push_back(filter.get());
281  chain().addFilters(std::move(filter));
282  }
283  basicTest();
284  for (auto filter: filters) {
285  EXPECT_EQ(filter->do_, 1);
286  EXPECT_EQ(filter->on_, 1);
287  }
288 }
289 
291  auto f1 = std::make_unique<TestFilter<true>>();
292  auto f2 = std::make_unique<TestFilterNoCallback<true>>();
293  auto f3 = std::make_unique<TestFilterNoCall<true>>();
294  auto f4 = std::make_unique<TestFilterNoCallbackNoCall<true>>();
295  TestFilter<true>* fp1 = f1.get();
296  TestFilter<true>* fp2 = f2.get();
297  TestFilter<true>* fp3 = f3.get();
298  TestFilter<true>* fp4 = f4.get();
299  chain().addFilters(std::move(f1), std::move(f2),
300  std::move(f3), std::move(f4));
301  basicTest();
302  EXPECT_EQ(fp1->do_, 1);
303  EXPECT_EQ(fp1->on_, 1);
304  // Only calls
305  EXPECT_EQ(fp2->do_, 1);
306  EXPECT_EQ(fp2->on_, 0);
307  // Only callbacks
308  EXPECT_EQ(fp3->do_, 0);
309  EXPECT_EQ(fp3->on_, 1);
310  // No callbacks or calls
311  EXPECT_EQ(fp4->do_, 0);
312  EXPECT_EQ(fp4->on_, 0);
313 }
314 
316  auto f1 = std::make_unique<TestFilterNoCallback<true>>();
317  auto f2 = std::make_unique<TestFilterNoCall<true>>();
318  TestFilter<true>* fp1 = f1.get();
319  TestFilter<true>* fp2 = f2.get();
320  chain().addFilters(std::move(f1));
321  basicTest();
322 
323  EXPECT_EQ(fp1->do_, 1);
324  EXPECT_EQ(fp1->on_, 0);
325  EXPECT_EQ(fp2->do_, 0);
326  EXPECT_EQ(fp2->on_, 0);
327 
328  chain().addFilters(std::move(f2));
329  basicTest();
330 
331  EXPECT_EQ(fp1->do_, 2);
332  EXPECT_EQ(fp1->on_, 0);
333  EXPECT_EQ(fp2->do_, 0);
334  EXPECT_EQ(fp2->on_, 1);
335 }
336 
337 TEST_F(OwnedGenericFilterTest, WantsMultiAddHard) {
338  const unsigned NUM_FILTERS = 5000;
339  auto filters = getRandomFilters(NUM_FILTERS);
340  // Now check the counts on each filter. Filters are pushed to the front
341  // of the chain, so filters towards the front have low call/callback counts
342  for (unsigned i = 0; i < NUM_FILTERS; ++i) {
343  auto f = filters[i];
344  if (f->kWantsCalls_) {
345  EXPECT_EQ(f->do_, i + 1);
346  } else {
347  EXPECT_EQ(f->do_, 0);
348  }
349  if (f->kWantsCallbacks_) {
350  EXPECT_EQ(f->on_, i + 1);
351  } else {
352  EXPECT_EQ(f->on_, 0);
353  }
354  }
355 }
356 
357 TEST_F(OwnedGenericFilterTest, ChangeCallback) {
358  // The call-only filter in the chain doesn't want callbacks, so doing
359  // chain()->setCallback() is an error! Instead, must use chain().setCallback()
360  auto f = std::make_unique<TestFilterNoCallback<true>>();
361  MockTesterCallback callback2;
362 
363  TestFilter<true>* fp = f.get();
364  chain().addFilters(std::move(f));
365  basicTest();
366 
367  EXPECT_EQ(fp->do_, 1);
368  EXPECT_EQ(fp->on_, 0);
369 
370  chain().setCallback(&callback2);
371  EXPECT_EQ(actor_->cb_, &callback2);
372  EXPECT_CALL(callback2, onA());
373  actor_->cb_->onA();
374 
375  EXPECT_EQ(fp->on_, 0);
376 }
377 
379  const unsigned NUM_FILTERS = 5000;
380  auto filters = getRandomFilters(NUM_FILTERS);
381  // Now check the counts on each filter
382  unsigned i = 0;
383  for (auto f: filters) {
384  if (f->kWantsCalls_) {
385  EXPECT_EQ(f->do_, i + 1);
386  } else {
387  EXPECT_EQ(f->do_, 0);
388  }
389  if (f->kWantsCallbacks_) {
390  EXPECT_EQ(f->on_, i + 1);
391  } else {
392  EXPECT_EQ(f->on_, 0);
393  }
394  delete f;
395  ++i;
396  }
397  delete actor_;
398 }
399 
401  // Some objects have a special behavior when the callback is set to
402  // nullptr. So in this case, we need to make sure it propagates
403  auto filters = getRandomFilters(100);
404  chain().setCallback(nullptr);
405  CHECK(nullptr == actor_->cb_);
406 
407  testFilters(filters, nullptr);
408 
409  MockTesterCallback head;
410  chain().setCallback(&head);
411 
412  testFilters(filters, &head);
413 
414  TesterInterface::Callback* cb = &head;
415  for (auto f: filters) {
416  if (f->kWantsCallbacks_) {
417  cb = f;
418  }
419  }
420  // The actor's callback should be the last filter in the chain that
421  // wants callbacks
422  ASSERT_EQ(actor_->cb_, cb);
423 }
424 
425 // This class owns itself
426 class TestFilterOddDeleteDo: public TestFilter<false> {
427  public:
428  explicit TestFilterOddDeleteDo(int* deletions):
429  TestFilter<false>(true, true),
430  deletions_(CHECK_NOTNULL(deletions)) {}
431  ~TestFilterOddDeleteDo() override { ++*deletions_; }
432 
433  void doA() override {
434  auto call = call_;
435  if (id_ % 2) {
436  delete this;
437  } else if (times_++) {
438  delete this;
439  }
440  call->doA();
441  };
442  unsigned times_{0};
443  int* const deletions_;
444 };
445 
447  // Test where a filter in the middle of the chain deletes itself early
448  int deletions = 0;
449 
450  for (unsigned i = 0; i < 4; ++i) {
451  chain().addFilters(new TestFilterOddDeleteDo(&deletions));
452  }
453 
454  for (unsigned i = 0; i < 2; ++i) {
455  // First time around, the odd id's get deleted
456  // Second time should just forward the calls normally
457  EXPECT_CALL(*actor_, doA());
458  chain()->doA();
459  EXPECT_EQ(deletions, (i + 1) * 2);
460  }
461  basicTest();
462  delete actor_;
463 }
464 
465 template<bool Owned=false>
466 class TestFilterOddDeleteOn: public TestFilter<Owned> {
467  public:
468  explicit TestFilterOddDeleteOn(int* deletions):
469  deletions_(CHECK_NOTNULL(deletions)) {}
470  ~TestFilterOddDeleteOn() override { ++*deletions_; }
471 
472  void onA() override {
473  auto callback = this->callback_;
474  if (this->id_ % 2) {
475  delete this;
476  } else if (times_++) {
477  delete this;
478  }
479  callback->onA();
480  };
481  unsigned times_{0};
482  int* const deletions_;
483 };
484 
486  // Test where a filter in the middle of the chain deletes itself early
487  int deletions = 0;
488 
489  for (unsigned i = 0; i < 4; ++i) {
490  chain().addFilters(new TestFilterOddDeleteOn<>(&deletions));
491  }
492 
493  for (unsigned i = 0; i < 2; ++i) {
494  // First time around, the odd id's get deleted
495  // Second time should just forward the calls normally
496  EXPECT_CALL(callback_, onA());
497  actor_->cb_->onA();
498  EXPECT_EQ(deletions, (i + 1) * 2);
499  }
500  basicTest();
501  delete actor_;
502 }
503 
505  // Add some filters to the chain and reset the chain. Make sure all the
506  // filters are deleted.
507  const unsigned NUM_FILTERS = 1000;
508  int deletions = 0;
509  for (unsigned i = 0; i < NUM_FILTERS; ++i) {
510  chain().addFilters(
512  }
513  chain_.reset();
514  EXPECT_EQ(deletions, NUM_FILTERS);
515 }
516 
518  for (unsigned i = 1; i < 100; ++i) {
519  auto filters = getRandomFilters(i);
520  EXPECT_EQ(actor_, &chain().getChainEnd());
521  }
522 }
523 
524 TEST_F(OwnedGenericFilterTest, SetDestination) {
525  auto filters = getRandomFilters(20);
526  EXPECT_CALL(*actor_, doA());
527  chain()->doA();
528  auto tester2 = getTester<true>();
529  actor_ = tester2.get();
530  auto oldTester = chain().setDestination(std::move(tester2));
531  EXPECT_CALL(*actor_, doA());
532  chain()->doA();
533 }
534 
536  auto filters = getRandomFilters(20);
537  size_t count = 0;
538  chain().foreach([&count] (GenericFilter<TesterInterface,
541  std::default_delete<TesterInterface> >* filter) {
542  if (dynamic_cast<TestFilter<true>*>(filter)) {
543  count++;
544  }
545  });
546  EXPECT_EQ(count, 20);
547 }
void * ptr
void addFilterToChain(std::deque< TestFilter< Owned > * > &refs)
std::enable_if<!Owned, FilterT * >::type getFilter()
auto f
std::deque< TestFilter< Owned > * > getRandomFilters(unsigned num)
PUSHMI_INLINE_VAR constexpr detail::filter_fn filter
Definition: filter.h:75
#define ASSERT_EQ(val1, val2)
Definition: gtest.h:1956
void SetUp() override
void doA() override
FilterChain< TesterInterface, TesterInterface::Callback, TestFilter< Owned >,&TesterInterface::setCallback, Owned > & chain()
std::enable_if< Owned, unique_ptr< MockTester > >::type getTester()
PskType type
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
virtual void setCallback(Callback *cb)=0
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
TestFilterOddDeleteOn(int *deletions)
unique_ptr< FilterChain< TesterInterface, TesterInterface::Callback, TestFilter< Owned >,&TesterInterface::setCallback, Owned > > chain_
std::unordered_map< std::string, IValidator * > refs
Definition: JSONSchema.cpp:104
folly::std T
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
void onA() override
MockTesterCallback callback_
std::enable_if< Owned, unique_ptr< FilterT > >::type getFilter()
std::unique_ptr< AsyncFizzServer::HandshakeCallback > cb_
std::enable_if<!std::is_array< T >::value, std::unique_ptr< T > >::type make_unique(Args &&...args)
Definition: Memory.h:259
void setCallback(TesterInterface::Callback *cb) override
TEST_F(AsyncSSLSocketWriteTest, write_coalescing1)
void testFilters(const std::deque< TestFilter< Owned > * > &filters, MockTesterCallback *expectedCb)
int * count
const Value * get_pointer(const Expected< Value, Error > &ex) noexcept
Definition: Expected.h:1374
static uint32_t idCounter_
void setCallback(Callback *cb) override
void basicTest()
#define EXPECT_CALL(obj, call)
folly::Function< void()> callback_
TestFilterOddDeleteDo(int *deletions)
TestFilter(bool calls, bool callbacks)
Future< bool > call(int depth, Executor *executor)
T * get_pointer(const unique_ptr< T > &ptr)
virtual ~TesterInterface()
#define MOCK_METHOD0(m,...)