1 /* GLib testing framework examples and tests
2 *
3 * Copyright © 2015 Collabora Ltd.
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <glib.h>
22
23 /* This test does NOT depend on any dbus binaries preinstalled on test host.
24 * On Unix it uses mock environment (test_xdg_runtime)
25 * or mock dbus-launch binary (test_x11_autolaunch).
26 * On Windows it relies on the fact that libgio provides
27 * internal session dbus-server on win32.
28 */
29
30 #include <errno.h>
31
32 #include <glib/gstdio.h>
33 #include <gio/gio.h>
34 #include <gio/gunixsocketaddress.h>
35
36 static void
37 print_address (void)
38 {
39 GError *error = NULL;
40 gchar *addr;
41
42 addr = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, NULL,
43 &error);
44
45 g_assert_no_error (error);
46 g_assert_nonnull (addr);
47 g_print ("%s\n", addr);
48 g_free (addr);
49 }
50
51 #ifdef G_OS_UNIX
52
53 static GSocket *mock_bus = NULL;
54 static gchar *mock_bus_path = NULL;
55 /* this is deliberately something that needs escaping */
56 static gchar tmpdir[] = "/tmp/gdbus,unix,test.XXXXXX";
57
58 static void
59 set_up_mock_xdg_runtime_dir (void)
60 {
61 GError *error = NULL;
62 GSocketAddress *addr;
63
64 mock_bus = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, 0,
65 &error);
66 g_assert_no_error (error);
67 g_assert_true (G_IS_SOCKET (mock_bus));
68
69 /* alters tmpdir in-place */
70 if (g_mkdtemp_full (tmpdir, 0700) == NULL)
71 {
72 int errsv = errno;
73 g_error ("g_mkdtemp_full: %s", g_strerror (errsv));
74 }
75
76 mock_bus_path = g_strconcat (tmpdir, "/bus", NULL);
77 addr = g_unix_socket_address_new (mock_bus_path);
78 g_socket_bind (mock_bus, addr, FALSE, &error);
79 g_assert_no_error (error);
80 g_object_unref (addr);
81
82 g_setenv ("XDG_RUNTIME_DIR", tmpdir, TRUE);
83 }
84
85 static void
86 tear_down_mock_xdg_runtime_dir (void)
87 {
88 GError *error = NULL;
89
90 g_socket_close (mock_bus, &error);
91 g_assert_no_error (error);
92
93 if (g_unlink (mock_bus_path) < 0)
94 {
95 int errsv = errno;
96 g_error ("g_unlink(\"%s\"): %s", mock_bus_path, g_strerror (errsv));
97 }
98
99 if (g_rmdir (tmpdir) < 0)
100 {
101 int errsv = errno;
102 g_error ("g_rmdir(\"%s\"): %s", tmpdir, g_strerror (errsv));
103 }
104
105 g_clear_object (&mock_bus);
106 g_clear_pointer (&mock_bus_path, g_free);
107 }
108
109 static gchar *path = NULL;
110
111 static void
112 set_up_mock_dbus_launch (void)
113 {
114 path = g_strconcat (g_test_get_dir (G_TEST_BUILT), ":",
115 g_getenv ("PATH"), NULL);
116 g_setenv ("PATH", path, TRUE);
117
118 /* libdbus won't even try X11 autolaunch if DISPLAY is unset; GDBus
119 * does the same in Debian derivatives (proposed upstream in
120 * GNOME#723506) */
121 g_setenv ("DISPLAY", "an unrealistic mock X11 display", TRUE);
122 }
123
124 static void
125 tear_down_mock_dbus_launch (void)
126 {
127 g_clear_pointer (&path, g_free);
128 }
129
130 static void
131 test_x11_autolaunch (void)
132 {
133 if (g_test_subprocess ())
134 {
135 g_unsetenv ("DISPLAY");
136 g_unsetenv ("DBUS_SESSION_BUS_ADDRESS");
137 g_unsetenv ("XDG_RUNTIME_DIR");
138 g_unsetenv ("G_MESSAGES_DEBUG");
139 set_up_mock_dbus_launch ();
140
141 print_address ();
142
143 tear_down_mock_dbus_launch ();
144 return;
145 }
146
147 g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT);
148 g_test_trap_assert_stderr_unmatched ("?*");
149 g_test_trap_assert_stdout ("hello:this=address-is-from-the,mock=dbus-launch\n");
150 g_test_trap_assert_passed ();
151 }
152
153 static void
154 test_xdg_runtime (void)
155 {
156 if (g_test_subprocess ())
157 {
158 g_unsetenv ("DISPLAY");
159 g_unsetenv ("DBUS_SESSION_BUS_ADDRESS");
160 set_up_mock_xdg_runtime_dir ();
161 set_up_mock_dbus_launch ();
162
163 print_address ();
164
165 tear_down_mock_dbus_launch ();
166 tear_down_mock_xdg_runtime_dir ();
167 return;
168 }
169
170 g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT);
171 g_test_trap_assert_stderr_unmatched ("?*");
172 g_test_trap_assert_stdout ("unix:path=/tmp/gdbus%2Cunix%2Ctest.*/bus\n");
173 g_test_trap_assert_passed ();
174 }
175
176 #endif
177
178 #ifdef G_OS_WIN32
179 static void
180 check_and_cleanup_autolaunched_win32_bus (void)
181 {
182 /* win32 autostarted bus runs infinitely if no client ever connected.
183 * However it exits in several seconds if the last client disconnects.
184 * _This_ test only checks successful launching and connectivity,
185 * and don't bother on bus termination behavior (being it a bug or not).
186 * So connect+disconnect here is not only connectivity test,
187 * but also the workaround the bus process infinite run.
188 */
189 GError *err = NULL;
190 GDBusConnection *bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &err);
191 g_assert_no_error (err);
192 g_object_unref (bus);
193 }
194
195 static void
196 test_win32_autolaunch (void)
197 {
198 if (g_test_subprocess ())
199 {
200 print_address ();
201
202 check_and_cleanup_autolaunched_win32_bus ();
203 return;
204 }
205
206 g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT);
207 /* stderr is not checked: coverage prints warnings there */
208 g_test_trap_assert_stdout ("nonce-tcp:host=localhost,port=*,noncefile=*\\gdbus-nonce-file-*\n");
209 g_test_trap_assert_passed ();
210 }
211 #endif
212
213 int
214 main (int argc,
215 char *argv[])
216 {
217 g_test_init (&argc, &argv, NULL);
218
219 #ifdef G_OS_UNIX
220 g_test_add_func ("/gdbus/x11-autolaunch", test_x11_autolaunch);
221 g_test_add_func ("/gdbus/xdg-runtime", test_xdg_runtime);
222 #endif
223
224 #ifdef G_OS_WIN32
225 g_test_add_func ("/gdbus/win32-autolaunch", test_win32_autolaunch);
226 #endif
227
228 return g_test_run ();
229 }