1 // Copyright 2022 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/core/lib/promise/interceptor_list.h"
16
17 #include <grpc/event_engine/memory_allocator.h>
18
19 #include <memory>
20
21 #include "gtest/gtest.h"
22 #include "src/core/lib/resource_quota/arena.h"
23 #include "src/core/lib/resource_quota/memory_quota.h"
24 #include "src/core/lib/resource_quota/resource_quota.h"
25 #include "src/core/util/ref_counted_ptr.h"
26 #include "test/core/promise/test_context.h"
27
28 namespace grpc_core {
29 namespace {
30
31 class InterceptorListTest : public ::testing::Test {
32 protected:
33 RefCountedPtr<Arena> arena_ = SimpleArenaAllocator()->MakeArena();
34 TestContext<Arena> arena_ctx_{arena_.get()};
35 };
36
TEST_F(InterceptorListTest,NoOp)37 TEST_F(InterceptorListTest, NoOp) { InterceptorList<std::string>(); }
38
TEST_F(InterceptorListTest,CanRunOne)39 TEST_F(InterceptorListTest, CanRunOne) {
40 InterceptorList<std::string> list;
41 list.AppendMap([](std::string s) { return s + "a"; }, DEBUG_LOCATION);
42 EXPECT_EQ(list.Run("hello")(), Poll<absl::optional<std::string>>("helloa"));
43 }
44
TEST_F(InterceptorListTest,CanRunTwo)45 TEST_F(InterceptorListTest, CanRunTwo) {
46 InterceptorList<std::string> list;
47 list.AppendMap([](std::string s) { return s + "a"; }, DEBUG_LOCATION);
48 list.AppendMap([](std::string s) { return s + "b"; }, DEBUG_LOCATION);
49 EXPECT_EQ(list.Run("hello")(), Poll<absl::optional<std::string>>("helloab"));
50 }
51
TEST_F(InterceptorListTest,CanRunTwoTwice)52 TEST_F(InterceptorListTest, CanRunTwoTwice) {
53 InterceptorList<std::string> list;
54 list.AppendMap([](std::string s) { return s + s; }, DEBUG_LOCATION);
55 list.AppendMap([](std::string s) { return s + s + s; }, DEBUG_LOCATION);
56 EXPECT_EQ(list.Run(std::string(10, 'a'))().value().value(),
57 std::string(60, 'a'));
58 EXPECT_EQ(list.Run(std::string(100, 'b'))().value().value(),
59 std::string(600, 'b'));
60 }
61
TEST_F(InterceptorListTest,CanRunManyWithCaptures)62 TEST_F(InterceptorListTest, CanRunManyWithCaptures) {
63 InterceptorList<std::string> list;
64 for (size_t i = 0; i < 26 * 1000; i++) {
65 list.AppendMap(
66 [i = std::make_shared<size_t>(i)](std::string s) {
67 return s + static_cast<char>((*i % 26) + 'a');
68 },
69 DEBUG_LOCATION);
70 }
71 std::string expected;
72 for (size_t i = 0; i < 1000; i++) {
73 expected += "abcdefghijklmnopqrstuvwxyz";
74 }
75 EXPECT_EQ(list.Run("")().value().value(), expected);
76 }
77
TEST_F(InterceptorListTest,CanRunOnePrepended)78 TEST_F(InterceptorListTest, CanRunOnePrepended) {
79 InterceptorList<std::string> list;
80 list.PrependMap([](std::string s) { return s + "a"; }, DEBUG_LOCATION);
81 EXPECT_EQ(list.Run("hello")(), Poll<absl::optional<std::string>>("helloa"));
82 }
83
TEST_F(InterceptorListTest,CanRunTwoPrepended)84 TEST_F(InterceptorListTest, CanRunTwoPrepended) {
85 InterceptorList<std::string> list;
86 list.PrependMap([](std::string s) { return s + "a"; }, DEBUG_LOCATION);
87 list.PrependMap([](std::string s) { return s + "b"; }, DEBUG_LOCATION);
88 EXPECT_EQ(list.Run("hello")(), Poll<absl::optional<std::string>>("helloba"));
89 }
90
TEST_F(InterceptorListTest,CanRunManyWithCapturesPrepended)91 TEST_F(InterceptorListTest, CanRunManyWithCapturesPrepended) {
92 InterceptorList<std::string> list;
93 for (size_t i = 0; i < 26 * 1000; i++) {
94 list.PrependMap(
95 [i = std::make_shared<size_t>(i)](std::string s) {
96 return s + static_cast<char>((*i % 26) + 'a');
97 },
98 DEBUG_LOCATION);
99 }
100 std::string expected;
101 for (size_t i = 0; i < 1000; i++) {
102 expected += "zyxwvutsrqponmlkjihgfedcba";
103 }
104 EXPECT_EQ(list.Run("")().value().value(), expected);
105 }
106
TEST_F(InterceptorListTest,CanRunManyWithCapturesThatDelay)107 TEST_F(InterceptorListTest, CanRunManyWithCapturesThatDelay) {
108 InterceptorList<std::string> list;
109 for (size_t i = 0; i < 26 * 1000; i++) {
110 list.AppendMap(
111 [i = std::make_shared<size_t>(i)](std::string s) {
112 return
113 [x = false, i, s]() mutable -> Poll<absl::optional<std::string>> {
114 if (!x) {
115 x = true;
116 return Pending{};
117 }
118 return s + static_cast<char>((*i % 26) + 'a');
119 };
120 },
121 DEBUG_LOCATION);
122 }
123 auto promise = list.Run("");
124 for (size_t i = 0; i < 26 * 1000; i++) {
125 EXPECT_TRUE(promise().pending()) << i;
126 }
127 std::string expected;
128 for (size_t i = 0; i < 1000; i++) {
129 expected += "abcdefghijklmnopqrstuvwxyz";
130 }
131 EXPECT_EQ(promise().value().value(), expected);
132 }
133
134 } // namespace
135 } // namespace grpc_core
136
main(int argc,char ** argv)137 int main(int argc, char** argv) {
138 ::testing::InitGoogleTest(&argc, argv);
139 return RUN_ALL_TESTS();
140 }
141