From 53e0544d6d7cd6950c25862eb82ba297ee20fd6d Mon Sep 17 00:00:00 2001
From: David <3dgiordano@gmail.com>
Date: Wed, 23 Jun 2021 07:52:22 -0300
Subject: [PATCH] Release 0.7.4 (#48)
---
SETUP.md | 3 +
TROUBLESHOOTING.md | 58 +++++++
citrix-client-win/pom.xml | 2 +-
.../client/windows/WinCitrixClient.java | 159 +++++++++++++-----
.../windows/WinCitrixClientFactory.java | 7 +
citrix-common/pom.xml | 2 +-
.../citrix/client/AbstractCitrixClient.java | 18 +-
.../jmeter/citrix/client/CitrixClient.java | 2 +
.../client/events/InteractionEvent.java | 23 ++-
citrix-jmeter/pom.xml | 2 +-
.../jmeter/citrix/clause/ClauseHelper.java | 12 +-
.../strategy/check/AbstractScreenChecker.java | 15 ++
.../strategy/check/PollingStrategy.java | 7 +-
.../jmeter/citrix/recorder/Capture.java | 69 ++++----
.../citrix/recorder/CitrixRecorder.java | 7 +
.../citrix/recorder/RecordingHandler.java | 8 +-
.../citrix/sampler/InteractionSampler.java | 26 ++-
.../jmeter/citrix/sampler/SamplerHelper.java | 41 ++++-
.../assertions/TestAssertionHelper.java | 8 +
.../citrix/sampler/SampleHelperTest.java | 10 +-
pom.xml | 2 +-
21 files changed, 381 insertions(+), 100 deletions(-)
diff --git a/SETUP.md b/SETUP.md
index a4ddb62..df56618 100644
--- a/SETUP.md
+++ b/SETUP.md
@@ -24,6 +24,7 @@ Here is the list of configurable properties, **non bold** properties should be
| bzm.citrix.client_factory.client_property.horizontal_resolution | Screen horizontal resolution | |
| bzm.citrix.client_factory.client_property.vertical_resolution | Screen vertical resolution | |
| bzm.citrix.client_factory.client_property.color_depth | Color depth, use Color16 to get 16 colors, Color256 to get 256 color, Color16Bit to get high colors (16bpp), Color24Bit to get true colors (24bpp), Keep it empty to let the client decide | |
+| bzm.citrix.client_factory.client_property.scaling | Allow resolution scaling on client | false |
| bzm.citrix.client_factory.client_property.socket_timeout_ms | JMeterProperty that defines the socket timeout of Receiver in Milliseconds | 5000 (in millis) | |
| bzm.citrix.clause_check_interval | Interval for the timing of clause checks | 1000 (in millis) |
| bzm.citrix.clause_check_timeout | Default time period (in ms) during which a clause must be validated | 3000 (in millis) |
@@ -52,5 +53,7 @@ Here is the list of configurable properties, **non bold** properties should be
| **bzm.citrix.ica_downloading_ignore_backends** | Ignore timers when downloading ICA during recording | true |
| **bzm.citrix.keystroke_delay** | Default delay between keystrokes | 100 |
| **bzm.citrix.keystroke_delay_variation** | Default variation added to delay between keystrokes | 10 |
+| **bzm.citrix.mouse_click_delay** | Default delay between mouse clicks | 1000 |
+| **bzm.citrix.mouse_click_delay_variation** | Default variation added to delay between mouse clicks | 10 |
diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md
index 164ad9d..f264e94 100644
--- a/TROUBLESHOOTING.md
+++ b/TROUBLESHOOTING.md
@@ -294,3 +294,61 @@ Open regedit.exe and set the following key to disable dpi scaling:
Location : HKEY_CURRENT_USER\Software\Citrix\ICA Client\DPI
Name : Enable_DPI
Data : dword:00000000
+
+---
+
+## OutOfMemoryError: Java heap space error
+
+JMeter has a set of default settings that allow the application to run without memory problems in most cases.
+However, under some circumstances, an `OutOfMemoryError` can occur.
+When the error occurs, this indicates that the configuration should be changed to consider the current memory usage.
+
+
+#### Solution
+
+In general, the `OutOfMemoryError` is due to the design of JMeter components and how they store information in the application memory for display.
+
+One of the main memory consumers are the `listeners`.
+
+#### 1. First, let's allocate as much memory as possible for 32-bit Java.
+
+Locate the directory where `jmeter.bat` is located and edit it with a text editor.
+
+Add after the line `@echo` the following line:
+```
+set HEAP=-Xms1024M -Xmx1024M -XX:MaxMetaspaceSize=256M
+```
+This allocates as much memory as possible to JMeter for the future runs.
+
+**Source:** [JMeter Wiki: JMeter keeps getting "Out of Memory" errors. What can I do?](https://cwiki.apache.org/confluence/display/JMETER/JMeterFAQ#JMeterFAQ-JMeterkeepsgetting%22OutofMemory%22errors.WhatcanIdo?)
+
+#### 2. Set a proper limit for the View Result Tree listener.
+
+Locate `user.properties` file and open them with a text editor.
+
+Add the following line to the configuration:
+```
+view.results.tree.max_results = 80
+```
+View Result Tree by default shows the last 500 items on the screen.
+
+This consumes memory and can cause long tests to end up with an `OutOfMemoryError`.
+
+Depending on the type of test you are running, the amount of information that JMeter stores may exceed the available memory.
+
+The recommended setting limits only the last 80 results to remain visible to ensure that all memory is not consumed.
+
+You can try increasing the value until you find the one best suited for the type of test you are running.
+
+**Source:** [JMeter View Results Tree documentation reference](https://jmeter.apache.org/usermanual/component_reference.html#View_Results_Tree)
+
+#### Final notes
+
+With the previous recommendations, in general, most of the problems with memory management in JMeter are solved.
+
+In case they are not enough, there is also a good article available from BlazeMeter that tries to summarize other possible solutions to other possible causes of memory error.
+
+[BlazeMeter: 9 Easy Solutions for a JMeter Load Test “Out of Memory” Failure](https://www.blazemeter.com/blog/9-easy-solutions-jmeter-load-test-%E2%80%9Cout-memory%E2%80%9D-failure)
+
+In case you can't find a solution, don't forget to contact support.
+
diff --git a/citrix-client-win/pom.xml b/citrix-client-win/pom.xml
index 934237c..12eb932 100644
--- a/citrix-client-win/pom.xml
+++ b/citrix-client-win/pom.xml
@@ -7,7 +7,7 @@
com.blazemeter.jmeter
citrix-parent
- 0.7.3
+ 0.7.4
citrix-client-win
diff --git a/citrix-client-win/src/main/java/com/blazemeter/jmeter/citrix/client/windows/WinCitrixClient.java b/citrix-client-win/src/main/java/com/blazemeter/jmeter/citrix/client/windows/WinCitrixClient.java
index bb8216e..2f27f43 100644
--- a/citrix-client-win/src/main/java/com/blazemeter/jmeter/citrix/client/windows/WinCitrixClient.java
+++ b/citrix-client-win/src/main/java/com/blazemeter/jmeter/citrix/client/windows/WinCitrixClient.java
@@ -18,6 +18,7 @@
import com.blazemeter.jmeter.citrix.client.windows.com4j.ClassFactory;
import com.blazemeter.jmeter.citrix.client.windows.com4j.ICAColorDepth;
import com.blazemeter.jmeter.citrix.client.windows.com4j.ICAEvent;
+import com.blazemeter.jmeter.citrix.client.windows.com4j.ICAScalingMode;
import com.blazemeter.jmeter.citrix.client.windows.com4j.ICAWindowType;
import com.blazemeter.jmeter.citrix.client.windows.com4j.IICAClient;
import com.blazemeter.jmeter.citrix.client.windows.com4j.IKeyboard;
@@ -87,6 +88,7 @@ public class WinCitrixClient extends AbstractCitrixClient {
private boolean replayMode;
private boolean visibleWindow;
+ private boolean scalingEnabled = false;
@Override
public void onVisible() {
@@ -104,6 +106,11 @@ public void onVisible() {
icaClient.setWindowPosition(winType, winPosXY, winPosXY, winAreaRelativeToScreenFlag);
}
+ if (!isScalingEnabled()) {
+ icaClient.scalingMode(ICAScalingMode.ScalingModeDisabled);
+ icaClient.scaleDisable();
+ }
+
LOGGER.info(
"Sess: des_dim={}x{}, des_depth={}bpp, dim={}x{}, depth={}bpp, Scr: dim={}x{}, depth={}bpp",
getDesiredHRes(), getDesiredVRes(), getDesiredColorDepth(), icaClient.getSessionWidth(),
@@ -113,7 +120,7 @@ public void onVisible() {
}
protected boolean isAppActive() {
- if (session != null) {
+ if (isSessionSet()) {
IWindow window = session.foregroundWindow();
if (window != null) {
LOGGER.debug("Active Window: c={} id={} w={} h={}", window.caption(), window.windowID(),
@@ -239,10 +246,32 @@ public void setDesiredColorDepth(ICAColorDepth colorDepth) {
this.desiredColorDepth = colorDepth;
}
+ public boolean isScalingEnabled() {
+ return this.scalingEnabled;
+ }
+
+ public void setScalingEnabled(boolean scalingEnabled) {
+ this.scalingEnabled = scalingEnabled;
+ }
+
@Override
public Rectangle getForegroundWindowArea() {
- WindowInfo info = fgKey != null ? windowInfos.get(fgKey) : null;
- return info != null ? new Rectangle(info.getArea()) : null;
+ if (!isSessionSet()) {
+ return null;
+ }
+ IWindow window = session.foregroundWindow();
+ return window != null ? new Rectangle(
+ window.positionX(), window.positionY(), window.width(), window.height()
+ ) : null;
+ }
+
+ @Override
+ public int getForegroundWindowID() {
+ if (!isSessionSet()) {
+ return 0;
+ }
+ IWindow window = session.foregroundWindow();
+ return window != null ? window.windowID() : 0;
}
@Override
@@ -277,7 +306,7 @@ protected void startSession(boolean replayMode, boolean visible) throws CitrixCl
}
}
if (waitUserActiveApp(getActiveAppTimeoutInMs()) || !isAppActive()) {
- if (icaClient.session() != null && icaClient.session().foregroundWindow() == null) {
+ if (!isSessionAvailable()) {
throw new CitrixClientException(ErrorCode.SESSION_ERROR,
"The user session was not in the expected state");
} else {
@@ -311,6 +340,10 @@ protected boolean waitUserActiveApp(long timeout) throws InterruptedException {
return totalWaitActiveApp >= timeout;
}
+ public boolean waitWindowActive() throws InterruptedException {
+ return !(waitUserActiveApp(getActiveAppTimeoutInMs()) || !isAppActive());
+ }
+
@Override
protected void stopSession() {
LOGGER.debug("Logging off ICA client");
@@ -347,7 +380,9 @@ protected void stopSession() {
try {
LOGGER.debug("Disposing ICA client");
- icaClient.dispose();
+ if (icaClient != null) {
+ icaClient.dispose();
+ }
} catch (Exception e) {
LOGGER.error("Unable to dispose icaClient", e);
}
@@ -359,7 +394,7 @@ protected void stopSession() {
private boolean isSessionAvailable() {
// Only when foregroundWindow is null when session unavailable
try {
- return (icaClient.session().foregroundWindow() != null);
+ return (icaClient.session() != null && icaClient.session().foregroundWindow() != null);
} catch (Exception e) {
// Any type of exception is an indication of a session loss.
// Whether the instance does not exist or in its nested methods.
@@ -389,8 +424,7 @@ private IScreenShot createScreenshot(Rectangle selection) throws CitrixClientExc
"Unable to create screenshot when ICA client is not running."
);
}
- ISession session = icaClient.session();
- if (session == null) {
+ if (!isSessionSet()) {
throw new CitrixClientException(ErrorCode.SCREENSHOT_ERROR,
"Unable to create screenshot whereas Citrix session is not available.");
}
@@ -534,6 +568,40 @@ private void switchForeground(Integer key) {
notifyHandlers(createWindowEvent(WindowState.FOREGROUND, info));
}
+ private void notifyKeyEvent(KeyState state, int keyCode,
+ int modifiers) {
+ notifyHandlers(new InteractionEvent(WinCitrixClient.this,
+ WinCitrixClient.this.getForegroundWindowID(),
+ WinCitrixClient.this.getForegroundWindowArea(),
+ state, keyCode, EventHelper.toModifiers(modifiers)));
+
+ }
+
+ private void notifyMouseEvent(MouseAction mouseAction, int x, int y,
+ int buttons,
+ int modifiers) {
+ notifyHandlers(new InteractionEvent(WinCitrixClient.this,
+ WinCitrixClient.this.getForegroundWindowID(),
+ WinCitrixClient.this.getForegroundWindowArea(),
+ mouseAction, x, y, EventHelper.toButtons(buttons),
+ EventHelper.toModifiers(modifiers)
+ ));
+
+ }
+
+ private void notifySessionEvent(EventType eventType) {
+ notifyHandlers(new SessionEvent(WinCitrixClient.this, eventType));
+ }
+
+ private void notifySessionEvent(EventType eventType, int errorCode) {
+ notifyHandlers(new SessionEvent(WinCitrixClient.this, eventType, errorCode));
+ }
+
+ private void notifyWindowEvent(WindowEvent.WindowState state,
+ WindowInfo info) {
+ notifyHandlers(createWindowEvent(state, info));
+ }
+
private void attachEvents() {
// Set events handlers
eventsCookie = icaClient.advise(_IICAClientEvents.class, new ICAClientAdapter(icaClient) {
@@ -587,7 +655,7 @@ public void onConnectFailed() {
LOGGER.error("On Connect Failed!");
logLastError();
- notifyHandlers(new SessionEvent(WinCitrixClient.this, EventType.CONNECT_FAIL));
+ notifySessionEvent(EventType.CONNECT_FAIL);
}
@Override
@@ -596,11 +664,10 @@ public void onConnect() {
LOGGER.debug("On Connect");
- session = icaClient.session();
- if (session == null) {
+ setSession();
+ if (!isSessionSet()) {
LOGGER.debug("ICA session in not available while client connects");
- notifyHandlers(new SessionEvent(WinCitrixClient.this, EventType.ERROR,
- KnownError.UNAVAILABLE_SESSION.getCode()));
+ notifySessionEvent(EventType.ERROR, KnownError.UNAVAILABLE_SESSION.getCode());
} else {
sessionCookie = session.advise(_ISessionEvents.class, new SessionAdapter() {
@@ -673,15 +740,13 @@ public void onWindowForeground(int windowID) {
@Override
public void onKeyDown(int keyId, int modifierState) {
super.onKeyDown(keyId, modifierState);
- notifyHandlers(new InteractionEvent(WinCitrixClient.this, KeyState.KEY_DOWN, keyId,
- EventHelper.toModifiers(modifierState)));
+ notifyKeyEvent(KeyState.KEY_DOWN, keyId, modifierState);
}
@Override
public void onKeyUp(int keyId, int modifierState) {
super.onKeyUp(keyId, modifierState);
- notifyHandlers(new InteractionEvent(WinCitrixClient.this, KeyState.KEY_UP, keyId,
- EventHelper.toModifiers(modifierState)));
+ notifyKeyEvent(KeyState.KEY_UP, keyId, modifierState);
}
});
@@ -689,62 +754,58 @@ public void onKeyUp(int keyId, int modifierState) {
@Override
public void onMouseDown(int buttonState, int modifierState, int xPos, int yPos) {
super.onMouseDown(buttonState, modifierState, xPos, yPos);
- notifyHandlers(
- new InteractionEvent(WinCitrixClient.this, MouseAction.BUTTON_DOWN, xPos,
- yPos, EventHelper.toButtons(buttonState),
- EventHelper.toModifiers(modifierState)));
+ notifyMouseEvent(MouseAction.BUTTON_DOWN, xPos, yPos,
+ buttonState, modifierState);
}
@Override
public void onMouseUp(int buttonState, int modifierState, int xPos, int yPos) {
super.onMouseUp(buttonState, modifierState, xPos, yPos);
- notifyHandlers(
- new InteractionEvent(WinCitrixClient.this, MouseAction.BUTTON_UP, xPos, yPos,
- EventHelper.toButtons(buttonState), EventHelper.toModifiers(modifierState)));
+ notifyMouseEvent(MouseAction.BUTTON_UP, xPos, yPos, buttonState,
+ modifierState);
}
@Override
public void onMove(int buttonState, int modifierState, int xPos, int yPos) {
super.onMove(buttonState, modifierState, xPos, yPos);
- notifyHandlers(
- new InteractionEvent(WinCitrixClient.this, MouseAction.MOVE, xPos, yPos,
- EventHelper.toButtons(buttonState), EventHelper.toModifiers(modifierState)));
+ notifyMouseEvent(MouseAction.MOVE, xPos, yPos, buttonState,
+ modifierState);
}
});
}
- notifyHandlers(new SessionEvent(WinCitrixClient.this, EventType.CONNECT));
+ notifySessionEvent(EventType.CONNECT);
}
@Override
public void onLogonFailed() {
super.onLogonFailed();
- notifyHandlers(new SessionEvent(WinCitrixClient.this, EventType.LOGON_FAIL));
+ notifySessionEvent(EventType.LOGON_FAIL);
}
@Override
public void onLogon() {
super.onLogon();
- notifyHandlers(new SessionEvent(WinCitrixClient.this, EventType.LOGON));
+ notifySessionEvent(EventType.LOGON);
}
@Override
public void onLogoffFailed() {
super.onLogoffFailed();
- notifyHandlers(new SessionEvent(WinCitrixClient.this, EventType.LOGOFF_FAIL));
+ notifySessionEvent(EventType.LOGOFF_FAIL);
}
@Override
public void onWindowDisplayed(int wndType) {
super.onWindowDisplayed(wndType);
- notifyHandlers(new SessionEvent(WinCitrixClient.this, EventType.SHOW));
+ notifySessionEvent(EventType.SHOW);
}
@Override
public void onWindowDestroyed(int wndType) {
super.onWindowDestroyed(wndType);
// Depends on wndType ?
- notifyHandlers(new SessionEvent(WinCitrixClient.this, EventType.HIDE));
+ notifySessionEvent(EventType.HIDE);
}
@Override
@@ -752,9 +813,9 @@ public void onDisconnectFailed() {
super.onDisconnectFailed();
LOGGER.debug("On Disconnect Failed!");
if (isUserLogged()) {
- notifyHandlers(new SessionEvent(WinCitrixClient.this, EventType.LOGOFF_FAIL));
+ notifySessionEvent(EventType.LOGOFF_FAIL);
}
- notifyHandlers(new SessionEvent(WinCitrixClient.this, EventType.DISCONNECT_FAIL));
+ notifySessionEvent(EventType.DISCONNECT_FAIL);
}
@Override
@@ -762,9 +823,9 @@ public void onDisconnect() {
super.onDisconnect();
LOGGER.debug("On Disconnect Interrupted:{}", wasInterrupted());
if (isUserLogged()) {
- notifyHandlers(new SessionEvent(WinCitrixClient.this, EventType.LOGOFF));
+ notifySessionEvent(EventType.LOGOFF);
}
- notifyHandlers(new SessionEvent(WinCitrixClient.this, EventType.DISCONNECT));
+ notifySessionEvent(EventType.DISCONNECT);
}
/* (non-Javadoc)
@@ -773,7 +834,7 @@ public void onDisconnect() {
@Override
public void onICAFile() {
super.onICAFile();
- notifyHandlers(new SessionEvent(WinCitrixClient.this, EventType.ICAFILE));
+ notifySessionEvent(EventType.ICAFILE);
}
/* (non-Javadoc)
@@ -783,11 +844,19 @@ public void onICAFile() {
public void onICAFileFailed() {
super.onICAFileFailed();
LOGGER.error("ICAFileFailed");
- notifyHandlers(new SessionEvent(WinCitrixClient.this, EventType.ICAFILE_FAIL));
+ notifySessionEvent(EventType.ICAFILE_FAIL);
}
});
}
+ private void setSession() {
+ session = icaClient.session();
+ }
+
+ private boolean isSessionSet() {
+ return session != null;
+ }
+
private EventCookie attachWindow(IWindow window) {
return window.advise(_IWindowEvents.class, new WindowAdapter(window.windowID()) {
@@ -801,7 +870,7 @@ public void onMove(int xPos, int yPos) {
area.setLocation(xPos, yPos);
LOGGER.debug("Sets window position={} to window {}", area.getLocation(),
this.getWindowID());
- notifyHandlers(createWindowEvent(WindowState.CHANGE_AREA, winInfo));
+ notifyWindowEvent(WindowState.CHANGE_AREA, winInfo);
} else {
LOGGER.debug("Should not happen : Unable to move the disposed window {}",
this.getWindowID());
@@ -816,7 +885,7 @@ public void onSize(int width, int height) {
final Rectangle area = winInfo.getArea();
area.setSize(width, height);
LOGGER.debug("Sets window dimension={} to window {}", area.getSize(), this.getWindowID());
- notifyHandlers(createWindowEvent(WindowState.CHANGE_AREA, winInfo));
+ notifyWindowEvent(WindowState.CHANGE_AREA, winInfo);
} else {
LOGGER.debug("Should not happen : Unable to resize the disposed window {}",
this.getWindowID());
@@ -833,7 +902,7 @@ public void onDestroy() {
windowCookies.get(this.getWindowID()).close();
windowCookies.remove(this.getWindowID());
LOGGER.debug("Removes window info of window {}", this.getWindowID());
- notifyHandlers(createWindowEvent(WindowState.CLOSED, winInfo));
+ notifyWindowEvent(WindowState.CLOSED, winInfo);
}
@Override
@@ -843,7 +912,7 @@ public void onCaptionChange(String caption) {
if (winInfo != null) {
winInfo.setCaption(caption);
LOGGER.debug("Sets window caption={} to window {}", caption, this.getWindowID());
- notifyHandlers(createWindowEvent(WindowState.CHANGE_CAPTION, winInfo));
+ notifyWindowEvent(WindowState.CHANGE_CAPTION, winInfo);
} else {
LOGGER.debug(
"Should not happen : Unable to change caption of the disposed window {}",
@@ -857,7 +926,7 @@ public void onActivate() {
final WindowInfo winInfo = windowInfos.get(this.getWindowID());
if (winInfo != null) {
LOGGER.debug("Activates window {}", this.getWindowID());
- notifyHandlers(createWindowEvent(WindowState.ACTIVATED, winInfo));
+ notifyWindowEvent(WindowState.ACTIVATED, winInfo);
} else {
LOGGER.debug("Should not happen : Unable to activate the disposed window {}",
this.getWindowID());
@@ -870,7 +939,7 @@ public void onDeactivate() {
final WindowInfo winInfo = windowInfos.get(this.getWindowID());
if (winInfo != null) {
LOGGER.debug("Deactivates window {}", this.getWindowID());
- notifyHandlers(createWindowEvent(WindowState.DEACTIVATED, winInfo));
+ notifyWindowEvent(WindowState.DEACTIVATED, winInfo);
} else {
LOGGER.debug("Should not happen : Unable to deactivate the disposed window {}",
this.getWindowID());
diff --git a/citrix-client-win/src/main/java/com/blazemeter/jmeter/citrix/client/windows/WinCitrixClientFactory.java b/citrix-client-win/src/main/java/com/blazemeter/jmeter/citrix/client/windows/WinCitrixClientFactory.java
index ded83b1..fa4ad9c 100644
--- a/citrix-client-win/src/main/java/com/blazemeter/jmeter/citrix/client/windows/WinCitrixClientFactory.java
+++ b/citrix-client-win/src/main/java/com/blazemeter/jmeter/citrix/client/windows/WinCitrixClientFactory.java
@@ -15,6 +15,7 @@ public class WinCitrixClientFactory extends AbstractCitrixClientFactory {
private static final String HORIZONTAL_RESOLUTION_PROPERTY = "horizontal_resolution";
private static final String VERTICAL_RESOLUTION_PROPERTY = "vertical_resolution";
private static final String COLOR_DEPTH_PROPERTY = "color_depth";
+ private static final String SCALING_PROPERTY = "scaling";
private static final String ICAFILE_TIMEOUT = "icafile_timeout_ms";
private static final String CONNECT_TIMEOUT = "connect_timeout_ms";
@@ -71,6 +72,12 @@ public CitrixClient createClient() {
);
}
+ if (!getClientProperty(SCALING_PROPERTY).isEmpty()) {
+ client.setScalingEnabled(
+ Boolean.parseBoolean(getClientProperty(SCALING_PROPERTY))
+ );
+ }
+
return client;
}
}
diff --git a/citrix-common/pom.xml b/citrix-common/pom.xml
index f7e2055..18d4c77 100644
--- a/citrix-common/pom.xml
+++ b/citrix-common/pom.xml
@@ -7,7 +7,7 @@
com.blazemeter.jmeter
citrix-parent
- 0.7.3
+ 0.7.4
diff --git a/citrix-common/src/main/java/com/blazemeter/jmeter/citrix/client/AbstractCitrixClient.java b/citrix-common/src/main/java/com/blazemeter/jmeter/citrix/client/AbstractCitrixClient.java
index 76f86ed..fbaccd1 100644
--- a/citrix-common/src/main/java/com/blazemeter/jmeter/citrix/client/AbstractCitrixClient.java
+++ b/citrix-common/src/main/java/com/blazemeter/jmeter/citrix/client/AbstractCitrixClient.java
@@ -420,7 +420,7 @@ private Point getAbsolutePosition(Point relativePosition) {
String msg =
"Unable to define absolute coordinates whereas no foreground window area is set.";
LOGGER.error(msg);
- throw new IllegalStateException(msg);
+ return null;
}
final Point position = new Point(area.x + relativePosition.x, area.y + relativePosition.y);
if (LOGGER.isTraceEnabled()) {
@@ -441,6 +441,20 @@ private void sendPositionalQuery(boolean relative, int x, int y, PositionalQuery
if (relative) {
origPosition = new Point(x, y);
position = getAbsolutePosition(origPosition);
+ if (position == null) {
+ // Wait for active window
+ try {
+ if (!waitWindowActive()) {
+ throw new CitrixClientException(CitrixClientException.ErrorCode.ACTIVEAPP_TIMEOUT,
+ "Timed out waiting for Active Window");
+ } else {
+ position = getAbsolutePosition(origPosition);
+ }
+ } catch (InterruptedException e) {
+ throw new CitrixClientException(CitrixClientException.ErrorCode.ACTIVEAPP_TIMEOUT,
+ "Wait for Active Window Interrupted");
+ }
+ }
} else {
origPosition = null;
position = new Point(x, y);
@@ -448,6 +462,8 @@ private void sendPositionalQuery(boolean relative, int x, int y, PositionalQuery
action.accept(position, origPosition);
}
+ protected abstract boolean waitWindowActive() throws InterruptedException;
+
@Override
public final void sendMouseButtonQuery(boolean buttonUp, Set buttons, int x, int y,
Set modifiers, boolean relative)
diff --git a/citrix-common/src/main/java/com/blazemeter/jmeter/citrix/client/CitrixClient.java b/citrix-common/src/main/java/com/blazemeter/jmeter/citrix/client/CitrixClient.java
index 972b972..6391613 100644
--- a/citrix-common/src/main/java/com/blazemeter/jmeter/citrix/client/CitrixClient.java
+++ b/citrix-common/src/main/java/com/blazemeter/jmeter/citrix/client/CitrixClient.java
@@ -199,6 +199,8 @@ void sendMouseMoveQuery(Set buttons, int x, int y, Set mo
void setCheckActiveAppPeriod(int period);
+ int getForegroundWindowID();
+
class Snapshot {
private final Rectangle fgWindowArea;
private final BufferedImage screenshot;
diff --git a/citrix-common/src/main/java/com/blazemeter/jmeter/citrix/client/events/InteractionEvent.java b/citrix-common/src/main/java/com/blazemeter/jmeter/citrix/client/events/InteractionEvent.java
index 7f765a4..88c4503 100644
--- a/citrix-common/src/main/java/com/blazemeter/jmeter/citrix/client/events/InteractionEvent.java
+++ b/citrix-common/src/main/java/com/blazemeter/jmeter/citrix/client/events/InteractionEvent.java
@@ -2,6 +2,7 @@
import com.blazemeter.jmeter.citrix.client.CitrixClient;
import com.blazemeter.jmeter.citrix.client.Win32Utils;
+import java.awt.Rectangle;
import java.util.EnumSet;
import java.util.Set;
@@ -10,7 +11,9 @@
*/
public class InteractionEvent extends ClientEvent {
- private static final long serialVersionUID = 4255880303186322061L;
+ private static final long serialVersionUID = 4255838475686322061L;
+ private final int windowID;
+ private final Rectangle foregroundWindowArea;
private final InteractionType interactionType;
private final Set modifiers;
// Key specific
@@ -30,9 +33,12 @@ public class InteractionEvent extends ClientEvent {
* @param keyCode the code of pressed key
* @param modifiers the set of pressed modifier keys
*/
- public InteractionEvent(CitrixClient source, KeyState state, int keyCode,
+ public InteractionEvent(CitrixClient source, int windowID, Rectangle foregroundWindowArea,
+ KeyState state, int keyCode,
Set modifiers) {
super(source);
+ this.windowID = windowID;
+ this.foregroundWindowArea = foregroundWindowArea;
interactionType = InteractionType.KEY;
this.modifiers = modifiers != null ? EnumSet.copyOf(modifiers) : EnumSet.noneOf(Modifier.class);
@@ -55,10 +61,13 @@ public InteractionEvent(CitrixClient source, KeyState state, int keyCode,
* @param buttons the set of pressed mouse buttons
* @param modifiers the set of pressed modifier keys
*/
- public InteractionEvent(CitrixClient source, MouseAction mouseAction, int x, int y,
+ public InteractionEvent(CitrixClient source, int windowID, Rectangle foregroundWindowArea,
+ MouseAction mouseAction, int x, int y,
Set buttons,
Set modifiers) {
super(source);
+ this.windowID = windowID;
+ this.foregroundWindowArea = foregroundWindowArea;
interactionType = InteractionType.MOUSE;
this.modifiers = modifiers != null ? EnumSet.copyOf(modifiers) : EnumSet.noneOf(Modifier.class);
@@ -158,6 +167,14 @@ public String getModifiersText() {
return EventHelper.getModifiersText(getModifiers());
}
+ public int getWindowID() {
+ return this.windowID;
+ }
+
+ public Rectangle getForegroundWindowArea() {
+ return this.foregroundWindowArea;
+ }
+
/**
* Enumerates the types of user interactions on Citrix session.
*/
diff --git a/citrix-jmeter/pom.xml b/citrix-jmeter/pom.xml
index 5921a4b..e89bd8b 100644
--- a/citrix-jmeter/pom.xml
+++ b/citrix-jmeter/pom.xml
@@ -8,7 +8,7 @@
com.blazemeter.jmeter
citrix-parent
- 0.7.3
+ 0.7.4
citrix-jmeter
diff --git a/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/clause/ClauseHelper.java b/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/clause/ClauseHelper.java
index c2552b0..c7cd35a 100644
--- a/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/clause/ClauseHelper.java
+++ b/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/clause/ClauseHelper.java
@@ -8,6 +8,7 @@
import com.github.kilianB.matcher.Hash;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
+import java.awt.image.RasterFormatException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -84,8 +85,15 @@ public static String hash(final BufferedImage image, final Rectangle area, Polli
if (area != null) {
Rectangle bounds = new Rectangle(image.getWidth(), image.getHeight());
Rectangle intersection = bounds.intersection(area);
- target = image
- .getSubimage(intersection.x, intersection.y, intersection.width, intersection.height);
+ try {
+ target = image
+ .getSubimage(intersection.x, intersection.y, intersection.width, intersection.height);
+ } catch (RasterFormatException e) {
+ LOGGER.debug("Image Width: {} Height: {} Area: {} Intersection: {} ", image.getWidth(),
+ image.getHeight(), area.toString(), intersection.toString());
+ LOGGER.error("Error in SubImage", e);
+ throw e;
+ }
}
boolean useLegacy = (context != null && isHashLegacy(context.getClause().getExpectedValue()));
diff --git a/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/clause/strategy/check/AbstractScreenChecker.java b/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/clause/strategy/check/AbstractScreenChecker.java
index c640572..104921f 100644
--- a/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/clause/strategy/check/AbstractScreenChecker.java
+++ b/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/clause/strategy/check/AbstractScreenChecker.java
@@ -19,6 +19,8 @@ public abstract class AbstractScreenChecker implements ClientChecker, Screenshot
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractScreenChecker.class);
+ private static final int MINIMUM_AREA_PIXELS = 2;
+
private final ScreenshotAssessor screenshotAssessor;
/**
@@ -81,6 +83,19 @@ public final CheckResult check(CitrixClient client, PollingContext context)
@Override
public String assess(BufferedImage image, Rectangle selection, PollingContext context)
throws ClauseComputationException {
+
+ if (image != null && selection != null) {
+ if (selection.x >= image.getWidth() || selection.y >= image.getHeight()) {
+ throw new ClauseComputationException("Selection area outside visible window");
+ }
+ if (selection.height < MINIMUM_AREA_PIXELS) {
+ selection.height = MINIMUM_AREA_PIXELS;
+ }
+ if (selection.width < MINIMUM_AREA_PIXELS) {
+ selection.height = MINIMUM_AREA_PIXELS;
+ }
+ }
+
return screenshotAssessor.assess(image, selection, context);
}
diff --git a/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/clause/strategy/check/PollingStrategy.java b/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/clause/strategy/check/PollingStrategy.java
index a3c7cdb..7d33d5a 100644
--- a/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/clause/strategy/check/PollingStrategy.java
+++ b/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/clause/strategy/check/PollingStrategy.java
@@ -97,14 +97,13 @@ public boolean wait(Clause clause, CitrixClient client, CheckResultCallback onCh
context.setPrevious(result);
+ } catch (CitrixClientException | ClauseComputationException e) {
+ LOGGER.warn("Unable to compute clause value at test #{}: {}", index, e);
+ } finally {
if (!success) {
LOGGER.debug("Sleeping for {}ms before next check", ClauseHelper.CLAUSE_INTERVAL);
TimeUnit.MILLISECONDS.sleep(ClauseHelper.CLAUSE_INTERVAL);
}
-
- } catch (CitrixClientException | ClauseComputationException e) {
- LOGGER.error("Unable to compute clause value at test #{}: {}", index, e);
- break;
}
index++;
}
diff --git a/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/recorder/Capture.java b/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/recorder/Capture.java
index c372fb3..aae72a5 100644
--- a/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/recorder/Capture.java
+++ b/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/recorder/Capture.java
@@ -1,6 +1,5 @@
package com.blazemeter.jmeter.citrix.recorder;
-import com.blazemeter.jmeter.citrix.client.CitrixClient;
import com.blazemeter.jmeter.citrix.client.events.InteractionEvent;
import com.blazemeter.jmeter.citrix.client.events.InteractionEvent.InteractionType;
import com.blazemeter.jmeter.citrix.client.events.InteractionEvent.MouseAction;
@@ -71,7 +70,7 @@ private boolean isMatchingFilter(InteractionEvent event) {
&& (eventType != InteractionType.MOUSE || event.getMouseAction() != MouseAction.MOVE
|| mouseCaptureOptions.contains(MouseCaptureOption.INCLUDE_MOVES));
if (LOGGER.isTraceEnabled()) {
- if (isMatching) {
+ if (!isMatching) {
LOGGER.trace(
"Discarding interaction with " +
"type={} and mouseAction={} while capture type={} and mouseCaptureOptions={}",
@@ -102,38 +101,48 @@ public CaptureItem handleInteractionEvent(InteractionEvent event) throws Capture
item = new CaptureItem(event);
addItem(item);
} else { // InteractionType.MOUSE
- if (mouseCaptureOptions.contains(MouseCaptureOption.RELATIVE_TO_FOREGROUND)) {
- Rectangle foreground = null;
- final CitrixClient client = event.getSource();
- if (client != null) {
- foreground = client.getForegroundWindowArea();
- }
+ if (isRelative()) {
+ Rectangle foreground = event.getForegroundWindowArea();
+ int windowID = event.getWindowID();
if (foreground == null) {
String msg =
- "Unable to get foreground window area from Citrix client " +
- "whereas relative capture is in progress.";
- LOGGER.error(msg);
- throw new IllegalStateException(msg);
- }
+ "No active window detected while in relative mode. Using absolute coordinates.";
+ LOGGER.debug(msg);
- final int x = event.getX();
- final int y = event.getY();
- if (foreground.contains(x, y)) {
- final int relX = x - foreground.x;
- final int relY = y - foreground.y;
- LOGGER.trace(
- "Adapting interaction coordinates" +
- " (X={}, Y={}) to foreground {} results in new coordinates (X={}, Y={})",
- x, y, foreground, relX, relY);
- InteractionEvent mouseEvent =
- new InteractionEvent(event.getSource(), event.getMouseAction(),
- relX, relY, event.getButtons(), event.getModifiers());
- item = new CaptureItem(mouseEvent);
+ // When relative is not possible, send it in absolute and fix it in post-process
+ item = new CaptureItem(event);
addItem(item);
- } else if (LOGGER.isTraceEnabled()) {
- LOGGER.trace(
- "Discarding mouse interaction not contained in foreground {} with X={}, Y={}",
- foreground, x, y);
+
+ } else {
+
+ final int x = event.getX();
+ final int y = event.getY();
+ if (foreground.contains(x, y)) {
+ final int relX = x - foreground.x;
+ final int relY = y - foreground.y;
+ LOGGER.debug(
+ "Adapting interaction coordinates" +
+ " (X={}, Y={}) to foreground {} results in new coordinates (X={}, Y={})",
+ x, y, foreground, relX, relY);
+ InteractionEvent mouseEvent =
+ new InteractionEvent(event.getSource(), windowID, foreground,
+ event.getMouseAction(),
+ relX, relY, event.getButtons(), event.getModifiers());
+ item = new CaptureItem(mouseEvent);
+ addItem(item);
+ } else {
+ LOGGER.debug(
+ "Mouse interaction not contained in foreground, " +
+ "migrating to absolute {} with X={}, Y={}",
+ foreground, x, y);
+
+ InteractionEvent mouseEvent =
+ new InteractionEvent(event.getSource(), 0, null,
+ event.getMouseAction(),
+ event.getX(), event.getY(), event.getButtons(), event.getModifiers());
+ item = new CaptureItem(mouseEvent);
+ addItem(item);
+ }
}
} else {
diff --git a/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/recorder/CitrixRecorder.java b/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/recorder/CitrixRecorder.java
index fc36181..cb21704 100644
--- a/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/recorder/CitrixRecorder.java
+++ b/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/recorder/CitrixRecorder.java
@@ -111,6 +111,7 @@ public class CitrixRecorder extends GenericController implements NonTestElement,
public CitrixRecorder() {
// Initialize recordingHandler
+ LOGGER.debug("Create recordingHandler");
recordingHandler = new RecordingHandler(this,
// time-stamp on log on and relay any session events to handler
e -> {
@@ -302,11 +303,15 @@ public void stopCapture(ClauseType clauseType) {
s -> notifySampleListeners(buildOkEvent(s, s == lastSampler ? shot : null)));
insertSamplersToPlan(samplers);
}
+ } else {
+ LOGGER.debug("Capture without samplers");
}
if (handler != null) {
handler.onCaptureChanged(null);
}
+ } else {
+ LOGGER.debug("No capture for {}", clauseType);
}
}
@@ -640,6 +645,8 @@ private List buildSamplersFromCapture(Capture capture) {
default:
break;
}
+ } else {
+ LOGGER.debug("Capture empty");
}
return samplers;
}
diff --git a/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/recorder/RecordingHandler.java b/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/recorder/RecordingHandler.java
index cc1db2b..c6ef99a 100644
--- a/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/recorder/RecordingHandler.java
+++ b/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/recorder/RecordingHandler.java
@@ -62,12 +62,18 @@ public void handleInteractionEvent(InteractionEvent event) {
CaptureItem item = currentCapture.handleInteractionEvent(event);
if (item != null) {
captureManager.onCaptureItemAdded(item);
- LOGGER.trace("Has captured event {} with label {}", event.getInteractionType(),
+ LOGGER.debug("Has captured event {} with label {}", event.getInteractionType(),
item.getLabel());
}
} catch (CaptureLimitException e) {
LOGGER.debug("Detects maximum capture size {} is reached", e.getSize());
captureManager.onCaptureSizeExceeded();
+ } catch (Exception ex) {
+ LOGGER.error("Exception handling interaction event", ex);
+ }
+ } else {
+ if (isCapturing()) {
+ LOGGER.debug("No capture handler for interaction event");
}
}
}
diff --git a/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/sampler/InteractionSampler.java b/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/sampler/InteractionSampler.java
index acf09a9..48fa50d 100644
--- a/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/sampler/InteractionSampler.java
+++ b/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/sampler/InteractionSampler.java
@@ -32,6 +32,10 @@ public class InteractionSampler extends CitrixBaseSampler {
.getPropDefault(CitrixUtils.PROPERTIES_PFX + "keystroke_delay", 100);
public static final long KEYSTROKE_DELAY_VARIATION = JMeterUtils
.getPropDefault(CitrixUtils.PROPERTIES_PFX + "keystroke_delay_variation", 10);
+ public static final long MOUSE_CLICK_DELAY = JMeterUtils
+ .getPropDefault(CitrixUtils.PROPERTIES_PFX + "mouse_click_delay", 1000);
+ public static final long MOUSE_CLICK_DELAY_VARIATION = JMeterUtils
+ .getPropDefault(CitrixUtils.PROPERTIES_PFX + "mouse_click_delay_variation", 10);
private static final Logger LOGGER = LoggerFactory.getLogger(InteractionSampler.class);
private static final long serialVersionUID = 6076968592699324616L;
private static final RandomDataGenerator VARIATION_GENERATOR = new RandomDataGenerator();
@@ -57,10 +61,15 @@ public InteractionSampler() {
}
// Gets the next duration variation for waiting times between keystrokes
- private static long getNextVariation() {
+ private static long getKeyStrokeNextVariation() {
return VARIATION_GENERATOR.nextLong(-KEYSTROKE_DELAY_VARIATION, KEYSTROKE_DELAY_VARIATION);
}
+ // Gets the next duration variation for waiting times between mouse clicks
+ private static long getMouseClickNextVariation() {
+ return VARIATION_GENERATOR.nextLong(-MOUSE_CLICK_DELAY_VARIATION, MOUSE_CLICK_DELAY_VARIATION);
+ }
+
private boolean isUnVersionedTestElement() {
return getInputTextVersion().isEmpty(); // It is versioned from version 0.7.0
}
@@ -278,6 +287,7 @@ protected void doClientAction(CitrixClient client)
if (isDoubleClick()) {
sampleClick(client);
}
+ delayMouseClick(getSamplerType());
break;
case MOUSE_SEQUENCE:
sampleMouseSequence(client);
@@ -287,6 +297,12 @@ protected void doClientAction(CitrixClient client)
}
}
+ private void delayMouseClick(SamplerType samplerType) throws InterruptedException {
+ long delay = MOUSE_CLICK_DELAY + getMouseClickNextVariation();
+ LOGGER.trace("{} {} waits {}ms before next mouse click", getThreadName(), samplerType, delay);
+ TimeUnit.MILLISECONDS.sleep(delay);
+ }
+
private void sampleClick(CitrixClient client) throws CitrixClientException {
final int x = getMouseX();
final int y = getMouseY();
@@ -312,7 +328,7 @@ private void sendKeystroke(CitrixClient client, int keyCode, boolean keyUp, bool
}
client.sendKeyQuery(keyCode, keyUp);
if (withDelay) {
- long delay = KEYSTROKE_DELAY + getNextVariation();
+ long delay = KEYSTROKE_DELAY + getKeyStrokeNextVariation();
LOGGER.trace("{} waits {}ms before next key stroke", getThreadName(), delay);
TimeUnit.MILLISECONDS.sleep(delay);
}
@@ -413,6 +429,7 @@ private void sampleMouseSequence(CitrixClient client)
mouseSequence.size());
}
for (MouseSequenceItem item : mouseSequence) {
+ boolean buttonUP = item.getAction() == MouseAction.BUTTON_UP;
TimeUnit.MILLISECONDS.sleep(item.getDelay());
final int x = item.getX();
final int y = item.getY();
@@ -427,10 +444,13 @@ private void sampleMouseSequence(CitrixClient client)
LOGGER.trace(
"{} sends mouse buttons change {}: X={}, Y={}, relative={}, buttons={}, modifiers={}",
getThreadName(), item.getAction(), x, y, relative, buttons, modifiers);
- client.sendMouseButtonQuery(item.getAction() == MouseAction.BUTTON_UP, buttons, x, y,
+ client.sendMouseButtonQuery(buttonUP, buttons, x, y,
modifiers,
relative);
}
+ if (buttonUP) {
+ delayMouseClick(getSamplerType());
+ }
}
}
}
diff --git a/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/sampler/SamplerHelper.java b/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/sampler/SamplerHelper.java
index d65dac9..be1b7a5 100644
--- a/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/sampler/SamplerHelper.java
+++ b/citrix-jmeter/src/main/java/com/blazemeter/jmeter/citrix/sampler/SamplerHelper.java
@@ -7,6 +7,7 @@
import com.blazemeter.jmeter.citrix.recorder.CaptureItem;
import com.blazemeter.jmeter.citrix.sampler.gui.InteractionSamplerGUI;
import com.blazemeter.jmeter.citrix.utils.CitrixUtils;
+import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.text.MessageFormat;
import java.util.ArrayList;
@@ -122,8 +123,9 @@ public static List buildKeySamplers(
LOGGER.debug(
"Initializing sampler from last capture " +
- "(keyState={}, keyCode={}) of group {} wich contains {} captures.",
- lastItem.getEvent().getKeyState(), lastItem.getEvent().getKeyCode(), group.type,
+ "(winID={}, keyState={}, keyCode={}) of group {} wich contains {} captures.",
+ lastItem.getEvent().getWindowID(), lastItem.getEvent().getKeyState(),
+ lastItem.getEvent().getKeyCode(), group.type,
group.items.size());
// Initialize sampler depending on group type
@@ -220,8 +222,30 @@ private static List groupMouseCaptures(Iterable
MouseCaptureGroup currentGroup = new MouseCaptureGroup(MouseSamplerType.SEQUENCE);
CaptureItem lastBtnDown = null;
MouseCaptureGroup lastMouseClick = null;
+ int lastWindowID = 0;
+ InteractionEvent lastEvent = null;
for (CaptureItem capture : items) {
final InteractionEvent event = capture.getEvent();
+
+ LOGGER.debug("Captured: WindowID {}, Action {}", event.getWindowID(), event.getMouseAction());
+ if (lastEvent != null) {
+ // Group events based on windows area detected
+ Rectangle lastForeground = lastEvent.getForegroundWindowArea();
+ Rectangle currentForeground = event.getForegroundWindowArea();
+ if (!Objects.equals(lastForeground, currentForeground)) {
+ LOGGER.debug("Captured: Focus Windows Area change, create separate group, {}, {}",
+ lastEvent.getForegroundWindowArea(),
+ event.getForegroundWindowArea()
+ );
+ if (!currentGroup.captures.isEmpty()) {
+ LOGGER.debug("Save the current group");
+ groups.add(currentGroup);
+ }
+ LOGGER.debug("Create new group");
+ currentGroup = new MouseCaptureGroup(MouseSamplerType.SEQUENCE);
+ lastBtnDown = null;
+ }
+ }
switch (event.getMouseAction()) {
case BUTTON_DOWN:
lastBtnDown = capture;
@@ -260,6 +284,7 @@ private static List groupMouseCaptures(Iterable
default:
break;
}
+ lastEvent = event;
}
if (!currentGroup.captures.isEmpty()) {
groups.add(currentGroup);
@@ -293,8 +318,16 @@ public static List buildMouseSamplers(
LOGGER.debug(
"Initializing sampler from last capture" +
- " (mouseAction={}) of group {} wich contains {} captures.",
- lastItem.getEvent().getMouseAction(), group.type, group.captures.size());
+ " (windowID={}, relative={}, fq={}, mouseAction={}) of group {} " +
+ "which contains {} captures.",
+ lastItem.getEvent().getWindowID(), capture.isRelative(),
+ lastItem.getEvent().getForegroundWindowArea() != null,
+ lastItem.getEvent().getMouseAction(),
+ group.type, group.captures.size());
+
+ if (capture.isRelative()) {
+ sampler.setRelative(lastItem.getEvent().getForegroundWindowArea() != null);
+ }
// Initialize sampler depending on group type
switch (group.type) {
diff --git a/citrix-jmeter/src/test/java/com/blazemeter/jmeter/citrix/assertions/TestAssertionHelper.java b/citrix-jmeter/src/test/java/com/blazemeter/jmeter/citrix/assertions/TestAssertionHelper.java
index 16db29a..ce66aa9 100644
--- a/citrix-jmeter/src/test/java/com/blazemeter/jmeter/citrix/assertions/TestAssertionHelper.java
+++ b/citrix-jmeter/src/test/java/com/blazemeter/jmeter/citrix/assertions/TestAssertionHelper.java
@@ -59,6 +59,14 @@ public void init() {
}
+ @Test
+ public void shouldAllowHashWhenAreaIsOutsideVisibleArea() throws ClauseComputationException {
+ // The same image generate the same hash any time
+ Rectangle area = new Rectangle(new Point(400, 300), new Dimension(300, 300));
+
+ String hash1 = ClauseHelper.hash(image_same_01, area, null);
+ }
+
@Test
public void testHashRepeatability() throws ClauseComputationException {
// The same image generate the same hash any time
diff --git a/citrix-jmeter/src/test/java/com/blazemeter/jmeter/citrix/sampler/SampleHelperTest.java b/citrix-jmeter/src/test/java/com/blazemeter/jmeter/citrix/sampler/SampleHelperTest.java
index 5d7fc3c..9d924ba 100644
--- a/citrix-jmeter/src/test/java/com/blazemeter/jmeter/citrix/sampler/SampleHelperTest.java
+++ b/citrix-jmeter/src/test/java/com/blazemeter/jmeter/citrix/sampler/SampleHelperTest.java
@@ -21,15 +21,19 @@ private static class CustomKeyCaptureGroup extends SamplerHelper.KeyCaptureGroup
super(type);
}
- protected void addCaptureKeyEvent(
+ protected void addCaptureKeyEvent(
CitrixClient client, int keyCode, int modifier) {
this.items.add(new CaptureItem(
- new InteractionEvent(client, KeyState.KEY_DOWN, keyCode,
+ new InteractionEvent(client, client.getForegroundWindowID(),
+ client.getForegroundWindowArea(),
+ KeyState.KEY_DOWN, keyCode,
EventHelper.toModifiers(modifier)
)
));
this.items.add(new CaptureItem(
- new InteractionEvent(client, KeyState.KEY_UP, keyCode,
+ new InteractionEvent(client, client.getForegroundWindowID(),
+ client.getForegroundWindowArea(),
+ KeyState.KEY_UP, keyCode,
EventHelper.toModifiers(0) // Always KeyUp lost the modifier state
)
));
diff --git a/pom.xml b/pom.xml
index 140f90b..71196e6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.blazemeter.jmeter
citrix-parent
- 0.7.3
+ 0.7.4
pom
Citrix Plugin for Apache JMeter