Skip to content

Commit

Permalink
[feat][test]: add env vars to generate config for Relay in node-base
Browse files Browse the repository at this point in the history
Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
  • Loading branch information
VietND96 committed May 10, 2024
1 parent 739ebea commit 39cd636
Show file tree
Hide file tree
Showing 16 changed files with 260 additions and 21 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ jobs:
- name: Set Selenium base version
if: contains(toJson(github.event.commits), '[deploy]') == false
run: |
make set_nightly_env
make set_build_nightly
cat .env | xargs -I {} echo {} >> $GITHUB_ENV
- name: Sets build date
run: |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ on:
pull_request:
paths-ignore:
- '**.md'
schedule:
- cron: '0 0 * * *'

permissions:
contents: read
Expand All @@ -45,6 +43,8 @@ jobs:
test-video: true
- test-strategy: test_parallel
test-video: false
- test-strategy: test_node_relay
test-video: false
steps:
- uses: actions/checkout@main
- name: Set up QEMU
Expand All @@ -61,6 +61,12 @@ jobs:
with:
python-version: '3.11'
check-latest: true
- name: Enable KVM
if: matrix.test-strategy == 'test_node_relay'
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Get branch name (only for push to branch)
if: github.event_name == 'push'
run: echo "BRANCH=$(echo ${PUSH_BRANCH##*/})" >> $GITHUB_ENV
Expand All @@ -76,7 +82,7 @@ jobs:
- name: Set Selenium base version
if: contains(toJson(github.event.commits), '[deploy]') == false
run: |
make set_nightly_env
make set_build_nightly
cat .env | xargs -I {} echo {} >> $GITHUB_ENV
- name: Sets build date
run: |
Expand Down
4 changes: 1 addition & 3 deletions .github/workflows/helm-chart-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ on:
description: 'Test parameter for different log level'
required: false
default: 'FINE'
schedule:
- cron: '0 0 * * *'

permissions:
contents: read
Expand Down Expand Up @@ -111,7 +109,7 @@ jobs:
- name: Set Selenium base version
if: contains(toJson(github.event.commits), '[deploy]') == false
run: |
make set_nightly_env
make set_build_nightly
cat .env | xargs -I {} echo {} >> $GITHUB_ENV
- name: Sets build date
run: |
Expand Down
9 changes: 9 additions & 0 deletions .github/workflows/nightly.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,16 @@ on:
- cron: '0 1 * * *'

jobs:
docker-test:
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
uses: ./.github/workflows/docker-test.yml

helm-chart-test:
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
uses: ./.github/workflows/helm-chart-test.yml

deploy:
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
name: Nightly build
runs-on: ubuntu-latest
permissions: write-all
Expand Down
24 changes: 23 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,10 @@ all: hub \
standalone_docker \
video

set_nightly_env:
set_build_nightly:
echo BASE_VERSION=$(BASE_VERSION_NIGHTLY) > .env ; \
echo BASE_RELEASE=$(BASE_RELEASE_NIGHTLY) >> .env ;
echo "Execute 'source .env' to set the environment variables"

docker_buildx_setup:
sudo apt-get install --upgrade docker-buildx-plugin
Expand Down Expand Up @@ -484,6 +485,27 @@ test_video: video hub chrome firefox edge
done
make test_video_integrity

test_node_relay: hub node_base standalone_firefox
sudo rm -rf ./tests/tests
for node in Android NodeFirefox ; do \
cd ./tests || true ; \
echo TAG=$(TAG_VERSION) > .env ; \
echo LOG_LEVEL=$(or $(LOG_LEVEL), "INFO") >> .env ; \
echo REQUEST_TIMEOUT=$(or $(REQUEST_TIMEOUT), 300) >> .env ; \
echo SESSION_TIMEOUT=$(or $(SESSION_TIMEOUT), 300) >> .env ; \
echo ANDROID_BASED_NAME=$(or $(ANDROID_BASED_NAME),budtmo) >> .env ; \
echo ANDROID_BASED_IMAGE=$(or $(ANDROID_BASED_IMAGE),docker-android) >> .env ; \
echo ANDROID_BASED_TAG=$(or $(ANDROID_BASED_TAG),emulator_14.0) >> .env ; \
echo ANDROID_PLATFORM_API=$(or $(ANDROID_PLATFORM_API),14) >> .env ; \
echo TEST_DELAY_AFTER_TEST=$(or $(TEST_DELAY_AFTER_TEST), 15) >> .env ; \
echo NODE=$$node >> .env ; \
echo TEST_NODE_RELAY=$$node >> .env ; \
echo UID=$$(id -u) >> .env ; \
echo BINDING_VERSION=$(BINDING_VERSION) >> .env ; \
docker compose -f docker-compose-v3-test-node-relay.yml up --no-log-prefix --exit-code-from tests --build ; \
if [ $$? -ne 0 ]; then exit 1; fi ; \
done

test_node_docker: hub standalone_docker standalone_chrome standalone_firefox standalone_edge video
sudo rm -rf ./tests/tests
sudo rm -rf ./tests/videos; mkdir -p ./tests/videos/Downloads
Expand Down
2 changes: 1 addition & 1 deletion NodeBase/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ COPY --chown="${SEL_UID}:${SEL_GID}" start-selenium-node.sh \
start-xvfb.sh \
start-vnc.sh \
start-novnc.sh \
generate_config /opt/bin/
generate_config generate_relay_config /opt/bin/

# Selenium Grid logo as wallpaper for Fluxbox
COPY selenium_grid_logo.png /usr/share/images/fluxbox/ubuntu-light.png
Expand Down
34 changes: 22 additions & 12 deletions NodeBase/generate_config
Original file line number Diff line number Diff line change
Expand Up @@ -48,24 +48,34 @@ echo "session-timeout = \"${SE_NODE_SESSION_TIMEOUT}\"" >> "$FILENAME"
echo "override-max-sessions = ${SE_NODE_OVERRIDE_MAX_SESSIONS}" >> "$FILENAME"
echo "detect-drivers = false" >> "$FILENAME"
echo "drain-after-session-count = ${DRAIN_AFTER_SESSION_COUNT:-$SE_DRAIN_AFTER_SESSION_COUNT}" >> "$FILENAME"
echo "max-sessions = ${SE_NODE_MAX_SESSIONS}
# When node is handled both browser and relay, SE_NODE_MAX_CONCURRENCY is used to configure max concurrency based on sum of them
echo "max-sessions = ${SE_NODE_MAX_CONCURRENCY:-${SE_NODE_MAX_SESSIONS}}
" >> "$FILENAME"

SE_NODE_BROWSER_NAME=$(cat /opt/selenium/browser_name)
SE_NODE_BROWSER_VERSION=$(short_version $(cat /opt/selenium/browser_version))
SE__BROWSER_BINARY_LOCATION=$(cat /opt/selenium/browser_binary_location)
if [ -f /opt/selenium/browser_name ]; then
SE_NODE_BROWSER_NAME=$(cat /opt/selenium/browser_name)
fi
if [ -f /opt/selenium/browser_version ]; then
SE_NODE_BROWSER_VERSION=$(short_version $(cat /opt/selenium/browser_version))
fi
if [ -f /opt/selenium/browser_binary_location ]; then
SE__BROWSER_BINARY_LOCATION=$(cat /opt/selenium/browser_binary_location)
fi

if [[ -z "$SE_NODE_STEREOTYPE" ]]; then
# 'browserName' is mandatory for default stereotype
if [[ -z "${SE_NODE_STEREOTYPE}" ]] && [[ -n "${SE_NODE_BROWSER_NAME}" ]]; then
SE_NODE_STEREOTYPE="{\"browserName\": \"${SE_NODE_BROWSER_NAME}\", \"browserVersion\": \"${SE_NODE_BROWSER_VERSION}\", \"platformName\": \"Linux\", ${SE__BROWSER_BINARY_LOCATION}}"
else
SE_NODE_STEREOTYPE="$SE_NODE_STEREOTYPE"
SE_NODE_STEREOTYPE="${SE_NODE_STEREOTYPE}"
fi

echo "[[node.driver-configuration]]" >> "$FILENAME"
echo "display-name = \"${SE_NODE_BROWSER_NAME}\"" >> "$FILENAME"
echo "stereotype = '${SE_NODE_STEREOTYPE}'" >> "$FILENAME"
echo "max-sessions = ${SE_NODE_MAX_SESSIONS}
" >> "$FILENAME"

# 'stereotype' setting is mandatory
if [[ -n "${SE_NODE_STEREOTYPE}" ]]; then
echo "[[node.driver-configuration]]" >> "$FILENAME"
echo "display-name = \"${SE_NODE_BROWSER_NAME}\"" >> "$FILENAME"
echo "stereotype = '${SE_NODE_STEREOTYPE}'" >> "$FILENAME"
echo "max-sessions = ${SE_NODE_MAX_SESSIONS}
" >> "$FILENAME"
fi


24 changes: 24 additions & 0 deletions NodeBase/generate_relay_config
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/bash

if [[ -z "$CONFIG_FILE" ]]; then
FILENAME="/opt/selenium/config.toml"
else
FILENAME="$CONFIG_FILE"
fi

if [[ -n "${SE_NODE_RELAY_URL}" ]]; then
echo "[relay]" >> "$FILENAME"
echo "url = \"${SE_NODE_RELAY_URL}\"" >> "$FILENAME"
if [[ -z "${SE_NODE_RELAY_STATUS_ENDPOINT}" ]]; then
echo "status-endpoint = \"/status\"" >> "$FILENAME"
else
echo "status-endpoint = \"${SE_NODE_RELAY_STATUS_ENDPOINT}\"" >> "$FILENAME"
fi
if [[ -n "${SE_NODE_RELAY_PROTOCOL_VERSION}" ]]; then
echo "protocol-version = \"${SE_NODE_RELAY_PROTOCOL_VERSION}\"" >> "$FILENAME"
fi
echo "configs = [
\"${SE_NODE_RELAY_MAX_SESSIONS}\", \"{\\\"browserName\\\": \\\"${SE_NODE_RELAY_BROWSER_NAME}\\\", \\\"platformName\\\": \\\"${SE_NODE_RELAY_PLATFORM_NAME}\\\", \\\"appium:platformVersion\\\": \\\"${SE_NODE_RELAY_PLATFORM_VERSION}\\\"}\"
]
" >> "$FILENAME"
fi
1 change: 1 addition & 0 deletions NodeBase/start-selenium-node.sh
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ fi
if [ "$GENERATE_CONFIG" = true ]; then
echo "Generating Selenium Config"
/opt/bin/generate_config
/opt/bin/generate_relay_config
fi

EXTRA_LIBS=""
Expand Down
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,35 @@ $ docker run -d \
--shm-size="2g" selenium/node-chrome:4.20.0-20240505
```

### Node configuration relay commands

Relaying commands to a service endpoint that supports WebDriver.
It is useful to connect an external service that supports WebDriver to Selenium Grid. An example of such service could be a cloud provider or an Appium server.
In this way, Grid can enable more coverage to platforms and versions not present locally.

The following is an en example of configuration relay commands.

[docker-compose-v3-test-node-relay.yml](tests/docker-compose-v3-test-node-relay.yml)

If you want to relay commands only, `selenium/node-base` is suitable and lightweight for this purpose.
In case you want to configure node with both browsers and relay commands, respective node images can be used.

To use environment variables for generate relay configs, set `SE_NODE_RELAY_URL` and other variables as below

```toml
[relay]
url = "${SE_NODE_RELAY_URL}"
status-endpoint = "${SE_NODE_RELAY_STATUS_ENDPOINT}"
protocol-version = "${SE_NODE_RELAY_PROTOCOL_VERSION}"
configs = [ '${SE_NODE_RELAY_MAX_SESSIONS}', '{"browserName": "${SE_NODE_RELAY_BROWSER_NAME}", "platformName": "${SE_NODE_RELAY_PLATFORM_NAME}", "appium:platformVersion": "${SE_NODE_RELAY_PLATFORM_VERSION}"}' ]
```

To run a sample test with the relayed node, you can clone the project and try below command:

```bash
make test_node_relay
```

### Setting Sub Path

By default, Selenium is reachable at `http://127.0.0.1:4444/`. Selenium can be configured to use a custom subpath by specifying the `SE_SUB_PATH`
Expand Down
1 change: 1 addition & 0 deletions Standalone/start-selenium-standalone.sh
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ if [ ! -z "$SE_NEW_SESSION_THREAD_POOL_SIZE" ]; then
fi

/opt/bin/generate_config
/opt/bin/generate_relay_config

echo "Selenium Grid Standalone configuration: "
cat /opt/selenium/config.toml
Expand Down
13 changes: 13 additions & 0 deletions tests/Dockerfile.emulator
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
ARG ANDROID_BASED_NAME
ARG ANDROID_BASED_IMAGE
ARG ANDROID_BASED_TAG
FROM ${ANDROID_BASED_NAME}/${ANDROID_BASED_IMAGE}:${ANDROID_BASED_TAG} AS android_based

ARG CHROME_DRIVER_URL
# Download appium chromedriver
RUN curl ${CHROME_DRIVER_URL} -o /tmp/chromedriver.zip \
&& rm -rf ~/.appium/node_modules/appium-uiautomator2-driver/node_modules/appium-chromedriver/chromedriver/linux \
&& mkdir -p ~/.appium/node_modules/appium-uiautomator2-driver/node_modules/appium-chromedriver/chromedriver/linux \
&& unzip /tmp/chromedriver.zip -d ~/.appium/node_modules/appium-uiautomator2-driver/node_modules/appium-chromedriver/chromedriver/linux \
&& ~/.appium/node_modules/appium-uiautomator2-driver/node_modules/appium-chromedriver/chromedriver/linux/chromedriver --version \
&& rm -rf /tmp/chromedriver.zip
13 changes: 13 additions & 0 deletions tests/SeleniumTests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,15 @@
WEB_DRIVER_WAIT_TIMEOUT = int(os.environ.get('WEB_DRIVER_WAIT_TIMEOUT', 60))
TEST_PARALLEL_HARDENING = os.environ.get('TEST_PARALLEL_HARDENING', 'false').lower() == 'true'
TEST_DELAY_AFTER_TEST = int(os.environ.get('TEST_DELAY_AFTER_TEST', 0))
TEST_NODE_RELAY = os.environ.get('TEST_NODE_RELAY', 'false')
TEST_ANDROID_PLATFORM_API = os.environ.get('ANDROID_PLATFORM_API')

if SELENIUM_GRID_USERNAME and SELENIUM_GRID_PASSWORD:
SELENIUM_GRID_HOST = f"{SELENIUM_GRID_USERNAME}:{SELENIUM_GRID_PASSWORD}@{SELENIUM_GRID_HOST}"

if TEST_NODE_RELAY == 'Android':
time.sleep(90)

class SeleniumGenericTests(unittest.TestCase):

def test_title(self):
Expand Down Expand Up @@ -126,6 +131,14 @@ def setUp(self):
options.set_capability('se:screenResolution', '1920x1080')
if SELENIUM_GRID_TEST_HEADLESS:
options.add_argument('--headless=new')
if TEST_NODE_RELAY == 'Android':
options.set_capability('platformName', TEST_NODE_RELAY)
options.set_capability('appium:platformVersion', TEST_ANDROID_PLATFORM_API)
options.set_capability('appium:deviceName', 'emulator-5554')
options.set_capability('appium:automationName', 'uiautomator2')
options.set_capability('appium:browserName', 'chrome')
else:
options.set_capability('platformName', 'Linux')
start_time = time.time()
self.driver = webdriver.Remote(
options=options,
Expand Down
94 changes: 94 additions & 0 deletions tests/docker-compose-v3-test-node-relay.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
version: "3"
services:
node-relay-emulator:
image: selenium/node-base:${TAG}
shm_size: 2gb
depends_on:
- selenium-hub
- appium-emulator
environment:
- SE_EVENT_BUS_HOST=selenium-hub
- SE_EVENT_BUS_PUBLISH_PORT=4442
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
- SE_LOG_LEVEL=${LOG_LEVEL}
- SE_NODE_SESSION_TIMEOUT=${SESSION_TIMEOUT}
- SE_NODE_RELAY_URL=http://appium-emulator:4723
- SE_NODE_RELAY_PROTOCOL_VERSION=HTTP/1.1
- SE_NODE_RELAY_MAX_SESSIONS=1
- SE_NODE_RELAY_PLATFORM_NAME=Android
- SE_NODE_RELAY_PLATFORM_VERSION=${ANDROID_PLATFORM_API}
- SE_NODE_RELAY_BROWSER_NAME=chrome
- SE_NODE_RELAY_WEB_VNC=ws://appium-emulator:6080/websockify

node-relay-standalone:
image: selenium/node-base:${TAG}
shm_size: 2gb
depends_on:
- selenium-hub
- firefox-receiver
volumes:
- ./relay_config.toml:/opt/selenium/config.toml
environment:
- SE_EVENT_BUS_HOST=selenium-hub
- SE_EVENT_BUS_PUBLISH_PORT=4442
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
- SE_LOG_LEVEL=${LOG_LEVEL}
- GENERATE_CONFIG=false

selenium-hub:
image: selenium/hub:${TAG}
container_name: selenium-hub
environment:
- SE_LOG_LEVEL=${LOG_LEVEL}
- SE_SESSION_REQUEST_TIMEOUT=${REQUEST_TIMEOUT}
ports:
- "4442:4442"
- "4443:4443"
- "4444:4444"

tests:
image: docker-selenium-tests:latest
build:
context: ./
dockerfile: ./Dockerfile
depends_on:
- selenium-hub
environment:
- RUN_IN_DOCKER_COMPOSE=true
- SELENIUM_GRID_HOST=selenium-hub
- BINDING_VERSION=${BINDING_VERSION}
- SELENIUM_ENABLE_MANAGED_DOWNLOADS=false
- TEST_NODE_RELAY=${TEST_NODE_RELAY}
- ANDROID_PLATFORM_API=${ANDROID_PLATFORM_API}
- TEST_DELAY_AFTER_TEST=${TEST_DELAY_AFTER_TEST}
command: ["./bootstrap.sh", "${NODE}"]

firefox-receiver:
image: selenium/standalone-firefox:${TAG}
shm_size: 2gb
container_name: firefox-receiver

appium-emulator:
image: ${ANDROID_BASED_NAME}/${ANDROID_BASED_IMAGE}:latest
shm_size: 2gb
build:
args:
ANDROID_BASED_NAME: ${ANDROID_BASED_NAME}
ANDROID_BASED_IMAGE: ${ANDROID_BASED_IMAGE}
ANDROID_BASED_TAG: ${ANDROID_BASED_TAG}
CHROME_DRIVER_URL: https://chromedriver.storage.googleapis.com/113.0.5672.63/chromedriver_linux64.zip
dockerfile: ./Dockerfile.emulator
container_name: appium-emulator
environment:
- EMULATOR_DEVICE=Nexus 5
- WEB_VNC=true
- APPIUM=true
- WEB_LOG=true
- WEB_LOG_PORT=9001
- EMULATOR_NO_SKIN=true
- EMULATOR_NAME=emulator-5554
devices:
- /dev/kvm
ports:
- "6080:6080"
- "4723:4723"
Loading

0 comments on commit 39cd636

Please sign in to comment.