diff --git a/Makefile b/Makefile index 30afd61cb..b2a220ca6 100644 --- a/Makefile +++ b/Makefile @@ -1202,7 +1202,8 @@ test_node_relay: hub node_base standalone_firefox echo BASE_VERSION=$(BASE_VERSION) >> .env ; \ if [ $$node = "Android" ] ; then \ echo BROWSER=firefox >> .env \ - && echo BROWSER_NAME=firefox >> .env ; \ + && echo BROWSER_NAME=firefox >> .env \ + && echo SELENIUM_ENABLE_MANAGED_DOWNLOADS=false >> .env ; \ fi ; \ if [ $$node = "NodeChrome" ] ; then \ echo BROWSER=chrome >> .env \ @@ -1219,7 +1220,8 @@ test_node_relay: hub node_base standalone_firefox fi ; \ if [ $$node = "NodeFirefox" ] ; then \ echo BROWSER=firefox >> .env \ - && echo BROWSER_NAME=firefox >> .env ; \ + && echo BROWSER_NAME=firefox >> .env \ + && echo SELENIUM_ENABLE_MANAGED_DOWNLOADS=$(or $(SELENIUM_ENABLE_MANAGED_DOWNLOADS), true) >> .env ; \ fi ; \ export $$(cat .env | xargs) ; \ envsubst < relay_config.toml > ./videos/relay_config.toml ; \ @@ -1266,7 +1268,7 @@ test_node_docker: hub standalone_docker standalone_chrome standalone_firefox sta echo TEST_PARALLEL_HARDENING=$(or $(TEST_PARALLEL_HARDENING), "false") >> .env ; \ echo LOG_LEVEL=$(or $(LOG_LEVEL), "INFO") >> .env ; \ echo REQUEST_TIMEOUT=$(or $(REQUEST_TIMEOUT), 300) >> .env ; \ - echo SELENIUM_ENABLE_MANAGED_DOWNLOADS=$(or $(SELENIUM_ENABLE_MANAGED_DOWNLOADS), "false") >> .env ; \ + echo SELENIUM_ENABLE_MANAGED_DOWNLOADS=$(or $(SELENIUM_ENABLE_MANAGED_DOWNLOADS), "true") >> .env ; \ echo TEST_DELAY_AFTER_TEST=$(or $(TEST_DELAY_AFTER_TEST), 0) >> .env ; \ echo RECORD_STANDALONE=$(or $(RECORD_STANDALONE), "true") >> .env ; \ echo SE_UPLOAD_RETAIN_LOCAL_FILE=$(or $(SE_UPLOAD_RETAIN_LOCAL_FILE), "false") >> .env ; \ diff --git a/kubernetes/DynamicGrid/Hub_Node/node-kubernetes-deployment.yaml b/kubernetes/DynamicGrid/Hub_Node/node-kubernetes-deployment.yaml index 25fda268f..6daf3f47c 100644 --- a/kubernetes/DynamicGrid/Hub_Node/node-kubernetes-deployment.yaml +++ b/kubernetes/DynamicGrid/Hub_Node/node-kubernetes-deployment.yaml @@ -40,6 +40,8 @@ spec: value: "10" - name: SE_RECORD_VIDEO value: "true" + - name: SE_NODE_ENABLE_MANAGED_DOWNLOADS + value: "true" resources: requests: memory: "512Mi" diff --git a/kubernetes/DynamicGrid/Standalone/standalone-kubernetes.yaml b/kubernetes/DynamicGrid/Standalone/standalone-kubernetes.yaml index abf27e066..66bd36fa0 100644 --- a/kubernetes/DynamicGrid/Standalone/standalone-kubernetes.yaml +++ b/kubernetes/DynamicGrid/Standalone/standalone-kubernetes.yaml @@ -40,6 +40,8 @@ spec: value: "10" - name: SE_RECORD_VIDEO value: "true" + - name: SE_NODE_ENABLE_MANAGED_DOWNLOADS + value: "true" resources: requests: memory: "512Mi" diff --git a/tests/SeleniumTests/__init__.py b/tests/SeleniumTests/__init__.py index 46a2d4016..0f371af06 100644 --- a/tests/SeleniumTests/__init__.py +++ b/tests/SeleniumTests/__init__.py @@ -1,6 +1,8 @@ import concurrent.futures import os import random +import shutil +import tempfile import time import traceback import unittest @@ -11,6 +13,7 @@ from selenium.webdriver.edge.options import Options as EdgeOptions from selenium.webdriver.firefox.options import Options as FirefoxOptions from selenium.webdriver.remote.client_config import ClientConfig +from selenium.webdriver.remote.file_detector import LocalFileDetector from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait @@ -117,6 +120,31 @@ def test_play_video(self): paused = video.get_property('paused') self.assertFalse(paused) + def test_upload_file(self): + driver = self.driver + # LocalFileDetector transfers the client-side file to the machine running the browser. + if TEST_NODE_RELAY == 'Android': + self.skipTest("HTML file upload via LocalFileDetector is not applicable to the Android emulator relay") + driver.file_detector = LocalFileDetector() + upload_dir = tempfile.mkdtemp() + file_name = 'selenium-upload.txt' + file_path = os.path.join(upload_dir, file_name) + try: + with open(file_path, 'w') as upload_file: + upload_file.write('docker-selenium remote upload test') + driver.get(f'http://{TEST_SITE}/upload') + wait = WebDriverWait(driver, WEB_DRIVER_WAIT_TIMEOUT) + file_input = wait.until(EC.presence_of_element_located((By.ID, 'file-upload'))) + file_input.send_keys(file_path) + driver.find_element(By.ID, 'file-submit').click() + uploaded_files = wait.until(EC.visibility_of_element_located((By.ID, 'uploaded-files'))) + self.assertTrue( + file_name in uploaded_files.text, + f"Uploaded file '{file_name}' not reported by the server, got '{uploaded_files.text}'", + ) + finally: + shutil.rmtree(upload_dir, ignore_errors=True) + def test_download_file(self): driver = self.driver driver.get(f'http://{TEST_SITE}/download') @@ -132,6 +160,15 @@ def test_download_file(self): lambda d: len(d.get_downloadable_files()) > 0 and str(d.get_downloadable_files()[0]).endswith(file_name) ) self.assertTrue(str(driver.get_downloadable_files()[0]).endswith(file_name)) + # Retrieve the managed download to the client to exercise the remote file forwarding. + download_dir = tempfile.mkdtemp() + try: + driver.download_file(file_name, download_dir) + downloaded_file = os.path.join(download_dir, file_name) + self.assertTrue(os.path.isfile(downloaded_file), f"Downloaded file not found at {downloaded_file}") + self.assertGreater(os.path.getsize(downloaded_file), 0, "Downloaded file is empty") + finally: + shutil.rmtree(download_dir, ignore_errors=True) def tearDown(self): if TEST_CUSTOM_SPECIFIC_NAME: diff --git a/tests/docker-compose-v3-test-node-relay.yml b/tests/docker-compose-v3-test-node-relay.yml index 3b695f8e1..e4e59c1c5 100644 --- a/tests/docker-compose-v3-test-node-relay.yml +++ b/tests/docker-compose-v3-test-node-relay.yml @@ -11,13 +11,15 @@ services: - SE_EVENT_BUS_HOST=selenium-hub - SE_LOG_LEVEL=${LOG_LEVEL} - GENERATE_CONFIG=false + - SE_NODE_ENABLE_MANAGED_DOWNLOADS=${SELENIUM_ENABLE_MANAGED_DOWNLOADS:-true} standalone: image: ${NAMESPACE}/standalone-${BROWSER}:${TAG} shm_size: 2gb environment: - - SE_OPTS=--enable-cdp true + - SE_OPTS=--enable-cdp true --enable-managed-downloads ${SELENIUM_ENABLE_MANAGED_DOWNLOADS:-true} - SE_NODE_ENABLE_CDP=true + - SE_NODE_ENABLE_MANAGED_DOWNLOADS=${SELENIUM_ENABLE_MANAGED_DOWNLOADS:-true} selenium-hub: image: ${NAMESPACE}/hub:${TAG} @@ -46,7 +48,7 @@ services: - RUN_IN_DOCKER_COMPOSE=true - SELENIUM_GRID_HOST=selenium-hub - BINDING_VERSION=${BINDING_VERSION} - - SELENIUM_ENABLE_MANAGED_DOWNLOADS=false + - SELENIUM_ENABLE_MANAGED_DOWNLOADS=${SELENIUM_ENABLE_MANAGED_DOWNLOADS:-true} - TEST_NODE_RELAY=${TEST_NODE_RELAY} - ANDROID_PLATFORM_API=${ANDROID_PLATFORM_API} - TEST_DELAY_AFTER_TEST=${TEST_DELAY_AFTER_TEST} diff --git a/tests/k8s/make/dynamic_grid_test.sh b/tests/k8s/make/dynamic_grid_test.sh index 77dc00418..0155ee86f 100755 --- a/tests/k8s/make/dynamic_grid_test.sh +++ b/tests/k8s/make/dynamic_grid_test.sh @@ -237,9 +237,8 @@ export SELENIUM_GRID_PORT=${GRID_LOCAL_PORT} export SELENIUM_GRID_USERNAME=${GRID_USERNAME} export SELENIUM_GRID_PASSWORD=${GRID_PASSWORD} export SELENIUM_GRID_TEST_HEADLESS=${SELENIUM_GRID_TEST_HEADLESS:-"false"} -# The browser runs in its own Job Pod and downloads into it, while the Node serves the -# downloadable files from a Pod local directory, so managed downloads are not retrievable here -export SELENIUM_ENABLE_MANAGED_DOWNLOADS=${SELENIUM_ENABLE_MANAGED_DOWNLOADS:-"false"} +# The Node forwards managed downloads to the browser Job Pod, so they are retrievable here. +export SELENIUM_ENABLE_MANAGED_DOWNLOADS=${SELENIUM_ENABLE_MANAGED_DOWNLOADS:-"true"} export TEST_DELAY_AFTER_TEST=${TEST_DELAY_AFTER_TEST:-"0"} export BINDING_VERSION=${BINDING_VERSION} export BASE_VERSION=${BASE_VERSION} diff --git a/tests/relay_config.toml b/tests/relay_config.toml index 3f89202d4..af58f5665 100755 --- a/tests/relay_config.toml +++ b/tests/relay_config.toml @@ -13,5 +13,5 @@ max-sessions = 1 url = "http://standalone:4444/wd/hub" status-endpoint = "/status" configs = [ - '3', '{"browserName":"${BROWSER_NAME}","platformName":"linux"}' + '3', '{"browserName":"${BROWSER_NAME}","platformName":"linux","se:downloadsEnabled":${SELENIUM_ENABLE_MANAGED_DOWNLOADS}}' ]