public inbox for isar-users@googlegroups.com
 help / color / mirror / Atom feed
From: "T. Schaffner" <tobias.schaffner@siemens.com>
To: <isar-users@googlegroups.com>
Cc: <quirin.gylstorff@siemens.com>, <henning.schild@siemens.com>,
	"Tobias Schaffner" <tobias.schaffner@siemens.com>
Subject: [PATCH v2 3/4] add unittests for the image-account-extension
Date: Tue, 9 May 2023 09:44:11 +0200	[thread overview]
Message-ID: <20230509074412.86392-4-tobias.schaffner@siemens.com> (raw)
In-Reply-To: <20230509074412.86392-1-tobias.schaffner@siemens.com>

From: Tobias Schaffner <tobias.schaffner@siemens.com>

This is a first example on how to use the unittest_isar module to test
python functions defined in a bitbake file.

Signed-off-by: Tobias Schaffner <tobias.schaffner@siemens.com>
---
 .../unittests/test_image_account_extension.py | 145 ++++++++++++++++++
 1 file changed, 145 insertions(+)
 create mode 100644 testsuite/unittests/test_image_account_extension.py

diff --git a/testsuite/unittests/test_image_account_extension.py b/testsuite/unittests/test_image_account_extension.py
new file mode 100644
index 00000000..d35de723
--- /dev/null
+++ b/testsuite/unittests/test_image_account_extension.py
@@ -0,0 +1,145 @@
+# This software is a part of ISAR.
+# Copyright (C) Siemens AG, 2023
+#
+# SPDX-License-Identifier: MIT
+
+from bitbake import load_function, DataSmart
+from rootfs import TemporaryRootfs
+
+import unittest
+from unittest.mock import patch
+from typing import Tuple
+
+
+file_name = "meta/classes/image-account-extension.bbclass"
+image_create_users = load_function(file_name, "image_create_users")
+image_create_groups = load_function(file_name, "image_create_groups")
+
+
+class TestImageAccountExtensionCommon(unittest.TestCase):
+
+    def setup(self) -> Tuple[DataSmart, TemporaryRootfs]:
+        rootfs = TemporaryRootfs()
+
+        d = DataSmart()
+        d.setVar("ROOTFSDIR", rootfs.path())
+
+        return (d, rootfs)
+
+
+class TestImageAccountExtensionImageCreateUsers(TestImageAccountExtensionCommon):
+
+    def setup(self, user_name: str) -> Tuple[DataSmart, TemporaryRootfs]:
+        d, rootfs = super().setup()
+        rootfs.create_file(
+            "/etc/passwd", "test:x:1000:1000::/home/test:/bin/sh")
+        d.setVar("USERS", user_name)
+        return (d, rootfs)
+
+    def test_new_user(self):
+        test_user = "new"
+        d, rootfs = self.setup(test_user)
+
+        with patch.object(bb.process, "run") as run_mock:
+            image_create_users(d)
+
+        run_mock.assert_called_once_with(
+            ["sudo", "-E", "chroot", rootfs.path(), "/usr/sbin/useradd", test_user])
+
+    def test_existing_user_no_change(self):
+        test_user = "test"
+        d, _ = self.setup(test_user)
+
+        with patch.object(bb.process, "run") as run_mock:
+            image_create_users(d)
+
+        run_mock.assert_not_called()
+
+    def test_existing_user_home_change(self):
+        test_user = "test"
+        d, _ = self.setup(test_user)
+        d.setVarFlag("USER_{}".format(test_user), "home", "/home/new_home")
+
+        with patch.object(bb.process, "run") as run_mock:
+            image_create_users(d)
+
+        assert run_mock.call_count == 1
+        assert run_mock.call_args[0][0][-5:] == ["/usr/sbin/usermod",
+                                                 '--home', '/home/new_home', '--move-home', 'test']
+
+    def test_deterministic_password(self):
+        test_user = "new"
+        cleartext_password = "test"
+        d, _ = self.setup(test_user)
+
+        d.setVarFlag("USER_{}".format(test_user),
+                     "flags", "clear-text-password")
+        d.setVarFlag("USER_{}".format(test_user),
+                     "password", cleartext_password)
+
+        source_date_epoch = "1672427776"
+        d.setVar("SOURCE_DATE_EPOCH", source_date_epoch)
+
+        # openssl passwd -6 -salt $(echo "1672427776" | sha256sum -z | cut -c 1-15) test
+        encrypted_password = "$6$eb2e2a12cccc88a$IuhgisFe5AKM5.VREKg8wIAcPSkaJDWBM1cMUsEjNZh2Wa6BT2f5OFhqGTGpL4lFzHGN8oiwvAh0jFO1GhO3S."
+
+        with patch.object(bb.process, "run") as run_mock:
+            image_create_users(d)
+
+        assert run_mock.call_count == 2
+        assert run_mock.call_args[0][1] == "{}:{}".format(
+            test_user, encrypted_password).encode()
+
+
+class TestImageAccountExtensionImageCreateGroups(TestImageAccountExtensionCommon):
+
+    def setup(self, group_name: str) -> Tuple[DataSmart, TemporaryRootfs]:
+        d, rootfs = super().setup()
+        rootfs.create_file("/etc/group", "test:x:1000:test")
+        d.setVar("GROUPS", group_name)
+        return (d, rootfs)
+
+    def test_new_group(self):
+        test_group = "new"
+        d, rootfs = self.setup(test_group)
+
+        with patch.object(bb.process, "run") as run_mock:
+            image_create_groups(d)
+
+        run_mock.assert_called_once_with(
+            ["sudo", "-E", "chroot", rootfs.path(), "/usr/sbin/groupadd", test_group])
+
+    def test_existing_group_no_change(self):
+        test_group = "test"
+        d, _ = self.setup(test_group)
+
+        with patch.object(bb.process, "run") as run_mock:
+            image_create_groups(d)
+
+        run_mock.assert_not_called()
+
+    def test_existing_group_id_change(self):
+        test_group = "test"
+        d, rootfs = self.setup(test_group)
+        d.setVarFlag("GROUP_{}".format(test_group), "gid", "1005")
+
+        with patch.object(bb.process, "run") as run_mock:
+            image_create_groups(d)
+
+        run_mock.assert_called_once_with(
+            ["sudo", "-E", "chroot", rootfs.path(), "/usr/sbin/groupmod", "--gid", "1005", test_group])
+
+    def test_system_flag(self):
+        test_group = "test"
+        d, _ = self.setup(test_group)
+        d.setVarFlag("GROUP_{}".format(test_group), "flags", "system")
+
+        with patch.object(bb.process, "run") as run_mock:
+            image_create_groups(d)
+
+        assert run_mock.call_count == 1
+        assert "--system" in run_mock.call_args[0][0]
+
+
+if __name__ == "__main__":
+    unittest.main()
-- 
2.34.1


  parent reply	other threads:[~2023-05-09  7:45 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-09  7:44 [PATCH v2 0/4] Rewrite the image-account-extension in python T. Schaffner
2023-05-09  7:44 ` [PATCH v2 1/4] simplify image-account-extension T. Schaffner
2023-05-09  7:44 ` [PATCH v2 2/4] create a minimal python unittest infrastructure T. Schaffner
2023-05-09  7:44 ` T. Schaffner [this message]
2023-05-09  7:44 ` [PATCH v2 4/4] set minimal python version in user_manual to 3.5 T. Schaffner
2023-05-22  4:41 ` [PATCH v2 0/4] Rewrite the image-account-extension in python Uladzimir Bely
2023-05-22  4:57   ` Uladzimir Bely
2023-05-22  6:52     ` Schaffner, Tobias

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230509074412.86392-4-tobias.schaffner@siemens.com \
    --to=tobias.schaffner@siemens.com \
    --cc=henning.schild@siemens.com \
    --cc=isar-users@googlegroups.com \
    --cc=quirin.gylstorff@siemens.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox