• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 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 #ifndef GRPC_TEST_CORE_CALL_BATCH_BUILDER_H
16 #define GRPC_TEST_CORE_CALL_BATCH_BUILDER_H
17 
18 #include "absl/strings/str_cat.h"
19 #include "gtest/gtest.h"
20 #include "src/core/lib/slice/slice.h"
21 #include "test/core/end2end/cq_verifier.h"
22 
23 namespace grpc_core {
24 
25 using ByteBufferUniquePtr =
26     std::unique_ptr<grpc_byte_buffer, void (*)(grpc_byte_buffer*)>;
27 ByteBufferUniquePtr ByteBufferFromSlice(Slice slice);
28 
29 absl::optional<std::string> FindInMetadataArray(const grpc_metadata_array& md,
30                                                 absl::string_view key);
31 
32 // Receiving container for incoming metadata.
33 class IncomingMetadata final : public CqVerifier::SuccessfulStateString {
34  public:
35   IncomingMetadata() = default;
~IncomingMetadata()36   ~IncomingMetadata() {
37     if (metadata_ != nullptr) grpc_metadata_array_destroy(metadata_.get());
38   }
39 
40   // Lookup a metadata value by key.
41   absl::optional<std::string> Get(absl::string_view key) const;
42 
43   // Make a GRPC_RECV_INITIAL_METADATA op - intended for the framework, not
44   // for tests.
45   grpc_op MakeOp();
46 
47   std::string GetSuccessfulStateString() override;
48 
49  private:
50   std::unique_ptr<grpc_metadata_array> metadata_ =
51       std::make_unique<grpc_metadata_array>(grpc_metadata_array{0, 0, nullptr});
52 };
53 
54 // Receiving container for one incoming message.
55 class IncomingMessage final : public CqVerifier::SuccessfulStateString {
56  public:
57   IncomingMessage() = default;
58   IncomingMessage(const IncomingMessage&) = delete;
59   IncomingMessage& operator=(const IncomingMessage&) = delete;
~IncomingMessage()60   ~IncomingMessage() {
61     if (payload_ != nullptr) grpc_byte_buffer_destroy(payload_);
62   }
63 
64   // Get the payload of the message - concatenated together into a string for
65   // easy verification.
66   std::string payload() const;
67   // Check if the message is the end of the stream.
is_end_of_stream()68   bool is_end_of_stream() const { return payload_ == nullptr; }
69   // Get the type of the message.
byte_buffer_type()70   grpc_byte_buffer_type byte_buffer_type() const { return payload_->type; }
71   // Get the compression algorithm used for the message.
compression()72   grpc_compression_algorithm compression() const {
73     return payload_->data.raw.compression;
74   }
75   std::string GetSuccessfulStateString() override;
76 
77   // Make a GRPC_OP_RECV_MESSAGE op - intended for the framework, not for
78   // tests.
79   grpc_op MakeOp();
80 
81   // Accessor for CoreEnd2endTest::IncomingCall - get a pointer to the
82   // underlying payload.
83   // We don't want to use this in tests directly.
raw_payload_ptr()84   grpc_byte_buffer** raw_payload_ptr() { return &payload_; }
85 
86  private:
87   grpc_byte_buffer* payload_ = nullptr;
88 };
89 
90 // Receiving container for incoming status on the client from the server.
91 class IncomingStatusOnClient final : public CqVerifier::SuccessfulStateString {
92  public:
93   IncomingStatusOnClient() = default;
94   IncomingStatusOnClient(const IncomingStatusOnClient&) = delete;
95   IncomingStatusOnClient& operator=(const IncomingStatusOnClient&) = delete;
96   IncomingStatusOnClient(IncomingStatusOnClient&& other) noexcept = default;
97   IncomingStatusOnClient& operator=(IncomingStatusOnClient&& other) noexcept =
98       default;
~IncomingStatusOnClient()99   ~IncomingStatusOnClient() {
100     if (data_ != nullptr) {
101       grpc_metadata_array_destroy(&data_->trailing_metadata);
102       gpr_free(const_cast<char*>(data_->error_string));
103     }
104   }
105 
106   // Get the status code.
status()107   grpc_status_code status() const { return data_->status; }
108   // Get the status details.
message()109   std::string message() const {
110     return std::string(data_->status_details.as_string_view());
111   }
112   // Get the error string.
error_string()113   std::string error_string() const {
114     return data_->error_string == nullptr ? "" : data_->error_string;
115   }
116   // Get a trailing metadata value by key.
117   absl::optional<std::string> GetTrailingMetadata(absl::string_view key) const;
118 
119   std::string GetSuccessfulStateString() override;
120 
121   // Make a GRPC_OP_RECV_STATUS_ON_CLIENT op - intended for the framework, not
122   // for tests.
123   grpc_op MakeOp();
124 
125  private:
126   struct Data {
127     grpc_metadata_array trailing_metadata{0, 0, nullptr};
128     grpc_status_code status;
129     Slice status_details;
130     const char* error_string = nullptr;
131   };
132   std::unique_ptr<Data> data_ = std::make_unique<Data>();
133 };
134 
135 // Receiving container for incoming status on the server from the client.
136 class IncomingCloseOnServer final : public CqVerifier::SuccessfulStateString {
137  public:
138   IncomingCloseOnServer() = default;
139   IncomingCloseOnServer(const IncomingCloseOnServer&) = delete;
140   IncomingCloseOnServer& operator=(const IncomingCloseOnServer&) = delete;
141 
142   // Get the cancellation bit.
was_cancelled()143   bool was_cancelled() const { return cancelled_ != 0; }
144 
145   // Make a GRPC_OP_RECV_CLOSE_ON_SERVER op - intended for the framework, not
146   // for tests.
147   grpc_op MakeOp();
148 
GetSuccessfulStateString()149   std::string GetSuccessfulStateString() override {
150     return absl::StrCat("close_on_server: cancelled=", cancelled_);
151   }
152 
153  private:
154   int cancelled_;
155 };
156 
157 // Build one batch. Returned from NewBatch (use that to instantiate this!)
158 // Upon destruction of the BatchBuilder, the batch will be executed with any
159 // added batches.
160 class BatchBuilder {
161  public:
BatchBuilder(grpc_call * call,CqVerifier * cq_verifier,int tag)162   BatchBuilder(grpc_call* call, CqVerifier* cq_verifier, int tag)
163       : call_(call), tag_(tag), cq_verifier_(cq_verifier) {
164     cq_verifier_->ClearSuccessfulStateStrings(CqVerifier::tag(tag_));
165   }
166   ~BatchBuilder();
167 
168   BatchBuilder(const BatchBuilder&) = delete;
169   BatchBuilder& operator=(const BatchBuilder&) = delete;
170   BatchBuilder(BatchBuilder&&) noexcept = default;
171 
172   // Add a GRPC_OP_SEND_INITIAL_METADATA op.
173   // Optionally specify flags, compression level.
174   BatchBuilder& SendInitialMetadata(
175       std::initializer_list<std::pair<absl::string_view, absl::string_view>> md,
176       uint32_t flags = 0,
177       absl::optional<grpc_compression_level> compression_level = absl::nullopt);
178 
179   // Add a GRPC_OP_SEND_MESSAGE op.
180   BatchBuilder& SendMessage(Slice payload, uint32_t flags = 0);
181   BatchBuilder& SendMessage(absl::string_view payload, uint32_t flags = 0) {
182     return SendMessage(Slice::FromCopiedString(payload), flags);
183   }
184 
185   // Add a GRPC_OP_SEND_CLOSE_FROM_CLIENT op.
186   BatchBuilder& SendCloseFromClient();
187 
188   // Add a GRPC_OP_SEND_STATUS_FROM_SERVER op.
189   BatchBuilder& SendStatusFromServer(
190       grpc_status_code status, absl::string_view message,
191       std::initializer_list<std::pair<absl::string_view, absl::string_view>>
192           md);
193 
194   // Add a GRPC_OP_RECV_INITIAL_METADATA op.
RecvInitialMetadata(IncomingMetadata & md)195   BatchBuilder& RecvInitialMetadata(IncomingMetadata& md) {
196     cq_verifier_->AddSuccessfulStateString(CqVerifier::tag(tag_), &md);
197     ops_.emplace_back(md.MakeOp());
198     return *this;
199   }
200 
201   // Add a GRPC_OP_RECV_MESSAGE op.
RecvMessage(IncomingMessage & msg)202   BatchBuilder& RecvMessage(IncomingMessage& msg) {
203     cq_verifier_->AddSuccessfulStateString(CqVerifier::tag(tag_), &msg);
204     ops_.emplace_back(msg.MakeOp());
205     return *this;
206   }
207 
208   // Add a GRPC_OP_RECV_STATUS_ON_CLIENT op.
RecvStatusOnClient(IncomingStatusOnClient & status)209   BatchBuilder& RecvStatusOnClient(IncomingStatusOnClient& status) {
210     cq_verifier_->AddSuccessfulStateString(CqVerifier::tag(tag_), &status);
211     ops_.emplace_back(status.MakeOp());
212     return *this;
213   }
214 
215   // Add a GRPC_OP_RECV_CLOSE_ON_SERVER op.
RecvCloseOnServer(IncomingCloseOnServer & close)216   BatchBuilder& RecvCloseOnServer(IncomingCloseOnServer& close) {
217     cq_verifier_->AddSuccessfulStateString(CqVerifier::tag(tag_), &close);
218     ops_.emplace_back(close.MakeOp());
219     return *this;
220   }
221 
222  private:
223   // We need to track little bits of memory up until the batch is executed.
224   // One Thing is one such block of memory.
225   // We specialize it with SpecificThing to track a specific type of memory.
226   // These get placed on things_ and deleted when the batch is executed.
227   class Thing {
228    public:
229     virtual ~Thing() = default;
230   };
231   template <typename T>
232   class SpecificThing final : public Thing {
233    public:
234     template <typename... Args>
SpecificThing(Args &&...args)235     explicit SpecificThing(Args&&... args) : t_(std::forward<Args>(args)...) {}
236     SpecificThing() = default;
237 
get()238     T& get() { return t_; }
239 
240    private:
241     T t_;
242   };
243 
244   // Make a thing of type T, and return a reference to it.
245   template <typename T, typename... Args>
Make(Args &&...args)246   T& Make(Args&&... args) {
247     things_.emplace_back(new SpecificThing<T>(std::forward<Args>(args)...));
248     return static_cast<SpecificThing<T>*>(things_.back().get())->get();
249   }
250 
251   grpc_call* call_;
252   const int tag_;
253   std::vector<grpc_op> ops_;
254   std::vector<std::unique_ptr<Thing>> things_;
255   CqVerifier* const cq_verifier_;
256 };
257 
258 }  // namespace grpc_core
259 
260 #endif  // GRPC_TEST_CORE_CALL_BATCH_BUILDER_H
261