def test_mender_inventory_network_scripts(self, request, prepared_test_build, bitbake_image): """ Test the 'inventory-network-scripts' build feature configuration through 'PACKAGECONFIG' is working as expected. This verifies that the 'inventory-network-scripts' option is a part build, and also that the inventory scripts are not included when removed. The test only runs for sdimg, as the build image should not really matter here. """ # # Feature enabled # reset_build_conf(prepared_test_build["build_dir"]) build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, [ 'PACKAGECONFIG_append_pn-mender-client = " inventory-network-scripts"' ], ) rootfs = latest_build_artifact(request, prepared_test_build["build_dir"], "core-image*.ext4") assert len(rootfs) > 0, "rootfs not generated" output = subprocess.check_output( ["debugfs", "-R", "ls /usr/share/mender/inventory", rootfs]) assert ( b"mender-inventory-geo" in output ), "mender-inventory-network-scripts seems not to be a part of the image, like they should" # # Feature disabled # reset_build_conf(prepared_test_build["build_dir"]) build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, [ 'PACKAGECONFIG_remove_pn-mender-client = " inventory-network-scripts"' ], ) rootfs = latest_build_artifact(request, prepared_test_build["build_dir"], "core-image*.ext4") assert len(rootfs) > 0, "ext4 not generated" output = subprocess.check_output( ["debugfs", "-R", "ls /usr/share/mender/inventory", rootfs]) assert ( b"mender-inventory-geo" not in output ), "mender-inventory-network-scripts unexpectedly a part of the image"
def test_artifact_signing_keys( self, request, prepared_test_build, bitbake_variables, bitbake_path, bitbake_image, ): """Test that MENDER_ARTIFACT_SIGNING_KEY and MENDER_ARTIFACT_VERIFY_KEY works correctly.""" build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, [ 'MENDER_ARTIFACT_SIGNING_KEY = "%s"' % os.path.join(os.getcwd(), signing_key("RSA").private), 'MENDER_ARTIFACT_VERIFY_KEY = "%s"' % os.path.join(os.getcwd(), signing_key("RSA").public), ], ) built_rootfs = latest_build_artifact( request, prepared_test_build["build_dir"], "core-image*.ext[234]" ) # Copy out the key we just added from the image and use that to # verify instead of the original, just to be sure. subprocess.check_call( [ "debugfs", "-R", "dump -p /etc/mender/artifact-verify-key.pem artifact-verify-key.pem", built_rootfs, ] ) try: built_artifact = latest_build_artifact( request, prepared_test_build["build_dir"], "core-image*.mender" ) output = subprocess.check_output( [ "mender-artifact", "read", "-k", os.path.join(os.getcwd(), "artifact-verify-key.pem"), built_artifact, ] ).decode() assert output.find("Signature: signed and verified correctly") >= 0 finally: os.remove("artifact-verify-key.pem")
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_tenant_token(self, request, prepared_test_build, bitbake_image): """Test setting a custom tenant-token""" build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, [ 'MENDER_TENANT_TOKEN = "%s"' % "authtentoken", 'IMAGE_FSTYPES += "dataimg"', ], ) built_rootfs = latest_build_artifact(request, prepared_test_build["build_dir"], "core-image*.dataimg") subprocess.check_call([ "debugfs", "-R", "dump -p /etc/mender/mender.conf mender.conf", built_rootfs, ]) try: with open("mender.conf") as fd: data = json.load(fd) assert data["TenantToken"] == "authtentoken" finally: os.remove("mender.conf")
def test_build_and_run_module(self, request, bitbake_variables, prepared_test_build, bitbake_image): build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, ['IMAGE_INSTALL_append = " mender-binary-delta"'], [ 'BBLAYERS_append = " %s/../meta-mender-commercial"' % bitbake_variables["LAYERDIR_MENDER"] ], ) image = latest_build_artifact(request, prepared_test_build["build_dir"], "core-image*.ext4") output = subprocess.check_output( ["debugfs", "-R", "ls -p /usr/share/mender/modules/v3", image]).decode() # Debugfs has output like this: # /3018/100755/0/0/mender-binary-delta/142672/ # /3015/100755/0/0/rootfs-image-v2/1606/ assert "mender-binary-delta" in [ line.split("/")[5] for line in output.split("\n") if line.startswith("/") ]
def ubimg_without_uboot_env(request, latest_ubimg, prepared_test_build, bitbake_image): """The ubireader_utils_info tool and friends don't support our UBI volumes that contain the U-Boot environment and hence not valid UBIFS structures. Therefore, make a new temporary image that doesn't contain U-Boot.""" # The tests are marked with "only_with_image('ubimg')", but that is checked # using a function fixture, and this is a session fixture, which cannot # depend on that. So we need this check here to bail out if we don't find a # ubimg. if not latest_ubimg: pytest.skip("No ubimg found") reset_build_conf(prepared_test_build["build_dir"]) build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, ['MENDER_FEATURES_DISABLE_append = " mender-uboot"'], ) ubimg = latest_build_artifact(request, prepared_test_build["build_dir"], "core-image*.ubimg") imgdir = tempfile.mkdtemp() tmpimg = os.path.join(imgdir, os.path.basename(ubimg)) shutil.copyfile(ubimg, tmpimg) def remove_ubimg(): os.unlink(tmpimg) request.addfinalizer(remove_ubimg) return tmpimg
def test_multiple_device_types_compatible( self, request, prepared_test_build, bitbake_path, bitbake_variables, bitbake_image, ): """Tests that we can include multiple device_types in the artifact.""" build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, ['MENDER_DEVICE_TYPES_COMPATIBLE = "machine1 machine2"'], ) image = latest_build_artifact(request, prepared_test_build["build_dir"], "core-image*.mender") output = run_verbose("mender-artifact read %s" % image, capture=True) assert b"Compatible devices: '[machine1 machine2]'" in output output = subprocess.check_output( "tar xOf %s header.tar.gz | tar xOz header-info" % image, shell=True).decode() data = json.loads(output) if version_is_minimum(bitbake_variables, "mender-artifact", "3.0.0"): assert data["artifact_depends"]["device_type"] == [ "machine1", "machine2" ] else: assert data["device_types_compatible"] == ["machine1", "machine2"]
def test_module_install( self, request, prepared_test_build, bitbake_path, latest_rootfs, bitbake_image ): # List of expected update modules default_update_modules = [ "deb", "directory", "docker", "rootfs-image-v2", "rpm", "script", "single-file", ] mender_vars = get_bitbake_variables(request, "mender-client") if "modules" in mender_vars["PACKAGECONFIG"].split(): originally_on = True else: originally_on = False output = subprocess.check_output( ["debugfs", "-R", "ls -p /usr/share/mender/modules/v3", latest_rootfs] ).decode() entries = [ elem.split("/")[5] for elem in output.split("\n") if elem.startswith("/") ] if originally_on: assert all([e in entries for e in default_update_modules]) build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, ['PACKAGECONFIG_remove = "modules"'], ) else: assert not any([e in entries for e in default_update_modules]) build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, ['PACKAGECONFIG_append = " modules"'], ) new_rootfs = latest_build_artifact( request, prepared_test_build["build_dir"], "core-image*.ext4" ) output = subprocess.check_output( ["debugfs", "-R", "ls -p /usr/share/mender/modules/v3", new_rootfs] ).decode() entries = [ elem.split("/")[5] for elem in output.split("\n") if elem.startswith("/") ] if originally_on: assert not any([e in entries for e in default_update_modules]) else: assert all([e in entries for e in default_update_modules])
def test_bootloader_embed(self, request, prepared_test_build, bitbake_image): """Test that MENDER_IMAGE_BOOTLOADER_FILE causes the bootloader to be embedded correctly in the resulting sdimg.""" loader_file = "bootloader.bin" loader_offset = 4 new_bb_vars = get_bitbake_variables( request, "core-image-minimal", prepared_test_build=prepared_test_build) loader_dir = new_bb_vars["DEPLOY_DIR_IMAGE"] loader_path = os.path.join(loader_dir, loader_file) run_verbose("mkdir -p %s" % os.path.dirname(loader_path)) run_verbose("cp /etc/os-release %s" % loader_path) build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, [ 'MENDER_IMAGE_BOOTLOADER_FILE = "%s"' % loader_file, 'MENDER_IMAGE_BOOTLOADER_BOOTSECTOR_OFFSET = "%d"' % loader_offset, ], ) built_sdimg = latest_build_artifact(request, prepared_test_build["build_dir"], "core-image*.sdimg") original = os.open(loader_path, os.O_RDONLY) embedded = os.open(built_sdimg, os.O_RDONLY) os.lseek(embedded, loader_offset * 512, 0) block_size = 4096 while True: org_read = os.read(original, block_size) org_read_size = len(org_read) emb_read = os.read(embedded, org_read_size) assert ( org_read == emb_read ), "Embedded bootloader is not identical to the file specified in MENDER_IMAGE_BOOTLOADER_FILE" if org_read_size < block_size: break os.close(original) os.close(embedded)
def versioned_mender_image(request, prepared_test_build, latest_mender_image, bitbake_variables, bitbake_image): """Gets the correct version of the artifact, whether it's the one we build by default, or one we have to produce ourselves. Returns a tuple of version and built image.""" global LAST_BUILD_VERSION version = request.param if version == 1: pytest.fail() if (version >= 2 and not version_is_minimum( bitbake_variables, "mender-artifact", "2.0.0")) or ( version >= 3 and not version_is_minimum( bitbake_variables, "mender-artifact", "3.0.0")): pytest.skip("Requires version %d of mender-artifact format." % version) if version_is_minimum(bitbake_variables, "mender-artifact", "3.0.0"): default_version = 3 elif version_is_minimum(bitbake_variables, "mender-artifact", "2.0.0"): default_version = 2 else: default_version = 2 if LAST_BUILD_VERSION != version: # Run a separate build for this artifact. This doesn't conflict with the # above version because the non-default version ends up in a different # directory. if version != default_version: build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, ['MENDER_ARTIFACT_EXTRA_ARGS = "-v %d"' % version], ) else: build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, ) LAST_BUILD_VERSION = version return ( version, latest_build_artifact(request, prepared_test_build["build_dir"], "core-image*.mender"), )
def test_module_install(self, request, prepared_test_build, bitbake_path, latest_rootfs, bitbake_image): mender_vars = get_bitbake_variables(request, "mender-client") if "modules" in mender_vars["PACKAGECONFIG"].split(): originally_on = True else: originally_on = False output = subprocess.check_output( ["debugfs", "-R", "ls -p /usr/share/mender", latest_rootfs]).decode() entries = [ elem.split("/")[5] for elem in output.split("\n") if elem.startswith("/") ] if originally_on: assert "modules" in entries build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, ['PACKAGECONFIG_remove = "modules"'], ) else: assert "modules" not in entries build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, ['PACKAGECONFIG_append = " modules"'], ) new_rootfs = latest_build_artifact(request, prepared_test_build["build_dir"], "core-image*.ext4") output = subprocess.check_output( ["debugfs", "-R", "ls -p /usr/share/mender", new_rootfs]).decode() entries = [ elem.split("/")[5] for elem in output.split("\n") if elem.startswith("/") ] if originally_on: assert "modules" not in entries else: assert "modules" in entries
def test_image_rootfs_extra_space(self, request, prepared_test_build, bitbake_variables, bitbake_image): """Test that setting IMAGE_ROOTFS_EXTRA_SPACE to arbitrary values does not break the build.""" build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, ['IMAGE_ROOTFS_EXTRA_SPACE_append = " + 640 - 222 + 900"'], ) built_rootfs = latest_build_artifact(request, prepared_test_build["build_dir"], "core-image*.ext4") assert (os.stat(built_rootfs).st_size == int( bitbake_variables["MENDER_CALC_ROOTFS_SIZE"]) * 1024)
def test_build_artifact_depends_and_provides(self, request, prepared_test_build, bitbake_image, bitbake_path, dependsprovides): """Test whether a build with enabled Artifact Provides and Depends does indeed add the parameters to the built Artifact""" build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, [param for param in str(dependsprovides).splitlines()], ) image = latest_build_artifact(request, prepared_test_build["build_dir"], "core-image*.mender") output = run_verbose("mender-artifact read %s" % image, capture=True).decode() other = TestBuild.BuildDependsProvides.parse(output) # MEN-2956: Mender-Artifact now writes rootfs-image-checksum by default. # MEN-3482: The new key for the rootfs image checksum is rootfs-image.checksum assert ( "rootfs-image.checksum" in other.provides or "rootfs_image_checksum" in other.provides ), "Empty rootfs_image_checksum in the built rootfs-image artifact, this should be added by default by `mender-artifact write rootfs-image`" # Then remove it, not to mess up the expected test output if "rootfs-image.checksum" in other.provides.keys(): del other.provides["rootfs-image.checksum"] if "rootfs_image_checksum" in other.provides.keys(): del other.provides["rootfs_image_checksum"] # MEN-3076: Mender-Artifacts writes software version by default # older versions did not, thus we remove the key before asserting the content if "rootfs-image.version" in other.provides.keys(): del other.provides["rootfs-image.version"] assert dependsprovides.__dict__ == other.__dict__
def test_bootimg_creation( self, request, bitbake_variables, prepared_test_build, bitbake_image ): """Test that we can build a bootimg successfully.""" build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, ['IMAGE_FSTYPES = "bootimg"'], ) built_img = latest_build_artifact( request, prepared_test_build["build_dir"], "core-image*.bootimg" ) distro_features = bitbake_variables["MENDER_FEATURES"].split() if "mender-grub" in distro_features and "mender-image-uefi" in distro_features: output = subprocess.check_output( ["mdir", "-i", built_img, "-b", "/EFI/BOOT"] ).decode() assert "mender_grubenv1" in output.split("/")
def test_build_addon( self, request, bitbake_variables, prepared_test_build, bitbake_image ): build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, ['IMAGE_INSTALL_append = " mender-monitor"'], [ 'BBLAYERS_append = " %s/../meta-mender-commercial"' % bitbake_variables["LAYERDIR_MENDER"] ], ) image = latest_build_artifact( request, prepared_test_build["build_dir"], "core-image*.ext4" ) for expected_node in ( "/usr/bin/mender-monitorctl", "/usr/bin/mender-monitord", "/etc/mender-monitor/monitor.d/log.sh", "/etc/mender-monitor/monitor.d/service.sh", "/usr/share/mender-monitor/mender-monitorctl", "/usr/share/mender-monitor/mender-monitord", "/usr/share/mender-monitor/ctl.sh", "/usr/share/mender-monitor/daemon.sh", "/usr/share/mender-monitor/common/common.sh", "/usr/share/mender-monitor/config/config.sh", "/usr/share/mender-monitor/lib/monitor-lib.sh", "/usr/share/mender-monitor/lib/service-lib.sh", "/var/lib/mender-monitor", ): output = subprocess.check_output( ["debugfs", "-R", "stat %s" % expected_node, image] ).decode() # The nodes are either files or symlinks assert "Type: regular" in output or "Type: symlink" in output
def test_build_mender_gateway(self, request, bitbake_variables, prepared_test_build, bitbake_image): build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, ['IMAGE_INSTALL_append = " mender-gateway"'], [ 'BBLAYERS_append = " %s/../meta-mender-commercial"' % bitbake_variables["LAYERDIR_MENDER"] ], ) image = latest_build_artifact(request, prepared_test_build["build_dir"], "core-image*.ext4") for file in ( "/usr/bin/mender-gateway", "/usr/share/mender/inventory/mender-inventory-mender-gateway", ): output = subprocess.check_output( ["debugfs", "-R", f"stat {file}", image]).decode() assert "Type: regular" in output
def do_install_mender_binary_delta( self, request, prepared_test_build, bitbake_variables, bitbake_image, connection, http_server, board_type, use_s3, s3_address, ): build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, ['IMAGE_INSTALL_append = " mender-binary-delta"'], [ 'BBLAYERS_append = " %s/../meta-mender-commercial"' % bitbake_variables["LAYERDIR_MENDER"] ], ) image = latest_build_artifact(request, prepared_test_build["build_dir"], "core-image*.mender") Helpers.install_update(image, connection, http_server, board_type, use_s3, s3_address) reboot(connection) run_after_connect("true", connection) connection.run("mender -commit") return image
def test_equal_checksum_ubimg_and_artifact(self, request, prepared_test_build, bitbake_image): # See ubimg_without_uboot_env() for why this is needed. We need to do it # explicitly here because we need both the artifact and the ubimg. build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, ['MENDER_FEATURES_DISABLE_append = " mender-uboot"'], ) bufsize = 1048576 # 1MiB with tempfile.NamedTemporaryFile() as tmp_artifact: latest_mender_image = latest_build_artifact( request, prepared_test_build["build_dir"], "*.mender") subprocess.check_call( "tar xOf %s data/0000.tar.gz | tar xzO > %s" % (latest_mender_image, tmp_artifact.name), shell=True, ) size = os.stat(tmp_artifact.name).st_size hash = hashlib.md5() while True: buf = tmp_artifact.read(bufsize) if len(buf) == 0: break hash.update(buf) artifact_hash = hash.hexdigest() artifact_info = subprocess.check_output( ["ubireader_display_info", tmp_artifact.name]) artifact_ls = subprocess.check_output( ["ls", "-l", tmp_artifact.name]) tmpdir = tempfile.mkdtemp() try: ubifsdir = extract_ubimg_images( latest_build_artifact(request, prepared_test_build["build_dir"], "*.ubimg"), tmpdir, ) rootfsa = os.path.join(ubifsdir, [ img for img in os.listdir(ubifsdir) if "rootfsa" in img ][0]) bytes_read = 0 hash = hashlib.md5() with open(rootfsa, "rb") as fd: while bytes_read < size: buf = fd.read(min(size - bytes_read, bufsize)) if len(buf) == 0: break bytes_read += len(buf) hash.update(buf) image_hash = hash.hexdigest() image_info = subprocess.check_output( ["ubireader_display_info", rootfsa]) image_ls = subprocess.check_output(["ls", "-l", rootfsa]) finally: shutil.rmtree(tmpdir) assert artifact_info == image_info assert artifact_hash == image_hash, "Artifact:\n%s\nImage:\n%s" % ( artifact_ls, image_ls, )
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_state_scripts( self, request, prepared_test_build, bitbake_variables, bitbake_path, latest_rootfs, latest_mender_image, bitbake_image, ): """Test that state scripts that are specified in the build are included correctly.""" # First verify that the base build does *not* contain any state scripts. # Check rootfs. output = subprocess.check_output( ["debugfs", "-R", "ls -p /etc/mender", latest_rootfs]).decode() for line in output.split("\n"): if len(line) == 0: continue entry = line.split("/") if entry[5] == "scripts": # The scripts directory exists. That is fine in itself, but it # should not contain any script files ("version" is allowed). output = subprocess.check_output([ "debugfs", "-R", "ls -p /etc/mender/scripts", latest_rootfs ]).decode() for line in output.split("\n"): if len(line) == 0: continue entry = line.split("/") assert ( entry[5] == "." or entry[5] == ".." or entry[5] == "version" ), "There should be no script file in /etc/mender/scripts" break # Check artifact. output = subprocess.check_output("tar xOf %s header.tar.gz| tar tz" % latest_mender_image, shell=True).decode() for line in output.strip().split("\n"): if line == "scripts": output = subprocess.check_output( "tar xOf %s header.tar.gz| tar tz scripts" % latest_mender_image, shell=True, ).decode() assert len(output.strip()) == 0, ( "Unexpected scripts in base image: %s" % output) try: # Alright, now build a new image containing scripts. build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, ['IMAGE_INSTALL_append = " example-state-scripts"'], ) found_rootfs_scripts = { "version": False, "Idle_Enter_00": False, "Sync_Enter_10": False, "Sync_Leave_90": False, } found_artifact_scripts = { "ArtifactInstall_Enter_00": False, "ArtifactInstall_Leave_99": False, "ArtifactReboot_Leave_50": False, "ArtifactCommit_Enter_50": False, "ArtifactCommit_Leave_50": False, } # Check new rootfs. built_rootfs = latest_build_artifact( request, prepared_test_build["build_dir"], "core-image*.ext[234]") output = subprocess.check_output( ["debugfs", "-R", "ls -p /etc/mender/scripts", built_rootfs]).decode() for line in output.split("\n"): if len(line) == 0: continue entry = line.split("/") if entry[5] == "." or entry[5] == "..": continue assert found_rootfs_scripts.get( entry[5]) is not None, ("Unexpected script in rootfs %s" % entry[5]) found_rootfs_scripts[entry[5]] = True for script in found_rootfs_scripts: assert found_rootfs_scripts[script], ( "%s not found in rootfs script list" % script) # Check new artifact. built_mender_image = latest_build_artifact( request, prepared_test_build["build_dir"], "core-image*.mender") output = subprocess.check_output( "tar xOf %s header.tar.gz| tar tz scripts" % built_mender_image, shell=True, ).decode() for line in output.strip().split("\n"): script = os.path.basename(line) assert found_artifact_scripts.get(script) is not None, ( "Unexpected script in image: %s" % script) found_artifact_scripts[script] = True for script in found_artifact_scripts: assert found_artifact_scripts[script], ( "%s not found in artifact script list" % script) finally: # Clean up the state scripts directory. Ideally this wouldn't be # necessary, but unfortunately bitbake does not clean up deployment # files from recipes that are not included in the current build, so # we have to do it manually. build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, target="-c clean example-state-scripts", )
def test_boot_partition_population(self, request, prepared_test_build, bitbake_path, bitbake_image): # Notice in particular a mix of tabs, newlines and spaces. All there to # check that whitespace it treated correctly. build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, [ """ IMAGE_INSTALL_append = " test-boot-files" IMAGE_BOOT_FILES_append = " deployed-test1 deployed-test-dir2/deployed-test2 \ deployed-test3;renamed-deployed-test3 \ deployed-test-dir4/deployed-test4;renamed-deployed-test4 deployed-test5;renamed-deployed-test-dir5/renamed-deployed-test5 \ deployed-test-dir6/deployed-test6;renamed-deployed-test-dir6/renamed-deployed-test6 \ deployed-test-dir7/* \ deployed-test-dir8/*;./ \ deployed-test-dir9/*;renamed-deployed-test-dir9/ \ " """ ], ) image = latest_build_artifact(request, prepared_test_build["build_dir"], "core-image*.*img") extract_partition(image, 1) try: listing = (run_verbose("mdir -i img1.fs -b -/", capture=True).decode().split()) expected = [ "::/deployed-test1", "::/deployed-test2", "::/renamed-deployed-test3", "::/renamed-deployed-test4", "::/renamed-deployed-test-dir5/renamed-deployed-test5", "::/renamed-deployed-test-dir6/renamed-deployed-test6", "::/deployed-test7", "::/deployed-test8", "::/renamed-deployed-test-dir9/deployed-test9", ] assert all([item in listing for item in expected]) # Conflicting file with the same content should pass. build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, ['IMAGE_BOOT_FILES_append = " conflict-test1"'], ) # Conflicting file with different content should fail. try: build_image( prepared_test_build["build_dir"], prepared_test_build["bitbake_corebase"], bitbake_image, ['IMAGE_BOOT_FILES_append = " conflict-test2"'], ) pytest.fail( "Bitbake succeeded, but should have failed with a file conflict" ) except subprocess.CalledProcessError: pass finally: os.remove("img1.fs")
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