summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2018-05-04 09:02:53 +0200
committerThomas Haller <thaller@redhat.com>2018-05-11 10:59:19 +0200
commit7501037bd8bb302e8ae47109d52189b2a7485322 (patch)
tree198f15c6ebf8247a96e372da5f0d3a8b6242372c
parent9620d78abecaa259993a7b1ba8eb1969a349095f (diff)
downloadNetworkManager-7501037bd8bb302e8ae47109d52189b2a7485322.tar.gz
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.
-rw-r--r--.travis.yml11
-rw-r--r--Makefile.am53
-rw-r--r--clients/tests/test-client.check-on-disk/test_001-001.expected19
-rw-r--r--clients/tests/test-client.check-on-disk/test_001-002.expected21
-rw-r--r--clients/tests/test-client.check-on-disk/test_001-003.expected13
-rw-r--r--clients/tests/test-client.check-on-disk/test_001-004.expected13
-rw-r--r--clients/tests/test-client.check-on-disk/test_001-005.expected13
-rw-r--r--clients/tests/test-client.check-on-disk/test_001-006.expected13
-rw-r--r--clients/tests/test-client.check-on-disk/test_002-001.expected17
-rw-r--r--clients/tests/test-client.check-on-disk/test_002-002.expected17
-rw-r--r--clients/tests/test-client.check-on-disk/test_002-003.expected35
-rw-r--r--clients/tests/test-client.check-on-disk/test_002-004.expected36
-rw-r--r--clients/tests/test-client.check-on-disk/test_002-005.expected42
-rw-r--r--clients/tests/test-client.check-on-disk/test_002-006.expected36
-rw-r--r--clients/tests/test-client.check-on-disk/test_002-007.expected16
-rw-r--r--clients/tests/test-client.check-on-disk/test_002-008.expected20
-rw-r--r--clients/tests/test-client.check-on-disk/test_002-009.expected15
-rw-r--r--clients/tests/test-client.check-on-disk/test_002-010.expected36
-rw-r--r--clients/tests/test-client.check-on-disk/test_002-011.expected42
-rw-r--r--clients/tests/test-client.check-on-disk/test_002-012.expected36
-rw-r--r--clients/tests/test-client.check-on-disk/test_002-013.expected16
-rw-r--r--clients/tests/test-client.check-on-disk/test_002-014.expected20
-rw-r--r--clients/tests/test-client.check-on-disk/test_002-015.expected15
-rw-r--r--clients/tests/test-client.check-on-disk/test_002-016.expected14
-rw-r--r--clients/tests/test-client.check-on-disk/test_002-017.expected33
-rw-r--r--clients/tests/test-client.check-on-disk/test_003-001.expected13
-rw-r--r--clients/tests/test-client.check-on-disk/test_003-002.expected15
-rw-r--r--clients/tests/test-client.check-on-disk/test_003-003.expected13
-rw-r--r--clients/tests/test-client.check-on-disk/test_003-004.expected16
-rw-r--r--clients/tests/test-client.check-on-disk/test_003-005.expected16
-rw-r--r--clients/tests/test-client.check-on-disk/test_003-006.expected16
-rw-r--r--clients/tests/test-client.check-on-disk/test_003-007.expected16
-rw-r--r--clients/tests/test-client.check-on-disk/test_003-008.expected22
-rwxr-xr-xclients/tests/test-client.py600
-rw-r--r--libnm/nm-client.c12
-rwxr-xr-xtools/test-networkmanager-service.py249
36 files changed, 1514 insertions, 76 deletions
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..b5bba886a9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3781,6 +3781,59 @@ EXTRA_DIST += \
clients/tui/newt/meson.build
###############################################################################
+# clients/tests
+###############################################################################
+
+check-clients-tests-test-client: clients/cli/nmcli clients/tests/test-client.py
+ 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-clients-tests-test-client
+
+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..09a1375fd9
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_001-001.expected
@@ -0,0 +1,19 @@
+location: clients/tests/test-client.py:486: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..9f07c3d757
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_001-002.expected
@@ -0,0 +1,21 @@
+location: clients/tests/test-client.py:487: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..155fc5e17e
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_001-003.expected
@@ -0,0 +1,13 @@
+location: clients/tests/test-client.py:489: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..19ecd66ed4
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_001-004.expected
@@ -0,0 +1,13 @@
+location: clients/tests/test-client.py:490: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..3d07beff21
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_001-005.expected
@@ -0,0 +1,13 @@
+location: clients/tests/test-client.py:492: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..51b5259d5d
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_001-006.expected
@@ -0,0 +1,13 @@
+location: clients/tests/test-client.py:494: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..30bde4689f
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_002-001.expected
@@ -0,0 +1,17 @@
+location: clients/tests/test-client.py:499: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..f81d8b5084
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_002-002.expected
@@ -0,0 +1,17 @@
+location: clients/tests/test-client.py:501: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..f100ef7c3f
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_002-003.expected
@@ -0,0 +1,35 @@
+location: clients/tests/test-client.py:503: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..31543e1de5
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_002-004.expected
@@ -0,0 +1,36 @@
+location: clients/tests/test-client.py:505: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..f884359826
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_002-005.expected
@@ -0,0 +1,42 @@
+location: clients/tests/test-client.py:506: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..828dedc284
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_002-006.expected
@@ -0,0 +1,36 @@
+location: clients/tests/test-client.py:507: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..d369c18490
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_002-007.expected
@@ -0,0 +1,16 @@
+location: clients/tests/test-client.py:508: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..7b792a827d
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_002-008.expected
@@ -0,0 +1,20 @@
+location: clients/tests/test-client.py:509: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..1bf46ce66d
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_002-009.expected
@@ -0,0 +1,15 @@
+location: clients/tests/test-client.py:510: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..adb2ae244e
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_002-010.expected
@@ -0,0 +1,36 @@
+location: clients/tests/test-client.py:512: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..1838f8e920
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_002-011.expected
@@ -0,0 +1,42 @@
+location: clients/tests/test-client.py:513: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..4d014e3861
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_002-012.expected
@@ -0,0 +1,36 @@
+location: clients/tests/test-client.py:514: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..c1812c6e9c
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_002-013.expected
@@ -0,0 +1,16 @@
+location: clients/tests/test-client.py:515: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..f810745e22
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_002-014.expected
@@ -0,0 +1,20 @@
+location: clients/tests/test-client.py:516: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..533e2df740
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_002-015.expected
@@ -0,0 +1,15 @@
+location: clients/tests/test-client.py:517: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..5da15ca6b6
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_002-016.expected
@@ -0,0 +1,14 @@
+location: clients/tests/test-client.py:519: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..801b2f53c1
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_002-017.expected
@@ -0,0 +1,33 @@
+location: clients/tests/test-client.py:521: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..831678b5d9
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_003-001.expected
@@ -0,0 +1,13 @@
+location: clients/tests/test-client.py:531: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..1802b3fa5d
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_003-002.expected
@@ -0,0 +1,15 @@
+location: clients/tests/test-client.py:534: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..909812f0a2
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_003-003.expected
@@ -0,0 +1,13 @@
+location: clients/tests/test-client.py:539: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..f6b2ee90f0
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_003-004.expected
@@ -0,0 +1,16 @@
+location: clients/tests/test-client.py:542: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..805470f906
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_003-005.expected
@@ -0,0 +1,16 @@
+location: clients/tests/test-client.py:544: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..b8b41c9825
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_003-006.expected
@@ -0,0 +1,16 @@
+location: clients/tests/test-client.py:547: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..fa2ee0759d
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_003-007.expected
@@ -0,0 +1,16 @@
+location: clients/tests/test-client.py:549: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..4ea899645f
--- /dev/null
+++ b/clients/tests/test-client.check-on-disk/test_003-008.expected
@@ -0,0 +1,22 @@
+location: clients/tests/test-client.py:553: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..bce39a817d
--- /dev/null
+++ b/clients/tests/test-client.py
@@ -0,0 +1,600 @@
+#!/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("The file '%s' does not have the expected content. Let the test write the file by rerunning with NM_TEST_REGENERATE=1" % (filename))
+ self.assertEqual(content_old, content_new);
+ 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: