From 3f9e3e600e982bf050c93ea04367e2cfe2a6d414 Mon Sep 17 00:00:00 2001 From: dzmipt Date: Fri, 15 Mar 2024 17:51:27 +0100 Subject: [PATCH] Errors are rendered with '. All IO errors are rendered into tabs --- notes.md | 2 + src/kx/IPC.java | 4 +- src/studio/kdb/QErrors.java | 49 ---------------------- src/studio/ui/StudioWindow.java | 18 +++----- src/studio/ui/TabPanel.java | 15 +++++-- test-integration/studio/ui/ResultTest.java | 22 ++++++++++ test-integration/studio/ui/StudioTest.java | 11 ++++- test/kx/IPCTest.java | 18 ++++++++ 8 files changed, 70 insertions(+), 69 deletions(-) delete mode 100755 src/studio/kdb/QErrors.java create mode 100644 test/kx/IPCTest.java diff --git a/notes.md b/notes.md index 2c1fd9d6..fcc873fe 100644 --- a/notes.md +++ b/notes.md @@ -1,3 +1,5 @@ +* Any IO errors are added as Error tab (pop-up error message is used for internal bugs) + * KX errors from servers are now display with ' (not as symbol) * Parent folder can be specified in the server form (in add and edit server) * Persist location of the server list frame for every Studio window diff --git a/src/kx/IPC.java b/src/kx/IPC.java index df6bc623..1febaec7 100644 --- a/src/kx/IPC.java +++ b/src/kx/IPC.java @@ -49,11 +49,11 @@ public static KMessage deserialise(byte[] data, boolean compressed, boolean isLi } } - public KMessage deserialise(){ + public KMessage deserialise() { try { if (b[0] == -128) { j = 1; - return new KMessage(new K4Exception(rs().toString())); + return new KMessage(new K4Exception("'" + rs().s)); } return new KMessage(r()); } catch (UnsupportedEncodingException e) { diff --git a/src/studio/kdb/QErrors.java b/src/studio/kdb/QErrors.java deleted file mode 100755 index 2b680e44..00000000 --- a/src/studio/kdb/QErrors.java +++ /dev/null @@ -1,49 +0,0 @@ -package studio.kdb; - -import java.util.HashMap; -import java.util.Map; - -public class QErrors { - private static Map map = new HashMap(); - - public static String lookup(String s) { - return (String) map.get(s); - } - - - static { - map.put("access","attempt to read files above directory, run system commands or failed usr/pwd"); - map.put("assign","attempt to assign a value to a reserved word"); - map.put("conn","too many incoming connections (1022 max)"); - map.put("domain","out of domain"); - map.put("glim","`g# limit, kdb+ currently limited to 99 concurrent `g#'s "); - map.put("length","incompatible lengths, e.g. 1 2 3 4 + 1 2 3"); - map.put("limit","tried to generate a list longer than 2,000,000,000"); - map.put("loop","dependency loop"); - map.put("mismatch","columns that can't be aligned for R,R or K,K "); - map.put("Mlim","more than 999 nested columns in splayed tables"); - map.put("nyi","not yet implemented - suggests the\noperation you are tying to do makes sense\nbut it has not yet been implemented"); - map.put("os","operating system error"); - map.put("pl","peach can't handle parallel lambda's (2.3 only)"); - map.put("Q7","nyi op on file nested array"); - map.put("rank","invalid rank or valence"); - map.put("splay","nyi op on splayed table"); - map.put("stack","ran out of stack space"); - map.put("stop","user interrupt(ctrl-c) or time limit (-T)"); - map.put("stype","invalid type used to signal"); - map.put("type","wrong type, e.g `a+1"); - map.put("value","no value"); - map.put("vd1","attempted multithread update"); - map.put("wsfull","malloc failed. ran out of swap (or addressability on 32bit). or hit -w limit."); - map.put("branch","a branch(if;do;while;$[.;.;.]) more than 255 byte codes away"); - map.put("char","invalid character"); - map.put("constants","too many constants (max 96)"); - map.put("globals","too many global variables (32 max)"); - map.put("locals","too many local variables (24 max)"); - map.put("params","too many parameters (8 max)"); - map.put("u-fail","cannot apply `u# to data (not unique values), e.g `u#1 1"); - map.put("s-fail","cannot apply `s# to data (not ascending values) , e.g `s#2 1"); - map.put("noamend","can't change global state inside an amend"); - map.put("elim","more than 57 distinct enumerations"); - } -} diff --git a/src/studio/ui/StudioWindow.java b/src/studio/ui/StudioWindow.java index 728d8aca..bf366c95 100755 --- a/src/studio/ui/StudioWindow.java +++ b/src/studio/ui/StudioWindow.java @@ -1,6 +1,5 @@ package studio.ui; -import kx.K4Exception; import kx.KMessage; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -1690,7 +1689,6 @@ public static void queryExecutionComplete(EditorTab editor, QueryResult queryRes editor.getPane().stopClock(); JTextComponent textArea = editor.getTextArea(); textArea.setCursor(textCursor); - Throwable error = queryResult.getError(); if (queryResult.isComplete()) { long execTime = queryResult.getExecutionTimeInMS(); editor.getPane().setEditorStatus("Last execution time: " + (execTime > 0 ? "" + execTime : "<1") + " ms"); @@ -1699,19 +1697,13 @@ public static void queryExecutionComplete(EditorTab editor, QueryResult queryRes } StudioWindow window = editor.getStudioWindow(); - if (error == null || error instanceof K4Exception) { - try { - if (queryResult.isComplete()) { - window.addResultTab(queryResult, "Executed at server: " + queryResult.getServer().getDescription(true) ); - } - error = null; - } catch (Throwable exc) { - error = new RuntimeException("Error during result rendering", exc); - log.error("Error during result rendering", exc); + try { + if (queryResult.isComplete()) { + window.addResultTab(queryResult, "Executed at server: " + queryResult.getServer().getDescription(true) ); } - } + } catch (Throwable error) { + log.error("Error during result rendering", error); - if (error != null) { String message = error.getMessage(); if ((message == null) || (message.length() == 0)) message = "No message with exception. Exception is " + error; diff --git a/src/studio/ui/TabPanel.java b/src/studio/ui/TabPanel.java index 792c17c5..f43cff9e 100755 --- a/src/studio/ui/TabPanel.java +++ b/src/studio/ui/TabPanel.java @@ -1,5 +1,6 @@ package studio.ui; +import kx.K4Exception; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import studio.kdb.ListModel; @@ -118,9 +119,17 @@ private void initComponents() { updateFormatting(); } else { textArea = new JTextPane(); - String hint = QErrors.lookup(queryResult.getError().getMessage()); - hint = hint == null ? "" : "\nStudio Hint: Possibly this error refers to " + hint; - textArea.setText("An error occurred during execution of the query.\nThe server sent the response:\n" + queryResult.getError().getMessage() + hint); + Throwable error = queryResult.getError(); + String msg; + if (error instanceof K4Exception) { + msg = "An error occurred during execution of the query.\nThe server sent the response:\n" + error.getMessage(); + } else { + msg = "An unexpected error occurred whilst communicating with server.\nError: " + error.toString(); + if (error.getMessage() != null) { + msg += "\nMessage: " + error.getMessage(); + } + } + textArea.setText(msg); textArea.setForeground(Color.RED); textArea.setEditable(false); component = new JScrollPane(textArea); diff --git a/test-integration/studio/ui/ResultTest.java b/test-integration/studio/ui/ResultTest.java index 0f4ff855..86cb8666 100644 --- a/test-integration/studio/ui/ResultTest.java +++ b/test-integration/studio/ui/ResultTest.java @@ -13,6 +13,8 @@ import studio.kdb.MockQSession; import java.awt.*; +import java.io.EOFException; +import java.io.IOException; import java.util.Arrays; import java.util.regex.Pattern; @@ -112,5 +114,25 @@ public void testAuthenticationException() { textArea.requireText(Pattern.compile(".*error.*Authentication failed.*", Pattern.DOTALL)); } + @Test + public void testEOFException() { + setExpectedNumberOfLogErrors(1); + MockQSession.setResponse(new EOFException()); + execute(); + + JTextComponentFixture textArea = frameFixture.panel("resultPanel0").textBox(); + textArea.requireText(Pattern.compile(".*Error: java.io.EOFException", Pattern.DOTALL)); + } + + @Test + public void testIOException() { + setExpectedNumberOfLogErrors(1); + MockQSession.setResponse(new IOException("ioMessageHere")); + execute(); + + JTextComponentFixture textArea = frameFixture.panel("resultPanel0").textBox(); + textArea.requireText(Pattern.compile(".*Error: java.io.IOException.*ioMessageHere.*", Pattern.DOTALL)); + } + } diff --git a/test-integration/studio/ui/StudioTest.java b/test-integration/studio/ui/StudioTest.java index 7a0d38a2..2030f781 100644 --- a/test-integration/studio/ui/StudioTest.java +++ b/test-integration/studio/ui/StudioTest.java @@ -51,6 +51,7 @@ abstract public class StudioTest extends AssertJSwingJUnitTestCase { protected StudioWindow studioWindow; private static Path tmpConfigFolder; + private int expectedNumberOfErrors; @BeforeClass public static void initLogErrors() { @@ -82,8 +83,13 @@ public static void setupEmergency() { } + protected void setExpectedNumberOfLogErrors(int count) { + expectedNumberOfErrors = count; + } + @Override protected void onSetUp() { + expectedNumberOfErrors = 0; LogErrors.reset(); studio.ui.I18n.setLocale(Locale.getDefault()); @@ -98,8 +104,9 @@ protected void onTearDown() throws Exception { super.onTearDown(); String[] errors = LogErrors.get(); - if (errors.length > 0) { - fail("Error logs were detected:\n" + String.join("\n", errors)); + if (errors.length != expectedNumberOfErrors) { + fail("There were " + errors.length + " errors instead of expected number: " + expectedNumberOfErrors + "\n" + + String.join("\n", errors)); } } diff --git a/test/kx/IPCTest.java b/test/kx/IPCTest.java new file mode 100644 index 00000000..daec689c --- /dev/null +++ b/test/kx/IPCTest.java @@ -0,0 +1,18 @@ +package kx; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class IPCTest { + + @Test + public void errorDeserilisation() { + byte[] data = new byte[] {-128, 116, 121, 112, 101, 0}; + KMessage message = IPC.deserialise(data, false, true); + + assertTrue(message.getError() instanceof K4Exception); + assertEquals("'type", message.getError().getMessage()); + } +}