Skip to content

Commit

Permalink
Vt420 protocol support
Browse files Browse the repository at this point in the history
  • Loading branch information
Baraujo25 committed May 19, 2020
1 parent 4572601 commit 1922bb1
Show file tree
Hide file tree
Showing 92 changed files with 3,961 additions and 806 deletions.
88 changes: 78 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

This project implements a JMeter plugin to **support RTE (Remote Terminal Emulation) protocols** by providing a recorder for automatic test plan creation, and config and sampler for protocol interactions.

Nowadays the plugin supports **IBM protocol's TN5250, TN3270 and VT420** by using embedded [xtn5250](https://sourceforge.net/projects/xtn5250/), [dm3270](http://dmolony.github.io/) and [jvt220](https://github.com/jawi/jVT220) emulators with modifications [xtn5250 fork](https://github.com/abstracta/xtn5250), [dm3270 fork](https://github.com/abstracta/dm3270) and [jvt220 fork](https://github.com/Blazemeter/jVT220) to better accommodate to the plugin usage (exception handling, logging, external dependencies, etc).
Nowadays the plugin supports **IBM protocol's TN5250, TN3270 and VT420** by using embedded [xtn5250](https://sourceforge.net/projects/xtn5250/), [dm3270](http://dmolony.github.io/) and [jvt220](https://github.com/jawi/jVT220) emulators, with some modifications on [xtn5250 fork](https://github.com/abstracta/xtn5250), [dm3270 fork](https://github.com/abstracta/dm3270) and [jvt220 fork](https://github.com/Blazemeter/jVT220) to better accommodate to the plugin usage (exception handling, logging, external dependencies, etc).

People who usually work with these IBM servers interact with them, basically, by sending keystrokes from the terminal keyboard (or emulator) to fill forms or call processes. The plugin provides a [recording controller](#a-recording-controller-rte-recorder), which allows the user to interact through a terminal emulator, recording every interaction (samplers) with the mainframe application. Additionally, the plugin allows for manual test plan creation, providing a config element for setting connection parameters and a sampler to set fields on screen and attention key to send to the mainframe application. Besides, the sampler allows to simulate the existing attention keys on the terminal keyboard like ENTER, F1, F2, F3..., ATTN, CLEAR, etc.

Expand Down Expand Up @@ -83,12 +83,28 @@ The RTE Sampler fields are:
- *Disconnect*. This option allows to explicitly close the connection to the terminal server. This allows to restart the emulator status by re connecting to the server en following samplers.
> As previously stated, connections are (by default) automatically closed at the end of each thread iteration, so is not required to add a sampler with disconnect action at the end of each thread loop iteration.
- *RTE Message*. When "Send keys" action is selected it is possible to specify fields to send and attention key to use:
- *Payload*. Contains a grid where the user can add different types of input.
- Input by Tabulator: It will make as many tabulations as specified to the mainframe, before
sending the _"value"_. It is useful to avoid using coordinates.
- Input by Label: It precedes from a terminal screen label. It will send to the mainframe application the already set value to a field which matches the selected label.
- Input by Coordinates (row and column): It will send the text introduced in _"value"_ to the mainframe application at that position.
> For more information about inputs and how they work in a normal flow, check this [examples](docs/recorder/terminal-emulator/terminal-emulator.md#Input By Label Usage).
- *Payload*. Contains a grid in which user can specify different types of inputs:
- **Input by Coordinates:** (row and column) of a field in the screen. Rows and columns starting from [1,1] (are 1 indexed).
- **Input by Label:** It could be a word or a text preceded by a field on the terminal screen.
- **Input by Navigation:** As the name describes, this input is going to navigate before placing the input value (String). There are five types of navigation; the four arrow navigation keys, and the tabulator key. Also you can specify how many times to send the navigation key before the input value.
> Regardless from the input type, all of them will send a value (String) to the mainframe application.
- **Copy from Clipboard:** In order to make the input creation quicker, a string convention as been added. Remember to always make a tabulation between prefixes or inputs.
```text
<TAB> input
<UP*4> input
<DOWN> input
<RIGHT*2> input
<LEFT><LEFT> input
1 2 input
UserID input
```
- ***\<TAB>:*** It will create an input by navigation with just one tabulator key before sending the input value.
- ***\<UP\*4>:*** It will create an up arrow navigation input, sending four times the up arrow before sending the input value.
- ***\<LEFT>\<LEFT>:*** It will create a left arrow navigation with a double repetition of the left key before sending the input value. Which is equivalent to *<LEFT\*2>*.
- ***1 2*** It will create a coordinate input with row 1 and column 2 with an input value equals to 'input' as we see in above representation.
- ***UserID*** This format will create a label input, with the label 'UserID' and the input value equals to 'input'.

- *Attention Keys*. These buttons trigger the attention keys to be sent to the server on each sample. They all represent a key from a terminal's keyboard.
- *Wait for*. When using "Connect" or "Send keys" action it is possible to wait for a specific condition. If this condition is not reached after a specific time (defined in *Timeout* value), the sampler returns timeout error. There are four defined waiters:
- *Sync*. Waits for the system to return from X SYSTEM or Input Inhibited mode. Default value is checked, as it's recommended to always check that the system is not in Input Inhibited Mode after a sample (and before the next one) in order to get the correct screen in the sample result (and to ensure that the next sampler is executed from the desired screen). On the other hand, the sampler does an implicit "Wait for sync" each time it connects to a server, which means that if *Connect* mode is used, then it's not needed to check the *Wait for sync* function, unless you want to change the default timeout.
Expand All @@ -100,10 +116,18 @@ The RTE Sampler fields are:
All the "waiters" use a stable timeout value (in milliseconds) which specifies the time to wait for the emulator to remain at the desired state. The default value is 1000 milliseconds, but can be changed by adding the property `RTEConnectionConfig.stableTimeoutMillis=<time_in_millis>` in *jmeter.properties* file. The "Wait for silent" waiter is not affected by this setting since it has an explicit field for such purpose.
> Warning: both Stable Timeout and Silent Interval should be shorter than Timeout value, otherwise the sampler will always return a timeout error.
#### RTE-Extractor
![alt_text](docs/extractor/rte-extractor.png)
##### Character timeout
With the addition of the VT420 protocol, now we also support its "character at time" behavior, which means that, every time we type a key, we have to wait for a response of the server to send the next one.
Therefore a character timeout comes to play. This period of time is the maximum amount in milliseconds to wait for a server response when sending a character.

RTE-Extractor is a post-processor which its main purpose is to extract positions from response headers to be used later as a JMeter variable.
> Notice: If the time elapses, the user will experiment with a TimeoutException.
The default value of this timeout is 60000 milliseconds, but can be changed by adding the property `RTEConnectionConfig.characterTimeoutMillis=<time_in_millis>` in *jmeter.properties* file.

#### RTE-Position Extractor
![alt_text](docs/extractor/rte-position-extractor.png)

RTE-Position Extractor is a post-processor which its main purpose is to extract positions from response headers to be used later as a JMeter variable.
> Check [here](/docs/extractor/rte-extractor.md) for more information.

Expand Down Expand Up @@ -139,6 +163,50 @@ As explained previously, the RTE Sampler has 4 types of waiters which work as sy
- *Wait for Silent*: The client is considered to be silent when the terminal does not receive any characters from the server so, by setting the proper silent interval, the user could ensure that the server has sent all the information available to the client before continue the execution.
- *Wait for Text*: This waiter could be useful to check for a specific message before continue the execution. For example, it could be used to wait for a message with the confirmation that a specific process ended correctly or to check if a search returned any result before continue.

## Tips

#### How to extract a label from the screen.
The RTE plugin does not have a functionality for itself to achieve this goal. Therefore, Regular Expression Extractor will be our solution.

Example of usage:

![alter_text](docs/extractor/regex-extractor-date-screen.png)

We have obtained the screen above from a sampler response. Suppose we want to extract the date which appears close to the right top corner "**123456**".

In order to capture the date value we have to add a Regular Expression Extractor embedded in **bzm-RTE-SEND_INPUT-1** sampler.

A proper configuration in that case would be something like this:
![alter_text](docs/extractor/regex-extractor-label-config.png)
> If you want to understand how Regular Expression Extractor works, visit [this](https://guide.blazemeter.com/hc/en-us/articles/207421325-Using-RegEx-Regular-Expression-Extractor-with-JMeter-Using-RegEx-(Regular-Expression-Extractor)-with-JMeter) JMeter page.

#### How to extract a value on the screen from a given position.

In order to get a value, we have to know the beginning of the value in coordinates and the length of the text to match.

![alter_text](docs/extractor/regex-extractor-date-screen.png)

For instance, suppose that we need to extract the date using positions. We already know the size of the screen, which is 24x80 (in this case).

Using the emulator we have identify the beginning coordinates of the date value *(1,67)*. Also we know that the length of the text would be six characters.

With all this information we have develop a regex to match that criteria:

***^(.+\n){0}.{67}((.){6})(.\*\n){23}(.\*)$***

- **(.+\n){0}**: The _0_ parameter is the row of the beginning coordinates (1) minus one.
- **.{67}**: The _67_ parameter is the column of the beginning coordinates.
- **((.){6})**: The _6_ parameter is the length of the text we want to match. Also this group is the important one, match group Nº2, which is the Template value in Regular Expression Extractor.
- **(.\*\n){23}(.\*)**: The _23_ parameter is the height of the screen (24) minus our position row (1).

Once we got the regex, our Regular Expression Extractor would be like this:

![alter_text](docs/extractor/regex-extractor-position-config.png)
> If you want to understand how Regular Expression Extractor works, visit [this](https://guide.blazemeter.com/hc/en-us/articles/207421325-Using-RegEx-Regular-Expression-Extractor-with-JMeter-Using-RegEx-(Regular-Expression-Extractor)-with-JMeter) JMeter page.



## Compatibility

Expand Down
Binary file removed docs/extractor/extractor-component.gif
Binary file not shown.
Binary file added docs/extractor/position-extractor-component.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/extractor/position-extractor-usage.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/extractor/regex-extractor-date-screen.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/extractor/regex-extractor-label-config.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 6 additions & 5 deletions docs/extractor/rte-extractor.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# RTE-Extractor
![alt_text](rte-extractor.png)
# RTE-Position-Extractor
![alt_text](rte-position-extractor.png)
**REMEMBER**: This Extractor will ease the development of future implementations. Therefore is not mandatory for script creation. However it can be used in particular cases.

The RTE Extractor is a component that must be embedded into a sampler.


<h5>How to add a RTE-Extractor:</h5>
![alt_text](extractor-component.gif)
<h5>How to add a RTE-Position Extractor:</h5>

![alt_text](position-extractor-component.gif)


The aim of the Extractor is to have the ability to look into response headers for a Field Position (from a given position) and to set a JMeter Variable with the corresponding field position.
Expand Down Expand Up @@ -44,6 +45,6 @@ In this example we will look for the next field from position (1,2). As we have

Let's visualize all of this:

![alterText](extractor-usage.gif)
![alterText](position-extractor-usage.gif)
> In this example we gave the extractor the beginning of a field (1,2), and as you could see, it will search for the next field on the right, even when the given position is inside a field or outside of it.
Binary file removed docs/extractor/rte-extractor.png
Binary file not shown.
Binary file added docs/extractor/rte-position-extractor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/extractor/variable-prefix.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 7 additions & 2 deletions docs/recorder/terminal-emulator/terminal-emulator.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

- Pressing ![alt_text](/src/main/resources/dark-theme/copy.png) you are able to copy from the emulator, also using the standard keyboard shortcuts.
- Pressing ![alt_text](/src/main/resources/dark-theme/paste.png) you are able to paste in cursor position on the emulator, also using standard shortcuts.
> ANSI sequences are not allowed when pasting. E.g: '\t' '\033[A'.
- You can select a screen area to be used as input field label, press ![alt_text](/src/main/resources/dark-theme/inputByLabel.png) and then set the input field text, to record a test plan that uses the provided label to locate the input field on the screen and fill the field with provided text.
> Input by label allows to find the field on the screen regardless of changes of field positioning, which makes recorded test plans more robust (than using default input by coord).
Expand All @@ -13,12 +14,16 @@
- You can press assertion button ![alt_text](/src/main/resources/dark-theme/assertion.png) when you want to make sure that a part of the screen has appeared in the screen. This assertion has the same behaviour as JMeter Assertions. To assert for a part of the screen you just have to select a part of the screen and press the button. An assertion will be added to corresponding sampler.
>[Here](#recorder-screen-assertion-usage) is an example of usage.
- If you see ![alt_text](/src/main/resources/dark-theme/blocked-cursor.png) it is because you are
using the emulator with a VT protocol which it does not support the functionality of moving the
cursor position by clicking on the emulator.

- Clicking on ![alter_text](/src/main/resources/dark-theme/not-visible-credentials.png) / ![alter_text](/src/main/resources/dark-theme/visible-credentials.png) you will be able to show/hide credentials.

- If you click on the ![alter_text](/src/main/resources/dark-theme/help.png) icon in the emulator, a pop up window will be displayed with general help information on the emulator: shortcuts, explanation about indicators on the screen, etc.

- **Sample name:** As the label says, you can specify the name of the sample in current screen.
- **Sample name:** As the label says, you can specify the name of the sample in current screen.

### Input By Label Usage

Expand Down
Binary file modified docs/rte-sampler.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 10 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
<groupId>com.blazemeter.jmeter</groupId>
<artifactId>jmeter-bzm-rte</artifactId>
<packaging>jar</packaging>
<version>2.3</version>
<version>3.0</version>
<name>RTEPlugin Sampler as JMeter plugin</name>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

<jmeter.version>3.1</jmeter.version>
<jmeter.version>3.2</jmeter.version>
</properties>

<repositories>
Expand All @@ -35,12 +35,17 @@
<dependency>
<groupId>com.github.blazemeter</groupId>
<artifactId>xtn5250</artifactId>
<version>3.2</version>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>com.github.blazemeter</groupId>
<artifactId>dm3270</artifactId>
<version>0.12.1-lib</version>
<version>0.12.3-lib</version>
</dependency>
<dependency>
<groupId>com.github.blazemeter</groupId>
<artifactId>jVT220</artifactId>
<version>jvt220-v1.3</version>
</dependency>

<dependency>
Expand Down Expand Up @@ -230,7 +235,7 @@
</goals>
<configuration>
<includeArtifactIds>
wiresham,guava,snakeyaml,jackson-databind,jackson-core,jackson-annotations,xtn5250,dm3270,pcap4j-core
wiresham,guava,snakeyaml,jackson-databind,jackson-core,jackson-annotations,xtn5250,dm3270,pcap4j-core,jVT220
</includeArtifactIds>
<outputDirectory>${project.build.directory}/jmeter-test/lib</outputDirectory>
<stripVersion>true</stripVersion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.security.GeneralSecurityException;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import javax.net.SocketFactory;
Expand All @@ -19,8 +20,9 @@

public abstract class BaseProtocolClient implements RteProtocolClient {

protected static final ThreadFactory NAMED_THREAD_FACTORY = (runnable) -> new Thread(runnable,
"STABLE-TIMEOUT-EXECUTOR");
private static final Logger LOG = LoggerFactory.getLogger(BaseProtocolClient.class);

protected ExceptionHandler exceptionHandler;
protected ScheduledExecutorService stableTimeoutExecutor;

Expand All @@ -37,33 +39,33 @@ protected SocketFactory getSocketFactory(SSLType sslType, String server) throws
}

@Override
public void send(List<Input> input, AttentionKey attentionKey)
public void send(List<Input> input, AttentionKey attentionKey, long echoTimeoutMillis)
throws RteIOException {
input.forEach(this::setField);
input.forEach(i -> setField(i, echoTimeoutMillis));
sendAttentionKey(attentionKey);
exceptionHandler.throwAnyPendingError();
}

protected abstract void setField(Input input);
protected abstract void setField(Input input, long echoTimeoutMillis);

protected abstract void sendAttentionKey(AttentionKey attentionKey);

@Override
public void await(List<WaitCondition> waitConditions)
throws InterruptedException, TimeoutException, RteIOException {
List<ConditionWaiter> listeners = waitConditions.stream()
List<ConditionWaiter<?>> listeners = waitConditions.stream()
.map(this::buildWaiter)
.collect(Collectors.toList());
try {
for (ConditionWaiter listener : listeners) {
for (ConditionWaiter<?> listener : listeners) {
listener.await();
}
} finally {
listeners.forEach(ConditionWaiter::stop);
}
}

protected abstract ConditionWaiter buildWaiter(WaitCondition waitCondition);
protected abstract ConditionWaiter<?> buildWaiter(WaitCondition waitCondition);

@Override
public void disconnect() throws RteIOException {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.blazemeter.jmeter.rte.core;

import nl.lxtreme.jvt220.terminal.ScreenChangeListener;

public interface CharacterBasedProtocolClient extends RteProtocolClient {

void addScreenChangeListener(ScreenChangeListener listener);

void removeScreenChangeListener(ScreenChangeListener listener);

void send(String character);
}
Loading

0 comments on commit 1922bb1

Please sign in to comment.