2 * Copyright (C) 2013, 2014 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/>.
21 #include "testutils.h"
23 #if defined(WITH_DBUS) && defined(__linux__)
25 # include <dbus/dbus.h>
28 # define LIBVIRT_VIRSYSTEMDPRIV_H_ALLOW
29 # include "virsystemdpriv.h"
31 # include "virsystemd.h"
35 # include "rpc/virnetsocket.h"
36 # include "intprops.h"
37 # define VIR_FROM_THIS VIR_FROM_NONE
39 VIR_LOG_INIT("tests.systemdtest");
41 VIR_MOCK_WRAP_RET_ARGS(dbus_connection_send_with_reply_and_block
,
43 DBusConnection
*, connection
,
44 DBusMessage
*, message
,
45 int, timeout_milliseconds
,
48 DBusMessage
*reply
= NULL
;
49 const char *service
= dbus_message_get_destination(message
);
50 const char *member
= dbus_message_get_member(message
);
52 VIR_MOCK_REAL_INIT(dbus_connection_send_with_reply_and_block
);
54 if (STREQ(service
, "org.freedesktop.machine1")) {
55 if (getenv("FAIL_BAD_SERVICE")) {
56 dbus_set_error_const(error
,
57 "org.freedesktop.systemd.badthing",
58 "Something went wrong creating the machine");
60 reply
= dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN
);
62 if (STREQ(member
, "GetMachineByPID")) {
63 const char *object_path
= "/org/freedesktop/machine1/machine/qemu_2ddemo";
66 dbus_message_iter_init_append(reply
, &iter
);
67 if (!dbus_message_iter_append_basic(&iter
,
68 DBUS_TYPE_OBJECT_PATH
,
71 } else if (STREQ(member
, "Get")) {
72 const char *name
= "qemu-demo";
76 dbus_message_iter_init_append(reply
, &iter
);
77 dbus_message_iter_open_container(&iter
, DBUS_TYPE_VARIANT
,
80 if (!dbus_message_iter_append_basic(&sub
,
84 dbus_message_iter_close_container(&iter
, &sub
);
87 } else if (STREQ(service
, "org.freedesktop.login1")) {
88 char *supported
= getenv("RESULT_SUPPORT");
90 reply
= dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN
);
91 dbus_message_iter_init_append(reply
, &iter
);
93 if (!dbus_message_iter_append_basic(&iter
,
97 } else if (STREQ(service
, "org.freedesktop.DBus") &&
98 STREQ(member
, "ListActivatableNames")) {
99 const char *svc1
= "org.foo.bar.wizz";
100 const char *svc2
= "org.freedesktop.machine1";
101 const char *svc3
= "org.freedesktop.login1";
102 DBusMessageIter iter
;
104 reply
= dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN
);
105 dbus_message_iter_init_append(reply
, &iter
);
106 dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
,
109 if (!dbus_message_iter_append_basic(&sub
,
113 if (!getenv("FAIL_NO_SERVICE") &&
114 !dbus_message_iter_append_basic(&sub
,
118 if (!getenv("FAIL_NO_SERVICE") &&
119 !dbus_message_iter_append_basic(&sub
,
123 dbus_message_iter_close_container(&iter
, &sub
);
124 } else if (STREQ(service
, "org.freedesktop.DBus") &&
125 STREQ(member
, "ListNames")) {
126 const char *svc1
= "org.foo.bar.wizz";
127 const char *svc2
= "org.freedesktop.systemd1";
128 const char *svc3
= "org.freedesktop.login1";
129 DBusMessageIter iter
;
131 reply
= dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN
);
132 dbus_message_iter_init_append(reply
, &iter
);
133 dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
,
136 if (!dbus_message_iter_append_basic(&sub
,
140 if ((!getenv("FAIL_NO_SERVICE") && !getenv("FAIL_NOT_REGISTERED")) &&
141 !dbus_message_iter_append_basic(&sub
,
145 if ((!getenv("FAIL_NO_SERVICE") && !getenv("FAIL_NOT_REGISTERED")) &&
146 !dbus_message_iter_append_basic(&sub
,
150 dbus_message_iter_close_container(&iter
, &sub
);
152 reply
= dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN
);
158 virDBusMessageUnref(reply
);
163 static int testCreateContainer(const void *opaque ATTRIBUTE_UNUSED
)
165 unsigned char uuid
[VIR_UUID_BUFLEN
] = {
171 if (virSystemdCreateMachine("demo",
178 "highpriority.slice", 0) < 0) {
179 fprintf(stderr
, "%s", "Failed to create LXC machine\n");
186 static int testTerminateContainer(const void *opaque ATTRIBUTE_UNUSED
)
188 if (virSystemdTerminateMachine("lxc-demo") < 0) {
189 fprintf(stderr
, "%s", "Failed to terminate LXC machine\n");
196 static int testCreateMachine(const void *opaque ATTRIBUTE_UNUSED
)
198 unsigned char uuid
[VIR_UUID_BUFLEN
] = {
204 if (virSystemdCreateMachine("demo",
212 fprintf(stderr
, "%s", "Failed to create KVM machine\n");
219 static int testTerminateMachine(const void *opaque ATTRIBUTE_UNUSED
)
221 if (virSystemdTerminateMachine("test-qemu-demo") < 0) {
222 fprintf(stderr
, "%s", "Failed to terminate KVM machine\n");
229 static int testCreateNoSystemd(const void *opaque ATTRIBUTE_UNUSED
)
231 unsigned char uuid
[VIR_UUID_BUFLEN
] = {
239 setenv("FAIL_NO_SERVICE", "1", 1);
241 if ((rv
= virSystemdCreateMachine("demo",
249 unsetenv("FAIL_NO_SERVICE");
250 fprintf(stderr
, "%s", "Unexpected create machine success\n");
253 unsetenv("FAIL_NO_SERVICE");
256 fprintf(stderr
, "%s", "Unexpected create machine error\n");
263 static int testCreateSystemdNotRunning(const void *opaque ATTRIBUTE_UNUSED
)
265 unsigned char uuid
[VIR_UUID_BUFLEN
] = {
273 setenv("FAIL_NOT_REGISTERED", "1", 1);
275 if ((rv
= virSystemdCreateMachine("demo",
283 unsetenv("FAIL_NOT_REGISTERED");
284 fprintf(stderr
, "%s", "Unexpected create machine success\n");
287 unsetenv("FAIL_NOT_REGISTERED");
290 fprintf(stderr
, "%s", "Unexpected create machine error\n");
297 static int testCreateBadSystemd(const void *opaque ATTRIBUTE_UNUSED
)
299 unsigned char uuid
[VIR_UUID_BUFLEN
] = {
307 setenv("FAIL_BAD_SERVICE", "1", 1);
309 if ((rv
= virSystemdCreateMachine("demo",
317 unsetenv("FAIL_BAD_SERVICE");
318 fprintf(stderr
, "%s", "Unexpected create machine success\n");
321 unsetenv("FAIL_BAD_SERVICE");
324 fprintf(stderr
, "%s", "Unexpected create machine error\n");
332 static int testCreateNetwork(const void *opaque ATTRIBUTE_UNUSED
)
334 unsigned char uuid
[VIR_UUID_BUFLEN
] = {
343 size_t nnicindexes
= ARRAY_CARDINALITY(nicindexes
);
344 if (virSystemdCreateMachine("demo",
350 nnicindexes
, nicindexes
,
351 "highpriority.slice", 0) < 0) {
352 fprintf(stderr
, "%s", "Failed to create LXC machine\n");
361 testGetMachineName(const void *opaque ATTRIBUTE_UNUSED
)
363 char *tmp
= virSystemdGetMachineNameByPID(1234);
367 fprintf(stderr
, "%s", "Failed to create LXC machine\n");
371 if (STREQ(tmp
, "qemu-demo"))
379 struct testNameData
{
381 const char *expected
;
387 testScopeName(const void *opaque
)
389 const struct testNameData
*data
= opaque
;
393 if (!(actual
= virSystemdMakeScopeName(data
->name
, "lxc", data
->legacy
)))
396 if (STRNEQ(actual
, data
->expected
)) {
397 fprintf(stderr
, "Expected '%s' but got '%s'\n",
398 data
->expected
, actual
);
410 testMachineName(const void *opaque
)
412 const struct testNameData
*data
= opaque
;
416 if (!(actual
= virDomainGenerateMachineName("qemu", data
->id
,
420 if (STRNEQ(actual
, data
->expected
)) {
421 fprintf(stderr
, "Expected '%s' but got '%s'\n",
422 data
->expected
, actual
);
433 typedef int (*virSystemdCanHelper
)(bool * result
);
434 struct testPMSupportData
{
435 virSystemdCanHelper tested
;
438 static int testPMSupportHelper(const void *opaque
)
443 const char *results
[4] = {"yes", "no", "na", "challenge"};
444 int expected
[4] = {1, 0, 0, 1};
445 const struct testPMSupportData
*data
= opaque
;
447 for (i
= 0; i
< 4; i
++) {
448 setenv("RESULT_SUPPORT", results
[i
], 1);
449 if ((rv
= data
->tested(&result
)) < 0) {
450 fprintf(stderr
, "%s", "Unexpected canSuspend error\n");
454 if (result
!= expected
[i
]) {
455 fprintf(stderr
, "Unexpected result for answer '%s'\n", results
[i
]);
458 unsetenv("RESULT_SUPPORT");
463 unsetenv("RESULT_SUPPORT");
467 static int testPMSupportHelperNoSystemd(const void *opaque
)
471 const struct testPMSupportData
*data
= opaque
;
473 setenv("FAIL_NO_SERVICE", "1", 1);
475 if ((rv
= data
->tested(&result
)) == 0) {
476 unsetenv("FAIL_NO_SERVICE");
477 fprintf(stderr
, "%s", "Unexpected canSuspend success\n");
480 unsetenv("FAIL_NO_SERVICE");
483 fprintf(stderr
, "%s", "Unexpected canSuspend error\n");
490 static int testPMSupportSystemdNotRunning(const void *opaque
)
494 const struct testPMSupportData
*data
= opaque
;
496 setenv("FAIL_NOT_REGISTERED", "1", 1);
498 if ((rv
= data
->tested(&result
)) == 0) {
499 unsetenv("FAIL_NOT_REGISTERED");
500 fprintf(stderr
, "%s", "Unexpected canSuspend success\n");
503 unsetenv("FAIL_NOT_REGISTERED");
506 fprintf(stderr
, "%s", "Unexpected canSuspend error\n");
515 testActivationCreateFDs(virNetSocketPtr
*sockUNIX
,
516 virNetSocketPtr
**sockIP
,
523 if (virNetSocketNewListenUNIX("virsystemdtest.sock",
530 if (virNetSocketNewListenTCP("localhost",
535 virObjectUnref(*sockUNIX
);
544 testActivation(bool useNames
)
546 virNetSocketPtr sockUNIX
;
547 virNetSocketPtr
*sockIP
;
551 char nfdstr
[INT_BUFSIZE_BOUND(size_t)];
552 char pidstr
[INT_BUFSIZE_BOUND(pid_t
)];
553 virSystemdActivationMap map
[2];
556 VIR_AUTOPTR(virSystemdActivation
) act
= NULL
;
557 VIR_AUTOCLEAN(virBuffer
) names
= VIR_BUFFER_INITIALIZER
;
559 virBufferAddLit(&names
, "demo-unix.socket");
561 if (testActivationCreateFDs(&sockUNIX
, &sockIP
, &nsockIP
) < 0)
564 for (i
= 0; i
< nsockIP
; i
++)
565 virBufferAddLit(&names
, ":demo-ip.socket");
567 snprintf(nfdstr
, sizeof(nfdstr
), "%zu", 1 + nsockIP
);
568 snprintf(pidstr
, sizeof(pidstr
), "%lld", (long long)getpid());
570 setenv("LISTEN_FDS", nfdstr
, 1);
571 setenv("LISTEN_PID", pidstr
, 1);
573 if (virBufferError(&names
))
577 setenv("LISTEN_FDNAMES", virBufferCurrentContent(&names
), 1);
579 unsetenv("LISTEN_FDNAMES");
581 map
[0].name
= "demo-unix.socket";
582 map
[0].family
= AF_UNIX
;
583 map
[0].path
= virNetSocketGetPath(sockUNIX
);
585 map
[1].name
= "demo-ip.socket";
586 map
[1].family
= AF_INET
;
587 map
[1].port
= virNetSocketGetPort(sockIP
[0]);
589 if (virSystemdGetActivation(map
, ARRAY_CARDINALITY(map
), &act
) < 0)
593 fprintf(stderr
, "Activation object was not created: %s", virGetLastErrorMessage());
597 if (virSystemdActivationComplete(act
) == 0) {
598 fprintf(stderr
, "Activation did not report unclaimed FDs");
602 virSystemdActivationClaimFDs(act
, "demo-unix.socket", &fds
, &nfds
);
605 fprintf(stderr
, "Expected 1 UNIX fd, but got %zu\n", nfds
);
610 virSystemdActivationClaimFDs(act
, "demo-ip.socket", &fds
, &nfds
);
612 if (nfds
!= nsockIP
) {
613 fprintf(stderr
, "Expected %zu IP fd, but got %zu\n", nsockIP
, nfds
);
618 virSystemdActivationClaimFDs(act
, "demo-ip-alt.socket", &fds
, &nfds
);
621 fprintf(stderr
, "Expected 0 IP fd, but got %zu\n", nfds
);
625 if (virSystemdActivationComplete(act
) < 0) {
626 fprintf(stderr
, "Action was not complete: %s\n", virGetLastErrorMessage());
632 virObjectUnref(sockUNIX
);
633 for (i
= 0; i
< nsockIP
; i
++)
634 virObjectUnref(sockIP
[i
]);
642 testActivationEmpty(const void *opaque ATTRIBUTE_UNUSED
)
644 virSystemdActivationPtr act
;
646 unsetenv("LISTEN_FDS");
648 if (virSystemdGetActivation(NULL
, 0, &act
) < 0)
652 fprintf(stderr
, "Unexpectedly got activation object");
653 virSystemdActivationFree(&act
);
662 testActivationFDNames(const void *opaque ATTRIBUTE_UNUSED
)
664 return testActivation(true);
669 testActivationFDAddrs(const void *opaque ATTRIBUTE_UNUSED
)
671 return testActivation(false);
680 unsigned char uuid
[VIR_UUID_BUFLEN
];
682 /* The one we use in tests quite often */
683 if (virUUIDParse("c7a5fdbd-edaf-9455-926a-d65c16db1809", uuid
) < 0)
686 # define DO_TEST(_name, func) \
688 if (virTestRun(_name, func, NULL) < 0) \
690 if (virTestRun(_name "again ", func, NULL) < 0) \
692 virSystemdHasMachinedResetCachedValue(); \
695 DO_TEST("Test create container ", testCreateContainer
);
696 DO_TEST("Test terminate container ", testTerminateContainer
);
697 DO_TEST("Test create machine ", testCreateMachine
);
698 DO_TEST("Test terminate machine ", testTerminateMachine
);
699 DO_TEST("Test create no systemd ", testCreateNoSystemd
);
700 DO_TEST("Test create systemd not running ", testCreateSystemdNotRunning
);
701 DO_TEST("Test create bad systemd ", testCreateBadSystemd
);
702 DO_TEST("Test create with network ", testCreateNetwork
);
703 DO_TEST("Test getting machine name ", testGetMachineName
);
705 # define TEST_SCOPE(_name, unitname, _legacy) \
707 struct testNameData data = { \
708 .name = _name, .expected = unitname, .legacy = _legacy, \
710 if (virTestRun("Test scopename", testScopeName, &data) < 0) \
714 # define TEST_SCOPE_OLD(name, unitname) \
715 TEST_SCOPE(name, unitname, true)
716 # define TEST_SCOPE_NEW(name, unitname) \
717 TEST_SCOPE(name, unitname, false)
719 TEST_SCOPE_OLD("demo", "machine-lxc\\x2ddemo.scope");
720 TEST_SCOPE_OLD("demo-name", "machine-lxc\\x2ddemo\\x2dname.scope");
721 TEST_SCOPE_OLD("demo!name", "machine-lxc\\x2ddemo\\x21name.scope");
722 TEST_SCOPE_OLD(".demo", "machine-lxc\\x2d\\x2edemo.scope");
723 TEST_SCOPE_OLD("bull💩", "machine-lxc\\x2dbull\\xf0\\x9f\\x92\\xa9.scope");
725 TEST_SCOPE_NEW("qemu-3-demo", "machine-qemu\\x2d3\\x2ddemo.scope");
727 # define TEST_MACHINE(_name, _id, machinename) \
729 struct testNameData data = { \
730 .name = _name, .expected = machinename, .id = _id, \
732 if (virTestRun("Test scopename", testMachineName, &data) < 0) \
736 TEST_MACHINE("demo", 1, "qemu-1-demo");
737 TEST_MACHINE("demo-name", 2, "qemu-2-demo-name");
738 TEST_MACHINE("demo!name", 3, "qemu-3-demoname");
739 TEST_MACHINE(".demo", 4, "qemu-4-.demo");
740 TEST_MACHINE("bull\U0001f4a9", 5, "qemu-5-bull");
741 TEST_MACHINE("demo..name", 6, "qemu-6-demo.name");
742 TEST_MACHINE("12345678901234567890123456789012345678901234567890123456789", 7,
743 "qemu-7-123456789012345678901234567890123456789012345678901234567");
744 TEST_MACHINE("123456789012345678901234567890123456789012345678901234567890", 8,
745 "qemu-8-123456789012345678901234567890123456789012345678901234567");
747 # define TESTS_PM_SUPPORT_HELPER(name, function) \
749 struct testPMSupportData data = { \
752 if (virTestRun("Test " name " ", testPMSupportHelper, &data) < 0) \
754 virSystemdHasLogindResetCachedValue(); \
755 if (virTestRun("Test " name " no systemd ", \
756 testPMSupportHelperNoSystemd, &data) < 0) \
758 virSystemdHasLogindResetCachedValue(); \
759 if (virTestRun("Test systemd " name " not running ", \
760 testPMSupportSystemdNotRunning, &data) < 0) \
762 virSystemdHasLogindResetCachedValue(); \
765 TESTS_PM_SUPPORT_HELPER("canSuspend", &virSystemdCanSuspend
);
766 TESTS_PM_SUPPORT_HELPER("canHibernate", &virSystemdCanHibernate
);
767 TESTS_PM_SUPPORT_HELPER("canHybridSleep", &virSystemdCanHybridSleep
);
769 if (virTestRun("Test activation empty", testActivationEmpty
, NULL
) < 0)
772 if (fcntl(STDERR_FILENO
+ 1, F_GETFL
) == -1 && errno
== EBADF
&&
773 fcntl(STDERR_FILENO
+ 2, F_GETFL
) == -1 && errno
== EBADF
&&
774 fcntl(STDERR_FILENO
+ 3, F_GETFL
) == -1 && errno
== EBADF
) {
775 if (virTestRun("Test activation names", testActivationFDNames
, NULL
) < 0)
777 if (virTestRun("Test activation addrs", testActivationFDAddrs
, NULL
) < 0)
780 VIR_INFO("Skipping activation tests as FD 3/4/5 is open");
783 return ret
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;
786 VIR_TEST_MAIN_PRELOAD(mymain
, abs_builddir
"/.libs/virdbusmock.so")
788 #else /* ! (WITH_DBUS && __linux__) */
794 #endif /* ! WITH_DBUS */