Automate daily tests of ZIM behavior - Youtube only for now

This commit is contained in:
benoit74 2024-07-22 07:07:12 +00:00
parent 751e10473a
commit 6d078c4dcf
No known key found for this signature in database
GPG Key ID: B89606434FC7B530
5 changed files with 228 additions and 0 deletions

27
.github/workflows/DailyTests.yaml vendored Normal file
View File

@ -0,0 +1,27 @@
name: DailyTests
on:
schedule:
- cron: "0 4 * * *"
workflow_dispatch:
jobs:
run-daily-tests:
runs-on: ubuntu-22.04
steps:
- name: checkout
uses: actions/checkout@v4
- name: build zimit image
run: docker build -t local-zimit .
- name: run crawl of test website
run: docker run -v $PWD/output3:/output local-zimit zimit --url https://website.test.openzim.org/ --name tests_eng_test-website --zim-file tests_eng_test-website.zim
- name: build selenium test image
run: docker build -t local-selenium tests-daily
- name: run integration test suite
run: docker run -v $PWD/tests-daily/daily.py:/app/daily.py -v $PWD/output3:/output local-selenium bash -c "cd /app && pytest -h && pytest -v --log-level=INFO --log-format='%(levelname)s - %(message)s' daily.py"

View File

@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Add `--custom-behaviors` argument to support path/HTTP(S) URL custom behaviors to pass to the crawler (#313)
- Add daily automated end-to-end tests of a page with Youtube player (#330)
### Changed

View File

@ -39,6 +39,7 @@ test = [
dev = [
"pre-commit==3.7.1",
"debugpy==1.8.1",
"selenium==4.23.0", # used in daily tests, convenient for dev purpose (autocompletion)
"zimit[scripts]",
"zimit[lint]",
"zimit[test]",

75
tests-daily/Dockerfile Normal file
View File

@ -0,0 +1,75 @@
# Let's extract kiwix-tools as usual on alpine temporary build container
FROM alpine:3.18 as kiwix-serve
LABEL org.opencontainers.image.source https://github.com/openzim/kiwix-tools
# TARGETPLATFORM is injected by docker build
ARG TARGETPLATFORM
ARG KIWIX_TOOLS_VERSION
RUN set -e && \
# default (no KIWIX_TOOLS_VERSION set) to today's nightly
if [ -z "$KIWIX_TOOLS_VERSION" ] ; then KIWIX_TOOLS_VERSION=$(date +"%Y-%m-%d") ; fi && \
apk --no-cache add dumb-init curl && \
echo "TARGETPLATFORM: $TARGETPLATFORM" && \
if [ "$TARGETPLATFORM" = "linux/386" ]; then ARCH="i586"; \
# linux/arm64/v8 points to linux/arm64
elif [ "$TARGETPLATFORM" = "linux/arm64/v8" \
-o "$TARGETPLATFORM" = "linux/arm64" ]; then ARCH="aarch64"; \
# linux/arm translates to linux/arm/v7
elif [ "$TARGETPLATFORM" = "linux/arm/v7" ]; then ARCH="armv8"; \
elif [ "$TARGETPLATFORM" = "linux/arm/v6" ]; then ARCH="armv6"; \
elif [ "$TARGETPLATFORM" = "linux/amd64/v3" \
-o "$TARGETPLATFORM" = "linux/amd64/v2" \
-o "$TARGETPLATFORM" = "linux/amd64" ]; then ARCH="x86_64"; \
# we dont suppot any other arch so let it fail
else ARCH="unknown"; fi && \
# download requested kiwix-tools version
url="http://mirror.download.kiwix.org/nightly/$KIWIX_TOOLS_VERSION/kiwix-tools_linux-$ARCH-$KIWIX_TOOLS_VERSION.tar.gz" && \
echo "URL: $url" && \
mkdir /kiwix-serve && \
curl -k -L $url | tar -xz -C /kiwix-serve --strip-components 1
# Build real "workload" container
FROM python:3.12-slim-bookworm
# Add kiwix-serve
COPY --from=kiwix-serve /kiwix-serve /usr/local/bin
# Update apt + install dependencies + install Google Chrome dependencies + clean-up apt lists
RUN apt-get update -y && \
apt-get install -qqy wget xvfb unzip jq && \
apt-get install -qqy libxss1 libappindicator1 libgconf-2-4 \
fonts-liberation libasound2 libnspr4 libnss3 libx11-xcb1 libxtst6 lsb-release xdg-utils \
libgbm1 libnss3 libatk-bridge2.0-0 libgtk-3-0 libx11-xcb1 libxcb-dri3-0 && \
rm -rf /var/lib/apt/lists/*
# Fetch the latest version numbers and URLs for Chrome and ChromeDriver
RUN wget -q -O /tmp/versions.json https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions-with-downloads.json
# Install chrome
RUN CHROME_URL=$(jq -r '.channels.Stable.downloads.chrome[] | select(.platform=="linux64") | .url' /tmp/versions.json) && \
wget -q --continue -O /tmp/chrome-linux64.zip $CHROME_URL && \
unzip /tmp/chrome-linux64.zip -d /opt/chrome
RUN chmod +x /opt/chrome/chrome-linux64/chrome
# Install chromedriver
RUN CHROMEDRIVER_URL=$(jq -r '.channels.Stable.downloads.chromedriver[] | select(.platform=="linux64") | .url' /tmp/versions.json) && \
wget -q --continue -O /tmp/chromedriver-linux64.zip $CHROMEDRIVER_URL && \
unzip /tmp/chromedriver-linux64.zip -d /opt/chromedriver && \
chmod +x /opt/chromedriver/chromedriver-linux64/chromedriver
# Set up Chromedriver Environment variables
ENV CHROMEDRIVER_DIR /opt/chromedriver
ENV PATH $CHROMEDRIVER_DIR:$PATH
# Clean up
RUN rm /tmp/chrome-linux64.zip /tmp/chromedriver-linux64.zip /tmp/versions.json
# Update pip, install selenium, create work directory
RUN \
python -m pip install --no-cache-dir -U \
pip \
selenium==4.23.0 \
pytest==8.2.2 \
&& mkdir -p /work

124
tests-daily/daily.py Normal file
View File

@ -0,0 +1,124 @@
import logging
import subprocess
from time import sleep
import pytest
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.ui import WebDriverWait
KIWIX_SERVE_START_SLEEP = 1
ZIM_NAME = "tests_eng_test-website"
YOUTUBE_VIDEO_PATH = "youtube.fuzzy.replayweb.page/embed/g5skcrNXdDM"
CHECK_VIDEO_IS_PLAYING_AFTER_SECS = 30
logger = logging.getLogger(__name__)
@pytest.fixture(scope="module")
def chrome_driver():
"""Start chrome and setup chrome driver / selenium"""
logger.info("Starting Chrome")
chrome_options = Options()
chrome_options.add_argument("--headless")
chrome_options.add_argument("--no-sandbox")
# Other options of interest:
# --disable-dev-shm-usage (not needed anymore with recent chrome versions)
# --disable-gpu (important for some versions of Chrome)
# --remote-debugging-port=9222 (should you need to remote debug)
# Set path to Chrome binary
chrome_options.binary_location = "/opt/chrome/chrome-linux64/chrome"
# Set path to ChromeDriver
chrome_service = ChromeService(
executable_path="/opt/chromedriver/chromedriver-linux64/chromedriver"
)
# Set up driver
driver = webdriver.Chrome(service=chrome_service, options=chrome_options)
yield driver
# Cleanup
logger.info("Quitting Chrome")
driver.quit()
@pytest.fixture(scope="module")
def kiwix_serve():
"""Start kiwix-serve with given ZIM"""
logger.info("Starting kiwix-serve")
process = subprocess.Popen(
[
"/usr/bin/env",
"/usr/local/bin/kiwix-serve",
f"/output/{ZIM_NAME}.zim",
]
)
logger.info(
f"Waiting {KIWIX_SERVE_START_SLEEP} secs to be 'sure' that kiwix-serve is ready"
)
sleep(KIWIX_SERVE_START_SLEEP)
if process.poll() is not None:
raise Exception("kiwix-serve has terminated too early")
yield process
# Cleanup
logger.info("Quitting kiwix-serve")
process.terminate()
def test_youtube_video(chrome_driver, kiwix_serve): # noqa: ARG001
"""Test that youtube video loads, and still plays after a while"""
chrome_driver.get(f"http://localhost:80/content/{ZIM_NAME}/{YOUTUBE_VIDEO_PATH}")
if chrome_driver.title == "Content not found":
raise Exception("Wrong URL, kiwix-serve said that content is not found")
button = WebDriverWait(chrome_driver, 1).until(
expected_conditions.presence_of_element_located(
(By.XPATH, "//button[@title='Play']")
)
)
logger.info("Play button found in page")
button.click()
video = WebDriverWait(chrome_driver, 1).until(
expected_conditions.presence_of_element_located((By.TAG_NAME, "video"))
)
logger.info("Video found in page")
# arguments[0] is the video tag passed to execute_script
if not chrome_driver.execute_script("return arguments[0].paused === false", video):
raise Exception("Video is not playing, failed to start probably")
logger.info("Video is playing")
logger.info(
f"Waiting {CHECK_VIDEO_IS_PLAYING_AFTER_SECS} secs to check video is still "
"playing"
)
sleep(CHECK_VIDEO_IS_PLAYING_AFTER_SECS)
# arguments[0] is the video tag passed to execute_script
if not chrome_driver.execute_script("return arguments[0].paused === false", video):
raise Exception(
"Video is not playing anymore after "
f"{CHECK_VIDEO_IS_PLAYING_AFTER_SECS} secs"
)
logger.info("Video is still playing")