userver: /data/code/userver/libraries/grpc-protovalidate/tests/validator_client_test.cpp Source File
Loading...
Searching...
No Matches
validator_client_test.cpp
1#include <userver/utest/utest.hpp>
2
3#include <buf/validate/validate.pb.h>
4
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>
9
10#include <types/unit_test_client.usrv.pb.hpp>
11#include <types/unit_test_service.usrv.pb.hpp>
12
13#include <grpc-protovalidate/client/middleware.hpp>
14#include "utils.hpp"
15
16USERVER_NAMESPACE_BEGIN
17
18namespace {
19
20types::ConstrainedResponse CreateResponse(int32_t request_id) {
21 types::ConstrainedResponse response;
22
23 if (request_id != 0) {
24 // happy path
25 response.set_field(request_id);
26
27 types::ConstrainedMessage msg;
28 msg.set_required_rule(5);
29 *response.add_messages() = std::move(msg);
30 *response.add_messages() = tests::CreateValidMessage(6);
31 } else {
32 // error path
33 response.set_field(100);
34 *response.add_messages() = types::ConstrainedMessage{};
35 *response.add_messages() = tests::CreateInvalidMessage();
36 }
37
38 return response;
39}
40
41class UnitTestServiceValidator final : public types::UnitTestServiceBase {
42public:
43 CheckConstraintsUnaryResult CheckConstraintsUnary(CallContext&, types::ConstrainedRequest&& request) override {
44 return CreateResponse(request.field());
45 }
46
47 CheckConstraintsStreamingResult CheckConstraintsStreaming(
48 CallContext&,
49 CheckConstraintsStreamingReaderWriter& stream
50 ) override {
51 types::ConstrainedRequest request;
52 while (stream.Read(request)) {
53 stream.Write(CreateResponse(request.field()));
54 }
55 return grpc::Status::OK;
56 }
57
58 CheckInvalidResponseConstraintsResult CheckInvalidResponseConstraints(CallContext&, google::protobuf::Empty&&)
59 override {
60 types::InvalidConstraints response;
61 response.set_field(1);
62 return response;
63 }
64};
65
66class GrpcClientValidatorTest
67 : public ugrpc::tests::ServiceFixtureBase,
68 public testing::WithParamInterface<grpc_protovalidate::client::Settings> {
69public:
70 GrpcClientValidatorTest() {
71 SetClientMiddlewares({std::make_shared<grpc_protovalidate::client::Middleware>(GetParam())});
72 RegisterService(service_);
73 StartServer();
74 }
75
76 ~GrpcClientValidatorTest() override { StopServer(); }
77
78private:
79 UnitTestServiceValidator service_;
80};
81
82} // namespace
83
84INSTANTIATE_UTEST_SUITE_P(
85 /*no prefix*/,
86 GrpcClientValidatorTest,
87 testing::Values(
88 grpc_protovalidate::client::Settings{
89 .per_method =
90 {
91 {"types.UnitTestService/CheckConstraintsUnary", {.fail_fast = false}},
92 {"/UnknownMethod", {.fail_fast = true}},
93 }
94 },
95 grpc_protovalidate::client::Settings{
96 .global =
97 {
98 .fail_fast = false,
99 },
100 .per_method =
101 {
102 {"types.UnitTestService/CheckConstraintsUnary", {.fail_fast = false}},
103 {"/UnknownMethod", {.fail_fast = true}},
104 }
105 }
106 )
107);
108
109UTEST_P_MT(GrpcClientValidatorTest, AllValid, 2) {
110 constexpr std::size_t kRequestCount = 3;
111 auto client = MakeClient<types::UnitTestServiceClient>();
112 auto stream = client.CheckConstraintsStreaming();
113
114 const types::ConstrainedRequest request;
115 std::vector<types::ConstrainedRequest> requests(kRequestCount);
116 std::vector<types::ConstrainedResponse> responses;
117
118 for (std::size_t i = 0; i < kRequestCount; ++i) {
119 requests[i].set_field(static_cast<int32_t>(i + 1));
120 }
121
122 // check unary method
123
124 types::ConstrainedResponse response;
125 UEXPECT_NO_THROW(response = client.CheckConstraintsUnary(requests[0]));
126 EXPECT_EQ(response.field(), requests[0].field());
127
128 // check streaming method
129
130 auto write_task = engine::AsyncNoSpan([&stream, &requests] {
131 for (const auto& request : requests) {
132 const bool success = stream.Write(request);
133 if (!success) {
134 return false;
135 }
136 }
137
138 return stream.WritesDone();
139 });
140
141 while (stream.Read(response)) {
142 responses.push_back(std::move(response));
143 }
144
145 ASSERT_TRUE(write_task.Get());
146 ASSERT_EQ(responses.size(), kRequestCount);
147
148 for (std::size_t i = 0; i < kRequestCount; ++i) {
149 EXPECT_EQ(responses[i].field(), requests[i].field());
150 }
151}
152
153UTEST_P_MT(GrpcClientValidatorTest, AllInvalid, 2) {
154 constexpr std::size_t kRequestCount = 3;
155 const auto& streaming_settings = GetParam().Get("types.UnitTestService/CheckConstraintsStreaming");
156 auto client = MakeClient<types::UnitTestServiceClient>();
157 auto stream = client.CheckConstraintsStreaming();
158
159 types::ConstrainedRequest request;
160 std::vector<types::ConstrainedRequest> requests(kRequestCount);
161 const std::vector<types::ConstrainedResponse> responses;
162
163 request.set_field(1);
164 requests[0] = request;
165 request.set_field(0);
166 requests[1] = request;
167 request.set_field(3);
168 requests[2] = request;
169
170 // check unary method
171
172 try {
173 [[maybe_unused]] auto response = client.CheckConstraintsUnary(requests[1]);
174 ADD_FAILURE() << "Call must fail";
175 } catch (const grpc_protovalidate::client::ResponseError& err) {
176 EXPECT_EQ(err.GetErrorInfo().violations_size(), 20);
177 } catch (...) {
178 ADD_FAILURE() << "'ResponseError' exception expected";
179 }
180
181 // check streaming method
182
183 auto write_task = engine::AsyncNoSpan([&stream, &requests] {
184 for (const auto& request : requests) {
185 const bool success = stream.Write(request);
186 if (!success) {
187 return false;
188 }
189 }
190
191 return stream.WritesDone();
192 });
193
194 types::ConstrainedResponse response;
195
196 ASSERT_TRUE(stream.Read(response));
197 EXPECT_EQ(response.field(), 1);
198
199 try {
200 [[maybe_unused]] const bool result = stream.Read(response);
201 ADD_FAILURE() << "Call must fail";
202 } catch (const grpc_protovalidate::client::ResponseError& err) {
203 if (streaming_settings.fail_fast) {
204 EXPECT_EQ(err.GetErrorInfo().violations_size(), 1);
205 } else {
206 EXPECT_EQ(err.GetErrorInfo().violations_size(), 20);
207 }
208 } catch (...) {
209 ADD_FAILURE() << "'InvalidArgumentError' exception expected";
210 }
211
212 write_task.Get();
213}
214
215UTEST_P(GrpcClientValidatorTest, InvalidConstraints) {
216 auto client = MakeClient<types::UnitTestServiceClient>();
217
218 try {
219 [[maybe_unused]] auto response = client.CheckInvalidResponseConstraints(google::protobuf::Empty{});
220 ADD_FAILURE() << "Call must fail";
221 } catch (const grpc_protovalidate::client::ValidatorError&) {
222 // do nothing
223 } catch (...) {
224 ADD_FAILURE() << "'ValidatorError' exception expected";
225 }
226}
227
228USERVER_NAMESPACE_END