mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-10-07 00:31:11 +00:00
clients/tests: add python test script for nmcli tests
Add a test which runs nmcli against our stub NetworkManager service and compares the output. The output formats of nmcli are complicated and not easily understood. For example how --mode tabular|multiline interacts with selecting output-fields (--fields) and output modes ([default]|--terse|--pretty). Also, there are things like `nmcli connection show --order $FIELD_SPEC`. We need unit tests to ensure that we don't change the output accidentally.
This commit is contained in:
parent
5e6b0382ad
commit
d4093a3a2c
11
.travis.yml
11
.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:
|
||||
|
|
56
Makefile.am
56
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
|
||||
###############################################################################
|
||||
|
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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.
|
||||
|
||||
<<<
|
|
@ -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.
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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.
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
|
||||
>>>
|
||||
|
||||
<<<
|
|
@ -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
603
clients/tests/test-client.py
Executable 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()
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue