mirror of https://github.com/grpc/grpc.git
The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#)
https://grpc.io/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
260 lines
8.8 KiB
260 lines
8.8 KiB
// Copyright 2024 gRPC authors. |
|
// |
|
// Licensed under the Apache License, Version 2.0 (the "License"); |
|
// you may not use this file except in compliance with the License. |
|
// You may obtain a copy of the License at |
|
// |
|
// http://www.apache.org/licenses/LICENSE-2.0 |
|
// |
|
// Unless required by applicable law or agreed to in writing, software |
|
// distributed under the License is distributed on an "AS IS" BASIS, |
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
// See the License for the specific language governing permissions and |
|
// limitations under the License. |
|
|
|
#ifndef GRPC_TEST_CORE_CALL_BATCH_BUILDER_H |
|
#define GRPC_TEST_CORE_CALL_BATCH_BUILDER_H |
|
|
|
#include "absl/strings/str_cat.h" |
|
#include "gtest/gtest.h" |
|
#include "src/core/lib/slice/slice.h" |
|
#include "test/core/end2end/cq_verifier.h" |
|
|
|
namespace grpc_core { |
|
|
|
using ByteBufferUniquePtr = |
|
std::unique_ptr<grpc_byte_buffer, void (*)(grpc_byte_buffer*)>; |
|
ByteBufferUniquePtr ByteBufferFromSlice(Slice slice); |
|
|
|
absl::optional<std::string> FindInMetadataArray(const grpc_metadata_array& md, |
|
absl::string_view key); |
|
|
|
// Receiving container for incoming metadata. |
|
class IncomingMetadata final : public CqVerifier::SuccessfulStateString { |
|
public: |
|
IncomingMetadata() = default; |
|
~IncomingMetadata() { |
|
if (metadata_ != nullptr) grpc_metadata_array_destroy(metadata_.get()); |
|
} |
|
|
|
// Lookup a metadata value by key. |
|
absl::optional<std::string> Get(absl::string_view key) const; |
|
|
|
// Make a GRPC_RECV_INITIAL_METADATA op - intended for the framework, not |
|
// for tests. |
|
grpc_op MakeOp(); |
|
|
|
std::string GetSuccessfulStateString() override; |
|
|
|
private: |
|
std::unique_ptr<grpc_metadata_array> metadata_ = |
|
std::make_unique<grpc_metadata_array>(grpc_metadata_array{0, 0, nullptr}); |
|
}; |
|
|
|
// Receiving container for one incoming message. |
|
class IncomingMessage final : public CqVerifier::SuccessfulStateString { |
|
public: |
|
IncomingMessage() = default; |
|
IncomingMessage(const IncomingMessage&) = delete; |
|
IncomingMessage& operator=(const IncomingMessage&) = delete; |
|
~IncomingMessage() { |
|
if (payload_ != nullptr) grpc_byte_buffer_destroy(payload_); |
|
} |
|
|
|
// Get the payload of the message - concatenated together into a string for |
|
// easy verification. |
|
std::string payload() const; |
|
// Check if the message is the end of the stream. |
|
bool is_end_of_stream() const { return payload_ == nullptr; } |
|
// Get the type of the message. |
|
grpc_byte_buffer_type byte_buffer_type() const { return payload_->type; } |
|
// Get the compression algorithm used for the message. |
|
grpc_compression_algorithm compression() const { |
|
return payload_->data.raw.compression; |
|
} |
|
std::string GetSuccessfulStateString() override; |
|
|
|
// Make a GRPC_OP_RECV_MESSAGE op - intended for the framework, not for |
|
// tests. |
|
grpc_op MakeOp(); |
|
|
|
// Accessor for CoreEnd2endTest::IncomingCall - get a pointer to the |
|
// underlying payload. |
|
// We don't want to use this in tests directly. |
|
grpc_byte_buffer** raw_payload_ptr() { return &payload_; } |
|
|
|
private: |
|
grpc_byte_buffer* payload_ = nullptr; |
|
}; |
|
|
|
// Receiving container for incoming status on the client from the server. |
|
class IncomingStatusOnClient final : public CqVerifier::SuccessfulStateString { |
|
public: |
|
IncomingStatusOnClient() = default; |
|
IncomingStatusOnClient(const IncomingStatusOnClient&) = delete; |
|
IncomingStatusOnClient& operator=(const IncomingStatusOnClient&) = delete; |
|
IncomingStatusOnClient(IncomingStatusOnClient&& other) noexcept = default; |
|
IncomingStatusOnClient& operator=(IncomingStatusOnClient&& other) noexcept = |
|
default; |
|
~IncomingStatusOnClient() { |
|
if (data_ != nullptr) { |
|
grpc_metadata_array_destroy(&data_->trailing_metadata); |
|
gpr_free(const_cast<char*>(data_->error_string)); |
|
} |
|
} |
|
|
|
// Get the status code. |
|
grpc_status_code status() const { return data_->status; } |
|
// Get the status details. |
|
std::string message() const { |
|
return std::string(data_->status_details.as_string_view()); |
|
} |
|
// Get the error string. |
|
std::string error_string() const { |
|
return data_->error_string == nullptr ? "" : data_->error_string; |
|
} |
|
// Get a trailing metadata value by key. |
|
absl::optional<std::string> GetTrailingMetadata(absl::string_view key) const; |
|
|
|
std::string GetSuccessfulStateString() override; |
|
|
|
// Make a GRPC_OP_RECV_STATUS_ON_CLIENT op - intended for the framework, not |
|
// for tests. |
|
grpc_op MakeOp(); |
|
|
|
private: |
|
struct Data { |
|
grpc_metadata_array trailing_metadata{0, 0, nullptr}; |
|
grpc_status_code status; |
|
Slice status_details; |
|
const char* error_string = nullptr; |
|
}; |
|
std::unique_ptr<Data> data_ = std::make_unique<Data>(); |
|
}; |
|
|
|
// Receiving container for incoming status on the server from the client. |
|
class IncomingCloseOnServer final : public CqVerifier::SuccessfulStateString { |
|
public: |
|
IncomingCloseOnServer() = default; |
|
IncomingCloseOnServer(const IncomingCloseOnServer&) = delete; |
|
IncomingCloseOnServer& operator=(const IncomingCloseOnServer&) = delete; |
|
|
|
// Get the cancellation bit. |
|
bool was_cancelled() const { return cancelled_ != 0; } |
|
|
|
// Make a GRPC_OP_RECV_CLOSE_ON_SERVER op - intended for the framework, not |
|
// for tests. |
|
grpc_op MakeOp(); |
|
|
|
std::string GetSuccessfulStateString() override { |
|
return absl::StrCat("close_on_server: cancelled=", cancelled_); |
|
} |
|
|
|
private: |
|
int cancelled_; |
|
}; |
|
|
|
// Build one batch. Returned from NewBatch (use that to instantiate this!) |
|
// Upon destruction of the BatchBuilder, the batch will be executed with any |
|
// added batches. |
|
class BatchBuilder { |
|
public: |
|
BatchBuilder(grpc_call* call, CqVerifier* cq_verifier, int tag) |
|
: call_(call), tag_(tag), cq_verifier_(cq_verifier) { |
|
cq_verifier_->ClearSuccessfulStateStrings(CqVerifier::tag(tag_)); |
|
} |
|
~BatchBuilder(); |
|
|
|
BatchBuilder(const BatchBuilder&) = delete; |
|
BatchBuilder& operator=(const BatchBuilder&) = delete; |
|
BatchBuilder(BatchBuilder&&) noexcept = default; |
|
|
|
// Add a GRPC_OP_SEND_INITIAL_METADATA op. |
|
// Optionally specify flags, compression level. |
|
BatchBuilder& SendInitialMetadata( |
|
std::initializer_list<std::pair<absl::string_view, absl::string_view>> md, |
|
uint32_t flags = 0, |
|
absl::optional<grpc_compression_level> compression_level = absl::nullopt); |
|
|
|
// Add a GRPC_OP_SEND_MESSAGE op. |
|
BatchBuilder& SendMessage(Slice payload, uint32_t flags = 0); |
|
BatchBuilder& SendMessage(absl::string_view payload, uint32_t flags = 0) { |
|
return SendMessage(Slice::FromCopiedString(payload), flags); |
|
} |
|
|
|
// Add a GRPC_OP_SEND_CLOSE_FROM_CLIENT op. |
|
BatchBuilder& SendCloseFromClient(); |
|
|
|
// Add a GRPC_OP_SEND_STATUS_FROM_SERVER op. |
|
BatchBuilder& SendStatusFromServer( |
|
grpc_status_code status, absl::string_view message, |
|
std::initializer_list<std::pair<absl::string_view, absl::string_view>> |
|
md); |
|
|
|
// Add a GRPC_OP_RECV_INITIAL_METADATA op. |
|
BatchBuilder& RecvInitialMetadata(IncomingMetadata& md) { |
|
cq_verifier_->AddSuccessfulStateString(CqVerifier::tag(tag_), &md); |
|
ops_.emplace_back(md.MakeOp()); |
|
return *this; |
|
} |
|
|
|
// Add a GRPC_OP_RECV_MESSAGE op. |
|
BatchBuilder& RecvMessage(IncomingMessage& msg) { |
|
cq_verifier_->AddSuccessfulStateString(CqVerifier::tag(tag_), &msg); |
|
ops_.emplace_back(msg.MakeOp()); |
|
return *this; |
|
} |
|
|
|
// Add a GRPC_OP_RECV_STATUS_ON_CLIENT op. |
|
BatchBuilder& RecvStatusOnClient(IncomingStatusOnClient& status) { |
|
cq_verifier_->AddSuccessfulStateString(CqVerifier::tag(tag_), &status); |
|
ops_.emplace_back(status.MakeOp()); |
|
return *this; |
|
} |
|
|
|
// Add a GRPC_OP_RECV_CLOSE_ON_SERVER op. |
|
BatchBuilder& RecvCloseOnServer(IncomingCloseOnServer& close) { |
|
cq_verifier_->AddSuccessfulStateString(CqVerifier::tag(tag_), &close); |
|
ops_.emplace_back(close.MakeOp()); |
|
return *this; |
|
} |
|
|
|
private: |
|
// We need to track little bits of memory up until the batch is executed. |
|
// One Thing is one such block of memory. |
|
// We specialize it with SpecificThing to track a specific type of memory. |
|
// These get placed on things_ and deleted when the batch is executed. |
|
class Thing { |
|
public: |
|
virtual ~Thing() = default; |
|
}; |
|
template <typename T> |
|
class SpecificThing final : public Thing { |
|
public: |
|
template <typename... Args> |
|
explicit SpecificThing(Args&&... args) : t_(std::forward<Args>(args)...) {} |
|
SpecificThing() = default; |
|
|
|
T& get() { return t_; } |
|
|
|
private: |
|
T t_; |
|
}; |
|
|
|
// Make a thing of type T, and return a reference to it. |
|
template <typename T, typename... Args> |
|
T& Make(Args&&... args) { |
|
things_.emplace_back(new SpecificThing<T>(std::forward<Args>(args)...)); |
|
return static_cast<SpecificThing<T>*>(things_.back().get())->get(); |
|
} |
|
|
|
grpc_call* call_; |
|
const int tag_; |
|
std::vector<grpc_op> ops_; |
|
std::vector<std::unique_ptr<Thing>> things_; |
|
CqVerifier* const cq_verifier_; |
|
}; |
|
|
|
} // namespace grpc_core |
|
|
|
#endif // GRPC_TEST_CORE_CALL_BATCH_BUILDER_H
|
|
|