Docker 容器中的 Django 无法与 Selenium Grid 4 一起使用

问题描述 投票:0回答:1

我最近开始尝试容器化 django 应用程序。几天来我一直在努力让测试发挥作用,但没有成功。我没有使用 Selenium Grid 的经验,但这似乎是在 docker 容器中使用 Django 的方式,特别是当我需要能够查看正在发生的情况时。

# docker-compose.yml
version: "3.9"

services:
  myapp:
    build: .
    command: bash -c "
        npm run build
        && python manage.py migrate
        && python manage.py runserver 0.0.0.0:8000"

    volumes:
      - ./:/myapp
    env_file:
      - .env
    container_name: myapp-container
    ports:
      - "8000:8000"
    networks:
      mynetwork:
        ipv4_address: 171.20.0.3
  selenium-hub:
    image: selenium/hub:4.1
    container_name: selenium-hub
    ports:
      - "4442:4442"
      - "4443:4443"
      - "4444:4444"
    networks:
      mynetwork:
        ipv4_address: 171.20.0.4

  chrome:
    image: selenium/node-chrome:4.1
    container_name: chrome-worker
    shm_size: 2gb
    depends_on:
      - selenium-hub
    environment:
      - SE_EVENT_BUS_HOST=selenium-hub
      - SE_EVENT_BUS_PUBLISH_PORT=4442
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443

    networks:
      mynetwork:
        ipv4_address: 171.20.0.8


networks:
    mynetwork:
      ipam:
        config:
          - subnet: 171.20.0.0/24
            gateway: 171.20.0.1

在我的代码中,只需将

context.selenium = webdriver.Chrome(chrome_options=chrome_options)
更改为以下内容即可:

# environment.py - for Behave BDD testing

os.environ['DJANGO_LIVE_TEST_SERVER_ADDRESS'] = 'localhost:8000'

def before_all(context):
    chrome_options = Options()
    chrome_options.add_argument("--headless")
    chrome_options.add_argument("--disable-gpu")
    chrome_options.add_argument("--window-size=3840,2160")
    chrome_options.add_argument("--allow-insecure-localhost")
    # chrome_options.add_experimental_option("detach", True)
    # context.selenium = webdriver.Chrome(chrome_options=chrome_options)
    context.selenium = webdriver.Remote(command_executor='http://localhost:4444', options=chrome_options)
    context.selenium.implicitly_wait(1)
    TransactionTestCase.serialized_rollback = True

但是这会导致此错误:

HOOK-ERROR in before_all: MaxRetryError: HTTPConnectionPool(host='localhost', port=4444): Max retries exceeded with url: /session (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7fb9ddfe15b0>: Failed to establish a new connection: [Errno 111] Connection refused'))

我更新 command_executer 以使用服务主机名,如下所示:

   context.selenium = webdriver.Remote(command_executor='http://selenium-hub:4444', options=chrome_options)

这似乎取得了进展,测试开始运行,但每个单独的测试都出现了不同的连接错误:

raise exception_class(message, screen, stacktrace)
 selenium.common.exceptions.WebDriverException: Message: unknown error: 
net::ERR_CONNECTION_REFUSED (Session info: headless chrome=96.0.4664.45)

此外,现在似乎有来自 selenium-hub 和 chrome 服务的活动

selenium-hub     | 16:07:16.940 INFO [LocalDistributor.newSession] - Session created by the distributor. Id: 444dbca185db76e7e8780c98680b7859, Caps: Capabilities {acceptInsecureCerts: false, browserName: chrome, browserVersion: 96.0.4664.45, chrome: {chromedriverVersion: 96.0.4664.45 (76e4c1bb2ab46..., userDataDir: /tmp/.com.google.Chrome.2RTzs7}, goog:chromeOptions: {debuggerAddress: localhost:40633}, networkConnectionEnabled: false, pageLoadStrategy: normal, platformName: ANY, proxy: {}, se:cdp: ws://171.20.0.8:4444/sessio..., se:cdpVersion: 96.0.4664.45, se:vnc: ws://171.20.0.8:4444/sessio..., se:vncEnabled: true, se:vncLocalAddress: ws://171.20.0.8:7900, setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify, webauthn:extension:credBlob: true, webauthn:extension:largeBlob: true, webauthn:virtualAuthenticators: true}
chrome-worker    | 16:07:28.510 WARN [SeleniumSpanExporter$1.lambda$export$0] - {"traceId": "ae4768e55f596539cf20032361104584","eventTime": 1637770048509670200,"eventName": "HTTP request execution complete","attributes": {"http.flavor": 1,"http.handler_class": "org.openqa.selenium.remote.http.Route$PredicatedRoute","http.host": "171.20.0.4:4444","http.method": "POST","http.request_content_length": "41","http.scheme": "HTTP","http.status_code": 500,"http.target": "\u002fsession\u002f444dbca185db76e7e8780c98680b7859\u002furl","http.user_agent": "selenium\u002f3.141.0 (python linux)"}}
chrome-worker    | 
chrome-worker    | 16:07:51.014 WARN [SeleniumSpanExporter$1.lambda$export$0] - {"traceId": "338e4e8e48d62681ed1cb1e729d490d6","eventTime": 1637770071013768000,"eventName": "HTTP request execution complete","attributes": {"http.flavor": 1,"http.handler_class": "org.openqa.selenium.remote.http.Route$PredicatedRoute","http.host": "171.20.0.4:4444","http.method": "POST","http.request_content_length": "41","http.scheme": "HTTP","http.status_code": 500,"http.target": "\u002fsession\u002f444dbca185db76e7e8780c98680b7859\u002furl","http.user_agent": "selenium\u002f3.141.0 (python linux)"}}

我尝试删除为处理另一个问题而添加的自定义网络,但这没有帮助。我也尝试过使用特定的 IP 地址。当我尝试使用

myapp
curl -I http://selenium-hub/4444

容器连接到其他容器时
HTTP/1.1 302 Found
content-length: 0
Location: /ui/index.html

我不知道从这里该去哪里。

编辑:一些额外的上下文:

我正在使用 Behave 测试框架以及Behavior-django 包。安装和拆卸位于环境.py 文件中,如上所示。所有测试都位于

features
模块中并使用 docker,我从
docker exec -it myapp-container ./manage.py behave ./myapp/features/account.feature
开始。这在 docker 之外与常规 webdriver 完全兼容。我在上面添加了一行,显示
DJANGO_LIVE_TEST_SERVER_ADDRESS
环境变量的设置位置。似乎这对于使其发挥作用的其他问题很重要。我尝试将其设置为 django 服务主机名 -
myapp
以及分配的 IP 地址。 Behavior-django 库使用 LiveServerTestCase

启动测试服务器
python django docker selenium selenium-grid
1个回答
0
投票

我今天在对使用Behavior-django和Selenium Grid的应用程序进行docker化时遇到了这个确切的问题。

核心问题是Selenium/Firefox容器需要使用'myapp'主机而不是'localhost'。

我猴子修补了我的

LiveServerTestCase
中的
environment.py
类,如下所示:


import os
from django.test.testcases import LiveServerTestCase
from selenium import webdriver

os.environ["DJANGO_SETTINGS_MODULE"] = "backend.settings"


def before_all(context):
    options = webdriver.FirefoxOptions()
    if os.path.exists("/.dockerenv"):
        LiveServerTestCase.host = "myapp"
        context.driver = webdriver.Remote(
            command_executor="http://firefox:4444/wd/hub",
            desired_capabilities=options.to_capabilities(),
        )
    else:
        # needs geckodriver on system $PATH to control local firefox
        context.driver = webdriver.Firefox(options=options)


def after_all(context):
    context.driver.quit()

不要覆盖LiveServerTestCase

port
属性。每个测试都会在随机端口上实例化一个新服务器。我不知道这一点,并且花了很长时间想知道为什么我的第一个测试会通过,但第二个测试总是出现“地址正在使用”错误。

当您在行为步骤中使用

context.get_url()

 时,URL 将使用“myapp”主机和该测试的随机端口进行更新。例如。 
http://myapp:378936

进一步注意 if-else 逻辑,它检查我是否处于 Docker 环境中。这样,我就不会失去在本地计算机上以通常的方式运行项目的能力。

© www.soinside.com 2019 - 2024. All rights reserved.