Mercurial > hg > thermostat-ng > agent
changeset 2433:2689d87205f2
Add "shifter-style" rules loader to SwingVmBytemanView
This patch modifies the Rules tab of the Byteman plugin by
introducing a shifter-style UI for injecting and unloading rules.
There now exists a seperate textarea for unloaded and injected
rules, and buttons that can be used to transfer rules between
them. Additionally, the ability to load Byteman rules from
external files has been added.
Reviewed-by: jerboaa
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2016-August/020478.html
author | Alex Macdonald <almacdon@redhat.com> |
---|---|
date | Fri, 26 Aug 2016 14:08:00 -0400 |
parents | b36e89aa7070 |
children | 46b76de8b058 |
files | vm-byteman/client-swing/src/main/java/com/redhat/thermostat/vm/byteman/client/swing/internal/LocaleResources.java vm-byteman/client-swing/src/main/java/com/redhat/thermostat/vm/byteman/client/swing/internal/SwingVmBytemanView.java vm-byteman/client-swing/src/main/java/com/redhat/thermostat/vm/byteman/client/swing/internal/VmBytemanInformationController.java vm-byteman/client-swing/src/main/resources/com/redhat/thermostat/vm/byteman/client/swing/internal/strings.properties vm-byteman/client-swing/src/test/java/com/redhat/thermostat/vm/byteman/client/swing/internal/SwingVmBytemanViewTest.java |
diffstat | 5 files changed, 370 insertions(+), 48 deletions(-) [+] |
line wrap: on
line diff
--- a/vm-byteman/client-swing/src/main/java/com/redhat/thermostat/vm/byteman/client/swing/internal/LocaleResources.java Fri Aug 26 11:48:51 2016 -0400 +++ b/vm-byteman/client-swing/src/main/java/com/redhat/thermostat/vm/byteman/client/swing/internal/LocaleResources.java Fri Aug 26 14:08:00 2016 -0400 @@ -52,6 +52,9 @@ RULE_EMPTY, NO_RULES_LOADED, NO_METRICS_AVAILABLE, + LABEL_LOCAL_RULE, + LABEL_INJECTED_RULE, + IMPORT_RULE, ; static final String RESOURCE_BUNDLE = LocaleResources.class.getPackage().getName() + ".strings";
--- a/vm-byteman/client-swing/src/main/java/com/redhat/thermostat/vm/byteman/client/swing/internal/SwingVmBytemanView.java Fri Aug 26 11:48:51 2016 -0400 +++ b/vm-byteman/client-swing/src/main/java/com/redhat/thermostat/vm/byteman/client/swing/internal/SwingVmBytemanView.java Fri Aug 26 14:08:00 2016 -0400 @@ -41,11 +41,18 @@ import java.awt.ComponentOrientation; import java.awt.Cursor; import java.awt.FlowLayout; +import java.awt.Graphics; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.text.DateFormat; import java.util.ArrayList; import java.util.Date; @@ -58,6 +65,7 @@ import java.util.logging.Logger; import javax.swing.JButton; +import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; @@ -66,12 +74,15 @@ import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.JToggleButton; +import javax.swing.JSplitPane; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.border.LineBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; +import javax.swing.plaf.basic.BasicSplitPaneDivider; +import javax.swing.plaf.basic.BasicSplitPaneUI; import com.redhat.thermostat.client.swing.IconResource; import com.redhat.thermostat.client.swing.SwingComponent; @@ -113,17 +124,26 @@ private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); private static final Icon START_ICON = IconResource.SAMPLE.getIcon(); private static final Icon STOP_ICON = new FontAwesomeIcon('\uf28e', START_ICON.getIconHeight()); + private static final Icon ARROW_LEFT = IconResource.ARROW_LEFT.getIcon(); + private static final Icon ARROW_RIGHT = IconResource.ARROW_RIGHT.getIcon(); private static final String EMPTY_STR = ""; static final String NO_METRICS_AVAILABLE = t.localize(LocaleResources.NO_METRICS_AVAILABLE).getContents(); // Names for buttons used in testing static final String TOGGLE_BUTTON_NAME = "TOGGLE_RULE_BUTTON"; - static final String RULES_TEXT_NAME = "RULES_TEXT"; + static final String RULES_INJECTED_TEXT_NAME = "RULES_INJECTED_TEXT"; + static final String RULES_UNLOADED_TEXT_NAME = "RULES_UNLOADED_TEXT"; static final String METRICS_TEXT_NAME = "METRICS_TEXT"; + private String injectedRuleContent; + private String unloadedRuleContent; + private boolean generateRuleToggle; private final JTextArea metricsText; - private final JTextArea rulesText; + private final JTextArea unloadedRulesText; + private final JTextArea injectedRulesText; + private final JButton injectRuleButton; + private final JButton unloadRuleButton; private JPanel graphMainPanel; private ChartPanel graphPanel; private JFreeChart graph; @@ -175,29 +195,119 @@ final double yWeightRow1 = 0.90; final double yWeightRow2 = 0.05; final double xWeightFullWidth = 1.0; + final double halfWeight = 0.5; final Insets paddingInsets = new Insets(5, 5, 5, 5); // Rules tab final JPanel rulesPanel = new JPanel(); rulesPanel.setLayout(new GridBagLayout()); - rulesText = new ThermostatTextArea(EMPTY_STR); - rulesText.setName(RULES_TEXT_NAME); - rulesText.setMargin(paddingInsets); - rulesText.setBackground(Color.WHITE); - rulesText.setCursor(new Cursor(Cursor.TEXT_CURSOR)); - rulesText.setBorder(new LineBorder(Color.BLACK)); + + // Label Descriptors + JLabel localLabel = new JLabel(t.localize(LocaleResources.LABEL_LOCAL_RULE).getContents()); GridBagConstraints cRules = new GridBagConstraints(); + cRules.gridx = 0; + cRules.gridy = 0; + cRules.anchor = GridBagConstraints.LINE_START; + cRules.insets = paddingInsets; + rulesPanel.add(localLabel, cRules); + JLabel injectLabel = new JLabel(t.localize(LocaleResources.LABEL_INJECTED_RULE).getContents()); + cRules = new GridBagConstraints(); + cRules.gridx = 1; + cRules.gridy = 0; + cRules.anchor = GridBagConstraints.LINE_END; + cRules.insets = paddingInsets; + rulesPanel.add(injectLabel, cRules); + + // Unloaded Rules TextArea + unloadedRulesText = new ThermostatTextArea(EMPTY_STR); + unloadedRulesText.setName(RULES_UNLOADED_TEXT_NAME); + unloadedRulesText.setMargin(paddingInsets); + unloadedRulesText.setBackground(Color.WHITE); + unloadedRulesText.setCursor(new Cursor(Cursor.TEXT_CURSOR)); + unloadedRulesText.setBorder(new LineBorder(Color.BLACK)); + unloadedRulesText.setText(t.localize(LocaleResources.NO_RULES_LOADED).getContents()); + JScrollPane unloadedPane = new ThermostatScrollPane(unloadedRulesText); + unloadedPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + + // Injected Rules TextArea + injectedRulesText = new ThermostatTextArea(EMPTY_STR); + injectedRulesText.setName(RULES_INJECTED_TEXT_NAME); + injectedRulesText.setMargin(paddingInsets); + injectedRulesText.setBackground(Color.WHITE); + injectedRulesText.setCursor(new Cursor(Cursor.TEXT_CURSOR)); + injectedRulesText.setBorder(new LineBorder(Color.BLACK)); + injectedRulesText.setEditable(false); + injectedRulesText.setText(t.localize(LocaleResources.NO_RULES_LOADED).getContents()); + JScrollPane injectedPane = new ThermostatScrollPane(injectedRulesText); + injectedPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + + // Inject & Unload Buttons + injectRuleButton = new JButton(ARROW_RIGHT); + injectRuleButton.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent e) { + fireInjectAction(InjectAction.INJECT_RULE); + } + }); + unloadRuleButton = new JButton(ARROW_LEFT); + unloadRuleButton.setEnabled(false); + unloadRuleButton.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent e) { + fireInjectAction(InjectAction.UNLOAD_RULE); + } + }); + + // Split Pane and Divider + JSplitPane splitPane = new JSplitPane(); + splitPane.setLeftComponent(unloadedPane); + splitPane.setRightComponent(injectedPane); + splitPane.setResizeWeight(halfWeight); + BasicSplitPaneUI ui = new BasicSplitPaneUI() { + public BasicSplitPaneDivider createDefaultDivider() { + return new BasicSplitPaneDivider(this) { + @Override + public void paint(Graphics g) { + g.setColor(rulesPanel.getBackground()); + g.fillRect(0, 0, getSize().width, getSize().height); + super.paint(g); + } + }; + } + }; + splitPane.setUI(ui); + BasicSplitPaneDivider divider = ui.getDivider(); + divider.setCursor(Cursor.getDefaultCursor()); + divider.setLayout(new GridBagLayout()); + divider.setDividerSize((int)(injectRuleButton.getPreferredSize().getWidth())*2); + cRules = new GridBagConstraints(); cRules.fill = GridBagConstraints.BOTH; cRules.gridx = 0; - cRules.gridy = 0; + cRules.gridy = 1; + divider.add(unloadRuleButton, cRules); + cRules = new GridBagConstraints(); + cRules.fill = GridBagConstraints.BOTH; + cRules.gridx = 1; + cRules.gridy = 1; + divider.add(injectRuleButton, cRules); + cRules = new GridBagConstraints(); + cRules.weighty = halfWeight; + cRules = new GridBagConstraints(); + cRules.fill = GridBagConstraints.BOTH; + cRules.gridx = 0; + cRules.gridwidth = 2; + cRules.gridy = 1; cRules.weighty = yWeightRow0 + yWeightRow1; cRules.weightx = xWeightFullWidth; cRules.insets = paddingInsets; - JScrollPane scrollPane = new ThermostatScrollPane(rulesText); - rulesPanel.add(scrollPane, cRules); + rulesPanel.add(splitPane, cRules); + + // Import & Generate Rule Buttons + cRules = new GridBagConstraints(); cRules.fill = GridBagConstraints.BOTH; cRules.gridx = 0; - cRules.gridy = 1; + cRules.gridy = 2; + cRules.gridwidth = 2; cRules.weighty = yWeightRow2; cRules.weightx = xWeightFullWidth; cRules.insets = paddingInsets; @@ -213,11 +323,36 @@ @Override public void actionPerformed(java.awt.event.ActionEvent e) { + generateRuleToggle = true; fireGenerateEvent(GenerateAction.GENERATE_TEMPLATE); } }); buttonHolder.add(generateRuleButton); + JButton importRuleButton = new JButton(t.localize(LocaleResources.IMPORT_RULE).getContents()); + importRuleButton.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent e) { + JFileChooser chooser = new JFileChooser(); + int result = chooser.showOpenDialog(rulesPanel); + if (result == JFileChooser.APPROVE_OPTION) { + File file = chooser.getSelectedFile(); + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + unloadedRulesText.setText(EMPTY_STR); + String line = reader.readLine(); + while(line != null) { + unloadedRulesText.append(line + "\n"); + line = reader.readLine(); + } + } catch (FileNotFoundException fnfe) { + fnfe.printStackTrace(); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + } + } + }); + buttonHolder.add(importRuleButton); buttonHolder.setAlignmentX(Component.RIGHT_ALIGNMENT); rulesPanel.add(buttonHolder, cRules); @@ -488,23 +623,37 @@ @Override public void setInjectState(final BytemanInjectState state) { - final String buttonLabel; - if (!viewControlsEnabled) { - buttonLabel = t.localize(LocaleResources.INJECT_RULE).getContents(); - } else if (state == BytemanInjectState.UNLOADING || state == BytemanInjectState.INJECTED) { - buttonLabel = t.localize(LocaleResources.UNLOAD_RULE).getContents(); - } else { - buttonLabel = t.localize(LocaleResources.INJECT_RULE).getContents(); - } SwingUtilities.invokeLater(new Runnable() { @Override public void run() { + final String buttonLabel; + if (!viewControlsEnabled) { + buttonLabel = t.localize(LocaleResources.INJECT_RULE).getContents(); + } else if (state == BytemanInjectState.UNLOADING || state == BytemanInjectState.INJECTED) { + buttonLabel = t.localize(LocaleResources.UNLOAD_RULE).getContents(); + } else { + buttonLabel = t.localize(LocaleResources.INJECT_RULE).getContents(); + } + if (!viewControlsEnabled) { toggleButton.setToggleActionState(BytemanInjectState.DISABLED); } else { toggleButton.setToggleActionState(state); } toggleButton.setText(buttonLabel); + + if (state == BytemanInjectState.INJECTED) { + injectedRulesText.setText(unloadedRulesText.getText()); + injectRuleButton.setEnabled(false); + unloadRuleButton.setEnabled(true); + } else if (state == BytemanInjectState.UNLOADING) { + if (EMPTY_STR.equals(unloadedRulesText.getText().trim())) { + unloadedRulesText.setText(injectedRulesText.getText()); + } + } else if (state == BytemanInjectState.UNLOADED){ + injectRuleButton.setEnabled(true); + unloadRuleButton.setEnabled(false); + } } }); @@ -546,7 +695,12 @@ SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - rulesText.setText(rule); + if (generateRuleToggle) { + unloadedRulesText.setText(rule); + generateRuleToggle = false; + } else { + injectedRulesText.setText(rule); + } } }); } @@ -573,6 +727,55 @@ }); } + // Package private for testing + String getInjectedRuleContent() throws InvocationTargetException, InterruptedException { + injectedRuleContent = ""; + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + injectedRuleContent = injectedRulesText.getText(); + } + }); + return injectedRuleContent; + } + + // Package private for testing + void setUnloadedRuleContent(final String rule) throws InvocationTargetException, InterruptedException { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + unloadedRulesText.setText(rule); + } + }); + } + + // Package private for testing + String getUnloadedRuleContent() throws InvocationTargetException, InterruptedException { + unloadedRuleContent = ""; + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + unloadedRuleContent = unloadedRulesText.getText(); + } + }); + return unloadedRuleContent; + } + + // Package private for testing + boolean isInjectButtonEnabled() { + return injectRuleButton.isEnabled(); + } + + // Package private for testing + boolean isUnloadButtonEnabled() { + return unloadRuleButton.isEnabled(); + } + + // Package private for testing + void enableGenerateRuleToggle() { + generateRuleToggle = true; + } + private void updateGraphInView(List<BytemanMetric> metrics, String xkey, String ykey, String filter, String value, String graphtype) { final List<BytemanMetric> ms = metrics; final String xk = xkey; @@ -710,7 +913,7 @@ @Override public void run() { - content[0] = rulesText.getText(); + content[0] = unloadedRulesText.getText(); } });
--- a/vm-byteman/client-swing/src/main/java/com/redhat/thermostat/vm/byteman/client/swing/internal/VmBytemanInformationController.java Fri Aug 26 11:48:51 2016 -0400 +++ b/vm-byteman/client-swing/src/main/java/com/redhat/thermostat/vm/byteman/client/swing/internal/VmBytemanInformationController.java Fri Aug 26 14:08:00 2016 -0400 @@ -84,6 +84,7 @@ private static final Logger logger = LoggingUtils.getLogger(VmBytemanInformationController.class); private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); private static final Charset UTF_8_CHARSET = Charset.forName("UTF-8"); + private static final String EMPTY_STR = ""; static final String NO_RULES_LOADED = t.localize(LocaleResources.NO_RULES_LOADED).getContents(); private final VmRef vm; @@ -365,7 +366,7 @@ } private boolean isEmpty(String rule) { - if (rule == null) { + if (EMPTY_STR.equals(rule.trim())) { return true; } return NO_RULES_LOADED.equals(rule);
--- a/vm-byteman/client-swing/src/main/resources/com/redhat/thermostat/vm/byteman/client/swing/internal/strings.properties Fri Aug 26 11:48:51 2016 -0400 +++ b/vm-byteman/client-swing/src/main/resources/com/redhat/thermostat/vm/byteman/client/swing/internal/strings.properties Fri Aug 26 14:08:00 2016 -0400 @@ -10,3 +10,6 @@ RULE_EMPTY = Rule to inject is empty. NO_RULES_LOADED = <no-rules-loaded> NO_METRICS_AVAILABLE = <no-metrics-available> +LABEL_LOCAL_RULE = Local Rule +LABEL_INJECTED_RULE = Injected Rule +IMPORT_RULE = Import Rule from File
--- a/vm-byteman/client-swing/src/test/java/com/redhat/thermostat/vm/byteman/client/swing/internal/SwingVmBytemanViewTest.java Fri Aug 26 11:48:51 2016 -0400 +++ b/vm-byteman/client-swing/src/test/java/com/redhat/thermostat/vm/byteman/client/swing/internal/SwingVmBytemanViewTest.java Fri Aug 26 14:08:00 2016 -0400 @@ -37,6 +37,9 @@ package com.redhat.thermostat.vm.byteman.client.swing.internal; import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.awt.Container; import java.awt.Dimension; @@ -45,13 +48,26 @@ import java.util.Arrays; import java.util.Collections; import java.util.Date; +import java.util.concurrent.CountDownLatch; import javax.swing.JFrame; import javax.swing.JTextArea; import javax.swing.SwingUtilities; import javax.swing.text.JTextComponent; +import com.redhat.thermostat.client.command.RequestQueue; +import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.Clock; +import com.redhat.thermostat.storage.core.AgentId; +import com.redhat.thermostat.storage.core.HostRef; +import com.redhat.thermostat.storage.core.VmId; +import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.storage.dao.VmInfoDAO; +import com.redhat.thermostat.storage.model.AgentInformation; +import com.redhat.thermostat.storage.model.VmInfo; +import com.redhat.thermostat.vm.byteman.client.swing.internal.VmBytemanView.GenerateAction; +import com.redhat.thermostat.vm.byteman.common.VmBytemanDAO; import org.fest.swing.annotation.GUITest; import org.fest.swing.core.NameMatcher; import org.fest.swing.edt.FailOnThreadViolationRepaintManager; @@ -109,7 +125,66 @@ frame = null; view = null; } - + + @GUITest + @Test + public void testShifterInjectAndUnloadButtons() throws InvocationTargetException, InterruptedException { + String content = "RULE foo bar baz"; + String newContent = "RULE new rule"; + String mainClass = "foo-main-class"; + + // Initial set-up + assertEquals(true, view.isInjectButtonEnabled()); + assertEquals(false, view.isUnloadButtonEnabled()); + assertEquals(t.localize(LocaleResources.NO_RULES_LOADED).getContents(), view.getInjectedRuleContent()); + assertEquals(t.localize(LocaleResources.NO_RULES_LOADED).getContents(), view.getUnloadedRuleContent()); + + testInjectRule(content); + testPreservingRuleDuringActionEvent(content, newContent); + testUnloadRule(newContent); + testGenerateRule(mainClass); + } + + private void testInjectRule(String content) throws InvocationTargetException, InterruptedException { + view.setUnloadedRuleContent(content); + assertEquals(content, view.getUnloadedRuleContent()); + setInjectStateInEDT(VmBytemanView.BytemanInjectState.INJECTED); + assertEquals(content, view.getInjectedRuleContent()); + assertEquals(false, view.isInjectButtonEnabled()); + assertEquals(true, view.isUnloadButtonEnabled()); + } + + private void testPreservingRuleDuringActionEvent(String oldContent, String newContent) throws InvocationTargetException, InterruptedException { + view.setUnloadedRuleContent(newContent); + ActionEvent<VmBytemanView.TabbedPaneContentAction> event = new ActionEvent<>(this, VmBytemanView.TabbedPaneContentAction.RULES_CHANGED); + event.setPayload(oldContent); + view.contentChanged(event); + assertEquals(newContent, view.getUnloadedRuleContent()); + assertEquals(oldContent, view.getInjectedRuleContent()); + } + + private void testUnloadRule(String content) throws InvocationTargetException, InterruptedException { + setInjectStateInEDT(VmBytemanView.BytemanInjectState.UNLOADED); + ActionEvent event = new ActionEvent<>(this, VmBytemanView.TabbedPaneContentAction.RULES_CHANGED); + event.setPayload(t.localize(LocaleResources.NO_RULES_LOADED).getContents()); + view.contentChanged(event); + assertEquals(t.localize(LocaleResources.NO_RULES_LOADED).getContents(), view.getInjectedRuleContent()); + assertEquals(content, view.getUnloadedRuleContent()); + assertEquals(true, view.isInjectButtonEnabled()); + assertEquals(false, view.isUnloadButtonEnabled()); + } + + private void testGenerateRule(String mainClass) throws InvocationTargetException, InterruptedException { + VmBytemanInformationController controller = createController(); + String template = controller.generateTemplateForVM(mainClass); + ActionEvent event = new ActionEvent<>(this, VmBytemanView.TabbedPaneContentAction.RULES_CHANGED); + event.setPayload(template); + view.enableGenerateRuleToggle(); + view.contentChanged(event); + assertEquals(template, view.getUnloadedRuleContent()); + } + + @GUITest @Test public void testInjectButton() throws InvocationTargetException, InterruptedException { @@ -140,13 +215,19 @@ }); checkButtonState(VmBytemanView.BytemanInjectState.UNLOADING, toggleButton); assertEquals(t.localize(LocaleResources.UNLOAD_RULE).getContents(), toggleButtonFixture.text()); + assertEquals(view.isInjectButtonEnabled(), false); + assertEquals(view.isUnloadButtonEnabled(), true); setInjectStateInEDT(VmBytemanView.BytemanInjectState.INJECTED); checkButtonState(VmBytemanView.BytemanInjectState.INJECTED, toggleButton); + assertEquals(view.isInjectButtonEnabled(), false); + assertEquals(view.isUnloadButtonEnabled(), true); assertEquals(t.localize(LocaleResources.UNLOAD_RULE).getContents(), toggleButtonFixture.text()); setInjectStateInEDT(VmBytemanView.BytemanInjectState.UNLOADED); checkButtonState(VmBytemanView.BytemanInjectState.UNLOADED, toggleButton); + assertEquals(view.isInjectButtonEnabled(), true); + assertEquals(view.isUnloadButtonEnabled(), false); assertEquals(t.localize(LocaleResources.INJECT_RULE).getContents(), toggleButtonFixture.text()); setInjectStateInEDT(VmBytemanView.BytemanInjectState.DISABLED); @@ -156,29 +237,31 @@ setInjectStateInEDT(VmBytemanView.BytemanInjectState.INJECTING); checkButtonState(VmBytemanView.BytemanInjectState.INJECTING, toggleButton); assertEquals(t.localize(LocaleResources.INJECT_RULE).getContents(), toggleButtonFixture.text()); + assertEquals(view.isInjectButtonEnabled(), true); + assertEquals(view.isUnloadButtonEnabled(), false); } - + @GUITest @Test - public void testGetRuleContent() { + public void testGetRuleContent() throws InvocationTargetException, InterruptedException { String ruleContent = ""; setRuleContentInEDT(ruleContent); - - String actual = view.getRuleContent(); + + String actual = view.getUnloadedRuleContent(); assertEquals(ruleContent, actual); - + ruleContent = "foo\nbar\nbaz"; setRuleContentInEDT(ruleContent); - actual = view.getRuleContent(); + actual = view.getUnloadedRuleContent(); assertEquals(ruleContent, actual); } - + @GUITest @Test public void testContentChangedMetrics() { String content = "{ \"foo\": \"bar\" }"; String marker = "marker"; - long timestamp = 1_440_000_000_000L; + long timestamp = 1_440_000_000_000L; DateFormat metricsDateFormat = SwingVmBytemanView.metricsDateFormat; String timestring = metricsDateFormat.format(new Date(timestamp)); BytemanMetric m = new BytemanMetric(); @@ -186,39 +269,44 @@ m.setMarker(marker); m.setTimeStamp(timestamp); - ActionEvent<VmBytemanView.TabbedPaneContentAction> event = new ActionEvent<>(this, VmBytemanView.TabbedPaneContentAction.METRICS_CHANGED); event.setPayload(Arrays.asList(m)); view.contentChanged(event); verifyMetricsTextEquals(timestring + ": " + marker + " " + content + "\n"); - + // Do the same with an empty metrics list event = new ActionEvent<>(this, VmBytemanView.TabbedPaneContentAction.METRICS_CHANGED); event.setPayload(Collections.emptyList()); view.contentChanged(event); verifyMetricsTextEquals(SwingVmBytemanView.NO_METRICS_AVAILABLE + "\n"); } - + @GUITest @Test - public void testContentChangedRules() { - String content = "RULE foo bar baz"; - + public void testContentChangedRules() throws InvocationTargetException, InterruptedException { + + String content = "RULE foo bar baz"; + + // Unloaded rules shouldn't be overwritten if they already have content in them + String unloadedRule = "RULE baz bar foo"; + view.setUnloadedRuleContent(unloadedRule); + assertEquals(view.getUnloadedRuleContent(), unloadedRule); ActionEvent<VmBytemanView.TabbedPaneContentAction> event = new ActionEvent<>(this, VmBytemanView.TabbedPaneContentAction.RULES_CHANGED); event.setPayload(content); view.contentChanged(event); - verifyRulesTextEquals(content); - + verifyUnloadedRulesTextEquals(unloadedRule); + // Do the same, now setting empty content = ""; + view.setUnloadedRuleContent(content); event = new ActionEvent<>(this, VmBytemanView.TabbedPaneContentAction.RULES_CHANGED); event.setPayload(content); view.contentChanged(event); - verifyRulesTextEquals(content); + verifyUnloadedRulesTextEquals(content); } - private void verifyRulesTextEquals(String expected) { - final JTextComponent text = getJTextAreaWithName(SwingVmBytemanView.RULES_TEXT_NAME); + private void verifyUnloadedRulesTextEquals(String expected) { + final JTextComponent text = getJTextAreaWithName(SwingVmBytemanView.RULES_UNLOADED_TEXT_NAME); verifyEquals(text, expected); } @@ -226,7 +314,7 @@ final JTextComponent text = getJTextAreaWithName(SwingVmBytemanView.METRICS_TEXT_NAME); verifyEquals(text, expected); } - + private void verifyEquals(final JTextComponent text, final String expected) { GuiActionRunner.execute(new GuiTask() { @Override @@ -237,7 +325,7 @@ } private void setRuleContentInEDT(final String ruleContent) { - final JTextComponent text = getJTextAreaWithName(SwingVmBytemanView.RULES_TEXT_NAME); + final JTextComponent text = getJTextAreaWithName(SwingVmBytemanView.RULES_UNLOADED_TEXT_NAME); GuiActionRunner.execute(new GuiTask() { @Override protected void executeInEDT() throws Throwable { @@ -264,9 +352,9 @@ assertEquals(reference.isSelected(), toggleButton.isSelected()); } }); - + } - + private void setInjectStateInEDT(final VmBytemanView.BytemanInjectState state) { GuiActionRunner.execute(new GuiTask() { @Override @@ -289,7 +377,7 @@ frame.pack(); frame.setVisible(true); } - + // For basic, quick and dirty UI testing public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { @@ -299,4 +387,28 @@ }); } + private VmBytemanInformationController createController() { + VmRef ref = mock(VmRef.class); + when(ref.getVmId()).thenReturn("some-vm-id"); + when(ref.getHostRef()).thenReturn(new HostRef("some-agent-id", "some-host-name")); + AgentInfoDAO agentInfoDao = mock(AgentInfoDAO.class); + AgentInformation agentInfo = mock(AgentInformation.class); + when(agentInfo.isAlive()).thenReturn(true); + when(agentInfoDao.getAgentInformation(any(AgentId.class))).thenReturn(agentInfo); + VmInfoDAO vmInfoDao = mock(VmInfoDAO.class); + VmInfo vmInfo = mock(VmInfo.class); + when(vmInfo.isAlive(agentInfo)).thenReturn(VmInfo.AliveStatus.RUNNING); + when(vmInfoDao.getVmInfo(any(VmId.class))).thenReturn(vmInfo); + when(vmInfoDao.getVmInfo(any(VmRef.class))).thenReturn(vmInfo); + VmBytemanDAO vmBytemanDao = mock(VmBytemanDAO.class); + RequestQueue requestQueue = mock(RequestQueue.class); + return new VmBytemanInformationController(view, ref, agentInfoDao, vmInfoDao, vmBytemanDao, requestQueue) { + + @Override + void waitWithTimeOut(CountDownLatch latch) { + // nothing, return immediately for tests + } + }; + } + }