ci: add ui(dashboard) tests based on pytest and selenium
This commit is contained in:
parent
d320497d0c
commit
8cdb1458c7
|
@ -165,7 +165,7 @@ jobs:
|
||||||
path: _packages/**/*
|
path: _packages/**/*
|
||||||
|
|
||||||
docker:
|
docker:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: aws-amd64
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
@ -196,12 +196,17 @@ jobs:
|
||||||
tags: ${{ env.EMQX_IMAGE_TAG }}
|
tags: ${{ env.EMQX_IMAGE_TAG }}
|
||||||
build-args: |
|
build-args: |
|
||||||
EMQX_NAME=${{ env.EMQX_NAME }}
|
EMQX_NAME=${{ env.EMQX_NAME }}
|
||||||
- name: test docker image
|
- name: smoke test
|
||||||
run: |
|
run: |
|
||||||
CID=$(docker run -d --rm -P $EMQX_IMAGE_TAG)
|
CID=$(docker run -d --rm -P $EMQX_IMAGE_TAG)
|
||||||
HTTP_PORT=$(docker inspect --format='{{(index (index .NetworkSettings.Ports "18083/tcp") 0).HostPort}}' $CID)
|
HTTP_PORT=$(docker inspect --format='{{(index (index .NetworkSettings.Ports "18083/tcp") 0).HostPort}}' $CID)
|
||||||
./scripts/test/emqx-smoke-test.sh localhost $HTTP_PORT
|
./scripts/test/emqx-smoke-test.sh localhost $HTTP_PORT
|
||||||
docker stop $CID
|
docker stop $CID
|
||||||
|
- name: dashboard tests
|
||||||
|
working-directory: ./scripts/ui-tests
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
docker compose up --abort-on-container-exit --exit-code-from selenium
|
||||||
- name: test two nodes cluster with proto_dist=inet_tls in docker
|
- name: test two nodes cluster with proto_dist=inet_tls in docker
|
||||||
run: |
|
run: |
|
||||||
./scripts/test/start-two-nodes-in-docker.sh -P $EMQX_IMAGE_TAG $EMQX_IMAGE_OLD_VERSION_TAG
|
./scripts/test/start-two-nodes-in-docker.sh -P $EMQX_IMAGE_TAG $EMQX_IMAGE_OLD_VERSION_TAG
|
||||||
|
@ -216,6 +221,11 @@ jobs:
|
||||||
with:
|
with:
|
||||||
name: "${{ matrix.profile[0] }}-docker"
|
name: "${{ matrix.profile[0] }}-docker"
|
||||||
path: "${{ env.EMQX_NAME }}-${{ env.PKG_VSN }}.tar.gz"
|
path: "${{ env.EMQX_NAME }}-${{ env.PKG_VSN }}.tar.gz"
|
||||||
|
- name: cleanup
|
||||||
|
if: always()
|
||||||
|
working-directory: ./scripts/ui-tests
|
||||||
|
run: |
|
||||||
|
docker compose rm -fs
|
||||||
|
|
||||||
spellcheck:
|
spellcheck:
|
||||||
needs: linux
|
needs: linux
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
import pytest
|
||||||
|
from selenium import webdriver
|
||||||
|
|
||||||
|
def pytest_addoption(parser):
|
||||||
|
parser.addoption("--dashboard-host", action="store", default="localhost", help="Dashboard host")
|
||||||
|
parser.addoption("--dashboard-port", action="store", default="18083", help="Dashboard port")
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def dashboard_host(request):
|
||||||
|
return request.config.getoption("--dashboard-host")
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def dashboard_port(request):
|
||||||
|
return request.config.getoption("--dashboard-port")
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
import time
|
||||||
|
import unittest
|
||||||
|
import pytest
|
||||||
|
from urllib.parse import urljoin
|
||||||
|
from selenium import webdriver
|
||||||
|
from selenium.webdriver.common.by import By
|
||||||
|
from selenium.webdriver.common.keys import Keys
|
||||||
|
from selenium.webdriver.chrome.options import Options
|
||||||
|
from selenium.webdriver.support.wait import WebDriverWait
|
||||||
|
from selenium.webdriver.common import utils
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def driver():
|
||||||
|
options = Options()
|
||||||
|
options.add_argument("--headless")
|
||||||
|
options.add_argument("--no-sandbox")
|
||||||
|
_driver = webdriver.Chrome(options=options)
|
||||||
|
yield _driver
|
||||||
|
_driver.quit()
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def dashboard_url(dashboard_host, dashboard_port):
|
||||||
|
count = 0
|
||||||
|
while utils.is_connectable(port=dashboard_port, host=dashboard_host) is False:
|
||||||
|
if count == 30:
|
||||||
|
raise Exception("Dashboard is not ready")
|
||||||
|
count += 1
|
||||||
|
time.sleep(1)
|
||||||
|
return f"http://{dashboard_host}:{dashboard_port}"
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def login(driver, dashboard_url):
|
||||||
|
driver.get(dashboard_url)
|
||||||
|
assert "EMQX Dashboard" == driver.title
|
||||||
|
assert f"{dashboard_url}/#/login?to=/dashboard/overview" == driver.current_url
|
||||||
|
driver.find_element(By.XPATH, "//div[@class='login']//form[1]//input[@type='text']").send_keys("admin")
|
||||||
|
driver.find_element(By.XPATH, "//div[@class='login']//form[1]//input[@type='password']").send_keys("admin")
|
||||||
|
driver.find_element(By.XPATH, "//div[@class='login']//form[1]//button[1]").click()
|
||||||
|
dest_url = urljoin(dashboard_url, "/#/dashboard/overview")
|
||||||
|
driver.get(dest_url)
|
||||||
|
ensure_current_url(driver, dest_url)
|
||||||
|
|
||||||
|
def ensure_current_url(driver, url):
|
||||||
|
count = 0
|
||||||
|
while url != driver.current_url:
|
||||||
|
if count == 10:
|
||||||
|
raise Exception(f"Failed to load {url}")
|
||||||
|
count += 1
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
def wait_title(driver):
|
||||||
|
return WebDriverWait(driver, 10).until(lambda x: x.find_element("xpath", "//div[@id='app']//h1[@class='header-title']"))
|
||||||
|
|
||||||
|
def test_basic(driver, login, dashboard_url):
|
||||||
|
driver.get(dashboard_url)
|
||||||
|
title = wait_title(driver)
|
||||||
|
assert "Cluster Overview" == title.text
|
||||||
|
|
||||||
|
def test_log(driver, login, dashboard_url):
|
||||||
|
dest_url = urljoin(dashboard_url, "/#/log")
|
||||||
|
driver.get(dest_url)
|
||||||
|
ensure_current_url(driver, dest_url)
|
||||||
|
title = wait_title(driver)
|
||||||
|
assert "Logging" == title.text
|
||||||
|
label = driver.find_element(By.XPATH, "//div[@id='app']//form//label[./label/span[text()='Enable Log Handler']]")
|
||||||
|
assert driver.find_elements(By.ID, label.get_attribute("for"))
|
||||||
|
label = driver.find_element(By.XPATH, "//div[@id='app']//form//label[./label/span[text()='Log Level']]")
|
||||||
|
assert driver.find_elements(By.ID, label.get_attribute("for"))
|
||||||
|
label = driver.find_element(By.XPATH, "//div[@id='app']//form//label[./label/span[text()='Log Formatter']]")
|
||||||
|
assert driver.find_elements(By.ID, label.get_attribute("for"))
|
||||||
|
label = driver.find_element(By.XPATH, "//div[@id='app']//form//label[./label/span[text()='Time Offset']]")
|
||||||
|
assert driver.find_elements(By.ID, label.get_attribute("for"))
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
version: '3.9'
|
||||||
|
|
||||||
|
services:
|
||||||
|
emqx:
|
||||||
|
image: ${EMQX_IMAGE_TAG:-emqx/emqx:latest}
|
||||||
|
environment:
|
||||||
|
EMQX_DASHBOARD__DEFAULT_PASSWORD: admin
|
||||||
|
|
||||||
|
selenium:
|
||||||
|
shm_size: '2gb'
|
||||||
|
image: ghcr.io/emqx/selenium-chrome:latest
|
||||||
|
volumes:
|
||||||
|
- ./:/app
|
||||||
|
depends_on:
|
||||||
|
- emqx
|
||||||
|
command: python3 -m pytest --dashboard-host emqx --dashboard-port 18083
|
Loading…
Reference in New Issue