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
This commit is contained in:
Mike Fleetwood 2019-09-24 09:17:30 +01:00 committed by Curtis Gedak
parent a97c23c57c
commit 8db9a83b39
2 changed files with 44 additions and 2 deletions

View File

@ -11,7 +11,7 @@ stages:
gcc-c++ libuuid-devel parted-devel gtkmm30-devel make gcc-c++ libuuid-devel parted-devel gtkmm30-devel make
polkit file polkit file
# Extra packages only needed during the test stage. # Extra packages only needed during the test stage.
- yum install -y e2fsprogs - yum install -y e2fsprogs xorg-x11-server-Xvfb
- cat /etc/os-release - cat /etc/os-release
.ubuntu_image_template: &ubuntu_image_definition .ubuntu_image_template: &ubuntu_image_definition
@ -23,7 +23,7 @@ stages:
uuid-dev libparted-dev libgtkmm-3.0-dev make uuid-dev libparted-dev libgtkmm-3.0-dev make
policykit-1 policykit-1
# Extra packages only needed during the test stage. # Extra packages only needed during the test stage.
- apt-get install -y e2fsprogs - apt-get install -y e2fsprogs xvfb
- cat /etc/os-release - cat /etc/os-release
.build_stage_template: &build_stage_definition .build_stage_template: &build_stage_definition

View File

@ -43,6 +43,7 @@
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <stdlib.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
@ -203,6 +204,38 @@ TEST_F(ext2Test, Create)
} // namespace GParted } // 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(). // Custom Google Test main().
// Reference: // Reference:
// * Google Test, Primer, Writing the main() function // * Google Test, Primer, Writing the main() function
@ -210,6 +243,15 @@ TEST_F(ext2Test, Create)
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
printf("Running main() from %s\n", __FILE__); 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);
}
printf("DISPLAY=\"%s\"\n", display);
testing::InitGoogleTest(&argc, argv); testing::InitGoogleTest(&argc, argv);
// Initialise threading in GParted to allow FileSystem interface classes to // Initialise threading in GParted to allow FileSystem interface classes to