Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature run selenium tests grid on kubernetes via helm chart #2027

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .github/workflows/helm-chart-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ on:
- 'charts/selenium-grid/**'
workflow_dispatch:

permissions:
contents: read

jobs:
lint-test:
name: "Lint Tests with ct"
runs-on: ubuntu-latest
steps:
- name: Checkout
Expand Down Expand Up @@ -45,6 +49,68 @@ jobs:

- name: Create kind cluster
uses: helm/kind-action@v1.8.0
with:
config: ./tests/kind-cluster-config.yaml

- name: Run chart-testing (install)
run: ct install --all --config tests/chart-test.yaml

deploy-grid-selenium-tests:
name: "Run Selenium Tests on K8s"
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
browser: [NodeChrome,NodeEdge,NodeFirefox]
steps:

- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Helm
uses: azure/setup-helm@v3
with:
version: v3.13.2

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
check-latest: true

- name: Create kind cluster
uses: helm/kind-action@v1.8.0
with:
config: ./tests/kind-cluster-config.yaml

# 👋 Documentation link for Ingress Installation on kind k8s cluster https://kind.sigs.k8s.io/docs/user/ingress
- name: Install ingress-nginx on kind kubernetes cluster
run: |
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
kubectl wait --namespace ingress-nginx \
--for=condition=ready pod \
--selector=app.kubernetes.io/component=controller \
--timeout=90s

- name: Deploy Selenium Grid Chart
run: |
helm repo add kedacore https://kedacore.github.io/charts
helm repo update
helm dependency build charts/selenium-grid
helm upgrade --install selenium-grid -f ./tests/override-kind-auth-${{matrix.browser}}-values.yaml charts/selenium-grid --namespace selenium-grid-test --create-namespace
kubectl get ingress --all-namespaces

- name: Verify Post Deployment Grid Health and k8s pods status
run: |
sleep 20 # Allow Kubernetes to pull Docker Images and start Pods
python ./tests/K8sSmokeTest.py "http://localhost"
kubectl get pods -n selenium-grid-test
kubectl get events -n selenium-grid-test

- name: Run Selenium Tests Against Kubernetes
run: |
export SELENIUM_GRID_HOST=localhost
export SELENIUM_GRID_PORT=80
./tests/bootstrap.sh testonkubernetes.py ${{matrix.browser}}
4 changes: 2 additions & 2 deletions .github/workflows/update-dev-beta-browser-images.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ jobs:
run: |
export SKIP_BUILD=true
export NAMESPACE=$NAME
VERSION=$CHANNEL ./tests/bootstrap.sh Node$BROWSER_CAPS
VERSION=$CHANNEL ./tests/bootstrap.sh Standalone$BROWSER_CAPS
VERSION=$CHANNEL ./tests/bootstrap.sh test.py Node$BROWSER_CAPS
VERSION=$CHANNEL ./tests/bootstrap.sh test.py Standalone$BROWSER_CAPS

- name: Login Docker Hub
run: docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD"
Expand Down
12 changes: 6 additions & 6 deletions Makefile
amardeep2006 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -315,22 +315,22 @@ test: test_chrome \


test_chrome:
VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/bootstrap.sh NodeChrome
VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/bootstrap.sh test.py NodeChrome

test_chrome_standalone:
VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/bootstrap.sh StandaloneChrome
VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/bootstrap.sh test.py StandaloneChrome

test_edge:
VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/bootstrap.sh NodeEdge
VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/bootstrap.sh test.py NodeEdge

test_edge_standalone:
VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/bootstrap.sh StandaloneEdge
VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/bootstrap.sh test.py StandaloneEdge

test_firefox:
VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/bootstrap.sh NodeFirefox
VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/bootstrap.sh test.py NodeFirefox

test_firefox_standalone:
VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/bootstrap.sh StandaloneFirefox
VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/bootstrap.sh test.py StandaloneFirefox

# This should run on its own CI job. There is no need to combine it with the other tests.
# Its main purpose is to check that a video file was generated.
Expand Down
6 changes: 3 additions & 3 deletions charts/selenium-grid/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ helm install selenium-grid --set ingress.hostname=selenium-grid.k8s.local docker
Selenium Grid has the ability to autoscale browser nodes up/down based on the pending requests in the
session queue.

To do this [KEDA](https://keda.sh/docs/2.10/scalers/selenium-grid-scaler/) is used. When enabling
To do this [KEDA](https://keda.sh/docs/2.12/scalers/selenium-grid-scaler/) is used. When enabling
autoscaling using `autoscaling.enabling` KEDA is installed automatically. To instead use an existing
installation of KEDA you can enable autoscaling with `autoscaling.enableWithExistingKEDA` instead.

KEDA can scale either with
[deployments](https://keda.sh/docs/2.10/concepts/scaling-deployments/#scaling-of-deployments-and-statefulsets)
or [jobs](https://keda.sh/docs/2.10/concepts/scaling-jobs/) and the charts support both types. This
[deployments](https://keda.sh/docs/2.12/concepts/scaling-deployments/#scaling-of-deployments-and-statefulsets)
or [jobs](https://keda.sh/docs/2.12/concepts/scaling-jobs/) and the charts support both types. This
chart support both modes. It is controlled with `autoscaling.scalingType` that can be set to either
job (default) or deployment.

Expand Down
8 changes: 4 additions & 4 deletions tests/SeleniumTests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from selenium.webdriver.chrome.options import Options as ChromeOptions

SELENIUM_GRID_HOST = os.environ.get('SELENIUM_GRID_HOST', 'localhost')

SELENIUM_GRID_PORT = os.environ.get('SELENIUM_GRID_PORT', '4444')

class SeleniumGenericTests(unittest.TestCase):

Expand Down Expand Up @@ -70,22 +70,22 @@ class ChromeTests(SeleniumGenericTests):
def setUp(self):
self.driver = webdriver.Remote(
options=ChromeOptions(),
command_executor="http://%s:4444" % SELENIUM_GRID_HOST
command_executor="http://%s:%s" % (SELENIUM_GRID_HOST,SELENIUM_GRID_PORT)
)

class EdgeTests(SeleniumGenericTests):
def setUp(self):
self.driver = webdriver.Remote(
options=EdgeOptions(),
command_executor="http://%s:4444" % SELENIUM_GRID_HOST
command_executor="http://%s:%s" % (SELENIUM_GRID_HOST,SELENIUM_GRID_PORT)
)


class FirefoxTests(SeleniumGenericTests):
def setUp(self):
self.driver = webdriver.Remote(
options=FirefoxOptions(),
command_executor="http://%s:4444" % SELENIUM_GRID_HOST
command_executor="http://%s:%s" % (SELENIUM_GRID_HOST,SELENIUM_GRID_PORT)
)

def test_title_and_maximize_window(self):
Expand Down
4 changes: 2 additions & 2 deletions tests/SmokeTests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from urllib.request import urlopen

SELENIUM_GRID_HOST = os.environ.get('SELENIUM_GRID_HOST', 'localhost')

SELENIUM_GRID_PORT = os.environ.get('SELENIUM_GRID_PORT', '4444')

class SmokeTests(unittest.TestCase):
def smoke_test_container(self, port):
Expand All @@ -35,4 +35,4 @@ def smoke_test_container(self, port):

class GridTest(SmokeTests):
def test_grid_is_up(self):
self.smoke_test_container(4444)
self.smoke_test_container('%s' % SELENIUM_GRID_PORT)
2 changes: 1 addition & 1 deletion tests/bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ python -m pip install selenium==4.15.0 \
docker===6.1.3 \
| grep -v 'Requirement already satisfied'

python test.py $1
python $1 $2
ret_code=$?

if [ "${CI:-false}" = "false" ]; then
Expand Down
2 changes: 1 addition & 1 deletion tests/docker-compose-v3-test-video.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@ services:
environment:
- RUN_IN_DOCKER_COMPOSE=true
- SELENIUM_GRID_HOST=selenium-hub
command: ["./bootstrap.sh", "${NODE}"]
command: ["./bootstrap.sh", "test.py", "${NODE}"]
18 changes: 18 additions & 0 deletions tests/kind-cluster-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# This Config is required for KIND cluster to enable ingress. Documented here https://kind.sigs.k8s.io/docs/user/ingress
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "ingress-ready=true"
extraPortMappings:
- containerPort: 80
hostPort: 80
protocol: TCP
- containerPort: 443
hostPort: 443
protocol: TCP
13 changes: 13 additions & 0 deletions tests/override-kind-auth-NodeChrome-values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# This is used in Helm chart testing. This disables the basic auth on seleneium grid
# Basic auth settings for Selenium Grid
basicAuth:
# Enable or disable basic auth
enabled: false
# Configuration for edge nodes
edgeNode:
# Enable edge nodes
enabled: false
# Configuration for firefox nodes
firefoxNode:
# Enable firefox nodes
enabled: false
13 changes: 13 additions & 0 deletions tests/override-kind-auth-NodeEdge-values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# This is used in Helm chart testing. This disables the basic auth on seleneium grid
# Basic auth settings for Selenium Grid
basicAuth:
# Enable or disable basic auth
enabled: false
# Configuration for chrome nodes
chromeNode:
# Enable chrome nodes
enabled: false
# Configuration for firefox nodes
firefoxNode:
# Enable firefox nodes
enabled: false
13 changes: 13 additions & 0 deletions tests/override-kind-auth-NodeFirefox-values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# This is used in Helm chart testing. This disables the basic auth on seleneium grid
# Basic auth settings for Selenium Grid
basicAuth:
# Enable or disable basic auth
enabled: false
# Configuration for chrome nodes
chromeNode:
# Enable chrome nodes
enabled: false
# Configuration for edge nodes
edgeNode:
# Enable edge nodes
enabled: false
54 changes: 54 additions & 0 deletions tests/testonkubernetes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import logging
import sys
import unittest

# LOGGING #
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)

TEST_NAME_MAP = {
# Chrome Images
'NodeChrome': 'ChromeTests',
'StandaloneChrome': 'ChromeTests',

# Edge Images
'NodeEdge': 'EdgeTests',
'StandaloneEdge': 'EdgeTests',

# Firefox Images
'NodeFirefox': 'FirefoxTests',
'StandaloneFirefox': 'FirefoxTests',
}


if __name__ == '__main__':
# The container to test against
image = sys.argv[1]


try:
# Smoke tests
logger.info('*********** Running smoke tests %s Tests **********' % image)
image_class = "%sTest" % image
module = __import__('SmokeTests', fromlist='GridTest')
test_class = getattr(module, 'GridTest')
suite = unittest.TestLoader().loadTestsFromTestCase(test_class)
test_runner = unittest.TextTestRunner(verbosity=3)
failed = not test_runner.run(suite).wasSuccessful()
except Exception as e:
logger.fatal(e)
failed = True

try:
# Run Selenium tests
logger.info('*********** Running Selenium tests %s Tests **********' % image)
test_class = getattr(__import__('SeleniumTests', fromlist=[TEST_NAME_MAP[image]]), TEST_NAME_MAP[image])
suite = unittest.TestLoader().loadTestsFromTestCase(test_class)
test_runner = unittest.TextTestRunner(verbosity=3)
failed = not test_runner.run(suite).wasSuccessful()
except Exception as e:
logger.fatal(e)
failed = True

if failed:
exit(1)