1 // Copyright 2021 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 "quiche/quic/core/quic_connection_context.h"
6
7 #include "quiche/quic/platform/api/quic_test.h"
8 #include "quiche/quic/platform/api/quic_thread.h"
9
10 using testing::ElementsAre;
11
12 namespace quic::test {
13 namespace {
14
15 class TraceCollector : public QuicConnectionTracer {
16 public:
17 ~TraceCollector() override = default;
18
PrintLiteral(const char * literal)19 void PrintLiteral(const char* literal) override { trace_.push_back(literal); }
20
PrintString(absl::string_view s)21 void PrintString(absl::string_view s) override {
22 trace_.push_back(std::string(s));
23 }
24
trace() const25 const std::vector<std::string>& trace() const { return trace_; }
26
27 private:
28 std::vector<std::string> trace_;
29 };
30
31 struct FakeConnection {
FakeConnectionquic::test::__anon99a72df40111::FakeConnection32 FakeConnection() { context.tracer = std::make_unique<TraceCollector>(); }
33
tracequic::test::__anon99a72df40111::FakeConnection34 const std::vector<std::string>& trace() const {
35 return static_cast<const TraceCollector*>(context.tracer.get())->trace();
36 }
37
38 QuicConnectionContext context;
39 };
40
SimpleSwitch()41 void SimpleSwitch() {
42 FakeConnection connection;
43
44 // These should be ignored since current context is nullptr.
45 EXPECT_EQ(QuicConnectionContext::Current(), nullptr);
46 QUIC_TRACELITERAL("before switch: literal");
47 QUIC_TRACESTRING(std::string("before switch: string"));
48 QUIC_TRACEPRINTF("%s: %s", "before switch", "printf");
49
50 {
51 QuicConnectionContextSwitcher switcher(&connection.context);
52 QUIC_TRACELITERAL("literal");
53 QUIC_TRACESTRING(std::string("string"));
54 QUIC_TRACEPRINTF("%s", "printf");
55 }
56
57 EXPECT_EQ(QuicConnectionContext::Current(), nullptr);
58 QUIC_TRACELITERAL("after switch: literal");
59 QUIC_TRACESTRING(std::string("after switch: string"));
60 QUIC_TRACEPRINTF("%s: %s", "after switch", "printf");
61
62 EXPECT_THAT(connection.trace(), ElementsAre("literal", "string", "printf"));
63 }
64
NestedSwitch()65 void NestedSwitch() {
66 FakeConnection outer, inner;
67
68 {
69 QuicConnectionContextSwitcher switcher(&outer.context);
70 QUIC_TRACELITERAL("outer literal 0");
71 QUIC_TRACESTRING(std::string("outer string 0"));
72 QUIC_TRACEPRINTF("%s %s %d", "outer", "printf", 0);
73
74 {
75 QuicConnectionContextSwitcher nested_switcher(&inner.context);
76 QUIC_TRACELITERAL("inner literal");
77 QUIC_TRACESTRING(std::string("inner string"));
78 QUIC_TRACEPRINTF("%s %s", "inner", "printf");
79 }
80
81 QUIC_TRACELITERAL("outer literal 1");
82 QUIC_TRACESTRING(std::string("outer string 1"));
83 QUIC_TRACEPRINTF("%s %s %d", "outer", "printf", 1);
84 }
85
86 EXPECT_THAT(outer.trace(), ElementsAre("outer literal 0", "outer string 0",
87 "outer printf 0", "outer literal 1",
88 "outer string 1", "outer printf 1"));
89
90 EXPECT_THAT(inner.trace(),
91 ElementsAre("inner literal", "inner string", "inner printf"));
92 }
93
AlternatingSwitch()94 void AlternatingSwitch() {
95 FakeConnection zero, one, two;
96 for (int i = 0; i < 15; ++i) {
97 FakeConnection* connection =
98 ((i % 3) == 0) ? &zero : (((i % 3) == 1) ? &one : &two);
99
100 QuicConnectionContextSwitcher switcher(&connection->context);
101 QUIC_TRACEPRINTF("%d", i);
102 }
103
104 EXPECT_THAT(zero.trace(), ElementsAre("0", "3", "6", "9", "12"));
105 EXPECT_THAT(one.trace(), ElementsAre("1", "4", "7", "10", "13"));
106 EXPECT_THAT(two.trace(), ElementsAre("2", "5", "8", "11", "14"));
107 }
108
109 typedef void (*ThreadFunction)();
110
111 template <ThreadFunction func>
112 class TestThread : public QuicThread {
113 public:
TestThread()114 TestThread() : QuicThread("TestThread") {}
115 ~TestThread() override = default;
116
117 protected:
Run()118 void Run() override { func(); }
119 };
120
121 template <ThreadFunction func>
RunInThreads(size_t n_threads)122 void RunInThreads(size_t n_threads) {
123 using ThreadType = TestThread<func>;
124 std::vector<ThreadType> threads(n_threads);
125
126 for (ThreadType& t : threads) {
127 t.Start();
128 }
129
130 for (ThreadType& t : threads) {
131 t.Join();
132 }
133 }
134
135 class QuicConnectionContextTest : public QuicTest {
136 protected:
137 };
138
TEST_F(QuicConnectionContextTest,NullTracerOK)139 TEST_F(QuicConnectionContextTest, NullTracerOK) {
140 FakeConnection connection;
141 std::unique_ptr<QuicConnectionTracer> tracer;
142
143 {
144 QuicConnectionContextSwitcher switcher(&connection.context);
145 QUIC_TRACELITERAL("msg 1 recorded");
146 }
147
148 connection.context.tracer.swap(tracer);
149
150 {
151 QuicConnectionContextSwitcher switcher(&connection.context);
152 // Should be a no-op since connection.context.tracer is nullptr.
153 QUIC_TRACELITERAL("msg 2 ignored");
154 }
155
156 EXPECT_THAT(static_cast<TraceCollector*>(tracer.get())->trace(),
157 ElementsAre("msg 1 recorded"));
158 }
159
TEST_F(QuicConnectionContextTest,TestSimpleSwitch)160 TEST_F(QuicConnectionContextTest, TestSimpleSwitch) {
161 RunInThreads<SimpleSwitch>(10);
162 }
163
TEST_F(QuicConnectionContextTest,TestNestedSwitch)164 TEST_F(QuicConnectionContextTest, TestNestedSwitch) {
165 RunInThreads<NestedSwitch>(10);
166 }
167
TEST_F(QuicConnectionContextTest,TestAlternatingSwitch)168 TEST_F(QuicConnectionContextTest, TestAlternatingSwitch) {
169 RunInThreads<AlternatingSwitch>(10);
170 }
171
172 } // namespace
173 } // namespace quic::test
174