]> granicus.if.org Git - vim/commitdiff
patch 8.2.4788: large payload for LSP message not tested v8.2.4788
authorYegappan Lakshmanan <yegappan@yahoo.com>
Tue, 19 Apr 2022 09:25:13 +0000 (10:25 +0100)
committerBram Moolenaar <Bram@vim.org>
Tue, 19 Apr 2022 09:25:13 +0000 (10:25 +0100)
Problem:    Large payload for LSP message not tested.
Solution:   Add a test with a large LSP payload. (Yegappan Lakshmanan,
            closes #10223)

src/channel.c
src/testdir/test_channel.vim
src/testdir/test_channel_lsp.py
src/version.c

index b981af4006ae53e5e84dded5487a97670a978847..87dc00cd0c5152fe58f1bef5d9f83538adb7cbb7 100644 (file)
@@ -2031,6 +2031,8 @@ channel_consume(channel_T *channel, ch_part_T part, int len)
  * Collapses the first and second buffer for "channel"/"part".
  * Returns FAIL if that is not possible.
  * When "want_nl" is TRUE collapse more buffers until a NL is found.
+ * When the channel part mode is "lsp", collapse all the buffers as the http
+ * header and the JSON content can be present in multiple buffers.
  */
     int
 channel_collapse(channel_T *channel, ch_part_T part, int want_nl)
index 6fef421e56aae5370dd5c07a10975d579ad729f0..e156fa687042b1e284926b1be89ecf33c8e490b8 100644 (file)
@@ -2466,7 +2466,7 @@ func LspOtCb(chan, msg)
 endfunc
 
 func LspTests(port)
-  " call ch_logfile('Xlsprpc.log', 'w')
+  " call ch_logfile('Xlspclient.log', 'w')
   let ch = ch_open(s:localhost .. a:port, #{mode: 'lsp', callback: 'LspCb'})
   if ch_status(ch) == "fail"
     call assert_report("Can't open the lsp channel")
@@ -2620,6 +2620,16 @@ func LspTests(port)
   " send a ping to make sure communication still works
   call assert_equal('alive', ch_evalexpr(ch, #{method: 'ping'}).result)
 
+  " Test for a large payload
+  let content = repeat('abcdef', 11000)
+  let resp = ch_evalexpr(ch, #{method: 'large-payload',
+        \ params: #{text: content}})
+  call assert_equal(#{jsonrpc: '2.0', id: 26, result:
+        \ #{method: 'large-payload', jsonrpc: '2.0', id: 26,
+        \ params: #{text: content}}}, resp)
+  " send a ping to make sure communication still works
+  call assert_equal('alive', ch_evalexpr(ch, #{method: 'ping'}).result)
+
   " Test for invoking an unsupported method
   let resp = ch_evalexpr(ch, #{method: 'xyz', params: {}}, #{timeout: 200})
   call assert_equal({}, resp)
index fb8ed2243f3915c9eec47becc8c3a63df15109bb..ea0fd1034a90a7cf946a5407318060c56c3904d7 100644 (file)
@@ -24,6 +24,11 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
     def setup(self):
         self.request.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
 
+    def debuglog(self, msg):
+        if self.debug:
+            with open("Xlspserver.log", "a") as myfile:
+                myfile.write(msg)
+
     def send_lsp_msg(self, msgid, resp_dict):
         v = {'jsonrpc': '2.0', 'result': resp_dict}
         if msgid != -1:
@@ -34,8 +39,7 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
         resp += "\r\n"
         resp += s
         if self.debug:
-            with open("Xlspdebug.log", "a") as myfile:
-                myfile.write("\n=> send\n" + resp)
+            self.debuglog("SEND: ({0} bytes) '{1}'\n".format(len(resp), resp))
         self.request.sendall(resp.encode('utf-8'))
 
     def send_wrong_payload(self):
@@ -136,6 +140,10 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
         time.sleep(0.2)
         self.send_lsp_msg(-1, 'wrong-payload')
 
+    def do_large_payload(self, payload):
+        # test for sending a large (> 64K) payload
+        self.send_lsp_msg(payload['id'], payload)
+
     def do_rpc_resp_incorrect_id(self, payload):
         self.send_lsp_msg(-1, 'rpc-resp-incorrect-id-1')
         self.send_lsp_msg(-1, 'rpc-resp-incorrect-id-2')
@@ -185,8 +193,6 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
     def process_msg(self, msg):
         try:
             decoded = json.loads(msg)
-            print("Decoded:")
-            print(str(decoded))
             if 'method' in decoded:
                 test_map = {
                         'ping': self.do_ping,
@@ -194,6 +200,7 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
                         'simple-rpc': self.do_simple_rpc,
                         'rpc-with-notif': self.do_rpc_with_notif,
                         'wrong-payload': self.do_wrong_payload,
+                        'large-payload': self.do_large_payload,
                         'rpc-resp-incorrect-id': self.do_rpc_resp_incorrect_id,
                         'simple-notif': self.do_simple_notif,
                         'multi-notif': self.do_multi_notif,
@@ -211,28 +218,40 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
                 if decoded['method'] in test_map:
                     test_map[decoded['method']](decoded)
                 else:
-                    print("Error: Unsupported method: " + decoded['method'])
+                    self.debuglog("Error: Unsupported method - " + decoded['method'] + "\n")
             else:
-                print("Error: 'method' field is not found")
+                self.debuglog("Error: 'method' field is not found\n")
 
         except ValueError:
-            print("json decoding failed")
+            self.debuglog("Error: json decoding failed\n")
 
     def process_msgs(self, msgbuf):
         while True:
             sidx = msgbuf.find('Content-Length: ')
             if sidx == -1:
+                # partial message received
                 return msgbuf
             sidx += 16
             eidx = msgbuf.find('\r\n')
             if eidx == -1:
+                # partial message received
                 return msgbuf
             msglen = int(msgbuf[sidx:eidx])
 
             hdrend = msgbuf.find('\r\n\r\n')
             if hdrend == -1:
+                # partial message received
+                return msgbuf
+
+            if msglen > len(msgbuf[hdrend + 4:]):
+                if self.debug:
+                    self.debuglog("Partial message ({0} bytes)\n".format(len(msgbuf)))
+                # partial message received
                 return msgbuf
 
+            if self.debug:
+                self.debuglog("Complete message ({0} bytes) received\n".format(msglen))
+
             # Remove the header
             msgbuf = msgbuf[hdrend + 4:]
             payload = msgbuf[:msglen]
@@ -243,27 +262,25 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
             msgbuf = msgbuf[msglen:]
 
     def handle(self):
-        print("=== socket opened ===")
         self.debug = False
+        self.debuglog("=== socket opened ===\n")
         msgbuf = ''
         while True:
             try:
                 received = self.request.recv(4096).decode('utf-8')
             except socket.error:
-                print("=== socket error ===")
+                self.debuglog("=== socket error ===\n")
                 break
             except IOError:
-                print("=== socket closed ===")
+                self.debuglog("=== socket closed ===\n")
                 break
             if received == '':
-                print("=== socket closed ===")
+                self.debuglog("=== socket closed ===\n")
                 break
-            print("\nReceived:\n{0}".format(received))
 
             # Write the received lines into the file for debugging
             if self.debug:
-                with open("Xlspdebug.log", "a") as myfile:
-                    myfile.write("\n<= recv\n" + received)
+                self.debuglog("RECV: ({0} bytes) '{1}'\n".format(len(received), received))
 
             # Can receive more than one line in a response or a partial line.
             # Accumulate all the received characters and process one line at
@@ -287,8 +304,6 @@ def main(host, port, server_class=ThreadedTCPServer):
     if len(sys.argv) >= 2 and sys.argv[1] == 'delay':
         port = 13684
         writePortInFile(port)
-
-        print("Wait for it...")
         time.sleep(0.5)
 
     server = server_class((host, port), ThreadedTCPRequestHandler)
@@ -301,8 +316,6 @@ def main(host, port, server_class=ThreadedTCPServer):
 
     writePortInFile(port)
 
-    print("Listening on port {0}".format(port))
-
     # Main thread terminates, but the server continues running
     # until server.shutdown() is called.
     try:
index c221c28ad8a4a6365263f7497c147a0fa96d0cf6..411ea1ad8d41d34407425be9c90ddeef640b7b94 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4788,
 /**/
     4787,
 /**/