2 * Copyright (C) 2015 Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see
16 * <http://www.gnu.org/licenses/>.
23 #include "testutils.h"
25 #include "rpc/virnetdaemon.h"
27 #define VIR_FROM_THIS VIR_FROM_RPC
29 #if !defined(WIN32) && defined(WITH_JSON)
30 struct testClientPriv
{
36 testClientNew(virNetServerClient
*client G_GNUC_UNUSED
,
37 void *opaque G_GNUC_UNUSED
)
39 struct testClientPriv
*priv
;
41 priv
= g_new0(struct testClientPriv
, 1);
50 testClientPreExec(virNetServerClient
*client G_GNUC_UNUSED
,
53 struct testClientPriv
*priv
= data
;
55 return virJSONValueNewNumberInt(priv
->magic
);
60 testClientNewPostExec(virNetServerClient
*client
,
66 if (virJSONValueGetNumberInt(object
, &magic
) < 0)
72 return testClientNew(client
, opaque
);
77 testClientFree(void *opaque
)
84 testCreateServer(const char *server_name
, const char *host
, int family
)
86 virNetServer
*srv
= NULL
;
87 virNetServerService
*svc1
= NULL
;
88 virNetServerService
*svc2
= NULL
;
89 virNetServerClient
*cln1
= NULL
;
90 virNetServerClient
*cln2
= NULL
;
91 virNetSocket
*sk1
= NULL
;
92 virNetSocket
*sk2
= NULL
;
95 if (socketpair(PF_UNIX
, SOCK_STREAM
, 0, fdclient
) < 0) {
96 virReportSystemError(errno
, "%s",
97 "Cannot create socket pair");
101 if (!(srv
= virNetServerNew(server_name
, 1,
110 if (!(svc1
= virNetServerServiceNewTCP(host
,
113 VIR_NET_SERVER_SERVICE_AUTH_NONE
,
120 if (!(svc2
= virNetServerServiceNewTCP(host
,
123 VIR_NET_SERVER_SERVICE_AUTH_POLKIT
,
130 virNetServerAddService(srv
, svc1
);
131 virNetServerAddService(srv
, svc2
);
133 if (virNetSocketNewConnectSockFD(fdclient
[0], &sk1
) < 0)
135 if (virNetSocketNewConnectSockFD(fdclient
[1], &sk2
) < 0)
138 if (!(cln1
= virNetServerClientNew(virNetServerNextClientID(srv
),
140 VIR_NET_SERVER_SERVICE_AUTH_SASL
,
150 if (!(cln2
= virNetServerClientNew(virNetServerNextClientID(srv
),
152 VIR_NET_SERVER_SERVICE_AUTH_POLKIT
,
162 if (virNetServerAddClient(srv
, cln1
) < 0)
165 if (virNetServerAddClient(srv
, cln2
) < 0)
170 virDispatchError(NULL
);
171 virObjectUnref(cln1
);
172 virObjectUnref(cln2
);
173 virObjectUnref(svc1
);
174 virObjectUnref(svc2
);
180 g_clear_pointer(&srv
, virObjectUnref
);
184 static char *testGenerateJSON(const char *server_name
)
186 virNetDaemon
*dmn
= NULL
;
187 virNetServer
*srv
= NULL
;
188 g_autoptr(virJSONValue
) json
= NULL
;
189 char *jsonstr
= NULL
;
190 bool has_ipv4
, has_ipv6
;
192 /* Our pre-saved JSON file is created so that each service
193 * only has one socket. If we let libvirt bind to IPv4 and
194 * IPv6 we might end up with two sockets, so force one or
195 * the other based on what's available on thehost
197 if (virNetSocketCheckProtocols(&has_ipv4
,
201 if (!has_ipv4
&& !has_ipv6
)
204 if (!(srv
= testCreateServer(server_name
,
205 has_ipv4
? "127.0.0.1" : "::1",
206 has_ipv4
? AF_INET
: AF_INET6
)))
209 if (!(dmn
= virNetDaemonNew()))
212 if (virNetDaemonAddServer(dmn
, srv
) < 0)
215 if (!(json
= virNetDaemonPreExecRestart(dmn
)))
218 if (!(jsonstr
= virJSONValueToString(json
, true)))
221 fprintf(stderr
, "%s\n", jsonstr
);
223 virNetServerClose(srv
);
227 virDispatchError(NULL
);
232 struct testExecRestartData
{
233 const char *jsonfile
;
234 const char **serverNames
;
239 static virNetServer
*
240 testNewServerPostExecRestart(virNetDaemon
*dmn G_GNUC_UNUSED
,
242 virJSONValue
*object
,
245 struct testExecRestartData
*data
= opaque
;
247 for (i
= 0; i
< data
->nservers
; i
++) {
248 if (STREQ(data
->serverNames
[i
], name
)) {
249 return virNetServerNewPostExecRestart(object
,
252 testClientNewPostExec
,
259 virReportError(VIR_ERR_INTERNAL_ERROR
, "Unexpected server name '%s'", name
);
263 static int testExecRestart(const void *opaque
)
267 virNetDaemon
*dmn
= NULL
;
268 const struct testExecRestartData
*data
= opaque
;
269 g_autofree
char *infile
= NULL
;
270 g_autofree
char *outfile
= NULL
;
271 g_autofree
char *injsonstr
= NULL
;
272 g_autofree
char *outjsonstr
= NULL
;
273 g_autoptr(virJSONValue
) injson
= NULL
;
274 g_autoptr(virJSONValue
) outjson
= NULL
;
275 int fdclient
[2] = { -1, -1 }, fdserver
[2] = { -1, -1 };
277 if (socketpair(PF_UNIX
, SOCK_STREAM
, 0, fdclient
) < 0) {
278 virReportSystemError(errno
, "%s",
279 "Cannot create socket pair");
283 if (socketpair(PF_UNIX
, SOCK_STREAM
, 0, fdserver
) < 0) {
284 virReportSystemError(errno
, "%s",
285 "Cannot create socket pair");
289 /* We're blindly assuming the test case isn't using
290 * fds 100->103 for something else, which is probably
291 * fairly reasonable in general
293 if (dup2(fdserver
[0], 100) < 0 ||
294 dup2(fdserver
[1], 101) < 0 ||
295 dup2(fdclient
[0], 102) < 0 ||
296 dup2(fdclient
[1], 103) < 0) {
297 virReportSystemError(errno
, "%s", "dup2() failed");
301 infile
= g_strdup_printf("%s/virnetdaemondata/input-data-%s.json", abs_srcdir
,
304 outfile
= g_strdup_printf("%s/virnetdaemondata/output-data-%s.%s",
305 abs_srcdir
, data
->jsonfile
, data
->pass
? "json" : "err");
307 if (virFileReadAll(infile
, 8192, &injsonstr
) < 0)
310 if (!(injson
= virJSONValueFromString(injsonstr
)))
313 if (!(dmn
= virNetDaemonNewPostExecRestart(injson
,
316 testNewServerPostExecRestart
,
320 for (i
= 0; i
< data
->nservers
; i
++) {
321 if (!virNetDaemonHasServer(dmn
, data
->serverNames
[i
])) {
322 virReportError(VIR_ERR_INTERNAL_ERROR
,
323 "Server %s was not created",
324 data
->serverNames
[i
]);
329 if (!(outjson
= virNetDaemonPreExecRestart(dmn
)))
335 if (!(outjsonstr
= virJSONValueToString(outjson
, true)))
338 if (virTestCompareToFile(outjsonstr
, outfile
) < 0)
344 if (injson
&& !data
->pass
) {
345 ret
= virTestCompareToFile(virGetLastErrorMessage(), outfile
);
347 VIR_TEST_DEBUG("Test failed with different error message");
350 } else if (!data
->pass
) {
351 VIR_TEST_DEBUG("Test should have failed");
355 VIR_FORCE_CLOSE(fdserver
[0]);
356 VIR_FORCE_CLOSE(fdserver
[1]);
357 VIR_FORCE_CLOSE(fdclient
[0]);
358 VIR_FORCE_CLOSE(fdclient
[1]);
367 const char *server_names
[] = { "testServer0", "testServer1" };
369 if (virInitialize() < 0 ||
370 virEventRegisterDefaultImpl() < 0) {
371 virDispatchError(NULL
);
375 /* Hack to make it easier to generate new JSON files when
376 * the RPC classes change. Just set this env var, save
377 * the generated JSON, and replace the file descriptor
378 * numbers with 100, 101, 102, 103.
380 if (getenv("VIR_GENERATE_JSON")) {
381 char *json
= testGenerateJSON(server_names
[0]);
385 fprintf(stdout
, "%s\n", json
);
390 # define EXEC_RESTART_TEST_FULL(file, nservers, pass) \
392 struct testExecRestartData data = { \
393 file, server_names, nservers, pass \
395 if (virTestRun("ExecRestart " file, \
396 testExecRestart, &data) < 0) \
400 # define EXEC_RESTART_TEST(file, N) EXEC_RESTART_TEST_FULL(file, N, true)
401 # define EXEC_RESTART_TEST_FAIL(file, N) EXEC_RESTART_TEST_FULL(file, N, false)
404 EXEC_RESTART_TEST("initial", 1);
405 EXEC_RESTART_TEST("anon-clients", 1);
406 EXEC_RESTART_TEST("admin", 2);
407 EXEC_RESTART_TEST("admin-server-names", 2);
408 EXEC_RESTART_TEST("no-keepalive-required", 2);
409 EXEC_RESTART_TEST("client-ids", 1);
410 EXEC_RESTART_TEST("client-timestamp", 1);
411 EXEC_RESTART_TEST_FAIL("anon-clients", 2);
412 EXEC_RESTART_TEST("client-auth-pending", 1);
413 EXEC_RESTART_TEST_FAIL("client-auth-pending-failure", 1);
414 EXEC_RESTART_TEST_FAIL("invalid-max-clients-failure", 1);
416 return ret
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;
418 VIR_TEST_MAIN_PRELOAD(mymain
, VIR_TEST_MOCK("virnetdaemon"))
425 VIR_TEST_MAIN(mymain
);