IMPALA-9028: impala-shell should not try to reconnect if quitting

When the impala-shell is disconnected, it will try to reconnect
for any command that a user runs (as part of ImpalaShell's precmd()).
This doesn't make sense when the user is trying to quit the shell
(i.e. by typing 'quit' or 'exit' or hitting Ctrl-D).

This skips the attempt to reconnect when quitting the shell.

Testing:
 - Added test in test_shell_interactive.py
 - Verified by hand

Change-Id: I6a76bc515db609498fa8772e9f0b0c547b82c09e
Reviewed-on: http://gerrit.cloudera.org:8080/14391
Reviewed-by: Thomas Tauber-Marshall <tmarshall@cloudera.com>
Tested-by: Impala Public Jenkins <impala-public-jenkins@cloudera.com>
diff --git a/shell/impala_shell.py b/shell/impala_shell.py
index 35af848..554ae26 100755
--- a/shell/impala_shell.py
+++ b/shell/impala_shell.py
@@ -147,6 +147,8 @@
   HISTORY_FILE_QUERY_DELIM = '_IMP_DELIM_'
   # Strings that are interpreted as True for some shell options.
   TRUE_STRINGS = ("true", "TRUE", "True", "1")
+  # List of quit commands
+  QUIT_COMMANDS = ("quit", "exit")
 
   VALID_SHELL_OPTIONS = {
     'LIVE_PROGRESS' : (lambda x: x in ImpalaShell.TRUE_STRINGS, "print_progress"),
@@ -580,6 +582,10 @@
         print_to_stderr("Failed to reconnect and close (try %i/%i): %s" % (
             cancel_try + 1, ImpalaShell.CANCELLATION_TRIES, err_msg))
 
+  def _is_quit_command(self, command):
+    # Do a case insensitive check
+    return command.lower() in ImpalaShell.QUIT_COMMANDS
+
   def set_prompt(self, db):
     self.prompt = ImpalaShell.PROMPT_FORMAT.format(
         host=self.impalad[0], port=self.impalad[1], db=db)
@@ -597,7 +603,8 @@
       # If cmdqueue is populated, then commands are executed from the cmdqueue, and user
       # input is ignored. Send an empty string as the user input just to be safe.
       return str()
-    if not self.imp_client.is_connected():
+    # There is no need to reconnect if we are quitting.
+    if not self.imp_client.is_connected() and not self._is_quit_command(args):
       print_to_stderr("Connection lost, reconnecting...")
       self._connect()
       self._validate_database(immediately=True)
diff --git a/tests/shell/test_shell_interactive.py b/tests/shell/test_shell_interactive.py
index 92e5ab2..65b85a7 100755
--- a/tests/shell/test_shell_interactive.py
+++ b/tests/shell/test_shell_interactive.py
@@ -238,6 +238,21 @@
                                           wait_until_connected=False)
     assert ImpalaShellClass.DISCONNECTED_PROMPT in result.stdout, result.stderr
 
+  def test_quit_no_reconnect(self, vector):
+    """Test that a disconnected shell does not try to reconnect if quitting"""
+    result = run_impala_shell_interactive(vector, 'quit;', shell_args=['-ifoo'],
+                                          wait_until_connected=False)
+    assert "reconnect" not in result.stderr
+
+    result = run_impala_shell_interactive(vector, 'exit;', shell_args=['-ifoo'],
+                                          wait_until_connected=False)
+    assert "reconnect" not in result.stderr
+
+    # Null case: This is not quitting, so it will result in an attempt to reconnect.
+    result = run_impala_shell_interactive(vector, 'show tables;', shell_args=['-ifoo'],
+                                          wait_until_connected=False)
+    assert "reconnect" in result.stderr
+
   def test_bash_cmd_timing(self, vector):
     """Test existence of time output in bash commands run from shell"""
     args = ["! ls;"]