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

Attempting to automate testing of armv7 (armhf) images using a Debian 11.3 armhf VM and QEMU #9

Draft
wants to merge 44 commits into
base: trunk
Choose a base branch
from

Conversation

jamesmortensen
Copy link

This draft pull request is for automating the testing of armhf images. We have tests for x86_64 and arm64 images using CircleCI, thanks to their medium (x86_64) and arm-medium (aarch64) runners. However, I've not found a free cloud provider which hosts armhf images.

I've created a Debian 11.3 armhf VM with Docker installed, and I've published it to GitHub here: https://github.com/jamesmortensen/virtual-machine-releases/releases/tag/debian-11.3-armhf-ci-v1.0

The plan was to do the following:

  • Create a job in CircleCI on the arm-medium runner.
  • Download the armhf VM and extract it.
  • Launch the VM with a startup script and wait for a health check to confirm the VM has booted.
  • Connect to the Docker socket in the VM by setting DOCKER_HOST.
  • Pull existing linux/arm/v7 images from Docker Hub and run the tests on this platform, but using the Docker Engine inside the VM. (To save time waiting for images to build while working through the testing process)

While everything works in theory, the challenge I've run into is that the CircleCI runners do not have a hypervisor, like KVM, built into the kernel. Emulation via QEMU is possible, but it is so slow to where we get a UNIXHttpPoolConnection timeout. Below are some steps to replicate:

# Start the VM after downloading and extracting the tar.xz archive from the above virtual-machine-releases link.
$ cd debian-11.3-armhf-ci
$ sh start-vm.sh &
$ bash wait-for-vm.sh

# Override DOCKER_HOST to point to the Docker socket in the VM
$ export DOCKER_HOST=unix:///tmp/docker-on-debianhf.sock

# Connect to VM Docker socket and open ports via SSH port forwarding
$ ssh -p 8022 debianhf@1127 0.0.1 -N -f -L/tmp/docker-on-debianhf.sock:/var/run/docker.sock ssh://debianhf@127.0.0.1
$ ssh -p 8022 debianhf@1127 0.0.1 -N -f -L4444:127.0.0.1:4444 -L5555:127.0.0.1:5555 -L7900:127.0.0.1:7900

$ USE_RANDOM_USER_ID=false  NAMESPACE=seleniarm VERSION=4.1.4 BUILD_DATE=today SKIP_BUILD=true make test_multi_arch
#docker run --rm --privileged aptman/qus -- -r ; \
#docker run --rm --privileged aptman/qus -s -- -p
#docker run --rm --privileged -v /home/debian/qemu-binfmt/qemu-binfmt-conf.sh:/qus/qemu-binfmt-conf.sh  aptman/qus -s -- -p
VERSION=4.1.4-today NAMESPACE=seleniarm ./tests/bootstrap.sh NodeChromium
Collecting virtualenv
  Downloading virtualenv-20.14.1-py2.py3-none-any.whl (8.8 MB)
Collecting platformdirs<3,>=2
  Downloading platformdirs-2.5.2-py3-none-any.whl (14 kB)
Collecting filelock<4,>=3.2
  Downloading filelock-3.7.0-py3-none-any.whl (10 kB)
Collecting distlib<1,>=0.3.1
  Downloading distlib-0.3.4-py2.py3-none-any.whl (461 kB)
Installing collected packages: platformdirs, filelock, distlib, virtualenv
  WARNING: The script virtualenv is installed in '/home/ubuntu/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed distlib-0.3.4 filelock-3.7.0 platformdirs-2.5.2 virtualenv-20.14.1
./tests/bootstrap.sh: line 6: virtualenv: command not found
./tests/bootstrap.sh: line 7: docker-selenium-tests/bin/activate: No such file or directory
Collecting selenium==4.1.3
  Downloading selenium-4.1.3-py3-none-any.whl (968 kB)
Collecting docker===4.2.0
  Downloading docker-4.2.0-py2.py3-none-any.whl (143 kB)
Collecting trio-websocket~=0.9
  Downloading trio_websocket-0.9.2-py3-none-any.whl (16 kB)
Collecting trio~=0.17
  Downloading trio-0.20.0-py3-none-any.whl (359 kB)
Collecting urllib3[secure,socks]~=1.26
  Downloading urllib3-1.26.9-py2.py3-none-any.whl (138 kB)
Collecting websocket-client>=0.32.0
  Downloading websocket_client-1.3.2-py3-none-any.whl (54 kB)
Collecting async-generator>=1.10
  Downloading async_generator-1.10-py3-none-any.whl (18 kB)
Collecting wsproto>=0.14
  Downloading wsproto-1.1.0-py3-none-any.whl (24 kB)
Collecting sniffio
  Downloading sniffio-1.2.0-py3-none-any.whl (10 kB)
Collecting outcome
  Downloading outcome-1.1.0-py2.py3-none-any.whl (9.7 kB)
Collecting sortedcontainers
  Downloading sortedcontainers-2.4.0-py2.py3-none-any.whl (29 kB)
Collecting PySocks!=1.5.7,<2.0,>=1.5.6; extra == "socks"
  Downloading PySocks-1.7.1-py3-none-any.whl (16 kB)
Collecting h11<1,>=0.9.0
  Downloading h11-0.13.0-py3-none-any.whl (58 kB)
Installing collected packages: async-generator, sniffio, outcome, sortedcontainers, trio, h11, wsproto, trio-websocket, PySocks, urllib3, selenium, websocket-client, docker
  WARNING: The script wsdump is installed in '/home/ubuntu/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed PySocks-1.7.1 async-generator-1.10 docker-4.2.0 h11-0.13.0 outcome-1.1.0 selenium-4.1.3 sniffio-1.2.0 sortedcontainers-2.4.0 trio-0.20.0 trio-websocket-0.9.2 urllib3-1.26.9 websocket-client-1.3.2 wsproto-1.1.0
/usr/lib/python3/dist-packages/requests/__init__.py:89: RequestsDependencyWarning: urllib3 (1.26.9) or chardet (3.0.4) doesn't match a supported version!
  warnings.warn("urllib3 ({}) or chardet ({}) doesn't match a supported "
2022-05-22 17:00:05,281 - __main__ - INFO - ========== Starting NodeChromium Container ==========
2022-05-22 17:00:17,204 - __main__ - INFO - Launching Hub...
2022-05-22 17:00:17,288 - __main__ - INFO - SKIP_BUILD is true...not rebuilding images...
2022-05-22 17:00:17,289 - __main__ - INFO - Running Hub container...
2022-05-22 17:01:12,111 - __main__ - INFO - Hub up and running
2022-05-22 17:01:12,124 - __main__ - INFO - Hub Launched
2022-05-22 17:01:12,124 - __main__ - INFO - SKIP_BUILD is true...not rebuilding images...
2022-05-22 17:01:12,124 - __main__ - INFO - Running NodeChromium container...
Traceback (most recent call last):
  File "/home/ubuntu/.local/lib/python3.8/site-packages/urllib3/connectionpool.py", line 449, in _make_request
    six.raise_from(e, None)
  File "<string>", line 3, in raise_from
  File "/home/ubuntu/.local/lib/python3.8/site-packages/urllib3/connectionpool.py", line 444, in _make_request
    httplib_response = conn.getresponse()
  File "/usr/lib/python3.8/http/client.py", line 1348, in getresponse
    response.begin()
  File "/usr/lib/python3.8/http/client.py", line 316, in begin
    version, status, reason = self._read_status()
  File "/usr/lib/python3.8/http/client.py", line 277, in _read_status
    line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
  File "/usr/lib/python3.8/socket.py", line 669, in readinto
    return self._sock.recv_into(b)
socket.timeout: timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/requests/adapters.py", line 439, in send
    resp = conn.urlopen(
  File "/home/ubuntu/.local/lib/python3.8/site-packages/urllib3/connectionpool.py", line 785, in urlopen
    retries = retries.increment(
  File "/home/ubuntu/.local/lib/python3.8/site-packages/urllib3/util/retry.py", line 550, in increment
    raise six.reraise(type(error), error, _stacktrace)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/urllib3/packages/six.py", line 770, in reraise
    raise value
  File "/home/ubuntu/.local/lib/python3.8/site-packages/urllib3/connectionpool.py", line 703, in urlopen
    httplib_response = self._make_request(
  File "/home/ubuntu/.local/lib/python3.8/site-packages/urllib3/connectionpool.py", line 451, in _make_request
    self._raise_timeout(err=e, url=url, timeout_value=read_timeout)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/urllib3/connectionpool.py", line 340, in _raise_timeout
    raise ReadTimeoutError(
urllib3.exceptions.ReadTimeoutError: UnixHTTPConnectionPool(host='localhost', port=None): Read timed out. (read timeout=60)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "test.py", line 201, in <module>
    test_container_id = launch_container(image, network='grid', ports=ports, platform=platform)
  File "test.py", line 146, in launch_container
    container_id = client.containers.run("%s/%s:%s" % (NAMESPACE, IMAGE_NAME_MAP[container], VERSION),
  File "/home/ubuntu/.local/lib/python3.8/site-packages/docker/models/containers.py", line 809, in run
    container.start()
  File "/home/ubuntu/.local/lib/python3.8/site-packages/docker/models/containers.py", line 400, in start
    return self.client.api.start(self.id, **kwargs)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/docker/utils/decorators.py", line 19, in wrapped
    return f(self, resource_id, *args, **kwargs)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/docker/api/container.py", line 1094, in start
    res = self._post(url)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/docker/utils/decorators.py", line 46, in inner
    return f(self, *args, **kwargs)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/docker/api/client.py", line 226, in _post
    return self.post(url, **self._set_request_timeout(kwargs))
  File "/usr/lib/python3/dist-packages/requests/sessions.py", line 581, in post
    return self.request('POST', url, data=data, json=json, **kwargs)
  File "/usr/lib/python3/dist-packages/requests/sessions.py", line 533, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/lib/python3/dist-packages/requests/sessions.py", line 646, in send
    r = adapter.send(request, **kwargs)
  File "/usr/lib/python3/dist-packages/requests/adapters.py", line 529, in send
    raise ReadTimeout(e, request=request)
requests.exceptions.ReadTimeout: UnixHTTPConnectionPool(host='localhost', port=None): Read timed out. (read timeout=60)
./tests/bootstrap.sh: line 18: deactivate: command not found
make: *** [Makefile:449: test_chromium_multi] Error 1

Additionally, when attempting to start the containers beforehand and then run tests, they still fail:

$ docker run --rm -it -p 7900:7900 -p 4444:4444 -p 5555:5555 -d seleniarm/standalone-firefox:latest

# Confirm the container is up before running a modified version of test.py, which does not attempt to launch containers
$ curl -L http://127.0.0.1:4444/status

# Run tests on standalone-firefox
$ USE_RANDOM_USER_ID=false  NAMESPACE=seleniarm VERSION=4.1.4 BUILD_DATE=today SKIP_BUILD=true make test_firefox_standalone_multi
VERSION=4.1.4-today NAMESPACE=seleniarm ./tests/bootstrap.sh StandaloneFirefox
./tests/bootstrap.sh: line 6: virtualenv: command not found
./tests/bootstrap.sh: line 7: docker-selenium-tests/bin/activate: No such file or directory
/usr/lib/python3/dist-packages/requests/__init__.py:89: RequestsDependencyWarning: urllib3 (1.26.9) or chardet (3.0.4) doesn't match a supported version!
  warnings.warn("urllib3 ({}) or chardet ({}) doesn't match a supported "
2022-05-24 03:47:58,427 - __main__ - INFO - ========== Starting StandaloneFirefox Container ==========
2022-05-24 03:47:58,427 - __main__ - INFO - ========== / Containers ready to go ==========
2022-05-24 03:47:58,427 - __main__ - INFO - *********** Running smoke tests StandaloneFirefox Tests **********
test_grid_is_up (SmokeTests.GridTest) ... ok

----------------------------------------------------------------------
Ran 1 test in 1.517s

OK
2022-05-24 03:47:59,949 - __main__ - INFO - *********** Running Selenium tests StandaloneFirefox Tests **********
test_play_video (SeleniumTests.FirefoxTests) ... ERROR
test_select_from_a_dropdown (SeleniumTests.FirefoxTests) ... ERROR
test_title (SeleniumTests.FirefoxTests) ... ERROR
test_title_and_maximize_window (SeleniumTests.FirefoxTests) ... ERROR
test_visit_basic_auth_secured_page (SeleniumTests.FirefoxTests) ... ERROR
test_with_frames (SeleniumTests.FirefoxTests) ... ERROR

======================================================================
ERROR: test_play_video (SeleniumTests.FirefoxTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/ubuntu/docker-seleniarm/tests/SeleniumTests/__init__.py", line 84, in setUp
    self.driver = webdriver.Remote(
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 269, in __init__
    self.start_session(capabilities, browser_profile)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 360, in start_session
    response = self.execute(Command.NEW_SESSION, parameters)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 425, in execute
    self.error_handler.check_response(response)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/errorhandler.py", line 247, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.SessionNotCreatedException: Message: Could not start a new session. Error while creating session with the driver service. Stopping driver service: Could not start a new session. Response code 500. Message: Failed to read marionette port
Build info: version: '4.1.4', revision: '535d840ee2'
System info: host: '1c9c6aeb1190', ip: '172.17.0.2', os.name: 'Linux', os.arch: 'arm', os.version: '5.10.0-13-armmp-lpae', java.version: '11.0.14'
Driver info: driver.version: unknown
Build info: version: '4.1.4', revision: '535d840ee2'
System info: host: '1c9c6aeb1190', ip: '172.17.0.2', os.name: 'Linux', os.arch: 'arm', os.version: '5.10.0-13-armmp-lpae', java.version: '11.0.14'
Driver info: driver.version: unknown
Stacktrace:
    at org.openqa.selenium.grid.node.config.DriverServiceSessionFactory.apply (DriverServiceSessionFactory.java:194)
    at org.openqa.selenium.grid.node.config.DriverServiceSessionFactory.apply (DriverServiceSessionFactory.java:67)
    at org.openqa.selenium.grid.node.local.SessionSlot.apply (SessionSlot.java:145)
    at org.openqa.selenium.grid.node.local.LocalNode.newSession (LocalNode.java:349)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor.startSession (LocalDistributor.java:609)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor.newSession (LocalDistributor.java:535)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor$NewSessionRunnable.handleNewSessionRequest (LocalDistributor.java:746)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor$NewSessionRunnable.lambda$run$1 (LocalDistributor.java:707)
    at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1128)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:628)
    at java.lang.Thread.run (Thread.java:829)

======================================================================
ERROR: test_select_from_a_dropdown (SeleniumTests.FirefoxTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/ubuntu/docker-seleniarm/tests/SeleniumTests/__init__.py", line 84, in setUp
    self.driver = webdriver.Remote(
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 269, in __init__
    self.start_session(capabilities, browser_profile)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 360, in start_session
    response = self.execute(Command.NEW_SESSION, parameters)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 425, in execute
    self.error_handler.check_response(response)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/errorhandler.py", line 247, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.SessionNotCreatedException: Message: Could not start a new session. Error while creating session with the driver service. Stopping driver service: Could not start a new session. Response code 500. Message: Failed to read marionette port
Build info: version: '4.1.4', revision: '535d840ee2'
System info: host: '1c9c6aeb1190', ip: '172.17.0.2', os.name: 'Linux', os.arch: 'arm', os.version: '5.10.0-13-armmp-lpae', java.version: '11.0.14'
Driver info: driver.version: unknown
Build info: version: '4.1.4', revision: '535d840ee2'
System info: host: '1c9c6aeb1190', ip: '172.17.0.2', os.name: 'Linux', os.arch: 'arm', os.version: '5.10.0-13-armmp-lpae', java.version: '11.0.14'
Driver info: driver.version: unknown
Stacktrace:
    at org.openqa.selenium.grid.node.config.DriverServiceSessionFactory.apply (DriverServiceSessionFactory.java:194)
    at org.openqa.selenium.grid.node.config.DriverServiceSessionFactory.apply (DriverServiceSessionFactory.java:67)
    at org.openqa.selenium.grid.node.local.SessionSlot.apply (SessionSlot.java:145)
    at org.openqa.selenium.grid.node.local.LocalNode.newSession (LocalNode.java:349)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor.startSession (LocalDistributor.java:609)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor.newSession (LocalDistributor.java:535)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor$NewSessionRunnable.handleNewSessionRequest (LocalDistributor.java:746)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor$NewSessionRunnable.lambda$run$1 (LocalDistributor.java:707)
    at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1128)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:628)
    at java.lang.Thread.run (Thread.java:829)

======================================================================
ERROR: test_title (SeleniumTests.FirefoxTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/ubuntu/docker-seleniarm/tests/SeleniumTests/__init__.py", line 84, in setUp
    self.driver = webdriver.Remote(
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 269, in __init__
    self.start_session(capabilities, browser_profile)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 360, in start_session
    response = self.execute(Command.NEW_SESSION, parameters)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 425, in execute
    self.error_handler.check_response(response)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/errorhandler.py", line 247, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.SessionNotCreatedException: Message: Could not start a new session. Error while creating session with the driver service. Stopping driver service: Could not start a new session. Response code 500. Message: Failed to read marionette port
Build info: version: '4.1.4', revision: '535d840ee2'
System info: host: '1c9c6aeb1190', ip: '172.17.0.2', os.name: 'Linux', os.arch: 'arm', os.version: '5.10.0-13-armmp-lpae', java.version: '11.0.14'
Driver info: driver.version: unknown
Build info: version: '4.1.4', revision: '535d840ee2'
System info: host: '1c9c6aeb1190', ip: '172.17.0.2', os.name: 'Linux', os.arch: 'arm', os.version: '5.10.0-13-armmp-lpae', java.version: '11.0.14'
Driver info: driver.version: unknown
Stacktrace:
    at org.openqa.selenium.grid.node.config.DriverServiceSessionFactory.apply (DriverServiceSessionFactory.java:194)
    at org.openqa.selenium.grid.node.config.DriverServiceSessionFactory.apply (DriverServiceSessionFactory.java:67)
    at org.openqa.selenium.grid.node.local.SessionSlot.apply (SessionSlot.java:145)
    at org.openqa.selenium.grid.node.local.LocalNode.newSession (LocalNode.java:349)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor.startSession (LocalDistributor.java:609)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor.newSession (LocalDistributor.java:535)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor$NewSessionRunnable.handleNewSessionRequest (LocalDistributor.java:746)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor$NewSessionRunnable.lambda$run$1 (LocalDistributor.java:707)
    at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1128)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:628)
    at java.lang.Thread.run (Thread.java:829)

======================================================================
ERROR: test_title_and_maximize_window (SeleniumTests.FirefoxTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/ubuntu/docker-seleniarm/tests/SeleniumTests/__init__.py", line 84, in setUp
    self.driver = webdriver.Remote(
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 269, in __init__
    self.start_session(capabilities, browser_profile)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 360, in start_session
    response = self.execute(Command.NEW_SESSION, parameters)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 425, in execute
    self.error_handler.check_response(response)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/errorhandler.py", line 247, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.SessionNotCreatedException: Message: Could not start a new session. Error while creating session with the driver service. Stopping driver service: Could not start a new session. Response code 500. Message: Failed to read marionette port
Build info: version: '4.1.4', revision: '535d840ee2'
System info: host: '1c9c6aeb1190', ip: '172.17.0.2', os.name: 'Linux', os.arch: 'arm', os.version: '5.10.0-13-armmp-lpae', java.version: '11.0.14'
Driver info: driver.version: unknown
Build info: version: '4.1.4', revision: '535d840ee2'
System info: host: '1c9c6aeb1190', ip: '172.17.0.2', os.name: 'Linux', os.arch: 'arm', os.version: '5.10.0-13-armmp-lpae', java.version: '11.0.14'
Driver info: driver.version: unknown
Stacktrace:
    at org.openqa.selenium.grid.node.config.DriverServiceSessionFactory.apply (DriverServiceSessionFactory.java:194)
    at org.openqa.selenium.grid.node.config.DriverServiceSessionFactory.apply (DriverServiceSessionFactory.java:67)
    at org.openqa.selenium.grid.node.local.SessionSlot.apply (SessionSlot.java:145)
    at org.openqa.selenium.grid.node.local.LocalNode.newSession (LocalNode.java:349)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor.startSession (LocalDistributor.java:609)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor.newSession (LocalDistributor.java:535)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor$NewSessionRunnable.handleNewSessionRequest (LocalDistributor.java:746)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor$NewSessionRunnable.lambda$run$1 (LocalDistributor.java:707)
    at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1128)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:628)
    at java.lang.Thread.run (Thread.java:829)

======================================================================
ERROR: test_visit_basic_auth_secured_page (SeleniumTests.FirefoxTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/ubuntu/docker-seleniarm/tests/SeleniumTests/__init__.py", line 84, in setUp
    self.driver = webdriver.Remote(
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 269, in __init__
    self.start_session(capabilities, browser_profile)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 360, in start_session
    response = self.execute(Command.NEW_SESSION, parameters)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 425, in execute
    self.error_handler.check_response(response)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/errorhandler.py", line 247, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.SessionNotCreatedException: Message: Could not start a new session. Error while creating session with the driver service. Stopping driver service: Could not start a new session. Response code 500. Message: Failed to read marionette port
Build info: version: '4.1.4', revision: '535d840ee2'
System info: host: '1c9c6aeb1190', ip: '172.17.0.2', os.name: 'Linux', os.arch: 'arm', os.version: '5.10.0-13-armmp-lpae', java.version: '11.0.14'
Driver info: driver.version: unknown
Build info: version: '4.1.4', revision: '535d840ee2'
System info: host: '1c9c6aeb1190', ip: '172.17.0.2', os.name: 'Linux', os.arch: 'arm', os.version: '5.10.0-13-armmp-lpae', java.version: '11.0.14'
Driver info: driver.version: unknown
Stacktrace:
    at org.openqa.selenium.grid.node.config.DriverServiceSessionFactory.apply (DriverServiceSessionFactory.java:194)
    at org.openqa.selenium.grid.node.config.DriverServiceSessionFactory.apply (DriverServiceSessionFactory.java:67)
    at org.openqa.selenium.grid.node.local.SessionSlot.apply (SessionSlot.java:145)
    at org.openqa.selenium.grid.node.local.LocalNode.newSession (LocalNode.java:349)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor.startSession (LocalDistributor.java:609)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor.newSession (LocalDistributor.java:535)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor$NewSessionRunnable.handleNewSessionRequest (LocalDistributor.java:746)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor$NewSessionRunnable.lambda$run$1 (LocalDistributor.java:707)
    at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1128)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:628)
    at java.lang.Thread.run (Thread.java:829)

======================================================================
ERROR: test_with_frames (SeleniumTests.FirefoxTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/ubuntu/docker-seleniarm/tests/SeleniumTests/__init__.py", line 84, in setUp
    self.driver = webdriver.Remote(
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 269, in __init__
    self.start_session(capabilities, browser_profile)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 360, in start_session
    response = self.execute(Command.NEW_SESSION, parameters)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 425, in execute
    self.error_handler.check_response(response)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/errorhandler.py", line 247, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.SessionNotCreatedException: Message: Could not start a new session. Error while creating session with the driver service. Stopping driver service: Could not start a new session. Response code 500. Message: Failed to read marionette port
Build info: version: '4.1.4', revision: '535d840ee2'
System info: host: '1c9c6aeb1190', ip: '172.17.0.2', os.name: 'Linux', os.arch: 'arm', os.version: '5.10.0-13-armmp-lpae', java.version: '11.0.14'
Driver info: driver.version: unknown
Build info: version: '4.1.4', revision: '535d840ee2'
System info: host: '1c9c6aeb1190', ip: '172.17.0.2', os.name: 'Linux', os.arch: 'arm', os.version: '5.10.0-13-armmp-lpae', java.version: '11.0.14'
Driver info: driver.version: unknown
Stacktrace:
    at org.openqa.selenium.grid.node.config.DriverServiceSessionFactory.apply (DriverServiceSessionFactory.java:194)
    at org.openqa.selenium.grid.node.config.DriverServiceSessionFactory.apply (DriverServiceSessionFactory.java:67)
    at org.openqa.selenium.grid.node.local.SessionSlot.apply (SessionSlot.java:145)
    at org.openqa.selenium.grid.node.local.LocalNode.newSession (LocalNode.java:349)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor.startSession (LocalDistributor.java:609)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor.newSession (LocalDistributor.java:535)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor$NewSessionRunnable.handleNewSessionRequest (LocalDistributor.java:746)
    at org.openqa.selenium.grid.distributor.local.LocalDistributor$NewSessionRunnable.lambda$run$1 (LocalDistributor.java:707)
    at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1128)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:628)
    at java.lang.Thread.run (Thread.java:829)

----------------------------------------------------------------------
Ran 6 tests in 861.464s

FAILED (errors=6)
2022-05-24 04:02:21,607 - __main__ - INFO - Cleaning up...
Traceback (most recent call last):
  File "test.py", line 236, in <module>
    test_container = client.containers.get(test_container_id)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/docker/models/containers.py", line 880, in get
    resp = self.client.api.inspect_container(container_id)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/docker/utils/decorators.py", line 16, in wrapped
    raise errors.NullResource(
docker.errors.NullResource: Resource ID was not provided
./tests/bootstrap.sh: line 18: deactivate: command not found
make: *** [Makefile:458: test_firefox_standalone_multi] Error 1

Ironically, I can start an armhf VM on a Macbook Pro M1, connect to the Docker socket, and run the tests and have them pass, but the hardware on a Macbook Pro M1 is much more than what we have available in CircleCI, GitHub Actions, and other CI/CD providers.

I am not sure yet how to increase the UnixHTTPConnectionPool timeout, but that's likely the next thing I would look into in order to see if it's possible to automate this testing in a CI environment. This draft pull request is not intended to be merged at this time, but to highlight the challenges and document this progress so others can follow along.

…different architecture before running tests. Added 10 second delay when platform is specified to give containers time to start when running under emulation. Experimented with geckodriver armv7 binary, which results in Firefox tests passing using qemu-user-static
… set the DOCKER_HOST when running the build.
…c and that's what was being used in the Makefile.
@jamesmortensen
Copy link
Author

Firefox tests run on the update-firefox_104.0-1 branch on a Mac M1, but using a QEMU armhf VM from https://github.com/jamesmortensen/virtual-machine-releases/releases/tag/debian-11.3-armhf-ci-v1.0

To allow the grid enough time to start, we set GRID_STATUS_MAX_ATTEMPTS=10 instead of the default of only 3, due to the slower emulation of a different architecture. This was after building images using PLATFORMS=linux/arm/v7 VERSION=4.4.0 make build_multi to build all images for the armhf platform:

node-firefox:

$ USE_RANDOM_USER_ID=false  NAMESPACE=selenium VERSION=4.4.0 BUILD_DATE=20220903 SKIP_BUILD=true GRID_STATUS_MAX_ATTEMPTS=10 make test_firefox_multi
VERSION=4.4.0-20220903 NAMESPACE=selenium ./tests/bootstrap.sh NodeFirefox
created virtual environment CPython3.10.6.final.0-64 in 319ms
  creator CPython3Posix(dest=/Users/james/Dev/seleniumHQ/docker-seleniarm/tests/docker-selenium-tests, clear=False, no_vcs_ignore=False, global=False)
  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/Users/james/Library/Application Support/virtualenv)
    added seed packages: PySocks==1.7.1, async_generator==1.10, attrs==22.1.0, certifi==2022.6.15, cffi==1.15.1, charset_normalizer==2.1.1, cryptography==37.0.4, docker==4.2.0, h11==0.13.0, idna==3.3, outcome==1.2.0, pip==22.2.2, pyOpenSSL==22.0.0, pycparser==2.21, requests==2.28.1, selenium==4.3.0, setuptools==65.3.0, six==1.16.0, sniffio==1.3.0, sortedcontainers==2.4.0, trio==0.21.0, trio_websocket==0.9.2, urllib3==1.26.12, urllib3_secure_extra==0.1.0, websocket_client==1.4.0, wheel==0.37.1, wsproto==1.2.0
  activators BashActivator,CShellActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator
2022-09-03 17:06:53,329 - __main__ - INFO - ========== Starting NodeFirefox Container ==========
2022-09-03 17:06:56,884 - __main__ - INFO - Launching Hub...
2022-09-03 17:06:56,898 - __main__ - INFO - SKIP_BUILD is true...not rebuilding images...
2022-09-03 17:06:56,898 - __main__ - INFO - Running Hub container...
2022-09-03 17:07:04,234 - __main__ - INFO - Hub up and running
2022-09-03 17:07:04,234 - __main__ - INFO - Hub Launched
2022-09-03 17:07:04,234 - __main__ - INFO - SKIP_BUILD is true...not rebuilding images...
2022-09-03 17:07:04,234 - __main__ - INFO - Running NodeFirefox container...
2022-09-03 17:07:14,358 - __main__ - INFO - NodeFirefox up and running
2022-09-03 17:07:14,628 - __main__ - INFO - ========== / Containers ready to go ==========
2022-09-03 17:07:14,628 - __main__ - INFO - *********** Running smoke tests NodeFirefox Tests **********
test_grid_is_up (SmokeTests.GridTest) ... ok

----------------------------------------------------------------------
Ran 1 test in 22.135s

OK
2022-09-03 17:07:36,764 - __main__ - INFO - *********** Running Selenium tests NodeFirefox Tests **********
test_play_video (SeleniumTests.FirefoxTests) ... ok
test_select_from_a_dropdown (SeleniumTests.FirefoxTests) ... ok
test_title (SeleniumTests.FirefoxTests) ... ok
test_title_and_maximize_window (SeleniumTests.FirefoxTests) ... ok
test_visit_basic_auth_secured_page (SeleniumTests.FirefoxTests) ... ok
test_with_frames (SeleniumTests.FirefoxTests) ... ok

----------------------------------------------------------------------
Ran 6 tests in 427.560s

OK
2022-09-03 17:14:44,343 - __main__ - INFO - Cleaning up...
2022-09-03 17:14:54,278 - __main__ - INFO - Hub / Node Cleaned up

node-chromium tests passed as well:

$ USE_RANDOM_USER_ID=false  NAMESPACE=selenium VERSION=4.4.0 BUILD_DATE=20220903 SKIP_BUILD=true GRID_STATUS_MAX_ATTEMPTS=10 make test_chromium_multi
VERSION=4.4.0-20220903 NAMESPACE=selenium ./tests/bootstrap.sh NodeChromium
created virtual environment CPython3.10.6.final.0-64 in 346ms
  creator CPython3Posix(dest=/Users/james/Dev/seleniumHQ/docker-seleniarm/tests/docker-selenium-tests, clear=False, no_vcs_ignore=False, global=False)
  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/Users/james/Library/Application Support/virtualenv)
    added seed packages: PySocks==1.7.1, async_generator==1.10, attrs==22.1.0, certifi==2022.6.15, cffi==1.15.1, charset_normalizer==2.1.1, cryptography==37.0.4, docker==4.2.0, h11==0.13.0, idna==3.3, outcome==1.2.0, pip==22.2.2, pyOpenSSL==22.0.0, pycparser==2.21, requests==2.28.1, selenium==4.3.0, setuptools==65.3.0, six==1.16.0, sniffio==1.3.0, sortedcontainers==2.4.0, trio==0.21.0, trio_websocket==0.9.2, urllib3==1.26.12, urllib3_secure_extra==0.1.0, websocket_client==1.4.0, wheel==0.37.1, wsproto==1.2.0
  activators BashActivator,CShellActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator
2022-09-03 17:33:12,053 - __main__ - INFO - ========== Starting NodeChromium Container ==========
2022-09-03 17:33:15,362 - __main__ - INFO - Launching Hub...
2022-09-03 17:33:15,374 - __main__ - INFO - SKIP_BUILD is true...not rebuilding images...
2022-09-03 17:33:15,374 - __main__ - INFO - Running Hub container...
2022-09-03 17:33:23,532 - __main__ - INFO - Hub up and running
2022-09-03 17:33:23,532 - __main__ - INFO - Hub Launched
2022-09-03 17:33:23,532 - __main__ - INFO - SKIP_BUILD is true...not rebuilding images...
2022-09-03 17:33:23,532 - __main__ - INFO - Running NodeChromium container...
2022-09-03 17:33:31,532 - __main__ - INFO - NodeChromium up and running
2022-09-03 17:33:31,592 - __main__ - INFO - ========== / Containers ready to go ==========
2022-09-03 17:33:31,592 - __main__ - INFO - *********** Running smoke tests NodeChromium Tests **********
test_grid_is_up (SmokeTests.GridTest) ... ok

----------------------------------------------------------------------
Ran 1 test in 21.947s

OK
2022-09-03 17:33:53,541 - __main__ - INFO - *********** Running Selenium tests NodeChromium Tests **********
test_play_video (SeleniumTests.ChromeTests) ... ok
test_select_from_a_dropdown (SeleniumTests.ChromeTests) ... ok
test_title (SeleniumTests.ChromeTests) ... ok
test_visit_basic_auth_secured_page (SeleniumTests.ChromeTests) ... ok
test_with_frames (SeleniumTests.ChromeTests) ... ok

----------------------------------------------------------------------
Ran 5 tests in 192.944s

OK
2022-09-03 17:37:06,602 - __main__ - INFO - Cleaning up...
2022-09-03 17:37:13,862 - __main__ - INFO - Hub / Node Cleaned up

standalone-firefox:

USE_RANDOM_USER_ID=false  NAMESPACE=selenium VERSION=4.4.0 BUILD_DATE=20220903 SKIP_BUILD=true GRID_STATUS_MAX_ATTEMPTS=10 make test_firefox_standalone_multi
VERSION=4.4.0-20220903 NAMESPACE=selenium ./tests/bootstrap.sh StandaloneFirefox
created virtual environment CPython3.10.6.final.0-64 in 325ms
  creator CPython3Posix(dest=/Users/james/Dev/seleniumHQ/docker-seleniarm/tests/docker-selenium-tests, clear=False, no_vcs_ignore=False, global=False)
  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/Users/james/Library/Application Support/virtualenv)
    added seed packages: PySocks==1.7.1, async_generator==1.10, attrs==22.1.0, certifi==2022.6.15, cffi==1.15.1, charset_normalizer==2.1.1, cryptography==37.0.4, docker==4.2.0, h11==0.13.0, idna==3.3, outcome==1.2.0, pip==22.2.2, pyOpenSSL==22.0.0, pycparser==2.21, requests==2.28.1, selenium==4.3.0, setuptools==65.3.0, six==1.16.0, sniffio==1.3.0, sortedcontainers==2.4.0, trio==0.21.0, trio_websocket==0.9.2, urllib3==1.26.12, urllib3_secure_extra==0.1.0, websocket_client==1.4.0, wheel==0.37.1, wsproto==1.2.0
  activators BashActivator,CShellActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator
2022-09-03 17:49:47,973 - __main__ - INFO - ========== Starting StandaloneFirefox Container ==========
2022-09-03 17:49:47,974 - __main__ - INFO - SKIP_BUILD is true...not rebuilding images...
2022-09-03 17:49:47,974 - __main__ - INFO - Running StandaloneFirefox container...
2022-09-03 17:49:53,015 - __main__ - INFO - StandaloneFirefox up and running
2022-09-03 17:49:53,015 - __main__ - INFO - ========== / Containers ready to go ==========
2022-09-03 17:49:53,015 - __main__ - INFO - *********** Running smoke tests StandaloneFirefox Tests **********
test_grid_is_up (SmokeTests.GridTest) ... ok

----------------------------------------------------------------------
Ran 1 test in 16.589s

OK
2022-09-03 17:50:09,605 - __main__ - INFO - *********** Running Selenium tests StandaloneFirefox Tests **********
test_play_video (SeleniumTests.FirefoxTests) ... ok
test_select_from_a_dropdown (SeleniumTests.FirefoxTests) ... ok
test_title (SeleniumTests.FirefoxTests) ... ok
test_title_and_maximize_window (SeleniumTests.FirefoxTests) ... ok
test_visit_basic_auth_secured_page (SeleniumTests.FirefoxTests) ... ok
test_with_frames (SeleniumTests.FirefoxTests) ... ok

----------------------------------------------------------------------
Ran 6 tests in 403.058s

OK
2022-09-03 17:56:52,733 - __main__ - INFO - Cleaning up...
2022-09-03 17:56:55,525 - __main__ - INFO - Standalone Cleaned up

standalone-chromium:

$ USE_RANDOM_USER_ID=false  NAMESPACE=selenium VERSION=4.4.0 BUILD_DATE=20220903 SKIP_BUILD=true GRID_STATUS_MAX_ATTEMPTS=10 make test_chromium_standalone_multi
VERSION=4.4.0-20220903 NAMESPACE=selenium ./tests/bootstrap.sh StandaloneChromium
created virtual environment CPython3.10.6.final.0-64 in 336ms
  creator CPython3Posix(dest=/Users/james/Dev/seleniumHQ/docker-seleniarm/tests/docker-selenium-tests, clear=False, no_vcs_ignore=False, global=False)
  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/Users/james/Library/Application Support/virtualenv)
    added seed packages: PySocks==1.7.1, async_generator==1.10, attrs==22.1.0, certifi==2022.6.15, cffi==1.15.1, charset_normalizer==2.1.1, cryptography==37.0.4, docker==4.2.0, h11==0.13.0, idna==3.3, outcome==1.2.0, pip==22.2.2, pyOpenSSL==22.0.0, pycparser==2.21, requests==2.28.1, selenium==4.3.0, setuptools==65.3.0, six==1.16.0, sniffio==1.3.0, sortedcontainers==2.4.0, trio==0.21.0, trio_websocket==0.9.2, urllib3==1.26.12, urllib3_secure_extra==0.1.0, websocket_client==1.4.0, wheel==0.37.1, wsproto==1.2.0
  activators BashActivator,CShellActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator
2022-09-03 17:45:39,409 - __main__ - INFO - ========== Starting StandaloneChromium Container ==========
2022-09-03 17:45:39,409 - __main__ - INFO - SKIP_BUILD is true...not rebuilding images...
2022-09-03 17:45:39,409 - __main__ - INFO - Running StandaloneChromium container...
2022-09-03 17:45:44,141 - __main__ - INFO - StandaloneChromium up and running
2022-09-03 17:45:44,141 - __main__ - INFO - ========== / Containers ready to go ==========
2022-09-03 17:45:44,141 - __main__ - INFO - *********** Running smoke tests StandaloneChromium Tests **********
test_grid_is_up (SmokeTests.GridTest) ... ok

----------------------------------------------------------------------
Ran 1 test in 16.340s

OK
2022-09-03 17:46:00,482 - __main__ - INFO - *********** Running Selenium tests StandaloneChromium Tests **********
test_play_video (SeleniumTests.ChromeTests) ... ok
test_select_from_a_dropdown (SeleniumTests.ChromeTests) ... ok
test_title (SeleniumTests.ChromeTests) ... ok
test_visit_basic_auth_secured_page (SeleniumTests.ChromeTests) ... ok
test_with_frames (SeleniumTests.ChromeTests) ... ok

----------------------------------------------------------------------
Ran 5 tests in 176.257s

OK
2022-09-03 17:48:56,772 - __main__ - INFO - Cleaning up...
2022-09-03 17:48:59,230 - __main__ - INFO - Standalone Cleaned up

Verifying we're actually running armv7 images:

$ docker images
REPOSITORY                     TAG              IMAGE ID       CREATED       SIZE
selenium/standalone-firefox    4.4.0-20220903   98f35bc56550   2 hours ago   1.1GB
selenium/standalone-chromium   4.4.0-20220903   a04ce1b49493   2 hours ago   1.26GB
selenium/node-firefox          4.4.0-20220903   a273358cfd2b   2 hours ago   1.1GB
selenium/node-chromium         4.4.0-20220903   7539aa620556   2 hours ago   1.26GB
selenium/node-base             4.4.0-20220903   46ab1dee63be   3 hours ago   732MB
selenium/hub                   4.4.0-20220903   1390631f1bea   3 hours ago   344MB
selenium/base                  4.4.0-20220903   e9d73c993776   3 hours ago   344MB
aptman/qus                     latest           36b94f61e9a7   2 weeks ago   229MB

$ docker run --rm -it --platform linux/arm/v7 selenium/node-firefox:4.4.0-20220903 bash -c 'arch'
armv7l

$ docker run --rm -it --platform linux/arm/v7 selenium/node-chromium:4.4.0-20220903 bash -c 'arch'
armv7l

$ docker run --rm -it --platform linux/arm/v7 selenium/standalone-firefox:4.4.0-20220903 bash -c 'arch'
armv7l

$ docker run --rm -it --platform linux/arm/v7 selenium/standalone-chromium:4.4.0-20220903 bash -c 'arch'
armv7l

Still not successful in getting the tests to run on the armv7-tests branch on CircleCI, even with the larger arm-large runners. I will double check that I have the GRID_STATUS_MAX_ATTEMPTS=10 environment variable set. If it's not successful, then I will consider creating a script that can be run on a Mac M1 to run the tests on this hardware instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant