1// Copyright 2019 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package conformance_test 6 7import ( 8 "encoding/binary" 9 "flag" 10 "io" 11 "log" 12 "os" 13 "os/exec" 14 "path/filepath" 15 "testing" 16 17 "google.golang.org/protobuf/encoding/protojson" 18 "google.golang.org/protobuf/encoding/prototext" 19 "google.golang.org/protobuf/proto" 20 21 pb "google.golang.org/protobuf/internal/testprotos/conformance" 22) 23 24func init() { 25 // When the environment variable RUN_AS_CONFORMANCE_PLUGIN is set, 26 // we skip running the tests and instead act as a conformance plugin. 27 // This allows the binary to pass itself to conformance. 28 if os.Getenv("RUN_AS_CONFORMANCE_PLUGIN") == "1" { 29 main() 30 os.Exit(0) 31 } 32} 33 34var ( 35 execute = flag.Bool("execute", false, "execute the conformance test") 36 protoRoot = flag.String("protoroot", os.Getenv("PROTOBUF_ROOT"), "The root of the protobuf source tree.") 37) 38 39func Test(t *testing.T) { 40 if !*execute { 41 t.SkipNow() 42 } 43 binPath := filepath.Join(*protoRoot, "bazel-bin", "conformance", "conformance_test_runner") 44 cmd := exec.Command(binPath, 45 "--failure_list", "failing_tests.txt", 46 "--text_format_failure_list", "failing_tests_text_format.txt", 47 "--enforce_recommended", 48 os.Args[0]) 49 cmd.Env = append(os.Environ(), "RUN_AS_CONFORMANCE_PLUGIN=1") 50 out, err := cmd.CombinedOutput() 51 if err != nil { 52 t.Fatalf("execution error: %v\n\n%s", err, out) 53 } 54} 55 56func main() { 57 var sizeBuf [4]byte 58 inbuf := make([]byte, 0, 4096) 59 for { 60 _, err := io.ReadFull(os.Stdin, sizeBuf[:]) 61 if err == io.EOF { 62 break 63 } 64 if err != nil { 65 log.Fatalf("conformance: read request: %v", err) 66 } 67 size := binary.LittleEndian.Uint32(sizeBuf[:]) 68 if int(size) > cap(inbuf) { 69 inbuf = make([]byte, size) 70 } 71 inbuf = inbuf[:size] 72 if _, err := io.ReadFull(os.Stdin, inbuf); err != nil { 73 log.Fatalf("conformance: read request: %v", err) 74 } 75 76 req := &pb.ConformanceRequest{} 77 if err := proto.Unmarshal(inbuf, req); err != nil { 78 log.Fatalf("conformance: parse request: %v", err) 79 } 80 res := handle(req) 81 82 out, err := proto.Marshal(res) 83 if err != nil { 84 log.Fatalf("conformance: marshal response: %v", err) 85 } 86 binary.LittleEndian.PutUint32(sizeBuf[:], uint32(len(out))) 87 if _, err := os.Stdout.Write(sizeBuf[:]); err != nil { 88 log.Fatalf("conformance: write response: %v", err) 89 } 90 if _, err := os.Stdout.Write(out); err != nil { 91 log.Fatalf("conformance: write response: %v", err) 92 } 93 } 94} 95 96func handle(req *pb.ConformanceRequest) (res *pb.ConformanceResponse) { 97 var msg proto.Message = &pb.TestAllTypesProto2{} 98 if req.GetMessageType() == "protobuf_test_messages.proto3.TestAllTypesProto3" { 99 msg = &pb.TestAllTypesProto3{} 100 } 101 102 // Unmarshal the test message. 103 var err error 104 switch p := req.Payload.(type) { 105 case *pb.ConformanceRequest_ProtobufPayload: 106 err = proto.Unmarshal(p.ProtobufPayload, msg) 107 case *pb.ConformanceRequest_JsonPayload: 108 err = protojson.UnmarshalOptions{ 109 DiscardUnknown: req.TestCategory == pb.TestCategory_JSON_IGNORE_UNKNOWN_PARSING_TEST, 110 }.Unmarshal([]byte(p.JsonPayload), msg) 111 case *pb.ConformanceRequest_TextPayload: 112 err = prototext.Unmarshal([]byte(p.TextPayload), msg) 113 default: 114 return &pb.ConformanceResponse{ 115 Result: &pb.ConformanceResponse_RuntimeError{ 116 RuntimeError: "unknown request payload type", 117 }, 118 } 119 } 120 if err != nil { 121 return &pb.ConformanceResponse{ 122 Result: &pb.ConformanceResponse_ParseError{ 123 ParseError: err.Error(), 124 }, 125 } 126 } 127 128 // Marshal the test message. 129 var b []byte 130 switch req.RequestedOutputFormat { 131 case pb.WireFormat_PROTOBUF: 132 b, err = proto.Marshal(msg) 133 res = &pb.ConformanceResponse{ 134 Result: &pb.ConformanceResponse_ProtobufPayload{ 135 ProtobufPayload: b, 136 }, 137 } 138 case pb.WireFormat_JSON: 139 b, err = protojson.Marshal(msg) 140 res = &pb.ConformanceResponse{ 141 Result: &pb.ConformanceResponse_JsonPayload{ 142 JsonPayload: string(b), 143 }, 144 } 145 case pb.WireFormat_TEXT_FORMAT: 146 b, err = prototext.MarshalOptions{ 147 EmitUnknown: req.PrintUnknownFields, 148 }.Marshal(msg) 149 res = &pb.ConformanceResponse{ 150 Result: &pb.ConformanceResponse_TextPayload{ 151 TextPayload: string(b), 152 }, 153 } 154 default: 155 return &pb.ConformanceResponse{ 156 Result: &pb.ConformanceResponse_RuntimeError{ 157 RuntimeError: "unknown output format", 158 }, 159 } 160 } 161 if err != nil { 162 return &pb.ConformanceResponse{ 163 Result: &pb.ConformanceResponse_SerializeError{ 164 SerializeError: err.Error(), 165 }, 166 } 167 } 168 return res 169} 170