blob: 86c651c0fb3de4791b222be2ee2dc256dd350380 [file] [log] [blame]
Josh Haberman35a1cc72015-04-01 17:23:48 -07001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
Josh Haberman35a1cc72015-04-01 17:23:48 -07003//
Joshua Haberman8a4bfd62023-09-08 19:26:10 -07004// Use of this source code is governed by a BSD-style
5// license that can be found in the LICENSE file or at
6// https://developers.google.com/open-source/licenses/bsd
Josh Haberman35a1cc72015-04-01 17:23:48 -07007
8#include <errno.h>
9#include <stdarg.h>
10#include <unistd.h>
11
Jorg Browna3e1de02022-06-17 04:13:20 -070012#include <memory>
13#include <string>
14#include <utility>
15
Mike Kruskal15954172022-09-09 10:42:19 -070016#include "google/protobuf/util/json_util.h"
17#include "google/protobuf/util/type_resolver_util.h"
Mike Kruskala9f1ea62023-01-24 21:49:33 -080018#include "absl/log/absl_check.h"
19#include "absl/log/absl_log.h"
Mike Kruskala3c8e2d2022-08-24 10:46:33 -070020#include "absl/status/status.h"
21#include "absl/status/statusor.h"
Mike Kruskaled5c57a2022-08-10 22:51:29 -070022#include "conformance/conformance.pb.h"
Mike Kruskalca4b0632022-08-11 20:55:01 -070023#include "conformance/conformance.pb.h"
Mike Kruskala2ba8bc2023-10-18 13:12:07 -070024#include "google/protobuf/editions/golden/test_messages_proto2_editions.pb.h"
25#include "google/protobuf/editions/golden/test_messages_proto3_editions.pb.h"
Jonathan Albrecht5e033862023-08-04 17:44:30 -070026#include "google/protobuf/endian.h"
Protobuf Team Bot0287cf42023-08-22 07:26:58 -070027#include "google/protobuf/message.h"
Mike Kruskal15954172022-09-09 10:42:19 -070028#include "google/protobuf/test_messages_proto2.pb.h"
29#include "google/protobuf/test_messages_proto3.pb.h"
30#include "google/protobuf/test_messages_proto3.pb.h"
Protobuf Team Bot0287cf42023-08-22 07:26:58 -070031#include "google/protobuf/text_format.h"
Mike Kruskal15954172022-09-09 10:42:19 -070032#include "google/protobuf/util/type_resolver.h"
33#include "google/protobuf/stubs/status_macros.h"
Josh Haberman35a1cc72015-04-01 17:23:48 -070034
Jorg Browna3e1de02022-06-17 04:13:20 -070035// Must be included last.
Mike Kruskal15954172022-09-09 10:42:19 -070036#include "google/protobuf/port_def.inc"
Josh Habermanb0500b32015-07-10 16:36:59 -070037
Rafi Kamal58d44202019-11-11 17:06:56 -080038namespace google {
39namespace protobuf {
Jorg Browna3e1de02022-06-17 04:13:20 -070040namespace {
41using ::conformance::ConformanceRequest;
42using ::conformance::ConformanceResponse;
43using ::google::protobuf::util::BinaryToJsonString;
44using ::google::protobuf::util::JsonParseOptions;
45using ::google::protobuf::util::JsonToBinaryString;
46using ::google::protobuf::util::NewTypeResolverForDescriptorPool;
47using ::google::protobuf::util::TypeResolver;
48using ::protobuf_test_messages::proto2::TestAllTypesProto2;
49using ::protobuf_test_messages::proto3::TestAllTypesProto3;
Mike Kruskala2ba8bc2023-10-18 13:12:07 -070050using TestAllTypesProto2Editions =
51 ::protobuf_test_messages::editions::proto2::TestAllTypesProto2;
52using TestAllTypesProto3Editions =
53 ::protobuf_test_messages::editions::proto3::TestAllTypesProto3;
Rafi Kamal58d44202019-11-11 17:06:56 -080054
Mike Kruskala3c8e2d2022-08-24 10:46:33 -070055absl::Status ReadFd(int fd, char* buf, size_t len) {
Josh Haberman35a1cc72015-04-01 17:23:48 -070056 while (len > 0) {
Jorg Browna3e1de02022-06-17 04:13:20 -070057 ssize_t bytes_read = read(fd, buf, len);
Josh Haberman35a1cc72015-04-01 17:23:48 -070058
Jorg Browna3e1de02022-06-17 04:13:20 -070059 if (bytes_read == 0) {
Mike Kruskala3c8e2d2022-08-24 10:46:33 -070060 return absl::DataLossError("unexpected EOF");
Jorg Browna3e1de02022-06-17 04:13:20 -070061 }
Josh Haberman35a1cc72015-04-01 17:23:48 -070062
63 if (bytes_read < 0) {
Mike Kruskala3c8e2d2022-08-24 10:46:33 -070064 return absl::ErrnoToStatus(errno, "error reading from test runner");
Josh Haberman35a1cc72015-04-01 17:23:48 -070065 }
66
67 len -= bytes_read;
Jorg Browna3e1de02022-06-17 04:13:20 -070068 buf += bytes_read;
Josh Haberman35a1cc72015-04-01 17:23:48 -070069 }
Mike Kruskala3c8e2d2022-08-24 10:46:33 -070070 return absl::OkStatus();
Josh Haberman35a1cc72015-04-01 17:23:48 -070071}
72
Mike Kruskala3c8e2d2022-08-24 10:46:33 -070073absl::Status WriteFd(int fd, const void* buf, size_t len) {
Mike Kruskald220b432022-08-29 18:19:38 -040074 if (static_cast<size_t>(write(fd, buf, len)) != len) {
Mike Kruskala3c8e2d2022-08-24 10:46:33 -070075 return absl::ErrnoToStatus(errno, "error reading to test runner");
Josh Haberman35a1cc72015-04-01 17:23:48 -070076 }
Mike Kruskala3c8e2d2022-08-24 10:46:33 -070077 return absl::OkStatus();
Josh Haberman35a1cc72015-04-01 17:23:48 -070078}
79
Jorg Browna3e1de02022-06-17 04:13:20 -070080class Harness {
81 public:
82 Harness() {
83 google::protobuf::LinkMessageReflection<TestAllTypesProto2>();
84 google::protobuf::LinkMessageReflection<TestAllTypesProto3>();
Mike Kruskala2ba8bc2023-10-18 13:12:07 -070085 google::protobuf::LinkMessageReflection<TestAllTypesProto2Editions>();
86 google::protobuf::LinkMessageReflection<TestAllTypesProto3Editions>();
Jorg Browna3e1de02022-06-17 04:13:20 -070087
88 resolver_.reset(NewTypeResolverForDescriptorPool(
89 "type.googleapis.com", DescriptorPool::generated_pool()));
Mike Kruskala3c8e2d2022-08-24 10:46:33 -070090 type_url_ = absl::StrCat("type.googleapis.com/",
Jorg Browna3e1de02022-06-17 04:13:20 -070091 TestAllTypesProto3::GetDescriptor()->full_name());
Yilun Chong020a24d2017-06-29 11:33:22 -070092 }
Jorg Browna3e1de02022-06-17 04:13:20 -070093
Mike Kruskala3c8e2d2022-08-24 10:46:33 -070094 absl::StatusOr<ConformanceResponse> RunTest(
Jorg Browna3e1de02022-06-17 04:13:20 -070095 const ConformanceRequest& request);
96
97 // Returns Ok(true) if we're done processing requests.
Mike Kruskala3c8e2d2022-08-24 10:46:33 -070098 absl::StatusOr<bool> ServeConformanceRequest();
Jorg Browna3e1de02022-06-17 04:13:20 -070099
100 private:
101 bool verbose_ = false;
102 std::unique_ptr<TypeResolver> resolver_;
103 std::string type_url_;
104};
105
Mike Kruskala3c8e2d2022-08-24 10:46:33 -0700106absl::StatusOr<ConformanceResponse> Harness::RunTest(
Jorg Browna3e1de02022-06-17 04:13:20 -0700107 const ConformanceRequest& request) {
108 const Descriptor* descriptor =
109 DescriptorPool::generated_pool()->FindMessageTypeByName(
110 request.message_type());
111 if (descriptor == nullptr) {
Mike Kruskala3c8e2d2022-08-24 10:46:33 -0700112 return absl::NotFoundError(
113 absl::StrCat("No such message type: ", request.message_type()));
Jorg Browna3e1de02022-06-17 04:13:20 -0700114 }
115
116 std::unique_ptr<Message> test_message(
117 MessageFactory::generated_factory()->GetPrototype(descriptor)->New());
118 ConformanceResponse response;
Josh Haberman35a1cc72015-04-01 17:23:48 -0700119
120 switch (request.payload_case()) {
Yilun Chong18a0c2c2017-06-27 18:24:15 -0700121 case ConformanceRequest::kProtobufPayload: {
Yilun Chong020a24d2017-06-29 11:33:22 -0700122 if (!test_message->ParseFromString(request.protobuf_payload())) {
Jorg Browna3e1de02022-06-17 04:13:20 -0700123 response.set_parse_error("parse error (no more details available)");
124 return response;
Josh Haberman35a1cc72015-04-01 17:23:48 -0700125 }
126 break;
Yilun Chong18a0c2c2017-06-27 18:24:15 -0700127 }
Josh Haberman35a1cc72015-04-01 17:23:48 -0700128
Josh Habermanb0500b32015-07-10 16:36:59 -0700129 case ConformanceRequest::kJsonPayload: {
Feng Xiao6bbe1972018-08-08 17:00:41 -0700130 JsonParseOptions options;
131 options.ignore_unknown_fields =
132 (request.test_category() ==
Jorg Browna3e1de02022-06-17 04:13:20 -0700133 conformance::JSON_IGNORE_UNKNOWN_PARSING_TEST);
134
135 std::string proto_binary;
Mike Kruskala3c8e2d2022-08-24 10:46:33 -0700136 absl::Status status =
Jorg Browna3e1de02022-06-17 04:13:20 -0700137 JsonToBinaryString(resolver_.get(), type_url_, request.json_payload(),
Joshua Haberman5c028d62020-11-20 10:44:58 -0800138 &proto_binary, options);
Josh Habermanb0500b32015-07-10 16:36:59 -0700139 if (!status.ok()) {
Jorg Browna3e1de02022-06-17 04:13:20 -0700140 response.set_parse_error(
Mike Kruskala3c8e2d2022-08-24 10:46:33 -0700141 absl::StrCat("parse error: ", status.message()));
Jorg Browna3e1de02022-06-17 04:13:20 -0700142 return response;
Josh Habermanb0500b32015-07-10 16:36:59 -0700143 }
144
Yilun Chong020a24d2017-06-29 11:33:22 -0700145 if (!test_message->ParseFromString(proto_binary)) {
Jorg Browna3e1de02022-06-17 04:13:20 -0700146 response.set_runtime_error(
147 "parsing JSON generated invalid proto output");
148 return response;
Feng Xiaoe841bac2015-12-11 17:09:20 -0800149 }
Jorg Browna3e1de02022-06-17 04:13:20 -0700150
Josh Haberman35a1cc72015-04-01 17:23:48 -0700151 break;
Josh Habermanb0500b32015-07-10 16:36:59 -0700152 }
Josh Haberman35a1cc72015-04-01 17:23:48 -0700153
Yilun Chongcb95a7f2019-01-11 11:40:52 -0800154 case ConformanceRequest::kTextPayload: {
Jorg Browna3e1de02022-06-17 04:13:20 -0700155 if (!TextFormat::ParseFromString(request.text_payload(),
156 test_message.get())) {
157 response.set_parse_error("parse error (no more details available)");
158 return response;
Yilun Chongcb95a7f2019-01-11 11:40:52 -0800159 }
160 break;
161 }
162
Josh Haberman35a1cc72015-04-01 17:23:48 -0700163 case ConformanceRequest::PAYLOAD_NOT_SET:
Mike Kruskala3c8e2d2022-08-24 10:46:33 -0700164 return absl::InvalidArgumentError("request didn't have payload");
Paul Yangcecba292018-12-14 16:05:03 -0800165
166 default:
Mike Kruskala3c8e2d2022-08-24 10:46:33 -0700167 return absl::InvalidArgumentError(
168 absl::StrCat("unknown payload type", request.payload_case()));
Yilun Chong0adb74c2019-01-08 15:06:30 -0800169 }
170
Josh Habermanb0500b32015-07-10 16:36:59 -0700171 switch (request.requested_output_format()) {
172 case conformance::UNSPECIFIED:
Mike Kruskala3c8e2d2022-08-24 10:46:33 -0700173 return absl::InvalidArgumentError("unspecified output format");
Josh Haberman35a1cc72015-04-01 17:23:48 -0700174
Yilun Chong18a0c2c2017-06-27 18:24:15 -0700175 case conformance::PROTOBUF: {
Mike Kruskala9f1ea62023-01-24 21:49:33 -0800176 ABSL_CHECK(
Jorg Browna3e1de02022-06-17 04:13:20 -0700177 test_message->SerializeToString(response.mutable_protobuf_payload()));
Josh Haberman35a1cc72015-04-01 17:23:48 -0700178 break;
Yilun Chong18a0c2c2017-06-27 18:24:15 -0700179 }
Josh Haberman35a1cc72015-04-01 17:23:48 -0700180
Josh Habermanb0500b32015-07-10 16:36:59 -0700181 case conformance::JSON: {
Jorg Browna3e1de02022-06-17 04:13:20 -0700182 std::string proto_binary;
Mike Kruskala9f1ea62023-01-24 21:49:33 -0800183 ABSL_CHECK(test_message->SerializeToString(&proto_binary));
Mike Kruskala3c8e2d2022-08-24 10:46:33 -0700184 absl::Status status =
Jorg Browna3e1de02022-06-17 04:13:20 -0700185 BinaryToJsonString(resolver_.get(), type_url_, proto_binary,
186 response.mutable_json_payload());
Feng Xiaoe841bac2015-12-11 17:09:20 -0800187 if (!status.ok()) {
Mike Kruskala3c8e2d2022-08-24 10:46:33 -0700188 response.set_serialize_error(absl::StrCat(
Jorg Browna3e1de02022-06-17 04:13:20 -0700189 "failed to serialize JSON output: ", status.message()));
Feng Xiaoe841bac2015-12-11 17:09:20 -0800190 }
Josh Haberman35a1cc72015-04-01 17:23:48 -0700191 break;
Josh Habermanb0500b32015-07-10 16:36:59 -0700192 }
Feng Xiaoe841bac2015-12-11 17:09:20 -0800193
Yilun Chongcb95a7f2019-01-11 11:40:52 -0800194 case conformance::TEXT_FORMAT: {
Hao Nguyen2f864fd2019-03-20 11:45:01 -0700195 TextFormat::Printer printer;
196 printer.SetHideUnknownFields(!request.print_unknown_fields());
Mike Kruskala9f1ea62023-01-24 21:49:33 -0800197 ABSL_CHECK(printer.PrintToString(*test_message,
Mike Kruskala02c9022022-12-08 12:15:31 -0800198 response.mutable_text_payload()));
Yilun Chongcb95a7f2019-01-11 11:40:52 -0800199 break;
200 }
201
Feng Xiaoe841bac2015-12-11 17:09:20 -0800202 default:
Mike Kruskala3c8e2d2022-08-24 10:46:33 -0700203 return absl::InvalidArgumentError(absl::StrCat(
Jorg Browna3e1de02022-06-17 04:13:20 -0700204 "unknown output format", request.requested_output_format()));
Josh Haberman35a1cc72015-04-01 17:23:48 -0700205 }
Jorg Browna3e1de02022-06-17 04:13:20 -0700206
207 return response;
Josh Haberman35a1cc72015-04-01 17:23:48 -0700208}
209
Mike Kruskala3c8e2d2022-08-24 10:46:33 -0700210absl::StatusOr<bool> Harness::ServeConformanceRequest() {
Jorg Browna3e1de02022-06-17 04:13:20 -0700211 uint32_t in_len;
212 if (!ReadFd(STDIN_FILENO, reinterpret_cast<char*>(&in_len), sizeof(in_len))
213 .ok()) {
214 // EOF means we're done.
215 return true;
216 }
Jonathan Albrecht5e033862023-08-04 17:44:30 -0700217 in_len = internal::little_endian::ToHost(in_len);
Jorg Browna3e1de02022-06-17 04:13:20 -0700218
219 std::string serialized_input;
220 serialized_input.resize(in_len);
Zouhair Mahieddined8861a72022-07-11 18:32:33 +0200221 RETURN_IF_ERROR(ReadFd(STDIN_FILENO, &serialized_input[0], in_len));
Jorg Browna3e1de02022-06-17 04:13:20 -0700222
Josh Haberman35a1cc72015-04-01 17:23:48 -0700223 ConformanceRequest request;
Mike Kruskala9f1ea62023-01-24 21:49:33 -0800224 ABSL_CHECK(request.ParseFromString(serialized_input));
Josh Haberman35a1cc72015-04-01 17:23:48 -0700225
Mike Kruskala3c8e2d2022-08-24 10:46:33 -0700226 absl::StatusOr<ConformanceResponse> response = RunTest(request);
Jorg Browna3e1de02022-06-17 04:13:20 -0700227 RETURN_IF_ERROR(response.status());
228
229 std::string serialized_output;
230 response->SerializeToString(&serialized_output);
231
Jonathan Albrecht5e033862023-08-04 17:44:30 -0700232 uint32_t out_len = internal::little_endian::FromHost(
233 static_cast<uint32_t>(serialized_output.size()));
234
Jorg Browna3e1de02022-06-17 04:13:20 -0700235 RETURN_IF_ERROR(WriteFd(STDOUT_FILENO, &out_len, sizeof(out_len)));
Jonathan Albrecht5e033862023-08-04 17:44:30 -0700236 RETURN_IF_ERROR(WriteFd(STDOUT_FILENO, serialized_output.data(),
237 serialized_output.size()));
Jorg Browna3e1de02022-06-17 04:13:20 -0700238
239 if (verbose_) {
Mike Kruskala9f1ea62023-01-24 21:49:33 -0800240 ABSL_LOG(INFO) << "conformance-cpp: request=" << request.ShortDebugString()
Mike Kruskala02c9022022-12-08 12:15:31 -0800241 << ", response=" << response->ShortDebugString();
Josh Haberman35a1cc72015-04-01 17:23:48 -0700242 }
Jorg Browna3e1de02022-06-17 04:13:20 -0700243 return false;
Josh Haberman35a1cc72015-04-01 17:23:48 -0700244}
Jorg Browna3e1de02022-06-17 04:13:20 -0700245} // namespace
Rafi Kamal58d44202019-11-11 17:06:56 -0800246} // namespace protobuf
247} // namespace google
248
Josh Haberman35a1cc72015-04-01 17:23:48 -0700249int main() {
Jorg Browna3e1de02022-06-17 04:13:20 -0700250 google::protobuf::Harness harness;
251 int total_runs = 0;
252 while (true) {
253 auto is_done = harness.ServeConformanceRequest();
254 if (!is_done.ok()) {
Mike Kruskala9f1ea62023-01-24 21:49:33 -0800255 ABSL_LOG(FATAL) << is_done.status();
Josh Haberman35a1cc72015-04-01 17:23:48 -0700256 }
Jorg Browna3e1de02022-06-17 04:13:20 -0700257 if (*is_done) {
258 break;
259 }
260 total_runs++;
Josh Haberman35a1cc72015-04-01 17:23:48 -0700261 }
Mike Kruskala9f1ea62023-01-24 21:49:33 -0800262 ABSL_LOG(INFO) << "conformance-cpp: received EOF from test runner after "
Mike Kruskala02c9022022-12-08 12:15:31 -0800263 << total_runs << " tests";
Josh Haberman35a1cc72015-04-01 17:23:48 -0700264}