# mugen

## About mugen
mugen is a testing framework provided by openEuler community. This repo contains mugen along with testcases and testsuits for openEuler risc-v port.

## Update log
- New mugen entry function
- Added support for setting testsuit directory and testing envrionment
- Added python util functions for testing

## How to use

#### Installation
Simply run `bash dep_install.sh`.

#### Set testing envrionment
- run `bash mugen.sh -c --ip $ip --password $passwd --user $user --port $port`
- Parameters
  - ip: ip address of target machine
  - user: username of target machine, default is root
  - password
  - port: ssh port of target machine, default is22
- Configuration file is located at `./conf/env.json`
```
{
    "NODE": [
        {
            "ID": 1,
            "LOCALTION": "local",
            "MACHINE": "physical",
            "FRAME": "aarch64",
            "NIC": "eth0",
            "MAC": "55:54:00:c8:a9:21",
            "IPV4": "192.168.0.10",
            "USER": "root",
            "PASSWORD": "openEuler12#$",
            "SSH_PORT": 22,
            "BMC_IP": "",
            "BMC_USER": "",
            "BMC_PASSWORD": ""
        },
        {
            "ID": 2,
            "LOCALTION": "remote",
            "MACHINE": "kvm",
            "FRAME": "aarch64",
            "NIC": "eth0",
            "MAC": "55:54:00:c8:a9:22",
            "IPV4": "192.168.0.11",
            "USER": "root",
            "PASSWORD": "openEuler12#$",
            "SSH_PORT": 22,
            "HOST_IP": "",
            "HOST_USER": "",
            "HOST_PASSWORD": ""
            "HOST_SSH_PORT": ""
        }
    ]
}
```
- In the testcases, use NODE${id}_${LOCALTION} to use the configured environment.

#### Run the test
- Run all test cases
`bash mugen.sh -a`
- Run a test suite
`bash mugen.sh -f testsuite`
- Run a test case
`bash mugen.sh -f testsuite -r testcase`
- Save the testing log
```
bash mugen.sh -a -x 
bash mugen.sh -f testsuite -x
bash mugen.sh -f testsuite -r testcase -x
```

#### Write your test case
- Follow the template we provided: 
```
source ${OET_PATH}/libs/locallibs/common_lib.sh

# Load the data and config 
function config_params() {
    LOG_INFO "Start to config params of the case."

    LOG_INFO "No params need to config."

    LOG_INFO "End to config params of the case."
}

# Prepare the testing environment, eg. Install required packages
function pre_test() {
    LOG_INFO "Start to prepare the test environment."

    LOG_INFO "No pkgs need to install."

    LOG_INFO "End to prepare the test environment."
}

# Run the test
function run_test() {
    LOG_INFO "Start to run test."

    # to test ls
    ls -CZl -all
    CHECK_RESULT 0

    # To check the result
    CHECK_RESULT "$(ls / | grep -cE 'proc|usr|roor|var|sys|etc|boot|dev')" 7

    LOG_INFO "End to run test."
}

# Cleaning the testing environment
function post_test() {
    LOG_INFO "Start to restore the test environment."

    LOG_INFO "Nothing to do."

    LOG_INFO "End to restore the test environment."
}

main "$@"
```

- A testcase is a shell/python script, and a return value of `0` indicates a successful test.
  - Examples: oe_test_casename_02 and oe_test_casename_03


#### The json file in suite2cases
- The json file is a configuration of a test suit.
- Note that:   
<img src='data:image/png;base64,[encoded data, 199364 characters]' />

#### Util functions provided by mugen
- How to load and call these util functions
```
# bash
source ${OET_PATH}/libs/locallibs/common_lib.sh

# python
import os, sys, subprocess

LIBS_PATH = os.environ.get("OET_PATH") + "/libs/locallibs"
sys.path.append(LIBS_PATH)
import xxx
```
  
- Util functions
  - Logging
  ```
  # bash 
  LOG_INFO "$message"
  LOG_WARN "$message"
  LOG_DEBUG "$message"
  LOG_ERROR "$message"
  # python
  import mugen_log
  mugen_log.logging(level, message) # level:INFO,WARN,DEBUG,ERROR;message:日志输出
  ```
  - Check result
  ```
  # bash
  CHECK_RESULT $1 $2 $3 $4
  # $1: Return value of last command
  # $2: Expected value
  # $3: Comp mode, 0: ret == expected -> successful ; 1: ret != expected -> successful
  # $4: Output of 
  ```
  - Install/Uninstall of rpm packages
  ```
  # bash
  ## func 1
  DNF_INSTALL "vim bc" "$node_id"
  DNF_REMOVE "$node_id" "jq" "$mode"

  # mode: Default 0, indicates normal removal of the package; when mode is not 0, mugen will only remove the required package.
  # python
  import rpm_manage
  tpmfile = rpm_manage.rpm_install(pkgs, node, tmpfile)
  rpm_manage.rpm_remove(node, pkgs, tmpfile)
  ```
  - Remote execution
  ```
  # bash
  ## func 1
  SSH_CMD "$cmd" $remote_ip $remote_password $remote_user $time_out $remote_port`
  ## func 2
  P_SSH_CMD --cmd $cmd --node $node(PORT)
  P_SSH_CMD --cmd $cmd --ip $remote_ip --password $remote_password --port $remote_port --user $remote_user --timeout $timeout
  # python
  conn = ssh_cmd.pssh_conn(remote_ip, remote_password,remote_port,remote_user,remote_timeout)
  exitcode, output = ssh_cmd.pssh_cmd(conn, cmd)

  # port: default is 22
  # user: default is root
  # timeout: default is unlimited
  ```
  - File transfer
  ```
  # bash
  ## func 1
  ### local -> remote  
  `SSH_SCP $local_path/$file $REMOTE_USER@$REMOTE_IP:$remote_path "$REMOTE_PASSWD"`
  ### local <- remote
  `SSH_SCP $REMOTE_USER@$REMOTE_IP:$remote_path/$file $local_path "$REMOTE_PASSWD"`
  ## func 2
  ### Transfer a directory
  SFTP get/put --localdir $localdir --remotedir $remotedir
  ### Transfer a file
  SFTP get/put --localdir $localdir --remotedir $remotedir --localfile/remotefile $localfile/$remotefile
  # python
  ### Transfer a directory
  import ssh_cmd, sftp
  conn = ssh_cmd.pssh_conn(remote_ip, remote_password,remote_port,remote_user,remote_timeout)
  psftp_get(conn,remote_dir, local_dir)
  psftp_put(local_dir=local_dir, remote_dir=remote_dir)
  ### Transfer a directory
  import ssh_cmd, sftp
  psftp_get(remote_dir, remote_file, local_dir)
  psftp_put(local_dir=local_dir, local_file=local_file, remote_dir=remote_dir)

  
  # get: get from remote
  # put: put into remote
  # localdir: default is local $(pwd)
  # remotedir: default is remote $(pwd)
  ```
  - Get a free port
  ```
  # bash
  GET_FREE_PORT $ip
  # python
  import free_port
  free_port.find_free_port(ip)
  ```
  - Check if a port is taken
  ```
  # bash 
  IS_FREE_PORT $port $ip
  # python
  import free_port
  free_port.is_free_port(port, ip)
  ```
  - Get a test NIC
  ```
  # bash
  TEST_NIC $node_id
  # python
  import get_test_device
  get_test_nic(node_id)

  # node_id: 默认为1号节点
  ```
  - Get a test Disk
  ```
  # bash
  TEST_DISK $node_id
  # python
  import get_test_device
  get_test_disk(node_id)

  # node_id: default is 1
  ```
  - Sleep
  ```
  # bash
  SLEEP_WAIT $wait_time $cmd
  # python
  import sleep_wait
  sleep_wait.sleep_wait(wait_time,cmd)
  ```
  - Reboot remote
  ```
  # bash
  REMOTE_REBOOT_WAIT $node_id $wait_time
  ```

#### How to debug your testcase
- use `export OET_PATH=$(pwd)` to set `OET_PATH` and just run the script in their correspoding dir

#### About timeout
- Default timeout is 30 min
- If a test case costs more than 30 min，set `TIMEOUT` in the test case script

#### FAQ
- Timeout in remote execution
  - Possible cause: ssh will wait for stdout and will not exit unless there is a signal
  - Possible solution: Redirect stdout to /dev/null, like `cmd > /dev/nul 2>&1 &`

## Contribution

1.  Fork the repository
2.  Create Feat_xxx branch
3.  Commit your code
4.  Create Pull Request


## Gitee Feature

1.  You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2.  Gitee blog [blog.gitee.com](https://blog.gitee.com)
3.  Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4.  The most valuable open source project [GVP](https://gitee.com/gvp)
5.  The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6.  The most popular members  [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
