From 79835e4005b43c1e944dcaf3f642eec41f2b9d35 Mon Sep 17 00:00:00 2001 From: staticdev Date: Wed, 15 Jul 2026 17:47:22 +0200 Subject: [PATCH] python3Packages.beets: add single-plugin passthru tests Add a positive `beet --help` check for every functional built-in plugin, with only that plugin enabled. Assisted-by: Codex (GPT-5) Co-Authored-By: Doron Behar --- .../python-modules/beets/default.nix | 105 +++++++++++++++--- 1 file changed, 92 insertions(+), 13 deletions(-) diff --git a/pkgs/development/python-modules/beets/default.nix b/pkgs/development/python-modules/beets/default.nix index aaa19af69e67..47269e66701a 100644 --- a/pkgs/development/python-modules/beets/default.nix +++ b/pkgs/development/python-modules/beets/default.nix @@ -278,7 +278,9 @@ buildPythonPackage (finalAttrs: { bench.testPaths = [ ]; bpd = { }; bpm.testPaths = [ ]; - bpsync.testPaths = [ ]; + bpsync = { + testPaths = [ ]; + }; bucket = { }; chroma = { propagatedBuildInputs = [ pyacoustid ]; @@ -291,10 +293,15 @@ buildPythonPackage (finalAttrs: { propagatedBuildInputs = [ requests ]; testPaths = [ ]; }; - discogs.propagatedBuildInputs = [ - discogs-client - requests - ]; + discogs = { + propagatedBuildInputs = [ + discogs-client + requests + ]; + singlePluginTest.config = { + user_token = "test"; + }; + }; duplicates.testPaths = [ ]; edit = { }; embedart = { @@ -337,7 +344,10 @@ buildPythonPackage (finalAttrs: { testPaths = [ ]; }; limit = { }; - listenbrainz = { }; + listenbrainz.singlePluginTest.config = { + token = "test"; + username = "test"; + }; loadext = { propagatedBuildInputs = [ requests ]; testPaths = [ ]; @@ -366,11 +376,14 @@ buildPythonPackage (finalAttrs: { plexupdate = { }; random = { }; replace = { }; - replaygain.wrapperBins = [ - aacgain - ffmpeg - mp3gain - ]; + replaygain = { + singlePluginTest.config.backend = "gstreamer"; + wrapperBins = [ + aacgain + ffmpeg + mp3gain + ]; + }; rewrite.testPaths = [ ]; scrub.testPaths = [ ]; smartplaylist = { }; @@ -378,7 +391,10 @@ buildPythonPackage (finalAttrs: { propagatedBuildInputs = [ soco ]; testPaths = [ ]; }; - spotify = { }; + spotify.singlePluginTest.setup = '' + mkdir -p $HOME/.config/beets + echo '{"access_token":"test"}' > $HOME/.config/beets/spotify_token.json + ''; subsonicplaylist = { propagatedBuildInputs = [ requests ]; testPaths = [ ]; @@ -428,6 +444,10 @@ buildPythonPackage (finalAttrs: { enable = !disableAllPlugins; builtin = false; propagatedBuildInputs = [ ]; + singlePluginTest = { + config = { }; + setup = ""; + }; testPaths = [ "test/plugins/test_${n}.py" ]; wrapperBins = [ ]; } a @@ -497,7 +517,66 @@ buildPythonPackage (finalAttrs: { -c $out/config.yaml \ mpdstats --help 2> $out/mpdstats-help-stderr || true ''; - }; + } + # Build and start beets once for each supported built-in plugin. Keeping the + # plugins isolated makes missing optional dependencies visible. + // lib.pipe finalAttrs.finalPackage.passthru.plugins.all [ + # Deprecated plugins are not useful regression targets. + (lib.filterAttrs (_: pluginAttrs: !(pluginAttrs.deprecated or false))) + (lib.concatMapAttrs ( + pluginName: pluginAttrs: + let + testConfig = { + plugins = [ pluginName ]; + } + # Some plugins do not accept an empty attribute set as config. + // lib.optionalAttrs (pluginAttrs.singlePluginTest.config != { }) { + ${pluginName} = pluginAttrs.singlePluginTest.config; + }; + beetsWithSinglePlugin = beets.override { + disableAllPlugins = true; + pluginOverrides = { + ${pluginName}.enable = true; + }; + # The runCommand below is the relevant check; avoid running + # the full upstream test suite once per plugin. NOTE that + # testing whether any plugin's `testPaths` is incorrect, is + # done for all plugins via the `beets-minimal` derivation. + doCheck = false; + }; + in + { + "with-single-plugin-${pluginName}" = beetsWithSinglePlugin; + "single-plugin-${pluginName}" = runCommand "beets-single-plugin-${pluginName}-test" { } '' + set -euo pipefail + export HOME=$(mktemp -d) + ${pluginAttrs.singlePluginTest.setup} + mkdir $out + + cat <<'EOF' > $out/config.yaml + ${lib.generators.toYAML { } testConfig} + EOF + + status=0 + ${lib.getExe beetsWithSinglePlugin} \ + -c "$out/config.yaml" \ + --help > "$out/stdout" 2> "$out/stderr" || status=$? + + # beet exits successfully when a plugin fails to load, so its + # stderr must also be checked for the diagnostic. + if (( status != 0 )) || grep -Fq "error loading plugin" "$out/stderr"; then + { + printf '%s\n' '----- stdout -----' + cat "$out/stdout" + printf '%s\n' '----- stderr -----' + cat "$out/stderr" + } >&2 + exit 1 + fi + ''; + } + )) + ]; }; meta = {