Line data Source code
1 : /*
2 : SSSD
3 :
4 : Common utilities for dbus based tests.
5 :
6 : Authors:
7 : Stef Walter <stefw@redhat.com>
8 :
9 : Copyright (C) Red Hat, Inc 2014
10 :
11 : This program is free software; you can redistribute it and/or modify
12 : it under the terms of the GNU General Public License as published by
13 : the Free Software Foundation; either version 3 of the License, or
14 : (at your option) any later version.
15 :
16 : This program is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : GNU General Public License for more details.
20 :
21 : You should have received a copy of the GNU General Public License
22 : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 : */
24 :
25 : #include "config.h"
26 :
27 : #include <stdio.h>
28 : #include "tests/common.h"
29 :
30 : struct mock_server {
31 : char *temp_dir;
32 : char *dbus_address;
33 : pid_t pid;
34 : DBusConnection *client;
35 :
36 : /* Used for synchronization */
37 : int sync_fds[2];
38 :
39 : /* Only used during init */
40 : sbus_server_conn_init_fn init_fn;
41 : void *init_pvt_data;
42 : };
43 :
44 : /*
45 : * If you think we're going to do full error propagation during tests ...
46 : * you're going to have a bad time (reading this code)
47 : */
48 : #define verify_eq(x, y) \
49 : do { if ((x) != (y)) { fprintf(stderr, "failed: %s == %s\n", #x, #y); abort(); } } while (0)
50 : #define verify_neq(x, y) \
51 : do { if ((x) == (y)) { fprintf(stderr, "failed: %s != %s\n", #x, #y); abort(); } } while (0)
52 :
53 : static int
54 9 : mock_server_cleanup(struct mock_server *mock)
55 : {
56 : int child_status;
57 : const char *file;
58 : struct stat sb;
59 :
60 9 : dbus_connection_close(mock->client);
61 9 : dbus_connection_unref(mock->client);
62 :
63 : /* Tell the server thread to quit */
64 9 : verify_eq (write(mock->sync_fds[0], "X", 1), 1);
65 :
66 : /* Wait for the server child, it always returns mock */
67 9 : verify_eq (waitpid(mock->pid, &child_status, 0), mock->pid);
68 9 : verify_eq (child_status, 0);
69 :
70 9 : file = strchr(mock->dbus_address, '/');
71 9 : if (stat(file, &sb) == 0) {
72 0 : verify_eq (unlink(file), 0);
73 : }
74 9 : verify_eq (rmdir(mock->temp_dir), 0);
75 :
76 9 : return EOK;
77 : }
78 :
79 : static int
80 0 : on_accept_connection(struct sbus_connection *conn,
81 : void *data)
82 : {
83 0 : struct mock_server *mock = data;
84 :
85 0 : verify_eq (mock->init_fn(conn, mock->init_pvt_data), EOK);
86 :
87 : /* Synchronization point: test_dbus_setup_mock() should return */
88 0 : verify_eq (write(mock->sync_fds[1], "X", 1), 1);
89 :
90 0 : return EOK;
91 : }
92 :
93 : static void
94 0 : on_sync_fd_written(struct tevent_context *loop,
95 : struct tevent_fd *fde,
96 : uint16_t flags,
97 : void *data)
98 : {
99 0 : bool *stop_server = data;
100 0 : *stop_server = true;
101 0 : }
102 :
103 : static void
104 0 : mock_server_child(void *data)
105 : {
106 0 : struct mock_server *mock = data;
107 : struct tevent_context *loop;
108 : struct sbus_connection *server;
109 0 : bool stop_server = false;
110 : TALLOC_CTX *ctx;
111 :
112 0 : ctx = talloc_new(NULL);
113 0 : loop = tevent_context_init(ctx);
114 :
115 0 : verify_eq (sbus_new_server(ctx, loop, mock->dbus_address, geteuid(), getegid(),
116 : false, &server, on_accept_connection, mock), EOK);
117 :
118 0 : tevent_add_fd(loop, ctx, mock->sync_fds[1], TEVENT_FD_READ,
119 : on_sync_fd_written, &stop_server);
120 :
121 : /* Synchronization point: test_dbus_setup_mock() should connect */
122 0 : verify_eq (write(mock->sync_fds[1], "X", 1), 1);
123 :
124 : /* Do the loop */
125 0 : while(!stop_server) {
126 0 : verify_eq (tevent_loop_once(loop), 0);
127 : }
128 :
129 : /* TODO: sbus doesn't support cleanup of a server */
130 :
131 0 : talloc_free(ctx);
132 0 : }
133 :
134 : struct DBusConnection *
135 9 : test_dbus_setup_mock(TALLOC_CTX *mem_ctx,
136 : struct tevent_context *loop,
137 : sbus_server_conn_init_fn init_fn,
138 : void *init_pvt_data)
139 : {
140 : struct mock_server *mock;
141 : char dummy;
142 :
143 9 : mock = talloc_zero(mem_ctx, struct mock_server);
144 9 : talloc_set_destructor(mock, mock_server_cleanup);
145 9 : mock->init_fn = init_fn;
146 9 : mock->init_pvt_data = init_pvt_data;
147 :
148 9 : mock->temp_dir = mkdtemp(talloc_strdup(mock, "/tmp/sssd-dbus-tests.XXXXXX"));
149 9 : verify_neq (mock->temp_dir, NULL);
150 9 : mock->dbus_address = talloc_asprintf(mock, "unix:path=%s/sbus", mock->temp_dir);
151 9 : verify_neq (mock->dbus_address, NULL);
152 :
153 : /* We use an fd pair as a synchronization device, integrates with tevent well */
154 9 : verify_eq (socketpair(PF_LOCAL, SOCK_STREAM, 0, mock->sync_fds), 0);
155 :
156 : /* Run the dbus server in a child process */
157 9 : mock->pid = fork();
158 9 : if (mock->pid == 0) {
159 0 : mock_server_child(mock);
160 0 : _exit(0);
161 : }
162 :
163 9 : verify_neq (mock->pid, -1);
164 :
165 : /* Synchronization point: wait for sync point in mock_server_child */
166 9 : verify_eq (read(mock->sync_fds[0], &dummy, 1), 1);
167 :
168 : /* Open a shared D-BUS connection to the address */
169 9 : mock->client = dbus_connection_open_private(mock->dbus_address, NULL);
170 9 : verify_neq (mock->client, NULL);
171 :
172 : /* Synchronization point: wait for sync point in on_accept_connection */
173 9 : verify_eq (read(mock->sync_fds[0], &dummy, 1), 1);
174 :
175 9 : return mock->client;
176 : }
177 :
178 : DBusMessage *
179 33 : test_dbus_call_sync(DBusConnection *conn, const char *object_path,
180 : const char *interface, const char *method,
181 : DBusError *error, int first_arg_type, ...)
182 : {
183 : DBusMessage *message;
184 : DBusMessage *reply;
185 : va_list va;
186 :
187 33 : message = dbus_message_new_method_call(NULL, object_path, interface, method);
188 33 : verify_neq(message, NULL);
189 :
190 33 : va_start(va, first_arg_type);
191 33 : verify_eq(dbus_message_append_args_valist(message, first_arg_type, va), TRUE);
192 33 : va_end(va);
193 :
194 33 : reply = dbus_connection_send_with_reply_and_block(conn, message, -1, error);
195 33 : dbus_message_unref(message);
196 :
197 33 : return reply;
198 : }
|