【问题标题】:Django Selenium test works in local Docker container but not on Jenkins serverDjango Selenium 测试适用于本地 Docker 容器,但不适用于 Jenkins 服务器
【发布时间】:2021-06-02 14:24:28
【问题描述】:

当我以交互模式在本地运行 Docker 映像然后手动进行测试时,它可以工作。但是当我推送到 GitHub 时,Jenkins 会拉取并运行测试,然后在尝试启动 Firefox 浏览器时超时。

我尝试了不同的 Docker 基础镜像。我尝试将 executable_path 提供给本地文件,也没有(在添加系统路径时)。

我是 Docker 和 Jenkins 的新手,我不确定自己做错了什么。 提前感谢您的帮助。

码头文件:

FROM ubuntu:bionic

COPY BS_PM2021_TEAM_27/requirements.txt requirements.txt
RUN apt-get update
RUN su -
RUN apt-get install sudo -y
RUN sudo apt-get install -y xvfb
RUN sudo apt-get install -y firefox
RUN sudo apt-get install -y wget
RUN wget https://github.com/mozilla/geckodriver/releases/download/v0.24.0/geckodriver-v0.24.0-linux64.tar.gz
RUN tar -xvzf geckodriver*
RUN chmod +x geckodriver
RUN sudo mv geckodriver /usr/local/bin/
RUN export GECKODRIVER=$PATH:/user/local/bin/geckodriver
RUN sudo apt-get install -y python3.8
RUN sudo apt-get install -y python3-pip
RUN pip3 install -r requirements.txt
RUN Xvfb &
RUN export DISPLAY=localhost:0.0

WORKDIR .

COPY . .

requirements.txt:

asgiref==3.3.4
Django==3.2.3
EasyProcess==0.3
filter-profanity==1.0.9
pytz==2021.1
PyVirtualDisplay==2.2
selenium==3.141.0
sqlparse==0.4.1
urllib3==1.26.5

Jenkins 文件:

pipeline {
    environment {
        OUTPUT1 = "foo"
        OUTPUT2 = 'bar'
    }
    agent {
        dockerfile true
    }
    triggers {
        githubPush()
    }
    stages {
        stage('Build') {
            steps {
                sh """
                    cd BS_PM2021_TEAM_27
                    chmod 555 geckodriver-linux64
                    python3 manage.py makemigrations
                    python3 manage.py migrate
                """
            }
        }
        stage('Run Unit Tests') {
            steps {
                dir("BS_PM2021_TEAM_27"){
                    script{
                        try{
                            sh(returnStdout: true, script: "python3 manage.py test Preschool_Play.tests_integration.TestIntegrationWithSelenium.test_login_then_add_and_delete_new_child 2>&1 | xargs echo > out1.txt")
                        }finally{
                            OUTPUT1 = sh(returnStdout: true, script: "cat out1.txt")
                            OUTPUT2 = sh(returnStdout: true, script: "tail -4 geckodriver.log")
                        }
                    }
                }
            }
        }
    }
    post{
        always{
            echo 'Sending test report email...'
            dir("BS_PM2021_TEAM_27"){
                sh """
                     python3 manage.py email_report -s "Tests Report" -b "${OUTPUT1}"
                     python3 manage.py email_report -s "Log" -b '${OUTPUT2}'
                """
            }
            echo 'Email sent.'
        }
    }
}

测试文件:

import time
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from django.test.utils import override_settings
from selenium import webdriver
from selenium.webdriver import FirefoxOptions
from .models import *
import os
from pyvirtualdisplay import Display


class TestIntegrationWithSelenium(StaticLiveServerTestCase):

    def setUp(self):
        if os.name != 'nt':
            opts = FirefoxOptions()
            opts.add_argument("--headless")
            opts.add_argument('--disable-gpu')
            self.display = Display(visible=False, size=(800, 600))
            self.display.start()
            self.browser = webdriver.Firefox(executable_path='./geckodriver-linux64', options=opts)
        else:
            self.browser = webdriver.Firefox(executable_path='./win-geckodriver.exe')
        ...

    def tearDown(self):
        self.browser.close()
        self.display.stop()

    @override_settings(DEBUG=True)
    def test_login_then_add_and_delete_new_child(self):
        ...

Jenkins 构建控制台输出:

Started by user eilonco
Obtained BS_PM2021_TEAM_27/Jenkinsfile from git https://github.com/RotemLibrati/BS_PM2021_TEAM_27
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] node
Running on Jenkins in /var/jenkins_home/workspace/Team_27/Team27Pipe
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Declarative: Checkout SCM)
[Pipeline] checkout
No credentials specified
 > git rev-parse --is-inside-work-tree # timeout=10
Fetching changes from the remote Git repository
 > git config remote.origin.url https://github.com/RotemLibrati/BS_PM2021_TEAM_27 # timeout=10
Fetching upstream changes from https://github.com/RotemLibrati/BS_PM2021_TEAM_27
 > git --version # timeout=10
 > git fetch --tags --progress -- https://github.com/RotemLibrati/BS_PM2021_TEAM_27 +refs/heads/*:refs/remotes/origin/* # timeout=10
 > git rev-parse refs/remotes/origin/master^{commit} # timeout=10
 > git rev-parse refs/remotes/origin/origin/master^{commit} # timeout=10
Checking out Revision bbd3426db88b2b6c0f463462d047c5dd5dac5053 (refs/remotes/origin/master)
 > git config core.sparsecheckout # timeout=10
 > git checkout -f bbd3426db88b2b6c0f463462d047c5dd5dac5053 # timeout=10
Commit message: "ubuntu2"
 > git rev-list --no-walk bbd3426db88b2b6c0f463462d047c5dd5dac5053 # timeout=10
[Pipeline] }
[Pipeline] // stage
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Declarative: Agent Setup)
[Pipeline] isUnix
[Pipeline] readFile
[Pipeline] sh
+ docker build -t 13639d9ab6390428bae282a0c7bbd0a0cdd1b696 -f Dockerfile .
Sending build context to Docker daemon  97.69MB

Step 1/20 : FROM ubuntu:bionic
 ---> 81bcf752ac3d
Step 2/20 : COPY BS_PM2021_TEAM_27/requirements.txt requirements.txt
 ---> Using cache
 ---> b848b4fa92dc
Step 3/20 : RUN apt-get update
 ---> Using cache
 ---> bae0ca787abd
Step 4/20 : RUN su -
 ---> Using cache
 ---> f301a6b617a1
Step 5/20 : RUN apt-get install sudo -y
 ---> Using cache
 ---> 3e273f710455
Step 6/20 : RUN sudo apt-get install -y xvfb
 ---> Using cache
 ---> 9d9a38840300
Step 7/20 : RUN sudo apt-get install -y firefox
 ---> Using cache
 ---> 434e2720c7a4
Step 8/20 : RUN sudo apt-get install -y wget
 ---> Using cache
 ---> 81e448f0eda5
Step 9/20 : RUN wget https://github.com/mozilla/geckodriver/releases/download/v0.24.0/geckodriver-v0.24.0-linux64.tar.gz
 ---> Using cache
 ---> 02e07299c327
Step 10/20 : RUN tar -xvzf geckodriver*
 ---> Using cache
 ---> 0371bbbf3016
Step 11/20 : RUN chmod +x geckodriver
 ---> Using cache
 ---> d23fe7800069
Step 12/20 : RUN sudo mv geckodriver /usr/local/bin/
 ---> Using cache
 ---> b63dd57bc1eb
Step 13/20 : RUN export GECKODRIVER=$PATH:/user/local/bin/geckodriver
 ---> Using cache
 ---> ee6e81e81a6a
Step 14/20 : RUN sudo apt-get install -y python3.8
 ---> Using cache
 ---> 9b61093b0eb9
Step 15/20 : RUN sudo apt-get install -y python3-pip
 ---> Using cache
 ---> 7a647ad74b43
Step 16/20 : RUN pip3 install -r requirements.txt
 ---> Using cache
 ---> 0d17d8da547e
Step 17/20 : RUN Xvfb &
 ---> Using cache
 ---> 201fb5ca7b65
Step 18/20 : RUN export DISPLAY=localhost:0.0
 ---> Using cache
 ---> c0fab92bf6d6
Step 19/20 : WORKDIR .
 ---> Using cache
 ---> 7738a4afa668
Step 20/20 : COPY . .
 ---> 7fea506200d5
Successfully built 7fea506200d5
Successfully tagged 13639d9ab6390428bae282a0c7bbd0a0cdd1b696:latest
[Pipeline] }
[Pipeline] // stage
[Pipeline] isUnix
[Pipeline] sh
+ docker inspect -f . 13639d9ab6390428bae282a0c7bbd0a0cdd1b696
.
[Pipeline] withDockerContainer
Jenkins seems to be running inside container 1b8310761f551fe6f780ed06f030c1bfa7f8f94aaec42df21ceb958a5f8a9417
$ docker run -t -d -u 1000:1000 -w /var/jenkins_home/workspace/Team_27/Team27Pipe --volumes-from 1b8310761f551fe6f780ed06f030c1bfa7f8f94aaec42df21ceb958a5f8a9417 -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** 13639d9ab6390428bae282a0c7bbd0a0cdd1b696 cat
$ docker top 00492076b546b5a216713f20e47a2399bd87b3186226bbc8cb53abdba42c6f4f -eo pid,comm
[Pipeline] {
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Build)
[Pipeline] sh
+ cd BS_PM2021_TEAM_27
+ chmod 555 geckodriver-linux64
+ python3 manage.py makemigrations
No changes detected
+ python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  No migrations to apply.
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Run Unit Tests)
[Pipeline] dir
Running in /var/jenkins_home/workspace/Team_27/Team27Pipe/BS_PM2021_TEAM_27
[Pipeline] {
[Pipeline] script
[Pipeline] {
[Pipeline] sh
+ python3 manage.py test Preschool_Play.tests_integration.TestIntegrationWithSelenium.test_login_then_add_and_delete_new_child
+ xargs echo
[Pipeline] sh
+ cat out1.txt
[Pipeline] sh
+ tail -4 geckodriver.log
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // dir
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Declarative: Post Actions)
[Pipeline] echo
Sending test report email...
[Pipeline] dir
Running in /var/jenkins_home/workspace/Team_27/Team27Pipe/BS_PM2021_TEAM_27
[Pipeline] {
[Pipeline] sh
+ python3 manage.py email_report -s Tests Report -b Creating test database for alias default... System check identified no issues (0 silenced). E ====================================================================== ERROR: test_login_then_add_and_delete_new_child (Preschool_Play.tests_integration.TestIntegrationWithSelenium) ---------------------------------------------------------------------- Traceback (most recent call last): File /var/jenkins_home/workspace/Team_27/Team27Pipe/BS_PM2021_TEAM_27/Preschool_Play/tests_integration.py, line 20, in setUp self.browser = webdriver.Firefox(executable_path=./geckodriver-linux64, options=opts) File /usr/local/lib/python3.6/dist-packages/selenium/webdriver/firefox/webdriver.py, line 174, in __init__ keep_alive=True) File /usr/local/lib/python3.6/dist-packages/selenium/webdriver/remote/webdriver.py, line 157, in __init__ self.start_session(capabilities, browser_profile) File /usr/local/lib/python3.6/dist-packages/selenium/webdriver/remote/webdriver.py, line 252, in start_session response = self.execute(Command.NEW_SESSION, parameters) File /usr/local/lib/python3.6/dist-packages/selenium/webdriver/remote/webdriver.py, line 321, in execute self.error_handler.check_response(response) File /usr/local/lib/python3.6/dist-packages/selenium/webdriver/remote/errorhandler.py, line 242, in check_response raise exception_class(message, screen, stacktrace) selenium.common.exceptions.TimeoutException: Message: Connection refused (os error 111) ---------------------------------------------------------------------- Ran 1 test in 61.588s FAILED (errors=1) Destroying test database for alias default...

+ python3 manage.py email_report -s Log -b [GFX1-]: glxtest: libpci missing
[GFX1-]: glxtest: libEGL missing
[GFX1-]: glxtest: libEGL missing
[GFX1-]: RenderCompositorSWGL failed mapping default framebuffer, no dt

[Pipeline] }
[Pipeline] // dir
[Pipeline] echo
Email sent.
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
$ docker stop --time=1 00492076b546b5a216713f20e47a2399bd87b3186226bbc8cb53abdba42c6f4f
$ docker rm -f 00492076b546b5a216713f20e47a2399bd87b3186226bbc8cb53abdba42c6f4f
[Pipeline] // withDockerContainer
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

Django 控制台输出:

Creating test database for alias default...
System check identified no issues (0 silenced).
E ======================================================================
ERROR: test_login_then_add_and_delete_new_child (Preschool_Play.tests_integration.TestIntegrationWithSelenium)
----------------------------------------------------------------------
Traceback (most recent call last): File /var/jenkins_home/workspace/Team_27/Team27Pipe/BS_PM2021_TEAM_27/Preschool_Play/tests_integration.py,
line 20, in setUp self.browser = webdriver.Firefox(executable_path=./geckodriver-linux64, options=opts)
File /usr/local/lib/python3.6/dist-packages/selenium/webdriver/firefox/webdriver.py,
line 174, in __init__ keep_alive=True) File /usr/local/lib/python3.6/dist-packages/selenium/webdriver/remote/webdriver.py,
line 157, in __init__ self.start_session(capabilities, browser_profile) File /usr/local/lib/python3.6/dist-packages/selenium/webdriver/remote/webdriver.py,
line 252, in start_session response = self.execute(Command.NEW_SESSION, parameters) File /usr/local/lib/python3.6/dist-packages/selenium/webdriver/remote/webdriver.py,
line 321, in execute self.error_handler.check_response(response) File /usr/local/lib/python3.6/dist-packages/selenium/webdriver/remote/errorhandler.py,
line 242, in check_response raise exception_class(message, screen, stacktrace) selenium.common.exceptions.TimeoutException: Message: Connection refused (os error 111)
----------------------------------------------------------------------
Ran 1 test in 61.588s FAILED (errors=1)
Destroying test database for alias default...

geckodriver.log:

[GFX1-]: glxtest: libpci missing
[GFX1-]: glxtest: libEGL missing
[GFX1-]: glxtest: libEGL missing
[GFX1-]: RenderCompositorSWGL failed mapping default framebuffer, no dt

当我在本地容器上运行时,测试通过并且 geckodriver.log 是:

# cat geckodriver.log
1622651926935   mozrunner::runner       INFO    Running command: "/usr/bin/firefox" "-marionette" "--headless" "--disable-gpu" "-foreground" "-no-remote" "-profile" "/tmp/rust_mozprofile.jh7CncJfRv6O"
*** You are running in headless mode.
[GFX1-]: glxtest: libpci missing
[GFX1-]: glxtest: libEGL missing
[GFX1-]: glxtest: Unable to open a connection to the X server
[GFX1-]: glxtest: libEGL missing
[GFX1-]: No GPUs detected via PCI
1622651927369   Marionette      INFO    Marionette enabled

(/usr/lib/firefox/firefox:81): GLib-GObject-CRITICAL **: 16:38:47.908: g_object_set: assertion 'G_IS_OBJECT (object)' failed

(/usr/lib/firefox/firefox:101): GLib-GObject-CRITICAL **: 16:38:47.998: g_object_set: assertion 'G_IS_OBJECT (object)' failed
console.warn: SearchSettings: "get: No settings file exists, new profile?" (new Error("", "(unknown module)"))
1622651929513   Marionette      INFO    Listening on port 45265

(/usr/lib/firefox/firefox:163): GLib-GObject-CRITICAL **: 16:38:49.575: g_object_set: assertion 'G_IS_OBJECT (object)' failed
1622651929580   Marionette      WARN    TLS certificate errors will be ignored for this session
1622651936233   Marionette      INFO    Stopped listening on port 45265

这里我在Ubuntu服务器上运行也成功了:

ubuntu@primary:~$ cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.2 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
ubuntu@primary:~$ docker container start -a -i eager_cartwright
root@68abe3dfecd3:/# cd BS_PM2021_TEAM_27/
root@68abe3dfecd3:/BS_PM2021_TEAM_27# rm geckodriver.log
root@68abe3dfecd3:/BS_PM2021_TEAM_27# python3 manage.py test Preschool_Play.tests_integration.TestIntegrationWithSelenium.test_login_then_add_and_delete_new_child
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
Not Found: /favicon.ico
Not Found: /favicon.ico
[<Child: Name: kid2. Parent: parent>]
.
----------------------------------------------------------------------
Ran 1 test in 14.417s

OK
Destroying test database for alias 'default'...
root@68abe3dfecd3:/BS_PM2021_TEAM_27#
root@68abe3dfecd3:/BS_PM2021_TEAM_27# cat geckodriver.log
1622660833134   geckodriver     INFO    Listening on 127.0.0.1:32959
1622660834143   mozrunner::runner       INFO    Running command: "/usr/bin/firefox" "--marionette" "--headless" "--disable-gpu" "-foreground" "-no-remote" "-profile" "/tmp/rust_mozprofilePskEQC"
*** You are running in headless mode.
[GFX1-]: glxtest: libpci missing
[GFX1-]: glxtest: libEGL missing
[GFX1-]: glxtest: Unable to open a connection to the X server
[GFX1-]: glxtest: libEGL missing
[GFX1-]: No GPUs detected via PCI
1622660834624   Marionette      INFO    Marionette enabled

(/usr/lib/firefox/firefox:73): GLib-GObject-CRITICAL **: 19:07:15.322: g_object_set: assertion 'G_IS_OBJECT (object)' failed

(/usr/lib/firefox/firefox:88): GLib-GObject-CRITICAL **: 19:07:15.523: g_object_set: assertion 'G_IS_OBJECT (object)' failed
console.warn: SearchSettings: "get: No settings file exists, new profile?" (new Error("", "(unknown module)"))
1622660838023   Marionette      INFO    Listening on port 45137
1622660838185   Marionette      WARN    TLS certificate errors will be ignored for this session

(/usr/lib/firefox/firefox:151): GLib-GObject-CRITICAL **: 19:07:18.187: g_object_set: assertion 'G_IS_OBJECT (object)' failed
1622660846356   Marionette      INFO    Stopped listening on port 45137

更新:我怀疑我大学的服务器没有显示选项,也没有 GPU,这就是 Selenium 找不到任何 GPU 的原因。但是我不知道它仍然可以在没有 GUI 的 Ubuntu 服务器上运行的原因。也许是因为 Ubuntu 服务器仍然可以识别我的笔记本电脑 GPU。

【问题讨论】:

    标签: python django docker jenkins selenium-webdriver


    【解决方案1】:

    问题在于 X 服务器的帧缓冲区,在 Ubuntu 服务器上测试,你会遇到同样的问题

    【讨论】:

    • 当我在 Ubuntu 容器中运行它时,它也会抱怨 X 服务器,但它仍然通过了测试。你确定这是问题吗?我添加了本地容器成功的日志文件
    • 尝试在 ubuntu 服务器而不是 ubuntu 桌面上运行容器
    • 它也适用于 ubuntu 服务器。我是不是误会或做错了什么?
    • 詹金斯在哪里
    • 根据日志,问题是 GFX1-]:glxtest:libpci 缺失 [GFX1-]:glxtest:libEGL 缺失 [GFX1-]:glxtest:无法打开与 X 服务器的连接 [GFX1- ]: glxtest: libEGL 缺失 [GFX1-]: 没有通过 PCI 检测到 GPU
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多