def test_dataimg_creation(self, request, bitbake_variables, prepared_test_build, bitbake_image): """Test that we can build a dataimg successfully.""" build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, ['IMAGE_FSTYPES = "dataimg"'], ) built_img = latest_build_artifact(request, prepared_test_build["build_dir"], "core-image*.dataimg") # Check that it contains the device_type file, as we expect. with make_tempdir() as tmpdir: menderdir = os.path.join(tmpdir, "mender") if ("ARTIFACTIMG_FSTYPE" in bitbake_variables and bitbake_variables["ARTIFACTIMG_FSTYPE"] == "ubifs"): subprocess.check_call( ["ubireader_extract_files", "-o", tmpdir, built_img]) else: os.mkdir(menderdir) subprocess.check_call([ "debugfs", "-R", "dump -p /mender/device_type %s" % os.path.join(menderdir, "device_type"), built_img, ]) with open(os.path.join(menderdir, "device_type")) as fd: content = fd.read() assert (content == "device_type=%s\n" % bitbake_variables["MENDER_DEVICE_TYPE"])
def test_expected_files_ext234_mender_monitor(self, conversion, bitbake_path, bitbake_variables, latest_rootfs): """Test mender-monitor expected files (only state folder)""" if not conversion: pytest.skip("Test only applicable for mender-convert images.") with make_tempdir() as tmpdir: # Check whether mender-monitor exists in /var/lib self.verify_file_exists( tmpdir, latest_rootfs, "/var/lib", "mender-monitor", ) # Check contents of /var/lib/mender-monitor output = subprocess.check_output( [ "debugfs", "-R", "stat /var/lib/mender-monitor", latest_rootfs ], cwd=tmpdir, ).decode() assert "Type: symlink" in output assert 'Fast link dest: "/data/mender-monitor"' in output
def test_expected_data_dirs( self, conversion, bitbake_path, bitbake_variables, latest_part_image ): with make_tempdir() as tmpdir: old_cwd_fd = os.open(".", os.O_RDONLY) os.chdir(tmpdir) try: data_part_number = get_data_part_number(latest_part_image) extract_partition(latest_part_image, data_part_number) output = subprocess.check_output( ["debugfs", "-R", "ls -l -p /", f"img{data_part_number}.fs"] ).decode() nodes = [ line.split("/")[5] for line in output.split("\n") if len(line) > 0 ] # Expect /data/mender to exist always assert "mender" in nodes # Independently from mender-configure's installation status, we create the # symlink for /var/lib/mender-configure to the data partition for mender-convert # to support the subsequent installation of the add-on by the user # Expect addons to be installed for Yocto and not for mender-convert assert "mender-configure" in nodes finally: os.fchdir(old_cwd_fd) os.close(old_cwd_fd)
def test_split_mender_conf( self, bitbake_path, bitbake_variables, latest_part_image ): with make_tempdir() as tmpdir: old_cwd_fd = os.open(".", os.O_RDONLY) os.chdir(tmpdir) try: data_part_number = get_data_part_number(latest_part_image) extract_partition(latest_part_image, data_part_number) subprocess.check_call( [ "debugfs", "-R", "dump -p /mender/mender.conf mender.conf", "img%d.fs" % data_part_number, ] ) with open("mender.conf") as fd: content = json.load(fd) assert "RootfsPartA" in content assert "RootfsPartB" in content assert len(content) == 2 finally: os.fchdir(old_cwd_fd) os.close(old_cwd_fd)
def test_mender_grubenv(self, bitbake_path, bitbake_variables, latest_part_image): with make_tempdir() as tmpdir: old_cwd_fd = os.open(".", os.O_RDONLY) os.chdir(tmpdir) try: extract_partition(latest_part_image, 1) for env_name in ["mender_grubenv1", "mender_grubenv2"]: subprocess.check_call( [ "mcopy", "-i", "img1.fs", "::/grub-mender-grubenv/%s/env" % env_name, ".", ] ) with open("env") as fd: data = fd.read() os.unlink("env") assert ( "mender_boot_part=%s" % bitbake_variables["MENDER_ROOTFS_PART_A"][-1] in data ) assert "upgrade_available=0" in data assert "bootcount=0" in data finally: os.fchdir(old_cwd_fd) os.close(old_cwd_fd)
def test_expected_files_ext234_mender_shell( self, conversion, bitbake_path, bitbake_variables, latest_rootfs ): """Test mender-shell expected files""" # Expect to be installed for Yocto and not for mender-convert expect_installed = not conversion with make_tempdir() as tmpdir: # Check whether mender-shell exists in /usr/bin output = subprocess.check_output( ["debugfs", "-R", "ls -l -p /usr/bin", latest_rootfs], cwd=tmpdir ).decode() binary_found = any( [ line.split("/")[5] == "mender-shell" for line in output.split("\n") if len(line) > 0 ] ) assert ( expect_installed and binary_found or (not expect_installed and not binary_found) ) # Check whether mender-shell.conf exists in /etc/mender output = subprocess.check_output( ["debugfs", "-R", "ls -l -p /etc/mender", latest_rootfs], cwd=tmpdir ).decode() conf_found = any( [ line.split("/")[5] == "mender-shell.conf" for line in output.split("\n") if len(line) > 0 ] ) assert ( expect_installed and conf_found or (not expect_installed and not conf_found) ) # Check mender-shell.conf contents if expect_installed: subprocess.check_call( [ "debugfs", "-R", "dump -p /etc/mender/mender-shell.conf mender-shell.conf", latest_rootfs, ], cwd=tmpdir, ) with open(os.path.join(tmpdir, "mender-shell.conf")) as fd: mender_shell_vars = json.load(fd) assert len(mender_shell_vars) == 2, mender_shell_vars assert "ServerURL" in mender_shell_vars, mender_shell_vars assert "User" in mender_shell_vars, mender_shell_vars
def test_volume_contents(self, bitbake_variables, ubimg_without_uboot_env): """Test that data volume has correct contents""" with make_tempdir() as tmpdir: rootdir = extract_ubimg_files(ubimg_without_uboot_env, tmpdir) assert os.path.exists( os.path.join(rootdir, "rootfsa/usr/bin/mender")) assert os.path.exists( os.path.join(rootdir, "rootfsb/usr/bin/mender"))
def test_fstab_correct(self, bitbake_path, bitbake_variables, latest_part_image): with make_tempdir() as tmpdir: old_cwd_fd = os.open(".", os.O_RDONLY) os.chdir(tmpdir) try: extract_partition(latest_part_image, 2) subprocess.check_call( ["debugfs", "-R", "dump -p /etc/fstab fstab", "img2.fs"] ) with open("fstab") as fd: data = fd.read() TestMostPartitionImages.verify_fstab(data) finally: os.fchdir(old_cwd_fd) os.close(old_cwd_fd)
def test_expected_files_ubifs(self, bitbake_path, bitbake_variables, latest_ubifs): """Test that artifact_info file is correctly embedded.""" with make_tempdir() as tmpdir: # NOTE: ubireader_extract_files can keep permissions only if # running as root, which we won't do subprocess.check_call( "ubireader_extract_files -o {outdir} {ubifs}".format( outdir=tmpdir, ubifs=latest_ubifs), shell=True, ) path = os.path.join(tmpdir, "etc/fstab") with open(path) as fd: data = fd.read() TestRootfs.verify_fstab(data)
def test_expected_files_ext234_mender_connect(self, conversion, bitbake_path, bitbake_variables, latest_rootfs): """Test mender-connect expected files""" # Expect to be installed for Yocto and not for mender-convert expect_installed = not conversion with make_tempdir() as tmpdir: # Check whether mender-connect exists in /usr/bin self.verify_file_exists(tmpdir, latest_rootfs, "/usr/bin", "mender-connect", expect_installed) # Check whether mender-connect.conf exists in /etc/mender self.verify_file_exists( tmpdir, latest_rootfs, "/etc/mender", "mender-connect.conf", expect_installed, ) # Check mender-connect.conf contents if expect_installed: subprocess.check_call( [ "debugfs", "-R", "dump -p /etc/mender/mender-connect.conf mender-connect.conf", latest_rootfs, ], cwd=tmpdir, ) with open(os.path.join(tmpdir, "mender-connect.conf")) as fd: mender_connect_vars = json.load(fd) assert len(mender_connect_vars) == 2, mender_connect_vars assert "ShellCommand" in mender_connect_vars, mender_connect_vars assert "User" in mender_connect_vars, mender_connect_vars
def test_perform_update( self, request, setup_board, prepared_test_build, bitbake_variables, bitbake_image, connection, http_server, board_type, use_s3, s3_address, ): """Perform a delta update. """ if ("read-only-rootfs" not in bitbake_variables["IMAGE_FEATURES"].strip().split()): pytest.skip("Only works when using read-only-rootfs IMAGE_FEATURE") if distutils.spawn.find_executable( "mender-binary-delta-generator") is None: pytest.fail("mender-binary-delta-generator not found in PATH") built_artifact = self.do_install_mender_binary_delta( request, prepared_test_build, bitbake_variables, bitbake_image, connection, http_server, board_type, use_s3, s3_address, ) with make_tempdir() as tmpdir: # Copy previous build artifact_from = os.path.join(tmpdir, "artifact_from.mender") shutil.copyfile(built_artifact, artifact_from) # Create new image installing some extra software build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, ['IMAGE_INSTALL_append = " nano"'], ) built_artifact = latest_build_artifact( request, prepared_test_build["build_dir"], "core-image*.mender") artifact_to = os.path.join(tmpdir, "artifact_to.mender") shutil.copyfile(built_artifact, artifact_to) # Create delta Artifact using mender-binary-delta-generator artifact_delta = os.path.join(tmpdir, "artifact_delta.mender") subprocess.check_call( f"mender-binary-delta-generator -n v2.0-deltafrom-v1.0 {artifact_from} {artifact_to} -o {artifact_delta}", shell=True, ) # Verbose provides/depends of the different Artifacts and the client (when supported) connection.run("mender show-provides", warn=True) subprocess.check_call( "mender-artifact read %s" % artifact_from, shell=True, ) subprocess.check_call( "mender-artifact read %s" % artifact_to, shell=True, ) subprocess.check_call( "mender-artifact read %s" % artifact_delta, shell=True, ) # Install Artifact, verify partitions and commit (active, passive) = determine_active_passive_part(bitbake_variables, connection) Helpers.install_update(artifact_delta, connection, http_server, board_type, use_s3, s3_address) reboot(connection) run_after_connect("true", connection) (new_active, new_passive) = determine_active_passive_part( bitbake_variables, connection) assert new_active == passive assert new_passive == active connection.run("mender -commit")
def test_expected_files_ext234( self, bitbake_path, bitbake_variables, latest_rootfs ): """Test mender client expected files""" with make_tempdir() as tmpdir: try: subprocess.check_call( [ "debugfs", "-R", "dump -p /etc/mender/artifact_info artifact_info", latest_rootfs, ], cwd=tmpdir, ) with open(os.path.join(tmpdir, "artifact_info")) as fd: data = fd.read() TestRootfs.verify_artifact_info_data( data, bitbake_variables["MENDER_ARTIFACT_NAME"] ) assert ( os.stat(os.path.join(tmpdir, "artifact_info")).st_mode & 0o777 == 0o644 ) subprocess.check_call( ["debugfs", "-R", "dump -p /etc/fstab fstab", latest_rootfs], cwd=tmpdir, ) with open(os.path.join(tmpdir, "fstab")) as fd: data = fd.read() TestRootfs.verify_fstab(data) output = subprocess.check_output( ["debugfs", "-R", "ls -l -p /data", latest_rootfs], cwd=tmpdir ).decode() for line in output.split("\n"): splitted = line.split("/") if len(splitted) <= 1: continue # Should only contain "." and "..". In addition, debugfs # sometimes, but not always, returns a strange 0 entry, with # no name, but a "0" in the sixth column. It is not present # when mounting the filesystem. assert ( splitted[5] == "." or splitted[5] == ".." or splitted[6] == "0" ) # Check whether mender exists in /usr/bin output = subprocess.check_output( ["debugfs", "-R", "ls -l -p /usr/bin", latest_rootfs], cwd=tmpdir ).decode() assert any( [ line.split("/")[5] == "mender" for line in output.split("\n") if len(line) > 0 ] ) # Check whether DBus files exist output = subprocess.check_output( [ "debugfs", "-R", "ls -l -p /usr/share/dbus-1/system.d", latest_rootfs, ], cwd=tmpdir, ).decode() assert any( [ line.split("/")[5] == "io.mender.AuthenticationManager.conf" for line in output.split("\n") if len(line) > 0 ] ) except: subprocess.call(["ls", "-l", "artifact_info"]) print("Contents of artifact_info:") subprocess.call(["cat", "artifact_info"]) raise
def test_extra_parts(self, request, latest_part_image, prepared_test_build, bitbake_image): sdimg = latest_part_image.endswith(".sdimg") uefiimg = latest_part_image.endswith(".uefiimg") gptimg = latest_part_image.endswith(".gptimg") biosimg = latest_part_image.endswith(".biosimg") with make_tempdir() as tmpdir1, make_tempdir( ) as tmpdir2, make_tempdir() as tmpdir3, make_tempdir() as tmpdir4: with open(os.path.join(tmpdir1, "tmpfile1"), "w") as fd: fd.write("Test content1\n") with open(os.path.join(tmpdir2, "tmpfile2"), "w") as fd: fd.write("Test content2\n") with open(os.path.join(tmpdir3, "tmpfile3"), "w") as fd: fd.write("Test content3\n") with open(os.path.join(tmpdir4, "tmpfile4"), "w") as fd: fd.write("Test content4\n") build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, [ 'MENDER_EXTRA_PARTS = "test1 test2 test3 test4"', 'MENDER_EXTRA_PARTS[test1] = "--fixed-size 100M --label=test1 --fstype=ext4 --source rootfs --rootfs-dir %s"' % tmpdir1, 'MENDER_EXTRA_PARTS[test2] = "--fixed-size 50M --fstype=ext4 --source rootfs --rootfs-dir %s --label=test2"' % tmpdir2, 'MENDER_EXTRA_PARTS[test3] = "--fixed-size 50M --fstype=ext4 --source rootfs --rootfs-dir %s --label=test3"' % tmpdir3, 'MENDER_EXTRA_PARTS[test4] = "--fixed-size 50M --fstype=ext4 --source rootfs --rootfs-dir %s --label=test4"' % tmpdir4, 'MENDER_EXTRA_PARTS_FSTAB[test1] = "auto nouser"', 'MENDER_EXTRA_PARTS_FSTAB[test2] = "ext4 default,ro"', 'MENDER_EXTRA_PARTS_FSTAB[test3] = "ext4 default,ro 1"', 'MENDER_EXTRA_PARTS_FSTAB[test4] = "ext4 default,ro 1 0"', ], ) image = latest_build_artifact(request, prepared_test_build["build_dir"], "*img") # Take extended partition into account for MBR partition tables. if uefiimg or gptimg: # Example # 1 16384 49151 16.0 MiB 0700 Microsoft basic data # 2 49152 507903 224.0 MiB 8300 Linux filesystem # 3 507904 966655 224.0 MiB 8300 Linux filesystem # 4 983040 1245183 128.0 MiB 8300 Linux filesystem # 5 1261568 1466367 100.0 MiB 8300 Linux filesystem # 6 1474560 1679359 100.0 MiB 8300 Linux filesystem output = subprocess.check_output(["sgdisk", "-p", image]).decode() test1_re = r"^\s*5\s+([0-9]+)\s+([0-9]+)\s+100.0\s+MiB\s+8300\s+" test2_re = r"^\s*6\s+([0-9]+)\s+([0-9]+)\s+50.0\s+MiB\s+8300\s+" test3_re = r"^\s*7\s+([0-9]+)\s+([0-9]+)\s+50.0\s+MiB\s+8300\s+" test4_re = r"^\s*8\s+([0-9]+)\s+([0-9]+)\s+50.0\s+MiB\s+8300\s+" extra_start = 5 else: # Example: # ...sdimg1 * 16384 49151 32768 16M c W95 FAT32 (LBA) # ...sdimg2 49152 507903 458752 224M 83 Linux # ...sdimg3 507904 966655 458752 224M 83 Linux # ...sdimg4 983039 1576959 593921 290M f W95 Ext'd (LBA) # ...sdimg5 983040 1245183 262144 128M 83 Linux # ...sdimg6 1261568 1466367 204800 100M 83 Linux # ...sdimg7 1474560 1576959 102400 50M 83 Linux output = subprocess.check_output(["fdisk", "-l", image]).decode() test1_re = r"img6(?:\s|\*)+([0-9]+)\s+([0-9]+)\s+[0-9]+\s+100M\s+83\s+" test2_re = r"img7(?:\s|\*)+([0-9]+)\s+([0-9]+)\s+[0-9]+\s+50M\s+83\s+" test3_re = r"img8(?:\s|\*)+([0-9]+)\s+([0-9]+)\s+[0-9]+\s+50M\s+83\s+" test4_re = r"img9(?:\s|\*)+([0-9]+)\s+([0-9]+)\s+[0-9]+\s+50M\s+83\s+" extra_start = 6 match1 = re.search(test1_re, output, flags=re.MULTILINE) match2 = re.search(test2_re, output, flags=re.MULTILINE) match3 = re.search(test3_re, output, flags=re.MULTILINE) match4 = re.search(test4_re, output, flags=re.MULTILINE) assert match1 is not None assert match2 is not None assert match3 is not None assert match4 is not None ext4 = latest_build_artifact(request, prepared_test_build["build_dir"], "*.ext4") fstab = subprocess.check_output( ["debugfs", "-R", "cat /etc/fstab", ext4]).decode() # Example: # /dev/mmcblk0p5 /mnt/test1 auto nouser 0 2 # /dev/mmcblk0p6 /mnt/test2 auto default,ro 0 2 # /dev/mmcblk0p7 /mnt/test3 auto default,ro 1 2 # /dev/mmcblk0p8 /mnt/test4 auto default,ro 1 0 test1_re = ( r"^/dev/[a-z0-9]+%d\s+/mnt/test1\s+auto\s+nouser\s+0\s+2\s*$" % extra_start) test2_re = r"^/dev/[a-z0-9]+%d\s+/mnt/test2\s+ext4\s+default,ro\s+0\s+2\s*$" % ( extra_start + 1) test3_re = r"^/dev/[a-z0-9]+%d\s+/mnt/test3\s+ext4\s+default,ro\s+1\s+2\s*$" % ( extra_start + 2) test4_re = r"^/dev/[a-z0-9]+%d\s+/mnt/test4\s+ext4\s+default,ro\s+1\s+0\s*$" % ( extra_start + 3) assert re.search(test1_re, fstab, flags=re.MULTILINE) is not None assert re.search(test2_re, fstab, flags=re.MULTILINE) is not None assert re.search(test3_re, fstab, flags=re.MULTILINE) is not None assert re.search(test4_re, fstab, flags=re.MULTILINE) is not None
def test_expected_files_ext234(self, bitbake_path, bitbake_variables, latest_rootfs): """Test mender client expected files""" with make_tempdir() as tmpdir: subprocess.check_call( ["debugfs", "-R", "dump -p /etc/fstab fstab", latest_rootfs], cwd=tmpdir, ) with open(os.path.join(tmpdir, "fstab")) as fd: data = fd.read() TestRootfs.verify_fstab(data) output = subprocess.check_output( ["debugfs", "-R", "ls -l -p /data", latest_rootfs], cwd=tmpdir).decode() for line in output.split("\n"): splitted = line.split("/") if len(splitted) <= 1: continue # Should only contain "." and "..". In addition, debugfs # sometimes, but not always, returns a strange 0 entry, with # no name, but a "0" in the sixth column. It is not present # when mounting the filesystem. assert splitted[5] == "." or splitted[5] == ".." or splitted[ 6] == "0" # Check whether mender exists in /usr/bin self.verify_file_exists(tmpdir, latest_rootfs, "/usr/bin", "mender", True) # Check whether mender exists in /var/lib self.verify_file_exists( tmpdir, latest_rootfs, "/var/lib", "mender", True, ) # Check contents of /var/lib/mender output = subprocess.check_output( ["debugfs", "-R", "stat /var/lib/mender", latest_rootfs], cwd=tmpdir, ).decode() assert "Type: symlink" in output assert 'Fast link dest: "/data/mender"' in output # Check whether D-Bus policy files exist self.verify_file_exists( tmpdir, latest_rootfs, "/usr/share/dbus-1/system.d", "io.mender.AuthenticationManager.conf", True, ) if version_is_minimum(bitbake_variables, "mender-client", "3.0.0"): self.verify_file_exists( tmpdir, latest_rootfs, "/usr/share/dbus-1/system.d", "io.mender.UpdateManager.conf", True, )
def test_expected_files_ext234_mender_configure(self, conversion, bitbake_path, bitbake_variables, latest_rootfs): """Test mender-configure expected files""" # Expect to be installed for Yocto and not for mender-convert expect_installed = not conversion with make_tempdir() as tmpdir: # Check whether mender-configure exists in /usr/share/mender/modules/v3 self.verify_file_exists( tmpdir, latest_rootfs, "/usr/share/mender/modules/v3", "mender-configure", expect_installed, ) # Check whether mender-configure is executable if expect_installed: self.verify_file_executable( tmpdir, latest_rootfs, "/usr/share/mender/modules/v3", "mender-configure", ) # Check whether mender-inventory-mender-configure exists in /usr/share/mender/inventory self.verify_file_exists( tmpdir, latest_rootfs, "/usr/share/mender/inventory", "mender-inventory-mender-configure", expect_installed, ) # Check whether mender-inventory-mender-configure is executable if expect_installed: self.verify_file_executable( tmpdir, latest_rootfs, "/usr/share/mender/inventory", "mender-inventory-mender-configure", ) # Independently from mender-configure's installation status, we create the # symlink for /var/lib/mender-configure to the data partition for mender-convert # to support the subsequent installation of the add-on by the user # Check whether mender-configure exists in /var/lib self.verify_file_exists( tmpdir, latest_rootfs, "/var/lib", "mender-configure", ) # Check contents of /var/lib/mender-configure output = subprocess.check_output( [ "debugfs", "-R", "stat /var/lib/mender-configure", latest_rootfs ], cwd=tmpdir, ).decode() assert "Type: symlink" in output assert 'Fast link dest: "/data/mender-configure"' in output