.. _resources_testing:

Testing
=======

All the procedures on this page assume that you have a build of WirePlumber
in a ``build`` directory inside the source tree; see :ref:`daemon_installing`
if you have not built the project yet.

.. _resources_testing_reproducing:

Testing a change or reproducing a bug
-------------------------------------

You do not need to install your build over the system-provided WirePlumber in
order to test a change or reproduce a bug. WirePlumber is an ordinary PipeWire
client, so you can stop the session-managed instance and run your own build
straight from the source tree, against the PipeWire daemon that is already
running.

.. code:: console

   $ systemctl --user stop wireplumber
   $ make run

``make run`` compiles anything that is out of date and then runs WirePlumber
through ``wp-uninstalled.sh``, which sets up the environment so that the
modules, scripts and configuration files are all taken from the source tree.
Nothing outside the source tree is modified. Press *Ctrl+C* to stop it and
run ``systemctl --user start wireplumber`` to get your normal session
manager back.

The full procedure, including what to do on systems where WirePlumber is not
started by systemd, is described in the *Run independently or without
installing* section of :ref:`daemon_running`. If you want to run the whole
stack uninstalled, including PipeWire itself, see the *Run from the PipeWire
source tree* section on the same page.

.. tip::

   ``make run`` defaults to ``WIREPLUMBER_DEBUG=3``. When reporting a bug,
   attach a more verbose log, for example
   ``make run WIREPLUMBER_DEBUG=D`` or, to keep the noise down,
   ``make run WIREPLUMBER_DEBUG=I,s-*:D``. See :ref:`daemon_logging`
   for the full syntax.

To run the daemon under a debugger or another wrapper, see the
*Running in gdb / valgrind / etc...* section of :ref:`resources_contributing`.

Automated unit tests
--------------------

WirePlumber has automated tests that you can easily run with:

.. code:: console

   $ meson test -C build

This will automatically compile all test dependencies, so you can be sure
that this always tests your latest changes.

If you wish to run a specific test instead of all of them, you can run:

.. code:: console

   $ meson test -C build test-name

When debugging a single test, you can additionally enable verbose test output
by appending ``-v`` and you can also run the test in gdb by appending ``--gdb``.

For more information on how to use ``meson test``, please refer to
`meson's manual <https://mesonbuild.com/Unit-tests.html>`_

.. important::

   When submitting changes for review, always ensure that all tests pass

Please note that many WirePlumber tests require specific SPA test plugins
to be available in your PipeWire installation. More specifically, PipeWire
needs to be configured with the following options enabled:

.. code:: console

   -Dvideotestsrc=true -Daudiotestsrc=true -Dtest=true

If these SPA plugins are not found in the system, some tests will fail.
This is expected.

WirePlumber examples
--------------------

WirePlumber ships examples in ``tests/examples``. These are meant to be run
against an already running PipeWire daemon; they do *not* replace your session
manager.

Lua examples
^^^^^^^^^^^^

Most of the examples are standalone Lua scripts that are executed with
``wpexec``. Run them from the top-level directory with ``wp-uninstalled.sh``:

.. code:: console

   $ ./wp-uninstalled.sh wpexec tests/examples/get-default-sink-volume.lua

The following examples are available:

  - **get-default-sink-volume.lua**: prints the volume of the default sink,
    demonstrating :ref:`Core.require_api() <lua_core_api>` with the
    *default-nodes* and *mixer* plugins
  - **interactive.lua**: an interactive script that also demonstrates how
    arguments are passed to a script; it accepts a JSON object as its second
    argument, for example::

       $ ./wp-uninstalled.sh wpexec tests/examples/interactive.lua \
             '{ option1 = "value1" }'

  - **filter-chain.lua**: loads *libpipewire-module-filter-chain* with a 6-band
    equalizer configuration, demonstrating how to load a PipeWire module that
    takes a JSON string as arguments
  - **bt-profile-switch.lua**: a standalone policy script that switches the
    profile of a Bluetooth device
  - **bt-pinephone.lua**: platform-specific management of the offload SCO nodes
    on the PinePhone

C examples
^^^^^^^^^^

``tests/examples/node-extra-params.c`` demonstrates how to set additional node
properties that reside in the special ``params`` field of ``Props``. It is built
as part of the normal build:

.. code:: console

   $ ./wp-uninstalled.sh ./build/tests/examples/node-extra-params

Native API clients
------------------

pw-cat
^^^^^^

Using the default device:

.. code:: console

   $ wpctl status  # verify the default device
   $ pw-record test.wav
   $ pw-play test.wav


Using a non-default device:

.. code:: console

   $ pw-record --list-targets  # find the node id
   $ pw-record --target <node_id> test.wav
   $ pw-play --list-targets  # find the node id
   $ pw-play --target <node_id> test.wav

or

.. code:: console

   $ wpctl status  # find the capture & playback node ids
   $ pw-record --target <node_id> test.wav
   $ pw-play --target <node_id> test.wav

.. note::

   node ids can be used interchangeably when specifying targets in all use cases

video-play
^^^^^^^^^^

Using the default device:

.. code:: console

   $ cd path/to/pipewire-source-dir
   $ ./build/src/examples/video-play


Using a non-default device:

.. code:: console

   $ wpctl status  # find the device node id from the list
   $ cd path/to/pipewire-source-dir
   $ ./build/src/examples/video-play <node_id>

PulseAudio compat API clients
-----------------------------

pacat
^^^^^

Using the default device:

.. code:: console

   $ wpctl status  # verify the default device
   $ parecord test.wav
   $ paplay test.wav

pavucontrol
^^^^^^^^^^^

Use the command:

.. code:: console

  $ pavucontrol

* Volume level meters should work
* Changing the volume should work

ALSA compat API clients
-----------------------

aplay / arecord
^^^^^^^^^^^^^^^

.. note::

   unless you have installed PipeWire in the default system prefix
   (``/usr``), the ALSA compat API will not work, unless you copy
   ``libasound_module_pcm_pipewire.so`` in the alsa plugins directory
   (usually ``/usr/<libdir>/alsa-lib/``) and that you add the contents of
   ``pipewire-alsa/conf/50-pipewire.conf`` in your ``~/.asoundrc``
   (or anywhere else, system-wide, where libasound can read it)

Using the default device:

.. code:: console

   $ wpctl status  # verify the default devices
   $ arecord -D pipewire -f S16_LE -r 48000 test.wav
   $ aplay -D pipewire test.wav

Using a non-default device:

.. code:: console

   $ wpctl status  # find the capture & playback node ids
   $ PIPEWIRE_NODE=<node_id> arecord -D pipewire -f S16_LE -r 48000 test.wav
   $ PIPEWIRE_NODE=<node_id> aplay -D pipewire test.wav

or

.. code:: console

   $ wpctl status  # find the capture & playback device node ids
   $ arecord -D pipewire:NODE=<node_id> -f S16_LE -r 48000 test.wav
   $ aplay -D pipewire:NODE=<node_id> test.wav


JACK compat API clients
-----------------------

qjackctl
^^^^^^^^

.. code:: console

   $ pw-jack qjackctl

* This should correctly connect.
* The "Graph" window should show the PipeWire graph.

jack_simple_client
^^^^^^^^^^^^^^^^^^

.. code:: console

   $ wpctl status  # find the target device node id
   $ wpctl inspect <node_id>  # find the node.id
   $ PIPEWIRE_NODE=<node_id> pw-jack jack_simple_client

.. note::

   The JACK layer is not controlled by the session manager, it creates its own
   links; which is why it is required to specify a node id.

Device Reservation
------------------

with PulseAudio
^^^^^^^^^^^^^^^

1. With PulseAudio running, start a pulseaudio client.

.. code:: console

   $ gst-launch-1.0 audiotestsrc ! pulsesink

2. Start PipeWire & WirePlumber

   - The device in use by PA will not be available in PW

3. Stop the PA client

   - A few seconds later, WirePlumber should assume control of the device

4. ``wpctl status`` should be able to confirm that the device is available

5. Start a PA client again

   - It should not be able to play; it will just freeze

6. Stop WirePlumber

   - The PA client should immediately start playing

with JACK
^^^^^^^^^

1. Start PipeWire & WirePlumber

   - All devices should be available

2. Start ``jackdbus``

   1. through ``qjackctl``:

      - Enable *Setup* -> *Misc* -> *Enable JACK D-Bus interface*
      - Click *Start* on the main window

   2. or manually:

      - Run ``jackdbus auto``
      - Run ``qdbus org.jackaudio.service /org/jackaudio/Controller org.jackaudio.JackControl.StartServer``

3. Wait a few seconds and run ``wpctl status`` to inspect

   - The devices taken by JACK should no longer be available
   - There should be two *JACK System* nodes (sink & source)

4. Run an audio client on PipeWire (ex ``pw-play test.wav``)

   - Notice how audio now goes through JACK

5. Stop JACK

   - through ``qjackctl``, click *Stop*
   - or manually: ``qdbus org.jackaudio.service /org/jackaudio/Controller org.jackaudio.JackControl.StopServer``

6. Wait a few seconds and run ``wpctl status`` to inspect

   - The devices that were release by JACK should again be available
   - There should be no *JACK System* nodes

.. note::

   You may also start WirePlumber *after* starting JACK. It should immediately
   go to the state described in step 3
