mirror of https://github.com/OpenVidu/openvidu.git
openvidu: Docker image to tests deployments
parent
8d522bb136
commit
e482181644
|
@ -0,0 +1,3 @@
|
||||||
|
python_modules/
|
||||||
|
src/geckodriver.*
|
||||||
|
*/__pycache__/
|
|
@ -0,0 +1,47 @@
|
||||||
|
FROM ubuntu:22.04
|
||||||
|
|
||||||
|
ENV DEBIAN_FRONTEND noninteractive \
|
||||||
|
DISPLAY :99.0
|
||||||
|
|
||||||
|
# Install Software
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -qqy --no-install-recommends \
|
||||||
|
lbzip2 \
|
||||||
|
gnupg2 \
|
||||||
|
xvfb \
|
||||||
|
x11-utils \
|
||||||
|
wget \
|
||||||
|
python3 \
|
||||||
|
python3-pip
|
||||||
|
|
||||||
|
# Install latest chrome
|
||||||
|
RUN wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb && \
|
||||||
|
apt install -y ./google-chrome-stable_current_amd64.deb && \
|
||||||
|
rm google-chrome-stable_current_amd64.deb
|
||||||
|
|
||||||
|
# Install non snap version of firefox
|
||||||
|
ENV FF_INSTALLER_NAME=firefox-latest.tar.bz2
|
||||||
|
RUN cd /tmp && \
|
||||||
|
apt-get update && apt-get install libdbus-glib-1-2 -y && \
|
||||||
|
rm -rf /var/lib/apt/lists/* && \
|
||||||
|
wget --progress=dot:mega -O ${FF_INSTALLER_NAME} \
|
||||||
|
'https://download.mozilla.org/?product=firefox-latest-ssl&os=linux64&lang=en-US' && \
|
||||||
|
tar -x -C /usr/local/bin -f ${FF_INSTALLER_NAME} && \
|
||||||
|
rm -f ${FF_INSTALLER_NAME} && \
|
||||||
|
ln -s /usr/local/bin/firefox/firefox /usr/bin/firefox
|
||||||
|
|
||||||
|
# Copy source code and install dependencies
|
||||||
|
COPY ./src/ /workdir/src/
|
||||||
|
COPY ./requirements.txt /workdir/
|
||||||
|
RUN cd /workdir && pip3 install -r requirements.txt
|
||||||
|
|
||||||
|
WORKDIR /workdir/src
|
||||||
|
|
||||||
|
# Cache web driver
|
||||||
|
RUN python3 main.py install-drivers
|
||||||
|
|
||||||
|
# Copy entrypoint
|
||||||
|
COPY ./entrypoint.sh /usr/local/bin/
|
||||||
|
RUN chmod +x /usr/local/bin/entrypoint.sh
|
||||||
|
|
||||||
|
ENTRYPOINT [ "/usr/local/bin/entrypoint.sh" ]
|
|
@ -0,0 +1,82 @@
|
||||||
|
# OpenVidu Deployment Tester
|
||||||
|
|
||||||
|
This is a simple python automation script to test the deployment of any kind of OpenVidu Server deployment. Its purpose is to test most general deployment scenarios and to provide a simple and portable way to test the deployment of OpenVidu Server.
|
||||||
|
|
||||||
|
The script uses selenium to control a browser and execute the tests. As this automation tool is packaged in a docker container, it is not necessary to install any other dependency in the machine where the script is going to be executed.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
- A working OpenVidu Server deployment (CE/PRO/Enterprise)
|
||||||
|
- Docker installed in the machine where the script is going to be executed.
|
||||||
|
- OpenVidu Call. It is not strictly necessary, but it is recommended to execute some tests.
|
||||||
|
|
||||||
|
## Test cases
|
||||||
|
|
||||||
|
### 1. Basic Test
|
||||||
|
|
||||||
|
This test case will simply check from the dashboard (CE) or Inspector (PRO/Enterprise) that OpenVidu WebRTC minimal capabilities are working (Video and TURN)
|
||||||
|
|
||||||
|
**1. OpenVidu CE without forcing TURN candidates to be used (Chrome)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run openvidu/openvidu-deployment-tester basic-test \
|
||||||
|
--openvidu-url <OPENVIDU_URL> \
|
||||||
|
--openvidu-secret <OPENVIDU_SECRET> \
|
||||||
|
--openvidu-edition ce \
|
||||||
|
--browser chrome
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. OpenVidu CE without forcing TURN candidates to be used (Firefox)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run openvidu/openvidu-deployment-tester basic-test \
|
||||||
|
--openvidu-url <OPENVIDU_URL> \
|
||||||
|
--openvidu-secret <OPENVIDU_SECRET> \
|
||||||
|
--openvidu-edition ce \
|
||||||
|
--browser firefox
|
||||||
|
```
|
||||||
|
|
||||||
|
**3. OpenVidu CE forcing TURN candidates to be used (Firefox)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run openvidu/openvidu-deployment-tester basic-test \
|
||||||
|
--openvidu-url <OPENVIDU_URL> \
|
||||||
|
--openvidu-secret <OPENVIDU_SECRET> \
|
||||||
|
--openvidu-edition ce \
|
||||||
|
--browser firefox \
|
||||||
|
--turn
|
||||||
|
```
|
||||||
|
|
||||||
|
**4. OpenVidu PRO without forcing TURN candidates to be used (Chrome)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run openvidu/openvidu-deployment-tester basic-test \
|
||||||
|
--openvidu-url <OPENVIDU_URL> \
|
||||||
|
--openvidu-secret <OPENVIDU_SECRET> \
|
||||||
|
--openvidu-edition pro \
|
||||||
|
--browser chrome
|
||||||
|
```
|
||||||
|
|
||||||
|
**5. OpenVidu PRO without forcing TURN candidates to be used (Firefox)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run openvidu/openvidu-deployment-tester basic-test \
|
||||||
|
--openvidu-url <OPENVIDU_URL> \
|
||||||
|
--openvidu-secret <OPENVIDU_SECRET> \
|
||||||
|
--openvidu-edition pro \
|
||||||
|
--browser firefox
|
||||||
|
```
|
||||||
|
|
||||||
|
**6. OpenVidu PRO forcing TURN candidates to be used (Firefox)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run openvidu/openvidu-deployment-tester basic-test \
|
||||||
|
--openvidu-url <OPENVIDU_URL> \
|
||||||
|
--openvidu-secret <OPENVIDU_SECRET> \
|
||||||
|
--openvidu-edition ce \
|
||||||
|
--browser firefox \
|
||||||
|
--turn
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Recording tests
|
||||||
|
|
||||||
|
Working on...
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/bash -x
|
#!/bin/bash -x
|
||||||
VERSION=$1
|
VERSION=$1
|
||||||
if [[ ! -z $VERSION ]]; then
|
if [[ ! -z $VERSION ]]; then
|
||||||
docker build --pull --no-cache --rm=true -t openvidu/openvidu-health-checker:$VERSION .
|
docker build --pull --no-cache --rm=true -t openvidu/openvidu-deployment-tester:latest .
|
||||||
else
|
else
|
||||||
echo "Error: You need to specify a version as first argument"
|
echo "Error: You need to specify a version as first argument"
|
||||||
fi
|
fi
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -eu -o pipefail
|
||||||
|
|
||||||
|
# Iniciar XVFB
|
||||||
|
export DISPLAY_NUM=99
|
||||||
|
export DISPLAY=":${DISPLAY_NUM}"
|
||||||
|
|
||||||
|
# Esperar hasta que XVFB esté listo
|
||||||
|
while ! xdpyinfo -display "${DISPLAY}" >/dev/null 2>&1; do
|
||||||
|
DISPLAY_NUM=$((DISPLAY_NUM+1))
|
||||||
|
DISPLAY=":${DISPLAY_NUM}"
|
||||||
|
echo "Trying to launch XVFB on display ${DISPLAY}..."
|
||||||
|
/usr/bin/Xvfb "${DISPLAY}" -screen 0 1280x720x16 &
|
||||||
|
sleep 2s
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Running tests... Please wait..."
|
||||||
|
|
||||||
|
python3 main.py "$@"
|
|
@ -0,0 +1,4 @@
|
||||||
|
selenium==4.8.2
|
||||||
|
webdriver-manager==3.8.5
|
||||||
|
prettytable==3.6.0
|
||||||
|
beautifulsoup4==4.12.0
|
|
@ -0,0 +1,34 @@
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
def install_drivers_parser(subparsers):
|
||||||
|
install_drivers_parser = subparsers.add_parser("install-drivers")
|
||||||
|
install_drivers_parser.add_argument("--chrome-version", required=False, help="Chrome version to install (e.g. 87.0.4280.88")
|
||||||
|
install_drivers_parser.add_argument("--gecko-version", required=False, help="Gecko version to install (e.g. 0.29.1")
|
||||||
|
|
||||||
|
def test_parser(subparsers, command):
|
||||||
|
test_parser = subparsers.add_parser(command)
|
||||||
|
test_parser.add_argument("--openvidu-url", required=True, help="OpenVidu URL to test")
|
||||||
|
test_parser.add_argument("--openvidu-secret", required=True, help="OpenVidu secret used for OpenVidu API")
|
||||||
|
if command == "basic-test":
|
||||||
|
test_parser.add_argument("--openvidu-edition", required=True, choices=["ce", "pro", "enterprise"], help="OpenVidu edition to test")
|
||||||
|
test_parser.add_argument("--browser", required=True, choices=["chrome", "firefox"], help="Browser to test")
|
||||||
|
test_parser.add_argument("--turn", required=False, default=False, action='store_true', help="Force TURN usage. Only available for Firefox")
|
||||||
|
elif command == "recording-test":
|
||||||
|
test_parser.add_argument("--openvidu-call-url", required=True, help="OpenVidu Call URL to test")
|
||||||
|
|
||||||
|
def initialize_parser():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
subparsers = parser.add_subparsers(dest="command")
|
||||||
|
|
||||||
|
install_drivers_parser(subparsers)
|
||||||
|
test_parser(subparsers, "basic-test")
|
||||||
|
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def print_args(args):
|
||||||
|
print("Executing command: " + args.command)
|
||||||
|
for arg, value in vars(args).items():
|
||||||
|
if arg != 'command':
|
||||||
|
if arg == 'openvidu-secret':
|
||||||
|
value = '********'
|
||||||
|
print(f"\t{arg}: {value}")
|
|
@ -0,0 +1,25 @@
|
||||||
|
import cli_utils
|
||||||
|
import utils
|
||||||
|
|
||||||
|
import tests
|
||||||
|
|
||||||
|
# Define your commands here
|
||||||
|
def install_drivers(args):
|
||||||
|
cli_utils.print_args(args)
|
||||||
|
utils.install_drivers(args.chrome_version, args.gecko_version)
|
||||||
|
|
||||||
|
# Define the command-line arguments
|
||||||
|
parser = cli_utils.initialize_parser()
|
||||||
|
|
||||||
|
# Parse the command-line arguments and call the appropriate command with its arguments
|
||||||
|
args = parser.parse_args()
|
||||||
|
if hasattr(args, "openvidu_url") and args.openvidu_url.endswith("/"):
|
||||||
|
args.openvidu_url = args.openvidu_url[:-1]
|
||||||
|
if hasattr(args, "openvidu_secret"):
|
||||||
|
args.openvidu_url = utils.authenticated_url(args.openvidu_url, args.openvidu_secret)
|
||||||
|
if args.command == "install-drivers":
|
||||||
|
install_drivers(args)
|
||||||
|
elif args.command == "basic-test":
|
||||||
|
tests.basic_test(args)
|
||||||
|
else:
|
||||||
|
print("Error: No command specified")
|
|
@ -0,0 +1,52 @@
|
||||||
|
import utils
|
||||||
|
from selenium.webdriver.common.keys import Keys
|
||||||
|
from selenium.webdriver.common.by import By
|
||||||
|
|
||||||
|
def basic_test(args):
|
||||||
|
print("Running basic test with args:", args)
|
||||||
|
driver = utils.runBrowser(args.browser, args.turn)
|
||||||
|
if args.openvidu_edition == "ce":
|
||||||
|
url_test = args.openvidu_url + '/dashboard'
|
||||||
|
driver.get(url_test)
|
||||||
|
|
||||||
|
elem = driver.find_element(By.ID,'test-btn')
|
||||||
|
elem.send_keys(Keys.RETURN)
|
||||||
|
|
||||||
|
elem = driver.find_element(By.NAME, 'secret')
|
||||||
|
elem.send_keys(args.openvidu_secret)
|
||||||
|
|
||||||
|
elem = driver.find_element(By.ID, 'join-btn')
|
||||||
|
elem.send_keys(Keys.RETURN)
|
||||||
|
elif args.openvidu_edition == "pro":
|
||||||
|
url_test = args.openvidu_url + '/inspector'
|
||||||
|
driver.get(url_test)
|
||||||
|
|
||||||
|
elem = driver.find_element(By.ID, 'secret-input')
|
||||||
|
elem.send_keys(args.openvidu_secret)
|
||||||
|
|
||||||
|
elem = driver.find_element(By.ID, 'login-btn')
|
||||||
|
elem.send_keys(Keys.RETURN)
|
||||||
|
|
||||||
|
# print('data:image/png;base64,' + self.driver.get_screenshot_as_base64())
|
||||||
|
elem = driver.find_element(By.ID,'menu-test-btn')
|
||||||
|
elem.send_keys(Keys.RETURN)
|
||||||
|
|
||||||
|
elem = driver.find_element(By.ID,'test-btn')
|
||||||
|
elem.send_keys(Keys.RETURN)
|
||||||
|
else:
|
||||||
|
print("Error: Invalid OpenVidu edition specified")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
video_error = False
|
||||||
|
try:
|
||||||
|
driver.find_element(By.XPATH, "//*[contains(text(), 'Stream playing')]")
|
||||||
|
print('Video detected.\n')
|
||||||
|
except:
|
||||||
|
video_error = True
|
||||||
|
finally:
|
||||||
|
# print('data:image/png;base64,' + driver.get_screenshot_as_base64())
|
||||||
|
if args.browser == "firefox":
|
||||||
|
utils.print_candidates(driver)
|
||||||
|
|
||||||
|
if video_error == True:
|
||||||
|
raise Exception('Error. No video detected')
|
|
@ -0,0 +1,126 @@
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
|
||||||
|
from webdriver_manager.chrome import ChromeDriverManager
|
||||||
|
from webdriver_manager.firefox import GeckoDriverManager
|
||||||
|
from selenium.webdriver.chrome.service import Service as ChromeService
|
||||||
|
from selenium.webdriver.firefox.service import Service as FirefoxService
|
||||||
|
from selenium.webdriver.common.by import By
|
||||||
|
from selenium import webdriver
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
from prettytable import from_html_one
|
||||||
|
|
||||||
|
def install_drivers(chrome_version, gecko_version):
|
||||||
|
print("Downloading drivers...")
|
||||||
|
# Download Chrome driver
|
||||||
|
chrome_driver_manager = ChromeDriverManager(version=chrome_version)
|
||||||
|
chrome_driver_manager.install()
|
||||||
|
|
||||||
|
# Download Firefox driver
|
||||||
|
firefox_driver_manager = GeckoDriverManager(version=gecko_version)
|
||||||
|
firefox_driver_manager.install()
|
||||||
|
|
||||||
|
with open("chrome_version", "w") as f:
|
||||||
|
f.write(chrome_driver_manager.driver.get_version())
|
||||||
|
with open("firefox_version", "w") as f:
|
||||||
|
f.write(firefox_driver_manager.driver.get_version())
|
||||||
|
|
||||||
|
def authenticated_url(openvidu_url, openvidu_secret):
|
||||||
|
separator = "://"
|
||||||
|
basic_auth_url_str = "OPENVIDUAPP:" + openvidu_secret + "@"
|
||||||
|
split_url = openvidu_url.split(separator)
|
||||||
|
return split_url[0] + separator + basic_auth_url_str + split_url[1]
|
||||||
|
|
||||||
|
def runBrowser(browser, turn=False):
|
||||||
|
driver=None
|
||||||
|
if browser == "chrome":
|
||||||
|
driver = runChrome()
|
||||||
|
else:
|
||||||
|
driver = runFirefox(turn)
|
||||||
|
driver.maximize_window()
|
||||||
|
driver.implicitly_wait(10)
|
||||||
|
return driver
|
||||||
|
|
||||||
|
def runChrome():
|
||||||
|
# Get Chrome driver version from environment variable
|
||||||
|
chrome_version = os.environ.get("CHROME_VERSION")
|
||||||
|
|
||||||
|
# Get Chrome driver version from file if not found in environment variable
|
||||||
|
# Read it only if file exist (it may not exist if running in a container)
|
||||||
|
if chrome_version is None and os.path.isfile("chrome_version"):
|
||||||
|
with open("chrome_version", "r") as f:
|
||||||
|
chrome_version = f.read()
|
||||||
|
print("Chrome version: ", chrome_version)
|
||||||
|
print("Running chrome...")
|
||||||
|
options = webdriver.ChromeOptions()
|
||||||
|
options.add_argument("--use-fake-ui-for-media-stream")
|
||||||
|
options.add_argument("--disable-infobars")
|
||||||
|
options.add_argument("--ignore-certificate-errors")
|
||||||
|
options.add_argument("--start-maximized")
|
||||||
|
options.add_argument("--use-fake-device-for-media-stream")
|
||||||
|
options.add_argument("--no-sandbox")
|
||||||
|
|
||||||
|
return webdriver.Chrome(
|
||||||
|
service=ChromeService(ChromeDriverManager(version=chrome_version).install()),
|
||||||
|
options = options)
|
||||||
|
|
||||||
|
def runFirefox(turn=False):
|
||||||
|
# Get Gecko driver version from environment variable
|
||||||
|
gecko_version = os.environ.get("GECKO_VERSION")
|
||||||
|
|
||||||
|
# Get Gecko driver version from file if not found in environment variable
|
||||||
|
# Read it only if file exist (it may not exist if running in a container)
|
||||||
|
if gecko_version is None and os.path.isfile("firefox_version"):
|
||||||
|
with open("firefox_version", "r") as f:
|
||||||
|
gecko_version = f.read()
|
||||||
|
|
||||||
|
print("Gecko version: ", gecko_version)
|
||||||
|
print("Running firefox with Turn: ", turn)
|
||||||
|
options = webdriver.FirefoxOptions()
|
||||||
|
options.set_preference('media.navigator.permission.disabled', True)
|
||||||
|
options.set_preference('media.navigator.streams.fake', True)
|
||||||
|
options.set_preference('media.peerconnection.enabled', True)
|
||||||
|
options.set_preference('media.peerconnection.ice.obfuscate_host_addresses', False)
|
||||||
|
options.set_preference('media.peerconnection.identity.enabled', True)
|
||||||
|
options.set_preference('media.peerconnection.mtransport_process', True)
|
||||||
|
options.set_preference('media.peerconnection.ice.no_host', False)
|
||||||
|
options.set_preference('network.process.enabled', True)
|
||||||
|
options.set_preference('media.peerconnection.ice.relay_only', turn)
|
||||||
|
options.set_preference('media.peerconnection.turn.disable', not turn)
|
||||||
|
|
||||||
|
return webdriver.Firefox(
|
||||||
|
service=FirefoxService(GeckoDriverManager(version=gecko_version).install()),
|
||||||
|
options = options)
|
||||||
|
|
||||||
|
def print_candidates(driver):
|
||||||
|
try:
|
||||||
|
# New tab
|
||||||
|
driver.execute_script("window.open('');")
|
||||||
|
# Switch to the new window
|
||||||
|
driver.switch_to.window(driver.window_handles[1])
|
||||||
|
# Open about:webrtc
|
||||||
|
driver.get('about:webrtc')
|
||||||
|
peer_conn_elems = driver.find_elements(By.CLASS_NAME, "peer-connection")
|
||||||
|
for peer_conn in peer_conn_elems:
|
||||||
|
show_details_elems = peer_conn.find_elements(By.XPATH, "//*[contains(text(), 'show details')]")
|
||||||
|
for show_details in show_details_elems:
|
||||||
|
show_details.click()
|
||||||
|
|
||||||
|
print("Waiting for candidates to be checked...")
|
||||||
|
# Get ice stats
|
||||||
|
time.sleep(15)
|
||||||
|
# about:webrtc page refreshes each second, so we need to
|
||||||
|
# safe the entire HTML in a variable to have a Snapshot of the situation
|
||||||
|
about_webrtc_html = '<html>' + driver.find_element(By.TAG_NAME, 'html').get_attribute('innerHTML') + '</html>'
|
||||||
|
# Search the tables using a parser and print all candidates
|
||||||
|
soup = BeautifulSoup(about_webrtc_html, 'html.parser')
|
||||||
|
for caption in soup.findAll('caption', {'data-l10n-id' : 'about-webrtc-trickle-caption-msg'}):
|
||||||
|
print(from_html_one(str(caption.parent)))
|
||||||
|
# Close about:webrtc
|
||||||
|
driver.close()
|
||||||
|
driver.switch_to.window(driver.window_handles[0])
|
||||||
|
driver.close()
|
||||||
|
except:
|
||||||
|
print('[Warn] Some candidates may not appear in test result')
|
||||||
|
driver.switch_to.window(driver.window_handles[0])
|
||||||
|
driver.close()
|
|
@ -1,38 +0,0 @@
|
||||||
FROM ubuntu:20.04
|
|
||||||
|
|
||||||
ENV DEBIAN_FRONTEND noninteractive
|
|
||||||
ENV DISPLAY :99.0
|
|
||||||
|
|
||||||
# Install Software
|
|
||||||
RUN apt-get update && \
|
|
||||||
apt-get install -qqy --no-install-recommends \
|
|
||||||
gnupg2 \
|
|
||||||
xvfb \
|
|
||||||
x11-utils \
|
|
||||||
wget \
|
|
||||||
python3 \
|
|
||||||
python3-pip
|
|
||||||
|
|
||||||
# Install Chrome and firefox
|
|
||||||
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
|
|
||||||
&& echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list \
|
|
||||||
&& apt-get update -qqy \
|
|
||||||
&& apt-get -qqy install \
|
|
||||||
google-chrome-stable firefox \
|
|
||||||
&& rm /etc/apt/sources.list.d/google-chrome.list
|
|
||||||
|
|
||||||
RUN pip3 install selenium webdriver_manager prettytable beautifulsoup4
|
|
||||||
|
|
||||||
WORKDIR /workdir
|
|
||||||
|
|
||||||
COPY ./run.sh ./entrypoint.sh /usr/local/bin/
|
|
||||||
COPY ./openvidu_health_check.py ./download_webdrivers.py ./
|
|
||||||
RUN chmod +x /usr/local/bin/entrypoint.sh /usr/local/bin/run.sh
|
|
||||||
|
|
||||||
# Cache web driver
|
|
||||||
RUN python3 download_webdrivers.py
|
|
||||||
|
|
||||||
ENTRYPOINT [ "/usr/local/bin/entrypoint.sh" ]
|
|
||||||
|
|
||||||
CMD [ "openvidu_health_check.py" ]
|
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
# Openvidu health checker
|
|
||||||
|
|
||||||
The main purpose of this image is to have a self-contained and independent docker image to test and check possible errors in OpenVidu deployments.
|
|
||||||
|
|
||||||
This image is also usefull to automation tests of infrastructure.
|
|
||||||
|
|
||||||
# Current health checks
|
|
||||||
|
|
||||||
## 1. Video working and Turn correctly setup
|
|
||||||
|
|
||||||
```
|
|
||||||
docker run --shm-size 2g \
|
|
||||||
-e OV_URL=<OV_URL> \
|
|
||||||
-e OV_SECRET=<OV_SECRET> \
|
|
||||||
openvidu/openvidu-health-checker
|
|
||||||
```
|
|
||||||
|
|
||||||
Just put your OpenVidu url at `OV_URL` and your `OV_SECRET` and the stack will be tested.
|
|
||||||
|
|
||||||
This health check includes:
|
|
||||||
|
|
||||||
- 1. Inspector Test Video in **Chrome**
|
|
||||||
- 2. Inspector Test Video in **Firefox**
|
|
||||||
- 3. Inspector Test Video in **Firefox** with **TURN forced**.
|
|
||||||
|
|
||||||
If allways works:
|
|
||||||
|
|
||||||
- STUN/TURN is correctly configured
|
|
||||||
- Video Publishing/Subscribing works
|
|
||||||
|
|
||||||
If works sometimes:
|
|
||||||
|
|
||||||
- Bad ports opened.
|
|
||||||
- Bad internet connection.
|
|
||||||
- No possible connection via STUN/TURN
|
|
||||||
|
|
||||||
If don't work:
|
|
||||||
|
|
||||||
- Bad port configuration.
|
|
||||||
- No possible connection via STUN/TURN
|
|
||||||
- Simply a deployment which is not deployed correctly
|
|
|
@ -1,12 +0,0 @@
|
||||||
from openvidu_health_check import InfraSmokeTests
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
try:
|
|
||||||
init_obj = InfraSmokeTests()
|
|
||||||
init_obj.runChrome()
|
|
||||||
except:
|
|
||||||
print("Chrome web driver downloaded")
|
|
||||||
try:
|
|
||||||
init_obj.runFirefox()
|
|
||||||
except:
|
|
||||||
print("Firefox web driver downloaded")
|
|
|
@ -1,15 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
asyncRun() {
|
|
||||||
"$@" &
|
|
||||||
pid="$!"
|
|
||||||
trap "echo 'Stopping PID $pid'; kill -SIGTERM $pid" SIGINT SIGTERM
|
|
||||||
|
|
||||||
# A signal emitted while waiting will make the wait command return code > 128
|
|
||||||
# Let's wrap it in a loop that doesn't end before the process is indeed stopped
|
|
||||||
while kill -0 $pid > /dev/null 2>&1; do
|
|
||||||
wait
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
asyncRun /usr/local/bin/run.sh "$@"
|
|
|
@ -1,189 +0,0 @@
|
||||||
#!/usr/bin/python3
|
|
||||||
import unittest
|
|
||||||
import requests
|
|
||||||
from selenium import webdriver
|
|
||||||
from selenium.webdriver import firefox
|
|
||||||
from selenium.webdriver.firefox import service
|
|
||||||
from webdriver_manager.chrome import ChromeDriverManager
|
|
||||||
from webdriver_manager.firefox import GeckoDriverManager
|
|
||||||
from selenium.webdriver.chrome import options
|
|
||||||
from selenium.webdriver.chrome.service import Service as ChromeService
|
|
||||||
from selenium.webdriver.firefox.service import Service as FirefoxService
|
|
||||||
from selenium.webdriver.common.keys import Keys
|
|
||||||
from selenium.webdriver.common.by import By
|
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
from prettytable import from_html_one
|
|
||||||
import time
|
|
||||||
import os
|
|
||||||
|
|
||||||
class InfraSmokeTests(unittest.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
print('Executing test... Please wait...')
|
|
||||||
self.openvidu_url = os.getenv('OV_URL')
|
|
||||||
self.openvidu_password = os.getenv('OV_SECRET')
|
|
||||||
self.is_openvidu_ce = self.check_is_openvidu_ce()
|
|
||||||
if self.is_openvidu_ce:
|
|
||||||
self.inject_basic_auth_in_url()
|
|
||||||
self.driver = None
|
|
||||||
|
|
||||||
def test_chrome_no_relay(self):
|
|
||||||
self.inspector_check(browser="chrome")
|
|
||||||
|
|
||||||
def test_firefox_no_relay(self):
|
|
||||||
self.inspector_check(browser="firefox")
|
|
||||||
|
|
||||||
def test_firefox_force_relay(self):
|
|
||||||
self.inspector_check(browser="firefox", turn=True)
|
|
||||||
|
|
||||||
def inspector_check(self, browser="chrome", turn=False):
|
|
||||||
print('\n\n======================================================================')
|
|
||||||
print('|')
|
|
||||||
print('|')
|
|
||||||
print('| Testing OpenVidu ' + ('CE ' if self.is_openvidu_ce else 'PRO/ENTERPRISE ') + 'with ' + browser + ' and force relay: ' + str(turn))
|
|
||||||
print('|')
|
|
||||||
print('|')
|
|
||||||
print('======================================================================')
|
|
||||||
if self.openvidu_url == None or self.openvidu_password == None:
|
|
||||||
raise(Exception("You must specify OV_URL and OV_SECRET environment variables"))
|
|
||||||
if browser == "chrome":
|
|
||||||
self.runChrome()
|
|
||||||
else:
|
|
||||||
self.runFirefox(turn)
|
|
||||||
|
|
||||||
if self.is_openvidu_ce:
|
|
||||||
url_test = self.openvidu_url + '/dashboard'
|
|
||||||
self.driver.get(url_test)
|
|
||||||
|
|
||||||
elem = self.driver.find_element(By.ID,'test-btn')
|
|
||||||
elem.send_keys(Keys.RETURN)
|
|
||||||
|
|
||||||
elem = self.driver.find_element(By.NAME, 'secret')
|
|
||||||
elem.send_keys(self.openvidu_password)
|
|
||||||
|
|
||||||
elem = self.driver.find_element(By.ID, 'join-btn')
|
|
||||||
elem.send_keys(Keys.RETURN)
|
|
||||||
|
|
||||||
else:
|
|
||||||
url_test = self.openvidu_url + '/inspector'
|
|
||||||
self.driver.get(url_test)
|
|
||||||
|
|
||||||
elem = self.driver.find_element(By.ID, 'secret-input')
|
|
||||||
elem.send_keys(self.openvidu_password)
|
|
||||||
|
|
||||||
elem = self.driver.find_element(By.ID, 'login-btn')
|
|
||||||
elem.send_keys(Keys.RETURN)
|
|
||||||
|
|
||||||
# print('data:image/png;base64,' + self.driver.get_screenshot_as_base64())
|
|
||||||
elem = self.driver.find_element(By.ID,'menu-test-btn')
|
|
||||||
elem.send_keys(Keys.RETURN)
|
|
||||||
|
|
||||||
elem = self.driver.find_element(By.ID,'test-btn')
|
|
||||||
elem.send_keys(Keys.RETURN)
|
|
||||||
|
|
||||||
video_error = False
|
|
||||||
try:
|
|
||||||
self.driver.find_element(By.XPATH, "//*[contains(text(), 'Stream playing')]")
|
|
||||||
print('Video detected.\n')
|
|
||||||
except:
|
|
||||||
video_error = True
|
|
||||||
finally:
|
|
||||||
# print('data:image/png;base64,' + self.driver.get_screenshot_as_base64())
|
|
||||||
if browser == "firefox":
|
|
||||||
self.print_candidates()
|
|
||||||
|
|
||||||
if video_error == True:
|
|
||||||
raise Exception('Error. No video detected')
|
|
||||||
|
|
||||||
self.driver.switch_to.window(self.driver.window_handles[0])
|
|
||||||
elem = self.driver.find_element(By.ID,'test-btn')
|
|
||||||
elem.send_keys(Keys.RETURN)
|
|
||||||
|
|
||||||
self.closeBrowser()
|
|
||||||
print('Sucess with ' + browser + ' and Force Turn: ' + str(turn) + '\n')
|
|
||||||
print('----------------------------------------------------------------------\n')
|
|
||||||
|
|
||||||
def runChrome(self):
|
|
||||||
self.options = webdriver.ChromeOptions()
|
|
||||||
self.options.add_argument("--use-fake-ui-for-media-stream")
|
|
||||||
self.options.add_argument("--disable-infobars")
|
|
||||||
self.options.add_argument("--ignore-certificate-errors")
|
|
||||||
self.options.add_argument("--start-maximized")
|
|
||||||
self.options.add_argument("--use-fake-device-for-media-stream")
|
|
||||||
self.options.add_argument("--no-sandbox")
|
|
||||||
|
|
||||||
self.driver = webdriver.Chrome(
|
|
||||||
service=ChromeService(ChromeDriverManager().install()),
|
|
||||||
options = self.options)
|
|
||||||
self.driver.implicitly_wait(15)
|
|
||||||
|
|
||||||
def runFirefox(self, turn=False):
|
|
||||||
print("Running firefox with Turn: ", turn)
|
|
||||||
self.options = webdriver.FirefoxOptions()
|
|
||||||
self.options.set_preference('media.navigator.permission.disabled', False)
|
|
||||||
self.options.set_preference('media.navigator.streams.fake', True)
|
|
||||||
self.options.set_preference('media.peerconnection.enabled', True)
|
|
||||||
self.options.set_preference('media.peerconnection.ice.obfuscate_host_addresses', False)
|
|
||||||
self.options.set_preference('media.peerconnection.identity.enabled', True)
|
|
||||||
self.options.set_preference('media.peerconnection.mtransport_process', True)
|
|
||||||
self.options.set_preference('media.peerconnection.ice.no_host', False)
|
|
||||||
self.options.set_preference('network.process.enabled', True)
|
|
||||||
self.options.set_preference('media.peerconnection.ice.relay_only', turn)
|
|
||||||
self.options.set_preference('media.peerconnection.turn.disable', not turn)
|
|
||||||
|
|
||||||
self.driver = webdriver.Firefox(
|
|
||||||
service=FirefoxService(GeckoDriverManager().install()),
|
|
||||||
options = self.options)
|
|
||||||
self.driver.implicitly_wait(15)
|
|
||||||
self.driver.maximize_window()
|
|
||||||
|
|
||||||
def check_is_openvidu_ce(self):
|
|
||||||
response = requests.get(self.openvidu_url + "/dashboard")
|
|
||||||
if response.status_code == 401:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def inject_basic_auth_in_url(self):
|
|
||||||
separator = "://"
|
|
||||||
basic_auth_url_str = "OPENVIDUAPP:" + self.openvidu_password + "@"
|
|
||||||
split_url = self.openvidu_url.split(separator)
|
|
||||||
self.openvidu_url = split_url[0] + separator + basic_auth_url_str + split_url[1]
|
|
||||||
|
|
||||||
|
|
||||||
def print_candidates(self):
|
|
||||||
try:
|
|
||||||
# New tab
|
|
||||||
self.driver.execute_script("window.open('');")
|
|
||||||
# Switch to the new window
|
|
||||||
self.driver.switch_to.window(self.driver.window_handles[1])
|
|
||||||
# Open about:webrtc
|
|
||||||
self.driver.get('about:webrtc')
|
|
||||||
peer_conn_elems = self.driver.find_elements(By.CLASS_NAME, "peer-connection")
|
|
||||||
for peer_conn in peer_conn_elems:
|
|
||||||
show_details_elems = peer_conn.find_elements(By.XPATH, "//*[contains(text(), 'show details')]")
|
|
||||||
for show_details in show_details_elems:
|
|
||||||
show_details.click()
|
|
||||||
|
|
||||||
print("Waiting for candidates to be checked...")
|
|
||||||
# Get ice stats
|
|
||||||
time.sleep(15)
|
|
||||||
# about:webrtc page refreshes each second, so we need to
|
|
||||||
# safe the entire HTML in a variable to have a Snapshot of the situation
|
|
||||||
about_webrtc_html = '<html>' + self.driver.find_element(By.TAG_NAME, 'html').get_attribute('innerHTML') + '</html>'
|
|
||||||
# Search the tables using a parser and print all candidates
|
|
||||||
soup = BeautifulSoup(about_webrtc_html, 'html.parser')
|
|
||||||
for caption in soup.findAll('caption', {'data-l10n-id' : 'about-webrtc-trickle-caption-msg'}):
|
|
||||||
print(from_html_one(str(caption.parent)))
|
|
||||||
# Close about:webrtc
|
|
||||||
self.driver.close()
|
|
||||||
except:
|
|
||||||
print('[Warn] Some candidates may not appear in test result')
|
|
||||||
|
|
||||||
def closeBrowser(self):
|
|
||||||
# close the browser window
|
|
||||||
self.driver.close()
|
|
||||||
self.driver.quit()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
unittest.main()
|
|
|
@ -1,16 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
set -eu -o pipefail
|
|
||||||
|
|
||||||
# Launch XVFB
|
|
||||||
/usr/bin/Xvfb :99 -screen 0 1280x720x16 &
|
|
||||||
|
|
||||||
# Wait for XVFB
|
|
||||||
while ! xdpyinfo >/dev/null 2>&1
|
|
||||||
do
|
|
||||||
sleep 0.50s
|
|
||||||
echo "Waiting xvfb..."
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "Running tests... Please wait..."
|
|
||||||
|
|
||||||
exec python3 "$@"
|
|
|
@ -18,12 +18,12 @@ RUN apt update && apt -y upgrade && apt install -y \
|
||||||
ttf-ancient-fonts fonts-beng fonts-wqy-zenhei fonts-indic \
|
ttf-ancient-fonts fonts-beng fonts-wqy-zenhei fonts-indic \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Install chrome
|
# Install latest stable Chrome browser
|
||||||
RUN apt update && apt -y upgrade && apt install -y wget sudo
|
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4CCA1EAF950CEE4AB83976DCA040830F7FAC5991 \
|
||||||
RUN wget http://dl.google.com/linux/deb/pool/main/g/google-chrome-stable/google-chrome-stable_${CHROME_VERSION}_amd64.deb \
|
&& echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list \
|
||||||
&& apt install -y ./google-chrome-stable_${CHROME_VERSION}_amd64.deb \
|
&& apt update \
|
||||||
&& rm google-chrome-stable_${CHROME_VERSION}_amd64.deb \
|
&& apt install -y google-chrome-stable \
|
||||||
&& google-chrome --version
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Add root user to pulseaudio group
|
# Add root user to pulseaudio group
|
||||||
RUN adduser root pulse-access
|
RUN adduser root pulse-access
|
||||||
|
|
Loading…
Reference in New Issue