Skip to content

Commit 838f721

Browse files
authored
feat: video record and upload for standalone and dynamic grid (#2362)
* test: add test for video uploader with RCLONE * Update Video/video_gridUrl.sh --------- Signed-off-by: Viet Nguyen Duc <[email protected]>
1 parent 0a4a778 commit 838f721

25 files changed

+644
-194
lines changed

.circleci/config.yml

+6
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ workflows:
8181
use-random-user: false
8282
platforms: linux/arm64
8383
machine-type: ubuntu2204arm64
84+
- docker-test:
85+
name: "Docker test - Video recording standalone"
86+
test-strategy: test_video_standalone
87+
use-random-user: false
88+
platforms: linux/arm64
89+
machine-type: ubuntu2204arm64
8490
- docker-test:
8591
name: "Docker test - Dynamic Grid"
8692
test-strategy: test_node_docker

.github/workflows/docker-test.yml

+4
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ jobs:
5050
use-random-user: false
5151
test-video: true
5252
build-all: false
53+
- test-strategy: test_video_standalone
54+
use-random-user: false
55+
test-video: true
56+
build-all: false
5357
- test-strategy: test_node_docker
5458
use-random-user: false
5559
test-video: true

Makefile

+45-65
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,14 @@ build: all
6767

6868
ci: build test
6969

70-
gen_certs:
70+
prepare_resources:
7171
rm -rf ./Base/configs/node && mkdir -p ./Base/configs/node && cp -r ./charts/selenium-grid/configs/node ./Base/configs
72+
73+
gen_certs:
7274
rm -rf ./Base/certs && cp -r ./charts/selenium-grid/certs ./Base
7375
./Base/certs/gen-cert-helper.sh -d ./Base/certs
7476

75-
base: gen_certs
77+
base: prepare_resources gen_certs
7678
cd ./Base && docker buildx build --platform $(PLATFORMS) $(BUILD_ARGS) --build-arg VERSION=$(BASE_VERSION) --build-arg RELEASE=$(BASE_RELEASE) --build-arg AUTHORS=$(AUTHORS) -t $(NAME)/base:$(TAG_VERSION) .
7779

7880
base_nightly:
@@ -580,24 +582,31 @@ test_parallel: hub chrome firefox edge chromium
580582
echo SELENIUM_GRID_PROTOCOL=https >> .env ; \
581583
echo CHART_CERT_PATH=$$(readlink -f ./videos/certs/tls.crt) >> .env ; \
582584
export $$(cat .env | xargs) ; \
583-
DOCKER_DEFAULT_PLATFORM=$(PLATFORMS) docker compose --profile $(PLATFORMS) -f docker-compose-v3-test-parallel.yml up -d --no-log-prefix ; \
585+
DOCKER_DEFAULT_PLATFORM=$(PLATFORMS) docker compose --profile $(PLATFORMS) -f docker-compose-v3-test-parallel.yml up -d --remove-orphans --no-log-prefix ; \
584586
RUN_IN_DOCKER_COMPOSE=true bash ./bootstrap.sh $$node ; \
585587
done ; \
586588
docker compose -f docker-compose-v3-test-parallel.yml down
587589

590+
test_video_standalone: standalone_chrome standalone_chromium standalone_firefox standalone_edge
591+
DOCKER_COMPOSE_FILE=docker-compose-v3-test-standalone.yml make test_video
592+
588593
test_video_dynamic_name:
589-
VIDEO_FILE_NAME=auto TEST_DELAY_AFTER_TEST=0 \
594+
VIDEO_FILE_NAME=auto \
590595
make test_video
591596

592597
# This should run on its own CI job. There is no need to combine it with the other tests.
593598
# Its main purpose is to check that a video file was generated.
594599
test_video: video hub chrome firefox edge chromium
595600
sudo rm -rf ./tests/tests
596-
sudo rm -rf ./tests/videos; mkdir -p ./tests/videos
601+
sudo rm -rf ./tests/videos; mkdir -p ./tests/videos/upload
602+
sudo chmod -R 777 ./tests/videos
603+
docker_compose_file=$(or $(DOCKER_COMPOSE_FILE), docker-compose-v3-test-video.yml) ; \
604+
list_of_tests_amd64=$(or $(LIST_OF_TESTS_AMD64), "NodeChrome NodeChromium NodeFirefox NodeEdge") ; \
605+
list_of_tests_arm64=$(or $(LIST_OF_TESTS_ARM64), "NodeChromium NodeFirefox") ; \
597606
if [ "$(PLATFORMS)" = "linux/amd64" ]; then \
598-
list_nodes="NodeChrome NodeChromium NodeFirefox NodeEdge" ; \
607+
list_nodes="$${list_of_tests_amd64}" ; \
599608
else \
600-
list_nodes="NodeChromium NodeFirefox" ; \
609+
list_nodes="${list_of_tests_arm64}" ; \
601610
fi; \
602611
for node in $${list_nodes}; do \
603612
cd ./tests || true ; \
@@ -607,6 +616,10 @@ test_video: video hub chrome firefox edge chromium
607616
echo UID=$$(id -u) >> .env ; \
608617
echo BINDING_VERSION=$(BINDING_VERSION) >> .env ; \
609618
echo TEST_DELAY_AFTER_TEST=$(or $(TEST_DELAY_AFTER_TEST), 0) >> .env ; \
619+
echo SELENIUM_ENABLE_MANAGED_DOWNLOADS=$(or $(SELENIUM_ENABLE_MANAGED_DOWNLOADS), "true") >> .env ; \
620+
echo BASIC_AUTH_USERNAME=$(or $(BASIC_AUTH_USERNAME), "admin") >> .env ; \
621+
echo BASIC_AUTH_PASSWORD=$(or $(BASIC_AUTH_PASSWORD), "admin") >> .env ; \
622+
echo SUB_PATH=$(or $(SUB_PATH), "/selenium") >> .env ; \
610623
if [ $$node = "NodeChrome" ] ; then \
611624
echo BROWSER=chrome >> .env ; \
612625
echo VIDEO_FILE_NAME=$${VIDEO_FILE_NAME:-"chrome_video.mp4"} >> .env ; \
@@ -627,7 +640,7 @@ test_video: video hub chrome firefox edge chromium
627640
echo VIDEO_FILE_NAME=$${VIDEO_FILE_NAME:-"firefox_video.mp4"} >> .env ; \
628641
echo VIDEO_FILE_NAME_SUFFIX=$${VIDEO_FILE_NAME_SUFFIX:-"true"} >> .env ; \
629642
fi ; \
630-
DOCKER_DEFAULT_PLATFORM=$(PLATFORMS) docker compose -f docker-compose-v3-test-video.yml up --abort-on-container-exit ; \
643+
DOCKER_DEFAULT_PLATFORM=$(PLATFORMS) docker compose -f $${docker_compose_file} up --remove-orphans --build --exit-code-from tests ; \
631644
done
632645
make test_video_integrity
633646

@@ -676,18 +689,27 @@ test_node_relay: hub node_base standalone_firefox
676689
fi ; \
677690
export $$(cat .env | xargs) ; \
678691
envsubst < relay_config.toml > ./videos/relay_config.toml ; \
679-
DOCKER_DEFAULT_PLATFORM=$(PLATFORMS) docker compose --profile $$node -f docker-compose-v3-test-node-relay.yml up --no-log-prefix --exit-code-from tests ; \
692+
DOCKER_DEFAULT_PLATFORM=$(PLATFORMS) docker compose --profile $$node -f docker-compose-v3-test-node-relay.yml up --remove-orphans --no-log-prefix --build --exit-code-from tests ; \
680693
if [ $$? -ne 0 ]; then exit 1; fi ; \
681694
done
682695

696+
test_standalone_docker: standalone_docker
697+
DOCKER_COMPOSE_FILE=docker-compose-v3-test-standalone-docker.yaml CONFIG_FILE=standalone_docker_config.toml \
698+
RECORD_STANDALONE=true GRID_URL=http://0.0.0.0:4444 LIST_OF_TESTS_AMD64="DeploymentAutoscaling" TEST_PARALLEL_HARDENING=true \
699+
SELENIUM_ENABLE_MANAGED_DOWNLOADS=true LOG_LEVEL=SEVERE SKIP_CHECK_DOWNLOADS_VOLUME=true make test_node_docker
700+
683701
test_node_docker: hub standalone_docker standalone_chrome standalone_firefox standalone_edge standalone_chromium video
684702
sudo rm -rf ./tests/tests
685-
sudo rm -rf ./tests/videos; mkdir -p ./tests/videos/Downloads
703+
sudo rm -rf ./tests/videos; mkdir -p ./tests/videos/Downloads; mkdir -p ./tests/videos/upload
686704
sudo chmod -R 777 ./tests/videos
705+
docker_compose_file=$(or $(DOCKER_COMPOSE_FILE), docker-compose-v3-test-node-docker.yaml) ; \
706+
config_file=$(or $(CONFIG_FILE), config.toml) ; \
707+
list_of_tests_amd64=$(or $(LIST_OF_TESTS_AMD64), "NodeChrome NodeChromium NodeFirefox NodeEdge") ; \
708+
list_of_tests_arm64=$(or $(LIST_OF_TESTS_ARM64), "NodeChromium NodeFirefox") ; \
687709
if [ "$(PLATFORMS)" = "linux/amd64" ]; then \
688-
list_nodes="NodeChrome NodeChromium NodeFirefox NodeEdge" ; \
710+
list_nodes="$${list_of_tests_amd64}" ; \
689711
else \
690-
list_nodes="NodeChromium NodeFirefox" ; \
712+
list_nodes="$${list_of_tests_arm64}" ; \
691713
fi; \
692714
for node in $${list_nodes} ; do \
693715
cd tests || true ; \
@@ -702,6 +724,8 @@ test_node_docker: hub standalone_docker standalone_chrome standalone_firefox sta
702724
echo REQUEST_TIMEOUT=$(or $(REQUEST_TIMEOUT), 300) >> .env ; \
703725
echo SELENIUM_ENABLE_MANAGED_DOWNLOADS=$(or $(SELENIUM_ENABLE_MANAGED_DOWNLOADS), "false") >> .env ; \
704726
echo TEST_DELAY_AFTER_TEST=$(or $(TEST_DELAY_AFTER_TEST), 0) >> .env ; \
727+
echo RECORD_STANDALONE=$(or $(RECORD_STANDALONE), "true") >> .env ; \
728+
echo GRID_URL=$(or $(GRID_URL), "") >> .env ; \
705729
echo NODE=$$node >> .env ; \
706730
echo UID=$$(id -u) >> .env ; \
707731
echo BINDING_VERSION=$(BINDING_VERSION) >> .env ; \
@@ -716,64 +740,20 @@ test_node_docker: hub standalone_docker standalone_chrome standalone_firefox sta
716740
fi ; \
717741
if [ $$node = "NodeChromium" ] ; then \
718742
echo NODE_CHROME=chromium >> .env ; \
743+
else \
744+
echo NODE_CHROME=chromium >> .env ; \
719745
fi ; \
720746
export $$(cat .env | xargs) ; \
721-
envsubst < config.toml > ./videos/config.toml ; \
722-
DOCKER_DEFAULT_PLATFORM=$(PLATFORMS) docker compose -f docker-compose-v3-test-node-docker.yaml up --no-log-prefix --exit-code-from tests ; \
747+
envsubst < $${config_file} > ./videos/config.toml ; \
748+
DOCKER_DEFAULT_PLATFORM=$(PLATFORMS) docker compose -f $${docker_compose_file} up --remove-orphans --no-log-prefix --build --exit-code-from tests ; \
723749
if [ $$? -ne 0 ]; then exit 1; fi ; \
724-
if [ -d "$$DOWNLOADS_DIR" ] && [ $$(ls -1q $$DOWNLOADS_DIR | wc -l) -eq 0 ]; then \
750+
if [ "$$SKIP_CHECK_DOWNLOADS_VOLUME" != "true" ] && [ -d "$$DOWNLOADS_DIR" ] && [ $$(ls -1q $$DOWNLOADS_DIR | wc -l) -eq 0 ]; then \
725751
echo "Mounted downloads directory is empty. Downloaded files could not be retrieved!" ; \
726752
exit 1 ; \
727753
fi ; \
728754
done
729755
make test_video_integrity
730756

731-
test_standalone_docker: standalone_docker standalone_chrome standalone_firefox standalone_edge standalone_chromium video
732-
sudo rm -rf ./tests/tests
733-
sudo rm -rf ./tests/videos; mkdir -p ./tests/videos/Downloads
734-
sudo chmod -R 777 ./tests/videos
735-
if [ "$(PLATFORMS)" = "linux/amd64" ]; then \
736-
list_nodes="DeploymentAutoscaling" ; \
737-
else \
738-
list_nodes="NodeChromium NodeFirefox" ; \
739-
fi; \
740-
for node in $${list_nodes} ; do \
741-
cd tests || true ; \
742-
DOWNLOADS_DIR="./videos/Downloads" ; \
743-
sudo rm -rf $$DOWNLOADS_DIR/* ; \
744-
echo NAMESPACE=$(NAME) > .env ; \
745-
echo TAG=$(TAG_VERSION) >> .env ; \
746-
echo VIDEO_TAG=$(FFMPEG_TAG_VERSION)-$(BUILD_DATE) >> .env ; \
747-
echo TEST_DRAIN_AFTER_SESSION_COUNT=$(or $(TEST_DRAIN_AFTER_SESSION_COUNT), 0) >> .env ; \
748-
echo TEST_PARALLEL_HARDENING=$(or $(TEST_PARALLEL_HARDENING), "true") >> .env ; \
749-
echo LOG_LEVEL=$(or $(LOG_LEVEL), "INFO") >> .env ; \
750-
echo REQUEST_TIMEOUT=$(or $(REQUEST_TIMEOUT), 300) >> .env ; \
751-
echo SELENIUM_ENABLE_MANAGED_DOWNLOADS=$(or $(SELENIUM_ENABLE_MANAGED_DOWNLOADS), "true") >> .env ; \
752-
echo TEST_DELAY_AFTER_TEST=$(or $(TEST_DELAY_AFTER_TEST), 0) >> .env ; \
753-
echo NODE=$$node >> .env ; \
754-
echo UID=$$(id -u) >> .env ; \
755-
echo BINDING_VERSION=$(BINDING_VERSION) >> .env ; \
756-
echo HOST_IP=$$(hostname -I | awk '{print $$1}') >> .env ; \
757-
if [ "$(PLATFORMS)" = "linux/amd64" ]; then \
758-
echo NODE_EDGE=edge >> .env ; \
759-
else \
760-
echo NODE_EDGE=chromium >> .env ; \
761-
fi; \
762-
if [ $$node = "NodeChrome" ] ; then \
763-
echo NODE_CHROME=chrome >> .env ; \
764-
fi ; \
765-
if [ $$node = "NodeChromium" ] ; then \
766-
echo NODE_CHROME=chromium >> .env ; \
767-
else \
768-
echo NODE_CHROME=chromium >> .env ; \
769-
fi ; \
770-
export $$(cat .env | xargs) ; \
771-
envsubst < standalone_docker_config.toml > ./videos/config.toml ; \
772-
DOCKER_DEFAULT_PLATFORM=$(PLATFORMS) docker compose -f docker-compose-v3-test-standalone-docker.yaml up --no-log-prefix --build --exit-code-from tests ; \
773-
if [ $$? -ne 0 ]; then exit 1; fi ; \
774-
done
775-
make test_video_integrity
776-
777757
test_custom_ca_cert:
778758
VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/customCACert/bootstrap.sh
779759

@@ -800,7 +780,7 @@ test_video_integrity:
800780
# Using ffmpeg to verify file integrity
801781
# https://superuser.com/questions/100288/how-can-i-check-the-integrity-of-a-video-file-avi-mpeg-mp4
802782
list_files=$$(find ./tests/videos -type f -name "*.mp4"); \
803-
echo "Number of video files: $$(echo $$list_files | wc -w)"; \
783+
echo "::warning:: Number of video files: $$(echo $$list_files | wc -w)"; \
804784
number_corrupted_files=0; \
805785
if [ -z "$$list_files" ]; then \
806786
echo "No video files found"; \
@@ -827,8 +807,8 @@ chart_render_template:
827807
RENDER_HELM_TEMPLATE_ONLY=true make chart_test_autoscaling_disabled chart_test_autoscaling_deployment_https chart_test_autoscaling_deployment chart_test_autoscaling_job_https chart_test_autoscaling_job_hostname chart_test_autoscaling_job
828808

829809
chart_test_autoscaling_disabled:
830-
PLATFORMS=$(PLATFORMS) TEST_CHROMIUM=true RELEASE_NAME=selenium SELENIUM_GRID_AUTOSCALING=false TEST_DELAY_AFTER_TEST=0 CHART_ENABLE_TRACING=true \
831-
SECURE_INGRESS_ONLY_GENERATE=true SELENIUM_GRID_PROTOCOL=https SELENIUM_GRID_HOST=$$(hostname -i) SELENIUM_GRID_PORT=443 \
810+
PLATFORMS=$(PLATFORMS) TEST_CHROMIUM=true RELEASE_NAME=selenium SELENIUM_GRID_AUTOSCALING=false CHART_ENABLE_TRACING=true \
811+
SECURE_INGRESS_ONLY_GENERATE=true SELENIUM_GRID_PROTOCOL=https SELENIUM_GRID_HOST=$$(hostname -i) SELENIUM_GRID_PORT=443 EXTERNAL_UPLOADER_CONFIG=true \
832812
VERSION=$(TAG_VERSION) VIDEO_TAG=$(FFMPEG_TAG_VERSION)-$(BUILD_DATE) NAMESPACE=$(NAMESPACE) BINDING_VERSION=$(BINDING_VERSION) \
833813
TEMPLATE_OUTPUT_FILENAME="k8s_nodeChromium_enableTracing_secureIngress_generateCerts_ingressPublicIP_subPath.yaml" \
834814
./tests/charts/make/chart_test.sh NoAutoscaling
@@ -852,7 +832,7 @@ chart_test_autoscaling_deployment:
852832
chart_test_autoscaling_job_https:
853833
PLATFORMS=$(PLATFORMS) TEST_EXISTING_KEDA=true RELEASE_NAME=selenium CHART_ENABLE_BASIC_AUTH=true \
854834
SECURE_CONNECTION_SERVER=true SELENIUM_GRID_PROTOCOL=https SELENIUM_GRID_PORT=443 SUB_PATH=/ \
855-
VERSION=$(TAG_VERSION) VIDEO_TAG=$(FFMPEG_TAG_VERSION)-$(BUILD_DATE) NAMESPACE=$(NAMESPACE) BINDING_VERSION=$(BINDING_VERSION) \
835+
VERSION=$(TAG_VERSION) VIDEO_TAG=$(FFMPEG_TAG_VERSION)-$(BUILD_DATE) NAMESPACE=$(NAMESPACE) BINDING_VERSION=$(BINDING_VERSION) EXTERNAL_UPLOADER_CONFIG=true \
856836
TEMPLATE_OUTPUT_FILENAME="k8s_prefixSelenium_basicAuth_secureServer_autoScaling_scaledJob_existingKEDA.yaml" \
857837
./tests/charts/make/chart_test.sh JobAutoscaling
858838

NodeFirefox/Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ RUN if [ "$(dpkg --print-architecture)" = "amd64" ]; then \
3131
# GeckoDriver
3232
#============
3333
ARG GECKODRIVER_VERSION=latest
34-
RUN LATEST_VERSION=$(curl -s https://api.github.com/repos/mozilla/geckodriver/releases/latest | jq -r '.tag_name') \
34+
RUN LATEST_VERSION=$(curl -sk https://api.github.com/repos/mozilla/geckodriver/releases/latest | jq -r '.tag_name') \
3535
&& DRIVER_ARCH=$(if [ "$(dpkg --print-architecture)" = "amd64" ]; then echo "linux64"; else echo "linux-aarch64"; fi) \
3636
&& GK_VERSION=$(if [ ${GECKODRIVER_VERSION:-latest} = "latest" ]; then echo "${LATEST_VERSION}"; else echo $GECKODRIVER_VERSION; fi) \
3737
&& echo "Using GeckoDriver version: "$GK_VERSION \

README.md

+16-2
Original file line numberDiff line numberDiff line change
@@ -685,16 +685,30 @@ services:
685685
```
686686
687687
`SE_VIDEO_FILE_NAME=auto` will use the session id as the video file name. This ensures that the video file name is unique to upload.
688+
Video file name construction automatically works based on Node endpoint `/status` (and optional GraphQL endpoint) to get session ID, capabilities.
689+
690+
| | Hub/Nodes | Standalone roles | Dynamic Grid |
691+
|------------------------------------------|-------------------|------------------|----------------|
692+
| `SE_VIDEO_RECORD_STANDALONE` (mandatory) | `false` (default) | `true` | user input |
693+
| `DISPLAY_CONTAINER_NAME` (mandatory) | user input | user input | (not required) |
694+
| `SE_NODE_PORT` (optional) | `5555` | `4444` | (not required) |
695+
| `SE_NODE_GRID_URL` (optional) | user input | (not required) | (not required) |
688696

689697
`SE_VIDEO_UPLOAD_ENABLED=true` will enable the video upload feature. In the background, it will create a pipefile with file and destination for uploader to consume and proceed.
690698

691699
`SE_VIDEO_INTERNAL_UPLOAD=true` will use RCLONE installed in the container for upload. If you want to use another container for upload, set it to `false`.
692700

693701
For environment variables with prefix `RCLONE_` is used to pass remote configuration to RCLONE. You can find more information about RCLONE configuration [here](https://rclone.org/docs/).
702+
When using in Dynamic Grid, those variables should be combined with the prefix `SE_`, for example `SE_RCLONE_`. See below reference for more details.
703+
704+
### Reference
705+
- Configure video recording and uploading for Hub and Nodes: [docker-compose-v3-video-upload.yml](docker-compose-v3-video-upload.yml)
706+
707+
- Configure video recording and uploading for Standalone roles: [docker-compose-v3-video-upload-standalone.yml](docker-compose-v3-video-upload-standalone.yml)
694708

695-
[`docker-compose-v3-video-upload.yml`](docker-compose-v3-video-upload.yml)
709+
- Configure video recording and uploading for Dynamic Grid (node-docker): [docker-compose-v3-video-upload-dynamic-grid.yml](docker-compose-v3-video-upload-dynamic-grid.yml)
696710

697-
Note that upload function is not supported for Dynamic Grid. If you want it, please create a feature request.
711+
- Configure video recording and uploading for Dynamic Grid standalone (standalone-docker): [tests/docker-compose-v3-test-standalone-docker.yaml](tests/docker-compose-v3-test-standalone-docker.yaml)
698712

699713
___
700714

Video/Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ RUN groupadd ${SEL_GROUP} \
7272
# Add Supervisor configuration files
7373
#======================================
7474
COPY supervisord.conf /etc
75-
COPY --chown="${SEL_UID}:${SEL_GID}" entry_point.sh video.sh video_ready.py video_graphQLQuery.sh /opt/bin/
75+
COPY --chown="${SEL_UID}:${SEL_GID}" entry_point.sh video.sh video_ready.py video_graphQLQuery.sh video_gridUrl.sh /opt/bin/
7676

7777
#======================================
7878
# Add RCLONE for uploading videos

Video/supervisord.conf

+5-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ stdout_logfile_maxbytes=0
2828
[program:video-ready]
2929
priority=5
3030
command=python3 /opt/bin/video_ready.py
31+
stopasgroup = true
32+
killasgroup=true
3133
autostart=true
3234
autorestart=true
3335

@@ -38,7 +40,9 @@ stdout_logfile_maxbytes=0
3840

3941
[program:video-upload]
4042
priority=10
41-
command=bash -c "if [ ${SE_VIDEO_INTERNAL_UPLOAD} = "true" ]; then /opt/bin/upload.sh; fi"
43+
command=/opt/bin/upload.sh
44+
stopasgroup = true
45+
killasgroup=true
4246
autostart=%(ENV_SE_VIDEO_INTERNAL_UPLOAD)s
4347
autorestart=%(ENV_SE_VIDEO_INTERNAL_UPLOAD)s
4448

0 commit comments

Comments
 (0)