Skip to content

Commit

Permalink
Merge pull request #205 from MalloZup/qa-tests
Browse files Browse the repository at this point in the history
Qa tests
  • Loading branch information
MalloZup committed Jul 3, 2020
2 parents 5c1edcf + e90fd31 commit 4d127ea
Show file tree
Hide file tree
Showing 14 changed files with 1,061 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ http://hawk-ui.github.io
- [Release](doc/release.md)
- [Installation](#installation-and-deployment)
- [Devel notes](#devel)
- [Testing](e2e_test/README.md)

## Build Dependencies

Expand Down Expand Up @@ -88,4 +89,3 @@ server instance runs as).
of Pacemaker CLI tools as another user in order to support Pacemaker's
ACL feature. It is used by Hawk when performing various management
tasks.

3 changes: 3 additions & 0 deletions e2e_test/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.git
**/__pycache__
**/*.pyc
2 changes: 2 additions & 0 deletions e2e_test/.pylintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[MESSAGES CONTROL]
disable=missing-docstring,line-too-long,too-many-public-methods,too-many-instance-attributes,too-many-arguments,too-many-statements,too-few-public-methods
19 changes: 19 additions & 0 deletions e2e_test/.travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
language: python

services:
- docker

dist: xenial

python:
- "3.5"
- "3.6"
- "3.7"
- "3.8"

install:
- pip install -r requirements-test.txt

script:
- make test
- make test-docker
3 changes: 3 additions & 0 deletions e2e_test/AUTHORS
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Alexei.Tighineanu@suse.com @atighineanu
Alvaro.Carvajal@suse.com @alvarocarvajald
Ricardo.Branco@suse.com @ricardobranco777
41 changes: 41 additions & 0 deletions e2e_test/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Defines the tag for OBS and build script builds:
#!BuildTag: hawk_test
# Use the repositories defined in OBS for installing packages
#!UseOBSRepositories
FROM opensuse/tumbleweed

RUN zypper -n install -y --no-recommends \
MozillaFirefox \
MozillaFirefox-branding-upstream \
chromium \
file \
python3 \
python3-paramiko \
python3-PyVirtualDisplay \
python3-selenium \
shadow \
xauth \
xdpyinfo \
xorg-x11-fonts \
xorg-x11-server-Xvfb && \
zypper -n clean -a

RUN zypper -n install -y --no-recommends wget tar gzip
RUN zypper -n clean -a
RUN wget https://github.com/mozilla/geckodriver/releases/download/v0.26.0/geckodriver-v0.26.0-linux64.tar.gz
RUN tar xvf geckodriver-v0.26.0-linux64.tar.gz
RUN mv geckodriver /usr/local/bin
RUN chmod +x /usr/local/bin/*

RUN useradd -l -m -d /test test

COPY *.py /

ENV PYTHONPATH /
ENV PYTHONUNBUFFERED 1
ENV DBUS_SESSION_BUS_ADDRESS /dev/null

WORKDIR /test

USER test
ENTRYPOINT ["/usr/bin/python3", "/hawk_test.py"]
7 changes: 7 additions & 0 deletions e2e_test/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
test:
@flake8 --ignore=E501
@pylint --ignored-modules=distutils *.py

test-docker:
@docker build -t hawk_test -f Dockerfile.alpine .
@docker run --rm hawk_test --help
72 changes: 72 additions & 0 deletions e2e_test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Hawk end to end tests.

This Docker image runs a set of Selenium tests for testing [Hawk](https://github.com/ClusterLabs/hawk/)

The following tests are executed by openQA during ci regularly.

As developer you can execute them manually when you do an update on hawk.

# Pre-requisites:

* docker
* 2 Hawk vms running
(normally it is a cluster)
See https://github.com/SUSE/pacemaker-deploy for deploying hawk


# Quickstart:

1) Create the docker image
`docker build . -t hawk_test `

2) Run the tests with:
``` docker run --ipc=host hawk_test -H 10.162.32.175 -S 10.162.29.122 -t 15 -s linux --xvfb ```

Notes:
- You may want to add `--net=host` if you have problems with DNS resolution.

## Dependencies

- OS packages:
- Xvfb (optional)
- Docker (optional)
- Firefox
- [Geckodriver](https://github.com/mozilla/geckodriver/releases)
- Chromium (optional)
- [Chromedriver](https://chromedriver.chromium.org/downloads) (optional)
- Python 3
- Python packages:
- paramiko
- selenium
- PyVirtualDisplay

## Options

```
-h, --help show this help message and exit
-b {firefox,chrome,chromium}, --browser {firefox,chrome,chromium}
Browser to use in the test
-H HOST, --host HOST Host or IP address where HAWK is running
-S SLAVE, --slave SLAVE
Host or IP address of the slave
-I VIRTUAL_IP, --virtual-ip VIRTUAL_IP
Virtual IP address in CIDR notation
-P PORT, --port PORT TCP port where HAWK is running
-p PREFIX, --prefix PREFIX
Prefix to add to Resources created during the test
-t TEST_VERSION, --test-version TEST_VERSION
Test SLES Version. Ex: 12-SP3, 12-SP4, 15, 15-SP1
-s SECRET, --secret SECRET
root SSH Password of the HAWK node
-r RESULTS, --results RESULTS
Generate hawk_test.results file for use with openQA.
--xvfb Use Xvfb. Headless mode
```

## FAQ

- Why Xvfb?
- The `-headless` in both browsers still have bugs, specially with modal dialogs.
- Having Xvfb prevents it from connecting to our X system.
- Why docker?
- The Docker image packs the necessary dependencies in such a way that fits the compatibility matrix between Python, Selenium, Firefox (and Geckodriver) & Chromium (and Chromedriver).
161 changes: 161 additions & 0 deletions e2e_test/hawk_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
#!/usr/bin/python3
# Copyright (C) 2019 SUSE LLC
"""HAWK GUI interface Selenium test: tests hawk GUI with Selenium using firefox or chrome"""

import argparse
import ipaddress
import re
import shutil
import socket
import sys

from pyvirtualdisplay import Display

from hawk_test_driver import HawkTestDriver
from hawk_test_results import ResultSet
from hawk_test_ssh import HawkTestSSH


def hostname(string):
try:
socket.getaddrinfo(string, 1)
return string
except socket.gaierror:
raise argparse.ArgumentTypeError("Unknown host: %s" % string)


def cidr_address(string):
try:
ipaddress.ip_network(string, False)
return string
except ValueError:
raise argparse.ArgumentTypeError("Invalid CIDR address: %s" % string)


def port(string):
if string.isdigit() and 1 <= int(string) <= 65535:
return string
raise argparse.ArgumentTypeError("Invalid port number: %s" % string)


def sles_version(string):
if re.match(r"\d{2}(?:-SP\d)?$", string):
return string
raise argparse.ArgumentTypeError("Invalid SLES version: %s" % string)


def parse_args():
parser = argparse.ArgumentParser(description='HAWK GUI interface Selenium test')
parser.add_argument('-b', '--browser', default='firefox', choices=['firefox', 'chrome', 'chromium'],
help='Browser to use in the test')
parser.add_argument('-H', '--host', default='localhost', type=hostname,
help='Host or IP address where HAWK is running')
parser.add_argument('-S', '--slave', type=hostname,
help='Host or IP address of the slave')
parser.add_argument('-I', '--virtual-ip', type=cidr_address,
help='Virtual IP address in CIDR notation')
parser.add_argument('-P', '--port', default='7630', type=port,
help='TCP port where HAWK is running')
parser.add_argument('-p', '--prefix', default='',
help='Prefix to add to Resources created during the test')
parser.add_argument('-t', '--test-version', required=True, type=sles_version,
help='Test SLES Version. Ex: 12-SP3, 12-SP4, 15, 15-SP1')
parser.add_argument('-s', '--secret',
help='root SSH Password of the HAWK node')
parser.add_argument('-r', '--results',
help='Generate hawk_test.results file')
parser.add_argument('--xvfb', action='store_true',
help='Use Xvfb. Headless mode')
args = parser.parse_args()
return args


def main():
args = parse_args()

if args.prefix and not args.prefix.isalpha():
print("ERROR: Prefix must be alphanumeric", file=sys.stderr)
sys.exit(1)

driver = "geckodriver" if args.browser == "firefox" else "chromedriver"
if shutil.which(driver) is None:
print("ERROR: Please download %s to a directory in PATH" % driver, file=sys.stderr)
sys.exit(1)

if args.xvfb:
global DISPLAY # pylint: disable=global-statement
DISPLAY = Display()
DISPLAY.start()

# Create driver instance
browser = HawkTestDriver(addr=args.host, port=args.port,
browser=args.browser, headless=args.xvfb,
version=args.test_version.lower())

# Initialize results set
results = ResultSet()

# Establish SSH connection to verify status
ssh = HawkTestSSH(args.host, args.secret)
results.add_ssh_tests()

# Resources to create
mycluster = args.prefix + 'Anderes'
myprimitive = args.prefix + 'cool_primitive'
myclone = args.prefix + 'cool_clone'
mygroup = args.prefix + 'cool_group'

# Tests to perform
if args.virtual_ip:
browser.test('test_add_virtual_ip', results, args.virtual_ip)
browser.test('test_remove_virtual_ip', results)
else:
results.set_test_status('test_add_virtual_ip', 'skipped')
results.set_test_status('test_remove_virtual_ip', 'skipped')
browser.test('test_set_stonith_maintenance', results)
ssh.verify_stonith_in_maintenance(results)
browser.test('test_disable_stonith_maintenance', results)
browser.test('test_view_details_first_node', results)
browser.test('test_clear_state_first_node', results)
browser.test('test_set_first_node_maintenance', results)
ssh.verify_node_maintenance(results)
browser.test('test_disable_maintenance_first_node', results)
browser.test('test_add_new_cluster', results, mycluster)
browser.test('test_remove_cluster', results, mycluster)
browser.test('test_click_on_history', results)
browser.test('test_generate_report', results)
browser.test('test_click_on_command_log', results)
browser.test('test_click_on_status', results)
browser.test('test_add_primitive', results, myprimitive)
ssh.verify_primitive(myprimitive, args.test_version, results)
browser.test('test_remove_primitive', results, myprimitive)
ssh.verify_primitive_removed(myprimitive, results)
browser.test('test_add_clone', results, myclone)
browser.test('test_remove_clone', results, myclone)
browser.test('test_add_group', results, mygroup)
browser.test('test_remove_group', results, mygroup)
browser.test('test_click_around_edit_conf', results)
if args.slave:
browser.addr = args.slave
browser.test('test_fencing', results)
else:
results.set_test_status('test_fencing', 'skipped')

# Save results if run with -r or --results
if args.results:
results.logresults(args.results)

return results.get_failed_tests_total()


if __name__ == "__main__":
DISPLAY = None
try:
sys.exit(main())
except KeyboardInterrupt:
if DISPLAY is not None:
DISPLAY.stop()
sys.exit(1)
finally:
if DISPLAY is not None:
DISPLAY.stop()
Loading

0 comments on commit 4d127ea

Please sign in to comment.