mirror of https://github.com/OpenVidu/openvidu.git
openvidu-deployment-tester: Add recording and call parametrizable tests
parent
868835bb91
commit
11e5888747
|
@ -14,7 +14,8 @@ RUN apt-get update && \
|
||||||
x11-utils \
|
x11-utils \
|
||||||
wget \
|
wget \
|
||||||
python3 \
|
python3 \
|
||||||
python3-pip
|
python3-pip \
|
||||||
|
ffmpeg
|
||||||
|
|
||||||
# Install latest chrome
|
# Install latest chrome
|
||||||
RUN wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb && \
|
RUN wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb && \
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
selenium==4.8.2
|
selenium==4.8.2
|
||||||
webdriver-manager==3.8.5
|
webdriver-manager==3.8.5
|
||||||
prettytable==3.6.0
|
prettytable==3.6.0
|
||||||
beautifulsoup4==4.12.0
|
beautifulsoup4==4.12.0
|
||||||
|
opencv-python-headless==4.7.0.72
|
||||||
|
numpy==1.24.2
|
|
@ -9,12 +9,17 @@ def test_parser(subparsers, command):
|
||||||
test_parser = subparsers.add_parser(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-url", required=True, help="OpenVidu URL to test")
|
||||||
test_parser.add_argument("--openvidu-secret", required=True, help="OpenVidu secret used for OpenVidu API")
|
test_parser.add_argument("--openvidu-secret", required=True, help="OpenVidu secret used for OpenVidu API")
|
||||||
|
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")
|
||||||
|
|
||||||
|
# Basic test specific parameter
|
||||||
if command == "basic-test":
|
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("--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")
|
if command.startswith("call-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")
|
test_parser.add_argument("--openvidu-call-url", required=True, help="OpenVidu Call URL to test")
|
||||||
|
test_parser.add_argument("--number-of-clients", required=False, nargs='?', help="Number of clients to test", const=4, default=4, type=int)
|
||||||
|
test_parser.add_argument("--openvidu-call-username", required=True, help="OpenVidu Call user to test")
|
||||||
|
test_parser.add_argument("--openvidu-call-password", required=True, help="OpenVidu Call password to test")
|
||||||
|
|
||||||
def initialize_parser():
|
def initialize_parser():
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
@ -22,13 +27,7 @@ def initialize_parser():
|
||||||
|
|
||||||
install_drivers_parser(subparsers)
|
install_drivers_parser(subparsers)
|
||||||
test_parser(subparsers, "basic-test")
|
test_parser(subparsers, "basic-test")
|
||||||
|
test_parser(subparsers, "call-test-recording")
|
||||||
|
test_parser(subparsers, "call-test")
|
||||||
|
|
||||||
return parser
|
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}")
|
|
|
@ -5,7 +5,6 @@ import tests
|
||||||
|
|
||||||
# Define your commands here
|
# Define your commands here
|
||||||
def install_drivers(args):
|
def install_drivers(args):
|
||||||
cli_utils.print_args(args)
|
|
||||||
utils.install_drivers(args.chrome_version, args.gecko_version)
|
utils.install_drivers(args.chrome_version, args.gecko_version)
|
||||||
|
|
||||||
# Define the command-line arguments
|
# Define the command-line arguments
|
||||||
|
@ -21,5 +20,9 @@ if args.command == "install-drivers":
|
||||||
install_drivers(args)
|
install_drivers(args)
|
||||||
elif args.command == "basic-test":
|
elif args.command == "basic-test":
|
||||||
tests.basic_test(args)
|
tests.basic_test(args)
|
||||||
|
elif args.command == "call-test-recording":
|
||||||
|
tests.call_recording_test(args)
|
||||||
|
elif args.command == "call-test":
|
||||||
|
tests.call_test(args)
|
||||||
else:
|
else:
|
||||||
print("Error: No command specified")
|
print("Error: No command specified")
|
|
@ -1,38 +1,26 @@
|
||||||
import utils
|
import utils
|
||||||
|
import time
|
||||||
from selenium.webdriver.common.keys import Keys
|
from selenium.webdriver.common.keys import Keys
|
||||||
from selenium.webdriver.common.by import By
|
from selenium.webdriver.common.by import By
|
||||||
|
from requests.auth import HTTPBasicAuth
|
||||||
|
import requests
|
||||||
|
|
||||||
def basic_test(args):
|
def basic_test(args):
|
||||||
print("Running basic test with args:", args)
|
print("Running basic test with args:", args)
|
||||||
driver = utils.runBrowser(args.browser, args.turn)
|
driver = utils.runBrowser(args.browser, args.turn)
|
||||||
|
base_url = args.openvidu_url
|
||||||
|
|
||||||
if args.openvidu_edition == "ce":
|
if args.openvidu_edition == "ce":
|
||||||
url_test = args.openvidu_url + '/dashboard'
|
driver.get(f"{base_url}/dashboard")
|
||||||
driver.get(url_test)
|
driver.find_element(By.ID, 'test-btn').send_keys(Keys.RETURN)
|
||||||
|
driver.find_element(By.NAME, 'secret').send_keys(args.openvidu_secret)
|
||||||
elem = driver.find_element(By.ID,'test-btn')
|
driver.find_element(By.ID, 'join-btn').send_keys(Keys.RETURN)
|
||||||
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":
|
elif args.openvidu_edition == "pro":
|
||||||
url_test = args.openvidu_url + '/inspector'
|
driver.get(f"{base_url}/inspector")
|
||||||
driver.get(url_test)
|
driver.find_element(By.ID, 'secret-input').send_keys(args.openvidu_secret)
|
||||||
|
driver.find_element(By.ID, 'login-btn').send_keys(Keys.RETURN)
|
||||||
elem = driver.find_element(By.ID, 'secret-input')
|
driver.find_element(By.ID, 'menu-test-btn').send_keys(Keys.RETURN)
|
||||||
elem.send_keys(args.openvidu_secret)
|
driver.find_element(By.ID, 'test-btn').send_keys(Keys.RETURN)
|
||||||
|
|
||||||
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:
|
else:
|
||||||
print("Error: Invalid OpenVidu edition specified")
|
print("Error: Invalid OpenVidu edition specified")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
@ -44,9 +32,75 @@ def basic_test(args):
|
||||||
except:
|
except:
|
||||||
video_error = True
|
video_error = True
|
||||||
finally:
|
finally:
|
||||||
# print('data:image/png;base64,' + driver.get_screenshot_as_base64())
|
|
||||||
if args.browser == "firefox":
|
if args.browser == "firefox":
|
||||||
utils.print_candidates(driver)
|
utils.print_candidates(driver)
|
||||||
|
|
||||||
if video_error == True:
|
if video_error:
|
||||||
raise Exception('Error. No video detected')
|
raise Exception('Error. No video detected')
|
||||||
|
|
||||||
|
def call_recording_test(args):
|
||||||
|
print("Testing recording with OpenVidu Call with args:", args)
|
||||||
|
driver = utils.runBrowser(args.browser, args.turn)
|
||||||
|
driver.get(args.openvidu_call_url)
|
||||||
|
|
||||||
|
utils.call_login(driver, args.openvidu_call_username, args.openvidu_call_password)
|
||||||
|
session_name = utils.call_session(driver, args.number_of_clients)
|
||||||
|
|
||||||
|
print('Starting recording')
|
||||||
|
driver.find_element(By.ID, 'activities-panel-btn').send_keys(Keys.RETURN)
|
||||||
|
time.sleep(5)
|
||||||
|
driver.find_element(By.ID, 'mat-expansion-panel-header-0').send_keys(Keys.RETURN)
|
||||||
|
time.sleep(5)
|
||||||
|
driver.find_element(By.ID, 'start-recording-btn').send_keys(Keys.RETURN)
|
||||||
|
|
||||||
|
print('Recording started')
|
||||||
|
time.sleep(10)
|
||||||
|
|
||||||
|
print('Stopping recording')
|
||||||
|
driver.find_element(By.ID, 'stop-recording-btn').send_keys(Keys.RETURN)
|
||||||
|
print('Recording stopped')
|
||||||
|
time.sleep(5)
|
||||||
|
utils.close_all_tabs(driver, args.browser)
|
||||||
|
|
||||||
|
print(f'Downloading recording from {args.openvidu_url}/openvidu/recordings/{session_name}/{session_name}.mp4')
|
||||||
|
url = f'{args.openvidu_url}/openvidu/recordings/{session_name}/{session_name}.mp4'
|
||||||
|
|
||||||
|
if args.browser == "chrome":
|
||||||
|
print("Checking if recording is green (Default video color from chrome emulated video is green)")
|
||||||
|
is_green = utils.is_video_green(url, HTTPBasicAuth('OPENVIDUAPP', args.openvidu_secret), f'{session_name}.mp4')
|
||||||
|
is_video_valid = utils.is_video_valid(url, HTTPBasicAuth('OPENVIDUAPP', args.openvidu_secret), f'{session_name}.mp4')
|
||||||
|
print("Recording is", "green" if is_green else "not green")
|
||||||
|
if not is_green or not is_video_valid:
|
||||||
|
exit(1)
|
||||||
|
elif args.browser == "firefox":
|
||||||
|
# Close all tabs
|
||||||
|
print("Checking if recording is a valid video")
|
||||||
|
is_valid = utils.is_video_valid(url, HTTPBasicAuth('OPENVIDUAPP', args.openvidu_secret), f'{session_name}.mp4')
|
||||||
|
print("Recording is", "valid" if is_valid else "not valid")
|
||||||
|
if not is_valid:
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
print('Removing recording')
|
||||||
|
url = f'{args.openvidu_url}/openvidu/api/recordings/stop/{session_name}'
|
||||||
|
requests.delete(url, auth=HTTPBasicAuth('OPENVIDUAPP', args.openvidu_secret), verify=False)
|
||||||
|
|
||||||
|
def call_test(args):
|
||||||
|
print(f"Testing recording with OpenVidu Call with args: {args}")
|
||||||
|
driver = utils.runBrowser(args.browser, args.turn)
|
||||||
|
driver.get(args.openvidu_call_url)
|
||||||
|
|
||||||
|
utils.call_login(driver, args.openvidu_call_username, args.openvidu_call_password)
|
||||||
|
utils.call_session(driver, args.number_of_clients)
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
videos = driver.find_elements(By.TAG_NAME, 'video')
|
||||||
|
|
||||||
|
if len(videos) != args.number_of_clients:
|
||||||
|
raise Exception('Error. Number of videos is not equal to number of clients')
|
||||||
|
|
||||||
|
for i, video in enumerate(videos):
|
||||||
|
current_time = float(video.get_attribute('currentTime'))
|
||||||
|
print(f'Video {i} is playing. Current time: {current_time}')
|
||||||
|
if current_time < 1:
|
||||||
|
raise Exception('Error. Video is not playing')
|
||||||
|
utils.close_all_tabs(driver, args.browser)
|
|
@ -1,11 +1,16 @@
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
import requests
|
||||||
|
import subprocess
|
||||||
|
|
||||||
from webdriver_manager.chrome import ChromeDriverManager
|
from webdriver_manager.chrome import ChromeDriverManager
|
||||||
from webdriver_manager.firefox import GeckoDriverManager
|
from webdriver_manager.firefox import GeckoDriverManager
|
||||||
from selenium.webdriver.chrome.service import Service as ChromeService
|
from selenium.webdriver.chrome.service import Service as ChromeService
|
||||||
from selenium.webdriver.firefox.service import Service as FirefoxService
|
from selenium.webdriver.firefox.service import Service as FirefoxService
|
||||||
from selenium.webdriver.common.by import By
|
from selenium.webdriver.common.by import By
|
||||||
|
from selenium.webdriver.common.keys import Keys
|
||||||
from selenium import webdriver
|
from selenium import webdriver
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from prettytable import from_html_one
|
from prettytable import from_html_one
|
||||||
|
@ -46,8 +51,11 @@ def runChrome():
|
||||||
|
|
||||||
# Load version from file
|
# Load version from file
|
||||||
chrome_version = None
|
chrome_version = None
|
||||||
with open("chrome_version", "r") as f:
|
|
||||||
chrome_version = f.read()
|
# Check if chrome version file exists and load it
|
||||||
|
if os.path.isfile("chrome_version"):
|
||||||
|
with open("chrome_version", "r") as f:
|
||||||
|
chrome_version = f.read()
|
||||||
|
|
||||||
print("Running chrome...")
|
print("Running chrome...")
|
||||||
print("Chrome version: ", chrome_version)
|
print("Chrome version: ", chrome_version)
|
||||||
|
@ -68,8 +76,11 @@ def runFirefox(turn=False):
|
||||||
|
|
||||||
# Load version from file
|
# Load version from file
|
||||||
gecko_version = None
|
gecko_version = None
|
||||||
with open("gecko_version", "r") as f:
|
|
||||||
gecko_version = f.read()
|
# Check if gecko version file exists and load it
|
||||||
|
if os.path.isfile("gecko_version"):
|
||||||
|
with open("gecko_version", "r") as f:
|
||||||
|
gecko_version = f.read()
|
||||||
|
|
||||||
print("Running firefox with Turn: ", turn)
|
print("Running firefox with Turn: ", turn)
|
||||||
print("Gecko version: ", gecko_version)
|
print("Gecko version: ", gecko_version)
|
||||||
|
@ -120,4 +131,92 @@ def print_candidates(driver):
|
||||||
except:
|
except:
|
||||||
print('[Warn] Some candidates may not appear in test result')
|
print('[Warn] Some candidates may not appear in test result')
|
||||||
driver.switch_to.window(driver.window_handles[0])
|
driver.switch_to.window(driver.window_handles[0])
|
||||||
driver.close()
|
driver.close()
|
||||||
|
|
||||||
|
def call_session(driver, num_of_clients):
|
||||||
|
print('First session entering')
|
||||||
|
session_name = driver.find_element(By.ID, 'session-name-input').get_attribute('value')
|
||||||
|
driver.find_element(By.ID, 'join-btn').send_keys(Keys.RETURN)
|
||||||
|
|
||||||
|
print('Joining user 1 to session', session_name)
|
||||||
|
driver.find_element(By.ID, 'join-button').send_keys(Keys.RETURN)
|
||||||
|
url_link = driver.current_url
|
||||||
|
|
||||||
|
for i in range(2, num_of_clients + 1):
|
||||||
|
print(f'Joining user {i} to session {session_name}')
|
||||||
|
driver.execute_script(f'window.open("{url_link}", "_blank");')
|
||||||
|
driver.switch_to.window(driver.window_handles[-1])
|
||||||
|
driver.find_element(By.ID, 'join-button').send_keys(Keys.RETURN)
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
driver.switch_to.window(driver.window_handles[0])
|
||||||
|
return session_name
|
||||||
|
|
||||||
|
def call_login(driver, username, password):
|
||||||
|
print('Logging in')
|
||||||
|
driver.find_element(By.NAME, 'username').send_keys(username)
|
||||||
|
driver.find_element(By.NAME, 'password').send_keys(password)
|
||||||
|
driver.find_element(By.ID, 'join-btn').send_keys(Keys.RETURN)
|
||||||
|
|
||||||
|
def close_all_tabs(driver, browser):
|
||||||
|
if browser == 'firefox':
|
||||||
|
# Close all tabs
|
||||||
|
for i in range(0, len(driver.window_handles)):
|
||||||
|
driver.switch_to.window(driver.window_handles[0])
|
||||||
|
driver.close()
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
def is_video_green(url, basic_auth, video_filename):
|
||||||
|
# Download the video from the URL
|
||||||
|
response = requests.get(url, auth=basic_auth, verify=False)
|
||||||
|
open(video_filename, 'wb').write(response.content)
|
||||||
|
|
||||||
|
# Read the video using OpenCV
|
||||||
|
cap = cv2.VideoCapture(video_filename)
|
||||||
|
|
||||||
|
# Parameters to calculate if the video is mostly green
|
||||||
|
total_frames = 0
|
||||||
|
green_frames = 0
|
||||||
|
green_threshold = 0.8
|
||||||
|
|
||||||
|
while cap.isOpened():
|
||||||
|
ret, frame = cap.read()
|
||||||
|
if not ret:
|
||||||
|
break
|
||||||
|
|
||||||
|
total_frames += 1
|
||||||
|
|
||||||
|
# Define green ranges in the RGB color space
|
||||||
|
lower_green = np.array([0, 100, 0])
|
||||||
|
upper_green = np.array([100, 255, 100])
|
||||||
|
|
||||||
|
# Create a mask to select only green pixels
|
||||||
|
mask = cv2.inRange(frame, lower_green, upper_green)
|
||||||
|
|
||||||
|
# Calculate the percentage of green pixels in the frame
|
||||||
|
green_ratio = np.sum(mask == 255) / (mask.shape[0] * mask.shape[1])
|
||||||
|
|
||||||
|
if green_ratio > green_threshold:
|
||||||
|
green_frames += 1
|
||||||
|
|
||||||
|
# Clean up resources
|
||||||
|
cap.release()
|
||||||
|
|
||||||
|
# Remove the video file
|
||||||
|
os.remove(video_filename)
|
||||||
|
|
||||||
|
# Determine if the video is mostly green
|
||||||
|
return green_frames / total_frames > 0.8
|
||||||
|
|
||||||
|
def is_video_valid(url, basic_auth, video_filename):
|
||||||
|
response = requests.get(url, auth=basic_auth, verify=False)
|
||||||
|
open(video_filename, 'wb').write(response.content)
|
||||||
|
try:
|
||||||
|
cmd = ["ffprobe", "-v", "error", "-show_streams", "-select_streams", "v:0", video_filename]
|
||||||
|
output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
|
||||||
|
if output:
|
||||||
|
return True
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"Error: {e}")
|
||||||
|
finally:
|
||||||
|
os.remove(video_filename)
|
Loading…
Reference in New Issue