~bigbes/tarantool

tarantool-protobuf

ref: 46045da1d9330db68d0e8210ff0ba4ae2c0885db tarantool-protobuf/cmd/conformance/core.lua -rw-r--r-- 4.0 KiB
46045da1 — Eugene Blikh codec: precompute per-field readers (runtime decode +10–17%) 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
-- 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
        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