|
| 1 | +# |
| 2 | +# JSON-RPC Test Suite |
| 3 | +# Tests JSON-RPC protocol with a calculator server |
| 4 | +# |
| 5 | + |
| 6 | +import ulsp |
| 7 | +import json |
| 8 | + |
| 9 | +global work_items |
| 10 | +global jsonrpc_test_count, jsonrpc_pass_count, jsonrpc_fail_count |
| 11 | + |
| 12 | +############################# |
| 13 | +# JRPC server Calculator |
| 14 | +############################# |
| 15 | +class JRPC_Calc(jrpc_server) |
| 16 | + |
| 17 | + method start(addr) |
| 18 | + local sock, msg |
| 19 | + if not (jrpc_server := JRPC_HTTPSocket(addr,"n")) then |
| 20 | + write("server open(",addr,") ERROR: ", \&errortext | "Unknown") & fail |
| 21 | + |
| 22 | + repeat { |
| 23 | + msg := jrpc_server.get_msg() | next |
| 24 | + case msg.get_kind() of { |
| 25 | + "request" : thread handle_request(msg) |
| 26 | + default: |
| 27 | + write("jrpc:msg: " || msg.get_kind(), image(msg.get_content())) |
| 28 | + } |
| 29 | + } |
| 30 | + end |
| 31 | + |
| 32 | + method handle_request(msg) |
| 33 | + local id := msg.get_id(), |
| 34 | + x := integer(msg.get_params()[1]), |
| 35 | + y := integer(msg.get_params()[2]) |
| 36 | + |
| 37 | + # uncomment to trigger some test failures |
| 38 | + #if x = 9 then fail |
| 39 | + case msg.get_method() of { |
| 40 | + "+" : {jrpc_server.send_msg(msg.make_result_response(x + y))} |
| 41 | + "-" : jrpc_server.send_msg(msg.make_result_response(x - y)) |
| 42 | + "*" : jrpc_server.send_msg(msg.make_result_response(x * y)) |
| 43 | + "/" : jrpc_server.send_msg(msg.make_result_response(x / y)) |
| 44 | + default: write("jrpc:request:unsupported: ", msg.get_method()) |
| 45 | + } |
| 46 | + |
| 47 | + end |
| 48 | +end |
| 49 | + |
| 50 | +############################### |
| 51 | +# client |
| 52 | +############################### |
| 53 | +class JRPC_client(jrpc_client) |
| 54 | + |
| 55 | + method listen(addr) |
| 56 | + if not (jrpc_client := JRPC_HTTPSocket(addr,"na")) then |
| 57 | + stop("client open(", addr, ") ERROR: ", \&errortext | "Unknown") |
| 58 | + end |
| 59 | + |
| 60 | + method test(op, params, answer) |
| 61 | + local id |
| 62 | + static idx := 0, mtx := mutex() |
| 63 | + critical mtx: id := idx +:=1 |
| 64 | + jrpc_client.send_msg(JRPC_Message().make_request(id, op, params)) |
| 65 | + work_items[id] := [op, params, answer] |
| 66 | + end |
| 67 | + |
| 68 | + method start() |
| 69 | + local x := ?9, y := ?8+1 |
| 70 | + test("+", [x, y], x+y) |
| 71 | + test("-", [x, y], x-y) |
| 72 | + test("*", [x, y], x*y) |
| 73 | + test("/", [x, y], x/y) |
| 74 | + end |
| 75 | + |
| 76 | +end |
| 77 | + |
| 78 | +class JSONRPCTest() |
| 79 | + method run_all_tests() |
| 80 | + local calc, client, jobset, addr, id, op, x, y, answer, |
| 81 | + workers, i, response, job |
| 82 | + |
| 83 | + jsonrpc_test_count := 0 |
| 84 | + jsonrpc_pass_count := 0 |
| 85 | + jsonrpc_fail_count := 0 |
| 86 | + |
| 87 | + write("JSON-RPC Test Suite") |
| 88 | + write("========================================") |
| 89 | + |
| 90 | + addr := ":" || 5000 + ?1000 |
| 91 | + if &features == ("MacOS" | "MS Windows NT") then |
| 92 | + addr := "127.0.0.1" || addr |
| 93 | + |
| 94 | + client := JRPC_client() |
| 95 | + calc := JRPC_Calc() |
| 96 | + thread calc.start(addr) |
| 97 | + client.listen(addr) |
| 98 | + workers:=[] |
| 99 | + work_items := mutex(table()) |
| 100 | + every !4 do put(workers, thread client.start()) |
| 101 | + every wait(!workers) |
| 102 | + jobset:=set() |
| 103 | + every insert(jobset, !*work_items) |
| 104 | + |
| 105 | + every i := !(*work_items*2) do { |
| 106 | + if *jobset = 0 then break |
| 107 | + if response := client.jrpc_client.get_msg(100) then { |
| 108 | + delete(jobset, id:=response.get_id()) |
| 109 | + job := work_items[id] |
| 110 | + op:=job[1]; x:=job[2][1]; y:=job[2][2]; answer := job[3] |
| 111 | + jsonrpc_test_count +:= 1 |
| 112 | + if response.get_result() = answer then { |
| 113 | + jsonrpc_pass_count +:= 1 |
| 114 | + write(left(id, 2), ": ", x, " ", op, " ", y, " = ", right(response.get_result(), 3), |
| 115 | + " Pass") |
| 116 | + } else { |
| 117 | + jsonrpc_fail_count +:= 1 |
| 118 | + write(left(id, 2), ": ", x, " ", op, " ", y, " = ", right(response.get_result(), 3), |
| 119 | + " Fail (expected ", answer, ")") |
| 120 | + } |
| 121 | + } |
| 122 | + } |
| 123 | + |
| 124 | + every job := work_items[id:=!jobset] do { |
| 125 | + op:=job[1]; x:=job[2][1]; y:=job[2][2] |
| 126 | + jsonrpc_test_count +:= 1 |
| 127 | + jsonrpc_fail_count +:= 1 |
| 128 | + write(left(id, 2), ": ", x, " ", op, " ", y, " = Failed to get a response") |
| 129 | + } |
| 130 | + |
| 131 | + # Print results |
| 132 | + write("\n========================================") |
| 133 | + write("Test Results:") |
| 134 | + write("Total tests: ", jsonrpc_test_count) |
| 135 | + write("Passed: ", jsonrpc_pass_count) |
| 136 | + write("Failed: ", jsonrpc_fail_count) |
| 137 | + if jsonrpc_test_count > 0 then { |
| 138 | + write("Success rate: ", real(jsonrpc_pass_count) / real(jsonrpc_test_count) * 100, "%") |
| 139 | + } |
| 140 | + |
| 141 | + if jsonrpc_pass_count = jsonrpc_test_count then |
| 142 | + return |
| 143 | + end |
| 144 | +end |
| 145 | + |
| 146 | +$ifdef STANDALONE |
| 147 | +procedure main() |
| 148 | + local test_suite |
| 149 | + |
| 150 | + test_suite := JSONRPCTest() |
| 151 | + if test_suite.run_all_tests() then { |
| 152 | + write("✓ All tests passed") |
| 153 | + exit(0) |
| 154 | + } else { |
| 155 | + write("✗ Some tests failed") |
| 156 | + exit(1) |
| 157 | + } |
| 158 | +end |
| 159 | +$endif |
| 160 | + |
0 commit comments