1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
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.
7  */
8 
9 #pragma once
10 #include <folly/portability/GTest.h>
11 #include <proxygen/lib/http/codec/HTTPParallelCodec.h>
12 #include <proxygen/lib/http/codec/test/TestUtils.h>
13 #include <proxygen/lib/utils/Logging.h>
14 
15 class HTTPParallelCodecTest : public testing::Test {
16  public:
HTTPParallelCodecTest(proxygen::HTTPParallelCodec & upstreamCodec,proxygen::HTTPParallelCodec & downstreamCodec)17   HTTPParallelCodecTest(proxygen::HTTPParallelCodec& upstreamCodec,
18                         proxygen::HTTPParallelCodec& downstreamCodec)
19       : upstreamCodec_(upstreamCodec), downstreamCodec_(downstreamCodec) {
20   }
21 
SetUp()22   void SetUp() override {
23     downstreamCodec_.setCallback(&callbacks_);
24     upstreamCodec_.setCallback(&callbacks_);
25     // Most tests are downstream tests, so generate the upstream conn preface
26     // by default
27     upstreamCodec_.generateConnectionPreface(output_);
28   }
29 
SetUpUpstreamTest()30   void SetUpUpstreamTest() {
31     output_.move();
32     downstreamCodec_.generateConnectionPreface(output_); // no-op
33     downstreamCodec_.generateSettings(output_);
34   }
35 
36   bool parse(std::function<void(folly::IOBuf*)> hackIngress =
37                  std::function<void(folly::IOBuf*)>()) {
38     return parseImpl(downstreamCodec_, hackIngress);
39   }
40 
41   bool parseUpstream(std::function<void(folly::IOBuf*)> hackIngress =
42                          std::function<void(folly::IOBuf*)>()) {
43     return parseImpl(upstreamCodec_, hackIngress);
44   }
45 
46   /*
47    * hackIngress is used to keep the codec's strict checks while having
48    * separate checks for tests
49    */
parseImpl(proxygen::HTTPParallelCodec & codec,std::function<void (folly::IOBuf *)> hackIngress)50   bool parseImpl(proxygen::HTTPParallelCodec& codec,
51                  std::function<void(folly::IOBuf*)> hackIngress) {
52     dumpToFile(codec.getTransportDirection() ==
53                proxygen::TransportDirection::UPSTREAM);
54     auto ingress = output_.move();
55     if (hackIngress) {
56       hackIngress(ingress.get());
57     }
58     size_t parsed = codec.onIngress(*ingress);
59     return (parsed == ingress->computeChainDataLength());
60   }
61 
62   /*
63    * dumpToFile dumps binary frames to files ("/tmp/http2_*.bin"),
64    * allowing debugging individual frames.
65    * @note: assign true to dump_ to turn on dumpToFile
66    */
67   void dumpToFile(bool isUpstream = false) {
68     if (!dump_) {
69       return;
70     }
71     auto endpoint = isUpstream ? "client" : "server";
72     auto filename = folly::to<std::string>(
73         "/tmp/parallel_", endpoint, "_", testInfo_->name(), ".bin");
74     proxygen::dumpBinToFile(filename, output_.front());
75   }
76 
77  protected:
78   proxygen::FakeHTTPCodecCallback callbacks_;
79   proxygen::HTTPParallelCodec& upstreamCodec_;
80   proxygen::HTTPParallelCodec& downstreamCodec_;
81   folly::IOBufQueue output_{folly::IOBufQueue::cacheChainLength()};
82   const testing::TestInfo* testInfo_{
83       testing::UnitTest::GetInstance()->current_test_info()};
84   bool dump_{false};
85 };
86