Don't rely on resources provided by mock metadata server by default,
create the from within the test instead.
This allows for more flexibility, but the locality of the test fixture
relative to the tests makes the test more legible.
When a pexpect check fails, we want to see the full content of the
buffer, so we can better see where it went wrong. Increase the context
that is printed in the error message.
"preexec_fn" is not great, because it is not generally safe in multi
threaded code (and we don't know whether the test didn't start other
threads already, like a GDBus worker thread). Well, it probably is safe,
if you only call async signal safe code, but it's not clear what os.dup2()
does under the hood.
Just avoid that. We can pass on the FD directly.
test_ec2 (__main__.TestNmCloudSetup.test_ec2) ... /usr/lib64/python3.11/unittest/case.py:579: ResourceWarning: unclosed file <_io.BufferedWriter name=5>
if method() is not None:
ResourceWarning: Enable tracemalloc to get the object allocation traceback
ok
Fixes: d89d42bf23 ('tests/client: test nm-cloud-setup')
This seems unnecessary, because we spawn the child process via subprocess.Popen and
set "pass_fds". That already ensures to pass on the FD.
Worse, socket.set_inheritable() is only added in Python 3.4, that means the
test is gonna break for Python 3.2 and 3.3. Just avoid that by not using the
unnecessary function. For the same reason, drop "inheritable=True" from
os.dup2(). "inheritable=True" is already the default, but only exists
since Python 3.4.
Fixes: d89d42bf23 ('tests/client: test nm-cloud-setup')
The test uses subprocess.Popen()'s "pass_fd" argument. That is only
available since Python 3.2. Possibly it could be solved differently, but
that is not implemented. Instead, skip the test.
Also, socket.socket.set_inheritable() is Python 3.4. But presumably
we don't need it.
Fixes: d89d42bf23 ('tests/client: test nm-cloud-setup')
The mock service is more widely useful -- in particular for testing
nm-cloud-setup in a following commit.
Split the commonly useful parts into TestNmClient class.
During srv_shutdown() we do
p.stdin.close()
p.kill()
Usually, the kill wins and the service just drops off the bus:
libnm-dbus[3201919]: <debug> [438617.45324] nmclient[40f7938626f3f5f0]: name owner changed: ":1.1" -> (null)
libnm-dbus[3201919]: <debug> [438617.45332] nmclient[40f7938626f3f5f0]: release all
at which point all objects in NMClient get destroyed and the signals get
emitted in the order:
libnm-dbus[3201919]: <trace> [438617.45574] nmclient[40f7938626f3f5f0]: [nmclient] emit "device-removed" signal for /org/freedesktop/NetworkManager/Devices/1
nmcli[out]: eth0: device removed
libnm-dbus[3201919]: <trace> [438617.45590] nmclient[40f7938626f3f5f0]: [nmclient] emit "any-device-removed" signal for /org/freedesktop/NetworkManager/Devices/1
libnm-dbus[3201919]: <trace> [438617.45593] nmclient[40f7938626f3f5f0]: [nmclient] emit "connection-removed" signal for /org/freedesktop/NetworkManager/Settings/Connectio>
nmcli[out]: con-1: connection profile removed
However, sometimes the stub service notices that stdin was closed and it
sends signals about shutting down:
libnm-dbus[3201061]: <trace> [438226.44965] nmclient[401639659459c316]: interfaces-removed: [/org/freedesktop/NetworkManager/Settings] receive interface remove event for >
libnm-dbus[3201061]: <trace> [438226.44966] nmclient[401639659459c316]: [/org/freedesktop/NetworkManager/Settings]: changed-type 0x01 linked
libnm-dbus[3201061]: <trace> [438226.44967] nmclient[401639659459c316]: [/org/freedesktop/NetworkManager/Settings]: changed-type 0x01 consumed
libnm-dbus[3201061]: <trace> [438226.44968] nmclient[401639659459c316]: [/org/freedesktop/NetworkManager/Settings]: changed-type 0x02 linked
libnm-dbus[3201061]: <trace> [438226.44969] nmclient[401639659459c316]: [/org/freedesktop/NetworkManager/Settings]: unregister NMClient from D-Bus object
libnm-dbus[3201061]: <trace> [438226.44971] nmclient[401639659459c316]: [/org/freedesktop/NetworkManager/Settings]: drop D-Bus instance
libnm-dbus[3201061]: <trace> [438226.44971] nmclient[401639659459c316]: [/org/freedesktop/NetworkManager/Settings]: set D-Bus object state unlinked
libnm-dbus[3201061]: <trace> [438226.44972] nmclient[401639659459c316]: [nmclient] emit "connection-removed" signal for /org/freedesktop/NetworkManager/Settings/Connectio>
nmcli[out]: con-1: connection profile removed
libnm-dbus[3201061]: <trace> [438226.44992] nmclient[401639659459c316]: interfaces-removed: [/org/freedesktop/NetworkManager] receive interface remove event for interface>
libnm-dbus[3201061]: <trace> [438226.44994] nmclient[401639659459c316]: [/org/freedesktop/NetworkManager]: changed-type 0x01 linked
libnm-dbus[3201061]: <trace> [438226.44995] nmclient[401639659459c316]: [/org/freedesktop/NetworkManager]: changed-type 0x01 consumed
libnm-dbus[3201061]: <trace> [438226.44996] nmclient[401639659459c316]: [/org/freedesktop/NetworkManager]: changed-type 0x02 linked
libnm-dbus[3201061]: <trace> [438226.44998] nmclient[401639659459c316]: [/org/freedesktop/NetworkManager]: unregister NMClient from D-Bus object
libnm-dbus[3201061]: <trace> [438226.44999] nmclient[401639659459c316]: [/org/freedesktop/NetworkManager]: drop D-Bus instance
libnm-dbus[3201061]: <trace> [438226.45000] nmclient[401639659459c316]: [/org/freedesktop/NetworkManager]: set D-Bus object state unlinked
libnm-dbus[3201061]: <trace> [438226.45001] nmclient[401639659459c316]: [nmclient] emit "device-removed" signal for /org/freedesktop/NetworkManager/Devices/1
nmcli[out]: eth0: device removed
libnm-dbus[3201061]: <trace> [438226.45005] nmclient[401639659459c316]: [nmclient] emit "any-device-removed" signal for /org/freedesktop/NetworkManager/Devices/1
nmcli[out]: NetworkManager is stopped
libnm-dbus[3201061]: <debug> [438226.45545] nmclient[401639659459c316]: name owner changed: ":1.1" -> (null)
libnm-dbus[3201061]: <debug> [438226.45550] nmclient[401639659459c316]: release all
The fix is to accept the events in any order.
(cherry picked from commit 8548ab29ee)
The test stub service watches stdin, and if it gets closed the service
will shut down. Note that the service does not catch any signals, so
sending a signal will kill the service right away.
The previous code first closed stdin, and then killed the process.
That can result in different outcomes on D-Bus. Usually the signal
gets received first, and the test service just drops off the bus.
Sometimes it notices the closing of stdin and shuts actively down.
That can make a difference, especially for the test_monitor() test which
runs the monitor while stopping the service.
We could just always kill the stub service to get consistent behavior.
However, that doesn't seem very useful. Instead, randomize the behavior
to easier see how the behavior differs.
(cherry picked from commit fc282d5e05)
For debugging libnm, LIBNM_CLIENT_DEBUG can be very useful.
As the tests compare stdout/stderr from nmcli with expected output, just
enabling it will break the tests. However, in combination with
LIBNM_CLIENT_DEBUG_FILE this can be very useful.
Preserve and pass on the environment variables, if set.
(cherry picked from commit 1630009234)
Sort imports by name. Also avoid "from signal import SIGINT". I find
it ugly to import names in the current namespace. "SIGINT" should be
refered to by its full name, including the package/namespace.
(cherry picked from commit ee17346cee)
This will allow to find some memory leaks and memory corruptions.
The bulk of the nmcli calls are still not hooked up with valgrind.
Since we call nmcli a thousand time, we could not just run valgrind with
all of them. We would have instead to enable it randomly. This is
more work.
(cherry picked from commit debf78dbed)
The base class is not used, and it's not clear that it would be useful.
Sure, we could extend "test-client.py" will various non-nmcli tests. That
might make sense. And then it might make sense to have more unit test classes.
So far, we don't need that. Drop the unused base class NmTestBase.
(cherry picked from commit d1e6d53013)
Under normal circumstances, the timeout is not supposed to be hit.
I see it hit on gitlab-ci. Was that because the machine was very
busy? It's hard to say whether there was a legitimate problem here,
and more importantly, what that problem was.
Try to increase the timeout. If there is a real problem, we probably
will still hit the timeout.
In case the D-Bus interfaces start dropping off (typically all off them go
one by one when the object is being deleted), don't reset all the properties.
In particular, keep most properties around, only tear down "o" and "ao",
so that the object dependencies get torn down, but we still get enough
properties around to identify what the dead object was its heyday.
One example of where this is not good is when the device-removed signal
is emmitted, the device no longer has the ifname:
$ nmcli monitor
<quit NetworkManager>
(null): device removed
(null): device removed
...
ModuleNotFoundError was only introduced in later python 3 versions.
Use just "ImportError", which is the parent class anyway.
Fixes: f7e484c8ed ('tests: fix "test-client.py" ignoring missing "NM" module')
(cherry picked from commit 9902373c6d)
The source file now contains UTF-8 (non ASCII) characters. Python2
doesn't like that:
"./src/tests/client/test-client.sh" "." "." "/usr/bin/python"
File "/builddir/build/BUILD/NetworkManager-1.39.2/src/tests/client/test-client.py", line 1730
SyntaxError: Non-ASCII character '\xe2' in file /builddir/build/BUILD/NetworkManager-1.39.2/src/tests/client/test-client.py on line 1730, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details
This test calls "nmcli g" with a bogus D-Bus bus address. We expect
a failure on stderr.
On alpine:latest, the error however looks slightly different:
b'size: 258\nlocation: src/tests/client/test-client.py:test_offline()/1\ncmd: $NMCLI g\nlang: C\nreturncode: 1\nstderr: 136 bytes\n>>>\nError: Could not create NMClient object: Key/Value pair 0, *invalid*, in address element *very:invalid* does not contain an equal sign.\n\n<<<\n'
On ubuntu:16.04 and debian:9 we got:
b"size: 258\nlocation: src/tests/client/test-client.py:test_offline()/1\ncmd: $NMCLI g\nlang: C\nreturncode: 1\nstderr: 136 bytes\n>>>\nError: Could not create NMClient object: Key/Value pair 0, 'invalid', in address element 'very:invalid' does not contain an equal sign.\n\n<<<\n"
On fedora and most recent systemd we got:
b'size: 258\nlocation: src/tests/client/test-client.py:test_offline()/1\ncmd: $NMCLI g\nlang: C\nreturncode: 1\nstderr: 136 bytes\n>>>\nError: Could not create NMClient object: Key/Value pair 0, ?invalid?, in address element ?very:invalid? does not contain an equal sign.\n\n<<<\n'
This depends on the glib version (whether to print `%s', '%s', or “%s”).
Also, as we run the application with lang=C, so that libc (I think)
replaces Unicode with an ASCII character. Here musl and glibc behave
differently.
Workaround by replace the unexpected text.
Let the replace_arr parameter of Util.replace_text() only contain
callables, and don't special case the argument. Previously, we
either expected a regex or a 2-tuple, and the code would check
each explicitly.
Aside that the tuples are hard to follow, it also makes
Util.replace_text() strongly tied to those types. By instead accepting
and arbitrary function, each element can implement its own replacement.
Also, make text that was replaced by regex atomic. Meaning, if we
first match (and replace) a certain part of the text with the regex,
then the replacement cannot be split again. This is done by returning
a 1-tuple from the replace function.
Seems the previous code did not work properly:
With python36-3.6.8-38.module+el8.5.0+12207+5c5719bc.x86_6 on rhel-8.6:
Traceback (most recent call last):
File "/root/nm-build/NetworkManager/src/tests/client/test-client.py", line 1157, in f
func(self)
File "/root/nm-build/NetworkManager/src/tests/client/test-client.py", line 1724, in test_offline
replace_stdout=replace_uuids,
File "/root/nm-build/NetworkManager/src/tests/client/test-client.py", line 797, in call_nmcli
frame,
File "/root/nm-build/NetworkManager/src/tests/client/test-client.py", line 997, in _call_nmcli
self.async_start(wait_all=sync_barrier)
File "/root/nm-build/NetworkManager/src/tests/client/test-client.py", line 1032, in async_start
async_job.wait_and_complete()
File "/root/nm-build/NetworkManager/src/tests/client/test-client.py", line 670, in wait_and_complete
self._complete_cb(self, return_code, stdout, stderr)
File "/root/nm-build/NetworkManager/src/tests/client/test-client.py", line 919, in complete_cb
stdout = Util.replace_text(stdout, replace_stdout)
File "/root/nm-build/NetworkManager/src/tests/client/test-client.py", line 362, in replace_text
if Util.is_regex_pattern(v_search):
File "/root/nm-build/NetworkManager/src/tests/client/test-client.py", line 208, in is_regex_pattern
t = re.Pattern
AttributeError: module 're' has no attribute 'Pattern'
On this python version, re.compile() give an object of type
_sre.SRE_Pattern.
# python -c 'import re; print(type(re.compile("a")))'
<class '_sre.SRE_Pattern'>
Fixes: beebde9e56 ('client/test: allow matching and replacing regex-es in nmcli output')
Set extra variables after the pre-defined ones have been set. This
allows overriding then.
In particular, this allows overriding DBUS_SESSION_BUS_ADDRESS so that
the test can check the behavior of the client is correct when it's set
to some garbage.