From patchwork Mon Jul 6 22:28:59 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Trevor Woerner X-Patchwork-Id: 91886 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4E0D3C44500 for ; Mon, 6 Jul 2026 22:29:25 +0000 (UTC) Received: from mail-qv1-f43.google.com (mail-qv1-f43.google.com [209.85.219.43]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.161869.1783376960285847474 for ; Mon, 06 Jul 2026 15:29:20 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20251104 header.b=NCjdE4Uc; spf=pass (domain: gmail.com, ip: 209.85.219.43, mailfrom: twoerner@gmail.com) Received: by mail-qv1-f43.google.com with SMTP id 6a1803df08f44-8f256eaedf8so37555756d6.2 for ; Mon, 06 Jul 2026 15:29:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1783376959; x=1783981759; darn=lists.yoctoproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to:content-type; bh=AY1AaOePOsDeEuk4oPElxBGhF9J51T/21Aclc0GdCoY=; b=NCjdE4UcYNBOB3b0G0LhAb59iBDs6VzNgEYDNPJ7MdJRNRHQ2HjtNdrPy+JqXF5vGI tyROPpc1c1o8GyYvgsnihGkoGkBAikmrqdvfNZXskX8FlEP8Qjg+s74dPvxcmvxWERRD 17XQQL9ZXOhhYw37+R094eMzBcGDSfSEn5yAt3cR3wTOo52Xgmp0wvTFx67n/6l3q1rs GOYr8le4H3wk2CV53pxmUiVJ3qsge89ewQFOuWZ9WhK3vwFLhn8CL3m7nwcLRiDdqD3r l9hIXfpzr6cDAYXl/AMzwzQsoimn/3ZwJnOpvAu5O8rwP6RN8PB1Q6iKJ2lWMF0FIBsb +OJg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783376959; x=1783981759; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to:content-type; bh=AY1AaOePOsDeEuk4oPElxBGhF9J51T/21Aclc0GdCoY=; b=TFt/zWaic4/YBAy8rLBvMg+98JVuQyqGBdCqy+dikjh1kZHBGX7f+te1kNWP71m56E XpWbzzqwg2wPNvwZVfreH2DbSRLCeOFigTuXAusrbflUEtepKuBBYFUAh1MT8IBrrhed LXIh28n4KMjm6oWnskBjj/RUnRr+XUNAf4sRX7JdbD0dK4mhJNzy+23DDVkLkU3y1yWd Embj+kk4dfebPORG1npH4xea2r7nuODCYMJ1NUqPyvI5jZALTXJJNJwQXHoM+hagHUGv I+E7YYsv7fBSO5LJu6fc4WVHfNyeQU8gsL05oOsN/575+74WmhYPIEDQWefk98w3j47L fkiA== X-Gm-Message-State: AOJu0YwflTyG5QQGIVsiEQtS74SNyudjCcRREhJ/BtyL4WK8jXNJLDqL Hm92PPbeTmXkFdrNiheEwGREz6UXEcFDOvcN3snWrmw/qhcLiQbmXx2Tng6SH0qM X-Gm-Gg: AfdE7cmFEuygwJpHbk8n1Zy98lfrRt+eIpUOCuadK8kP3GEmM/0RDgdDVwALZqsak88 ris21M26oonSzkIsCyzMr0UWXyuR3tGyr7zrH/x2IAsMS/PKweH7oHxLgtzN8tTzJKC61dZMaQJ tMqzqISy+uNeB8SRPYUaSAqp4QD9uo0NutdPGuXLywqD9Yc9rrkjO/YGMUI8ckjnoxBtU4XpLSo TcRMxZ2p9EvKzDNbdVf3BhnS74GR5T5ORXElYEeN+bbtlC7Py9kwWIgfqI+z63DY56mV3mGoWYk 9EZ/6jK8+MJFu+NLqLH0Y6xQlzcXzysuZldkRNVWSuIPANfQjH2a9yaJvDeRpShCViTJXNMb5Gc 1UfL7akQB/UbtDqvXX0S+thNZ49BnNwrkcVP/s5sNH3Qvo1eMzi5rqR7XT/5lvwzbgGWZGwu/SF FImqoj677gXrw1YH2NngvY7tz8ZJED6hMfyJ4vXSWs/FZJf0weZWxPX3LdD2BWfHpfzw== X-Received: by 2002:ad4:5764:0:b0:8f2:940e:2406 with SMTP id 6a1803df08f44-8fcb1aed76fmr35774026d6.2.1783376958909; Mon, 06 Jul 2026 15:29:18 -0700 (PDT) Received: from localhost.localdomain (pppoe-209-91-167-254.vianet.ca. [209.91.167.254]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-8f472a9d8c0sm143663726d6.49.2026.07.06.15.29.16 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 06 Jul 2026 15:29:18 -0700 (PDT) From: Trevor Woerner To: yocto-patches@lists.yoctoproject.org Subject: [wic][PATCH v4 1/6] tests: add the standalone unit-test suite skeleton Date: Mon, 6 Jul 2026 18:28:59 -0400 Message-ID: <20260706222904.664863-2-twoerner@gmail.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260706222904.664863-1-twoerner@gmail.com> References: <20260706222904.664863-1-twoerner@gmail.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 06 Jul 2026 22:29:25 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/yocto-patches/message/4443 wic has no test mechanism of its own; it relies on the oe-selftest from oe-core, which needs a full bitbake build to exercise even pure-Python logic. This starts a small standalone suite that runs from a plain checkout, with no BitBake and no OpenEmbedded build. This is the skeleton only and adds no tests. It gives pyproject.toml a "tests" extra (pytest and the just command runner) and a pytest config section, adds a justfile with default and tests recipes, creates tests/unit/ with a placeholder .gitkeep, ignores .pytest_cache/, and adds a README Testing section covering install and how to run the suite. AI-Generated: codex/claude-opus 4.8 (xhigh) Signed-off-by: Trevor Woerner --- changes in v4: - drop the tests/docs/ documentation tree; the suite now ships with a short README Testing section only. - add a justfile as the command runner and drop the run-tests.sh wrapper; just joins the tests extra. changes in v3: - no change in this revision. changes in v2: - v1 submitted the entire test suite as a single commit; v2 breaks the work into a reviewable series, and this patch is one step of it. --- .gitignore | 1 + README.md | 15 +++++++++++++++ justfile | 10 ++++++++++ pyproject.toml | 14 ++++++++++++++ tests/unit/.gitkeep | 0 5 files changed, 40 insertions(+) create mode 100644 justfile create mode 100644 tests/unit/.gitkeep diff --git a/.gitignore b/.gitignore index eeb8a6ec4087..a0f016bc5823 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ **/__pycache__ +.pytest_cache/ diff --git a/README.md b/README.md index 75229421763c..c9c38eb5e98a 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,21 @@ environment file or folder (generated via `bitbake -c rootfs_wicenv - `src/bb/*`: various bitbake helpers that were brought along and used in other parts of wic. - `src/oe/*`: various oe-core helpers that were brought along and used in other parts of wic. +## Testing + +wic's test suite lives under `tests/` and runs from a plain checkout +with nothing but `pytest`; it needs no BitBake and no OpenEmbedded +build. Install the test extras and run it: + +``` +pip install -e ".[tests]" +just tests +``` + +The test extras include [just](https://just.systems/), the command +runner used to drive the suite; run `just` on its own to list the +available recipes. + ## Contributing Please send all patches, comments, or questions to the yocto-patches diff --git a/justfile b/justfile new file mode 100644 index 000000000000..41a9d3d236f4 --- /dev/null +++ b/justfile @@ -0,0 +1,10 @@ +# wic test-suite command runner. Run `just` to list recipes. + +# List the available recipes. +default: + @just --list + +# Run the test suite. Extra args pass through to pytest +# (e.g. `just tests -k ` or `just tests tests/unit`). +tests *args: + pytest {{args}} diff --git a/pyproject.toml b/pyproject.toml index fdc1ce0f5ece..e60c4fcc1595 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,6 +21,12 @@ classifiers = [ Homepage = "https://git.yoctoproject.org/wic" Repository = "https://git.yoctoproject.org/wic" +[project.optional-dependencies] +tests = [ + "pytest >= 9.1.1", + "rust-just >= 1.55.1", +] + [project.scripts] wic = "wic.cli:main" @@ -36,3 +42,11 @@ build-backend = "hatchling.build" [tool.hatch.version] path = "src/wic/cli.py" + +[tool.pytest.ini_options] +testpaths = ["tests"] +# Keep a test's scratch directory only when that test fails, and keep +# just the most recent failing session, so repeated runs do not pile up +# leftover directories under the pytest base temp directory. +tmp_path_retention_policy = "failed" +tmp_path_retention_count = 1 diff --git a/tests/unit/.gitkeep b/tests/unit/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 From patchwork Mon Jul 6 22:29:00 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Trevor Woerner X-Patchwork-Id: 91888 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6BDFBC44501 for ; Mon, 6 Jul 2026 22:29:25 +0000 (UTC) Received: from mail-qk1-f181.google.com (mail-qk1-f181.google.com [209.85.222.181]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.162835.1783376961351528012 for ; Mon, 06 Jul 2026 15:29:21 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20251104 header.b=WWzw1cSq; spf=pass (domain: gmail.com, ip: 209.85.222.181, mailfrom: twoerner@gmail.com) Received: by mail-qk1-f181.google.com with SMTP id af79cd13be357-92e67555e24so163686785a.3 for ; Mon, 06 Jul 2026 15:29:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1783376960; x=1783981760; darn=lists.yoctoproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to:content-type; bh=i4niLYMtCI3pGTTrb1BSmuCRjAIRYPUa5GLBitC2wPY=; b=WWzw1cSqpX+eSKPEbz53C6jU12CXXxwCB/eiEK0ItHIHQh27RKkQrxdJGkcrwjdTl7 MVkVGzOrZvJ7Bw/1pSBSmqowgobXon36BJDsXElD910bX0DlNZQQ/TeqQKI4dSMjpqKQ RoxjSEeAbsZd+XM9pDzN3pHUNRgFtvWdr8CSkZR/68n7fJHLZgvEvcEMuabYiDunFu4f S1MmM2qMMO0Jg6S1082NcJl8fhO0AGj8c8exDugP0dFKyx3WHePrfLTOwuzkwoWa2vSy ARLNonXkcPAP0OPOhvDlxE3AX5ZowRGa+fDjMJI97D6XcrmV/2srWy9d9b1/g3BJphki HkSw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783376960; x=1783981760; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to:content-type; bh=i4niLYMtCI3pGTTrb1BSmuCRjAIRYPUa5GLBitC2wPY=; b=TwDCYHhoxC9Q+LLwkOizyP4gAnd5CXTg0Z8L9qAy3OGJM0gzNzm3rrpMNxNEdNOgmP w8zSel7wTesuyRwhhnoGloWCa7aMMnivuoFw8naWDJ+IKeedFPUs0TtYtMLA/cZ+mmQ1 a3cnWVqNjybWHF0mTQvUMmN2MtAVYeUdLN+G5JjJX0REOOMqxn9n+orFT7xr1lID+gnv DSTbawl5YLgJlV8rOEXkr3OX99UB+IqNQ/aCWMhEExMoWzM0rhrP7dv2UuA3Xfy37w4G 1jqN3nDEXO+gwybc9yxUENeRxE8Csu5E4ugPOE1ltMHCk0d8nPM2n3viTJXzuIHitnP3 9+Fw== X-Gm-Message-State: AOJu0Yzd/QiNb7EbfyEqpYOziN+rUiiLFGYJ0Kr3ljDNV1cy1ugxbzQh GlI/ezbnpo+Kj9pLV5LLA76w2p1mPAHr9E68SFQ4hBm9QdN7UKiuVT3+JdEZydcz X-Gm-Gg: AfdE7cmUfMrTH6Od48pNh7vIqSlwFJQY9pqdmTJrJCMdURSAJB2hRb/CBETEpdUdXNA anZZms7RdE4OMg4Zm7EKwhVnIJjdBROvmqVnwSpuHqGNu+OaIUE5ljltGMA5EeZkoly1+k8JVx5 KGxNj+rGl5LQWXqQt7iIwXZN8L+bAAZGVlP8PR2+2XW0UAtFyYSwGcrKWdZDHKe/ewjmCbxPti0 J0UsS4dxDuuXmI3pcJ4qB9La/Fa2pbnpkDJpqDIxGr+zW40zO4R7Uu20xG1bIGtQohRIcCRTd0x 15wtaYDhxXNQd7Cz6Ni6IEC0MaU+/x/t9O3kE1Z+jeYSaf5+qucTlsgvsC2SkiRFsVtqpKu4jex rRx2J5zllffaNlBm5gqTeihI4lpK5Z7Hu6+pTTm+HeJ5q2LOQqZyxCoGJ7yESCilB9S76eOneWD ZQvfkreaJ9HTxxj3YCitUvSZPFET6nYbQofhbD7oWIJX7ep4SFSg9a5DxswAdBNo9ggA== X-Received: by 2002:a05:6214:2521:b0:8ca:10aa:e1f9 with SMTP id 6a1803df08f44-8fcb4903b99mr32972886d6.42.1783376960159; Mon, 06 Jul 2026 15:29:20 -0700 (PDT) Received: from localhost.localdomain (pppoe-209-91-167-254.vianet.ca. [209.91.167.254]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-8f472a9d8c0sm143663726d6.49.2026.07.06.15.29.19 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 06 Jul 2026 15:29:19 -0700 (PDT) From: Trevor Woerner To: yocto-patches@lists.yoctoproject.org Subject: [wic][PATCH v4 2/6] tests: add conftest with a wic-import preflight and session banner Date: Mon, 6 Jul 2026 18:29:00 -0400 Message-ID: <20260706222904.664863-3-twoerner@gmail.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260706222904.664863-1-twoerner@gmail.com> References: <20260706222904.664863-1-twoerner@gmail.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 06 Jul 2026 22:29:25 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/yocto-patches/message/4444 tests/conftest.py prepares the suite and describes the run. It adds the in-tree src/ to sys.path so the tests import the wic in the checkout without an install, then imports wic once up front: if that fails, the session stops immediately with pytest.exit() and the reason, rather than letting every test error out one by one against a missing or wrong wic. A pytest_report_header hook prints a short banner naming the host, the Python and pytest versions, and the wic under test with its version and imported path, so a run can be attributed when more than one checkout or virtualenv is in play. AI-Generated: codex/claude-opus 4.8 (xhigh) Signed-off-by: Trevor Woerner --- changes in v4: - move the wic-import check here from the run-tests.sh wrapper, so it runs on every invocation regardless of how pytest is launched; on failure the session stops with pytest.exit(). changes in v3: - no change in this revision. changes in v2: - v1 submitted the entire test suite as a single commit; v2 breaks the work into a reviewable series, and this patch is one step of it. --- tests/conftest.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/conftest.py diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 000000000000..13b8953cec40 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,28 @@ +# Session setup and banner for the wic test suite. + +import platform +import sys +from pathlib import Path + +import pytest + +_SRC = Path(__file__).resolve().parent.parent / "src" +if str(_SRC) not in sys.path: + sys.path.insert(0, str(_SRC)) + +try: + import wic.cli as _wic_cli +except Exception as exc: + pytest.exit("cannot import wic from %s: %s" % (_SRC, exc), returncode=1) + + +def pytest_report_header(config): + return "\n".join([ + "wic test suite", + " host: %s %s %s" % ( + platform.node(), platform.system(), platform.machine()), + " python: %s pytest: %s" % ( + platform.python_version(), pytest.__version__), + " wic: %s (%s)" % ( + getattr(_wic_cli, "__version__", "(unknown)"), _wic_cli.__file__), + ]) From patchwork Mon Jul 6 22:29:01 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Trevor Woerner X-Patchwork-Id: 91887 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 04F75C43602 for ; Mon, 6 Jul 2026 22:29:26 +0000 (UTC) Received: from mail-qk1-f172.google.com (mail-qk1-f172.google.com [209.85.222.172]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.162836.1783376964120369947 for ; Mon, 06 Jul 2026 15:29:24 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20251104 header.b=hYQuyXtc; spf=pass (domain: gmail.com, ip: 209.85.222.172, mailfrom: twoerner@gmail.com) Received: by mail-qk1-f172.google.com with SMTP id af79cd13be357-92e57a753f9so257674785a.2 for ; Mon, 06 Jul 2026 15:29:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1783376963; x=1783981763; darn=lists.yoctoproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=rJj9x+KFWryKNgy0kpcNQKsjI8ajviFt4P6n+ALge6M=; b=hYQuyXtchFkjjw2tyvJnDv1Lno4kXHXVVg++NQLa4gXWjICGAcSLVklu1pGECo3Jfi eIbDebDkp0S6qUAK0/H96hYVD7oO0NjZ+xxCVLhnuCQKmCs3s2JHGLj9UvPAGrkjj4sN SN9FX7bwem5XwJxpLqoq5hvrkABTCResIj5goG9dpcxE6cQkUx62AdC65niDf44BzVRH kG37ocWchJrghGrGl7lUWiQgoJFhtME2GXMKm4xIUjlhMfbCz7qVzbU1dnXe9gM/aYlp DpqlD6YtCzPG3rLWWGWMaTghc4JEKO62ico7HcfvYlUKLDo2Qp9TElSCA0kqOscOMf0s yZlw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783376963; x=1783981763; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=rJj9x+KFWryKNgy0kpcNQKsjI8ajviFt4P6n+ALge6M=; b=Xndax3GUV3FjVIMVYQpakPx6LLSzSrDEWdDQWgoh41y0nE4C2ceAWaRrwJwgX1hN4r yPj7QQZd459mSQTvPSmXSlM3Ll6Bdpd16KDtvwDo3i2kMKwBjOxCpRRBIrNr4sW6dymn fMUSV58Ie0t1x8LMa51jDR0C9qOYeL/hd6rwO+o51tCAEL6/zTIEeWgQjdo8pGn8Jm/Y D9S/IDSDng0jAkC7VPG+KYD9bfsMZlLovMzbN5+E/1VxKKxVoMcTAfJ8r5o7r5kvvrEZ CnP1Pdt7l89AEgxLteREtj9P9mLjfidski6OMNgO9HozxBoFnLYJrebBhdr7rALNlCYo YCmQ== X-Gm-Message-State: AOJu0YxRp9LSnMSLYzPuJ6IwNrJjZaWaSk0gwLv/ExFvEB4FVbhHq1WF m36WcFGAGAHRGm5DDdkwDf/LDlVvA2kqbzy+s0LyDltUqu976hI0H8M9B09k3kvr X-Gm-Gg: AfdE7cktROCnftLXwTVVkpB80zD/1Y1rr63yyP66cBUmLHtoCrw5KDoNUMyQ1CvU/sU HAOOtmOLgVZthC9UbestY8OVRk4FAX1tUawUnDuE+RdTct+jzD1GnArA4J/zycAYYKha7Uu4rDt gbGDaDysd42VDquEi02BBBT9aH6hg1uRMPvgcPEETZzXlFE8TfSyjVN5qNWTvAQ/qwVDJf+hOlv LpGjxsMCMNaO4asejOUbwh6Oyo1DY4y/bhKVN5GR8aSjkCdjCX0C56HmRvLTbF48HOgChEM6Ps4 B1lG+2NtZSMs6yx/EFe56yFZ4r7wEWxaq2j6c2qv9JXsRhd7k93x553tzWh4MuMC78t7WqPUs7r RD6lq0E/C1+oYPk+4/x8A25PQl9sAFsLHa0VtsFJgh/mdmtejCNVp3avaX0rRRxKHBPdabk3Hsf y71Lwks0E0Sctme+N2yknbMCTCfM8Q4MaWNM28oSIWDQnaxLPg7DktnAmhbn6hi8/vVg== X-Received: by 2002:a05:620a:6607:b0:92e:70a4:2c5b with SMTP id af79cd13be357-92ebb5c420cmr356630985a.69.1783376962986; Mon, 06 Jul 2026 15:29:22 -0700 (PDT) Received: from localhost.localdomain (pppoe-209-91-167-254.vianet.ca. [209.91.167.254]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-8f472a9d8c0sm143663726d6.49.2026.07.06.15.29.20 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 06 Jul 2026 15:29:21 -0700 (PDT) From: Trevor Woerner To: yocto-patches@lists.yoctoproject.org Subject: [wic][PATCH v4 3/6] tests: add optional coverage reporting Date: Mon, 6 Jul 2026 18:29:01 -0400 Message-ID: <20260706222904.664863-4-twoerner@gmail.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260706222904.664863-1-twoerner@gmail.com> References: <20260706222904.664863-1-twoerner@gmail.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 06 Jul 2026 22:29:26 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/yocto-patches/message/4445 Add branch coverage of the wic source as opt-in just recipes, so a plain run stays fast and quiet. coverage and pytest-cov join the tests extra; the coverage recipe prints a terminal report of the lines that were missed, and coverage-html additionally writes a browsable report to htmlcov/. .gitignore ignores the .coverage data file and htmlcov/. AI-Generated: codex/claude-opus 4.8 (xhigh) Signed-off-by: Trevor Woerner --- changes in v4: - expose coverage through just recipes (coverage, coverage-html) rather than run-tests.sh flags. changes in v3: - no change in this revision. changes in v2: - v1 submitted the entire test suite as a single commit; v2 breaks the work into a reviewable series, and this patch is one step of it. --- .gitignore | 2 ++ justfile | 8 ++++++++ pyproject.toml | 2 ++ 3 files changed, 12 insertions(+) diff --git a/.gitignore b/.gitignore index a0f016bc5823..e30cafa40f7f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ **/__pycache__ .pytest_cache/ +.coverage +htmlcov/ diff --git a/justfile b/justfile index 41a9d3d236f4..1be3e01e7c7d 100644 --- a/justfile +++ b/justfile @@ -8,3 +8,11 @@ default: # (e.g. `just tests -k ` or `just tests tests/unit`). tests *args: pytest {{args}} + +# Run the suite with a terminal branch-coverage report for wic. +coverage *args: + pytest {{args}} --cov=wic --cov-branch --cov-report=term-missing + +# Run the suite with an HTML coverage report (written to htmlcov/). +coverage-html *args: + pytest {{args}} --cov=wic --cov-branch --cov-report=term-missing --cov-report=html diff --git a/pyproject.toml b/pyproject.toml index e60c4fcc1595..2ad694b13358 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,8 @@ Repository = "https://git.yoctoproject.org/wic" [project.optional-dependencies] tests = [ "pytest >= 9.1.1", + "coverage >= 7.15.0", + "pytest-cov >= 7.1.0", "rust-just >= 1.55.1", ] From patchwork Mon Jul 6 22:29:02 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Trevor Woerner X-Patchwork-Id: 91890 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 75D17C43458 for ; Mon, 6 Jul 2026 22:29:35 +0000 (UTC) Received: from mail-qk1-f174.google.com (mail-qk1-f174.google.com [209.85.222.174]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.161871.1783376965541335556 for ; Mon, 06 Jul 2026 15:29:25 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20251104 header.b=sIQPPNl8; spf=pass (domain: gmail.com, ip: 209.85.222.174, mailfrom: twoerner@gmail.com) Received: by mail-qk1-f174.google.com with SMTP id af79cd13be357-92e7632b193so223408785a.2 for ; Mon, 06 Jul 2026 15:29:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1783376964; x=1783981764; darn=lists.yoctoproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to:content-type; bh=g8XYBvdHt4KI6c7j0GOgzFRHyu6nVjuGW5Ayik6PBuI=; b=sIQPPNl8akzQDf627G+e3083dJiHdCV+WnAHUiGOBfiZSdLmyYyoQ7lIFvzogFl4dg TYd0fuzEmAjm3ZcmdIIs0c59bDdjvfbXFjNidEZGW9pFAsHuLxIZkYw8iaUXchl/xLcD cuaACb0DsfC5yUCuDZoWxS0eALleW1PEqR+TOieSan5bvmXRkdCQR549B5Xtwva/sbc6 VHSdIIvdfqE4Bh4zCqXL/Iu5CMUMWdGi0pUUwM/hJqfNW9x4Uo3GqhXvLoaQB91vQb2N fW/y1+gW81vz4AvdE5fBHmLyx3JK8SsUJWmUh3eEluplc1RvX/+eFfN7Ve2ZgNSuWTeo SbXg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783376964; x=1783981764; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to:content-type; bh=g8XYBvdHt4KI6c7j0GOgzFRHyu6nVjuGW5Ayik6PBuI=; b=GhW5iC9NuNd2S+EqtS7TeXucNwH97sC2v2BBktTKzYf9yfZsKDukLFNbUwCT7N5bmg iDRGfmicx6zuMKWTp4FWddE+38XfV5QSo1xxOta6dcCQdn/tImzuG1MYrD3rLv0cHOY/ o3tyUnQNkiR5rMs8a5dEFKcNgRDDouzzpwpv7K9n73pjyRNrk/pGKkfVFQSyZ5sticgo PNCLZfbALIxZpv3CGzZ/xzN8YwaxESoGuCZTJid8G+0/ZvAAIk3D/mBgVodg6L20+alj HVrxK3V0qcIrVVX+p1LfA7HMBH4zvrE32vaVSQYX3/di5avQzQ6WwYHFYnOkrAbP6T7u 07hg== X-Gm-Message-State: AOJu0Yzxx+QtumkG1/sShYaH2lzskfoP0zk7GFgr/aaBguA3VS25h1w6 dwTedswYNTFkI1lIEX6WlwF0RDzSVqeCzOXOx51BavMewGhEUeYrU5SzsoEnEGng X-Gm-Gg: AfdE7cm5Ik3wpKJaT0LjEwPksk/cUbCmcCdosfEeMvjCVsWJ22iTNtwMie2ZLWJOrBD nk266U8eHbm/bkufiaSxNKu2IZC06bHDHijnoJMfJ5JCFiqpTIKTHBmBnmrFiT9GqREZyZgio+W 6qSluau9ewF1FPwdKcmdgNQDwpqbaxokGTQcjWa/mnD3h5zOSR4tzFxISn1QHEpNp8tGd7WZzKy y2H8pqvHHcFqc5JmijLQLLVFJA+nzZBI9aRR7DWo1F2YqlhGLp9ijuazrvykIXkh7vXzTVnKpqv V+wE2kDq8C0dXVWU7i6Sy6dF+UuwCM5hSaKsAPI1FTjoyha6W+wvZKYf5bbq1buVCCP7b9eB6Y1 fqu0X/9fI2wYwVHxVGBlpi4RII3FnvkzmmVHd3d3M3t7npRdDygcqXBGWjB0D0Ce1228DrqKiMV ZUoi1Y3uyb/gIvb93EhHUs2P1iCyBQc0X+KRFG1PrDYc+PpdtGNmMhQbA= X-Received: by 2002:a05:6214:e6b:b0:8ef:60f2:5b52 with SMTP id 6a1803df08f44-8fcb3f3377fmr31262486d6.37.1783376964193; Mon, 06 Jul 2026 15:29:24 -0700 (PDT) Received: from localhost.localdomain (pppoe-209-91-167-254.vianet.ca. [209.91.167.254]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-8f472a9d8c0sm143663726d6.49.2026.07.06.15.29.23 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 06 Jul 2026 15:29:23 -0700 (PDT) From: Trevor Woerner To: yocto-patches@lists.yoctoproject.org Subject: [wic][PATCH v4 4/6] add ruff linting Date: Mon, 6 Jul 2026 18:29:02 -0400 Message-ID: <20260706222904.664863-5-twoerner@gmail.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260706222904.664863-1-twoerner@gmail.com> References: <20260706222904.664863-1-twoerner@gmail.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 06 Jul 2026 22:29:35 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/yocto-patches/message/4446 Lint with ruff via just recipes. lint-tests runs ruff over tests/ and is held to a clean bar; lint also runs it over src/, whose findings are a preview since the wic source is not yet ruff-clean. ruff joins the tests extra and .gitignore ignores its .ruff_cache/. ruff is pinned exactly so the gate is reproducible: a ruff minor release can add rules that turn a previously clean tree red, so every machine must lint with the same version. Test modules relax E402 via per-file-ignores: they prepend src/ to sys.path before importing wic, which trips the rule, and that ordering is deliberate. AI-Generated: codex/claude-opus 4.8 (xhigh) Signed-off-by: Trevor Woerner --- changes in v4: - expose linting through just recipes (lint-tests, lint) rather than run-tests.sh flags. - pin ruff exactly (was a stale >= floor) so the clean-bar gate is reproducible across machines. - fold in the tests/** E402 ignore (its own patch in v2 and v3) and drop the linting.md doc; the pyproject.toml comment explains it. changes in v3: - no change in this revision. changes in v2: - v1 submitted the entire test suite as a single commit; v2 breaks the work into a reviewable series, and this patch is one step of it. --- .gitignore | 1 + justfile | 9 +++++++++ pyproject.toml | 8 ++++++++ 3 files changed, 18 insertions(+) diff --git a/.gitignore b/.gitignore index e30cafa40f7f..f2fd2f56b6d7 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .pytest_cache/ .coverage htmlcov/ +.ruff_cache/ diff --git a/justfile b/justfile index 1be3e01e7c7d..5ccd8144181d 100644 --- a/justfile +++ b/justfile @@ -16,3 +16,12 @@ coverage *args: # Run the suite with an HTML coverage report (written to htmlcov/). coverage-html *args: pytest {{args}} --cov=wic --cov-branch --cov-report=term-missing --cov-report=html + +# Lint the test suite; it is held to a clean bar, so this must be clean. +lint-tests: + ruff check tests + +# Lint the test suite and then the wic source. src/ is not yet +# ruff-clean, so its findings are a preview, not a gate. +lint: lint-tests + ruff check src diff --git a/pyproject.toml b/pyproject.toml index 2ad694b13358..569944ff468c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ tests = [ "pytest >= 9.1.1", "coverage >= 7.15.0", "pytest-cov >= 7.1.0", + "ruff == 0.15.20", "rust-just >= 1.55.1", ] @@ -52,3 +53,10 @@ testpaths = ["tests"] # leftover directories under the pytest base temp directory. tmp_path_retention_policy = "failed" tmp_path_retention_count = 1 + +[tool.ruff.lint.per-file-ignores] +# Test modules prepend the in-tree src/ directory to sys.path before +# importing wic, so the suite runs against a checkout that has not been +# installed. That bootstrap runs before the wic imports, which trips +# E402; the ordering is deliberate, so ignore E402 for the test tree. +"tests/**" = ["E402"] From patchwork Mon Jul 6 22:29:03 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Trevor Woerner X-Patchwork-Id: 91889 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8385BC44500 for ; Mon, 6 Jul 2026 22:29:35 +0000 (UTC) Received: from mail-qv1-f41.google.com (mail-qv1-f41.google.com [209.85.219.41]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.161872.1783376967169044579 for ; Mon, 06 Jul 2026 15:29:27 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20251104 header.b=UOve2KLC; spf=pass (domain: gmail.com, ip: 209.85.219.41, mailfrom: twoerner@gmail.com) Received: by mail-qv1-f41.google.com with SMTP id 6a1803df08f44-8f256eaedf8so37556396d6.2 for ; Mon, 06 Jul 2026 15:29:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1783376966; x=1783981766; darn=lists.yoctoproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to:content-type; bh=o/TyJz94mX2i1QV8NCVxcG4VNAPy5W9Tg1kMNh3vuSk=; b=UOve2KLCfaXk5Np2DIyDhmCaaBkNej7h4qkJnVndHYGINZc9/Qkce2BTihvXjyK6yZ OcbKJF9JgFAlo7+2o32aRys+aiz9CFjjoFBTYyKAiSGeel/BIvXflWHFFftPtXfy85CJ sV5MSo/nkkCHdjAEyAYCKA5UF8j1S1sIu4A/H1AqgcSAGmb3fZYPOe084QdLo63THi5O lA+t/gHxqQT0gxt0NZ70E8gFyQ3EE9SeR1D6ElmK0jNK1akOtlCvkIBuIhzsoTdg+OC1 f1SgoQZ+ox/VnDC2JUldHKXNUPZD/31V5qfV+DYr9iEgraLwUB2yW6LFiSpU3oOLHE4F O1TA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783376966; x=1783981766; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to:content-type; bh=o/TyJz94mX2i1QV8NCVxcG4VNAPy5W9Tg1kMNh3vuSk=; b=nfF650wB3JSBhRJkPN+Xr/yDv/nZbjtjz376VWCD5+/bdaYmWhw5zt+L7iST+ULvKo MQBvrUKCEae/uRmgtFsXZdzVrVOglYvumJkcelWHQcQZoq0e2cUNidGhutQaO8RUiqB+ cXUq9yPrStPPolqKBeVIlvrLfVwv/xbcWJQyZi3kUYj7rmz9V8oG5RaMiN/1J+vQvsUc ECHldfP+7IuXsvb5lv7nFODTzFKAaww+vVAnrqd+R3JUnDfd1+j9z+A9uuQBf3Wejdc3 HflBz0tJIrXsD/4YQkUFYPzqxd+IBtlwBJ7e3zNYvmrW+JzbdV+z3eGI12ARPJIZSQse fg2A== X-Gm-Message-State: AOJu0YzTIWUWyNcRglV8xalvBMKtIaTVpWlMmVSOlpbJG3b9Yr2nn6H3 qOjo327o+/k/L7muIhgWqig7TXcHiLNXQ+RpyS5X7tLh8qzP7t2u/6HtsUkJPK5f X-Gm-Gg: AfdE7cnEsaQzcsDaZLtpR0kcjbapewUXvTjqj9D6PTChiUfpXoCXFjPigSvoQKowHgM lU8C20+6W598H8Z4kxYH55GbMyj8XoPxMpLwlvsO5AYf8VqL2+reCrhpUbdoxl/M3FLkv9rOfNq Q1esdXh4JeaO656oMAKsT+zr3L13yesUMg1UGoaZZ+YW6uyO7RFY5H38p/D54Yfebevg6q9kIyj kd0e2BHU3h5ZCXej23D7LWlUgpYpgp7/FoPhPanjGURCoq6oWRXU0umVfySvHdzbDLPYL1xYZBe vu9TeFHi6Jz8zSXMGWVfF3i4tbya7snrNqe2uH14qK+Xd0V4lTTLeefvgfEEPjDBeRtbzn2CK1Y nTdz30ZQgANjtti4zhUmz/4QfJ3QfvBb47e/vEEUQUIaC5ohYqlZZeVI6GHKaDJOIw6g8SVjXKe xWi3PYTdoSlTNeLrFrTj5+J8ODcqSGfW8ZsgD+4scDAfioTUj7BF4Y7/w= X-Received: by 2002:a05:6214:2e4a:b0:8f4:821d:95f7 with SMTP id 6a1803df08f44-8fcb25a90bemr36342116d6.18.1783376965969; Mon, 06 Jul 2026 15:29:25 -0700 (PDT) Received: from localhost.localdomain (pppoe-209-91-167-254.vianet.ca. [209.91.167.254]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-8f472a9d8c0sm143663726d6.49.2026.07.06.15.29.24 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 06 Jul 2026 15:29:24 -0700 (PDT) From: Trevor Woerner To: yocto-patches@lists.yoctoproject.org Subject: [wic][PATCH v4 5/6] bb/utils: import errno so mkdirhier's OSError handler works Date: Mon, 6 Jul 2026 18:29:03 -0400 Message-ID: <20260706222904.664863-6-twoerner@gmail.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260706222904.664863-1-twoerner@gmail.com> References: <20260706222904.664863-1-twoerner@gmail.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 06 Jul 2026 22:29:35 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/yocto-patches/message/4447 mkdirhier() calls os.makedirs(directory, exist_ok=True) and, if that still raises OSError, re-checks the error before deciding what to do: except OSError as e: if e.errno != errno.EEXIST or not os.path.isdir(directory): raise e but the module never imports errno. The reference to errno.EEXIST is only evaluated when os.makedirs() actually raises, so the defect stays hidden on every ordinary call. The moment a real OSError occurs -- a parent component that is a file, a permission error, anything -- the handler itself raises NameError: name 'errno' is not defined, masking the original error with a misleading one. Import errno so the handler behaves as intended: it re-raises every real error, while tolerating only an EEXIST whose path is in fact already a directory. AI-Generated: codex/claude-opus 4.8 (xhigh) Signed-off-by: Trevor Woerner --- changes in v4: - new commit: the errno import fix now lands on its own, before the test that exercises it. In v2 and v3 it was folded into the test_bb_utils commit. --- src/wic/bb/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wic/bb/utils.py b/src/wic/bb/utils.py index 3750056ba563..0b40dd0c1d59 100644 --- a/src/wic/bb/utils.py +++ b/src/wic/bb/utils.py @@ -1,6 +1,7 @@ """ Minimal subset of BitBake's bb.utils used by standalone wic. """ +import errno import os # from bitbake/lib/bb/utils.py From patchwork Mon Jul 6 22:29:04 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Trevor Woerner X-Patchwork-Id: 91891 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8F504C43602 for ; Mon, 6 Jul 2026 22:29:35 +0000 (UTC) Received: from mail-qv1-f53.google.com (mail-qv1-f53.google.com [209.85.219.53]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.161873.1783376968676302139 for ; Mon, 06 Jul 2026 15:29:28 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20251104 header.b=lWkvAaBV; spf=pass (domain: gmail.com, ip: 209.85.219.53, mailfrom: twoerner@gmail.com) Received: by mail-qv1-f53.google.com with SMTP id 6a1803df08f44-8eabb1a9378so26604256d6.1 for ; Mon, 06 Jul 2026 15:29:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1783376968; x=1783981768; darn=lists.yoctoproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=uCG4cABeR4m1pYuK4vhoMKS1R1BUSQwaRNXndkspQRg=; b=lWkvAaBVmVR3tkh8z5xujAapRIT5IGMpQLOKrnyoSm8C+vFdIag7dVB+Pcc0z1D3Js ULGh8rcfCVYsIkeXPLKJKQgPAs47GuwfwAbxG7knjsQYws2k5S8nAHh8Uc0UZedbdzks BTyJ2DBlKdqYI/hO3B5xTXxiSb8EeqfXMOfrOafEmyHoIgRoo6W6FyPIJe+KrrblYVy9 dVDQVJ+O9FCHIbxEkyKSmSZmvuTEOnh287gU1mQRMR9vpyEHW5q0mV24IEkzLJf+5PNH AbBxrgSIKkHSuRoDIUvKfJUjB/nS9W4j2tINNGoQ10OyEvMLTwi/LASsOubnJQTkPOxY +m4g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783376968; x=1783981768; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=uCG4cABeR4m1pYuK4vhoMKS1R1BUSQwaRNXndkspQRg=; b=RNgEvEILeQr4Fbur6gWnFHs3yxyGJkyf0moPji/WpORbBwfIiW8qM7OrVS6B4sMQJu HVzLLDj+zzvCpCIODPYrFbsux7l6Xkv8Y27M7OGyhuhZ7NhDtt34JNVv7BnE/yjqg+Zg 0WXdI0n1XaPZsMneZj/q1aQOkglPHYlMF0SBfzGoLIfsb2oFBGrNeKZJLx037UUy4lLC XllAF8lnRs5cysHN+R/FS3gFf9F79+NbRq7sktNgtz4Lzmd7/8HGTYATqzXKP+pv68D/ IOKAuBGaycXz5D0EPnuVGu1tKJmqJ+5vc7r6r0EwhG7mK25VA59w62YbGxFKVlMyuXQ6 nNAg== X-Gm-Message-State: AOJu0Yzh0TZnWly7rEKRYIFJypRtlDwkWor5nUehyR8D61hEPgHRnjlH iD/A5NLl+aaPmBLLC/k7jxZFBxcsdU99J/ZG2VR816q3pcOr0U4R5U/u6bf2Dhsr X-Gm-Gg: AfdE7cnjb31Npe2U4imtQuZ2wpbjL4fXqrFr60tpelUI/EqpgNlBJ80tFTVMCpPVR28 YGvGeLSq+bJCU7YD5G2mY6kUoM9pwZUC8QMWffWvf5f47pNJq1b2LtFZQeTyj4DZa4LC6juYvYk UkxlSrQg3MzQ8O5AVdKYTz2PcPSvygICxh/Oo5li6zdui/8YTeo5BWc8sX6afZ9H7nQwOOFboz2 bW/Ib2RNPNeY3glsvkLueG+QKd7MiCnrMeZRH7oTuo+SRVDqzOb7Tk4HVhijxZ47WcF3DdPPTWg +a7KOr53jJZ+F8Kg0NicRbKhyu3WJIzel9FKU7GpbbNnfE9OrCco1d3aBA/FopTn+X4HclqvLOW 6ss8BoxLXs0aMebZNvgI2owa+/e3lSAt/0FoTwdJyrpETOEuFEC9dA2xuTzJ7RTKMiuP50I+0w6 zF+3c/7zJ782G7098uIkQYV+sPLhN3MXZ2t2rbMVxryrj25gkYsH75Ces= X-Received: by 2002:a05:6214:3285:b0:8dd:f14c:1dc with SMTP id 6a1803df08f44-8fcb26a6000mr32273526d6.1.1783376967281; Mon, 06 Jul 2026 15:29:27 -0700 (PDT) Received: from localhost.localdomain (pppoe-209-91-167-254.vianet.ca. [209.91.167.254]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-8f472a9d8c0sm143663726d6.49.2026.07.06.15.29.26 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 06 Jul 2026 15:29:26 -0700 (PDT) From: Trevor Woerner To: yocto-patches@lists.yoctoproject.org Subject: [wic][PATCH v4 6/6] tests/unit/test_bb_utils: cover mkdirhier() Date: Mon, 6 Jul 2026 18:29:04 -0400 Message-ID: <20260706222904.664863-7-twoerner@gmail.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260706222904.664863-1-twoerner@gmail.com> References: <20260706222904.664863-1-twoerner@gmail.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 06 Jul 2026 22:29:35 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/yocto-patches/message/4448 Add unit tests for mkdirhier(), the one function in wic.bb.utils. They pin the behaviour wic relies on so it cannot regress: it creates missing directories, accepts a directory that already exists, rejects a path containing an unexpanded bitbake variable (${...}), and allows a name with a lone brace or a lone dollar, neither of which is the ${ marker. Three tests cover the OSError handler that the errno import repairs: a path whose parent component is a regular file, a target that already exists as a file rather than a directory, and a directory that appears concurrently mid-call (a create race), which must be treated as success. Run against a wic.bb.utils that does not import errno, all three fail with NameError instead, so they catch that bug directly. The tests replace the tests/unit/.gitkeep placeholder. AI-Generated: codex/claude-opus 4.8 (xhigh) Signed-off-by: Trevor Woerner --- changes in v4: - reframe the tests to target mkdirhier's own behaviour: drop the cases that only re-exercised os.makedirs and the assertions that pinned implementation details. - the errno fix moved to its own preceding commit; this is tests only. changes in v3: - switch the tests from tempfile.mkdtemp() to pytest's tmp_path fixture so each test's scratch directory is cleaned up instead of leaking under /tmp; no change to what is tested. changes in v2: - v1 recorded this bug with an xfail marker in one large commit; v2 drops the xfail, asserts the correct behaviour directly, and lands the one-line errno-import fix in this same commit so the test passes green. --- tests/unit/.gitkeep | 0 tests/unit/test_bb_utils.py | 81 +++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) delete mode 100644 tests/unit/.gitkeep create mode 100644 tests/unit/test_bb_utils.py diff --git a/tests/unit/.gitkeep b/tests/unit/.gitkeep deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/unit/test_bb_utils.py b/tests/unit/test_bb_utils.py new file mode 100644 index 000000000000..0300b8d4a1a0 --- /dev/null +++ b/tests/unit/test_bb_utils.py @@ -0,0 +1,81 @@ +""" +Unit tests for wic.bb.utils.mkdirhier: a mkdir -p wrapper that rejects +unexpanded bitbake variables and, on error, tolerates an already-existing +directory while re-raising every real failure. +""" +import sys +from pathlib import Path + +import pytest + +_SRC = Path(__file__).resolve().parent.parent.parent / "src" +if str(_SRC) not in sys.path: + sys.path.insert(0, str(_SRC)) + +from wic.bb.utils import mkdirhier + + +class TestMkdirhier: + def test_creates_missing_directories(self, tmp_path): + target = tmp_path / "a" / "b" / "c" + mkdirhier(str(target)) + assert target.is_dir() + + def test_existing_directory_is_accepted(self, tmp_path): + # Calling it on a directory that already exists is not an error. + mkdirhier(str(tmp_path)) + mkdirhier(str(tmp_path)) + assert tmp_path.is_dir() + + def test_unexpanded_bitbake_variable_is_rejected(self, tmp_path): + target = tmp_path / "${WORKDIR}" / "sub" + with pytest.raises(Exception, match="unexpanded bitbake variable"): + mkdirhier(str(target)) + assert not (tmp_path / "${WORKDIR}").exists() + + def test_plain_brace_is_not_treated_as_a_variable(self, tmp_path): + # Only the '${' marker trips the guard; a bare brace is a legal + # (if unusual) directory name. + target = tmp_path / "plain{brace" + mkdirhier(str(target)) + assert target.is_dir() + + def test_dollar_without_brace_is_allowed(self, tmp_path): + # The guard keys on the literal '${' marker; a '$' on its own is + # not an unexpanded variable and is a legal directory name. + target = tmp_path / "price$5" + mkdirhier(str(target)) + assert target.is_dir() + + def test_path_under_a_file_raises(self, tmp_path): + # A parent component that is a regular file makes the underlying + # mkdir fail; the error must surface rather than be swallowed. + afile = tmp_path / "afile" + afile.write_text("x") + with pytest.raises(OSError): + mkdirhier(str(afile / "sub")) + + def test_existing_file_at_target_raises(self, tmp_path): + # The target already exists but is a file, not a directory: the + # error must propagate rather than be tolerated. + afile = tmp_path / "afile" + afile.write_text("x") + with pytest.raises(OSError): + mkdirhier(str(afile)) + + def test_concurrent_creation_is_treated_as_success(self, tmp_path, monkeypatch): + # If the directory appears while mkdirhier runs (a create race + # with another process), that is success, not an error. + import errno + + import wic.bb.utils as bb_utils + + target = tmp_path / "made-concurrently" + + def racing_makedirs(path, exist_ok=False): + target.mkdir() # someone else wins the race + raise OSError(errno.EEXIST, "File exists", str(path)) + + monkeypatch.setattr(bb_utils.os, "makedirs", racing_makedirs) + mkdirhier(str(target)) # must not raise + assert target.is_dir()