[gparted/filesystem-tests: 2/4] Run test program under xvfb-run to satisfy need for an X11 display (!49)



commit 318668537da33039ffc05c9a226f85e500457164
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date:   Tue Sep 24 09:17:30 2019 +0100

    Run test program under xvfb-run to satisfy need for an X11 display (!49)
    
    Running test_ext2 in GitLab Continuous Integration environment fails like
    this:
        (test_ext2:6338): Gtk-WARNING **: 09:06:17.576: cannot open display:
        Running main() from test_ext2.cc
    
    Obviously the GitLab CI environment doesn't have an X11 display, but
    unfortunately this test case code requires one.
    Utils::execute_command() calls Gtk::Main::run() so requires a Gtk::Main
    object constructing and therefore an X11 display, even though this
    program never displays anything graphical.  The call chain is:
        main()                       test_ext2.cc
          Gtk::Main::Main()          gtkmm/gtk/src/main.ccg
            Gtk::Main::init()        [1]
              gtk_init()             gtk/gtk/gtkmain.c [2]
    which exits with a non-zero exit status when the DISPLAY environment
    variable is unset.
    
    Looked at deriving from Gtk::Main class and writing a replacement init()
    method which calls gtk_init_check() instead of gtk_init() but
    Gtk::Main::instance_ is a private member so not accessible in a derived
    class.
    
    Tried using Glib::MainLoop instead of Gtk::Main, but that doesn't
    initialise everything that Gtk::Main(), so the program crashes.
    
    Therefore use xvfb-run [3][4] to run this test program against a virtual
    X11 display when a real display isn't available.  Coded execution of
    xvfb-run into this test program so that it can simply be executed on the
    command line like the other test programs, without having to remember to
    run "xvfb-run ./test_ext2 ...".
    
    [1] Gtk::Main::init()
        https://gitlab.gnome.org/GNOME/gtkmm/blob/3.10.1/gtk/src/main.ccg#L287
    [2] gtk_init()
        https://gitlab.gnome.org/GNOME/gtk/blob/3.10.9/gtk/gtkmain.c#L1000
    [3] how to run gtk app on linux without an x server
        https://superuser.com/questions/624918/how-to-run-gtk-app-on-linux-without-an-x-server
    [4] Using GTK without DISPLAY
        https://stackoverflow.com/questions/11694278/using-gtk-without-display
    
    Closes !49 - Add file system interface tests

 .gitlab-ci.yml     |  4 ++--
 tests/test_ext2.cc | 41 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 2 deletions(-)
---
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index e670c64c..fd7af87c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -11,7 +11,7 @@ stages:
                      gcc-c++ libuuid-devel parted-devel gtkmm30-devel make
                      polkit file
     # Extra packages only needed during the test stage.
-    - yum install -y e2fsprogs
+    - yum install -y e2fsprogs xorg-x11-server-Xvfb
     - cat /etc/os-release
 
 .ubuntu_image_template: &ubuntu_image_definition
@@ -23,7 +23,7 @@ stages:
                          uuid-dev libparted-dev libgtkmm-3.0-dev make
                          policykit-1
     # Extra packages only needed during the test stage.
-    - apt-get install -y e2fsprogs
+    - apt-get install -y e2fsprogs xvfb
     - cat /etc/os-release
 
 .build_stage_template: &build_stage_definition
diff --git a/tests/test_ext2.cc b/tests/test_ext2.cc
index ef5a48f2..d19ae446 100644
--- a/tests/test_ext2.cc
+++ b/tests/test_ext2.cc
@@ -43,6 +43,7 @@
 
 #include <iostream>
 #include <fstream>
+#include <stdlib.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <unistd.h>
@@ -203,6 +204,38 @@ TEST_F(ext2Test, Create)
 }  // namespace GParted
 
 
+// Re-execute current executable using xvfb-run so that it provides a virtual X11 display.
+void exec_using_xvfb_run(int argc, char** argv)
+{
+       // argc+2 = Space for "xvfb-run" command, existing argc strings plus NULL pointer.
+       size_t size = sizeof(char*) * (argc+2);
+       char** new_argv = (char**)malloc(size);
+       if (new_argv == NULL)
+       {
+               fprintf(stderr, "Failed to allocate %lu bytes of memory.  errno=%d,%s\n",
+                       (unsigned long)size, errno, strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+
+       new_argv[0] = strdup("xvfb-run");
+       if (new_argv[0] == NULL)
+       {
+               fprintf(stderr, "Failed to allocate %lu bytes of memory.  errno=%d,%s\n",
+                       (unsigned long)strlen(new_argv[0])+1, errno, strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+
+       // Copy argv pointers including final NULL pointer.
+       for (unsigned int i = 0; i <= (unsigned)argc; i++)
+               new_argv[i+1] = argv[i];
+
+       execvp(new_argv[0], new_argv);
+       fprintf(stderr, "Failed to execute '%s %s ...'.  errno=%d,%s\n", new_argv[0], new_argv[1],
+               errno, strerror(errno));
+       exit(EXIT_FAILURE);
+}
+
+
 // Custom Google Test main().
 // Reference:
 // *   Google Test, Primer, Writing the main() function
@@ -210,6 +243,14 @@ TEST_F(ext2Test, Create)
 int main(int argc, char** argv)
 {
        printf("Running main() from %s\n", __FILE__);
+
+       const char* display = getenv("DISPLAY");
+       if (display == NULL)
+       {
+               printf("DISPLAY environment variable unset.  Executing 'xvfb-run %s ...'\n", argv[0]);
+               exec_using_xvfb_run(argc, argv);
+       }
+
        testing::InitGoogleTest(&argc, argv);
 
        // Initialise threading in GParted to allow FileSystem interface classes to


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]