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