summary refs log tree commit diff
path: root/libnm-glib/tests
diff options
context:
space:
mode:
Diffstat (limited to 'libnm-glib/tests')
-rw-r--r--libnm-glib/tests/Makefile.am36
-rw-r--r--libnm-glib/tests/Makefile.in105
-rwxr-xr-xlibnm-glib/tests/test-fake-nm.py776
-rw-r--r--libnm-glib/tests/test-nm-client.c953
-rw-r--r--libnm-glib/tests/test-remote-settings-client.c24
-rwxr-xr-xlibnm-glib/tests/test-remote-settings-service.py37
6 files changed, 1861 insertions, 70 deletions
diff --git a/libnm-glib/tests/Makefile.am b/libnm-glib/tests/Makefile.am
index 07994481..38f449ac 100644
--- a/libnm-glib/tests/Makefile.am
+++ b/libnm-glib/tests/Makefile.am
@@ -5,20 +5,29 @@ AM_CPPFLAGS = \
 	-I$(top_builddir)/include \
 	-I$(top_srcdir)/libnm-util \
 	-I$(top_builddir)/libnm-util \
-	-I$(top_srcdir)/libnm-glib
+	-I$(top_srcdir)/libnm-glib \
+	-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
+	$(GLIB_CFLAGS) \
+	$(DBUS_CFLAGS)
+
+noinst_PROGRAMS = test-nm-client test-remote-settings-client
+
+####### NMClient and non-settings tests #######
 
-noinst_PROGRAMS = test-remote-settings-client
+test_nm_client_SOURCES = \
+	test-nm-client.c
+
+test_nm_client_LDADD = \
+	$(top_builddir)/libnm-util/libnm-util.la \
+	$(top_builddir)/libnm-glib/libnm-glib-test.la \
+	$(GLIB_LIBS) \
+	$(DBUS_LIBS)
 
 ####### remote settings client test #######
 
 test_remote_settings_client_SOURCES = \
 	test-remote-settings-client.c
 
-test_remote_settings_client_CPPFLAGS = \
-	$(GLIB_CFLAGS) \
-	$(DBUS_CFLAGS) \
-	$(AM_CPPFLAGS)
-
 test_remote_settings_client_LDADD = \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(top_builddir)/libnm-glib/libnm-glib-test.la \
@@ -27,11 +36,18 @@ test_remote_settings_client_LDADD = \
 
 ###########################################
 
+TEST_NM_BIN = test-fake-nm.py
 TEST_RSS_BIN = test-remote-settings-service.py
 
-EXTRA_DIST = $(TEST_RSS_BIN)
+EXTRA_DIST = $(TEST_RSS_BIN) $(TEST_NM_BIN)
 
-check-local: test-remote-settings-client
-	$(abs_builddir)/test-remote-settings-client $(abs_srcdir) $(TEST_RSS_BIN)
+check-local: test-nm-client test-remote-settings-client
+	if test -z "$$DBUS_SESSION_BUS_ADDRESS" ; then \
+	    dbus-launch --exit-with-session $(abs_builddir)/test-nm-client $(abs_srcdir) $(TEST_NM_BIN); \
+	    dbus-launch --exit-with-session $(abs_builddir)/test-remote-settings-client $(abs_srcdir) $(TEST_RSS_BIN); \
+	else \
+	    $(abs_builddir)/test-nm-client $(abs_srcdir) $(TEST_NM_BIN); \
+	    $(abs_builddir)/test-remote-settings-client $(abs_srcdir) $(TEST_RSS_BIN); \
+	fi;
 
 endif
diff --git a/libnm-glib/tests/Makefile.in b/libnm-glib/tests/Makefile.in
index e9ea17b1..28acdea0 100644
--- a/libnm-glib/tests/Makefile.in
+++ b/libnm-glib/tests/Makefile.in
@@ -78,13 +78,14 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-@ENABLE_TESTS_TRUE@noinst_PROGRAMS =  \
+@ENABLE_TESTS_TRUE@noinst_PROGRAMS = test-nm-client$(EXEEXT) \
 @ENABLE_TESTS_TRUE@	test-remote-settings-client$(EXEEXT)
 subdir = libnm-glib/tests
 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
 	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
+	$(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/gettext.m4 \
 	$(top_srcdir)/m4/gnome-code-coverage.m4 \
 	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
@@ -103,13 +104,12 @@ CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
 PROGRAMS = $(noinst_PROGRAMS)
-am__test_remote_settings_client_SOURCES_DIST =  \
-	test-remote-settings-client.c
-@ENABLE_TESTS_TRUE@am_test_remote_settings_client_OBJECTS = test_remote_settings_client-test-remote-settings-client.$(OBJEXT)
-test_remote_settings_client_OBJECTS =  \
-	$(am_test_remote_settings_client_OBJECTS)
+am__test_nm_client_SOURCES_DIST = test-nm-client.c
+@ENABLE_TESTS_TRUE@am_test_nm_client_OBJECTS =  \
+@ENABLE_TESTS_TRUE@	test-nm-client.$(OBJEXT)
+test_nm_client_OBJECTS = $(am_test_nm_client_OBJECTS)
 am__DEPENDENCIES_1 =
-@ENABLE_TESTS_TRUE@test_remote_settings_client_DEPENDENCIES =  \
+@ENABLE_TESTS_TRUE@test_nm_client_DEPENDENCIES =  \
 @ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-util/libnm-util.la \
 @ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-glib/libnm-glib-test.la \
 @ENABLE_TESTS_TRUE@	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@@ -117,6 +117,16 @@ AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
 am__v_lt_0 = --silent
 am__v_lt_1 = 
+am__test_remote_settings_client_SOURCES_DIST =  \
+	test-remote-settings-client.c
+@ENABLE_TESTS_TRUE@am_test_remote_settings_client_OBJECTS =  \
+@ENABLE_TESTS_TRUE@	test-remote-settings-client.$(OBJEXT)
+test_remote_settings_client_OBJECTS =  \
+	$(am_test_remote_settings_client_OBJECTS)
+@ENABLE_TESTS_TRUE@test_remote_settings_client_DEPENDENCIES =  \
+@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-util/libnm-util.la \
+@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-glib/libnm-glib-test.la \
+@ENABLE_TESTS_TRUE@	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 AM_V_P = $(am__v_P_@AM_V@)
 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
 am__v_P_0 = false
@@ -151,8 +161,10 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@)
 am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
-SOURCES = $(test_remote_settings_client_SOURCES)
-DIST_SOURCES = $(am__test_remote_settings_client_SOURCES_DIST)
+SOURCES = $(test_nm_client_SOURCES) \
+	$(test_remote_settings_client_SOURCES)
+DIST_SOURCES = $(am__test_nm_client_SOURCES_DIST) \
+	$(am__test_remote_settings_client_SOURCES_DIST)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -203,12 +215,15 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
+DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
 DBUS_LIBS = @DBUS_LIBS@
 DBUS_SYS_DIR = @DBUS_SYS_DIR@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 DHCLIENT_PATH = @DHCLIENT_PATH@
 DHCPCD_PATH = @DHCPCD_PATH@
+DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@
 DLLTOOL = @DLLTOOL@
 DNSMASQ_PATH = @DNSMASQ_PATH@
 DSYMUTIL = @DSYMUTIL@
@@ -233,7 +248,6 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
-GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -278,12 +292,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNDP_CFLAGS = @LIBNDP_CFLAGS@
+LIBNDP_LIBS = @LIBNDP_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
 LIBSOUP_LIBS = @LIBSOUP_LIBS@
+LIBTEAMDCTL_CFLAGS = @LIBTEAMDCTL_CFLAGS@
+LIBTEAMDCTL_LIBS = @LIBTEAMDCTL_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -300,6 +318,8 @@ MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
+NEWT_CFLAGS = @NEWT_CFLAGS@
+NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
@@ -327,11 +347,16 @@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
 POLKIT_CFLAGS = @POLKIT_CFLAGS@
 POLKIT_LIBS = @POLKIT_LIBS@
 POSUB = @POSUB@
+PPPD_PATH = @PPPD_PATH@
 PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
+PPPOE_PATH = @PPPOE_PATH@
 QT_CFLAGS = @QT_CFLAGS@
 QT_LIBS = @QT_LIBS@
 RANLIB = @RANLIB@
+READLINE_LIBS = @READLINE_LIBS@
 SED = @SED@
+SELINUX_CFLAGS = @SELINUX_CFLAGS@
+SELINUX_LIBS = @SELINUX_LIBS@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
@@ -346,6 +371,7 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VALGRIND_RULES = @VALGRIND_RULES@
 VAPIGEN = @VAPIGEN@
 VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
 VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
@@ -408,6 +434,7 @@ psdir = @psdir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
+subdirs = @subdirs@
 sysconfdir = @sysconfdir@
 systemdsystemunitdir = @systemdsystemunitdir@
 target_alias = @target_alias@
@@ -418,23 +445,33 @@ with_dhclient = @with_dhclient@
 with_dhcpcd = @with_dhcpcd@
 with_netconfig = @with_netconfig@
 with_resolvconf = @with_resolvconf@
+with_valgrind = @with_valgrind@
 @ENABLE_TESTS_TRUE@AM_CPPFLAGS = \
 @ENABLE_TESTS_TRUE@	-I$(top_srcdir)/include \
 @ENABLE_TESTS_TRUE@	-I$(top_builddir)/include \
 @ENABLE_TESTS_TRUE@	-I$(top_srcdir)/libnm-util \
 @ENABLE_TESTS_TRUE@	-I$(top_builddir)/libnm-util \
-@ENABLE_TESTS_TRUE@	-I$(top_srcdir)/libnm-glib
+@ENABLE_TESTS_TRUE@	-I$(top_srcdir)/libnm-glib \
+@ENABLE_TESTS_TRUE@	-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
+@ENABLE_TESTS_TRUE@	$(GLIB_CFLAGS) \
+@ENABLE_TESTS_TRUE@	$(DBUS_CFLAGS)
+
+
+####### NMClient and non-settings tests #######
+@ENABLE_TESTS_TRUE@test_nm_client_SOURCES = \
+@ENABLE_TESTS_TRUE@	test-nm-client.c
+
+@ENABLE_TESTS_TRUE@test_nm_client_LDADD = \
+@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-util/libnm-util.la \
+@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-glib/libnm-glib-test.la \
+@ENABLE_TESTS_TRUE@	$(GLIB_LIBS) \
+@ENABLE_TESTS_TRUE@	$(DBUS_LIBS)
 
 
 ####### remote settings client test #######
 @ENABLE_TESTS_TRUE@test_remote_settings_client_SOURCES = \
 @ENABLE_TESTS_TRUE@	test-remote-settings-client.c
 
-@ENABLE_TESTS_TRUE@test_remote_settings_client_CPPFLAGS = \
-@ENABLE_TESTS_TRUE@	$(GLIB_CFLAGS) \
-@ENABLE_TESTS_TRUE@	$(DBUS_CFLAGS) \
-@ENABLE_TESTS_TRUE@	$(AM_CPPFLAGS)
-
 @ENABLE_TESTS_TRUE@test_remote_settings_client_LDADD = \
 @ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-util/libnm-util.la \
 @ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-glib/libnm-glib-test.la \
@@ -443,8 +480,9 @@ with_resolvconf = @with_resolvconf@
 
 
 ###########################################
+@ENABLE_TESTS_TRUE@TEST_NM_BIN = test-fake-nm.py
 @ENABLE_TESTS_TRUE@TEST_RSS_BIN = test-remote-settings-service.py
-@ENABLE_TESTS_TRUE@EXTRA_DIST = $(TEST_RSS_BIN)
+@ENABLE_TESTS_TRUE@EXTRA_DIST = $(TEST_RSS_BIN) $(TEST_NM_BIN)
 all: all-am
 
 .SUFFIXES:
@@ -489,6 +527,10 @@ clean-noinstPROGRAMS:
 	echo " rm -f" $$list; \
 	rm -f $$list
 
+test-nm-client$(EXEEXT): $(test_nm_client_OBJECTS) $(test_nm_client_DEPENDENCIES) $(EXTRA_test_nm_client_DEPENDENCIES) 
+	@rm -f test-nm-client$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(test_nm_client_OBJECTS) $(test_nm_client_LDADD) $(LIBS)
+
 test-remote-settings-client$(EXEEXT): $(test_remote_settings_client_OBJECTS) $(test_remote_settings_client_DEPENDENCIES) $(EXTRA_test_remote_settings_client_DEPENDENCIES) 
 	@rm -f test-remote-settings-client$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(test_remote_settings_client_OBJECTS) $(test_remote_settings_client_LDADD) $(LIBS)
@@ -499,7 +541,8 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_remote_settings_client-test-remote-settings-client.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-nm-client.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-remote-settings-client.Po@am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -522,20 +565,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
 
-test_remote_settings_client-test-remote-settings-client.o: test-remote-settings-client.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_remote_settings_client_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_remote_settings_client-test-remote-settings-client.o -MD -MP -MF $(DEPDIR)/test_remote_settings_client-test-remote-settings-client.Tpo -c -o test_remote_settings_client-test-remote-settings-client.o `test -f 'test-remote-settings-client.c' || echo '$(srcdir)/'`test-remote-settings-client.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/test_remote_settings_client-test-remote-settings-client.Tpo $(DEPDIR)/test_remote_settings_client-test-remote-settings-client.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='test-remote-settings-client.c' object='test_remote_settings_client-test-remote-settings-client.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_remote_settings_client_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_remote_settings_client-test-remote-settings-client.o `test -f 'test-remote-settings-client.c' || echo '$(srcdir)/'`test-remote-settings-client.c
-
-test_remote_settings_client-test-remote-settings-client.obj: test-remote-settings-client.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_remote_settings_client_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_remote_settings_client-test-remote-settings-client.obj -MD -MP -MF $(DEPDIR)/test_remote_settings_client-test-remote-settings-client.Tpo -c -o test_remote_settings_client-test-remote-settings-client.obj `if test -f 'test-remote-settings-client.c'; then $(CYGPATH_W) 'test-remote-settings-client.c'; else $(CYGPATH_W) '$(srcdir)/test-remote-settings-client.c'; fi`
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/test_remote_settings_client-test-remote-settings-client.Tpo $(DEPDIR)/test_remote_settings_client-test-remote-settings-client.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='test-remote-settings-client.c' object='test_remote_settings_client-test-remote-settings-client.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_remote_settings_client_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_remote_settings_client-test-remote-settings-client.obj `if test -f 'test-remote-settings-client.c'; then $(CYGPATH_W) 'test-remote-settings-client.c'; else $(CYGPATH_W) '$(srcdir)/test-remote-settings-client.c'; fi`
-
 mostlyclean-libtool:
 	-rm -f *.lo
 
@@ -748,8 +777,14 @@ uninstall-am:
 	tags tags-am uninstall uninstall-am
 
 
-@ENABLE_TESTS_TRUE@check-local: test-remote-settings-client
-@ENABLE_TESTS_TRUE@	$(abs_builddir)/test-remote-settings-client $(abs_srcdir) $(TEST_RSS_BIN)
+@ENABLE_TESTS_TRUE@check-local: test-nm-client test-remote-settings-client
+@ENABLE_TESTS_TRUE@	if test -z "$$DBUS_SESSION_BUS_ADDRESS" ; then \
+@ENABLE_TESTS_TRUE@	    dbus-launch --exit-with-session $(abs_builddir)/test-nm-client $(abs_srcdir) $(TEST_NM_BIN); \
+@ENABLE_TESTS_TRUE@	    dbus-launch --exit-with-session $(abs_builddir)/test-remote-settings-client $(abs_srcdir) $(TEST_RSS_BIN); \
+@ENABLE_TESTS_TRUE@	else \
+@ENABLE_TESTS_TRUE@	    $(abs_builddir)/test-nm-client $(abs_srcdir) $(TEST_NM_BIN); \
+@ENABLE_TESTS_TRUE@	    $(abs_builddir)/test-remote-settings-client $(abs_srcdir) $(TEST_RSS_BIN); \
+@ENABLE_TESTS_TRUE@	fi;
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/libnm-glib/tests/test-fake-nm.py b/libnm-glib/tests/test-fake-nm.py
new file mode 100755
index 00000000..46ca3ff0
--- /dev/null
+++ b/libnm-glib/tests/test-fake-nm.py
@@ -0,0 +1,776 @@
+#!/usr/bin/env python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+
+from __future__ import print_function
+
+from gi.repository import GLib, GObject
+import sys
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+import random
+
+mainloop = GObject.MainLoop()
+quit_id = 0
+
+# NM State
+NM_STATE_UNKNOWN          = 0
+NM_STATE_ASLEEP           = 10
+NM_STATE_DISCONNECTED     = 20
+NM_STATE_DISCONNECTING    = 30
+NM_STATE_CONNECTING       = 40
+NM_STATE_CONNECTED_LOCAL  = 50
+NM_STATE_CONNECTED_SITE   = 60
+NM_STATE_CONNECTED_GLOBAL = 70
+
+# Device state
+NM_DEVICE_STATE_UNKNOWN      = 0
+NM_DEVICE_STATE_UNMANAGED    = 10
+NM_DEVICE_STATE_UNAVAILABLE  = 20
+NM_DEVICE_STATE_DISCONNECTED = 30
+NM_DEVICE_STATE_PREPARE      = 40
+NM_DEVICE_STATE_CONFIG       = 50
+NM_DEVICE_STATE_NEED_AUTH    = 60
+NM_DEVICE_STATE_IP_CONFIG    = 70
+NM_DEVICE_STATE_IP_CHECK     = 80
+NM_DEVICE_STATE_SECONDARIES  = 90
+NM_DEVICE_STATE_ACTIVATED    = 100
+NM_DEVICE_STATE_DEACTIVATING = 110
+NM_DEVICE_STATE_FAILED       = 120
+
+NM_DEVICE_TYPE_UNKNOWN    = 0
+NM_DEVICE_TYPE_ETHERNET   = 1
+NM_DEVICE_TYPE_WIFI       = 2
+NM_DEVICE_TYPE_UNUSED1    = 3
+NM_DEVICE_TYPE_UNUSED2    = 4
+NM_DEVICE_TYPE_BT         = 5
+NM_DEVICE_TYPE_OLPC_MESH  = 6
+NM_DEVICE_TYPE_WIMAX      = 7
+NM_DEVICE_TYPE_MODEM      = 8
+NM_DEVICE_TYPE_INFINIBAND = 9
+NM_DEVICE_TYPE_BOND       = 10
+NM_DEVICE_TYPE_VLAN       = 11
+NM_DEVICE_TYPE_ADSL       = 12
+NM_DEVICE_TYPE_BRIDGE     = 13
+NM_DEVICE_TYPE_GENERIC    = 14
+NM_DEVICE_TYPE_TEAM       = 15
+
+#########################################################
+IFACE_DBUS = 'org.freedesktop.DBus'
+
+class UnknownInterfaceException(dbus.DBusException):
+    _dbus_error_name = IFACE_DBUS + '.UnknownInterface'
+
+class UnknownPropertyException(dbus.DBusException):
+    _dbus_error_name = IFACE_DBUS + '.UnknownProperty'
+
+def to_path_array(src):
+    array = dbus.Array([], signature=dbus.Signature('o'))
+    for o in src:
+        array.append(o.path)
+    return array
+
+def to_path(src):
+    if src:
+        return dbus.ObjectPath(src.path)
+    return dbus.ObjectPath("/")
+
+class ExportedObj(dbus.service.Object):
+    def __init__(self, bus, object_path):
+        dbus.service.Object.__init__(self, bus, object_path)
+        self._bus = bus
+        self.path = object_path
+        self.__dbus_ifaces = {}
+
+    def add_dbus_interface(self, dbus_iface, get_props_func):
+        self.__dbus_ifaces[dbus_iface] = get_props_func
+
+    def _get_dbus_properties(self, iface):
+        return self.__dbus_ifaces[iface]()
+
+    @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='s', out_signature='a{sv}')
+    def GetAll(self, iface):
+        if iface not in self.__dbus_ifaces.keys():
+            raise UnknownInterfaceException()
+        return self._get_dbus_properties(iface)
+
+    @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='ss', out_signature='v')
+    def Get(self, iface, name):
+        if iface not in self.__dbus_ifaces.keys():
+            raise UnknownInterfaceException()
+        props = self._get_dbus_properties(iface)
+        if not name in props.keys():
+            raise UnknownPropertyException()
+        return props[name]
+
+###################################################################
+IFACE_DEVICE = 'org.freedesktop.NetworkManager.Device'
+
+PD_UDI = "Udi"
+PD_IFACE = "Interface"
+PD_DRIVER = "Driver"
+PD_STATE = "State"
+PD_ACTIVE_CONNECTION = "ActiveConnection"
+PD_IP4_CONFIG = "Ip4Config"
+PD_IP6_CONFIG = "Ip6Config"
+PD_DHCP4_CONFIG = "Dhcp4Config"
+PD_DHCP6_CONFIG = "Dhcp6Config"
+PD_MANAGED = "Managed"
+PD_AUTOCONNECT = "Autoconnect"
+PD_DEVICE_TYPE = "DeviceType"
+PD_AVAILABLE_CONNECTIONS = "AvailableConnections"
+
+class Device(ExportedObj):
+    counter = 1
+
+    def __init__(self, bus, iface, devtype):
+        object_path = "/org/freedesktop/NetworkManager/Devices/%d" % Device.counter
+        Device.counter = Device.counter + 1
+        ExportedObj.__init__(self, bus, object_path)
+        self.add_dbus_interface(IFACE_DEVICE, self.__get_props)
+
+        self.iface = iface
+        self.udi = "/sys/devices/virtual/%s" % iface
+        self.devtype = devtype
+        self.active_connection = None
+        self.state = NM_DEVICE_STATE_UNAVAILABLE
+        self.ip4_config = None
+        self.ip6_config = None
+        self.dhcp4_config = None
+        self.dhcp6_config = None
+        self.available_connections = []
+
+    # Properties interface
+    def __get_props(self):
+        props = {}
+        props[PD_UDI] = self.udi
+        props[PD_IFACE] = self.iface
+        props[PD_DRIVER] = "virtual"
+        props[PD_STATE] = dbus.UInt32(self.state)
+        props[PD_ACTIVE_CONNECTION] = to_path(self.active_connection)
+        props[PD_IP4_CONFIG] = to_path(self.ip4_config)
+        props[PD_IP6_CONFIG] = to_path(self.ip6_config)
+        props[PD_DHCP4_CONFIG] = to_path(self.dhcp4_config)
+        props[PD_DHCP6_CONFIG] = to_path(self.dhcp6_config)
+        props[PD_MANAGED] = True
+        props[PD_AUTOCONNECT] = True
+        props[PD_DEVICE_TYPE] = dbus.UInt32(self.devtype)
+        props[PD_AVAILABLE_CONNECTIONS] = to_path_array(self.available_connections)
+        return props
+
+    # methods
+    @dbus.service.method(dbus_interface=IFACE_DEVICE, in_signature='', out_signature='')
+    def Disconnect(self):
+        pass
+
+    def __notify(self, propname):
+        props = self._get_dbus_properties(IFACE_DEVICE)
+        changed = { propname: props[propname] }
+        Device.PropertiesChanged(self, changed)
+
+    @dbus.service.signal(IFACE_DEVICE, signature='a{sv}')
+    def PropertiesChanged(self, changed):
+        pass
+
+
+###################################################################
+
+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)
+      )
+
+###################################################################
+IFACE_WIRED = 'org.freedesktop.NetworkManager.Device.Wired'
+
+PE_HW_ADDRESS = "HwAddress"
+PE_PERM_HW_ADDRESS = "PermHwAddress"
+PE_SPEED = "Speed"
+PE_CARRIER = "Carrier"
+
+class WiredDevice(Device):
+    def __init__(self, bus, iface):
+        Device.__init__(self, bus, iface, NM_DEVICE_TYPE_ETHERNET)
+        self.add_dbus_interface(IFACE_WIRED, self.__get_props)
+
+        self.mac = random_mac()
+        self.carrier = False
+
+    # Properties interface
+    def __get_props(self):
+        props = {}
+        props[PE_HW_ADDRESS] = self.mac
+        props[PE_PERM_HW_ADDRESS] = self.mac
+        props[PE_SPEED] = dbus.UInt32(100)
+        props[PE_CARRIER] = self.carrier
+        return props
+
+    def __notify(self, propname):
+        props = self._get_dbus_properties(IFACE_WIRED)
+        changed = { propname: props[propname] }
+        WiredDevice.PropertiesChanged(self, changed)
+
+    @dbus.service.signal(IFACE_WIRED, signature='a{sv}')
+    def PropertiesChanged(self, changed):
+        pass
+
+###################################################################
+IFACE_WIFI_AP = 'org.freedesktop.NetworkManager.AccessPoint'
+
+PP_FLAGS = "Flags"
+PP_WPA_FLAGS = "WpaFlags"
+PP_RSN_FLAGS = "RsnFlags"
+PP_SSID = "Ssid"
+PP_FREQUENCY = "Frequency"
+PP_HW_ADDRESS = "HwAddress"
+PP_MODE = "Mode"
+PP_MAX_BITRATE = "MaxBitrate"
+PP_STRENGTH = "Strength"
+
+class WifiAp(ExportedObj):
+    counter = 0
+
+    def __init__(self, bus, ssid, mac, flags, wpaf, rsnf, freq):
+        path = "/org/freedesktop/NetworkManager/AccessPoint/%d" % WifiAp.counter
+        WifiAp.counter = WifiAp.counter + 1
+        ExportedObj.__init__(self, bus, path)
+        self.add_dbus_interface(IFACE_WIFI_AP, self.__get_props)
+
+        self.ssid = ssid
+        if mac:
+            self.bssid = mac
+        else:
+            self.bssid = random_mac()
+        self.flags = flags
+        self.wpaf = wpaf
+        self.rsnf = rsnf
+        self.freq = freq
+        self.strength = random.randint(0, 100)
+        self.strength_id = GLib.timeout_add_seconds(10, self.strength_cb, None)
+
+    def __del__(self):
+        if self.strength_id > 0:
+            GLib.source_remove(self.strength_id)
+        self.strength_id = 0
+
+    def strength_cb(self, ignored):
+        self.strength = random.randint(0, 100)
+        self.__notify(PP_STRENGTH)
+        return True
+
+    # Properties interface
+    def __get_props(self):
+        props = {}
+        props[PP_FLAGS] = dbus.UInt32(self.flags)
+        props[PP_WPA_FLAGS] = dbus.UInt32(self.wpaf)
+        props[PP_RSN_FLAGS] = dbus.UInt32(self.rsnf)
+        props[PP_SSID] = dbus.ByteArray(self.ssid)
+        props[PP_FREQUENCY] = dbus.UInt32(self.freq)
+        props[PP_HW_ADDRESS] = self.bssid
+        props[PP_MODE] = dbus.UInt32(2)  # NM_802_11_MODE_INFRA
+        props[PP_MAX_BITRATE] = dbus.UInt32(54000)
+        props[PP_STRENGTH] = dbus.Byte(self.strength)
+        return props
+
+    def __notify(self, propname):
+        props = self._get_dbus_properties(IFACE_WIFI_AP)
+        changed = { propname: props[propname] }
+        WifiAp.PropertiesChanged(self, changed)
+
+    @dbus.service.signal(IFACE_WIFI_AP, signature='a{sv}')
+    def PropertiesChanged(self, changed):
+        pass
+
+###################################################################
+IFACE_WIFI = 'org.freedesktop.NetworkManager.Device.Wireless'
+
+class ApNotFoundException(dbus.DBusException):
+    _dbus_error_name = IFACE_WIFI + '.AccessPointNotFound'
+
+PW_HW_ADDRESS = "HwAddress"
+PW_PERM_HW_ADDRESS = "PermHwAddress"
+PW_MODE = "Mode"
+PW_BITRATE = "Bitrate"
+PW_ACCESS_POINTS = "AccessPoints"
+PW_ACTIVE_ACCESS_POINT = "ActiveAccessPoint"
+PW_WIRELESS_CAPABILITIES = "WirelessCapabilities"
+
+class WifiDevice(Device):
+    def __init__(self, bus, iface):
+        Device.__init__(self, bus, iface, NM_DEVICE_TYPE_WIFI)
+        self.add_dbus_interface(IFACE_WIFI, self.__get_props)
+
+        self.mac = random_mac()
+        self.aps = []
+        self.active_ap = None
+
+    # methods
+    @dbus.service.method(dbus_interface=IFACE_WIFI, in_signature='', out_signature='ao')
+    def GetAccessPoints(self):
+        # only include non-hidden APs
+        array = []
+        for a in self.aps:
+            if a.ssid():
+                array.append(a)
+        return to_path_array(array)
+
+    @dbus.service.method(dbus_interface=IFACE_WIFI, in_signature='', out_signature='ao')
+    def GetAllAccessPoints(self):
+        # include all APs including hidden ones
+        return to_path_array(self.aps)
+
+    @dbus.service.method(dbus_interface=IFACE_WIFI, in_signature='a{sv}', out_signature='')
+    def RequestScan(self, props):
+        pass
+
+    @dbus.service.signal(IFACE_WIFI, signature='o')
+    def AccessPointAdded(self, ap_path):
+        pass
+
+    def add_ap(self, ap):
+        self.aps.append(ap)
+        self.__notify(PW_ACCESS_POINTS)
+        self.AccessPointAdded(to_path(ap))
+
+    @dbus.service.signal(IFACE_WIFI, signature='o')
+    def AccessPointRemoved(self, ap_path):
+        pass
+
+    def remove_ap(self, ap):
+        self.aps.remove(ap)
+        self.__notify(PW_ACCESS_POINTS)
+        self.AccessPointRemoved(to_path(ap))
+
+    # Properties interface
+    def __get_props(self):
+        props = {}
+        props[PW_HW_ADDRESS] = self.mac
+        props[PW_PERM_HW_ADDRESS] = self.mac
+        props[PW_MODE] = dbus.UInt32(3)  # NM_802_11_MODE_INFRA
+        props[PW_BITRATE] = dbus.UInt32(21000)
+        props[PW_WIRELESS_CAPABILITIES] = dbus.UInt32(0xFF)
+        props[PW_ACCESS_POINTS] = to_path_array(self.aps)
+        props[PW_ACTIVE_ACCESS_POINT] = to_path(self.active_ap)
+        return props
+
+    def __notify(self, propname):
+        props = self._get_dbus_properties(IFACE_WIFI)
+        changed = { propname: props[propname] }
+        WifiDevice.PropertiesChanged(self, changed)
+
+    @dbus.service.signal(IFACE_WIFI, signature='a{sv}')
+    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.path
+
+    def remove_ap_by_path(self, path):
+        for ap in self.aps:
+            if ap.path == path:
+                self.remove_ap(ap)
+                return
+        raise ApNotFoundException("AP %s not found" % path)
+
+
+###################################################################
+IFACE_WIMAX_NSP = 'org.freedesktop.NetworkManager.WiMax.Nsp'
+
+PN_NAME = "Name"
+PN_SIGNAL_QUALITY = "SignalQuality"
+PN_NETWORK_TYPE = "NetworkType"
+
+class WimaxNsp(ExportedObj):
+    counter = 0
+
+    def __init__(self, bus, name):
+        path = "/org/freedesktop/NetworkManager/Nsp/%d" % WimaxNsp.counter
+        WimaxNsp.counter = WimaxNsp.counter + 1
+        ExportedObj.__init__(self, bus, path)
+        self.add_dbus_interface(IFACE_WIMAX_NSP, self.__get_props)
+
+        self.name = name
+        self.strength = random.randint(0, 100)
+        self.strength_id = GLib.timeout_add_seconds(10, self.strength_cb, None)
+
+    def __del__(self):
+        if self.strength_id > 0:
+            GLib.source_remove(self.strength_id)
+        self.strength_id = 0
+
+    def strength_cb(self, ignored):
+        self.strength = random.randint(0, 100)
+        self.__notify(PN_SIGNAL_QUALITY)
+        return True
+
+    # Properties interface
+    def __get_props(self):
+        props = {}
+        props[PN_NAME] = self.name
+        props[PN_SIGNAL_QUALITY] = dbus.UInt32(self.strength)
+        props[PN_NETWORK_TYPE] = dbus.UInt32(0x1)  # NM_WIMAX_NSP_NETWORK_TYPE_HOME
+        return props
+
+    def __notify(self, propname):
+        props = self._get_dbus_properties(IFACE_WIMAX_NSP)
+        changed = { propname: props[propname] }
+        WimaxNsp.PropertiesChanged(self, changed)
+
+    @dbus.service.signal(IFACE_WIMAX_NSP, signature='a{sv}')
+    def PropertiesChanged(self, changed):
+        pass
+
+###################################################################
+IFACE_WIMAX = 'org.freedesktop.NetworkManager.Device.WiMax'
+
+class NspNotFoundException(dbus.DBusException):
+    _dbus_error_name = IFACE_WIMAX + '.NspNotFound'
+
+PX_NSPS = "Nsps"
+PX_HW_ADDRESS = "HwAddress"
+PX_CENTER_FREQUENCY = "CenterFrequency"
+PX_RSSI = "Rssi"
+PX_CINR = "Cinr"
+PX_TX_POWER = "TxPower"
+PX_BSID = "Bsid"
+PX_ACTIVE_NSP = "ActiveNsp"
+
+class WimaxDevice(Device):
+    def __init__(self, bus, iface):
+        Device.__init__(self, bus, iface, NM_DEVICE_TYPE_WIMAX)
+        self.add_dbus_interface(IFACE_WIMAX, self.__get_props)
+
+        self.mac = random_mac()
+        self.bsid = random_mac()
+        self.nsps = []
+        self.active_nsp = None
+
+    # methods
+    @dbus.service.method(dbus_interface=IFACE_WIMAX, in_signature='', out_signature='ao')
+    def GetNspList(self):
+        # include all APs including hidden ones
+        return to_path_array(self.nsps)
+
+    @dbus.service.signal(IFACE_WIMAX, signature='o')
+    def NspAdded(self, nsp_path):
+        pass
+
+    def add_nsp(self, nsp):
+        self.nsps.append(nsp)
+        self.__notify(PX_NSPS)
+        self.NspAdded(to_path(nsp))
+
+    @dbus.service.signal(IFACE_WIMAX, signature='o')
+    def NspRemoved(self, nsp_path):
+        pass
+
+    def remove_nsp(self, nsp):
+        self.nsps.remove(nsp)
+        self.__notify(PX_NSPS)
+        self.NspRemoved(to_path(nsp))
+
+    # Properties interface
+    def __get_props(self):
+        props = {}
+        props[PX_HW_ADDRESS] = self.mac
+        props[PX_CENTER_FREQUENCY] = dbus.UInt32(2525)
+        props[PX_RSSI] = dbus.Int32(-48)
+        props[PX_CINR] = dbus.Int32(24)
+        props[PX_TX_POWER] = dbus.Int32(9)
+        props[PX_BSID] = self.bsid
+        props[PX_NSPS] = to_path_array(self.nsps)
+        props[PX_ACTIVE_NSP] = to_path(self.active_nsp)
+        return props
+
+    def __notify(self, propname):
+        props = self._get_dbus_properties(IFACE_WIMAX)
+        changed = { propname: props[propname] }
+        WimaxDevice.PropertiesChanged(self, changed)
+
+    @dbus.service.signal(IFACE_WIMAX, signature='a{sv}')
+    def PropertiesChanged(self, changed):
+        pass
+
+    # test functions
+    def add_test_nsp(self, name):
+        nsp = WimaxNsp(self._bus, name)
+        self.add_nsp(nsp)
+        return nsp.path
+
+    def remove_nsp_by_path(self, path):
+        for nsp in self.nsps:
+            if nsp.path == path:
+                self.remove_nsp(nsp)
+                return
+        raise NspNotFoundException("NSP %s not found" % path)
+
+###################################################################
+IFACE_TEST = 'org.freedesktop.NetworkManager.LibnmGlibTest'
+IFACE_NM = 'org.freedesktop.NetworkManager'
+
+class PermissionDeniedException(dbus.DBusException):
+    _dbus_error_name = IFACE_NM + '.PermissionDenied'
+
+class UnknownDeviceException(dbus.DBusException):
+    _dbus_error_name = IFACE_NM + '.UnknownDevice'
+
+PM_DEVICES = 'Devices'
+PM_NETWORKING_ENABLED = 'NetworkingEnabled'
+PM_WWAN_ENABLED = 'WwanEnabled'
+PM_WWAN_HARDWARE_ENABLED = 'WwanHardwareEnabled'
+PM_WIRELESS_ENABLED = 'WirelessEnabled'
+PM_WIRELESS_HARDWARE_ENABLED = 'WirelessHardwareEnabled'
+PM_WIMAX_ENABLED = 'WimaxEnabled'
+PM_WIMAX_HARDWARE_ENABLED = 'WimaxHardwareEnabled'
+PM_ACTIVE_CONNECTIONS = 'ActiveConnections'
+PM_PRIMARY_CONNECTION = 'PrimaryConnection'
+PM_ACTIVATING_CONNECTION = 'ActivatingConnection'
+PM_STARTUP = 'Startup'
+PM_STATE = 'State'
+PM_VERSION = 'Version'
+PM_CONNECTIVITY = 'Connectivity'
+
+class NetworkManager(ExportedObj):
+    def __init__(self, bus, object_path):
+        ExportedObj.__init__(self, bus, object_path)
+        self.add_dbus_interface(IFACE_NM, self.__get_props)
+
+        self.devices = []
+        self.active_connections = []
+        self.primary_connection = None
+        self.activating_connection = None
+        self.state = NM_STATE_DISCONNECTED
+        self.connectivity = 1
+
+    @dbus.service.signal(IFACE_NM, signature='u')
+    def StateChanged(self, new_state):
+        pass
+
+    def set_state(self, new_state):
+        self.state = new_state
+        self.__notify(PM_STATE)
+        self.StateChanged(dbus.UInt32(self.state))
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='ao')
+    def GetDevices(self):
+        return self._get_dbus_properties(IFACE_NM)[PM_DEVICES]
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='s', out_signature='o')
+    def GetDeviceByIpIface(self, ip_iface):
+        for d in self.devices:
+            # ignore iface/ip_iface distinction for now
+            if d.iface == ip_iface:
+                return d.path
+        raise UnknownDeviceException("No device found for the requested iface.")
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='ooo', out_signature='o')
+    def ActivateConnection(self, conpath, devpath, specific_object):
+        device = None
+        for d in self.devices:
+            if d.path == devpath:
+                device = d
+                break
+        if not device:
+            raise UnknownDeviceException("No device found for the requested iface.")
+        raise PermissionDeniedException("Not yet implemented")
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='a{sa{sv}}oo', out_signature='oo')
+    def AddAndActivateConnection(self, connection, devpath, specific_object):
+        device = None
+        for d in self.devices:
+            if d.path == devpath:
+                device = d
+                break
+        if not device:
+            raise UnknownDeviceException("No device found for the requested iface.")
+        raise PermissionDeniedException("Not yet implemented")
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='o', out_signature='')
+    def DeactivateConnection(self, active_connection):
+        pass
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='b', out_signature='')
+    def Sleep(self, do_sleep):
+        if do_sleep:
+            self.state = NM_STATE_ASLEEP
+        else:
+            self.state = NM_STATE_DISCONNECTED
+        self.__notify(PM_STATE)
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='b', out_signature='')
+    def Enable(self, do_enable):
+        pass
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='a{ss}')
+    def GetPermissions(self):
+        return { "org.freedesktop.NetworkManager.enable-disable-network":   "yes",
+                 "org.freedesktop.NetworkManager.sleep-wake":               "no",
+                 "org.freedesktop.NetworkManager.enable-disable-wifi":      "yes",
+                 "org.freedesktop.NetworkManager.enable-disable-wwan":      "yes",
+                 "org.freedesktop.NetworkManager.enable-disable-wimax":     "yes",
+                 "org.freedesktop.NetworkManager.network-control":          "yes",
+                 "org.freedesktop.NetworkManager.wifi.share.protected":     "yes",
+                 "org.freedesktop.NetworkManager.wifi.share.open":          "yes",
+                 "org.freedesktop.NetworkManager.settings.modify.own":      "yes",
+                 "org.freedesktop.NetworkManager.settings.modify.system":   "yes",
+                 "org.freedesktop.NetworkManager.settings.modify.hostname": "yes" }
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='ss', out_signature='')
+    def SetLogging(self, level, domains):
+        pass
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='ss')
+    def GetLogging(self):
+        return ("info", "HW,RFKILL,CORE,DEVICE,WIFI,ETHER")
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='u')
+    def CheckConnectivity(self):
+        raise PermissionDeniedException("You fail")
+
+    @dbus.service.signal(IFACE_NM, signature='o')
+    def DeviceAdded(self, devpath):
+        pass
+
+    def add_device(self, device):
+        self.devices.append(device)
+        self.__notify(PM_DEVICES)
+        self.DeviceAdded(to_path(device))
+
+    @dbus.service.signal(IFACE_NM, signature='o')
+    def DeviceRemoved(self, devpath):
+        pass
+
+    def remove_device(self, device):
+        self.devices.remove(device)
+        self.__notify(PM_DEVICES)
+        self.DeviceRemoved(to_path(device))
+
+    ################# D-Bus Properties interface
+    def __get_props(self):
+        props = {}
+        props[PM_DEVICES] = to_path_array(self.devices)
+        props[PM_NETWORKING_ENABLED] = True
+        props[PM_WWAN_ENABLED] = True
+        props[PM_WWAN_HARDWARE_ENABLED] = True
+        props[PM_WIRELESS_ENABLED] = True
+        props[PM_WIRELESS_HARDWARE_ENABLED] = True
+        props[PM_WIMAX_ENABLED] = True
+        props[PM_WIMAX_HARDWARE_ENABLED] = True
+        props[PM_ACTIVE_CONNECTIONS] = to_path_array(self.active_connections)
+        props[PM_PRIMARY_CONNECTION] = to_path(self.primary_connection)
+        props[PM_ACTIVATING_CONNECTION] = to_path(self.activating_connection)
+        props[PM_STARTUP] = False
+        props[PM_STATE] = dbus.UInt32(self.state)
+        props[PM_VERSION] = "0.9.9.0"
+        props[PM_CONNECTIVITY] = dbus.UInt32(self.connectivity)
+        return props
+
+    def __notify(self, propname):
+        props = self._get_dbus_properties(IFACE_NM)
+        changed = { propname: props[propname] }
+        NetworkManager.PropertiesChanged(self, changed)
+
+    @dbus.service.signal(IFACE_NM, signature='a{sv}')
+    def PropertiesChanged(self, changed):
+        pass
+
+    ################# Testing methods
+    @dbus.service.method(IFACE_TEST, in_signature='', out_signature='')
+    def Quit(self):
+        mainloop.quit()
+
+    @dbus.service.method(IFACE_TEST, in_signature='s', out_signature='o')
+    def AddWiredDevice(self, ifname):
+        for d in self.devices:
+            if d.iface == ifname:
+                raise PermissionDeniedError("Device already added")
+        dev = WiredDevice(self._bus, ifname)
+        self.add_device(dev)
+        return dbus.ObjectPath(dev.path)
+
+    @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 PermissionDeniedError("Device already added")
+        dev = WifiDevice(self._bus, ifname)
+        self.add_device(dev)
+        return dbus.ObjectPath(dev.path)
+
+    @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 PermissionDeniedError("Device already added")
+        dev = WimaxDevice(self._bus, ifname)
+        self.add_device(dev)
+        return dbus.ObjectPath(dev.path)
+
+    @dbus.service.method(IFACE_TEST, in_signature='o', out_signature='')
+    def RemoveDevice(self, path):
+        for d in self.devices:
+            if d.path == path:
+                self.remove_device(d)
+                return
+        raise UnknownDeviceException("Device not found")
+
+    @dbus.service.method(IFACE_TEST, in_signature='sss', out_signature='o')
+    def AddWifiAp(self, ifname, ssid, mac):
+        for d in self.devices:
+            if d.iface == ifname:
+                return dbus.ObjectPath(d.add_test_ap(ssid, mac))
+        raise UnknownDeviceException("Device not found")
+
+    @dbus.service.method(IFACE_TEST, in_signature='so', out_signature='')
+    def RemoveWifiAp(self, ifname, ap_path):
+        for d in self.devices:
+            if d.iface == ifname:
+                d.remove_ap_by_path(ap_path)
+                return
+        raise UnknownDeviceException("Device not found")
+
+    @dbus.service.method(IFACE_TEST, in_signature='ss', out_signature='o')
+    def AddWimaxNsp(self, ifname, name):
+        for d in self.devices:
+            if d.iface == ifname:
+                return dbus.ObjectPath(d.add_test_nsp(name))
+        raise UnknownDeviceException("Device not found")
+
+    @dbus.service.method(IFACE_TEST, in_signature='so', out_signature='')
+    def RemoveWimaxNsp(self, ifname, nsp_path):
+        for d in self.devices:
+            if d.iface == ifname:
+                d.remove_nsp_by_path(nsp_path)
+                return
+        raise UnknownDeviceException("Device not found")
+
+def quit_cb(user_data):
+    mainloop.quit()
+
+def main():
+    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+    random.seed()
+
+    bus = dbus.SessionBus()
+    nm = NetworkManager(bus, "/org/freedesktop/NetworkManager")
+    if not bus.request_name("org.freedesktop.NetworkManager"):
+        sys.exit(1)
+
+    # quit after inactivity to ensure we don't stick around if tests fail
+    quit_id = GLib.timeout_add_seconds(20, quit_cb, None)
+
+    try:
+        mainloop.run()
+    except Exception as e:
+        pass
+
+    sys.exit(0)
+
+if __name__ == '__main__':
+    main()
+
diff --git a/libnm-glib/tests/test-nm-client.c b/libnm-glib/tests/test-nm-client.c
new file mode 100644
index 00000000..b181c8fa
--- /dev/null
+++ b/libnm-glib/tests/test-nm-client.c
@@ -0,0 +1,953 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2010 - 2014 Red Hat, Inc.
+ *
+ */
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <glib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#include <NetworkManager.h>
+#include "nm-client.h"
+#include "nm-device-wifi.h"
+#include "nm-device-ethernet.h"
+#include "nm-device-wimax.h"
+#include "nm-glib-compat.h"
+
+static const char *fake_path;
+static const char *fake_bin;
+static const char *fake_exec;
+static GMainLoop *loop = NULL;
+
+/*******************************************************************/
+
+typedef struct {
+	GDBusConnection *bus;
+	GDBusProxy *proxy;
+	GPid pid;
+	NMClient *client;
+} ServiceInfo;
+
+#define test_assert(condition) \
+do { \
+	if (!G_LIKELY (condition)) \
+		service_cleanup (); \
+	g_assert (condition); \
+} while (0)
+
+#define test_assert_cmpint(a, b, c) \
+do { \
+	if (!G_LIKELY (a b c)) \
+		service_cleanup (); \
+	g_assert_cmpint (a, b, c); \
+} while (0)
+
+#define test_assert_cmpstr(a, b, c) \
+do { \
+	if (!G_LIKELY (g_str_hash (a) b g_str_hash (c))) \
+		service_cleanup (); \
+	g_assert_cmpstr (a, b, c); \
+} while (0)
+
+#define test_assert_no_error(e) \
+do { \
+	if (G_UNLIKELY (e)) \
+		service_cleanup (); \
+	g_assert_no_error (e); \
+} while (0)
+
+static ServiceInfo * sinfo_static = NULL;
+
+static void
+service_cleanup (void)
+{
+	ServiceInfo *info = sinfo_static;
+
+	sinfo_static = NULL;
+
+	if (info) {
+		if (info->proxy)
+			g_object_unref (info->proxy);
+		if (info->bus)
+			g_object_unref (info->bus);
+		if (info->client)
+			g_object_unref (info->client);
+		if (info->pid)
+			kill (info->pid, SIGTERM);
+		memset (info, 0, sizeof (*info));
+		g_free (info);
+	} else
+		g_assert_not_reached ();
+}
+
+static gboolean
+name_exists (GDBusConnection *c, const char *name)
+{
+	GVariant *reply;
+	gboolean exists = FALSE;
+
+	reply = g_dbus_connection_call_sync (c,
+	                                     DBUS_SERVICE_DBUS,
+	                                     DBUS_PATH_DBUS,
+	                                     DBUS_INTERFACE_DBUS,
+	                                     "GetNameOwner",
+	                                     g_variant_new ("(s)", name),
+	                                     NULL,
+	                                     G_DBUS_CALL_FLAGS_NO_AUTO_START,
+	                                     -1,
+	                                     NULL,
+	                                     NULL);
+	if (reply != NULL) {
+		exists = TRUE;
+		g_variant_unref (reply);
+	}
+
+	return exists;
+}
+
+static ServiceInfo *
+service_init (void)
+{
+	ServiceInfo *sinfo;
+	const char *args[2] = { fake_exec, NULL };
+	GError *error = NULL;
+	int i = 100;
+
+	g_assert (!sinfo_static);
+
+	sinfo = g_malloc0 (sizeof (*sinfo));
+
+	sinfo_static = sinfo;
+
+	sinfo->bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL,  NULL);
+	test_assert (sinfo->bus);
+
+	if (!g_spawn_async (fake_path, (char **) args, NULL, 0, NULL, NULL, &sinfo->pid, &error))
+		test_assert_no_error (error);
+
+	/* Wait until the service is registered on the bus */
+	while (i > 0) {
+		g_usleep (G_USEC_PER_SEC / 50);
+		if (name_exists (sinfo->bus, "org.freedesktop.NetworkManager"))
+			break;
+		i--;
+	}
+	test_assert (i > 0);
+
+	/* Grab a proxy to our fake NM service to trigger tests */
+	sinfo->proxy = g_dbus_proxy_new_sync (sinfo->bus,
+	                                      G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
+	                                        G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
+	                                        G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+	                                      NULL,
+	                                      NM_DBUS_SERVICE,
+	                                      NM_DBUS_PATH,
+	                                      "org.freedesktop.NetworkManager.LibnmGlibTest",
+	                                      NULL, NULL);
+	test_assert (sinfo->proxy);
+
+	sinfo->client = nm_client_new ();
+	test_assert (sinfo->client != NULL);
+
+	return sinfo;
+}
+
+static ServiceInfo *
+service_get (void)
+{
+	g_assert (sinfo_static);
+	return sinfo_static;
+}
+
+#define _sinfo (service_get ())
+
+/*******************************************************************/
+
+static gboolean
+loop_quit (gpointer user_data)
+{
+	g_main_loop_quit ((GMainLoop *) user_data);
+	return G_SOURCE_REMOVE;
+}
+
+static gboolean
+add_device (const char *method, const char *ifname, char **out_path)
+{
+	GError *error = NULL;
+	GVariant *ret;
+
+	ret = g_dbus_proxy_call_sync (_sinfo->proxy,
+	                              method,
+	                              g_variant_new ("(s)", ifname),
+	                              G_DBUS_CALL_FLAGS_NO_AUTO_START,
+	                              3000,
+	                              NULL,
+	                              &error);
+	test_assert_no_error (error);
+	test_assert (ret);
+	test_assert_cmpstr (g_variant_get_type_string (ret), ==, "(o)");
+	if (out_path)
+		g_variant_get (ret, "(o)", out_path);
+	g_variant_unref (ret);
+	return TRUE;
+}
+
+/*******************************************************************/
+
+typedef struct {
+	GMainLoop *loop;
+	gboolean signaled;
+	gboolean notified;
+	guint quit_count;
+	guint quit_id;
+} DeviceAddedInfo;
+
+static void
+device_add_check_quit (DeviceAddedInfo *info)
+{
+	info->quit_count--;
+	if (info->quit_count == 0) {
+		g_source_remove (info->quit_id);
+		info->quit_id = 0;
+		g_main_loop_quit (info->loop);
+	}
+}
+
+static void
+device_added_cb (NMClient *c,
+                 NMDevice *device,
+                 DeviceAddedInfo *info)
+{
+	test_assert (device);
+	test_assert_cmpstr (nm_device_get_iface (device), ==, "eth0");
+	info->signaled = TRUE;
+	device_add_check_quit (info);
+}
+
+static void
+devices_notify_cb (NMClient *c,
+                   GParamSpec *pspec,
+                   DeviceAddedInfo *info)
+{
+	const GPtrArray *devices;
+	NMDevice *device;
+
+	devices = nm_client_get_devices (c);
+	test_assert (devices);
+	test_assert_cmpint (devices->len, ==, 1);
+
+	device = g_ptr_array_index (devices, 0);
+	test_assert (device);
+	test_assert_cmpstr (nm_device_get_iface (device), ==, "eth0");
+
+	info->notified = TRUE;
+
+	device_add_check_quit (info);
+}
+
+static void
+test_device_added (void)
+{
+	const GPtrArray *devices;
+	NMDevice *device;
+	DeviceAddedInfo info = { loop, FALSE, FALSE, 0, 0 };
+
+	service_init ();
+
+	/* Give NMClient a chance to initialize */
+	g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	devices = nm_client_get_devices (_sinfo->client);
+	test_assert (devices == NULL);
+
+	/* Tell the test service to add a new device */
+	add_device ("AddWiredDevice", "eth0", NULL);
+
+	g_signal_connect (_sinfo->client,
+	                  "device-added",
+	                  (GCallback) device_added_cb,
+	                  &info);
+	info.quit_count++;
+
+	g_signal_connect (_sinfo->client,
+	                  "notify::devices",
+	                  (GCallback) devices_notify_cb,
+	                  &info);
+	info.quit_count++;
+
+	/* Wait for libnm-glib to find the device */
+	info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	test_assert (info.signaled);
+	test_assert (info.notified);
+
+	g_signal_handlers_disconnect_by_func (_sinfo->client, device_added_cb, &info);
+	g_signal_handlers_disconnect_by_func (_sinfo->client, devices_notify_cb, &info);
+
+	devices = nm_client_get_devices (_sinfo->client);
+	test_assert (devices);
+	test_assert_cmpint (devices->len, ==, 1);
+
+	device = g_ptr_array_index (devices, 0);
+	test_assert (device);
+	test_assert_cmpstr (nm_device_get_iface (device), ==, "eth0");
+
+	service_cleanup ();
+}
+
+/*******************************************************************/
+
+static const char *expected_bssid = "66:55:44:33:22:11";
+
+typedef struct {
+	GMainLoop *loop;
+	gboolean found;
+	char *ap_path;
+	gboolean signaled;
+	gboolean notified;
+	guint quit_id;
+	guint quit_count;
+} WifiApInfo;
+
+static void
+wifi_check_quit (WifiApInfo *info)
+{
+	info->quit_count--;
+	if (info->quit_count == 0) {
+		g_source_remove (info->quit_id);
+		info->quit_id = 0;
+		g_main_loop_quit (info->loop);
+	}
+}
+
+static void
+wifi_device_added_cb (NMClient *c,
+                      NMDevice *device,
+                      WifiApInfo *info)
+{
+	test_assert_cmpstr (nm_device_get_iface (device), ==, "wlan0");
+	info->found = TRUE;
+	wifi_check_quit (info);
+}
+
+static void
+got_ap_path (WifiApInfo *info, const char *path)
+{
+	if (info->ap_path)
+		test_assert_cmpstr (info->ap_path, ==, path);
+	else
+		info->ap_path = g_strdup (path);
+}
+
+static void
+wifi_ap_added_cb (NMDeviceWifi *w,
+                  NMAccessPoint *ap,
+                  WifiApInfo *info)
+{
+	test_assert (ap);
+	test_assert_cmpstr (nm_access_point_get_bssid (ap), ==, expected_bssid);
+	got_ap_path (info, nm_object_get_path (NM_OBJECT (ap)));
+
+	info->signaled = TRUE;
+	wifi_check_quit (info);
+}
+
+static void
+wifi_ap_add_notify_cb (NMDeviceWifi *w,
+                       GParamSpec *pspec,
+                       WifiApInfo *info)
+{
+	const GPtrArray *aps;
+	NMAccessPoint *ap;
+
+	aps = nm_device_wifi_get_access_points (w);
+	test_assert (aps);
+	test_assert_cmpint (aps->len, ==, 1);
+
+	ap = g_ptr_array_index (aps, 0);
+	test_assert (ap);
+	test_assert_cmpstr (nm_access_point_get_bssid (ap), ==, "66:55:44:33:22:11");
+	got_ap_path (info, nm_object_get_path (NM_OBJECT (ap)));
+
+	info->notified = TRUE;
+	wifi_check_quit (info);
+}
+
+static void
+wifi_ap_removed_cb (NMDeviceWifi *w,
+                    NMAccessPoint *ap,
+                    WifiApInfo *info)
+{
+	test_assert (ap);
+	test_assert_cmpstr (info->ap_path, ==, nm_object_get_path (NM_OBJECT (ap)));
+
+	info->signaled = TRUE;
+	wifi_check_quit (info);
+}
+
+static void
+wifi_ap_remove_notify_cb (NMDeviceWifi *w,
+                          GParamSpec *pspec,
+                          WifiApInfo *info)
+{
+	const GPtrArray *aps;
+
+	aps = nm_device_wifi_get_access_points (w);
+	test_assert (aps == NULL);
+
+	info->notified = TRUE;
+	wifi_check_quit (info);
+}
+
+static void
+test_wifi_ap_added_removed (void)
+{
+	NMDeviceWifi *wifi;
+	WifiApInfo info = { loop, FALSE, FALSE, 0, 0 };
+	GVariant *ret;
+	GError *error = NULL;
+	char *expected_path = NULL;
+
+	service_init ();
+
+	/* Give NMClient a chance to initialize */
+	g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	/*************************************/
+	/* Add the wifi device */
+	add_device ("AddWifiDevice", "wlan0", NULL);
+
+	g_signal_connect (_sinfo->client,
+	                  "device-added",
+	                  (GCallback) wifi_device_added_cb,
+	                  &info);
+	info.quit_count = 1;
+
+	/* Wait for libnm-glib to find the device */
+	info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	test_assert (info.found);
+	g_signal_handlers_disconnect_by_func (_sinfo->client, wifi_device_added_cb, &info);
+
+	wifi = (NMDeviceWifi *) nm_client_get_device_by_iface (_sinfo->client, "wlan0");
+	test_assert (NM_IS_DEVICE_WIFI (wifi));
+
+	/*************************************/
+	/* Add the wifi device */
+	info.signaled =  FALSE;
+	info.notified = FALSE;
+	info.quit_id = 0;
+
+	ret = g_dbus_proxy_call_sync (_sinfo->proxy,
+	                              "AddWifiAp",
+	                              g_variant_new ("(sss)", "wlan0", "test-ap", expected_bssid),
+	                              G_DBUS_CALL_FLAGS_NO_AUTO_START,
+	                              3000,
+	                              NULL,
+	                              &error);
+	test_assert_no_error (error);
+	test_assert (ret);
+	test_assert_cmpstr (g_variant_get_type_string (ret), ==, "(o)");
+	g_variant_get (ret, "(o)", &expected_path);
+	g_variant_unref (ret);
+
+	g_signal_connect (wifi,
+	                  "access-point-added",
+	                  (GCallback) wifi_ap_added_cb,
+	                  &info);
+	info.quit_count = 1;
+
+	g_signal_connect (wifi,
+	                  "notify::access-points",
+	                  (GCallback) wifi_ap_add_notify_cb,
+	                  &info);
+	info.quit_count++;
+
+	/* Wait for libnm-glib to find the AP */
+	info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	test_assert (info.signaled);
+	test_assert (info.notified);
+	test_assert (info.ap_path);
+	test_assert_cmpstr (info.ap_path, ==, expected_path);
+	g_signal_handlers_disconnect_by_func (wifi, wifi_ap_added_cb, &info);
+	g_signal_handlers_disconnect_by_func (wifi, wifi_ap_add_notify_cb, &info);
+
+	/*************************************/
+	/* Remove the wifi device */
+	info.signaled =  FALSE;
+	info.notified = FALSE;
+	info.quit_id = 0;
+
+	ret = g_dbus_proxy_call_sync (_sinfo->proxy,
+	                              "RemoveWifiAp",
+	                              g_variant_new ("(so)", "wlan0", expected_path),
+	                              G_DBUS_CALL_FLAGS_NO_AUTO_START,
+	                              3000,
+	                              NULL,
+	                              &error);
+	test_assert_no_error (error);
+	g_clear_pointer (&ret, g_variant_unref);
+
+	g_signal_connect (wifi,
+	                  "access-point-removed",
+	                  (GCallback) wifi_ap_removed_cb,
+	                  &info);
+	info.quit_count = 1;
+
+	g_signal_connect (wifi,
+	                  "notify::access-points",
+	                  (GCallback) wifi_ap_remove_notify_cb,
+	                  &info);
+	info.quit_count++;
+
+	/* Wait for libnm-glib to find the AP */
+	info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	test_assert (info.signaled);
+	test_assert (info.notified);
+	g_signal_handlers_disconnect_by_func (wifi, wifi_ap_removed_cb, &info);
+	g_signal_handlers_disconnect_by_func (wifi, wifi_ap_remove_notify_cb, &info);
+
+	g_free (info.ap_path);
+	g_free (expected_path);
+	service_cleanup ();
+}
+
+/*******************************************************************/
+
+static const char *expected_nsp_name = "Clear";
+
+typedef struct {
+	GMainLoop *loop;
+	gboolean found;
+	char *nsp_path;
+	gboolean signaled;
+	gboolean notified;
+	guint quit_id;
+	guint quit_count;
+} WimaxNspInfo;
+
+static void
+wimax_check_quit (WimaxNspInfo *info)
+{
+	info->quit_count--;
+	if (info->quit_count == 0) {
+		g_source_remove (info->quit_id);
+		info->quit_id = 0;
+		g_main_loop_quit (info->loop);
+	}
+}
+
+static void
+wimax_device_added_cb (NMClient *c,
+                       NMDevice *device,
+                       WimaxNspInfo *info)
+{
+	test_assert_cmpstr (nm_device_get_iface (device), ==, "wmx0");
+	info->found = TRUE;
+	wimax_check_quit (info);
+}
+
+static void
+got_nsp_path (WimaxNspInfo *info, const char *path)
+{
+	if (info->nsp_path)
+		test_assert_cmpstr (info->nsp_path, ==, path);
+	else
+		info->nsp_path = g_strdup (path);
+}
+
+static void
+wimax_nsp_added_cb (NMDeviceWimax *w,
+                    NMWimaxNsp *nsp,
+                    WimaxNspInfo *info)
+{
+	test_assert (nsp);
+	test_assert_cmpstr (nm_wimax_nsp_get_name (nsp), ==, expected_nsp_name);
+	got_nsp_path (info, nm_object_get_path (NM_OBJECT (nsp)));
+
+	info->signaled = TRUE;
+	wimax_check_quit (info);
+}
+
+static void
+wimax_nsp_add_notify_cb (NMDeviceWimax *w,
+                         GParamSpec *pspec,
+                         WimaxNspInfo *info)
+{
+	const GPtrArray *nsps;
+	NMWimaxNsp *nsp;
+
+	nsps = nm_device_wimax_get_nsps (w);
+	test_assert (nsps);
+	test_assert_cmpint (nsps->len, ==, 1);
+
+	nsp = g_ptr_array_index (nsps, 0);
+	test_assert (nsp);
+	test_assert_cmpstr (nm_wimax_nsp_get_name (nsp), ==, expected_nsp_name);
+	got_nsp_path (info, nm_object_get_path (NM_OBJECT (nsp)));
+
+	info->notified = TRUE;
+	wimax_check_quit (info);
+}
+
+static void
+wimax_nsp_removed_cb (NMDeviceWimax *w,
+                      NMWimaxNsp *nsp,
+                      WimaxNspInfo *info)
+{
+	test_assert (nsp);
+	test_assert_cmpstr (info->nsp_path, ==, nm_object_get_path (NM_OBJECT (nsp)));
+
+	info->signaled = TRUE;
+	wimax_check_quit (info);
+}
+
+static void
+wimax_nsp_remove_notify_cb (NMDeviceWimax *w,
+                            GParamSpec *pspec,
+                            WimaxNspInfo *info)
+{
+	const GPtrArray *nsps;
+
+	nsps = nm_device_wimax_get_nsps (w);
+	test_assert (nsps == NULL);
+
+	info->notified = TRUE;
+	wimax_check_quit (info);
+}
+
+static void
+test_wimax_nsp_added_removed (void)
+{
+	NMDeviceWimax *wimax;
+	WimaxNspInfo info = { loop, FALSE, FALSE, 0, 0 };
+	GVariant *ret;
+	GError *error = NULL;
+	char *expected_path = NULL;
+
+	service_init ();
+
+	/* Give NMClient a chance to initialize */
+	g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	/*************************************/
+	/* Add the wimax device */
+	add_device ("AddWimaxDevice", "wmx0", NULL);
+
+	g_signal_connect (_sinfo->client,
+	                  "device-added",
+	                  (GCallback) wimax_device_added_cb,
+	                  &info);
+	info.quit_count = 1;
+
+	/* Wait for libnm-glib to find the device */
+	info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	test_assert (info.found);
+	g_signal_handlers_disconnect_by_func (_sinfo->client, wimax_device_added_cb, &info);
+
+	wimax = (NMDeviceWimax *) nm_client_get_device_by_iface (_sinfo->client, "wmx0");
+	test_assert (NM_IS_DEVICE_WIMAX (wimax));
+
+	/*************************************/
+	/* Add the wimax NSP */
+	info.signaled =  FALSE;
+	info.notified = FALSE;
+	info.quit_id = 0;
+
+	ret = g_dbus_proxy_call_sync (_sinfo->proxy,
+	                              "AddWimaxNsp",
+	                              g_variant_new ("(ss)", "wmx0", expected_nsp_name),
+	                              G_DBUS_CALL_FLAGS_NO_AUTO_START,
+	                              3000,
+	                              NULL,
+	                              &error);
+	test_assert_no_error (error);
+	test_assert (ret);
+	test_assert_cmpstr (g_variant_get_type_string (ret), ==, "(o)");
+	g_variant_get (ret, "(o)", &expected_path);
+	g_variant_unref (ret);
+
+	g_signal_connect (wimax,
+	                  "nsp-added",
+	                  (GCallback) wimax_nsp_added_cb,
+	                  &info);
+	info.quit_count = 1;
+
+	g_signal_connect (wimax,
+	                  "notify::nsps",
+	                  (GCallback) wimax_nsp_add_notify_cb,
+	                  &info);
+	info.quit_count++;
+
+	/* Wait for libnm-glib to find the AP */
+	info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	test_assert (info.signaled);
+	test_assert (info.notified);
+	test_assert (info.nsp_path);
+	test_assert_cmpstr (info.nsp_path, ==, expected_path);
+	g_signal_handlers_disconnect_by_func (wimax, wimax_nsp_added_cb, &info);
+	g_signal_handlers_disconnect_by_func (wimax, wimax_nsp_add_notify_cb, &info);
+
+	/*************************************/
+	/* Remove the wimax NSP */
+	info.signaled =  FALSE;
+	info.notified = FALSE;
+	info.quit_id = 0;
+
+	ret = g_dbus_proxy_call_sync (_sinfo->proxy,
+	                              "RemoveWimaxNsp",
+	                              g_variant_new ("(so)", "wmx0", expected_path),
+	                              G_DBUS_CALL_FLAGS_NO_AUTO_START,
+	                              3000,
+	                              NULL,
+	                              &error);
+	test_assert_no_error (error);
+	g_clear_pointer (&ret, g_variant_unref);
+
+	g_signal_connect (wimax,
+	                  "nsp-removed",
+	                  (GCallback) wimax_nsp_removed_cb,
+	                  &info);
+	info.quit_count = 1;
+
+	g_signal_connect (wimax,
+	                  "notify::nsps",
+	                  (GCallback) wimax_nsp_remove_notify_cb,
+	                  &info);
+	info.quit_count++;
+
+	/* Wait for libnm-glib to find the AP */
+	info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	test_assert (info.signaled);
+	test_assert (info.notified);
+	g_signal_handlers_disconnect_by_func (wimax, wimax_nsp_removed_cb, &info);
+	g_signal_handlers_disconnect_by_func (wimax, wimax_nsp_remove_notify_cb, &info);
+
+	g_free (info.nsp_path);
+	g_free (expected_path);
+	service_cleanup ();
+}
+
+/*******************************************************************/
+
+typedef struct {
+	GMainLoop *loop;
+	gboolean signaled;
+	gboolean notified;
+	guint quit_count;
+	guint quit_id;
+} DaInfo;
+
+static void
+da_check_quit (DaInfo *info)
+{
+	info->quit_count--;
+	if (info->quit_count == 0) {
+		g_source_remove (info->quit_id);
+		info->quit_id = 0;
+		g_main_loop_quit (info->loop);
+	}
+}
+
+static void
+da_device_added_cb (NMClient *c,
+                    NMDevice *device,
+                    DaInfo *info)
+{
+	da_check_quit (info);
+}
+
+static void
+da_device_removed_cb (NMClient *c,
+                      NMDevice *device,
+                      DaInfo *info)
+{
+	test_assert_cmpstr (nm_device_get_iface (device), ==, "eth0");
+	info->signaled = TRUE;
+	da_check_quit (info);
+}
+
+static void
+da_devices_notify_cb (NMClient *c,
+                      GParamSpec *pspec,
+                      DaInfo *info)
+{
+	const GPtrArray *devices;
+	NMDevice *device;
+	guint i;
+	const char *iface;
+
+	devices = nm_client_get_devices (c);
+	test_assert (devices);
+	test_assert_cmpint (devices->len, ==, 2);
+
+	for (i = 0; i < devices->len; i++) {
+		device = g_ptr_array_index (devices, i);
+		iface = nm_device_get_iface (device);
+
+		test_assert (!strcmp (iface, "wlan0") || !strcmp (iface, "eth1"));
+	}
+
+	info->notified = TRUE;
+	da_check_quit (info);
+}
+
+static void
+test_devices_array (void)
+{
+	DaInfo info = { loop };
+	char *paths[3] = { NULL, NULL, NULL };
+	NMDevice *device;
+	const GPtrArray *devices;
+	GError *error = NULL;
+	GVariant *ret;
+
+	service_init ();
+
+	/* Give NMClient a chance to initialize */
+	g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	/*************************************/
+	/* Add some devices */
+	add_device ("AddWifiDevice", "wlan0", &paths[0]);
+	add_device ("AddWiredDevice", "eth0", &paths[1]);
+	add_device ("AddWiredDevice", "eth1", &paths[2]);
+	info.quit_count = 3;
+
+	g_signal_connect (_sinfo->client,
+	                  "device-added",
+	                  (GCallback) da_device_added_cb,
+	                  &info);
+
+	/* Wait for libnm-glib to find the device */
+	info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	test_assert_cmpint (info.quit_count, ==, 0);
+	g_signal_handlers_disconnect_by_func (_sinfo->client, da_device_added_cb, &info);
+
+	/* Ensure the devices now exist */
+	devices = nm_client_get_devices (_sinfo->client);
+	test_assert (devices);
+	test_assert_cmpint (devices->len, ==, 3);
+
+	device = nm_client_get_device_by_iface (_sinfo->client, "wlan0");
+	test_assert (NM_IS_DEVICE_WIFI (device));
+
+	device = nm_client_get_device_by_iface (_sinfo->client, "eth0");
+	test_assert (NM_IS_DEVICE_ETHERNET (device));
+
+	device = nm_client_get_device_by_iface (_sinfo->client, "eth1");
+	test_assert (NM_IS_DEVICE_ETHERNET (device));
+
+	/********************************/
+	/* Now remove the device in the middle */
+	ret = g_dbus_proxy_call_sync (_sinfo->proxy,
+	                              "RemoveDevice",
+	                              g_variant_new ("(o)", paths[1]),
+	                              G_DBUS_CALL_FLAGS_NO_AUTO_START,
+	                              3000,
+	                              NULL,
+	                              &error);
+	test_assert_no_error (error);
+	test_assert (ret);
+	g_variant_unref (ret);
+
+	g_signal_connect (_sinfo->client,
+	                  "device-removed",
+	                  (GCallback) da_device_removed_cb,
+	                  &info);
+
+	g_signal_connect (_sinfo->client,
+	                  "notify::devices",
+	                  (GCallback) da_devices_notify_cb,
+	                  &info);
+	info.quit_count = 2;
+
+	/* Wait for libnm-glib to find the device */
+	info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	test_assert_cmpint (info.quit_count, ==, 0);
+	g_signal_handlers_disconnect_by_func (_sinfo->client, da_device_removed_cb, &info);
+	g_signal_handlers_disconnect_by_func (_sinfo->client, da_devices_notify_cb, &info);
+
+	/* Ensure only two are left */
+	devices = nm_client_get_devices (_sinfo->client);
+	test_assert (devices);
+	test_assert_cmpint (devices->len, ==, 2);
+
+	device = nm_client_get_device_by_iface (_sinfo->client, "wlan0");
+	test_assert (NM_IS_DEVICE_WIFI (device));
+
+	device = nm_client_get_device_by_iface (_sinfo->client, "eth1");
+	test_assert (NM_IS_DEVICE_ETHERNET (device));
+
+	g_free (paths[0]);
+	g_free (paths[1]);
+	g_free (paths[2]);
+	service_cleanup ();
+}
+
+/*******************************************************************/
+
+int
+main (int argc, char **argv)
+{
+	g_assert (argc == 3);
+
+#if !GLIB_CHECK_VERSION (2, 35, 0)
+	g_type_init ();
+#endif
+
+	g_test_init (&argc, &argv, NULL);
+
+	fake_path = argv[1];
+	fake_bin = argv[2];
+	fake_exec = g_strdup_printf ("%s/%s", argv[1], argv[2]);
+
+	loop = g_main_loop_new (NULL, FALSE);
+
+	g_test_add_func ("/libnm-glib/device-added", test_device_added);
+	g_test_add_func ("/libnm-glib/wifi-ap-added-removed", test_wifi_ap_added_removed);
+	g_test_add_func ("/libnm-glib/wimax-nsp-added-removed", test_wimax_nsp_added_removed);
+	g_test_add_func ("/libnm-glib/devices-array", test_devices_array);
+
+	return g_test_run ();
+}
+
diff --git a/libnm-glib/tests/test-remote-settings-client.c b/libnm-glib/tests/test-remote-settings-client.c
index ad62075d..e3ef7f22 100644
--- a/libnm-glib/tests/test-remote-settings-client.c
+++ b/libnm-glib/tests/test-remote-settings-client.c
@@ -342,17 +342,9 @@ test_remove_connection (void)
 
 /*******************************************************************/
 
-#if GLIB_CHECK_VERSION(2,25,12)
-typedef GTestFixtureFunc TCFunc;
-#else
-typedef void (*TCFunc)(void);
-#endif
-
-#define TESTCASE(t, d) g_test_create_case (#t, 0, d, NULL, (TCFunc) t, NULL)
-
-int main (int argc, char **argv)
+int
+main (int argc, char **argv)
 {
-	GTestSuite *suite;
     char *service_argv[3] = { NULL, NULL, NULL };
 	int ret;
 	GError *error = NULL;
@@ -360,7 +352,9 @@ int main (int argc, char **argv)
 
 	g_assert (argc == 3);
 
+#if !GLIB_CHECK_VERSION (2, 35, 0)
 	g_type_init ();
+#endif
 	
 	g_test_init (&argc, &argv, NULL);
 
@@ -390,12 +384,10 @@ int main (int argc, char **argv)
 	settings = nm_remote_settings_new (bus);
 	test_assert (settings != NULL);
 
-	suite = g_test_get_root ();
-
-	g_test_suite_add (suite, TESTCASE (test_add_connection, NULL));
-	g_test_suite_add (suite, TESTCASE (test_make_invisible, NULL));
-	g_test_suite_add (suite, TESTCASE (test_make_visible, NULL));
-	g_test_suite_add (suite, TESTCASE (test_remove_connection, NULL));
+	g_test_add_func ("/remote_settings/add_connection", test_add_connection);
+	g_test_add_func ("/remote_settings/make_invisible", test_make_invisible);
+	g_test_add_func ("/remote_settings/make_visible", test_make_visible);
+	g_test_add_func ("/remote_settings/remove_connection", test_remove_connection);
 
 	ret = g_test_run ();
 
diff --git a/libnm-glib/tests/test-remote-settings-service.py b/libnm-glib/tests/test-remote-settings-service.py
index 86542005..439073ad 100755
--- a/libnm-glib/tests/test-remote-settings-service.py
+++ b/libnm-glib/tests/test-remote-settings-service.py
@@ -1,8 +1,9 @@
 #!/usr/bin/env python
 # -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 
-import glib
-import gobject
+from __future__ import print_function
+
+from gi.repository import GLib, GObject
 import sys
 import dbus
 import dbus.service
@@ -21,7 +22,7 @@ class UnknownPropertyException(dbus.DBusException):
 class PermissionDeniedException(dbus.DBusException):
     _dbus_error_name = IFACE_SETTINGS + '.PermissionDenied'
 
-mainloop = gobject.MainLoop()
+mainloop = GObject.MainLoop()
 
 class Connection(dbus.service.Object):
     def __init__(self, bus, object_path, settings, remove_func):
@@ -30,7 +31,25 @@ class Connection(dbus.service.Object):
         self.settings = settings
         self.remove_func = remove_func
         self.visible = True
+        self.props = {}
+        self.props['Unsaved'] = False
+
+    # Properties interface
+    @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='s', out_signature='a{sv}')
+    def GetAll(self, iface):
+        if iface != IFACE_CONNECTION:
+            raise UnknownInterfaceException()
+        return self.props
+
+    @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='ss', out_signature='v')
+    def Get(self, iface, name):
+        if iface != IFACE_CONNECTION:
+            raise UnknownInterfaceException()
+        if not name in self.props.keys():
+            raise UnknownPropertyException()
+        return self.props[name]
 
+    # Connection methods
     @dbus.service.method(dbus_interface=IFACE_CONNECTION, in_signature='', out_signature='a{sa{sv}}')
     def GetSettings(self):
         if not self.visible:
@@ -72,10 +91,10 @@ class Settings(dbus.service.Object):
 
     @dbus.service.method(dbus_interface=IFACE_SETTINGS, in_signature='a{sa{sv}}', out_signature='o')
     def AddConnection(self, settings):
-        path = "/org/freedesktop/NetworkManager/Settings/Connection/%d" % self.counter
+        path = "/org/freedesktop/NetworkManager/Settings/Connection/{0}".format(self.counter)
         self.counter = self.counter + 1
         self.connections[path] = Connection(self.bus, path, settings, self.delete_connection)
-        print "Added connection %s" % path
+        print("Added connection {0}".format(path))
         return path
 
     def delete_connection(self, connection):
@@ -114,16 +133,16 @@ def main():
     if not bus.request_name("org.freedesktop.NetworkManager"):
         sys.exit(1)
 
-    print "Service started"
+    print("Service started")
 
-    gobject.timeout_add_seconds(20, quit_cb, None)
+    GLib.timeout_add_seconds(20, quit_cb, None)
 
     try:
         mainloop.run()
-    except Exception, e:
+    except Exception as e:
         pass
 
-    print "Service stopped"
+    print("Service stopped")
     sys.exit(0)
 
 if __name__ == '__main__':