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::ServiceWithClientFixture<UnitTestServiceValidator, types::UnitTestServiceClient>,
68 public testing::WithParamInterface<grpc_protovalidate::client::Settings> {
69public:
70 GrpcClientValidatorTest()
71 : ugrpc::tests::ServiceWithClientFixture<UnitTestServiceValidator, types::UnitTestServiceClient>(
72 ugrpc::server::ServerConfig{},
73 ugrpc::server::Middlewares{},
74 ugrpc::client::Middlewares{std::make_shared<grpc_protovalidate::client::Middleware>(GetParam())}
75 )
76 {}
77};
78
79} // namespace
80
81INSTANTIATE_UTEST_SUITE_P(
82 /*no prefix*/,
83 GrpcClientValidatorTest,
84 testing::Values(
85 grpc_protovalidate::client::Settings{
86 .per_method =
87 {{"types.UnitTestService/CheckConstraintsUnary", {.fail_fast = false, .validate_requests = true}},
88 {"/UnknownMethod", {.fail_fast = true}}}
89 },
90 grpc_protovalidate::client::Settings{
91 .global = {.fail_fast = false},
92 .per_method =
93 {{"types.UnitTestService/CheckConstraintsUnary", {.fail_fast = false, .validate_requests = true}},
94 {"/UnknownMethod", {.fail_fast = true}}}
95 }
96 )
97);
98
99UTEST_P_MT(GrpcClientValidatorTest, AllValid, 2) {
100 constexpr std::size_t kRequestCount = 3;
101
102 std::vector<types::ConstrainedRequest> requests(kRequestCount);
103 for (std::size_t i = 0; i < kRequestCount; ++i) {
104 requests[i].set_field(static_cast<int32_t>(i + 1));
105 }
106
107 // check unary method
108 types::ConstrainedResponse response;
109 UEXPECT_NO_THROW(response = GetClient().CheckConstraintsUnary(requests[0]));
110 EXPECT_EQ(response.field(), requests[0].field());
111
112 // check streaming method
113 auto stream = GetClient().CheckConstraintsStreaming();
114 auto write_task = engine::AsyncNoSpan([&stream, &requests] {
115 for (const auto& request : requests) {
116 const bool success = stream.Write(request);
117 if (!success) {
118 return false;
119 }
120 }
121
122 return stream.WritesDone();
123 });
124
125 std::vector<types::ConstrainedResponse> responses;
126 while (stream.Read(response)) {
127 responses.push_back(std::move(response));
128 }
129
130 ASSERT_TRUE(write_task.Get());
131 ASSERT_EQ(responses.size(), kRequestCount);
132
133 for (std::size_t i = 0; i < kRequestCount; ++i) {
134 EXPECT_EQ(responses[i].field(), requests[i].field());
135 }
136}
137
138UTEST_P_MT(GrpcClientValidatorTest, AllInvalid, 2) {
139 constexpr std::size_t kRequestCount = 3;
140
141 std::vector<types::ConstrainedRequest> requests(kRequestCount);
142 types::ConstrainedRequest request;
143 request.set_field(1);
144 requests[0] = request;
145 request.set_field(0);
146 requests[1] = request;
147 request.set_field(3);
148 requests[2] = request;
149
150 // check unary method
151 try {
152 [[maybe_unused]] auto response = GetClient().CheckConstraintsUnary(requests[1]);
153 ADD_FAILURE() << "Call must fail";
154 } catch (const grpc_protovalidate::client::ResponseError& err) {
155 EXPECT_EQ(err.GetErrorInfo().violations_size(), 20);
156 } catch (...) {
157 ADD_FAILURE() << "'ResponseError' exception expected";
158 }
159
160 // check streaming method
161 auto stream = GetClient().CheckConstraintsStreaming();
162 auto write_task = engine::AsyncNoSpan([&stream, &requests] {
163 for (const auto& request : requests) {
164 const bool success = stream.Write(request);
165 if (!success) {
166 return false;
167 }
168 }
169
170 return stream.WritesDone();
171 });
172
173 types::ConstrainedResponse response;
174
175 ASSERT_TRUE(stream.Read(response));
176 EXPECT_EQ(response.field(), 1);
177
178 try {
179 [[maybe_unused]] const bool result = stream.Read(response);
180 ADD_FAILURE() << "Call must fail";
181 } catch (const grpc_protovalidate::client::ResponseError& err) {
182 const auto& streaming_settings = GetParam().Get("types.UnitTestService/CheckConstraintsStreaming");
183 if (streaming_settings.fail_fast) {
184 EXPECT_EQ(err.GetErrorInfo().violations_size(), 1);
185 } else {
186 EXPECT_EQ(err.GetErrorInfo().violations_size(), 20);
187 }
188 } catch (...) {
189 ADD_FAILURE() << "'InvalidArgumentError' exception expected";
190 }
191
192 write_task.Get();
193}
194
195UTEST_P(GrpcClientValidatorTest, InvalidConstraints) {
196 UEXPECT_THROW_MSG(
197 GetClient().CheckInvalidResponseConstraints(google::protobuf::Empty{}),
198 grpc_protovalidate::client::ValidatorError,
199 "'types.UnitTestService/CheckInvalidResponseConstraints' failed: validator internal error"
200 );
201}
202
203UTEST_P(GrpcClientValidatorTest, InvalidRequest) {
204 types::ConstrainedRequest request;
205 request.set_field(100);
206
207 UEXPECT_THROW_MSG(
208 GetClient().CheckConstraintsUnary(request),
209 grpc_protovalidate::client::RequestError,
210 "'types.UnitTestService/CheckConstraintsUnary' failed: request violates constraints (count=1)"
211 );
212}
213
214USERVER_NAMESPACE_END