changeset 1756:a385e862f77f

Run original command if not previously configured and setup intercepted. Reviewed-by: omajid Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2015-August/015439.html PR2581
author Severin Gehwolf <sgehwolf@redhat.com>
date Thu, 03 Sep 2015 11:20:14 +0200
parents 5abd45b55267
children 47760bc2a861
files launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherImplTest.java setup-command/command/src/main/java/com/redhat/thermostat/setup/command/SetupCommand.java setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/SetupWindow.java setup-command/command/src/test/java/com/redhat/thermostat/setup/command/SetupCommandTest.java setup-command/distribution/thermostat-plugin.xml
diffstat 6 files changed, 217 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java	Wed Sep 02 15:27:53 2015 +0200
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java	Thu Sep 03 11:20:14 2015 +0200
@@ -157,14 +157,11 @@
             } else {
                 // With web-always-on we need to make sure that the setup ran.
                 if (isThermostatConfigured()) {
+                    logger.log(Level.FINE, "Running command without setup interception.");
                     runCommandFromArguments(args, listeners, inShell);
                 } else {
-                    if (Arrays.asList(args).contains("--skip-setup")) {
-                        runCommandFromArguments(args, listeners, inShell);
-                    } else {
-                        String[] setupArgs = {"setup"};
-                        runCommandFromArguments(setupArgs, listeners, inShell);
-                    }
+                    logger.log(Level.FINE, "Running command through setup.");
+                    runSetupThenInterceptedCommand(args);
                 }
             }
         } catch (NoClassDefFoundError e) {
@@ -188,11 +185,32 @@
             }
         }
     }
+    
+    private void runSetupThenInterceptedCommand(String[] originalCmdArgs) {
+        String origCmdArgs = convertOriginalArgsToString(originalCmdArgs);
+        String[] setupArgs = { "setup",
+                               "--origArgs",
+                               origCmdArgs
+                             };
+        runCommandFromArguments(setupArgs, null, false);
+    }
 
-    // Log messages might go to a file. Be sure to print to stdout as well.
-    private void printAndLogLine(String msg) {
-        System.out.println(msg);
-        logger.log(Level.INFO, msg);
+    private String convertOriginalArgsToString(String[] origArgs) {
+        if (origArgs.length == 0) {
+            throw new AssertionError("Running setup with no argument?");
+        }
+        final String separator = "|||";
+        // single argument
+        if (origArgs.length == 1) {
+            return origArgs[0];
+        }
+        StringBuffer buffer = new StringBuffer();
+        for (int i = 0; i < origArgs.length - 1; i++) {
+            buffer.append(origArgs[i]);
+            buffer.append(separator);
+        }
+        buffer.append(origArgs[origArgs.length - 1]);
+        return buffer.toString();
     }
 
     private boolean isThermostatConfigured() throws InvalidConfigurationException {
@@ -247,7 +265,8 @@
         runCommand(HELP_COMMAND_NAME, new String[] { "--", cmdName }, null, false);
     }
 
-    private void runCommandFromArguments(String[] args, Collection<ActionListener<ApplicationState>> listeners, boolean inShell) {
+    // package-private for testing
+    void runCommandFromArguments(String[] args, Collection<ActionListener<ApplicationState>> listeners, boolean inShell) {
         runCommand(args[0], Arrays.copyOfRange(args, 1, args.length), listeners, inShell);
     }
 
@@ -420,5 +439,6 @@
             }
         }
     }
+
 }
 
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherImplTest.java	Wed Sep 02 15:27:53 2015 +0200
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherImplTest.java	Thu Sep 03 11:20:14 2015 +0200
@@ -48,8 +48,11 @@
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.EnumSet;
+import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.ExecutorService;
 import java.util.logging.Handler;
 import java.util.logging.Level;
@@ -58,6 +61,8 @@
 
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.Options;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -70,6 +75,7 @@
 import com.redhat.thermostat.common.ActionNotifier;
 import com.redhat.thermostat.common.ApplicationService;
 import com.redhat.thermostat.common.ExitStatus;
+import com.redhat.thermostat.common.Pair;
 import com.redhat.thermostat.common.Version;
 import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand;
 import com.redhat.thermostat.common.cli.Arguments;
@@ -239,6 +245,7 @@
         when(infos.getCommandInfo(name4)).thenReturn(info4);
         when(infos.getCommandInfo("basic")).thenReturn(basicInfo);
         when(infos.getCommandInfo("help")).thenReturn(helpCommandInfo);
+        when(infos.getCommandInfo("setup")).thenReturn(mock(CommandInfo.class));
 
         Collection<CommandInfo> infoList = new ArrayList<CommandInfo>();
         infoList.add(helpCommandInfo);
@@ -682,6 +689,60 @@
         runAndVerifyCommand(new String[] { cmdName }, expected, isInShell);
     }
     
+    @Test
+    public void verifyOriginalCmdArgsArePassedOnToSetup() {
+        String[] argsList = new String[] { "list-vms", "--dbUrl=foo" };
+        List<Pair<String[], Boolean>> resultList = doOriginalCmdArgsArePassedOnToSetupTest(argsList);
+        assertEquals("Expected to run only setup", 1, resultList.size());
+        Pair<String[], Boolean> actual = resultList.get(0);
+        assertFalse("Expected to run outside shell", actual.getSecond());
+        String[] expectedList = new String[] { "setup", "--origArgs", "list-vms|||--dbUrl=foo" };
+        assertArrayEquals(expectedList, actual.getFirst());
+    }
+    
+    @Test
+    public void verifyOriginalCmdArgsArePassedOnToSetup2() {
+        String[] argsList = new String[] { "web-storage-service" };
+        List<Pair<String[], Boolean>> resultList = doOriginalCmdArgsArePassedOnToSetupTest(argsList);
+        assertEquals("Expected to run only setup", 1, resultList.size());
+        Pair<String[], Boolean> actual = resultList.get(0);
+        assertFalse("Expected to run outside shell", actual.getSecond());
+        String[] expectedList = new String[] { "setup", "--origArgs", "web-storage-service" };
+        assertArrayEquals(expectedList, actual.getFirst());
+    }
+    
+    private List<Pair<String[], Boolean>> doOriginalCmdArgsArePassedOnToSetupTest(String[] args) {
+        CommonPaths setupPaths = mock(CommonPaths.class);
+        File mockFile = mock(File.class);
+        when(mockFile.exists()).thenReturn(false);
+        when(setupPaths.getUserSetupCompleteStampFile()).thenReturn(mockFile);
+        File fileWithAbsPath = mock(File.class);
+        when(setupPaths.getSystemThermostatHome()).thenReturn(fileWithAbsPath);
+        when(setupPaths.getUserThermostatHome()).thenReturn(fileWithAbsPath);
+        final List<Pair<String[], Boolean>> runList = new ArrayList<>();
+        launcher = new LauncherImpl(bundleContext, ctxFactory, registry, infos,
+                                    new CommandSource(bundleContext), environment,
+                                    dbServiceFactory, version,
+                                    mock(ClientPreferences.class),
+                                    mock(Keyring.class), setupPaths, mock(LoggingInitializer.class)) {
+            @Override
+            void runCommandFromArguments(String[] args, Collection<ActionListener<ApplicationState>> listeners, boolean inShell) {
+                Pair<String[], Boolean> pair = new Pair<>(args, inShell);
+                runList.add(pair);
+            }
+        };
+        
+        wrappedRun(launcher, args, false, null);
+        return runList;
+    }
+    
+    private void assertArrayEquals(String[] expected, String[] actual) {
+        assertTrue(expected.length == actual.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals(expected[i], actual[i]);
+        }
+    }
+    
     private static class TestLogHandler extends Handler {
         
         private boolean loggedThermostatHome;
@@ -710,5 +771,6 @@
         }
         
     }
+
 }
 
--- a/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/SetupCommand.java	Wed Sep 02 15:27:53 2015 +0200
+++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/SetupCommand.java	Thu Sep 03 11:20:14 2015 +0200
@@ -38,12 +38,16 @@
 
 import java.awt.EventQueue;
 import java.lang.reflect.InvocationTargetException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.cli.AbstractCommand;
+import com.redhat.thermostat.common.cli.Arguments;
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
 import com.redhat.thermostat.common.cli.Console;
 import com.redhat.thermostat.common.cli.DependencyServices;
+import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.internal.utils.laf.ThemeManager;
 import com.redhat.thermostat.launcher.Launcher;
 import com.redhat.thermostat.setup.command.internal.SetupWindow;
@@ -53,15 +57,24 @@
 
 public class SetupCommand extends AbstractCommand {
 
+    private static final String ORIG_CMD_ARGUMENT_NAME = "origArgs";
+    private static final Logger logger = LoggingUtils.getLogger(SetupCommand.class);
     private final DependencyServices dependentServices = new DependencyServices();
     private SetupWindow mainWindow;
     private CommonPaths paths;
     private Launcher launcher;
     private ThermostatSetup thermostatSetup;
     private Console console;
+    private String[] origArgsList;
 
     @Override
     public void run(CommandContext ctx) throws CommandException {
+        Arguments args = ctx.getArguments();
+        if (args.hasArgument(ORIG_CMD_ARGUMENT_NAME)) {
+            String origArgs = args.getArgument(ORIG_CMD_ARGUMENT_NAME);
+            origArgsList = origArgs.split("\\|\\|\\|");
+        }
+        
         this.console = ctx.getConsole();
 
         try {
@@ -76,6 +89,22 @@
         } catch (InterruptedException | InvocationTargetException e) {
             throw new CommandException(new LocalizedString("SetupCommand failed to run"), e);
         }
+        runOriginalCommand(origArgsList);
+    }
+
+    private void runOriginalCommand(String[] args) {
+        if (args == null) {
+            return;
+        }
+        if (args.length == 0) {
+            throw new AssertionError("Original command args were empty!");
+        }
+        if (args[0].equals("setup")) {
+            // Do not run setup recursively
+            return;
+        }
+        logger.log(Level.FINE, "Running intercepted command '" + args[0] + "' after setup.");
+        launcher.run(args, false);
     }
 
     public void setPaths(CommonPaths paths) {
--- a/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/SetupWindow.java	Wed Sep 02 15:27:53 2015 +0200
+++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/SetupWindow.java	Thu Sep 03 11:20:14 2015 +0200
@@ -281,6 +281,10 @@
     }
 
     private void shutdown() {
+        // Explicitly dispose the window on shutdown since we might have
+        // intercepted another command and the window would otherwise
+        // stay open.
+        frame.dispose();
         shutdown.countDown();
     }
 }
--- a/setup-command/command/src/test/java/com/redhat/thermostat/setup/command/SetupCommandTest.java	Wed Sep 02 15:27:53 2015 +0200
+++ b/setup-command/command/src/test/java/com/redhat/thermostat/setup/command/SetupCommandTest.java	Thu Sep 03 11:20:14 2015 +0200
@@ -38,15 +38,23 @@
 
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import java.io.ByteArrayOutputStream;
 import java.io.PrintStream;
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -158,6 +166,49 @@
         }
     }
     
+    @Test
+    public void verifyOriginalCommandRunsAfterSetup() throws CommandException {
+        doTestOriginalCmdRunsAfterSetup("web-storage-service", new String[] {
+           "web-storage-service"     
+        });
+    }
+    
+    @Test
+    public void verifyOriginalCommandRunsAfterSetup2() throws CommandException {
+        doTestOriginalCmdRunsAfterSetup("list-vms|||--dbUrl=mongodb://127.0.0.1:25718", new String[] {
+           "list-vms", "--dbUrl=mongodb://127.0.0.1:25718"     
+        });
+    }
+    
+    @Test
+    public void verifySetupAsOrigCommandDoesNotRunAgain() throws CommandException {
+        cmd = createSetupCommand();
+        setServices();
+        
+        Arguments args = mock(Arguments.class);
+        CommandContext ctxt = mock(CommandContext.class);
+        when(ctxt.getArguments()).thenReturn(args);
+        when(args.hasArgument("origArgs")).thenReturn(true);
+        when(args.getArgument("origArgs")).thenReturn("setup");
+        
+        cmd.run(ctxt);
+        verify(launcher, times(0)).run(argThat(new ArgsMatcher(new String[] { "setup" })), eq(false));
+    }
+    
+    private void doTestOriginalCmdRunsAfterSetup(String origArgs, String[] argsList) throws CommandException {
+        cmd = createSetupCommand();
+        setServices();
+        
+        Arguments args = mock(Arguments.class);
+        CommandContext ctxt = mock(CommandContext.class);
+        when(ctxt.getArguments()).thenReturn(args);
+        when(args.hasArgument("origArgs")).thenReturn(true);
+        when(args.getArgument("origArgs")).thenReturn(origArgs);
+        
+        cmd.run(ctxt);
+        verify(launcher).run(argThat(new ArgsMatcher(argsList)), eq(false));
+    }
+    
     private SetupCommand createSetupCommand() {
         return new SetupCommand() {
             @Override
@@ -176,6 +227,37 @@
         cmd.setPaths(paths);
         cmd.setLauncher(launcher);
     }
+    
+    private static class ArgsMatcher extends BaseMatcher<String[]> {
+
+        private final String[] expected;
+        
+        private ArgsMatcher(String[] expected) {
+            this.expected = expected;
+        }
+        
+        @Override
+        public boolean matches(Object arg0) {
+            if (arg0 == null || arg0.getClass() != String[].class) {
+                return false;
+            }
+            String[] other = (String[])arg0;
+            if (other.length != expected.length) {
+                return false;
+            }
+            boolean matches = true;
+            for (int i = 0; i < expected.length; i++) {
+                matches = matches && Objects.equals(expected[i], other[i]);
+            }
+            return matches;
+        }
+
+        @Override
+        public void describeTo(Description arg0) {
+            arg0.appendText(Arrays.asList(expected).toString());
+        }
+        
+    }
 
 }
 
--- a/setup-command/distribution/thermostat-plugin.xml	Wed Sep 02 15:27:53 2015 +0200
+++ b/setup-command/distribution/thermostat-plugin.xml	Thu Sep 03 11:20:14 2015 +0200
@@ -44,6 +44,15 @@
       <name>setup</name>
       <summary>setup thermostat for first run</summary>
       <description>setup an initial mongodb user and webapp settings. Optionally create a client admin and agent user.</description>
+      <options>
+        <option>
+          <long>origArgs</long>
+          <short>o</short>
+          <argument>originalArgs</argument>
+          <required>false</required>
+          <description>A string holding '|||'-separated values of original arguments if a command got intercepted with setup.</description>
+        </option>
+      </options>
       <environments>
         <environment>cli</environment>
         <environment>shell</environment>