1#include <userver/utest/utest.hpp>
3#include <buf/validate/validate.pb.h>
5#include <userver/engine/async.hpp>
6#include <userver/grpc-protovalidate/client/exceptions.hpp>
7#include <userver/ugrpc/client/exceptions.hpp>
8#include <userver/ugrpc/tests/service_fixtures.hpp>
10#include <types/unit_test_client.usrv.pb.hpp>
11#include <types/unit_test_service.usrv.pb.hpp>
13#include <grpc-protovalidate/client/middleware.hpp>
16USERVER_NAMESPACE_BEGIN
20types::ConstrainedResponse CreateResponse(int32_t request_id) {
21 types::ConstrainedResponse response;
23 if (request_id != 0) {
25 response.set_field(request_id);
27 types::ConstrainedMessage msg;
28 msg.set_required_rule(5);
29 *response.add_messages() = std::move(msg);
30 *response.add_messages() = tests::CreateValidMessage(6);
33 response.set_field(100);
34 *response.add_messages() = types::ConstrainedMessage{};
35 *response.add_messages() = tests::CreateInvalidMessage();
41class UnitTestServiceValidator
final :
public types::UnitTestServiceBase {
43 CheckConstraintsUnaryResult CheckConstraintsUnary(CallContext&, types::ConstrainedRequest&& request)
override {
44 return CreateResponse(request.field());
47 CheckConstraintsStreamingResult CheckConstraintsStreaming(
49 CheckConstraintsStreamingReaderWriter& stream
51 types::ConstrainedRequest request;
52 while (stream.Read(request)) {
53 stream.Write(CreateResponse(request.field()));
55 return grpc::Status::OK;
58 CheckInvalidResponseConstraintsResult CheckInvalidResponseConstraints(CallContext&, google::protobuf::Empty&&)
60 types::InvalidConstraints response;
61 response.set_field(1);
66class GrpcClientValidatorTest
67 :
public ugrpc::tests::ServiceWithClientFixture<UnitTestServiceValidator, types::UnitTestServiceClient>,
68 public testing::WithParamInterface<grpc_protovalidate::client::Settings> {
70 GrpcClientValidatorTest()
71 : ugrpc::tests::ServiceWithClientFixture<UnitTestServiceValidator, types::UnitTestServiceClient>({
72 .client_middlewares = {std::make_shared<grpc_protovalidate::client::Middleware>(GetParam())},
81 GrpcClientValidatorTest,
83 grpc_protovalidate::client::Settings{
85 {{
"types.UnitTestService/CheckConstraintsUnary", {.fail_fast =
false, .validate_requests =
true}},
86 {
"/UnknownMethod", {.fail_fast =
true}}}
88 grpc_protovalidate::client::Settings{
89 .global = {.fail_fast =
false},
91 {{
"types.UnitTestService/CheckConstraintsUnary", {.fail_fast =
false, .validate_requests =
true}},
92 {
"/UnknownMethod", {.fail_fast =
true}}}
97UTEST_P_MT(GrpcClientValidatorTest, AllValid, 2) {
98 constexpr std::size_t kRequestCount = 3;
100 std::vector<types::ConstrainedRequest> requests(kRequestCount);
101 for (std::size_t i = 0; i < kRequestCount; ++i) {
102 requests[i].set_field(
static_cast<int32_t>(i + 1));
106 types::ConstrainedResponse response;
107 UEXPECT_NO_THROW(response = GetClient().CheckConstraintsUnary(requests[0]));
108 EXPECT_EQ(response.field(), requests[0].field());
111 auto stream = GetClient().CheckConstraintsStreaming();
112 auto write_task = engine::AsyncNoTracing([&stream, &requests] {
113 for (
const auto& request : requests) {
114 const bool success = stream.Write(request);
120 return stream.WritesDone();
123 std::vector<types::ConstrainedResponse> responses;
124 while (stream.Read(response)) {
125 responses.push_back(std::move(response));
128 ASSERT_TRUE(write_task.Get());
129 ASSERT_EQ(responses.size(), kRequestCount);
131 for (std::size_t i = 0; i < kRequestCount; ++i) {
132 EXPECT_EQ(responses[i].field(), requests[i].field());
136UTEST_P_MT(GrpcClientValidatorTest, AllInvalid, 2) {
137 constexpr std::size_t kRequestCount = 3;
139 std::vector<types::ConstrainedRequest> requests(kRequestCount);
140 types::ConstrainedRequest request;
141 request.set_field(1);
142 requests[0] = request;
143 request.set_field(0);
144 requests[1] = request;
145 request.set_field(3);
146 requests[2] = request;
150 [[maybe_unused]]
auto response = GetClient().CheckConstraintsUnary(requests[1]);
151 ADD_FAILURE() <<
"Call must fail";
152 }
catch (
const grpc_protovalidate::client::ResponseError& err) {
153 EXPECT_EQ(err.GetErrorInfo().violations_size(), 20);
155 ADD_FAILURE() <<
"'ResponseError' exception expected";
159 auto stream = GetClient().CheckConstraintsStreaming();
160 auto write_task = engine::AsyncNoTracing([&stream, &requests] {
161 for (
const auto& request : requests) {
162 const bool success = stream.Write(request);
168 return stream.WritesDone();
171 types::ConstrainedResponse response;
173 ASSERT_TRUE(stream.Read(response));
174 EXPECT_EQ(response.field(), 1);
177 [[maybe_unused]]
const bool result = stream.Read(response);
178 ADD_FAILURE() <<
"Call must fail";
179 }
catch (
const grpc_protovalidate::client::ResponseError& err) {
180 const auto& streaming_settings = GetParam().Get(
"types.UnitTestService/CheckConstraintsStreaming");
181 if (streaming_settings.fail_fast) {
182 EXPECT_EQ(err.GetErrorInfo().violations_size(), 1);
184 EXPECT_EQ(err.GetErrorInfo().violations_size(), 20);
187 ADD_FAILURE() <<
"'InvalidArgumentError' exception expected";
193UTEST_P(GrpcClientValidatorTest, InvalidConstraints) {
195 GetClient().CheckInvalidResponseConstraints(google::protobuf::Empty{}),
196 grpc_protovalidate::client::ValidatorError,
197 "'types.UnitTestService/CheckInvalidResponseConstraints' failed: validator internal error"
201UTEST_P(GrpcClientValidatorTest, InvalidRequest) {
202 types::ConstrainedRequest request;
203 request.set_field(100);
206 GetClient().CheckConstraintsUnary(request),
207 grpc_protovalidate::client::RequestError,
208 "'types.UnitTestService/CheckConstraintsUnary' failed: request violates constraints (count=1)"