cli: merge branch 'th/cli-unit-tests'

https://github.com/NetworkManager/NetworkManager/pull/110
This commit is contained in:
Thomas Haller
2018-05-11 16:53:49 +02:00
48 changed files with 1895 additions and 178 deletions

View File

@@ -104,10 +104,17 @@ script:
- |
if test "$BUILD_TYPE" == 'autotools'; then
git clean -fdx &&
./autogen.sh --with-systemd-logind=no --enable-more-warnings=no --enable-ifcfg-rh --enable-config-plugin-ibft --enable-ifupdown --enable-tests &&
./autogen.sh --prefix="$PWD/INST" --with-systemd-logind=no --enable-more-warnings=no --enable-ifcfg-rh --enable-config-plugin-ibft --enable-ifupdown --enable-tests &&
make -j4 &&
if [ "$CC" == gcc ]; then
sudo locale-gen de_DE.UTF-8 &&
sudo locale-gen pl_PL.UTF-8 &&
sudo make install &&
NM_TEST_CLIENT_CHECK_L10N=1 ./contrib/travis/travis-check.sh
else
./contrib/travis/travis-check.sh
fi
fi
env:
matrix:

View File

@@ -948,8 +948,11 @@ EXTRA_DIST += \
libnm/libnm.pc.in \
libnm/libnm.ver
libnm_NM_1_0_typelib =
if HAVE_INTROSPECTION
libnm_NM_1_0_typelib += libnm/NM-1.0.typelib
libnm/NM-1.0.gir: libnm/libnm.la
libnm_NM_1_0_gir_INCLUDES = Gio-2.0
libnm_NM_1_0_gir_PACKAGES = gio-2.0
@@ -1059,12 +1062,20 @@ EXTRA_DIST += \
###############################################################################
libnm_tests_programs = \
libnm/tests/test-general \
libnm/tests/test-general
check_programs += $(libnm_tests_programs)
libnm_tests_programs_req_introspection = \
libnm/tests/test-nm-client \
libnm/tests/test-remote-settings-client \
libnm/tests/test-secret-agent
check_programs += $(libnm_tests_programs)
if HAVE_INTROSPECTION
check_programs += $(libnm_tests_programs_req_introspection)
else
check_programs_norun += $(libnm_tests_programs_req_introspection)
endif
libnm_tests_cppflags = \
$(dflt_cppflags_libnm_core) \
@@ -1122,6 +1133,12 @@ $(libnm_tests_test_nm_client_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
$(libnm_tests_test_remote_settings_client_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
$(libnm_tests_test_secret_agent_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
# tools/test-networkmanager-service.py uses libnm's typelib. Ensure it
# is built first.
$(libnm_tests_test_nm_client_OBJECTS): $(libnm_NM_1_0_typelib)
$(libnm_tests_test_remote_settings_client_OBJECTS): $(libnm_NM_1_0_typelib)
$(libnm_tests_test_secret_agent_OBJECTS): $(libnm_NM_1_0_typelib)
###############################################################################
# just test, that we can build "nm-vpn-plugin-utils.c"
@@ -3409,9 +3426,13 @@ DISTCLEANFILES += $(clients_common_settings_doc_h)
check-local-settings-docs: $(clients_common_settings_doc_h)
@if test -z "$$NMTST_NO_CHECK_SETTINGS_DOCS" ; then \
if ! cmp -s "$(srcdir)/$(clients_common_settings_doc_h).in" "$(builddir)/$(clients_common_settings_doc_h)" ; then \
echo "The generated file \"$(builddir)/$(clients_common_settings_doc_h)\" differs from the source file \"$(srcdir)/$(clients_common_settings_doc_h).in\". You probably should copy the generated file over to the source file. You can skip this test by setting \$$NMTST_NO_CHECK_SETTINGS_DOCS=yes"; \
if test "$$NM_TEST_REGENERATE" == 1 ; then \
cp -f "$(builddir)/$(clients_common_settings_doc_h)" "$(srcdir)/$(clients_common_settings_doc_h).in"; \
else \
echo "The generated file \"$(builddir)/$(clients_common_settings_doc_h)\" differs from the source file \"$(srcdir)/$(clients_common_settings_doc_h).in\". You probably should copy the generated file over to the source file. You can skip this test by setting \$$NMTST_NO_CHECK_SETTINGS_DOCS=yes". You can also automatically copy the file by rerunning the test with \$$NM_TEST_REGENERATE=1 ; \
false; \
fi; \
fi;\
fi
check_local += check-local-settings-docs
else
@@ -3759,6 +3780,62 @@ EXTRA_DIST += \
clients/tui/meson.build \
clients/tui/newt/meson.build
###############################################################################
# clients/tests
###############################################################################
check-local-clients-tests-test-client: clients/cli/nmcli clients/tests/test-client.py
mkdir -p "$(builddir)/clients/tests/"
GI_TYPELIB_PATH="$(abs_builddir)/libnm$${GI_TYPELIB_PATH:+:$$GI_TYPELIB_PATH}" \
LD_LIBRARY_PATH="$(abs_builddir)/libnm/.libs$${LD_LIBRARY_PATH:+:$$LD_LIBRARY_PATH}" \
NM_TEST_CLIENT_BUILDDIR="$(abs_builddir)" \
NM_TEST_CLIENT_NMCLI_PATH=clients/cli/nmcli \
NM_TEST_CLIENT_IN_DBUS_SESSION=0 \
$(srcdir)/clients/tests/test-client.py -v &> "$(builddir)/clients/tests/test-client.log" && r=ok; \
cat "$(builddir)/clients/tests/test-client.log"; \
test "$$r" == ok
check_local += check-local-clients-tests-test-client
CLEANFILES += clients/tests/test-client.log
EXTRA_DIST += \
clients/tests/test-client.py \
\
clients/tests/test-client.check-on-disk/test_001-001.expected \
clients/tests/test-client.check-on-disk/test_001-002.expected \
clients/tests/test-client.check-on-disk/test_001-003.expected \
clients/tests/test-client.check-on-disk/test_001-004.expected \
clients/tests/test-client.check-on-disk/test_001-005.expected \
clients/tests/test-client.check-on-disk/test_001-006.expected \
clients/tests/test-client.check-on-disk/test_002-001.expected \
clients/tests/test-client.check-on-disk/test_002-002.expected \
clients/tests/test-client.check-on-disk/test_002-003.expected \
clients/tests/test-client.check-on-disk/test_002-004.expected \
clients/tests/test-client.check-on-disk/test_002-005.expected \
clients/tests/test-client.check-on-disk/test_002-006.expected \
clients/tests/test-client.check-on-disk/test_002-007.expected \
clients/tests/test-client.check-on-disk/test_002-008.expected \
clients/tests/test-client.check-on-disk/test_002-009.expected \
clients/tests/test-client.check-on-disk/test_002-010.expected \
clients/tests/test-client.check-on-disk/test_002-011.expected \
clients/tests/test-client.check-on-disk/test_002-012.expected \
clients/tests/test-client.check-on-disk/test_002-013.expected \
clients/tests/test-client.check-on-disk/test_002-014.expected \
clients/tests/test-client.check-on-disk/test_002-015.expected \
clients/tests/test-client.check-on-disk/test_002-016.expected \
clients/tests/test-client.check-on-disk/test_002-017.expected \
clients/tests/test-client.check-on-disk/test_003-001.expected \
clients/tests/test-client.check-on-disk/test_003-002.expected \
clients/tests/test-client.check-on-disk/test_003-003.expected \
clients/tests/test-client.check-on-disk/test_003-004.expected \
clients/tests/test-client.check-on-disk/test_003-005.expected \
clients/tests/test-client.check-on-disk/test_003-006.expected \
clients/tests/test-client.check-on-disk/test_003-007.expected \
clients/tests/test-client.check-on-disk/test_003-008.expected \
\
$(NULL)
###############################################################################
# data
###############################################################################
@@ -4431,10 +4508,16 @@ libnm_glib_tests_cppflags = \
$(GLIB_CFLAGS) \
$(DBUS_CFLAGS)
check_programs += \
libnm_glib_tests_programs_req_introspection = \
libnm-glib/tests/test-nm-client \
libnm-glib/tests/test-remote-settings-client
if HAVE_INTROSPECTION
check_programs += $(libnm_glib_tests_programs_req_introspection)
else
check_programs_norun += $(libnm_glib_tests_programs_req_introspection)
endif
libnm_glib_tests_test_nm_client_CPPFLAGS = $(libnm_glib_tests_cppflags)
libnm_glib_tests_test_nm_client_SOURCES = \
@@ -4466,6 +4549,11 @@ libnm_glib_tests_test_remote_settings_client_LDADD = \
$(libnm_glib_tests_test_remote_settings_client_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
# tools/test-networkmanager-service.py uses libnm's typelib. Ensure it
# is built first.
$(libnm_glib_tests_test_nm_client_OBJECTS): $(libnm_NM_1_0_typelib)
$(libnm_glib_tests_test_remote_settings_client_OBJECTS): $(libnm_NM_1_0_typelib)
endif
EXTRA_DIST += \

View File

@@ -0,0 +1,19 @@
location: clients/tests/test-client.py:489:test_001()/1
cmd: $NMCLI
lang: C
returncode: 0
stdout: 277 bytes
>>>
DNS configuration:
servers: 1.2.3.4 5.6.7.8
Use "nmcli device show" to get complete information about known devices and
"nmcli connection show" to get an overview on active connection profiles.
Consult nmcli(1) and nmcli-examples(5) manual pages for complete usage details.
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,21 @@
location: clients/tests/test-client.py:490:test_001()/2
cmd: $NMCLI
lang: pl_PL.UTF-8
returncode: 0
stdout: 310 bytes
>>>
DNS configuration:
servers: 1.2.3.4 5.6.7.8
Polecenie „nmcli device show” wyświetli pełne informacje o znanych
urządzeniach, a „nmcli connection show” wyświetli przegląd aktywnych
profili połączeń.
Strony podręcznika nmcli(1) i nmcli-examples(5) zawierają pełne informacje
o użyciu.
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,13 @@
location: clients/tests/test-client.py:492:test_001()/3
cmd: $NMCLI -f AP -mode multiline -p d show wlan0
lang: C
returncode: 10
stdout: 0 bytes
>>>
<<<
stderr: 33 bytes
>>>
Error: Device 'wlan0' not found.
<<<

View File

@@ -0,0 +1,13 @@
location: clients/tests/test-client.py:493:test_001()/4
cmd: $NMCLI -f AP -mode multiline -p d show wlan0
lang: de_DE.utf8
returncode: 10
stdout: 0 bytes
>>>
<<<
stderr: 47 bytes
>>>
Fehler: Gerät »wlan0« wurde nicht gefunden.
<<<

View File

@@ -0,0 +1,13 @@
location: clients/tests/test-client.py:495:test_001()/5
cmd: $NMCLI c s
lang: C
returncode: 0
stdout: 26 bytes
>>>
NAME UUID TYPE DEVICE
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,13 @@
location: clients/tests/test-client.py:497:test_001()/6
cmd: $NMCLI bogus s
lang: C
returncode: 2
stdout: 0 bytes
>>>
<<<
stderr: 68 bytes
>>>
Error: argument 'bogus' not understood. Try passing --help instead.
<<<

View File

@@ -0,0 +1,17 @@
location: clients/tests/test-client.py:502:test_002()/1
cmd: $NMCLI d
lang: C
returncode: 0
stdout: 215 bytes
>>>
DEVICE TYPE STATE CONNECTION
eth0 ethernet unavailable --
wlan0 wifi unavailable --
wlan1 wifi unavailable --
wlan1 wifi unavailable --
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,17 @@
location: clients/tests/test-client.py:504:test_002()/2
cmd: $NMCLI -f all d
lang: C
returncode: 0
stdout: 530 bytes
>>>
DEVICE TYPE STATE DBUS-PATH CONNECTION CON-UUID CON-PATH
eth0 ethernet unavailable /org/freedesktop/NetworkManager/Devices/1 -- -- --
wlan0 wifi unavailable /org/freedesktop/NetworkManager/Devices/2 -- -- --
wlan1 wifi unavailable /org/freedesktop/NetworkManager/Devices/3 -- -- --
wlan1 wifi unavailable /org/freedesktop/NetworkManager/Devices/4 -- -- --
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,35 @@
location: clients/tests/test-client.py:506:test_002()/3
cmd: $NMCLI
lang: C
returncode: 0
stdout: 551 bytes
>>>
eth0: unavailable
"eth0"
ethernet (virtual), 72:41:AB:90:41:5D, hw
wlan0: unavailable
"wlan0"
wifi (virtual), 5A:88:5E:B6:90:40, hw
wlan1: unavailable
"wlan1"
wifi (virtual), 7C:D4:69:31:67:0B, hw
wlan1: unavailable
"wlan1"
wifi (virtual), 41:21:6B:F3:C9:4A, hw
DNS configuration:
servers: 1.2.3.4 5.6.7.8
Use "nmcli device show" to get complete information about known devices and
"nmcli connection show" to get an overview on active connection profiles.
Consult nmcli(1) and nmcli-examples(5) manual pages for complete usage details.
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,36 @@
location: clients/tests/test-client.py:508:test_002()/4
cmd: $NMCLI -f AP -mode multiline d show wlan0
lang: C
returncode: 0
stdout: 1107 bytes
>>>
AP[1].IN-USE:
AP[1].SSID: wlan0-ap-3
AP[1].MODE: Infra
AP[1].CHAN: 1
AP[1].RATE: 54 Mbit/s
AP[1].SIGNAL: 61
AP[1].BARS: ***
AP[1].SECURITY: WPA1 WPA2
AP[2].IN-USE:
AP[2].SSID: wlan0-ap-1
AP[2].MODE: Infra
AP[2].CHAN: 1
AP[2].RATE: 54 Mbit/s
AP[2].SIGNAL: 34
AP[2].BARS: **
AP[2].SECURITY: WPA1 WPA2
AP[3].IN-USE:
AP[3].SSID: wlan0-ap-2
AP[3].MODE: Infra
AP[3].CHAN: 1
AP[3].RATE: 54 Mbit/s
AP[3].SIGNAL: 29
AP[3].BARS: *
AP[3].SECURITY: WPA1 WPA2
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,42 @@
location: clients/tests/test-client.py:509:test_002()/5
cmd: $NMCLI -f AP -mode multiline -p d show wlan0
lang: C
returncode: 0
stdout: 1558 bytes
>>>
===============================================================================
Device details (wlan0)
===============================================================================
AP[1].IN-USE:
AP[1].SSID: wlan0-ap-3
AP[1].MODE: Infra
AP[1].CHAN: 1
AP[1].RATE: 54 Mbit/s
AP[1].SIGNAL: 61
AP[1].BARS: ***
AP[1].SECURITY: WPA1 WPA2
-------------------------------------------------------------------------------
AP[2].IN-USE:
AP[2].SSID: wlan0-ap-1
AP[2].MODE: Infra
AP[2].CHAN: 1
AP[2].RATE: 54 Mbit/s
AP[2].SIGNAL: 34
AP[2].BARS: **
AP[2].SECURITY: WPA1 WPA2
-------------------------------------------------------------------------------
AP[3].IN-USE:
AP[3].SSID: wlan0-ap-2
AP[3].MODE: Infra
AP[3].CHAN: 1
AP[3].RATE: 54 Mbit/s
AP[3].SIGNAL: 29
AP[3].BARS: *
AP[3].SECURITY: WPA1 WPA2
-------------------------------------------------------------------------------
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,36 @@
location: clients/tests/test-client.py:510:test_002()/6
cmd: $NMCLI -f AP -mode multiline -t d show wlan0
lang: C
returncode: 0
stdout: 435 bytes
>>>
AP[1].IN-USE:
AP[1].SSID:wlan0-ap-3
AP[1].MODE:Infra
AP[1].CHAN:1
AP[1].RATE:54 Mbit/s
AP[1].SIGNAL:61
AP[1].BARS:***
AP[1].SECURITY:WPA1 WPA2
AP[2].IN-USE:
AP[2].SSID:wlan0-ap-1
AP[2].MODE:Infra
AP[2].CHAN:1
AP[2].RATE:54 Mbit/s
AP[2].SIGNAL:34
AP[2].BARS:**
AP[2].SECURITY:WPA1 WPA2
AP[3].IN-USE:
AP[3].SSID:wlan0-ap-2
AP[3].MODE:Infra
AP[3].CHAN:1
AP[3].RATE:54 Mbit/s
AP[3].SIGNAL:29
AP[3].BARS:*
AP[3].SECURITY:WPA1 WPA2
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,16 @@
location: clients/tests/test-client.py:511:test_002()/7
cmd: $NMCLI -f AP -mode tabular d show wlan0
lang: C
returncode: 0
stdout: 304 bytes
>>>
NAME IN-USE SSID MODE CHAN RATE SIGNAL BARS SECURITY
AP[1] wlan0-ap-3 Infra 1 54 Mbit/s 61 *** WPA1 WPA2
AP[2] wlan0-ap-1 Infra 1 54 Mbit/s 34 ** WPA1 WPA2
AP[3] wlan0-ap-2 Infra 1 54 Mbit/s 29 * WPA1 WPA2
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,20 @@
location: clients/tests/test-client.py:512:test_002()/8
cmd: $NMCLI -f AP -mode tabular -p d show wlan0
lang: C
returncode: 0
stdout: 460 bytes
>>>
==========================
Device details (wlan0)
==========================
NAME IN-USE SSID MODE CHAN RATE SIGNAL BARS SECURITY
----------------------------------------------------------------------------
AP[1] wlan0-ap-3 Infra 1 54 Mbit/s 61 *** WPA1 WPA2
AP[2] wlan0-ap-1 Infra 1 54 Mbit/s 34 ** WPA1 WPA2
AP[3] wlan0-ap-2 Infra 1 54 Mbit/s 29 * WPA1 WPA2
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,15 @@
location: clients/tests/test-client.py:513:test_002()/9
cmd: $NMCLI -f AP -mode tabular -t d show wlan0
lang: C
returncode: 0
stdout: 165 bytes
>>>
AP[1]: :wlan0-ap-3:Infra:1:54 Mbit/s:61:*** :WPA1 WPA2
AP[2]: :wlan0-ap-1:Infra:1:54 Mbit/s:34:** :WPA1 WPA2
AP[3]: :wlan0-ap-2:Infra:1:54 Mbit/s:29:* :WPA1 WPA2
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,36 @@
location: clients/tests/test-client.py:515:test_002()/10
cmd: $NMCLI -f AP -mode multiline d show wlan0
lang: pl_PL.UTF-8
returncode: 0
stdout: 1134 bytes
>>>
AP[1].IN-USE:
AP[1].SSID: wlan0-ap-3
AP[1].MODE: Infrastruktura
AP[1].CHAN: 1
AP[1].RATE: 54Mb/s
AP[1].SIGNAL: 61
AP[1].BARS: ***
AP[1].SECURITY: WPA1 WPA2
AP[2].IN-USE:
AP[2].SSID: wlan0-ap-1
AP[2].MODE: Infrastruktura
AP[2].CHAN: 1
AP[2].RATE: 54Mb/s
AP[2].SIGNAL: 34
AP[2].BARS: **
AP[2].SECURITY: WPA1 WPA2
AP[3].IN-USE:
AP[3].SSID: wlan0-ap-2
AP[3].MODE: Infrastruktura
AP[3].CHAN: 1
AP[3].RATE: 54Mb/s
AP[3].SIGNAL: 29
AP[3].BARS: *
AP[3].SECURITY: WPA1 WPA2
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,42 @@
location: clients/tests/test-client.py:516:test_002()/11
cmd: $NMCLI -f AP -mode multiline -p d show wlan0
lang: pl_PL.UTF-8
returncode: 0
stdout: 1592 bytes
>>>
===============================================================================
Informacje o urządzeniu (wlan0)
===============================================================================
AP[1].IN-USE:
AP[1].SSID: wlan0-ap-3
AP[1].MODE: Infrastruktura
AP[1].CHAN: 1
AP[1].RATE: 54Mb/s
AP[1].SIGNAL: 61
AP[1].BARS: ***
AP[1].SECURITY: WPA1 WPA2
-------------------------------------------------------------------------------
AP[2].IN-USE:
AP[2].SSID: wlan0-ap-1
AP[2].MODE: Infrastruktura
AP[2].CHAN: 1
AP[2].RATE: 54Mb/s
AP[2].SIGNAL: 34
AP[2].BARS: **
AP[2].SECURITY: WPA1 WPA2
-------------------------------------------------------------------------------
AP[3].IN-USE:
AP[3].SSID: wlan0-ap-2
AP[3].MODE: Infrastruktura
AP[3].CHAN: 1
AP[3].RATE: 54Mb/s
AP[3].SIGNAL: 29
AP[3].BARS: *
AP[3].SECURITY: WPA1 WPA2
-------------------------------------------------------------------------------
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,36 @@
location: clients/tests/test-client.py:517:test_002()/12
cmd: $NMCLI -f AP -mode multiline -t d show wlan0
lang: pl_PL.UTF-8
returncode: 0
stdout: 462 bytes
>>>
AP[1].IN-USE:
AP[1].SSID:wlan0-ap-3
AP[1].MODE:Infrastruktura
AP[1].CHAN:1
AP[1].RATE:54Mb/s
AP[1].SIGNAL:61
AP[1].BARS:***
AP[1].SECURITY:WPA1 WPA2
AP[2].IN-USE:
AP[2].SSID:wlan0-ap-1
AP[2].MODE:Infrastruktura
AP[2].CHAN:1
AP[2].RATE:54Mb/s
AP[2].SIGNAL:34
AP[2].BARS:**
AP[2].SECURITY:WPA1 WPA2
AP[3].IN-USE:
AP[3].SSID:wlan0-ap-2
AP[3].MODE:Infrastruktura
AP[3].CHAN:1
AP[3].RATE:54Mb/s
AP[3].SIGNAL:29
AP[3].BARS:*
AP[3].SECURITY:WPA1 WPA2
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,16 @@
location: clients/tests/test-client.py:518:test_002()/13
cmd: $NMCLI -f AP -mode tabular d show wlan0
lang: pl_PL.UTF-8
returncode: 0
stdout: 338 bytes
>>>
NAME IN-USE SSID MODE CHAN RATE SIGNAL BARS SECURITY
AP[1] wlan0-ap-3 Infrastruktura 1 54Mb/s 61 *** WPA1 WPA2
AP[2] wlan0-ap-1 Infrastruktura 1 54Mb/s 34 ** WPA1 WPA2
AP[3] wlan0-ap-2 Infrastruktura 1 54Mb/s 29 * WPA1 WPA2
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,20 @@
location: clients/tests/test-client.py:519:test_002()/14
cmd: $NMCLI -f AP -mode tabular -p d show wlan0
lang: pl_PL.UTF-8
returncode: 0
stdout: 530 bytes
>>>
===================================
Informacje o urządzeniu (wlan0)
===================================
NAME IN-USE SSID MODE CHAN RATE SIGNAL BARS SECURITY
-----------------------------------------------------------------------------------
AP[1] wlan0-ap-3 Infrastruktura 1 54Mb/s 61 *** WPA1 WPA2
AP[2] wlan0-ap-1 Infrastruktura 1 54Mb/s 34 ** WPA1 WPA2
AP[3] wlan0-ap-2 Infrastruktura 1 54Mb/s 29 * WPA1 WPA2
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,15 @@
location: clients/tests/test-client.py:520:test_002()/15
cmd: $NMCLI -f AP -mode tabular -t d show wlan0
lang: pl_PL.UTF-8
returncode: 0
stdout: 192 bytes
>>>
AP[1]: :wlan0-ap-3:Infrastruktura:1:54Mb/s:61:*** :WPA1 WPA2
AP[2]: :wlan0-ap-1:Infrastruktura:1:54Mb/s:34:** :WPA1 WPA2
AP[3]: :wlan0-ap-2:Infrastruktura:1:54Mb/s:29:* :WPA1 WPA2
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,14 @@
location: clients/tests/test-client.py:522:test_002()/16
cmd: $NMCLI c
lang: C
returncode: 0
stdout: 126 bytes
>>>
NAME UUID TYPE DEVICE
con-1 5fcfd6d7-1e63-3332-8826-a7eda103792d ethernet --
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,33 @@
location: clients/tests/test-client.py:524:test_002()/17
cmd: $NMCLI c s con-1
lang: C
returncode: 0
stdout: 990 bytes
>>>
connection.id: con-1
connection.uuid: 5fcfd6d7-1e63-3332-8826-a7eda103792d
connection.stable-id: --
connection.type: 802-3-ethernet
connection.interface-name: --
connection.autoconnect: yes
connection.autoconnect-priority: 0
connection.autoconnect-retries: -1 (default)
connection.auth-retries: -1
connection.timestamp: 0
connection.read-only: no
connection.permissions: --
connection.zone: --
connection.master: --
connection.slave-type: --
connection.autoconnect-slaves: -1 (default)
connection.secondaries: --
connection.gateway-ping-timeout: 0
connection.metered: unknown
connection.lldp: default
connection.mdns: -1 (default)
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,13 @@
location: clients/tests/test-client.py:534:test_003()/1
cmd: $NMCLI c add type ethernet ifname '*' con-name con-xx1
lang: C
returncode: 0
stdout: 80 bytes
>>>
Connection 'con-xx1' (UUID-con-xx1-REPLACED-REPLACED-REPLA) successfully added.
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,15 @@
location: clients/tests/test-client.py:537:test_003()/2
cmd: $NMCLI c s
lang: C
returncode: 0
stdout: 195 bytes
>>>
NAME UUID TYPE DEVICE
con-1 5fcfd6d7-1e63-3332-8826-a7eda103792d ethernet --
con-xx1 UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet --
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,13 @@
location: clients/tests/test-client.py:542:test_003()/3
cmd: $NMCLI c add type ethernet ifname '*'
lang: C
returncode: 0
stdout: 81 bytes
>>>
Connection 'ethernet' (UUID-ethernet-REPLACED-REPLACED-REPL) successfully added.
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,16 @@
location: clients/tests/test-client.py:545:test_003()/4
cmd: $NMCLI c s
lang: C
returncode: 0
stdout: 264 bytes
>>>
NAME UUID TYPE DEVICE
con-1 5fcfd6d7-1e63-3332-8826-a7eda103792d ethernet --
con-xx1 UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet --
ethernet UUID-ethernet-REPLACED-REPLACED-REPL ethernet --
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,16 @@
location: clients/tests/test-client.py:547:test_003()/5
cmd: $NMCLI c s
lang: pl_PL.UTF-8
returncode: 0
stdout: 264 bytes
>>>
NAME UUID TYPE DEVICE
con-1 5fcfd6d7-1e63-3332-8826-a7eda103792d ethernet --
con-xx1 UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet --
ethernet UUID-ethernet-REPLACED-REPLACED-REPL ethernet --
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,16 @@
location: clients/tests/test-client.py:550:test_003()/6
cmd: $NMCLI -f ALL c s
lang: C
returncode: 0
stdout: 912 bytes
>>>
NAME UUID TYPE TIMESTAMP TIMESTAMP-REAL AUTOCONNECT AUTOCONNECT-PRIORITY READONLY DBUS-PATH ACTIVE DEVICE STATE ACTIVE-PATH SLAVE
con-1 5fcfd6d7-1e63-3332-8826-a7eda103792d ethernet 0 never yes 0 no /org/freedesktop/NetworkManager/Settings/Connection/1 no -- -- -- --
con-xx1 UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet 0 never yes 0 no /org/freedesktop/NetworkManager/Settings/Connection/2 no -- -- -- --
ethernet UUID-ethernet-REPLACED-REPLACED-REPL ethernet 0 never yes 0 no /org/freedesktop/NetworkManager/Settings/Connection/3 no -- -- -- --
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,16 @@
location: clients/tests/test-client.py:552:test_003()/7
cmd: $NMCLI -f ALL c s
lang: pl_PL.UTF-8
returncode: 0
stdout: 912 bytes
>>>
NAME UUID TYPE TIMESTAMP TIMESTAMP-REAL AUTOCONNECT AUTOCONNECT-PRIORITY READONLY DBUS-PATH ACTIVE DEVICE STATE ACTIVE-PATH SLAVE
con-1 5fcfd6d7-1e63-3332-8826-a7eda103792d ethernet 0 nigdy tak 0 nie /org/freedesktop/NetworkManager/Settings/Connection/1 nie -- -- -- --
con-xx1 UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet 0 nigdy tak 0 nie /org/freedesktop/NetworkManager/Settings/Connection/2 nie -- -- -- --
ethernet UUID-ethernet-REPLACED-REPLACED-REPL ethernet 0 nigdy tak 0 nie /org/freedesktop/NetworkManager/Settings/Connection/3 nie -- -- -- --
<<<
stderr: 0 bytes
>>>
<<<

View File

@@ -0,0 +1,22 @@
location: clients/tests/test-client.py:556:test_003()/8
cmd: $NMCLI --complete-args -f ALL c s ''
lang: pl_PL.UTF-8
returncode: 0
stdout: 64 bytes
>>>
--active
--order
apath
con-1
con-xx1
ethernet
help
id
path
uuid
<<<
stderr: 0 bytes
>>>
<<<

603
clients/tests/test-client.py Executable file
View File

@@ -0,0 +1,603 @@
#!/usr/bin/env python
from __future__ import print_function
import sys
import os
import errno
import unittest
import socket
import itertools
import subprocess
import shlex
import re
import dbus
import time
import dbus.service
import dbus.mainloop.glib
# The test can be configured via the following environment variables:
ENV_NM_TEST_CLIENT_BUILDDIR = 'NM_TEST_CLIENT_BUILDDIR'
ENV_NM_TEST_CLIENT_NMCLI_PATH = 'NM_TEST_CLIENT_NMCLI_PATH'
ENV_NM_TEST_CLIENT_CHECK_L10N = 'NM_TEST_CLIENT_CHECK_L10N'
ENV_NM_TEST_REGENERATE = 'NM_TEST_REGENERATE'
###############################################################################
class PathConfiguration:
@staticmethod
def srcdir():
# this is the directory where the test script itself lies.
# Based on this directory, we find other parts that we expect
# in the source repository.
return os.path.dirname(os.path.abspath(__file__))
@staticmethod
def top_srcdir():
return os.path.abspath(PathConfiguration.srcdir() + "/../..")
@staticmethod
def test_networkmanager_service_path():
v = os.path.abspath(PathConfiguration.top_srcdir() + "/tools/test-networkmanager-service.py")
assert os.path.exists(v), ("Cannot find test server at \"%s\"" % (v))
return v
###############################################################################
os.sys.path.append(os.path.abspath(PathConfiguration.top_srcdir() + '/examples/python'))
import nmex
dbus_session_inited = False
_DEFAULT_ARG = object()
###############################################################################
class Util:
@staticmethod
def python_has_version(major, minor = 0):
return sys.version_info[0] > major \
or ( sys.version_info[0] == major \
and sys.version_info[1] >= minor)
@staticmethod
def is_string(s):
if Util.python_has_version(3):
t = str
else:
t = basestring
return isinstance(s, t)
_find_unsafe = re.compile(r'[^\w@%+=:,./-]',
re.ASCII if sys.version_info[0] >= 3 else 0).search
@staticmethod
def quote(s):
if Util.python_has_version(3, 3):
return shlex.quote(s)
if not s:
return "''"
if Util._find_unsafe(s) is None:
return s
return "'" + s.replace("'", "'\"'\"'") + "'"
@staticmethod
def popen_wait(p, timeout = None):
# wait() has a timeout argument only since 3.3
if Util.python_has_version(3, 3):
return p.wait(timeout)
if timeout is None:
return p.wait()
start = nmex.nm_boot_time_ns()
while True:
if p.poll() is not None:
return p.returncode
if start + (timeout * 1000000000) < nmex.nm_boot_time_ns():
raise Exception("timeout expired")
time.sleep(0.05)
@staticmethod
def iter_single(itr, min_num = 1, max_num = 1):
itr = list(itr)
n = 0
v = None
for c in itr:
n += 1
if n > 1:
break
v = c
if n < min_num:
raise AssertionError("Expected at least %s elements, but %s found" % (min_num, n))
if n > max_num:
raise AssertionError("Expected at most %s elements, but %s found" % (max_num, n))
return v
###############################################################################
class Configuration:
def __init__(self):
self._values = {}
def get(self, name):
v = self._values.get(name, None)
if name in self._values:
return v
if name == ENV_NM_TEST_CLIENT_BUILDDIR:
v = os.environ.get(ENV_NM_TEST_CLIENT_BUILDDIR, PathConfiguration.top_srcdir())
if not os.path.isdir(v):
raise Exception("Missing builddir. Set NM_TEST_CLIENT_BUILDDIR?")
elif name == ENV_NM_TEST_CLIENT_NMCLI_PATH:
v = os.environ.get(ENV_NM_TEST_CLIENT_NMCLI_PATH, None)
if v is None:
try:
v = os.path.abspath(self.get(ENV_NM_TEST_CLIENT_BUILDDIR) + "/clients/cli/nmcli")
except:
pass
if not os.path.exists(v):
raise Exception("Missing nmcli binary. Set NM_TEST_CLIENT_NMCLI_PATH?")
elif name == ENV_NM_TEST_CLIENT_CHECK_L10N:
# if we test locales other than 'C', the output of nmcli depends on whether
# nmcli can load the translations. Unfortunately, I cannot find a way to
# make gettext use the po/*.gmo files from the build-dir.
#
# hence, such tests only work, if you also issue `make-install`
#
# Only by setting NM_TEST_CLIENT_CHECK_L10N=1, these tests are included
# as well.
v = (os.environ.get(ENV_NM_TEST_CLIENT_CHECK_L10N, '0') == '1')
elif name == ENV_NM_TEST_REGENERATE:
# in the "regenerate" mode, the tests will rewrite the files on disk against
# which we assert. That is useful, if there are intentional changes and
# we want to regenerate the expected output.
v = (os.environ.get(ENV_NM_TEST_REGENERATE, '0') == '1')
else:
raise Exception()
self._values[name] = v
return v
conf = Configuration()
###############################################################################
class NMStubServer:
@staticmethod
def _conn_get_main_object(conn):
try:
return conn.get_object('org.freedesktop.NetworkManager', '/org/freedesktop/NetworkManager')
except:
return None
def __init__(self):
service_path = PathConfiguration.test_networkmanager_service_path()
self._conn = dbus.SessionBus()
p = subprocess.Popen([sys.executable, service_path],
stdin = subprocess.PIPE)
start = nmex.nm_boot_time_ns()
while True:
if p.poll() is not None:
p.stdin.close()
if p.returncode == 77:
raise unittest.SkipTest('the stub service %s exited with status 77' % (service_path))
raise Exception('the stub service %s exited unexpectedly' % (service_path))
nmobj = self._conn_get_main_object(self._conn)
if nmobj is not None:
break
if (nmex.nm_boot_time_ns() - start) / 1000000 >= 2000:
p.stdin.close()
p.kill()
Util.popen_wait(p, 1000)
raise Exception("after starting stub service the D-Bus name was not claimed in time")
self._nmobj = nmobj
self._nmiface = dbus.Interface(nmobj, "org.freedesktop.NetworkManager.LibnmGlibTest")
self._p = p
def shutdown(self):
self._nmobj = None
self._nmiface = None
self._conn = None
self._p.stdin.close()
self._p.kill()
Util.popen_wait(self._p, 1000)
self._p = None
if self._conn_get_main_object(self._conn) is not None:
raise Exception("Stub service is not still here although it should shut down")
class _MethodProxy:
def __init__(self, parent, method_name):
self._parent = parent
self._method_name = method_name
def __call__(self, *args, **kwargs):
dbus_iface = kwargs.pop('dbus_iface', None)
if dbus_iface is None:
dbus_iface = self._parent._nmiface
method = dbus_iface.get_dbus_method(self._method_name)
if kwargs:
# for convenience, we allow the caller to specify arguments
# as kwargs. In this case, we construct a a{sv} array as last argument.
kwargs2 = {}
args = list(args)
args.append(kwargs2)
for k in kwargs.keys():
kwargs2[k] = kwargs[k]
return method(*args)
def __getattr__(self, member):
if not member.startswith("op_"):
raise AttributeError(member)
return self._MethodProxy(self, member[3:])
def addConnection(self, connection, verify_connection = True):
return self.op_AddConnection(connection, verify_connection)
def findConnectionUuid(self, con_id):
try:
u = Util.iter_single(self.op_FindConnections(con_id = con_id))[1]
assert u, ("Invalid uuid %s" % (u))
except Exception as e:
raise AssertionError("Unexpectedly not found connection %s: %s" % (con_id, str(e)))
return u
###############################################################################
class NmTestBase(unittest.TestCase):
pass
class TestNmcli(NmTestBase):
@staticmethod
def _replace(text, replace_arr):
if not replace_arr:
return text
text = [text]
for replace in replace_arr:
try:
v_search = replace[0]()
except TypeError:
v_search = replace[0]
assert v_search is None or Util.is_string(v_search)
if not v_search:
continue
v_replace = replace[1]
v_search = v_search.encode('utf-8')
v_replace = v_replace.encode('utf-8')
text2 = []
for t in text:
if isinstance(t, tuple):
text2.append(t)
continue
t2 = t.split(v_search)
text2.append(t2[0])
for t3 in t2[1:]:
text2.append( (v_replace,) )
text2.append(t3)
text = text2
return b''.join([(t[0] if isinstance(t, tuple) else t) for t in text])
def call_nmcli(self,
args,
lang = None,
check_on_disk = _DEFAULT_ARG,
expected_returncode = _DEFAULT_ARG,
expected_stdout = _DEFAULT_ARG,
expected_stderr = _DEFAULT_ARG,
replace_stdout = None,
replace_stderr = None,
sort_lines_stdout = False):
frame = sys._getframe(1)
calling_fcn = frame.f_code.co_name
calling_num = self._calling_num.get(calling_fcn, 0) + 1
self._calling_num[calling_fcn] = calling_num
if lang is None or lang == 'C':
lang = 'C'
language = ''
elif lang is 'de':
lang = 'de_DE.utf8'
language = 'de'
elif lang is 'pl':
lang = 'pl_PL.UTF-8'
language = 'pl'
else:
self.fail('invalid language %s' % (lang))
env = {}
for k in ['LD_LIBRARY_PATH',
'DBUS_SESSION_BUS_ADDRESS']:
val = os.environ.get(k, None)
if val is not None:
env[k] = val
env['LANG'] = lang
env['LANGUAGE'] = language
env['LIBNM_USE_SESSION_BUS'] = '1'
env['LIBNM_USE_NO_UDEV'] = '1'
env['TERM'] = 'linux'
args = [conf.get(ENV_NM_TEST_CLIENT_NMCLI_PATH)] + list(args)
p = subprocess.Popen(args,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
env = env)
Util.popen_wait(p, 2000)
(returncode, stdout, stderr) = (p.returncode, p.stdout.read(), p.stderr.read())
p.stdout.close()
p.stderr.close()
stdout = self._replace(stdout, replace_stdout)
stderr = self._replace(stderr, replace_stderr)
if sort_lines_stdout:
stdout = b'\n'.join(sorted(stdout.split(b'\n')))
ignore_l10n_diff = ( lang != 'C'
and not conf.get(ENV_NM_TEST_CLIENT_CHECK_L10N))
test_name = '%s-%03d' % (calling_fcn, calling_num)
if check_on_disk is _DEFAULT_ARG:
check_on_disk = ( expected_returncode is _DEFAULT_ARG
and expected_stdout is _DEFAULT_ARG
and expected_stderr is _DEFAULT_ARG)
if expected_returncode is _DEFAULT_ARG:
expected_returncode = None
if expected_stdout is _DEFAULT_ARG:
expected_stdout = None
if expected_stderr is _DEFAULT_ARG:
expected_stderr = None
if expected_stderr is not None:
if expected_stderr != stderr:
if ignore_l10n_diff:
self._skip_test_for_l10n_diff.append(test_name)
else:
self.assertEqual(expected_stderr, stderr)
if expected_stdout is not None:
if expected_stdout != stdout:
if ignore_l10n_diff:
self._skip_test_for_l10n_diff.append(test_name)
else:
self.assertEqual(expected_stdout, stdout)
if expected_returncode is not None:
self.assertEqual(expected_returncode, returncode)
dirname = PathConfiguration.srcdir() + '/test-client.check-on-disk'
filename = os.path.abspath(dirname + '/' + test_name + '.expected')
if not check_on_disk:
if os.path.exists(filename):
self.fail("The file '%s' exists, although we expect it not to." % (filename))
return
try:
with open(filename, 'rb') as content_file:
content_old = content_file.read()
except:
content_old = None
# we cannot use frame.f_code.co_filename directly, because it might be different depending
# on where the file lies and which is CWD. We still want to give the location of
# the file, so that the user can easier find the source (when looking at the .expected files)
script_filename = 'clients/tests/test-client.py'
self.assertTrue(os.path.abspath(frame.f_code.co_filename).endswith(script_filename))
calling_location = '%s:%d:%s()/%d' % (script_filename, frame.f_lineno, frame.f_code.co_name, calling_num)
content_new = ('location: %s\n' % (calling_location)).encode('utf8') + \
('cmd: $NMCLI %s\n' % (' '.join([Util.quote(a) for a in args[1:]]))).encode('utf8') + \
('lang: %s\n' % (lang)).encode('utf8') + \
('returncode: %d\n' % (returncode)).encode('utf8') + \
('stdout: %d bytes\n>>>\n' % (len(stdout))).encode('utf8') + \
stdout + \
('\n<<<\nstderr: %d bytes\n>>>\n' % (len(stderr))).encode('utf8') + \
stderr + \
'\n<<<\n'.encode('utf8')
w = conf.get(ENV_NM_TEST_REGENERATE)
if content_old is not None:
if content_old == content_new:
return
if not w:
if ignore_l10n_diff:
self._skip_test_for_l10n_diff.append(test_name)
return
print("\n\n\nThe file '%s' does not have the expected content:" % (filename))
print("ACTUAL OUTPUT:\n[[%s]]\n" % (content_new))
print("EXPECT OUTPUT:\n[[%s]]\n" % (content_old))
print("Let the test write the file by rerunning with NM_TEST_REGENERATE=1\n\n")
raise AssertionError("Unexpected output of command, expected %s. Rerun test with NM_TEST_REGENERATE=1 to regenerate files" % (filename))
else:
if not w:
self.fail("The file '%s' does not exist. Let the test write the file by rerunning with NM_TEST_REGENERATE=1" % (filename))
try:
if not os.path.exists(dirname):
os.makedirs(dirname)
with open(filename, 'wb') as content_file:
content_file.write(content_new)
except Exception as e:
self.fail("Failure to write '%s': %s" % (filename, e))
def setUp(self):
if not dbus_session_inited:
self.skipTest("Own D-Bus session for testing is not initialized. Do you have dbus-run-session available?")
self.srv = NMStubServer()
self._calling_num = {}
self._skip_test_for_l10n_diff = []
def tearDown(self):
self.srv.shutdown()
self.srv = None
self._calling_num = None
if self._skip_test_for_l10n_diff:
# nmcli loads translations from the installation path. This failure commonly
# happens because you did not install the binary in the --prefix, before
# running the test. Hence, translations are not available or differ.
msg = "Skipped asserting for localized tests %s. Set NM_TEST_CLIENT_CHECK_L10N=1 to force fail." % (','.join(self._skip_test_for_l10n_diff))
if Util.python_has_version(3):
# python2 does not suppot skipping the test during tearDown()
self.skipTest(msg)
print(msg + "\n")
self._skip_test_for_l10n_diff = None
def init_001(self):
self.srv.op_AddObj('WiredDevice',
iface = 'eth0')
self.srv.op_AddObj('WifiDevice',
iface = 'wlan0')
self.srv.op_AddObj('WifiDevice',
iface = 'wlan1')
# add another device with an identical ifname. The D-Bus API itself
# does not enforce the ifnames are unique.
self.srv.op_AddObj('WifiDevice',
ident = 'wlan1/x',
iface = 'wlan1')
self.srv.op_AddObj('WifiAp',
device = 'wlan0')
self.srv.op_AddObj('WifiAp',
device = 'wlan0')
self.srv.op_AddObj('WifiAp',
device = 'wlan0')
self.srv.op_AddObj('WifiAp',
device = 'wlan1')
self.srv.addConnection( {
'connection': {
'type': '802-3-ethernet',
'id': 'con-1',
},
})
def test_001(self):
self.call_nmcli([])
self.call_nmcli([], lang = 'pl')
self.call_nmcli(['-f', 'AP', '-mode', 'multiline', '-p', 'd', 'show', 'wlan0'])
self.call_nmcli(['-f', 'AP', '-mode', 'multiline', '-p', 'd', 'show', 'wlan0'], lang = 'de')
self.call_nmcli(['c', 's'])
self.call_nmcli(['bogus', 's'])
def test_002(self):
self.init_001()
self.call_nmcli(['d'])
self.call_nmcli(['-f', 'all', 'd'])
self.call_nmcli([])
self.call_nmcli(['-f', 'AP', '-mode', 'multiline', 'd', 'show', 'wlan0'])
self.call_nmcli(['-f', 'AP', '-mode', 'multiline', '-p', 'd', 'show', 'wlan0'])
self.call_nmcli(['-f', 'AP', '-mode', 'multiline', '-t', 'd', 'show', 'wlan0'])
self.call_nmcli(['-f', 'AP', '-mode', 'tabular', 'd', 'show', 'wlan0'])
self.call_nmcli(['-f', 'AP', '-mode', 'tabular', '-p', 'd', 'show', 'wlan0'])
self.call_nmcli(['-f', 'AP', '-mode', 'tabular', '-t', 'd', 'show', 'wlan0'])
self.call_nmcli(['-f', 'AP', '-mode', 'multiline', 'd', 'show', 'wlan0'], lang = 'pl')
self.call_nmcli(['-f', 'AP', '-mode', 'multiline', '-p', 'd', 'show', 'wlan0'], lang = 'pl')
self.call_nmcli(['-f', 'AP', '-mode', 'multiline', '-t', 'd', 'show', 'wlan0'], lang = 'pl')
self.call_nmcli(['-f', 'AP', '-mode', 'tabular', 'd', 'show', 'wlan0'], lang = 'pl')
self.call_nmcli(['-f', 'AP', '-mode', 'tabular', '-p', 'd', 'show', 'wlan0'], lang = 'pl')
self.call_nmcli(['-f', 'AP', '-mode', 'tabular', '-t', 'd', 'show', 'wlan0'], lang = 'pl')
self.call_nmcli(['c'])
self.call_nmcli(['c', 's', 'con-1'])
def test_003(self):
self.init_001()
replace_stdout = []
replace_stdout.append((lambda: self.srv.findConnectionUuid('con-xx1'), 'UUID-con-xx1-REPLACED-REPLACED-REPLA'))
self.call_nmcli(['c', 'add', 'type', 'ethernet', 'ifname', '*', 'con-name', 'con-xx1'],
replace_stdout = replace_stdout)
self.call_nmcli(['c', 's'],
replace_stdout = replace_stdout)
replace_stdout.append((lambda: self.srv.findConnectionUuid('ethernet'), 'UUID-ethernet-REPLACED-REPLACED-REPL'))
self.call_nmcli(['c', 'add', 'type', 'ethernet', 'ifname', '*'],
replace_stdout = replace_stdout)
self.call_nmcli(['c', 's'],
replace_stdout = replace_stdout)
self.call_nmcli(['c', 's'], lang = 'pl',
replace_stdout = replace_stdout)
self.call_nmcli(['-f', 'ALL', 'c', 's'],
replace_stdout = replace_stdout)
self.call_nmcli(['-f', 'ALL', 'c', 's'], lang = 'pl',
replace_stdout = replace_stdout)
self.call_nmcli(['--complete-args', '-f', 'ALL', 'c', 's', ''], lang = 'pl',
replace_stdout = replace_stdout,
sort_lines_stdout = True)
###############################################################################
def main():
global dbus_session_inited
if len(sys.argv) >= 2 and sys.argv[1] == '--started-with-dbus-session':
dbus_session_inited = True
del sys.argv[1]
if not dbus_session_inited:
# we don't have yet our own dbus-session. Reexec ourself with
# a new dbus-session.
try:
try:
os.execlp('dbus-run-session', 'dbus-run-session', '--', sys.executable, __file__, '--started-with-dbus-session', *sys.argv[1:])
except OSError as e:
if e.errno != errno.ENOENT:
raise
# we have no dbus-run-session in path? Fall-through
# to skip tests gracefully
else:
raise Exception('unknown error during exec')
except Exception as e:
assert False, ("Failure to re-exec dbus-run-session: %s" % (str(e)))
if not dbus_session_inited:
# we still don't have a D-Bus session. Probably dbus-run-session is not available.
# retry with dbus-launch
if os.system('type dbus-launch 1>/dev/null') == 0:
try:
os.execlp('bash', 'bash', '-e', '-c',
'eval `dbus-launch --sh-syntax`;\n' + \
'trap "kill $DBUS_SESSION_BUS_PID" EXIT;\n' + \
'\n' + \
' '.join([Util.quote(a) for a in [sys.executable, __file__, '--started-with-dbus-session'] + sys.argv[1:]]) + ' \n' + \
'')
except Exception as e:
m = str(e)
else:
m = 'unknown error'
assert False, ('Failure to re-exec to start script with dbus-launch: %s' % (m))
unittest.main()
if __name__ == '__main__':
main()

View File

@@ -1228,7 +1228,7 @@ else
with_valgrind_suppressions='$(top_srcdir)/valgrind.suppressions'
fi
fi
AC_SUBST(NM_LOG_COMPILER, 'LOG_COMPILER = "$(top_srcdir)/tools/run-nm-test.sh" --called-from-make "$(LIBTOOL)" "$(with_valgrind)" "'"$with_valgrind_suppressions"'" --launch-dbus=auto')
AC_SUBST(NM_LOG_COMPILER, 'LOG_COMPILER = "$(top_srcdir)/tools/run-nm-test.sh" --called-from-make "$(abs_top_builddir)" "$(LIBTOOL)" "$(with_valgrind)" "'"$with_valgrind_suppressions"'" --launch-dbus=auto')
AM_PATH_PYTHON([], [], [PYTHON=python])
AC_SUBST(PYTHON, [$PYTHON])

View File

@@ -155,6 +155,9 @@ test_device_added (void)
DeviceAddedInfo info = { loop, FALSE, FALSE, 0, 0 };
sinfo = nmtstc_service_init ();
if (!nmtstc_service_available (sinfo))
return;
client = nmtstc_nm_client_new ();
devices = nm_client_get_devices (client);
@@ -312,6 +315,9 @@ test_wifi_ap_added_removed (void)
char *expected_path = NULL;
sinfo = nmtstc_service_init ();
if (!nmtstc_service_available (sinfo))
return;
client = nmtstc_nm_client_new ();
/*************************************/
@@ -535,6 +541,9 @@ test_wimax_nsp_added_removed (void)
char *expected_path = NULL;
sinfo = nmtstc_service_init ();
if (!nmtstc_service_available (sinfo))
return;
client = nmtstc_nm_client_new ();
/*************************************/
@@ -720,6 +729,9 @@ test_devices_array (void)
GVariant *ret;
sinfo = nmtstc_service_init ();
if (!nmtstc_service_available (sinfo))
return;
client = nmtstc_nm_client_new ();
/*************************************/
@@ -820,7 +832,8 @@ manager_running_changed (GObject *client,
static void
test_client_manager_running (void)
{
NMClient *client1, *client2;
gs_unref_object NMClient *client1 = NULL;
gs_unref_object NMClient *client2 = NULL;
guint quit_id;
int running_changed = 0;
GError *error = NULL;
@@ -842,6 +855,9 @@ test_client_manager_running (void)
/* Now start the test service. */
sinfo = nmtstc_service_init ();
if (!nmtstc_service_available (sinfo))
return;
client2 = nmtstc_nm_client_new ();
/* client2 should know that NM is running, but the previously-created
@@ -868,9 +884,6 @@ test_client_manager_running (void)
g_assert_cmpint (running_changed, ==, 2);
g_assert (!nm_client_get_manager_running (client1));
g_source_remove (quit_id);
g_object_unref (client1);
g_object_unref (client2);
}
/*****************************************************************************/

View File

@@ -70,6 +70,9 @@ test_add_connection (void)
time_t start, now;
gboolean done = FALSE;
if (!nmtstc_service_available (sinfo))
return;
connection = nm_connection_new ();
s_con = (NMSettingConnection *) nm_setting_connection_new ();
@@ -145,6 +148,9 @@ test_make_invisible (void)
gboolean done = FALSE, has_settings = FALSE;
char *path;
if (!nmtstc_service_available (sinfo))
return;
g_assert (remote != NULL);
/* Listen for the remove event when the connection becomes invisible */
@@ -212,6 +218,9 @@ test_make_visible (void)
char *path;
NMRemoteConnection *new = NULL;
if (!nmtstc_service_available (sinfo))
return;
g_assert (remote != NULL);
/* Wait for the new-connection signal when the connection is visible again */
@@ -292,6 +301,9 @@ test_remove_connection (void)
gboolean done = FALSE;
char *path;
if (!nmtstc_service_available (sinfo))
return;
/* Find a connection to delete */
list = nm_remote_settings_list_connections (settings);
g_assert_cmpint (g_slist_length (list), >, 0);
@@ -360,11 +372,14 @@ settings_service_running_changed (GObject *client,
static void
test_service_running (void)
{
NMRemoteSettings *settings2;
gs_unref_object NMRemoteSettings *settings2 = NULL;
guint quit_id;
int running_changed = 0;
gboolean running;
if (!nmtstc_service_available (sinfo))
return;
loop = g_main_loop_new (NULL, FALSE);
g_object_get (G_OBJECT (settings),
@@ -403,6 +418,7 @@ test_service_running (void)
/* Now restart it */
sinfo = nmtstc_service_init ();
g_assert (nmtstc_service_available (sinfo));
quit_id = g_timeout_add_seconds (5, loop_quit, loop);
g_main_loop_run (loop);
@@ -413,8 +429,6 @@ test_service_running (void)
NM_REMOTE_SETTINGS_SERVICE_RUNNING, &running,
NULL);
g_assert (running == TRUE);
g_object_unref (settings2);
}
/*****************************************************************************/

View File

@@ -110,6 +110,7 @@ typedef struct {
GDBusObjectManager *object_manager;
GCancellable *new_object_manager_cancellable;
struct udev *udev;
bool udev_inited:1;
} NMClientPrivate;
enum {
@@ -2603,8 +2604,13 @@ obj_nm_for_gdbus_object (NMClient *self, GDBusObject *object, GDBusObjectManager
NULL);
if (NM_IS_DEVICE (obj_nm)) {
priv = NM_CLIENT_GET_PRIVATE (self);
if (!priv->udev)
if (G_UNLIKELY (!priv->udev_inited)) {
priv->udev_inited = TRUE;
/* for testing, we don't want to use udev in libnm. */
if (!nm_streq0 (g_getenv ("LIBNM_USE_NO_UDEV"), "1"))
priv->udev = udev_new ();
}
if (priv->udev)
_nm_device_set_udev (NM_DEVICE (obj_nm), priv->udev);
}
g_object_set_qdata_full (G_OBJECT (object), _nm_object_obj_nm_quark (),

View File

@@ -70,6 +70,9 @@ test_device_added (void)
GError *error = NULL;
sinfo = nmtstc_service_init ();
if (!nmtstc_service_available (sinfo))
return;
client = nm_client_new (NULL, &error);
g_assert_no_error (error);
@@ -163,6 +166,9 @@ test_device_added_signal_after_init (void)
GError *error = NULL;
sinfo = nmtstc_service_init ();
if (!nmtstc_service_available (sinfo))
return;
client = nm_client_new (NULL, &error);
g_assert_no_error (error);
@@ -311,6 +317,9 @@ test_wifi_ap_added_removed (void)
char *expected_path = NULL;
sinfo = nmtstc_service_init ();
if (!nmtstc_service_available (sinfo))
return;
client = nm_client_new (NULL, &error);
g_assert_no_error (error);
@@ -510,6 +519,9 @@ test_wimax_nsp_added_removed (void)
char *expected_path = NULL;
sinfo = nmtstc_service_init ();
if (!nmtstc_service_available (sinfo))
return;
client = nm_client_new (NULL, &error);
g_assert_no_error (error);
@@ -686,6 +698,8 @@ test_devices_array (void)
GVariant *ret;
sinfo = nmtstc_service_init ();
if (!nmtstc_service_available (sinfo))
return;
/* Make sure that we test the async codepath in at least one test... */
nm_client_new_async (NULL, new_client_cb, &client);
@@ -778,7 +792,8 @@ nm_running_changed (GObject *client,
static void
test_client_nm_running (void)
{
NMClient *client1, *client2;
gs_unref_object NMClient *client1 = NULL;
gs_unref_object NMClient *client2 = NULL;
guint quit_id;
int running_changed = 0;
GError *error = NULL;
@@ -801,6 +816,9 @@ test_client_nm_running (void)
/* Now start the test service. */
sinfo = nmtstc_service_init ();
if (!nmtstc_service_available (sinfo))
return;
client2 = nm_client_new (NULL, &error);
g_assert_no_error (error);
@@ -828,9 +846,6 @@ test_client_nm_running (void)
g_assert_cmpint (running_changed, ==, 2);
g_assert (!nm_client_get_nm_running (client1));
g_source_remove (quit_id);
g_object_unref (client1);
g_object_unref (client2);
}
typedef struct {
@@ -934,6 +949,9 @@ test_active_connections (void)
GError *error = NULL;
sinfo = nmtstc_service_init ();
if (!nmtstc_service_available (sinfo))
return;
client = nm_client_new (NULL, &error);
g_assert_no_error (error);
@@ -1063,6 +1081,9 @@ test_activate_virtual (void)
GError *error = NULL;
sinfo = nmtstc_service_init ();
if (!nmtstc_service_available (sinfo))
return;
client = nm_client_new (NULL, &error);
g_assert_no_error (error);
@@ -1138,6 +1159,9 @@ test_activate_failed (void)
GError *error = NULL;
sinfo = nmtstc_service_init ();
if (!nmtstc_service_available (sinfo))
return;
client = nm_client_new (NULL, &error);
g_assert_no_error (error);
@@ -1172,6 +1196,9 @@ test_device_connection_compatibility (void)
const char *hw_addr2 = "52:54:00:ab:db:24";
sinfo = nmtstc_service_init ();
if (!nmtstc_service_available (sinfo))
return;
client = nm_client_new (NULL, &error);
g_assert_no_error (error);
@@ -1593,4 +1620,3 @@ main (int argc, char **argv)
return g_test_run ();
}

View File

@@ -63,6 +63,9 @@ test_add_connection (void)
time_t start, now;
gboolean done = FALSE;
if (!nmtstc_service_available (sinfo))
return;
connection = nmtst_create_minimal_connection (TEST_CON_ID, NULL, NM_SETTING_WIRED_SETTING_NAME, NULL);
nm_client_add_connection_async (client,
@@ -137,6 +140,9 @@ test_make_invisible (void)
gboolean has_settings = FALSE;
char *path;
if (!nmtstc_service_available (sinfo))
return;
g_assert (remote != NULL);
/* Listen for the remove event when the connection becomes invisible */
@@ -215,6 +221,9 @@ test_make_visible (void)
char *path;
NMRemoteConnection *new = NULL;
if (!nmtstc_service_available (sinfo))
return;
g_assert (remote != NULL);
/* Wait for the new-connection signal when the connection is visible again */
@@ -304,6 +313,9 @@ test_remove_connection (void)
gboolean done = FALSE;
char *path;
if (!nmtstc_service_available (sinfo))
return;
/* Find a connection to delete */
conns = nm_client_get_connections (client);
g_assert_cmpint (conns->len, >, 0);
@@ -384,6 +396,9 @@ test_add_remove_connection (void)
time_t start, now;
gboolean done = FALSE;
if (!nmtstc_service_available (sinfo))
return;
/* This will cause the test server to immediately delete the connection
* after creating it.
*/
@@ -437,6 +452,9 @@ test_add_bad_connection (void)
time_t start, now;
gboolean done = FALSE;
if (!nmtstc_service_available (sinfo))
return;
/* The test daemon doesn't support bond connections */
connection = nmtst_create_minimal_connection ("bad connection test", NULL, NM_SETTING_BOND_SETTING_NAME, NULL);
@@ -480,6 +498,9 @@ test_save_hostname (void)
gboolean done = FALSE;
GError *error = NULL;
if (!nmtstc_service_available (sinfo))
return;
/* test-networkmanager-service.py requires the hostname to contain a '.' */
nm_client_save_hostname (client, "foo", NULL, &error);
g_assert_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_HOSTNAME);

View File

@@ -247,6 +247,9 @@ test_setup (TestSecretAgentData *sadata, gconstpointer test_data)
GError *error = NULL;
sadata->sinfo = nmtstc_service_init ();
if (!sadata->sinfo)
return;
sadata->client = nm_client_new (NULL, &error);
g_assert_no_error (error);
@@ -311,6 +314,9 @@ test_cleanup (TestSecretAgentData *sadata, gconstpointer test_data)
GVariant *ret;
GError *error = NULL;
if (!sadata->sinfo)
return;
if (sadata->agent) {
if (nm_secret_agent_old_get_registered (sadata->agent)) {
nm_secret_agent_old_unregister (sadata->agent, NULL, &error);
@@ -360,6 +366,9 @@ connection_activated_none_cb (GObject *c,
static void
test_secret_agent_none (TestSecretAgentData *sadata, gconstpointer test_data)
{
if (!nmtstc_service_available (sadata->sinfo))
return;
nm_client_activate_connection_async (sadata->client,
sadata->connection,
sadata->device,
@@ -405,6 +414,9 @@ connection_activated_no_secrets_cb (GObject *c,
static void
test_secret_agent_no_secrets (TestSecretAgentData *sadata, gconstpointer test_data)
{
if (!nmtstc_service_available (sadata->sinfo))
return;
g_signal_connect (sadata->agent, "secret-requested",
G_CALLBACK (secrets_requested_no_secrets_cb),
sadata);
@@ -456,6 +468,9 @@ secrets_requested_cancel_cb (TestSecretAgent *agent,
static void
test_secret_agent_cancel (TestSecretAgentData *sadata, gconstpointer test_data)
{
if (!nmtstc_service_available (sadata->sinfo))
return;
g_signal_connect (sadata->agent, "secret-requested",
G_CALLBACK (secrets_requested_cancel_cb),
sadata);
@@ -510,6 +525,9 @@ secrets_requested_good_cb (TestSecretAgent *agent,
static void
test_secret_agent_good (TestSecretAgentData *sadata, gconstpointer test_data)
{
if (!nmtstc_service_available (sadata->sinfo))
return;
g_signal_connect (sadata->agent, "secret-requested",
G_CALLBACK (secrets_requested_good_cb),
sadata);
@@ -582,6 +600,9 @@ test_secret_agent_auto_register (void)
GError *error = NULL;
sinfo = nmtstc_service_init ();
if (!nmtstc_service_available (sinfo))
return;
loop = g_main_loop_new (NULL, FALSE);
agent = test_secret_agent_new ();
@@ -609,6 +630,8 @@ test_secret_agent_auto_register (void)
/* Restart test service */
sinfo = nmtstc_service_init ();
g_assert (nmtstc_service_available (sinfo));
g_main_loop_run (loop);
g_assert (nm_secret_agent_old_get_registered (agent));

View File

@@ -741,15 +741,13 @@ endif
test_args = [
'--called-from-make',
meson.build_root(),
'',
enable_valgrind ? valgrind.path() : '',
enable_valgrind ? valgrind_suppressions_path : '',
'--launch-dbus=auto'
]
# FIXME
#AC_SUBST(NM_LOG_COMPILER, 'LOG_COMPILER = "$(top_srcdir)/tools/run-nm-test.sh" --called-from-make "$(LIBTOOL)" "$(with_valgrind)" "'"$with_valgrind_suppressions"'" --launch-dbus=auto')
py3 = import('python3')
python = py3.find_python()

View File

@@ -42,18 +42,22 @@ typedef struct {
NMTstcServiceInfo *nmtstc_service_init (void);
void nmtstc_service_cleanup (NMTstcServiceInfo *info);
NMTstcServiceInfo *nmtstc_service_available (NMTstcServiceInfo *info);
static inline void _nmtstc_auto_service_cleanup (NMTstcServiceInfo **info)
{
if (info && *info) {
nmtstc_service_cleanup (*info);
*info = NULL;
nmtstc_service_cleanup (g_steal_pointer (info));
}
}
#define NMTSTC_SERVICE_INFO_SETUP(sinfo) \
NM_PRAGMA_WARNING_DISABLE ("-Wunused-variable") \
__attribute__ ((cleanup(_nmtstc_auto_service_cleanup))) NMTstcServiceInfo *sinfo = nmtstc_service_init (); \
__attribute__ ((cleanup(_nmtstc_auto_service_cleanup))) NMTstcServiceInfo *sinfo = ({ \
NMTstcServiceInfo *_sinfo; \
\
_sinfo = nmtstc_service_init (); \
if (!nmtstc_service_available (_sinfo)) \
return; \
_sinfo; \
}); \
NM_PRAGMA_WARNING_REENABLE
/*****************************************************************************/

View File

@@ -21,6 +21,7 @@
#include "nm-default.h"
#include <string.h>
#include <sys/wait.h>
#include "NetworkManager.h"
#include "nm-dbus-compat.h"
@@ -72,13 +73,60 @@ _libdbus_create_proxy_test (DBusGConnection *bus)
}
#endif
typedef struct {
GMainLoop *mainloop;
GDBusConnection *bus;
int exit_code;
bool exited:1;
bool name_found:1;
} ServiceInitWaitData;
static gboolean
_service_init_wait_probe_name (gpointer user_data)
{
ServiceInitWaitData *data = user_data;
if (!name_exists (data->bus, "org.freedesktop.NetworkManager"))
return G_SOURCE_CONTINUE;
data->name_found = TRUE;
g_main_loop_quit (data->mainloop);
return G_SOURCE_REMOVE;
}
static void
_service_init_wait_child_wait (GPid pid,
gint status,
gpointer user_data)
{
ServiceInitWaitData *data = user_data;
data->exited = TRUE;
data->exit_code = status;
g_main_loop_quit (data->mainloop);
}
NMTstcServiceInfo *
nmtstc_service_available (NMTstcServiceInfo *info)
{
gs_free char *m = NULL;
if (info)
return info;
/* This happens, when test-networkmanager-service.py exits with 77 status
* code. */
m = g_strdup_printf ("missing dependency for running NetworkManager stub service %s", TEST_NM_SERVICE);
g_test_skip (m);
return NULL;
}
NMTstcServiceInfo *
nmtstc_service_init (void)
{
NMTstcServiceInfo *info;
const char *args[] = { TEST_NM_PYTHON, TEST_NM_SERVICE, NULL };
GError *error = NULL;
int i;
info = g_malloc0 (sizeof (*info));
@@ -90,18 +138,55 @@ nmtstc_service_init (void)
* make sure the service exits if the test program crashes.
*/
g_spawn_async_with_pipes (NULL, (char **) args, NULL,
G_SPAWN_SEARCH_PATH,
G_SPAWN_SEARCH_PATH
| G_SPAWN_DO_NOT_REAP_CHILD,
NULL, NULL,
&info->pid, &info->keepalive_fd, NULL, NULL, &error);
g_assert_no_error (error);
/* Wait until the service is registered on the bus */
for (i = 1000; i > 0; i--) {
if (name_exists (info->bus, "org.freedesktop.NetworkManager"))
break;
g_usleep (G_USEC_PER_SEC / 50);
{
nm_auto_unref_gsource GSource *timeout_source = NULL;
nm_auto_unref_gsource GSource *child_source = NULL;
GMainContext *context = g_main_context_new ();
ServiceInitWaitData data = {
.bus = info->bus,
.mainloop = g_main_loop_new (context, FALSE),
};
gboolean had_timeout;
timeout_source = g_timeout_source_new (50);
g_source_set_callback (timeout_source, _service_init_wait_probe_name, &data, NULL);
g_source_attach (timeout_source, context);
child_source = g_child_watch_source_new (info->pid);
g_source_set_callback (child_source, (GSourceFunc)(void (*) (void)) _service_init_wait_child_wait, &data, NULL);
g_source_attach (child_source, context);
had_timeout = !nmtst_main_loop_run (data.mainloop, 3000);
g_source_destroy (timeout_source);
g_source_destroy (child_source);
g_main_loop_unref (data.mainloop);
g_main_context_unref (context);
if (had_timeout)
g_error ("test service %s did not start in time", TEST_NM_SERVICE);
if (!data.name_found) {
g_assert (data.exited);
info->pid = NM_PID_T_INVAL;
nmtstc_service_cleanup (info);
if ( WIFEXITED (data.exit_code)
&& WEXITSTATUS (data.exit_code) == 77) {
/* If the stub service exited with status 77 it means that it decided
* that it cannot conduct the tests and the test should be (gracefully)
* skip. The likely reason for that, is that libnm is not available
* via pygobject. */
return NULL;
}
g_error ("test service %s exited with error code %d", TEST_NM_SERVICE, data.exit_code);
}
}
g_assert (i > 0);
/* Grab a proxy to our fake NM service to trigger tests */
info->proxy = g_dbus_proxy_new_sync (info->bus,
@@ -126,26 +211,45 @@ nmtstc_service_init (void)
void
nmtstc_service_cleanup (NMTstcServiceInfo *info)
{
int i;
int ret;
gint64 t;
int status;
g_object_unref (info->proxy);
kill (info->pid, SIGTERM);
if (!info)
return;
/* Wait until the bus notices the service is gone */
for (i = 100; i > 0; i--) {
if (!name_exists (info->bus, "org.freedesktop.NetworkManager"))
break;
g_usleep (G_USEC_PER_SEC / 50);
}
g_assert (i > 0);
nm_close (nm_steal_fd (&info->keepalive_fd));
g_object_unref (info->bus);
nm_close (info->keepalive_fd);
g_clear_object (&info->proxy);
#if (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_GLIB
g_clear_pointer (&info->libdbus.bus, dbus_g_connection_unref);
#endif
if (info->pid != NM_PID_T_INVAL) {
kill (info->pid, SIGTERM);
t = g_get_monotonic_time ();
again_wait:
ret = waitpid (info->pid, &status, WNOHANG);
if (ret == 0) {
if (t + 2000000 < g_get_monotonic_time ()) {
kill (info->pid, SIGKILL);
g_error ("child process %lld did not exit within timeout", (long long) info->pid);
}
g_usleep (G_USEC_PER_SEC / 50);
goto again_wait;
}
if (ret == -1 && errno == EINTR)
goto again_wait;
g_assert (ret == info->pid);
}
g_assert (!name_exists (info->bus, "org.freedesktop.NetworkManager"));
g_clear_object (&info->bus);
memset (info, 0, sizeof (*info));
g_free (info);
}

View File

@@ -153,6 +153,14 @@ _nm_auto_protect_errno (int *p_saved_errno)
}
#define NM_AUTO_PROTECT_ERRNO(errsv_saved) nm_auto(_nm_auto_protect_errno) _nm_unused const int errsv_saved = (errno)
static inline void
_nm_auto_unref_gsource (GSource **ptr)
{
if (*ptr)
g_source_unref (g_steal_pointer (ptr));
}
#define nm_auto_unref_gsource nm_auto(_nm_auto_unref_gsource)
/*****************************************************************************/
/* http://stackoverflow.com/a/11172679 */
@@ -1367,4 +1375,6 @@ nm_close (int fd)
return r;
}
#define NM_PID_T_INVAL ((pid_t) -1)
#endif /* __NM_MACROS_INTERNAL_H__ */

View File

@@ -921,33 +921,26 @@ _nmtst_main_loop_run_timeout (gpointer user_data)
{
GMainLoop **p_loop = user_data;
g_assert (p_loop);
g_assert (*p_loop);
g_main_loop_quit (*p_loop);
*p_loop = NULL;
g_assert (p_loop && *p_loop);
g_main_loop_quit (g_steal_pointer (p_loop));
return G_SOURCE_REMOVE;
}
static inline gboolean
nmtst_main_loop_run (GMainLoop *loop, guint timeout_ms)
{
GSource *source = NULL;
guint id = 0;
nm_auto_unref_gsource GSource *source = NULL;
GMainLoop *loopx = loop;
if (timeout_ms > 0) {
source = g_timeout_source_new (timeout_ms);
g_source_set_callback (source, _nmtst_main_loop_run_timeout, &loopx, NULL);
id = g_source_attach (source, g_main_loop_get_context (loop));
g_assert (id);
g_source_unref (source);
g_source_attach (source, g_main_loop_get_context (loop));
}
g_main_loop_run (loop);
if (source && loopx)
if (source)
g_source_destroy (source);
/* if the timeout was reached, return FALSE. */

View File

@@ -34,7 +34,11 @@ else
CALLED_FROM_MAKE=0
fi
BUILDDIR=
if [ "$CALLED_FROM_MAKE" == 1 ]; then
BUILDDIR="$1"
shift
if [ -n "$1" ]; then
NMTST_LIBTOOL=($1 --mode=execute);
else
@@ -144,6 +148,7 @@ else
;;
esac
done
# we support calling the script directly. In this case,
# only pass the path to the test to run.
if test -z "${TEST+x}"; then
@@ -153,6 +158,20 @@ else
NMTST_SUPPRESSIONS="$SCRIPT_PATH/../valgrind.suppressions"
fi
if [[ -z "$NMTST_BUILDDIR" ]]; then
if [[ "${NMTST_BUILDDIR-x}" == x ]]; then
# autodetect
BUILDDIR="$(readlink -f "$TEST")"
while [[ -n "$BUILDDIR" ]]; do
BUILDDIR="$(dirname "$BUILDDIR")"
[[ "$BUILDDIR" == / ]] && BUILDDIR=
[[ -z "$BUILDDIR" ]] && break
[[ -e "$BUILDDIR/libnm/.libs/libnm.so" ]] && break
[[ -e "$BUILDDIR/libnm/libnm.so" ]] && break
done
fi
fi
fi
if [ "$NMTST_SET_DEBUG" == 1 -a -z "${NMTST_DEBUG+x}" ]; then
@@ -198,6 +217,16 @@ fi
[ -x "$TEST" ] || die "Cannot execute test \"$TEST\""
if [[ -n "$BUILDDIR" ]]; then
if [[ -d "$BUILDDIR/libnm" ]]; then
export GI_TYPELIB_PATH="$BUILDDIR/libnm/${GI_TYPELIB_PATH:+:$GI_TYPELIB_PATH}"
if [[ -d "$BUILDDIR/libnm/.libs" ]]; then
export LD_LIBRARY_PATH="$BUILDDIR/libnm/.libs${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
else
export LD_LIBRARY_PATH="$BUILDDIR/libnm${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
fi
fi
fi
if ! _is_true "$NMTST_USE_VALGRIND" 0; then
"${NMTST_DBUS_RUN_SESSION[@]}" \

View File

@@ -3,14 +3,60 @@
from __future__ import print_function
from gi.repository import GLib
import sys
import gi
from gi.repository import GLib
try:
gi.require_version('NM', '1.0')
from gi.repository import NM
except Exception as e:
print("Cannot load gi.NM: %s" % (str(e)))
sys.exit(77)
import dbus
import dbus.service
import dbus.mainloop.glib
import random
import collections
import uuid
import hashlib
_DEFAULT_ARG = object()
#########################################################
class TestError(AssertionError):
def __init__(self, message = 'Unspecified error', errors = None):
AssertionError.__init__(self, message)
self.errors = errors
def pseudorandom_stream(seed, length = None):
seed = str(seed)
v = None
i = 0
while length is None or length > 0:
if not v:
s = seed + str(i)
s = s.encode('utf8')
v = hashlib.sha256(s).hexdigest()
i += 1
yield int(v[0:2], 16)
v = v[2:]
if length is not None:
length -= 1
def pseudorandom_num(seed, v_end, v_start = 0):
n = 0
span = v_end - v_start
for r in pseudorandom_stream(seed):
n = n * 256 + r
if n > span:
break
return v_start + (n % span)
#########################################################
mainloop = GLib.MainLoop()
@@ -65,6 +111,7 @@ NM_ACTIVE_CONNECTION_STATE_DEACTIVATING = 3
NM_ACTIVE_CONNECTION_STATE_DEACTIVATED = 4
#########################################################
IFACE_DBUS = 'org.freedesktop.DBus'
class UnknownInterfaceException(dbus.DBusException):
@@ -88,9 +135,21 @@ class ExportedObj(dbus.service.Object):
DBusInterface = collections.namedtuple('DBusInterface', ['dbus_iface', 'get_props_func', 'prop_changed_func'])
def __init__(self, bus, object_path):
def __init__(self, bus, object_path, ident = None):
dbus.service.Object.__init__(self, bus, object_path)
self._bus = bus
# ident is an optional (unique) identifier for the instance.
# The test driver may set it to reference to the object by
# this identifier. For NetworkManager, the real ID of an
# object on D-Bus is the object_path. But that is generated
# by the stub server only after the test user created the
# object. The ident parameter may be specified by the user
# and thus can be hard-coded in the test.
if ident is None:
ident = object_path
self.ident = ident
self.path = object_path
self.__ensure_dbus_ifaces()
object_manager.add_object(self)
@@ -166,7 +225,11 @@ PD_AVAILABLE_CONNECTIONS = "AvailableConnections"
class Device(ExportedObj):
counter = 1
def __init__(self, bus, iface, devtype):
def __init__(self, bus, iface, devtype, ident = None):
if ident is None:
ident = iface
object_path = "/org/freedesktop/NetworkManager/Devices/%d" % Device.counter
Device.counter = Device.counter + 1
@@ -182,7 +245,7 @@ class Device(ExportedObj):
self.available_connections = []
self.add_dbus_interface(IFACE_DEVICE, self.__get_props, Device.PropertiesChanged)
ExportedObj.__init__(self, bus, object_path)
ExportedObj.__init__(self, bus, object_path, ident)
# Properties interface
def __get_props(self):
@@ -226,11 +289,12 @@ class Device(ExportedObj):
###################################################################
def random_mac():
return '%02X:%02X:%02X:%02X:%02X:%02X' % (
random.randint(0, 255), random.randint(0, 255), random.randint(0, 255),
random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
)
def random_mac(seed = None):
if seed is None:
r = tuple([random.randint(0, 255) for x in range(6)])
else:
r = tuple(pseudorandom_stream(seed, 6))
return '%02X:%02X:%02X:%02X:%02X:%02X' % r
###################################################################
IFACE_WIRED = 'org.freedesktop.NetworkManager.Device.Wired'
@@ -242,17 +306,17 @@ PE_CARRIER = "Carrier"
PE_S390_SUBCHANNELS = "S390Subchannels"
class WiredDevice(Device):
def __init__(self, bus, iface, mac, subchannels):
def __init__(self, bus, iface, mac = None, subchannels = None, ident = None):
if mac is None:
self.mac = random_mac()
else:
mac = random_mac(iface if ident is None else ident)
if subchannels is None:
subchannels = dbus.Array(signature = 's')
self.mac = mac
self.carrier = False
self.s390_subchannels = subchannels
self.add_dbus_interface(IFACE_WIRED, self.__get_props, WiredDevice.PropertiesChanged)
Device.__init__(self, bus, iface, NM_DEVICE_TYPE_ETHERNET)
Device.__init__(self, bus, iface, NM_DEVICE_TYPE_ETHERNET, ident)
# Properties interface
def __get_props(self):
@@ -279,13 +343,13 @@ PV_CARRIER = "Carrier"
PV_VLAN_ID = "VlanId"
class VlanDevice(Device):
def __init__(self, bus, iface):
self.mac = random_mac()
def __init__(self, bus, iface, ident = None):
self.mac = random_mac(iface if ident is None else ident)
self.carrier = False
self.vlan_id = 1
self.add_dbus_interface(IFACE_VLAN, self.__get_props, VlanDevice.PropertiesChanged)
Device.__init__(self, bus, iface, NM_DEVICE_TYPE_VLAN)
Device.__init__(self, bus, iface, NM_DEVICE_TYPE_VLAN, ident)
# Properties interface
def __get_props(self):
@@ -315,24 +379,35 @@ PP_STRENGTH = "Strength"
class WifiAp(ExportedObj):
counter = 0
def __init__(self, bus, ssid, mac, flags, wpaf, rsnf, freq):
def __init__(self, bus, ssid, bssid = None, flags = None, wpaf = None, rsnf = None, freq = None, strength = None, ident = None):
path = "/org/freedesktop/NetworkManager/AccessPoint/%d" % WifiAp.counter
WifiAp.counter = WifiAp.counter + 1
if flags is None:
flags = 0x1
if wpaf is None:
wpaf = 0x1cc
if rsnf is None:
rsnf = 0x1cc
if freq is None:
freq = 2412
if bssid is None:
bssid = random_mac(path)
if strength is None:
strength = pseudorandom_num(path, 100)
self.ssid = ssid
if mac:
self.bssid = mac
else:
self.bssid = random_mac()
self.bssid = bssid
self.flags = flags
self.wpaf = wpaf
self.rsnf = rsnf
self.freq = freq
self.strength = random.randint(0, 100)
self.strength = strength
self.strength_counter = 0
self.strength_id = GLib.timeout_add_seconds(10, self.strength_cb, None)
self.add_dbus_interface(IFACE_WIFI_AP, self.__get_props, WifiAp.PropertiesChanged)
ExportedObj.__init__(self, bus, path)
ExportedObj.__init__(self, bus, path, ident)
def __del__(self):
if self.strength_id > 0:
@@ -340,7 +415,8 @@ class WifiAp(ExportedObj):
self.strength_id = 0
def strength_cb(self, ignored):
self.strength = random.randint(0, 100)
self.strength_counter += 1
self.strength = pseudorandom_num(self.path + str(self.strength_counter), 100)
self.__notify(PP_STRENGTH)
return True
@@ -380,13 +456,15 @@ PW_ACTIVE_ACCESS_POINT = "ActiveAccessPoint"
PW_WIRELESS_CAPABILITIES = "WirelessCapabilities"
class WifiDevice(Device):
def __init__(self, bus, iface):
self.mac = random_mac()
def __init__(self, bus, iface, mac = None, ident = None):
if mac is None:
mac = random_mac(iface if ident is None else ident)
self.mac = mac
self.aps = []
self.active_ap = None
self.add_dbus_interface(IFACE_WIFI, self.__get_props, WifiDevice.PropertiesChanged)
Device.__init__(self, bus, iface, NM_DEVICE_TYPE_WIFI)
Device.__init__(self, bus, iface, NM_DEVICE_TYPE_WIFI, ident)
# methods
@dbus.service.method(dbus_interface=IFACE_WIFI, in_signature='', out_signature='ao')
@@ -411,6 +489,7 @@ class WifiDevice(Device):
self.aps.append(ap)
self.__notify(PW_ACCESS_POINTS)
self.AccessPointAdded(to_path(ap))
return ap
@dbus.service.signal(IFACE_WIFI, signature='o')
def AccessPointRemoved(self, ap_path):
@@ -440,12 +519,6 @@ class WifiDevice(Device):
def PropertiesChanged(self, changed):
pass
# test functions
def add_test_ap(self, ssid, mac):
ap = WifiAp(self._bus, ssid, mac, 0x1, 0x1cc, 0x1cc, 2412)
self.add_ap(ap)
return ap
def remove_ap_by_path(self, path):
for ap in self.aps:
if ap.path == path:
@@ -516,14 +589,14 @@ PX_BSID = "Bsid"
PX_ACTIVE_NSP = "ActiveNsp"
class WimaxDevice(Device):
def __init__(self, bus, iface):
self.mac = random_mac()
self.bsid = random_mac()
def __init__(self, bus, iface, ident = None):
self.mac = random_mac(iface if ident is None else ident)
self.bsid = random_mac(iface if ident is None else ident)
self.nsps = []
self.active_nsp = None
self.add_dbus_interface(IFACE_WIMAX, self.__get_props, WimaxDevice.PropertiesChanged)
Device.__init__(self, bus, iface, NM_DEVICE_TYPE_WIMAX)
Device.__init__(self, bus, iface, NM_DEVICE_TYPE_WIMAX, ident)
# methods
@dbus.service.method(dbus_interface=IFACE_WIMAX, in_signature='', out_signature='ao')
@@ -715,11 +788,8 @@ class NetworkManager(ExportedObj):
@dbus.service.method(dbus_interface=IFACE_NM, in_signature='s', out_signature='o')
def GetDeviceByIpIface(self, ip_iface):
for d in self.devices:
# ignore iface/ip_iface distinction for now
if d.iface == ip_iface:
d = self.find_device_first(ip_iface = ip_iface, require = UnknownDeviceException)
return to_path(d)
raise UnknownDeviceException("No device found for the requested iface.")
@dbus.service.method(dbus_interface=IFACE_NM, in_signature='ooo', out_signature='o')
def ActivateConnection(self, conpath, devpath, specific_object):
@@ -731,11 +801,7 @@ class NetworkManager(ExportedObj):
hash = connection.GetSettings()
s_con = hash['connection']
device = None
for d in self.devices:
if d.path == devpath:
device = d
break
device = self.find_device_first(path = devpath)
if not device and s_con['type'] == 'vlan':
ifname = s_con['interface-name']
device = VlanDevice(self._bus, ifname)
@@ -771,14 +837,7 @@ class NetworkManager(ExportedObj):
@dbus.service.method(dbus_interface=IFACE_NM, in_signature='a{sa{sv}}oo', out_signature='oo')
def AddAndActivateConnection(self, connection, devpath, specific_object):
device = None
for d in self.devices:
if d.path == devpath:
device = d
break
if not device:
raise UnknownDeviceException("No device found for the requested iface.")
device = self.find_device_first(path = devpath, require = UnknownDeviceException)
conpath = settings.AddConnection(connection)
return (conpath, self.ActivateConnection(conpath, devpath, specific_object))
@@ -831,11 +890,43 @@ class NetworkManager(ExportedObj):
def DeviceAdded(self, devpath):
pass
def find_devices(self, ident = _DEFAULT_ARG, path = _DEFAULT_ARG, iface = _DEFAULT_ARG, ip_iface = _DEFAULT_ARG):
r = None
for d in self.devices:
if ident is not _DEFAULT_ARG:
if d.ident != ident:
continue
if path is not _DEFAULT_ARG:
if d.path != path:
continue
if iface is not _DEFAULT_ARG:
if d.iface != iface:
continue
if ip_iface is not _DEFAULT_ARG:
# ignore iface/ip_iface distinction for now
if d.iface != ip_iface:
continue
yield d
def find_device_first(self, ident = _DEFAULT_ARG, path = _DEFAULT_ARG, iface = _DEFAULT_ARG, ip_iface = _DEFAULT_ARG, require = None):
r = None
for d in self.find_devices(ident = ident, path = path, iface = iface, ip_iface = ip_iface):
r = d
break
if r is None and require:
if require is TestError:
raise TestError('Device not found')
raise UnknownDeviceException('Device not found')
return r
def add_device(self, device):
if self.find_device_first(ident = device.ident, path = device.path) is not None:
raise TestError("Duplicate device ident=%s / path=%s" % (device.ident, device.path))
self.devices.append(device)
self.__notify(PM_DEVICES)
self.__notify(PM_ALL_DEVICES)
self.DeviceAdded(to_path(device))
return device
@dbus.service.signal(IFACE_NM, signature='o')
def DeviceRemoved(self, devpath):
@@ -880,70 +971,67 @@ class NetworkManager(ExportedObj):
def Quit(self):
mainloop.quit()
@dbus.service.method(IFACE_TEST, in_signature='a{ss}', out_signature='a(sss)')
def FindConnections(self, args):
return [(c.path, c.get_uuid(), c.get_id()) for c in settings.find_connections(**args)]
@dbus.service.method(IFACE_TEST, in_signature='sa{sv}', out_signature='o')
def AddObj(self, class_name, args):
if class_name in ['WiredDevice', 'WifiDevice']:
py_class = globals()[class_name]
d = py_class(self._bus, **args)
return to_path(self.add_device(d))
elif class_name in ['WifiAp']:
if 'device' not in args:
raise TestError('missing "device" paramter')
d = self.find_device_first(ident = args['device'], require = TestError)
del args['device']
if 'ssid' not in args:
args['ssid'] = d.ident + '-ap-' + str(WifiAp.counter + 1)
ap = WifiAp(self._bus, **args)
return to_path(d.add_ap(ap))
raise TestError("Invalid python type \"%s\"" % (class_name))
@dbus.service.method(IFACE_TEST, in_signature='ssas', out_signature='o')
def AddWiredDevice(self, ifname, mac, subchannels):
for d in self.devices:
if d.iface == ifname:
raise PermissionDeniedException("Device already added")
dev = WiredDevice(self._bus, ifname, mac, subchannels)
self.add_device(dev)
return to_path(dev)
return to_path(self.add_device(dev))
@dbus.service.method(IFACE_TEST, in_signature='s', out_signature='o')
def AddWifiDevice(self, ifname):
for d in self.devices:
if d.iface == ifname:
raise PermissionDeniedException("Device already added")
dev = WifiDevice(self._bus, ifname)
self.add_device(dev)
return to_path(dev)
return to_path(self.add_device(dev))
@dbus.service.method(IFACE_TEST, in_signature='s', out_signature='o')
def AddWimaxDevice(self, ifname):
for d in self.devices:
if d.iface == ifname:
raise PermissionDeniedException("Device already added")
dev = WimaxDevice(self._bus, ifname)
self.add_device(dev)
return to_path(dev)
return to_path(self.add_device(dev))
@dbus.service.method(IFACE_TEST, in_signature='o', out_signature='')
def RemoveDevice(self, path):
for d in self.devices:
if d.path == path:
d = self.find_device_first(path = path, require = TestError)
self.remove_device(d)
return
raise UnknownDeviceException("Device not found")
@dbus.service.method(IFACE_TEST, in_signature='sss', out_signature='o')
def AddWifiAp(self, ifname, ssid, mac):
for d in self.devices:
if d.iface == ifname:
return to_path(d.add_test_ap(ssid, mac))
raise UnknownDeviceException("Device not found")
def AddWifiAp(self, ident, ssid, bssid):
d = self.find_device_first(ident = ident, require = TestError)
ap = WifiAp(self._bus, ssid, bssid)
return to_path(d.add_ap(ap))
@dbus.service.method(IFACE_TEST, in_signature='so', out_signature='')
def RemoveWifiAp(self, ifname, ap_path):
for d in self.devices:
if d.iface == ifname:
def RemoveWifiAp(self, ident, ap_path):
d = self.find_device_first(ident = ident, require = TestError)
d.remove_ap_by_path(ap_path)
return
raise UnknownDeviceException("Device not found")
@dbus.service.method(IFACE_TEST, in_signature='ss', out_signature='o')
def AddWimaxNsp(self, ifname, name):
for d in self.devices:
if d.iface == ifname:
def AddWimaxNsp(self, ident, name):
d = self.find_device_first(ident = ident, require = TestError)
return to_path(d.add_test_nsp(name))
raise UnknownDeviceException("Device not found")
@dbus.service.method(IFACE_TEST, in_signature='so', out_signature='')
def RemoveWimaxNsp(self, ifname, nsp_path):
for d in self.devices:
if d.iface == ifname:
def RemoveWimaxNsp(self, ident, nsp_path):
d = self.find_device_first(ident = ident, require = TestError)
d.remove_nsp_by_path(nsp_path)
return
raise UnknownDeviceException("Device not found")
@dbus.service.method(IFACE_TEST, in_signature='', out_signature='')
def AutoRemoveNextConnection(self):
@@ -979,15 +1067,19 @@ class MissingSettingException(dbus.DBusException):
_dbus_error_name = IFACE_CONNECTION + '.MissingSetting'
class Connection(ExportedObj):
def __init__(self, bus, object_path, settings, remove_func, verify_connection=True):
def __init__(self, bus, path_counter, settings, remove_func, verify_connection=True):
path = "/org/freedesktop/NetworkManager/Settings/Connection/%s" % (path_counter)
if self.get_uuid(settings) is None:
if 'connection' not in settings:
settings['connection'] = { }
settings['connection']['uuid'] = uuid.uuid4()
if self.get_id(settings) is None:
settings['connection']['id'] = 'connection-%s' % (path_counter)
if self.get_uuid(settings) is None:
settings['connection']['uuid'] = str(uuid.uuid3(uuid.NAMESPACE_URL, path))
self.verify(settings, verify_strict=verify_connection)
self.path = object_path
self.path = path
self.settings = settings
self.remove_func = remove_func
self.visible = True
@@ -995,7 +1087,16 @@ class Connection(ExportedObj):
self.props['Unsaved'] = False
self.add_dbus_interface(IFACE_CONNECTION, self.__get_props, None)
ExportedObj.__init__(self, bus, object_path)
ExportedObj.__init__(self, bus, path)
def get_id(self, settings=None):
if settings is None:
settings = self.settings
if 'connection' in settings:
s_con = settings['connection']
if 'id' in s_con:
return s_con['id']
return None
def get_uuid(self, settings=None):
if settings is None:
@@ -1082,7 +1183,7 @@ class Settings(ExportedObj):
def __init__(self, bus, object_path):
self.connections = {}
self.bus = bus
self.counter = 1
self.counter = 0
self.remove_next_connection = False
self.props = {}
self.props['Hostname'] = "foobar.baz"
@@ -1098,6 +1199,19 @@ class Settings(ExportedObj):
def get_connection(self, path):
return self.connections[path]
def find_connections(self, path = None, con_id = None, con_uuid = None):
for c in self.connections.values():
if path is not None:
if c.path != path:
continue
if con_id is not None:
if c.get_id() != con_id:
continue
if con_uuid is not None:
if c.get_uuid() != con_uuid:
continue
yield c
@dbus.service.method(dbus_interface=IFACE_SETTINGS, in_signature='', out_signature='ao')
def ListConnections(self):
return self.connections.keys()
@@ -1107,24 +1221,23 @@ class Settings(ExportedObj):
return self.add_connection(settings)
def add_connection(self, settings, verify_connection=True):
path = "/org/freedesktop/NetworkManager/Settings/Connection/{0}".format(self.counter)
con = Connection(self.bus, path, settings, self.delete_connection, verify_connection)
self.counter += 1
con = Connection(self.bus, self.counter, settings, self.delete_connection, verify_connection)
uuid = con.get_uuid()
if uuid in [c.get_uuid() for c in self.connections.values()]:
raise InvalidSettingException('cannot add duplicate connection with uuid %s' % (uuid))
self.counter = self.counter + 1
self.connections[path] = con
self.connections[con.path] = con
self.props['Connections'] = dbus.Array(self.connections.keys(), 'o')
self.NewConnection(path)
self.NewConnection(con.path)
self.__notify('Connections')
if self.remove_next_connection:
self.remove_next_connection = False
self.connections[path].Delete()
self.connections[con.path].Delete()
return path
return con.path
def update_connection(self, connection, path=None, verify_connection=True):
if path is None: