# Performance Test Plan for Different Environment

The settings of JMeter performance test for different environment are basically consistent, just with differences of address, account, an so on, Here I utilize Shell Script and JMeter variable to handle uniformly 
<!-- more -->

## Install JMeter

> wget `https://mirror.cogentco.com/pub/apache//jmeter/binaries/apache-jmeter-5.4.1.tgz`  
tar -zxvf apache-jmeter-5.4.1.tgz -C /opt

Add bin directory to PATH
```
export PATH="$PATH:/opt/apache-jmeter-5.4.1/bin"
```
- This way we can execute `jmeter` command from anywhere

## Config Test Plan

Run JMeter GUI
> jmeter

### Normal Setting

1. Right click `Test Plan`, hover `Add`, then hove `Threads(User)`, click `Thread Group`, set appropriate value for `Number of Threads (users)`
![](https://chanvinxiao.com/cn/blog/performance-test-plan-for-different-environment/threads.png?40)
2. Right click the newly added `Thread Group` under `Test Plan` , hover `Add`, then hover `Config Element`, click `HTTP Request Default`, set `Server Name or IP` as `${__P(HOST)}`, `Port Number` as `${__P(PORT)}`
![](https://chanvinxiao.com/cn/blog/performance-test-plan-for-different-environment/defaults.png)
3. Right click `Thread Group`, hover `Add`, then hover `Sample`, click `HTTP Request`, set `Name` as `Frontend`, `Path` as `/`
![](https://chanvinxiao.com/cn/blog/performance-test-plan-for-different-environment/frontend.png?40)
4. Right click `Thread Group`, hover `Add`, then hover `Sample`, click `HTTP Request`, set `Name` as `Backend`, `Path` as `/api/currentUser`
![](https://chanvinxiao.com/cn/blog/performance-test-plan-for-different-environment/backend.png?40)
5. Right click `Thread Group`, hover `Add`, then hover `Assertion`, click `Response Assertion`, set `Field to Test` as `Response Code`, `Patten Matching Rules` as `Equals`, click `Add` in the bottom, input `200`
![](https://chanvinxiao.com/cn/blog/performance-test-plan-for-different-environment/assertion.png?40)

- [`__P`][jmeter-p] is function for JMeter to get the command line parameter

### Handle Authorization

The above backend api can only be access after login, the authorized method is token in the cookies or Authorization Header, so we need to get this token firstly, and append to every request
1. Right click `Test Plan`, hover `Add`, then hover `Threads(User)`, click `setUp Thread Group`
![](https://chanvinxiao.com/cn/blog/performance-test-plan-for-different-environment/setup.png?40)
2. Right click `setUp Thread Group`, hover `Add`, then hover `Sample`, click `HTTP Request`, set `Name` as `Login`, `Server Name or IP` as `${__P(HOST)}`, `Port Number` as `${__P(PORT)}`, Method of `HTTP Request` as `POST`, `Path` as `/api/login/account`, click `Add` in the bottom, add `Name` as `username` and `password`, `Value` as `${__P(USERNAME)}` and `${__P(PASSWORD)}` respectively
![](https://chanvinxiao.com/cn/blog/performance-test-plan-for-different-environment/login.png?40)
3. Right click `setUp Thread Group`, hover `Add`, then hover `Post Processors`, click `Regular Expression Extractor`, set `Name of created variable` as `token`, `Regular Expression` as `"token":"(.+?)"`, Template as `$1$`
![](https://chanvinxiao.com/cn/blog/performance-test-plan-for-different-environment/regular.png?40)
4. Right click `setUp Thread Group`, hover `Add`, then hover `Sample`, click `BeanShellSampler`, set `Name` as `Token`, `Script` as `${__setProperty(token, ${token})}`
![](https://chanvinxiao.com/cn/blog/performance-test-plan-for-different-environment/token.png?40)
5. Right click `Thread Group`, hover `Add`, then hover `Config Element`, click `HTTP Cookie Manager`, click `Add` in the bottom, set `Name` as `token`, `Value` as `${__property(token)}`, `Domain` as `${__P(HOST)}:${__P(PORT)}`, `Path` as `/`
![](https://chanvinxiao.com/cn/blog/performance-test-plan-for-different-environment/cookies.png)

- `"token":"(.+?)"` capture value of `token` in the return result as `$1$` 
- [`__setProperty`][jmeter-set-property] is function for JMeter to set global variable
- [`__property`][jmeter-property] is function for JMeter to get global variable

## Run Test Plan

### Run Directly

The above plan config set information of address and account as variable, which can be transmitted in the command line, such as:

> mkdir report  
HEAP="-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m"  
jmeter -n -t test.jmx \  
  -J HOST=127.0.0.1 \  
  -J PORT=80 \  
  -J USERNAME=USERNAME \  
  -J PASSWORD=PASSWORD \  
  -l log/local-20210620095700.txt \  
  -e -o report/local-20210620095700  

- `report` directory must exists, so that the report can be written, so `mkdir` need to be used to create it for the first time
- The above command line make use of [jmeter command line options][jmeter-command-options] `-n`, `-t`, `-J`, `-l`, `-e` and `-o`
- The html formatted test report in local-20210620095700, is composed by table data and visualized chart, as the following images shown:
![](https://chanvinxiao.com/cn/blog/performance-test-plan-for-different-environment/dash.png)
![](https://chanvinxiao.com/cn/blog/performance-test-plan-for-different-environment/time.png)

### Handle by Shell

The above commands are verbose, and we need to set every parameter for different environment, so I utilize Shell Script to simplify

#### Config Variable
```
export LOCAL_HOST=127.0.0.1
export LOCAL_PORT=80
export LOCAL_USERNAME=USERNAME
export LOCAL_PASSWORD=PASSWORD
export TESTING_HOST=192.168.1.10
export TESTING_PORT=80
export TESTING_USERNAME=USERNAME
export TESTING_PASSWORD=PASSWORD
export PRODUCT_HOST=192.168.1.100
export PRODUCT_PORT=80
export PRODUCT_USERNAME=USERNAME
export PRODUCT_PASSWORD=PASSWORD
```

#### Invoke Variable

```
#!/bin/sh

time=$(date "+%Y%m%d%H%M%S")
server=${1:-"local"}
prefix=$(echo $server | tr 'a-z' 'A-Z')_
HOST=${prefix}HOST
PORT=${prefix}PORT
USERNAME=${prefix}USERNAME
PASSWORD=${prefix}PASSWORD

if ! [ -d "report" ]
then
mkdir report
fi

HEAP="-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m"
jmeter -n -t test.jmx \
  -J HOST=${!HOST} \
  -J PORT=${!PORT} \
  -J USERNAME=${!USERNAME} \
  -J PASSWORD=${!PASSWORD} \
  -l log/$server-$time.txt \
  -e -o report/$server-$time
```

- `$(echo $VAR | tr 'a-z' 'A-Z')` indicates uppercase for all, same as `${VAR^^}` for `Bash` which above version 4.0 
- If `report` directory exists, we don't need to recreate it again, so we determine with `-d` firstly
- `${!HOST}` means the value of `$HOST` is the name the other variable, and the value of this other variable will be resolved

### Run Script

#### Local Environment
> ./test.sh  

#### Testing Environment
> ./test.sh testing  

#### Product Environment
> ./test.sh product  

- if the environment parameter is omitted, `${1:-"local"}` will set the default environment as `local`

## Summarize

The above plan and script can be downloaded via [this GitHub Repository][perf-test-plan], which fulfills the following:
- Config test plan dynamically for JMeter through the reception of parameter inputted by command line
- Utilize setup thread group to handle login, and set token as global variable
- Simplify command and handle uniformly for different environment with Shell Script

[jmeter-p]: https://jmeter.apache.org/usermanual/functions.html#__P
[jmeter-set-property]: https://jmeter.apache.org/usermanual/functions.html#__setProperty
[jmeter-property]: https://jmeter.apache.org/usermanual/functions.html#__property
[jmeter-command-options]: https://jmeter.apache.org/usermanual/get-started.html#options
[perf-test-plan]: https://github.com/vinzid/perf-test-plan
