Skip to content

Commit

Permalink
Release 0.7.0 (#37)
Browse files Browse the repository at this point in the history
* Release 0.7.0
  • Loading branch information
3dgiordano authored Dec 1, 2020
1 parent 9f0e03a commit def655b
Show file tree
Hide file tree
Showing 25 changed files with 466 additions and 77 deletions.
5 changes: 3 additions & 2 deletions MANUAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ You need then to update in **UDV**:

After that, update authentication information in **UDV-Recording** section:

- citrix_login to the login on portal
- citrix_password to the password on portal
- citrix_login to user login used in Citrix Portal
- citrix_password to the user's login password
- citrix_domain to the domain used for the login process

**Note:** Since JMeter 5.1, the new parameterized template will make this step optional as those 4 fields will be required
on template creation.
Expand Down
24 changes: 0 additions & 24 deletions PRE_REQUISITES.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,19 +135,6 @@ If running JMeter on virtual machines, check that you're dedicating memory and p

*Ensure that you are working with supported versions of your Citrix server.*

#### Disable the desktop toolbar

The Citrix administrator should disable the desktop toolbar.
There are several ways to do this:

- Add to the default.ica file:

ConnectionBar=0

- Follow the method described in:

-https://support.citrix.com/article/CTX138928. (Relevant only for published desktops, not published applications).

#### Session Disconnect

By default, when a client times out or disconnects from the Citrix server, the session remains open for a defined time period.
Expand All @@ -158,17 +145,6 @@ Therefore, the Citrix server administrator should configure the Citrix server to

If you are going to run more than one Citrix Session on JMeter, ensure that the Citrix server is configured to enable multiple sessions per user/client.

#### Run Citrix application in **non-seamless** mode, use **Windowed Mode** instead

See:

- https://docs.citrix.com/en-us/storefront/current-release/user-access/windowed-mode.html

To check this is in place, when you launch the Citrix application manually, the Citrix Window should appear explicitely.
You can also check that the ica file contains:

TWIMode=off

#### Avoid production environments if possible
Try to load test Citrix applications which are restricted to a few Citrix servers in a Citrix development or test environment rather than load testing in a live Citrix production environment.

Expand Down
2 changes: 1 addition & 1 deletion citrix-client-win/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>com.blazemeter.jmeter</groupId>
<artifactId>citrix-parent</artifactId>
<version>0.6.0</version>
<version>0.7.0</version>
</parent>
<artifactId>citrix-client-win</artifactId>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ protected void stopSession() {
}

if (waitUserLogoff(getLogoffTimeoutInMs())) {
LOGGER.error("Timed out waiting for Logoff");
LOGGER.warn("Timed out waiting for Logoff");
sessionCookie = null;
}
}
Expand All @@ -334,7 +334,7 @@ protected void stopSession() {
LOGGER.debug("Disconnecting ICA client");
icaClient.disconnect();
if (waitDisconnect(getDisconnectTimeoutInMs())) {
LOGGER.error("Timed out waiting for Disconnect");
LOGGER.warn("Timed out waiting for Disconnect");
}
}
} catch (Exception e) {
Expand Down
21 changes: 20 additions & 1 deletion citrix-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,26 @@
<parent>
<groupId>com.blazemeter.jmeter</groupId>
<artifactId>citrix-parent</artifactId>
<version>0.6.0</version>
<version>0.7.0</version>
</parent>
<dependencies>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.6.0</version>
</dependency>

<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>5.6.0</version>
</dependency>

<dependency>
<groupId>org.ini4j</groupId>
<artifactId>ini4j</artifactId>
<version>0.5.4</version>
</dependency>
</dependencies>
<artifactId>citrix-common</artifactId>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.ini4j.Profile;
import org.ini4j.Wini;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -122,9 +126,34 @@ public final Path getICAFilePath() {
return icaFilePath;
}

private Path patchICAFile(Path icaFilePath) {
// The idea of this method is to make the necessary changes
// to the ICA file that allow a correct execution.
try {
Wini ini = new Wini(icaFilePath.toFile());
boolean icaModified = false;
for (Map.Entry<String, Profile.Section> section : ini.entrySet()) {
for (Map.Entry<String, String> keyEntry : section.getValue().entrySet()) {

if ("connectionbar".equals(keyEntry.getKey().toLowerCase())
&& "1".equals(keyEntry.getValue())) {
keyEntry.setValue("0");
icaModified = true;
}
}
}
if (icaModified) {
ini.store();
}
} catch (IOException e) {
LOGGER.warn("ICA file processing error", e);
}
return icaFilePath;
}

@Override
public final void setICAFilePath(Path icaFilePath) {
this.icaFilePath = icaFilePath;
this.icaFilePath = patchICAFile(icaFilePath);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.blazemeter.jmeter.citrix.client;

import static com.sun.jna.platform.win32.WinUser.MAPVK_VK_TO_VSC;

import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import java.awt.event.KeyEvent;

public class Win32Utils {

public static int getVirtualKey(int keyCode) {
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-vkkeyscanexw
WinDef.HKL keyLayoutID = User32.INSTANCE.GetKeyboardLayout(0);
return User32.INSTANCE.VkKeyScanExW((char) keyCode, keyLayoutID);
}

public static char getVKCharacter(int vkCode, boolean vkShift, boolean vkAlt, boolean vkCtrl) {

//https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getkeyboardlayout
int currentThread = 0;
WinDef.HKL keyLayoutID = User32.INSTANCE.GetKeyboardLayout(currentThread);

// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mapvirtualkeyexa
int scanCode = User32.INSTANCE.MapVirtualKeyEx(vkCode, MAPVK_VK_TO_VSC, keyLayoutID);

// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-tounicodeex
byte[] keyStates = new byte[256];
byte keyDownState = (byte) 128;
keyStates[KeyEvent.VK_SHIFT] = vkShift ? keyDownState : 0;
keyStates[KeyEvent.VK_ALT] = vkAlt ? keyDownState : 0;
keyStates[KeyEvent.VK_CONTROL] = vkCtrl ? keyDownState : 0;

char[] buff = new char[1];
int buffCharSize = 1;
int menuActiveFlag = 0;
int ret = User32.INSTANCE.ToUnicodeEx(
vkCode, scanCode, keyStates, buff, buffCharSize, menuActiveFlag, keyLayoutID
);

switch (ret) {
case -1: //Error
return (char) -1;

case 0: //No Translation
return (char) 0;

default: //Returning key...
return buff[0];
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.EnumSet;
import java.util.Set;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -60,6 +61,12 @@ public static Set<Modifier> toModifiers(final int value) {
return result;
}

public static String getModifiersText(final Set<Modifier> modifiers) {
return modifiers.stream()
.map(Modifier::name)
.collect(Collectors.joining("+"));
}

public static int fromModifiers(Set<Modifier> modifiers) {
int flags = 0;
if (modifiers != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.blazemeter.jmeter.citrix.client.events;

import com.blazemeter.jmeter.citrix.client.CitrixClient;
import com.blazemeter.jmeter.citrix.client.Win32Utils;
import java.util.EnumSet;
import java.util.Set;

Expand Down Expand Up @@ -88,6 +89,17 @@ public int getKeyCode() {
return keyCode;
}

public int getTargetKeyCode() {
boolean withShift = modifiers.contains(Modifier.SHIFT);
boolean withAlt = modifiers.contains(Modifier.ALT);
boolean withCtrl = modifiers.contains(Modifier.CONTROL);
return Win32Utils.getVKCharacter(keyCode, withShift, withAlt, withCtrl);
}

public String getTargetKeyCodeString() {
return String.valueOf((char) getTargetKeyCode());
}

/**
* Gets the set of key modifiers pressed during this event.
*
Expand Down Expand Up @@ -142,6 +154,10 @@ public Set<MouseButton> getButtons() {
return buttons;
}

public String getModifiersText() {
return EventHelper.getModifiersText(getModifiers());
}

/**
* Enumerates the types of user interactions on Citrix session.
*/
Expand Down
6 changes: 5 additions & 1 deletion citrix-jmeter/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<parent>
<groupId>com.blazemeter.jmeter</groupId>
<artifactId>citrix-parent</artifactId>
<version>0.6.0</version>
<version>0.7.0</version>
</parent>

<artifactId>citrix-jmeter</artifactId>
Expand Down Expand Up @@ -191,6 +191,10 @@
<include>org.apache.pdfbox:pdfbox-tools</include>
<include>org.apache.pdfbox:pdfbox</include>
<include>org.apache.pdfbox:fontbox</include>
<include>com.sun.jna.platform</include>
<include>net.java.dev.jna:jna</include>
<include>net.java.dev.jna:jna-platform</include>
<include>org.ini4j:ini4j</include>
</includes>
</artifactSet>
</configuration>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.Serializable;
import org.apache.jmeter.engine.util.CompoundVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -101,6 +102,10 @@ public final String getExpectedValue() {
return expectedValue;
}

public final String getExpectedValueParametrized() {
return (new CompoundVariable(getExpectedValue())).execute();
}

/**
* Indicates whether the {@link #getSelection() selection} is relative to the
* foreground window.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ public static Rectangle getAbsoluteSelection(Rectangle selection, boolean relati
}

private static Predicate<String> getRegexPredicate(Clause clause) {
Pattern pattern = JMeterUtils.getPatternCache().getPattern(clause.getExpectedValue(),
Pattern pattern = JMeterUtils.getPatternCache().getPattern(
clause.getExpectedValueParametrized(),
Perl5Compiler.READ_ONLY_MASK);
return v -> JMeterUtils.getMatcher().matches(v, pattern);
}
Expand All @@ -183,7 +184,7 @@ public static boolean isHashLegacy(String hash) {
}

private static Predicate<String> getHashHammingDistancePredicate(Clause clause) {
String expectedValue = clause.getExpectedValue();
String expectedValue = clause.getExpectedValueParametrized();
int hashBitResolution = (isHashLegacy(expectedValue) ? LEGACY_BIT_RESOLUTION : BIT_RESOLUTION);
return v -> (
new Hash(
Expand All @@ -195,7 +196,7 @@ private static Predicate<String> getHashHammingDistancePredicate(Clause clause)
}

private static Predicate<String> getEqualPredicate(Clause clause) {
return v -> Objects.equals(v, clause.getExpectedValue());
return v -> Objects.equals(v, clause.getExpectedValueParametrized());
}

public static boolean isHashClause(Clause clause) {
Expand All @@ -217,7 +218,7 @@ public static boolean isHashClause(Clause clause) {
*/
public static Predicate<String> buildValuePredicate(Clause clause) {
LOGGER.debug("Builds predicate for clause {} with expected value='{}'", clause.getCheckType(),
clause.getExpectedValue());
clause.getExpectedValueParametrized());
if (clause.isUsingRegex()) {
return getRegexPredicate(clause);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ private void initialize() {
pnlExpectedValue.add(chbUseRegex, gbcRelative);

taExpectedValue = JSyntaxTextArea.getInstance(5, 80);
taExpectedValue.setLanguage("text");
taExpectedValue.addFocusListener(new ChangeHandler());
GridBagConstraints gbcExpectedValue = new GridBagConstraints();
gbcExpectedValue.anchor = GridBagConstraints.LINE_START;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,19 @@ public String execute(CheckResult result, CheckResult previous, Clause clause, i
if (result.isSuccessful()) {
if (clause.isUsingRegex()) {
value = "'" + result.getValue() + "' matches the expecting regular expression '"
+ clause.getExpectedValue() + "'";
+ clause.getExpectedValueParametrized() + "'";
} else {
value = "'" + result.getValue() + "' is equals to the expecting value '" +
clause.getExpectedValue()
clause.getExpectedValueParametrized()
+ "'";
}
} else {
if (clause.isUsingRegex()) {
value = "'" + result.getValue() + "' does not match the expecting regular expression '"
+ clause.getExpectedValue() + "'";
+ clause.getExpectedValueParametrized() + "'";
} else {
value = "'" + result.getValue() + "' differs from the expecting value '" +
clause.getExpectedValue()
clause.getExpectedValueParametrized()
+ "'";
}
}
Expand Down
Loading

0 comments on commit def655b

Please sign in to comment.