~bigbes/tarantool

tarantool-protobuf

ref: 0c13fd735d0b7e3218d2b9d1f64c074e01c14234 tarantool-protobuf/cmd/conformance/core.lua -rw-r--r-- 4.6 KiB
0c13fd73 — Eugene Blikh wire: truncate varints to 32 bits in int32/uint32/sint32/enum decode 3 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
-- Core dispatch for the Google protobuf conformance protocol.
--
-- Decodes a `conformance.ConformanceRequest` (wire bytes), runs it through
-- our codec/JSON in the requested format, and returns the encoded
-- `conformance.ConformanceResponse` bytes. The stdin/stdout framing is
-- handled by the thin wrapper in `cmd/conformance-runner.lua`.
--
-- Split out as a module so the luatest suite can drive `handle_request`
-- directly without spawning a subprocess.

local pb           = require('pb')
local conformance  = require('full.conformance.conformance_pb')
local proto3_tests = require('full.protobuf_test_messages.proto3.test_messages_proto3_pb')

local M = {}

-- Map of supported `message_type` -> descriptor. Any other message type
-- yields a `skipped` response so we don't claim conformance for protos we
-- don't actually support yet (proto2, editions).
local MESSAGE_REGISTRY = {
    ['protobuf_test_messages.proto3.TestAllTypesProto3'] =
        proto3_tests.TestAllTypesProto3_descriptor,
    ['conformance.FailureSet'] =
        conformance.FailureSet_descriptor,
}

local WIRE_FORMAT = conformance.WireFormat
local PROTOBUF    = WIRE_FORMAT.PROTOBUF
local JSON        = WIRE_FORMAT.JSON
local JSPB        = WIRE_FORMAT.JSPB
local TEXT_FORMAT = WIRE_FORMAT.TEXT_FORMAT

local function dispatch(req)
    local desc = MESSAGE_REGISTRY[req.message_type]
    if desc == nil then
        return {skipped = 'unsupported message type: ' ..
            tostring(req.message_type)}
    end

    -- 1. Decode the input payload into a Lua table.
    local msg
    if req.protobuf_payload ~= nil then
        local ok, decoded = pcall(pb.decode, desc, req.protobuf_payload)
        if not ok then
            return {parse_error = 'protobuf decode failed: ' ..
                tostring(decoded)}
        end
        msg = decoded
    elseif req.json_payload ~= nil then
        local ok, decoded = pcall(pb.json.decode, desc, req.json_payload)
        if not ok then
            return {parse_error = 'json decode failed: ' .. tostring(decoded)}
        end
        msg = decoded
    elseif req.jspb_payload ~= nil or req.text_payload ~= nil then
        return {skipped = 'jspb/text input not supported'}
    else
        return {runtime_error = 'no payload set in ConformanceRequest'}
    end

    -- 2. Serialize in the requested output format.
    local out_fmt = req.requested_output_format
    if out_fmt == PROTOBUF then
        local ok, bytes = pcall(pb.encode, desc, msg)
        if not ok then
            return {serialize_error = 'protobuf encode failed: ' ..
                tostring(bytes)}
        end
        return {protobuf_payload = bytes}
    elseif out_fmt == JSON then
        -- Optional opt-out: the Google harness crashes inside jsoncpp
        -- when comparing our currently-imperfect JSON output (enum
        -- numerics, map<K,V> shape, oneof object form). Setting
        -- PB_CONFORMANCE_SKIP_JSON=1 in the container short-circuits to
        -- `skipped` so the suite completes and PROTOBUF coverage stays
        -- measurable; the host tests run without the flag and still
        -- exercise the JSON output path end-to-end.
        if os.getenv('PB_CONFORMANCE_SKIP_JSON') then
            return {skipped =
                'JSON output deferred (see test/conformance/known_failures.txt)'}
        end
        local ok, jbytes = pcall(pb.json.encode, desc, msg)
        if not ok then
            return {serialize_error = 'json encode failed: ' ..
                tostring(jbytes)}
        end
        return {json_payload = jbytes}
    elseif out_fmt == JSPB or out_fmt == TEXT_FORMAT then
        return {skipped = 'jspb/text output not supported'}
    else
        return {runtime_error = 'unknown requested_output_format: ' ..
            tostring(out_fmt)}
    end
end

-- Takes the raw bytes of a ConformanceRequest, returns the raw bytes of
-- a ConformanceResponse. Never throws — every failure path produces a
-- well-formed ConformanceResponse so the conformance runner stays synced.
function M.handle_request(req_bytes)
    local ok, req = pcall(conformance.ConformanceRequest_decode, req_bytes)
    if not ok then
        return conformance.ConformanceResponse_encode(
            {runtime_error = 'failed to decode ConformanceRequest: ' ..
                tostring(req)})
    end
    local resp = dispatch(req)
    local ok2, bytes = pcall(conformance.ConformanceResponse_encode, resp)
    if not ok2 then
        return conformance.ConformanceResponse_encode(
            {runtime_error = 'failed to encode response: ' .. tostring(bytes)})
    end
    return bytes
end

-- Expose for introspection / extension.
M.MESSAGE_REGISTRY = MESSAGE_REGISTRY

return M