test_systemd.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. import infra.basetest
  2. import re
  3. from tests.init.base import InitSystemBase as InitSystemBase
  4. # In the following tests, the read-only cases use the default settings,
  5. # which historically used both a factory to populate a tmpfs on /var,
  6. # and pre-populated /var at buildtime. Since these are the default
  7. # settings, and they proved to generate a system that ultimately boots,
  8. # we still want to keep testing that. See later, below, for the
  9. # specialised test cases.
  10. class InitSystemSystemdBase(InitSystemBase):
  11. config = \
  12. """
  13. BR2_arm=y
  14. BR2_cortex_a9=y
  15. BR2_ARM_ENABLE_VFP=y
  16. BR2_TOOLCHAIN_EXTERNAL=y
  17. BR2_TOOLCHAIN_EXTERNAL_BOOTLIN=y
  18. BR2_INIT_SYSTEMD=y
  19. BR2_TARGET_GENERIC_GETTY_PORT="ttyAMA0"
  20. # BR2_TARGET_ROOTFS_TAR is not set
  21. BR2_PER_PACKAGE_DIRECTORIES=y
  22. """
  23. def check_systemd(self, fs):
  24. if "BR2_LINUX_KERNEL=y" in self.config:
  25. self.start_emulator(fs, "zImage", "vexpress-v2p-ca9")
  26. else:
  27. self.start_emulator(fs)
  28. self.check_init("/lib/systemd/systemd")
  29. # Test there is no tainted flag.
  30. output, ret = self.emulator.run("systemctl --no-pager status")
  31. self.assertEqual(ret, 0, f"'systemctl status' failed with exit code {ret}, with:\n{output}")
  32. try:
  33. # 'support-ended' tainted flag is only set based on the
  34. # SUPPORT_END variable in /etc/os-release; as we don't set
  35. # it in Buildroot, we can't get that flag in the runtime
  36. # tests, even on our maintenance branches, so we don't need
  37. # to filter it out.
  38. tainted_flags = [
  39. "".join(line.split(":")[1:]).strip()
  40. for line in output
  41. if line.strip().startswith("Tainted: ")
  42. ][0]
  43. raise RuntimeError(f"Tainted flags: {tainted_flags}")
  44. except IndexError:
  45. # No tainted flag \o/
  46. pass
  47. # Test all units are OK
  48. output, _ = self.emulator.run("systemctl --no-pager --failed --no-legend")
  49. self.assertEqual(len(output), 0)
  50. # Test we can reach the DBus daemon
  51. self.assertRunOk("busctl --no-pager")
  52. # Test we can read at least one line from the journal
  53. output, _ = self.emulator.run("journalctl --no-pager --lines 1 --quiet")
  54. self.assertEqual(len(output), 1)
  55. # Check the network is up
  56. self.check_network("eth0")
  57. class TestInitSystemSystemdRoNetworkd(InitSystemSystemdBase):
  58. config = InitSystemSystemdBase.config + \
  59. """
  60. BR2_SYSTEM_DHCP="eth0"
  61. # BR2_TARGET_GENERIC_REMOUNT_ROOTFS_RW is not set
  62. BR2_TARGET_ROOTFS_SQUASHFS=y
  63. """
  64. def test_run(self):
  65. self.check_systemd("squashfs")
  66. class TestInitSystemSystemdRwNetworkd(InitSystemSystemdBase):
  67. config = InitSystemSystemdBase.config + \
  68. """
  69. BR2_SYSTEM_DHCP="eth0"
  70. BR2_TARGET_ROOTFS_EXT2=y
  71. """
  72. def test_run(self):
  73. self.check_systemd("ext2")
  74. class TestInitSystemSystemdRoIfupdown(InitSystemSystemdBase):
  75. config = InitSystemSystemdBase.config + \
  76. """
  77. BR2_SYSTEM_DHCP="eth0"
  78. # BR2_PACKAGE_SYSTEMD_NETWORKD is not set
  79. # BR2_TARGET_GENERIC_REMOUNT_ROOTFS_RW is not set
  80. BR2_TARGET_ROOTFS_SQUASHFS=y
  81. """
  82. def test_run(self):
  83. self.check_systemd("squashfs")
  84. class TestInitSystemSystemdRoIfupdownDbusbroker(TestInitSystemSystemdRoIfupdown):
  85. config = TestInitSystemSystemdRoIfupdown.config + \
  86. """
  87. BR2_PACKAGE_DBUS_BROKER=y
  88. """
  89. def test_run(self):
  90. # Parent class' test_run() method does exactly that, no more:
  91. self.check_systemd("squashfs")
  92. # Check that the dbus-broker daemon is running as non-root
  93. cmd = "find /proc/$(pidof dbus-broker) -maxdepth 1 -name exe -user dbus"
  94. out, _ = self.emulator.run(cmd)
  95. self.assertEqual(len(out), 1)
  96. class TestInitSystemSystemdRoIfupdownDbusbrokerDbus(TestInitSystemSystemdRoIfupdownDbusbroker):
  97. config = TestInitSystemSystemdRoIfupdownDbusbroker.config + \
  98. """
  99. BR2_PACKAGE_DBUS=y
  100. """
  101. class TestInitSystemSystemdRwIfupdown(InitSystemSystemdBase):
  102. config = InitSystemSystemdBase.config + \
  103. """
  104. BR2_SYSTEM_DHCP="eth0"
  105. # BR2_PACKAGE_SYSTEMD_NETWORKD is not set
  106. BR2_TARGET_ROOTFS_EXT2=y
  107. """
  108. def test_run(self):
  109. self.check_systemd("ext2")
  110. class TestInitSystemSystemdRwIfupdownDbusbroker(TestInitSystemSystemdRwIfupdown):
  111. config = TestInitSystemSystemdRwIfupdown.config + \
  112. """
  113. BR2_PACKAGE_DBUS_BROKER=y
  114. """
  115. def test_run(self):
  116. # Parent class' test_run() method does exactly that, no more:
  117. self.check_systemd("ext2")
  118. # Check that the dbus-broker daemon is running as non-root
  119. cmd = "find /proc/$(pidof dbus-broker) -maxdepth 1 -name exe -user dbus"
  120. out, _ = self.emulator.run(cmd)
  121. self.assertEqual(len(out), 1)
  122. class TestInitSystemSystemdRwIfupdownDbusbrokerDbus(TestInitSystemSystemdRwIfupdownDbusbroker):
  123. config = TestInitSystemSystemdRwIfupdownDbusbroker.config + \
  124. """
  125. BR2_PACKAGE_DBUS=y
  126. """
  127. class TestInitSystemSystemdRoFull(InitSystemSystemdBase):
  128. config = InitSystemSystemdBase.config + \
  129. """
  130. BR2_SYSTEM_DHCP="eth0"
  131. # BR2_TARGET_GENERIC_REMOUNT_ROOTFS_RW is not set
  132. BR2_PACKAGE_SYSTEMD_JOURNAL_REMOTE=y
  133. BR2_PACKAGE_SYSTEMD_BACKLIGHT=y
  134. BR2_PACKAGE_SYSTEMD_BINFMT=y
  135. BR2_PACKAGE_SYSTEMD_COREDUMP=y
  136. BR2_PACKAGE_SYSTEMD_FIRSTBOOT=y
  137. BR2_PACKAGE_SYSTEMD_HIBERNATE=y
  138. BR2_PACKAGE_SYSTEMD_IMPORTD=y
  139. BR2_PACKAGE_SYSTEMD_LOCALED=y
  140. BR2_PACKAGE_SYSTEMD_LOGIND=y
  141. BR2_PACKAGE_SYSTEMD_MACHINED=y
  142. BR2_PACKAGE_SYSTEMD_POLKIT=y
  143. BR2_PACKAGE_SYSTEMD_QUOTACHECK=y
  144. BR2_PACKAGE_SYSTEMD_RANDOMSEED=y
  145. BR2_PACKAGE_SYSTEMD_RFKILL=y
  146. BR2_PACKAGE_SYSTEMD_SMACK_SUPPORT=y
  147. BR2_PACKAGE_SYSTEMD_SYSUSERS=y
  148. BR2_PACKAGE_SYSTEMD_VCONSOLE=y
  149. BR2_TARGET_ROOTFS_SQUASHFS=y
  150. """
  151. def test_run(self):
  152. self.check_systemd("squashfs")
  153. class TestInitSystemSystemdRwFull(InitSystemSystemdBase):
  154. config = InitSystemSystemdBase.config + \
  155. """
  156. BR2_SYSTEM_DHCP="eth0"
  157. BR2_PACKAGE_SYSTEMD_JOURNAL_REMOTE=y
  158. BR2_PACKAGE_SYSTEMD_BACKLIGHT=y
  159. BR2_PACKAGE_SYSTEMD_BINFMT=y
  160. BR2_PACKAGE_SYSTEMD_COREDUMP=y
  161. BR2_PACKAGE_SYSTEMD_FIRSTBOOT=y
  162. BR2_PACKAGE_SYSTEMD_HIBERNATE=y
  163. BR2_PACKAGE_SYSTEMD_IMPORTD=y
  164. BR2_PACKAGE_SYSTEMD_LOCALED=y
  165. BR2_PACKAGE_SYSTEMD_LOGIND=y
  166. BR2_PACKAGE_SYSTEMD_MACHINED=y
  167. BR2_PACKAGE_SYSTEMD_POLKIT=y
  168. BR2_PACKAGE_SYSTEMD_QUOTACHECK=y
  169. BR2_PACKAGE_SYSTEMD_RANDOMSEED=y
  170. BR2_PACKAGE_SYSTEMD_RFKILL=y
  171. BR2_PACKAGE_SYSTEMD_SMACK_SUPPORT=y
  172. BR2_PACKAGE_SYSTEMD_SYSUSERS=y
  173. BR2_PACKAGE_SYSTEMD_VCONSOLE=y
  174. BR2_TARGET_ROOTFS_EXT2=y
  175. """
  176. def test_run(self):
  177. self.check_systemd("ext2")
  178. # The following tests are all about read-only rootfs, and exercise either
  179. # using an un-populated factory for /var, or an overlaysfs on top of a
  180. # pre-populated /var. They all specialise the TestInitSystemSystemdRo*
  181. # test cases above.
  182. # Helper class for factory-based tests
  183. class InitSystemSystemdBaseFactory():
  184. config = \
  185. """
  186. # BR2_INIT_SYSTEMD_POPULATE_TMPFILES is not set
  187. BR2_ROOTFS_OVERLAY="{}"
  188. """.format(infra.filepath("tests/init/systemd-factory"))
  189. def test_run(self):
  190. super().test_run()
  191. # This one must be executed on the target, to check that
  192. # the factory feature works as expected
  193. out, exit_code = self.emulator.run("cat /var/foo/bar")
  194. self.assertEqual(exit_code, 0)
  195. self.assertEqual(out[0], "foobar")
  196. # /var/foo/bar is from the /var factory
  197. _, exit_code = self.emulator.run("test -e /usr/share/factory/var/foo/bar")
  198. self.assertEqual(exit_code, 0)
  199. # We can write in /var/foo/bar
  200. _, exit_code = self.emulator.run("echo barfoo >/var/foo/bar")
  201. self.assertEqual(exit_code, 0)
  202. # ... and it contains the new content
  203. out, exit_code = self.emulator.run("cat /var/foo/bar")
  204. self.assertEqual(exit_code, 0)
  205. self.assertEqual(out[0], "barfoo")
  206. # ... but the factory is umodified
  207. out, exit_code = self.emulator.run("cat /usr/share/factory/var/foo/bar")
  208. self.assertEqual(exit_code, 0)
  209. self.assertEqual(out[0], "foobar")
  210. class TestInitSystemSystemdRoNetworkdFactory(
  211. InitSystemSystemdBaseFactory,
  212. TestInitSystemSystemdRoNetworkd,
  213. ):
  214. config = InitSystemSystemdBaseFactory.config + \
  215. TestInitSystemSystemdRoNetworkd.config
  216. class TestInitSystemSystemdRoIfupdownFactory(
  217. InitSystemSystemdBaseFactory,
  218. TestInitSystemSystemdRoIfupdown,
  219. ):
  220. config = InitSystemSystemdBaseFactory.config + \
  221. TestInitSystemSystemdRoIfupdown.config
  222. class TestInitSystemSystemdRoIfupdownDbusbrokerFactory(
  223. InitSystemSystemdBaseFactory,
  224. TestInitSystemSystemdRoIfupdownDbusbroker,
  225. ):
  226. config = InitSystemSystemdBaseFactory.config + \
  227. TestInitSystemSystemdRoIfupdownDbusbroker.config
  228. class TestInitSystemSystemdRoIfupdownDbusbrokerDbusFactory(
  229. InitSystemSystemdBaseFactory,
  230. TestInitSystemSystemdRoIfupdownDbusbrokerDbus,
  231. ):
  232. config = InitSystemSystemdBaseFactory.config + \
  233. TestInitSystemSystemdRoIfupdownDbusbrokerDbus.config
  234. class TestInitSystemSystemdRoFullFactory(
  235. InitSystemSystemdBaseFactory,
  236. TestInitSystemSystemdRoFull,
  237. ):
  238. config = InitSystemSystemdBaseFactory.config + \
  239. TestInitSystemSystemdRoFull.config
  240. # Helper class for overlayfs-based tests
  241. class InitSystemSystemdBaseOverlayfs():
  242. config = \
  243. """
  244. # BR2_INIT_SYSTEMD_VAR_FACTORY is not set
  245. BR2_INIT_SYSTEMD_VAR_OVERLAYFS=y
  246. BR2_ROOTFS_OVERLAY="{}"
  247. BR2_LINUX_KERNEL=y
  248. BR2_LINUX_KERNEL_CUSTOM_VERSION=y
  249. BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="5.10.202"
  250. BR2_LINUX_KERNEL_DEFCONFIG="vexpress"
  251. BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="{}"
  252. BR2_LINUX_KERNEL_DTS_SUPPORT=y
  253. BR2_LINUX_KERNEL_INTREE_DTS_NAME="vexpress-v2p-ca9"
  254. """.format(infra.filepath("tests/init/systemd-factory"),
  255. infra.filepath("conf/overlayfs-kernel-fragment.config"))
  256. def test_run(self):
  257. super().test_run()
  258. # This one must be executed on the target, to check that
  259. # the tmpfiles pre-populate works as expected
  260. out, exit_code = self.emulator.run("cat /var/foo/bar")
  261. self.assertEqual(exit_code, 0)
  262. self.assertEqual(out[0], "foobar")
  263. # /var/foo/bar is from the pre-populated /var, so it should
  264. # not be present in the upper of the overlay
  265. _, exit_code = self.emulator.run("test -e /run/buildroot/mounts/var/upper/foo/bar")
  266. self.assertNotEqual(exit_code, 0)
  267. # We can write in /var/foo/bar
  268. _, exit_code = self.emulator.run("echo barfoo >/var/foo/bar")
  269. self.assertEqual(exit_code, 0)
  270. # ... and it contains the new content
  271. out, exit_code = self.emulator.run("cat /var/foo/bar")
  272. self.assertEqual(exit_code, 0)
  273. self.assertEqual(out[0], "barfoo")
  274. # ... and it to appears in the upper
  275. _, exit_code = self.emulator.run("test -e /run/buildroot/mounts/var/upper/foo/bar")
  276. self.assertEqual(exit_code, 0)
  277. # ... with the new content
  278. out, exit_code = self.emulator.run("cat /run/buildroot/mounts/var/upper/foo/bar")
  279. self.assertEqual(exit_code, 0)
  280. self.assertEqual(out[0], "barfoo")
  281. # ... while the lower still has the oldcontent
  282. out, exit_code = self.emulator.run("cat /run/buildroot/mounts/var/lower/foo/bar")
  283. self.assertEqual(exit_code, 0)
  284. self.assertEqual(out[0], "foobar")
  285. class TestInitSystemSystemdRoNetworkdOverlayfs(
  286. InitSystemSystemdBaseOverlayfs,
  287. TestInitSystemSystemdRoNetworkd,
  288. ):
  289. config = InitSystemSystemdBaseOverlayfs.config + \
  290. TestInitSystemSystemdRoNetworkd.config
  291. class TestInitSystemSystemdRoIfupdownOverlayfs(
  292. InitSystemSystemdBaseOverlayfs,
  293. TestInitSystemSystemdRoIfupdown,
  294. ):
  295. config = InitSystemSystemdBaseOverlayfs.config + \
  296. TestInitSystemSystemdRoIfupdown.config
  297. class TestInitSystemSystemdRoIfupdownDbusbrokerOverlayfs(
  298. InitSystemSystemdBaseOverlayfs,
  299. TestInitSystemSystemdRoIfupdownDbusbroker,
  300. ):
  301. config = InitSystemSystemdBaseOverlayfs.config + \
  302. TestInitSystemSystemdRoIfupdownDbusbroker.config
  303. class TestInitSystemSystemdRoIfupdownDbusbrokerDbusOverlayfs(
  304. InitSystemSystemdBaseOverlayfs,
  305. TestInitSystemSystemdRoIfupdownDbusbrokerDbus,
  306. ):
  307. config = InitSystemSystemdBaseOverlayfs.config + \
  308. TestInitSystemSystemdRoIfupdownDbusbrokerDbus.config
  309. class TestInitSystemSystemdRoFullOverlayfs(
  310. InitSystemSystemdBaseOverlayfs,
  311. TestInitSystemSystemdRoFull,
  312. ):
  313. config = InitSystemSystemdBaseOverlayfs.config + \
  314. TestInitSystemSystemdRoFull.config
  315. class InitSystemSystemdBaseOverlayfsVarBacking(InitSystemBase):
  316. @classmethod
  317. def gen_config(cls, overlaydir: str) -> str:
  318. return re.sub(
  319. r'^\s*BR2_ROOTFS_OVERLAY="(.*)"$',
  320. 'BR2_ROOTFS_OVERLAY="\\1 {}"'.format(infra.filepath(overlaydir)),
  321. TestInitSystemSystemdRoFullOverlayfs.config,
  322. flags=re.MULTILINE,
  323. )
  324. def check_var_mounted(self):
  325. self.assertRunOk("grep '^other-var-backing-store /run/buildroot/mounts/var tmpfs' /proc/mounts")
  326. class TestInitSystemSystemdRoFullOverlayfsVarBackingMountUnit(
  327. TestInitSystemSystemdRoFullOverlayfs,
  328. InitSystemSystemdBaseOverlayfsVarBacking,
  329. ):
  330. config = InitSystemSystemdBaseOverlayfsVarBacking.gen_config(
  331. 'tests/init/systemd-overlay-mount-unit',
  332. )
  333. def test_run(self):
  334. super().test_run()
  335. self.check_var_mounted()
  336. class TestInitSystemSystemdRoFullOverlayfsVarBackingFstab(
  337. TestInitSystemSystemdRoFullOverlayfs,
  338. InitSystemSystemdBaseOverlayfsVarBacking,
  339. ):
  340. config = InitSystemSystemdBaseOverlayfsVarBacking.gen_config(
  341. 'tests/init/systemd-overlay-fstab',
  342. )
  343. def test_run(self):
  344. super().test_run()
  345. self.check_var_mounted()