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 <memory>
18
19 #include "gtest/gtest.h"
20
21 #include <grpc/event_engine/memory_allocator.h>
22
23 #include "src/core/lib/gprpp/ref_counted_ptr.h"
24 #include "src/core/lib/resource_quota/arena.h"
25 #include "src/core/lib/resource_quota/memory_quota.h"
26 #include "src/core/lib/resource_quota/resource_quota.h"
27 #include "test/core/promise/test_context.h"
28
29 namespace grpc_core {
30 namespace {
31
32 class InterceptorListTest : public ::testing::Test {
33 protected:
34 MemoryAllocator memory_allocator_ = MemoryAllocator(
35 ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator("test"));
36 ScopedArenaPtr arena_ = MakeScopedArena(1024, &memory_allocator_);
37 TestContext<Arena> arena_ctx_{arena_.get()};
38 };
39
TEST_F(InterceptorListTest,NoOp)40 TEST_F(InterceptorListTest, NoOp) { InterceptorList<std::string>(); }
41
TEST_F(InterceptorListTest,CanRunOne)42 TEST_F(InterceptorListTest, CanRunOne) {
43 InterceptorList<std::string> list;
44 list.AppendMap([](std::string s) { return s + "a"; }, DEBUG_LOCATION);
45 EXPECT_EQ(list.Run("hello")(), Poll<absl::optional<std::string>>("helloa"));
46 }
47
TEST_F(InterceptorListTest,CanRunTwo)48 TEST_F(InterceptorListTest, CanRunTwo) {
49 InterceptorList<std::string> list;
50 list.AppendMap([](std::string s) { return s + "a"; }, DEBUG_LOCATION);
51 list.AppendMap([](std::string s) { return s + "b"; }, DEBUG_LOCATION);
52 EXPECT_EQ(list.Run("hello")(), Poll<absl::optional<std::string>>("helloab"));
53 }
54
TEST_F(InterceptorListTest,CanRunTwoTwice)55 TEST_F(InterceptorListTest, CanRunTwoTwice) {
56 InterceptorList<std::string> list;
57 list.AppendMap([](std::string s) { return s + s; }, DEBUG_LOCATION);
58 list.AppendMap([](std::string s) { return s + s + s; }, DEBUG_LOCATION);
59 EXPECT_EQ(list.Run(std::string(10, 'a'))().value().value(),
60 std::string(60, 'a'));
61 EXPECT_EQ(list.Run(std::string(100, 'b'))().value().value(),
62 std::string(600, 'b'));
63 }
64
TEST_F(InterceptorListTest,CanRunManyWithCaptures)65 TEST_F(InterceptorListTest, CanRunManyWithCaptures) {
66 InterceptorList<std::string> list;
67 for (size_t i = 0; i < 26 * 1000; i++) {
68 list.AppendMap(
69 [i = std::make_shared<size_t>(i)](std::string s) {
70 return s + static_cast<char>((*i % 26) + 'a');
71 },
72 DEBUG_LOCATION);
73 }
74 std::string expected;
75 for (size_t i = 0; i < 1000; i++) {
76 expected += "abcdefghijklmnopqrstuvwxyz";
77 }
78 EXPECT_EQ(list.Run("")().value().value(), expected);
79 }
80
TEST_F(InterceptorListTest,CanRunOnePrepended)81 TEST_F(InterceptorListTest, CanRunOnePrepended) {
82 InterceptorList<std::string> list;
83 list.PrependMap([](std::string s) { return s + "a"; }, DEBUG_LOCATION);
84 EXPECT_EQ(list.Run("hello")(), Poll<absl::optional<std::string>>("helloa"));
85 }
86
TEST_F(InterceptorListTest,CanRunTwoPrepended)87 TEST_F(InterceptorListTest, CanRunTwoPrepended) {
88 InterceptorList<std::string> list;
89 list.PrependMap([](std::string s) { return s + "a"; }, DEBUG_LOCATION);
90 list.PrependMap([](std::string s) { return s + "b"; }, DEBUG_LOCATION);
91 EXPECT_EQ(list.Run("hello")(), Poll<absl::optional<std::string>>("helloba"));
92 }
93
TEST_F(InterceptorListTest,CanRunManyWithCapturesPrepended)94 TEST_F(InterceptorListTest, CanRunManyWithCapturesPrepended) {
95 InterceptorList<std::string> list;
96 for (size_t i = 0; i < 26 * 1000; i++) {
97 list.PrependMap(
98 [i = std::make_shared<size_t>(i)](std::string s) {
99 return s + static_cast<char>((*i % 26) + 'a');
100 },
101 DEBUG_LOCATION);
102 }
103 std::string expected;
104 for (size_t i = 0; i < 1000; i++) {
105 expected += "zyxwvutsrqponmlkjihgfedcba";
106 }
107 EXPECT_EQ(list.Run("")().value().value(), expected);
108 }
109
TEST_F(InterceptorListTest,CanRunManyWithCapturesThatDelay)110 TEST_F(InterceptorListTest, CanRunManyWithCapturesThatDelay) {
111 InterceptorList<std::string> list;
112 for (size_t i = 0; i < 26 * 1000; i++) {
113 list.AppendMap(
114 [i = std::make_shared<size_t>(i)](std::string s) {
115 return
116 [x = false, i, s]() mutable -> Poll<absl::optional<std::string>> {
117 if (!x) {
118 x = true;
119 return Pending{};
120 }
121 return s + static_cast<char>((*i % 26) + 'a');
122 };
123 },
124 DEBUG_LOCATION);
125 }
126 auto promise = list.Run("");
127 for (size_t i = 0; i < 26 * 1000; i++) {
128 EXPECT_TRUE(promise().pending()) << i;
129 }
130 std::string expected;
131 for (size_t i = 0; i < 1000; i++) {
132 expected += "abcdefghijklmnopqrstuvwxyz";
133 }
134 EXPECT_EQ(promise().value().value(), expected);
135 }
136
137 } // namespace
138 } // namespace grpc_core
139
main(int argc,char ** argv)140 int main(int argc, char** argv) {
141 ::testing::InitGoogleTest(&argc, argv);
142 return RUN_ALL_TESTS();
143 }
144