Linux maintainer tooling and workflows
 help / color / mirror / Atom feed
From: Brian Masney <masneyb@kernel.org>
To: "Kernel.org Tools" <tools@kernel.org>
Cc: Konstantin Ryabitsev <konstantin@linuxfoundation.org>,
	 Jerome Brunet <jbrunet@baylibre.com>,
	 Dmitry Torokhov <dmitry.torokhov@gmail.com>,
	 Brian Masney <masneyb@kernel.org>
Subject: [PATCH b4 v2 3/3] review: tests: add tests for the patchwork key
Date: Fri, 30 Oct 2026 09:47:30 -0400	[thread overview]
Message-ID: <20261030-pw-key-command-v2-3-95fb0f822834@kernel.org> (raw)
In-Reply-To: <20261030-pw-key-command-v2-0-95fb0f822834@kernel.org>

Add tests for the various ways that the patchwork key can be provided.

Assisted-by: LLM
Signed-off-by: Brian Masney <masneyb@kernel.org>
---
 src/tests/test___init__.py | 114 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 114 insertions(+)

diff --git a/src/tests/test___init__.py b/src/tests/test___init__.py
index 764829d7e756..5d5c9dd3836b 100644
--- a/src/tests/test___init__.py
+++ b/src/tests/test___init__.py
@@ -2924,3 +2924,117 @@ class TestGetAmMessageFromLines:
         lines = payload.decode().splitlines()
         assert 'From the manual, bar() must be called here.' in lines
         assert '>From an old thread.' in lines
+
+
+class TestGetPwKey:
+    """b4.pw-user fetches the Patchwork key from git credential helpers."""
+
+    @pytest.fixture(autouse=True)
+    def _clear_cache(self, monkeypatch: pytest.MonkeyPatch) -> None:
+        monkeypatch.setattr(b4, '_PW_KEY_CACHE', {})
+        # Never fall back to prompting on the terminal
+        monkeypatch.setenv('GIT_TERMINAL_PROMPT', '0')
+        monkeypatch.delenv('GIT_ASKPASS', raising=False)
+        monkeypatch.delenv('SSH_ASKPASS', raising=False)
+
+    @staticmethod
+    def _set_helper(
+        monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path, body: str
+    ) -> pathlib.Path:
+        """Replace all credential helpers with a script that runs body."""
+        helper = tmp_path / 'helper.sh'
+        helper.write_text(f'#!/bin/sh\necho "$@" >> {tmp_path}/calls\n{body}\n')
+        helper.chmod(0o755)
+        count = int(os.environ.get('GIT_CONFIG_COUNT', '0'))
+        # An empty value resets any helpers from the user's own config
+        for i, val in enumerate(('', f'!{helper}')):
+            monkeypatch.setenv(f'GIT_CONFIG_KEY_{count + i}', 'credential.helper')
+            monkeypatch.setenv(f'GIT_CONFIG_VALUE_{count + i}', val)
+        monkeypatch.setenv('GIT_CONFIG_COUNT', str(count + 2))
+        return tmp_path / 'calls'
+
+    def test_plain_key(self) -> None:
+        assert b4.get_pw_key({'pw-key': 'secret'}) == 'secret'
+
+    def test_unset(self) -> None:
+        assert b4.get_pw_key({}) == ''
+
+    def test_no_user(
+        self, monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path
+    ) -> None:
+        """Without pw-user, credential helpers are never asked."""
+        calls = self._set_helper(monkeypatch, tmp_path, 'echo password=nope')
+        assert b4.get_pw_key({'pw-url': 'https://pw.example.org/'}) == ''
+        assert not calls.exists()
+
+    def test_key_wins(
+        self, monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path
+    ) -> None:
+        calls = self._set_helper(monkeypatch, tmp_path, 'echo password=nope')
+        config: b4.ConfigDictT = {
+            'pw-key': 'secret',
+            'pw-user': 'me',
+            'pw-url': 'https://pw.example.org/',
+        }
+        assert b4.get_pw_key(config) == 'secret'
+        assert not calls.exists()
+
+    def test_credential_helper(
+        self, monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path
+    ) -> None:
+        req = tmp_path / 'request'
+        self._set_helper(
+            monkeypatch, tmp_path, f'cat > {req}\necho password=fromhelper'
+        )
+        config: b4.ConfigDictT = {
+            'pw-user': 'me',
+            'pw-url': 'https://pw.example.org:8443/',
+        }
+        assert b4.get_pw_key(config) == 'fromhelper'
+        request = req.read_text().splitlines()
+        assert 'protocol=https' in request
+        assert 'host=pw.example.org:8443' in request
+        assert 'username=me' in request
+
+    def test_credential_helper_runs_once(
+        self, monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path
+    ) -> None:
+        calls = self._set_helper(monkeypatch, tmp_path, 'echo password=key')
+        config: b4.ConfigDictT = {
+            'pw-user': 'me',
+            'pw-url': 'https://pw.example.org/',
+        }
+        assert b4.get_pw_key(config) == 'key'
+        assert b4.get_pw_key(config) == 'key'
+        assert calls.read_text().count('get') == 1
+
+    def test_credential_helper_empty(
+        self,
+        monkeypatch: pytest.MonkeyPatch,
+        tmp_path: pathlib.Path,
+        caplog: pytest.LogCaptureFixture,
+    ) -> None:
+        self._set_helper(monkeypatch, tmp_path, 'true')
+        config: b4.ConfigDictT = {
+            'pw-user': 'me',
+            'pw-url': 'https://pw.example.org/',
+        }
+        with caplog.at_level(logging.CRITICAL, logger='b4'):
+            assert b4.get_pw_key(config) == ''
+        assert 'No patchwork key for me@pw.example.org' in caplog.text
+
+    def test_bad_url(self, caplog: pytest.LogCaptureFixture) -> None:
+        config: b4.ConfigDictT = {'pw-user': 'me', 'pw-url': 'pw.example.org'}
+        with caplog.at_level(logging.CRITICAL, logger='b4'):
+            assert b4.get_pw_key(config) == ''
+        assert 'Could not parse pw-url' in caplog.text
+
+    def test_ignored_in_worktree_config(self, gitdir: str) -> None:
+        """A cloned tree's .b4-config must not get to ask for credentials."""
+        wtcfg = pathlib.Path(gitdir) / '.b4-config'
+        wtcfg.write_text(
+            '[b4]\n\tpw-user = stolen\n\tpw-url = https://pw.example.org\n'
+        )
+        b4._setup_main_config(topdir=gitdir)
+        assert b4.MAIN_CONFIG.get('pw-url') == 'https://pw.example.org'
+        assert b4.MAIN_CONFIG.get('pw-user') is None

-- 
2.56.0


      parent reply	other threads:[~2026-10-30 13:47 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-30 13:47 [PATCH b4 v2 0/3] review: add support for fetching patchwork token via git credentials Brian Masney
2026-10-30 13:47 ` [PATCH b4 v2 1/3] review: centralize lookup of patchwork key in one place Brian Masney
2026-10-30 13:47 ` [PATCH b4 v2 2/3] review: add support for fetching patchwork key via git credentials Brian Masney
2026-10-30 13:47 ` Brian Masney [this message]

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20261030-pw-key-command-v2-3-95fb0f822834@kernel.org \
    --to=masneyb@kernel.org \
    --cc=dmitry.torokhov@gmail.com \
    --cc=jbrunet@baylibre.com \
    --cc=konstantin@linuxfoundation.org \
    --cc=tools@kernel.org \
    /path/to/YOUR_REPLY

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

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