diff --git a/.travis.yml b/.travis.yml index 72969fd847..e92131bf1a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -104,9 +104,16 @@ 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 && - ./contrib/travis/travis-check.sh + 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: diff --git a/Makefile.am b/Makefile.am index a7152bd07c..68faf421e1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3780,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 ############################################################################### diff --git a/clients/tests/test-client.check-on-disk/test_001-001.expected b/clients/tests/test-client.check-on-disk/test_001-001.expected new file mode 100644 index 0000000000..f3e8cf37ab --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_001-001.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_001-002.expected b/clients/tests/test-client.check-on-disk/test_001-002.expected new file mode 100644 index 0000000000..357cf3911b --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_001-002.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_001-003.expected b/clients/tests/test-client.check-on-disk/test_001-003.expected new file mode 100644 index 0000000000..ea06b8d0bb --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_001-003.expected @@ -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. + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_001-004.expected b/clients/tests/test-client.check-on-disk/test_001-004.expected new file mode 100644 index 0000000000..8e58d1493a --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_001-004.expected @@ -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. + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_001-005.expected b/clients/tests/test-client.check-on-disk/test_001-005.expected new file mode 100644 index 0000000000..c24b6cd32f --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_001-005.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_001-006.expected b/clients/tests/test-client.check-on-disk/test_001-006.expected new file mode 100644 index 0000000000..66c0e9917d --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_001-006.expected @@ -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. + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_002-001.expected b/clients/tests/test-client.check-on-disk/test_002-001.expected new file mode 100644 index 0000000000..bc0d4f5dd9 --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_002-001.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_002-002.expected b/clients/tests/test-client.check-on-disk/test_002-002.expected new file mode 100644 index 0000000000..d516e2f849 --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_002-002.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_002-003.expected b/clients/tests/test-client.check-on-disk/test_002-003.expected new file mode 100644 index 0000000000..ff88393cc6 --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_002-003.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_002-004.expected b/clients/tests/test-client.check-on-disk/test_002-004.expected new file mode 100644 index 0000000000..2e29897654 --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_002-004.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_002-005.expected b/clients/tests/test-client.check-on-disk/test_002-005.expected new file mode 100644 index 0000000000..f70e30a4b3 --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_002-005.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_002-006.expected b/clients/tests/test-client.check-on-disk/test_002-006.expected new file mode 100644 index 0000000000..e87dc1d11b --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_002-006.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_002-007.expected b/clients/tests/test-client.check-on-disk/test_002-007.expected new file mode 100644 index 0000000000..78f7bf66cd --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_002-007.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_002-008.expected b/clients/tests/test-client.check-on-disk/test_002-008.expected new file mode 100644 index 0000000000..951ad9ce0d --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_002-008.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_002-009.expected b/clients/tests/test-client.check-on-disk/test_002-009.expected new file mode 100644 index 0000000000..ce7172e346 --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_002-009.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_002-010.expected b/clients/tests/test-client.check-on-disk/test_002-010.expected new file mode 100644 index 0000000000..85b9337157 --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_002-010.expected @@ -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: 54 Mb/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: 54 Mb/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: 54 Mb/s +AP[3].SIGNAL: 29 +AP[3].BARS: * +AP[3].SECURITY: WPA1 WPA2 + +<<< +stderr: 0 bytes +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_002-011.expected b/clients/tests/test-client.check-on-disk/test_002-011.expected new file mode 100644 index 0000000000..e48611f59f --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_002-011.expected @@ -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: 54 Mb/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: 54 Mb/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: 54 Mb/s +AP[3].SIGNAL: 29 +AP[3].BARS: * +AP[3].SECURITY: WPA1 WPA2 +------------------------------------------------------------------------------- + +<<< +stderr: 0 bytes +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_002-012.expected b/clients/tests/test-client.check-on-disk/test_002-012.expected new file mode 100644 index 0000000000..542261c38d --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_002-012.expected @@ -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:54 Mb/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:54 Mb/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:54 Mb/s +AP[3].SIGNAL:29 +AP[3].BARS:* +AP[3].SECURITY:WPA1 WPA2 + +<<< +stderr: 0 bytes +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_002-013.expected b/clients/tests/test-client.check-on-disk/test_002-013.expected new file mode 100644 index 0000000000..54ddb50a32 --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_002-013.expected @@ -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 54 Mb/s 61 *** WPA1 WPA2 +AP[2] wlan0-ap-1 Infrastruktura 1 54 Mb/s 34 ** WPA1 WPA2 +AP[3] wlan0-ap-2 Infrastruktura 1 54 Mb/s 29 * WPA1 WPA2 + +<<< +stderr: 0 bytes +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_002-014.expected b/clients/tests/test-client.check-on-disk/test_002-014.expected new file mode 100644 index 0000000000..ea42ce9a43 --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_002-014.expected @@ -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 54 Mb/s 61 *** WPA1 WPA2 +AP[2] wlan0-ap-1 Infrastruktura 1 54 Mb/s 34 ** WPA1 WPA2 +AP[3] wlan0-ap-2 Infrastruktura 1 54 Mb/s 29 * WPA1 WPA2 + +<<< +stderr: 0 bytes +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_002-015.expected b/clients/tests/test-client.check-on-disk/test_002-015.expected new file mode 100644 index 0000000000..3854822bb3 --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_002-015.expected @@ -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:54 Mb/s:61:*** :WPA1 WPA2 +AP[2]: :wlan0-ap-1:Infrastruktura:1:54 Mb/s:34:** :WPA1 WPA2 +AP[3]: :wlan0-ap-2:Infrastruktura:1:54 Mb/s:29:* :WPA1 WPA2 + +<<< +stderr: 0 bytes +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_002-016.expected b/clients/tests/test-client.check-on-disk/test_002-016.expected new file mode 100644 index 0000000000..452db9a444 --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_002-016.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_002-017.expected b/clients/tests/test-client.check-on-disk/test_002-017.expected new file mode 100644 index 0000000000..88ac43f02f --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_002-017.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_003-001.expected b/clients/tests/test-client.check-on-disk/test_003-001.expected new file mode 100644 index 0000000000..9e37cf9f7a --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_003-001.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_003-002.expected b/clients/tests/test-client.check-on-disk/test_003-002.expected new file mode 100644 index 0000000000..3447e60919 --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_003-002.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_003-003.expected b/clients/tests/test-client.check-on-disk/test_003-003.expected new file mode 100644 index 0000000000..c241bc5bcb --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_003-003.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_003-004.expected b/clients/tests/test-client.check-on-disk/test_003-004.expected new file mode 100644 index 0000000000..2c921be2f4 --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_003-004.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_003-005.expected b/clients/tests/test-client.check-on-disk/test_003-005.expected new file mode 100644 index 0000000000..2ec86c01a1 --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_003-005.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_003-006.expected b/clients/tests/test-client.check-on-disk/test_003-006.expected new file mode 100644 index 0000000000..1e8a29973a --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_003-006.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_003-007.expected b/clients/tests/test-client.check-on-disk/test_003-007.expected new file mode 100644 index 0000000000..e566f474f7 --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_003-007.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.check-on-disk/test_003-008.expected b/clients/tests/test-client.check-on-disk/test_003-008.expected new file mode 100644 index 0000000000..44be3e054e --- /dev/null +++ b/clients/tests/test-client.check-on-disk/test_003-008.expected @@ -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 +>>> + +<<< diff --git a/clients/tests/test-client.py b/clients/tests/test-client.py new file mode 100755 index 0000000000..8afd22c167 --- /dev/null +++ b/clients/tests/test-client.py @@ -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() diff --git a/libnm/nm-client.c b/libnm/nm-client.c index f748512283..18d3e318ce 100644 --- a/libnm/nm-client.c +++ b/libnm/nm-client.c @@ -110,6 +110,7 @@ typedef struct { GDBusObjectManager *object_manager; GCancellable *new_object_manager_cancellable; struct udev *udev; + bool udev_inited:1; } NMClientPrivate; enum { @@ -2603,9 +2604,14 @@ 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) - priv->udev = udev_new (); - _nm_device_set_udev (NM_DEVICE (obj_nm), 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 (), obj_nm, g_object_unref); diff --git a/tools/test-networkmanager-service.py b/tools/test-networkmanager-service.py index 17bd7e28c0..ed435e67f8 100755 --- a/tools/test-networkmanager-service.py +++ b/tools/test-networkmanager-service.py @@ -21,6 +21,40 @@ import dbus.mainloop.glib import random import collections import uuid +import hashlib + +######################################################### + +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() @@ -75,6 +109,7 @@ NM_ACTIVE_CONNECTION_STATE_DEACTIVATING = 3 NM_ACTIVE_CONNECTION_STATE_DEACTIVATED = 4 ######################################################### + IFACE_DBUS = 'org.freedesktop.DBus' class UnknownInterfaceException(dbus.DBusException): @@ -98,9 +133,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) @@ -176,7 +223,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 @@ -192,7 +243,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): @@ -236,11 +287,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' @@ -252,17 +304,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: - self.mac = mac + 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): @@ -289,13 +341,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): @@ -325,24 +377,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: @@ -350,7 +413,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 @@ -390,13 +454,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') @@ -421,6 +487,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): @@ -450,12 +517,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: @@ -526,14 +587,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') @@ -841,11 +902,20 @@ class NetworkManager(ExportedObj): def DeviceAdded(self, devpath): pass + def find_device(self, ident): + for d in self.devices: + if d.ident == ident: + return d + def add_device(self, device): + d = self.find_device(device.ident) + if d: + raise TestError("Device with ident=%s already added (%s)" % (device.ident, d.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): @@ -890,32 +960,43 @@ 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(args['device']) + if not d: + raise TestError('no device "%s" found' % args['device']) + 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): @@ -926,10 +1007,11 @@ class NetworkManager(ExportedObj): 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)) + def AddWifiAp(self, ifname, ssid, bssid): + d = self.find_device(ifname) + if d: + ap = WifiAp(self._bus, ssid, bssid) + return to_path(d.add_ap(ap)) raise UnknownDeviceException("Device not found") @dbus.service.method(IFACE_TEST, in_signature='so', out_signature='') @@ -989,15 +1071,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 'connection' not in settings: + settings['connection'] = { } + if self.get_id(settings) is None: + settings['connection']['id'] = 'connection-%s' % (path_counter) if self.get_uuid(settings) is None: - if 'connection' not in settings: - settings['connection'] = { } - settings['connection']['uuid'] = uuid.uuid4() + 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 @@ -1005,7 +1091,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: @@ -1092,7 +1187,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" @@ -1108,6 +1203,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() @@ -1117,24 +1225,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: