summary refs log tree commit diff
path: root/libnm-core/tests
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2015-01-22 00:29:39 +0100
committerMichael Biebl <biebl@debian.org>2015-01-22 00:29:39 +0100
commit2c032d8f1c6292c1338a615e6ec40252889ba85c (patch)
tree1f77182220b2b0264288ba4a476ab47e5bc48716 /libnm-core/tests
parent33491bc4279481db8ae47213e34a6d695a0e8830 (diff)
Imported Upstream version 1.0.0 upstream/1.0.0
Diffstat (limited to 'libnm-core/tests')
-rw-r--r--libnm-core/tests/Makefile.am56
-rw-r--r--libnm-core/tests/Makefile.in959
-rw-r--r--libnm-core/tests/certs/ca-no-ending-newline.pem15
-rw-r--r--libnm-core/tests/certs/pkcs8-decrypted.derbin0 -> 1194 bytes
-rw-r--r--libnm-core/tests/certs/pkcs8-enc-key.pem29
-rw-r--r--libnm-core/tests/certs/pkcs8-noenc-key.pem28
-rw-r--r--libnm-core/tests/certs/test-aes-key.pem30
-rw-r--r--libnm-core/tests/certs/test-cert.p12bin0 -> 4092 bytes
-rw-r--r--libnm-core/tests/certs/test-key-only-decrypted.derbin0 -> 1192 bytes
-rw-r--r--libnm-core/tests/certs/test-key-only-decrypted.pem27
-rw-r--r--libnm-core/tests/certs/test-key-only.pem92
-rw-r--r--libnm-core/tests/certs/test2-cert.p12bin0 -> 4136 bytes
-rw-r--r--libnm-core/tests/certs/test2_ca_cert.pem27
-rw-r--r--libnm-core/tests/certs/test2_key_and_cert.pem119
-rw-r--r--libnm-core/tests/certs/test_ca_cert.derbin0 -> 1162 bytes
-rw-r--r--libnm-core/tests/certs/test_ca_cert.pem27
-rw-r--r--libnm-core/tests/certs/test_key_and_cert.pem119
-rw-r--r--libnm-core/tests/test-compare.c248
-rw-r--r--libnm-core/tests/test-crypto.c501
-rw-r--r--libnm-core/tests/test-general.c3961
-rw-r--r--libnm-core/tests/test-secrets.c766
-rw-r--r--libnm-core/tests/test-setting-8021x.c458
-rw-r--r--libnm-core/tests/test-setting-dcb.c326
-rw-r--r--libnm-core/tests/test-settings-defaults.c133
24 files changed, 7921 insertions, 0 deletions
diff --git a/libnm-core/tests/Makefile.am b/libnm-core/tests/Makefile.am
new file mode 100644
index 00000000..a21c131c
--- /dev/null
+++ b/libnm-core/tests/Makefile.am
@@ -0,0 +1,56 @@
+if ENABLE_TESTS
+
+certsdir = $(srcdir)/certs
+
+AM_CPPFLAGS = \
+	-I${top_srcdir}/include \
+	-I$(top_srcdir)/libnm-core \
+	-I$(top_builddir)/libnm-core \
+	-DNETWORKMANAGER_COMPILATION \
+	-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
+	$(GLIB_CFLAGS) \
+	-DTEST_CERT_DIR=\"$(certsdir)\"
+
+noinst_PROGRAMS =		\
+	test-compare		\
+	test-crypto		\
+	test-general		\
+	test-secrets		\
+	test-setting-8021x	\
+	test-setting-dcb	\
+	test-settings-defaults
+
+LDADD = \
+	$(top_builddir)/libnm-core/libnm-core.la \
+	$(GLIB_LIBS)
+
+TESTS = $(noinst_PROGRAMS)
+
+endif
+
+# test-cert.p12 created with:
+#
+# openssl pkcs12 -export \
+#	-in test_key_and_cert.pem \
+#	-inkey test_key_and_cert.pem \
+#	-certfile test_ca_cert.pem \
+#	-name "test-pkcs12" \
+#	-out test-cert.p12
+
+EXTRA_DIST =                              \
+	certs/test_ca_cert.pem            \
+	certs/test_ca_cert.der            \
+	certs/test_key_and_cert.pem       \
+	certs/test-cert.p12               \
+	certs/test2_ca_cert.pem           \
+	certs/test2_key_and_cert.pem      \
+	certs/test2-cert.p12              \
+	certs/ca-no-ending-newline.pem    \
+	certs/test-key-only.pem           \
+	certs/test-key-only-decrypted.der \
+	certs/test-key-only-decrypted.pem \
+	certs/pkcs8-enc-key.pem           \
+	certs/pkcs8-noenc-key.pem         \
+	certs/pkcs8-decrypted.der         \
+	certs/test-aes-key.pem
+
diff --git a/libnm-core/tests/Makefile.in b/libnm-core/tests/Makefile.in
new file mode 100644
index 00000000..b62df8b4
--- /dev/null
+++ b/libnm-core/tests/Makefile.in
@@ -0,0 +1,959 @@
+# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@ENABLE_TESTS_TRUE@noinst_PROGRAMS = test-compare$(EXEEXT) \
+@ENABLE_TESTS_TRUE@	test-crypto$(EXEEXT) test-general$(EXEEXT) \
+@ENABLE_TESTS_TRUE@	test-secrets$(EXEEXT) \
+@ENABLE_TESTS_TRUE@	test-setting-8021x$(EXEEXT) \
+@ENABLE_TESTS_TRUE@	test-setting-dcb$(EXEEXT) \
+@ENABLE_TESTS_TRUE@	test-settings-defaults$(EXEEXT)
+subdir = libnm-core/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/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 \
+	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
+	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
+	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+PROGRAMS = $(noinst_PROGRAMS)
+test_compare_SOURCES = test-compare.c
+test_compare_OBJECTS = test-compare.$(OBJEXT)
+test_compare_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+@ENABLE_TESTS_TRUE@test_compare_DEPENDENCIES =  \
+@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-core/libnm-core.la \
+@ENABLE_TESTS_TRUE@	$(am__DEPENDENCIES_1)
+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 = 
+test_crypto_SOURCES = test-crypto.c
+test_crypto_OBJECTS = test-crypto.$(OBJEXT)
+test_crypto_LDADD = $(LDADD)
+@ENABLE_TESTS_TRUE@test_crypto_DEPENDENCIES =  \
+@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-core/libnm-core.la \
+@ENABLE_TESTS_TRUE@	$(am__DEPENDENCIES_1)
+test_general_SOURCES = test-general.c
+test_general_OBJECTS = test-general.$(OBJEXT)
+test_general_LDADD = $(LDADD)
+@ENABLE_TESTS_TRUE@test_general_DEPENDENCIES =  \
+@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-core/libnm-core.la \
+@ENABLE_TESTS_TRUE@	$(am__DEPENDENCIES_1)
+test_secrets_SOURCES = test-secrets.c
+test_secrets_OBJECTS = test-secrets.$(OBJEXT)
+test_secrets_LDADD = $(LDADD)
+@ENABLE_TESTS_TRUE@test_secrets_DEPENDENCIES =  \
+@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-core/libnm-core.la \
+@ENABLE_TESTS_TRUE@	$(am__DEPENDENCIES_1)
+test_setting_8021x_SOURCES = test-setting-8021x.c
+test_setting_8021x_OBJECTS = test-setting-8021x.$(OBJEXT)
+test_setting_8021x_LDADD = $(LDADD)
+@ENABLE_TESTS_TRUE@test_setting_8021x_DEPENDENCIES =  \
+@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-core/libnm-core.la \
+@ENABLE_TESTS_TRUE@	$(am__DEPENDENCIES_1)
+test_setting_dcb_SOURCES = test-setting-dcb.c
+test_setting_dcb_OBJECTS = test-setting-dcb.$(OBJEXT)
+test_setting_dcb_LDADD = $(LDADD)
+@ENABLE_TESTS_TRUE@test_setting_dcb_DEPENDENCIES =  \
+@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-core/libnm-core.la \
+@ENABLE_TESTS_TRUE@	$(am__DEPENDENCIES_1)
+test_settings_defaults_SOURCES = test-settings-defaults.c
+test_settings_defaults_OBJECTS = test-settings-defaults.$(OBJEXT)
+test_settings_defaults_LDADD = $(LDADD)
+@ENABLE_TESTS_TRUE@test_settings_defaults_DEPENDENCIES =  \
+@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-core/libnm-core.la \
+@ENABLE_TESTS_TRUE@	$(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
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+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-compare.c test-crypto.c test-general.c test-secrets.c \
+	test-setting-8021x.c test-setting-dcb.c \
+	test-settings-defaults.c
+DIST_SOURCES = test-compare.c test-crypto.c test-general.c \
+	test-secrets.c test-setting-8021x.c test-setting-dcb.c \
+	test-settings-defaults.c
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+  mgn= red= grn= lgn= blu= brg= std=; \
+  am__color_tests=no
+am__tty_colors = { \
+  $(am__tty_colors_dummy); \
+  if test "X$(AM_COLOR_TESTS)" = Xno; then \
+    am__color_tests=no; \
+  elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+    am__color_tests=yes; \
+  elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+    am__color_tests=yes; \
+  fi; \
+  if test $$am__color_tests = yes; then \
+    red=''; \
+    grn=''; \
+    lgn=''; \
+    blu=''; \
+    mgn=''; \
+    brg=''; \
+    std=''; \
+  fi; \
+}
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ5_CFLAGS = @BLUEZ5_CFLAGS@
+BLUEZ5_LIBS = @BLUEZ5_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CKDB_PATH = @CKDB_PATH@
+CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@
+CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@
+CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+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@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GENHTML = @GENHTML@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
+GNUTLS_LIBS = @GNUTLS_LIBS@
+GREP = @GREP@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
+INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
+INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@
+INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@
+INTROSPECTION_LIBS = @INTROSPECTION_LIBS@
+INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@
+INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@
+INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@
+IPTABLES_PATH = @IPTABLES_PATH@
+IWMX_SDK_CFLAGS = @IWMX_SDK_CFLAGS@
+IWMX_SDK_LIBS = @IWMX_SDK_LIBS@
+KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDL = @LIBDL@
+LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
+LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
+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@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MM_GLIB_CFLAGS = @MM_GLIB_CFLAGS@
+MM_GLIB_LIBS = @MM_GLIB_LIBS@
+MOC = @MOC@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NEWT_CFLAGS = @NEWT_CFLAGS@
+NEWT_LIBS = @NEWT_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
+NM_MICRO_VERSION = @NM_MICRO_VERSION@
+NM_MINOR_VERSION = @NM_MINOR_VERSION@
+NM_MODIFY_SYSTEM_POLICY = @NM_MODIFY_SYSTEM_POLICY@
+NM_VERSION = @NM_VERSION@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+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@
+SYSTEMD_200_CFLAGS = @SYSTEMD_200_CFLAGS@
+SYSTEMD_200_LIBS = @SYSTEMD_200_LIBS@
+SYSTEMD_INHIBIT_CFLAGS = @SYSTEMD_INHIBIT_CFLAGS@
+SYSTEMD_INHIBIT_LIBS = @SYSTEMD_INHIBIT_LIBS@
+SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@
+SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@
+SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
+UDEV_DIR = @UDEV_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@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nmbinary = @nmbinary@
+nmconfdir = @nmconfdir@
+nmdatadir = @nmdatadir@
+nmrundir = @nmrundir@
+nmstatedir = @nmstatedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+systemdsystemunitdir = @systemdsystemunitdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+with_dhclient = @with_dhclient@
+with_dhcpcd = @with_dhcpcd@
+with_netconfig = @with_netconfig@
+with_resolvconf = @with_resolvconf@
+with_valgrind = @with_valgrind@
+@ENABLE_TESTS_TRUE@certsdir = $(srcdir)/certs
+@ENABLE_TESTS_TRUE@AM_CPPFLAGS = \
+@ENABLE_TESTS_TRUE@	-I${top_srcdir}/include \
+@ENABLE_TESTS_TRUE@	-I$(top_srcdir)/libnm-core \
+@ENABLE_TESTS_TRUE@	-I$(top_builddir)/libnm-core \
+@ENABLE_TESTS_TRUE@	-DNETWORKMANAGER_COMPILATION \
+@ENABLE_TESTS_TRUE@	-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
+@ENABLE_TESTS_TRUE@	$(GLIB_CFLAGS) \
+@ENABLE_TESTS_TRUE@	-DTEST_CERT_DIR=\"$(certsdir)\"
+
+@ENABLE_TESTS_TRUE@LDADD = \
+@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-core/libnm-core.la \
+@ENABLE_TESTS_TRUE@	$(GLIB_LIBS)
+
+@ENABLE_TESTS_TRUE@TESTS = $(noinst_PROGRAMS)
+
+# test-cert.p12 created with:
+#
+# openssl pkcs12 -export \
+#	-in test_key_and_cert.pem \
+#	-inkey test_key_and_cert.pem \
+#	-certfile test_ca_cert.pem \
+#	-name "test-pkcs12" \
+#	-out test-cert.p12
+EXTRA_DIST = \
+	certs/test_ca_cert.pem            \
+	certs/test_ca_cert.der            \
+	certs/test_key_and_cert.pem       \
+	certs/test-cert.p12               \
+	certs/test2_ca_cert.pem           \
+	certs/test2_key_and_cert.pem      \
+	certs/test2-cert.p12              \
+	certs/ca-no-ending-newline.pem    \
+	certs/test-key-only.pem           \
+	certs/test-key-only-decrypted.der \
+	certs/test-key-only-decrypted.pem \
+	certs/pkcs8-enc-key.pem           \
+	certs/pkcs8-noenc-key.pem         \
+	certs/pkcs8-decrypted.der         \
+	certs/test-aes-key.pem
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libnm-core/tests/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu libnm-core/tests/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstPROGRAMS:
+	@list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+test-compare$(EXEEXT): $(test_compare_OBJECTS) $(test_compare_DEPENDENCIES) $(EXTRA_test_compare_DEPENDENCIES) 
+	@rm -f test-compare$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(test_compare_OBJECTS) $(test_compare_LDADD) $(LIBS)
+
+test-crypto$(EXEEXT): $(test_crypto_OBJECTS) $(test_crypto_DEPENDENCIES) $(EXTRA_test_crypto_DEPENDENCIES) 
+	@rm -f test-crypto$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(test_crypto_OBJECTS) $(test_crypto_LDADD) $(LIBS)
+
+test-general$(EXEEXT): $(test_general_OBJECTS) $(test_general_DEPENDENCIES) $(EXTRA_test_general_DEPENDENCIES) 
+	@rm -f test-general$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(test_general_OBJECTS) $(test_general_LDADD) $(LIBS)
+
+test-secrets$(EXEEXT): $(test_secrets_OBJECTS) $(test_secrets_DEPENDENCIES) $(EXTRA_test_secrets_DEPENDENCIES) 
+	@rm -f test-secrets$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(test_secrets_OBJECTS) $(test_secrets_LDADD) $(LIBS)
+
+test-setting-8021x$(EXEEXT): $(test_setting_8021x_OBJECTS) $(test_setting_8021x_DEPENDENCIES) $(EXTRA_test_setting_8021x_DEPENDENCIES) 
+	@rm -f test-setting-8021x$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(test_setting_8021x_OBJECTS) $(test_setting_8021x_LDADD) $(LIBS)
+
+test-setting-dcb$(EXEEXT): $(test_setting_dcb_OBJECTS) $(test_setting_dcb_DEPENDENCIES) $(EXTRA_test_setting_dcb_DEPENDENCIES) 
+	@rm -f test-setting-dcb$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(test_setting_dcb_OBJECTS) $(test_setting_dcb_LDADD) $(LIBS)
+
+test-settings-defaults$(EXEEXT): $(test_settings_defaults_OBJECTS) $(test_settings_defaults_DEPENDENCIES) $(EXTRA_test_settings_defaults_DEPENDENCIES) 
+	@rm -f test-settings-defaults$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(test_settings_defaults_OBJECTS) $(test_settings_defaults_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-compare.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-crypto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-general.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-secrets.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-setting-8021x.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-setting-dcb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-settings-defaults.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list=' $(TESTS) '; \
+	$(am__tty_colors); \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *[\ \	]$$tst[\ \	]*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		col=$$red; res=XPASS; \
+	      ;; \
+	      *) \
+		col=$$grn; res=PASS; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *[\ \	]$$tst[\ \	]*) \
+		xfail=`expr $$xfail + 1`; \
+		col=$$lgn; res=XFAIL; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		col=$$red; res=FAIL; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      col=$$blu; res=SKIP; \
+	    fi; \
+	    echo "$${col}$$res$${std}: $$tst"; \
+	  done; \
+	  if test "$$all" -eq 1; then \
+	    tests="test"; \
+	    All=""; \
+	  else \
+	    tests="tests"; \
+	    All="All "; \
+	  fi; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="$$All$$all $$tests passed"; \
+	    else \
+	      if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+	      banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all $$tests failed"; \
+	    else \
+	      if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+	      banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    if test "$$skip" -eq 1; then \
+	      skipped="($$skip test was not run)"; \
+	    else \
+	      skipped="($$skip tests were not run)"; \
+	    fi; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  if test "$$failed" -eq 0; then \
+	    col="$$grn"; \
+	  else \
+	    col="$$red"; \
+	  fi; \
+	  echo "$${col}$$dashes$${std}"; \
+	  echo "$${col}$$banner$${std}"; \
+	  test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+	  test -z "$$report" || echo "$${col}$$report$${std}"; \
+	  echo "$${col}$$dashes$${std}"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \
+	clean-generic clean-libtool clean-noinstPROGRAMS cscopelist-am \
+	ctags ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
+
+
+# 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.
+.NOEXPORT:
diff --git a/libnm-core/tests/certs/ca-no-ending-newline.pem b/libnm-core/tests/certs/ca-no-ending-newline.pem
new file mode 100644
index 00000000..664e299a
--- /dev/null
+++ b/libnm-core/tests/certs/ca-no-ending-newline.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----

+MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD

+VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv

+bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv

+b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV

+UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU

+cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds

+b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH

+iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS

+r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4

+04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r

+GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9

+3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P

+lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/

+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/libnm-core/tests/certs/pkcs8-decrypted.der b/libnm-core/tests/certs/pkcs8-decrypted.der
new file mode 100644
index 00000000..2cbdeb5e
--- /dev/null
+++ b/libnm-core/tests/certs/pkcs8-decrypted.der
Binary files differdiff --git a/libnm-core/tests/certs/pkcs8-enc-key.pem b/libnm-core/tests/certs/pkcs8-enc-key.pem
new file mode 100644
index 00000000..0d08f2d2
--- /dev/null
+++ b/libnm-core/tests/certs/pkcs8-enc-key.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE6TAbBgkqhkiG9w0BBQMwDgQIwiGFT4Jz6RsCAggABIIEyJNMddDYofbhydUp
+J3VyrYIjv3LziJ7dkTXE3+mEYRCQrGLgljWBbib2JOLVCFt8melL6Yv1RcoVR7X7
+vrRqyycu0DumI4f5+Bf4wc234JNVhSaLYsw244fFtcnK2Gyn4IaVmWmrNvrwfX/w
+SKcVmO30D5C5PCKzv2bou5FmnJLKdDQV1t816cr9T8pTx7MHvBzSZXbh86334BhF
+T3zNwo8j2/+Gq2NBWUn+2GTTV8/r26aIwPcFi4QH6I2ghBwFmFHqU3/PoRm6nkmg
+CqJj2Dggy+8zE5qg0iId7lrio0OjCH+Qed6NGwIa2lgv/bhuJVP3FOk4gqamJWHi
+WMaq9McmS+03q2iokYeSQGbx85x+I90RTFZKhFx4dkerf6oTC/YoL4F++ff0e91v
+sOrQsBkgRhrRtFwa9OFCzbsknlixONdd+ITkyX490xz1wcZTDkKtMDRLIPWa2O0b
+MEq75jPYThZ5pF1vc5r+rqPafN7SfI+DDmhzJYEQNRoCWA4pH9Gwv0ayKnOgoj4K
+TuFhXvcyWzTnVXmcqEFyf3CRrB0Ti+Z61enupC+FCuYV5lGsx9kJaTumTk2UPD02
+9Ap3asDLozdEPSXBG3+oCM2s01/IJlxtR84C97r9rpmWTc9K6DCBScETe9KnIghW
+PU7XFogueG5Gwpe+x+IlTDq+qiyUNVX1uMGDcIaCC3VsoWqZrpnGGBhsovwBaXKt
+T9fT2nE27Fd6DRWso4fgos6PPx7RVveu17BTMVQeUq9L8GrV4JNrE3a9aoXdbUhc
+6gMiyAqxh/HEyciYoXsR9oVNi+VM0y8q3hL5nIcgDrCZr/c9aQ8+fuQBDXRrmrQd
+bR2iwNLCBnbmQmM/vM333VhJ4MSOKd3SGw/j41K+Nr3uP5KRZUwV+5yy3ef/hGxU
+i9JjCmSUt2bfWRUFlNaf1hCTYaKD0xnVr1SLFU4snIgh2qKawyqVc9EE2f+FcOM5
+0RtwQ3ku6FOk3cy6/xeKpResCHbWDS6nQaIKYyLukV+gm5MJIhOMkj2z4T1eXGUr
+Nu/L7Gz+ps7ct0lM8W82n5lzSEa5/l1eNGM0wtQoAwutFEZp7Nx/IBKK87jVttr6
+82UVJeRk7rO2Mpobfw2LbKwga4rsuLrx3UwVDBWdLx7dNIc1rGoAxhsc72+skFgF
+Uztwy4Yv1Uiji4T6v+mObPZD/HiIDL0vF02Pz08rNlgB0DgaTKrpql2FutIuQAdf
+AciffQIoh9VGERlJoWuunG/UTxg2XRl2m1vCDrgBMInax+PXCv7/5Vh21AQc3fWP
+uf4k6JSy46hYni7VTVKn6C/Di9z7oIrGl/jDkDsaenAbToyX9VWr3s7EBwnhTQ/I
+OQ9bkWCagHIQlwJbu4M4/VAbiR26NrcR0C3JXBlPlT0qvFFB8gKbJAQEXtwIFS2h
+m2fe0k6mQASMwdbJYXZ/wfsg5PPAWsKtny1aMvi0mTPSD5uRhIfEGEuR+AT4UbEW
+BkEIE0lgGly4P1SpunKDQQE6m/e7h8Nl4pi8SMSme3YoX5MJwCP/CNkLBDVenAZI
+oBrdoVox86SjwnUozVG192lcEAULlk+3ZGt6T9JXLBQl9hpNtyTC6SFh84R+5RoN
+AevNl1bDfO+Vci0uJw==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/libnm-core/tests/certs/pkcs8-noenc-key.pem b/libnm-core/tests/certs/pkcs8-noenc-key.pem
new file mode 100644
index 00000000..f73fb55a
--- /dev/null
+++ b/libnm-core/tests/certs/pkcs8-noenc-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQC80HGgFdlFIL2F
+W5rHQ99xOkMrWcZ7an9YurDebAE3M0UwqxM24+5mWbxc8FJ8yYugdMzuI5Nq77IA
+DwJpv9ZjMfnKC1VDMj3bmmMdPurfx8pLdLw/jhk3wBaYk6vMvh4z66Yvmb7valGq
+Pxh6CRTnekNGI9XA7me4JNBlisl0Qasn9g4pl9PiGJAruEamS4Pk6dSWbfw58bs7
+/Yo5ejyt/Mn1n0Q/r3Gv/lAS0qRvmrW6GE1rMtANMfuGRNlAln21TzNcJzykm+sp
+RWptxXEI0NY7u9+RP4M3C1mJxWir7AZDbtinpOZH6vF+92yMzgEYOLK/WZVdSPdW
+tROv9xtPAgMBAAECggEBAJAfp+vjYZJjuGaYEuAxjdhW+biYcWn5U7V9484TsSXa
+i+DnZOZMO8iCjMaAZuZ7zYmwPlE0dK12w29KBbSEy3eySRIRboa5TgBXq3pCcXRZ
+g6/vLlZw+AzXIiha6BODt3g4UwUYnWcQx79lJCDa18sNR1a9ucbn8+Har/wiYT3M
+JjTbUT6wR6rKEXchB58ZugYGhOTfugSDQg4U/dwEHPIaJ/wme++JUV5B/tjeGCG3
+F43o2Oos5vjfrDSpUKIYZn+2BdhP434jkwj22wQ2sy0ruU/kQx8nogMTRfP1v4GU
+9QmNXj/DB24K388ZxcDmcxBJxrGAJ0MohYFo28DqRBECgYEA6hyKEqe2UbJx/+B6
+8mYgHb+pS2j0M4jPl11q9MMLVxLnDY9xZ85IEyWHQEC0GavPSAois0oiDeGAm32c
+j6TFyV3/oPTmZSyV93/agWgnH9Xtc481pbNAb0GMfyotvRRE/+6ti9+Cl7oH9Qmm
+ldMk7Hn6sK9t2mUOW8idPjKqlqcCgYEAzne25BryLJoIinbRMZg9KTfxfgUE6EKc
+Tk5+9CFQn0/AItQJuKbIUyggYH4psWW5hWq6hFlmMYMR48FKv9ry7pZTB0djaoYD
+lN+wSuhzUYWXedkAjvPmekITmf6rbnPfwOZvsr8CGMEUekqJPnPLzsQy+Ea2y/fb
+QY4SHe7gExkCgYEAr+1scOJpZvFjK7ckjT3jipd6ADpJsORxo7zG4FImFnQU/6K4
+xRpGHWVJQyaccOIkrW04cGUYPDgmrjJx0ZwwKceijvEaphMgS1JgAHklVY4sl3ea
+CAAxPqoSi4lFv94Yj/9rmT4IZD6fNivfbJ20FKUBl37tXX4tkRmr2I64lOcCgYEA
+x3eqzrclrmdlxvfBZOuScwbkHP6WXhk0TwbQ6eRhsnfmxP8bITSoJoaGuRJKD2Oa
+l0WkSobgDwd0uhecsrvBpTS/pDGY32n3fdWZyNTHzEOHMyWtv23tBcJek5ERaBU0
+X3WBBiw4x1eKBBeMfjR6+xhbsbcHlQiw36V05UxJWMkCgYEAhtcYvrfU4K48IJTU
+qp03nvd+dMY3IUTdZNOCh8bswLKyn3aq3MfWF9Vp7kDAI3cfyMpSrAQnmg4nVcn6
+Gf3wakG8bpiSRbJnGN+iLm8JsD+3Vw9KzvKOOQVmpT7xt5Kupx1hWvLHQWvfYgOG
+qEtTM8/+LD7W3I7midJNt50CD8A=
+-----END PRIVATE KEY-----
diff --git a/libnm-core/tests/certs/test-aes-key.pem b/libnm-core/tests/certs/test-aes-key.pem
new file mode 100644
index 00000000..aab8f463
--- /dev/null
+++ b/libnm-core/tests/certs/test-aes-key.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,800391B7DD72364B4C2562E0B6AEA000
+
+E9dgNCIATOr4CN5c8o6B+8wdqq/I1BLmPmW2qT7YZepoF7E+RUb8ZLjo1VO2XsJw
+Ir4EzuH7837zBD9dP5CjlY8cWfR63gZpEWRY5Jub8kzvqiL4UZ0Qr8IHOZxAkKEz
+EL1Pn7e+tYt4kA372LPZHWO3vRCgmL1iSJj2/k3avPWAx7NUie4bzGI+00WNv699
+ClKzsJbWB1eiQvYgOr4aVV26oWfa896JkBoGhgZQ6ckqFpsdAos8m46iOSVZrwgq
+Y2/d1CvfQod+87c8LRatwAjf+d6YAJJaeMyxjCGuAY6/JyDsorUkM2OlvbTt6WOA
+gSPWO8I+Ov6THb4IuPhpIJ30Sl88tc6MlIByW49EWu2G1jPw3L8iqRzZ50Z85dyz
+N9yFP91wEwi5F0Zed4iEpg3NVfklEe/VYqCldc5f9fZ84G5V98ZlAdNSqwd/UNBU
+iPTflGqVpp1u+J2isOk+Agpj1MCxh2q0RNuvY9KHzOYBScirfbG4DKNbQgS/5Zw7
+3g9YL5Wbo7BczHLiXf/2adu6T8wI1LKRjkeLV9dK1Vw3ZaGy3mB9oFhCgjh9BNHw
+wC78CVcUErjtOXdQagiCQn5k5EGeAB97QFROoAFjAmGvq3xCi4EHd9Sk6fcMm7Oi
+1fuVR5EXUubF4Llq06lFzQp01s2F73noH49bs3qwdf0n8nrL2XhKB0XCOV/I3K5c
+Y3W+YSl361QGjZ/NUcFLIIy+Uro90MmUBNk6af+wGHRJeflpVnK0ATX1PtpNHziz
+jiMiIZicjgfVLxl1a5zTl6KUmGWKlZb533adQ0s6q9Qmi5Vk5L5W/GdMjcFtZbM6
+GU7EOkwihMLb3DVsNbm7vb8tUXqe/e5RmXtij8Yb+2a6/M9yaOHa0VjHzdiKHecr
+eEYaKQDj7NCWLslNnRRh9GmgXcu2pqBhqRM3HAt3cEaHKKWHTcoWcz11pFwMHNtn
+bU9GjGRVc3lCGhVNRiloO0zrKHmcBpDVLw2+ycXXpj/RaBW2fy0xRLKolyla+jEr
+zdLzVI61O50ZMycOtPmE7DVZpkokn32hGer1eCOFnsN1lywi4cWLvU0jbQC+CJyw
+T9vS8zB3WgOl8rC1AHsfQ4KYajlKleQm89deurQymnt/Qx49SiQA+TpwG9Xvx2TP
+3Vc1NwZfM9ZZ1+6xit/rTuS3LhnmhEnGnV5ZyvAdmkCcV2iHjOnLnQWWQn24MHU3
+8Y9D4AdpI5V7Igwr3vH2NZMiw1W2Yc5EJuPAT8nIs5sgOYhXB/QLPJvulvOQhuNC
+NPwJ6A505JrVNfHuEaoGUyA+mPeWuLwQo8y8cM6ZdFMG3RrwFNzuYTrc1Z/9GsmA
+C0UfHf5dL0r7oWZ1SbpSvsmHYqc8sIypq0ohuLEbpegS/hWP8b2/XDRTjfTiJOrM
+4LsUH9PMOJSxDlwS+7e3FdcGfgXfsMgB3aOjQvNpKEolOuv4A5LVFeMrrwtw4Xo1
+EuhstZwyarUTJenDUXzkakhA+8Yw/g2a7RsnANVTkeBuv2PbqFL4zdlsWvcpkz41
+ESxx1siSeU1E9beOII0zSi8vUD0IAevRHaWSlfU2po600IzX1FN97pa4DJV2ycgn
+-----END RSA PRIVATE KEY-----
diff --git a/libnm-core/tests/certs/test-cert.p12 b/libnm-core/tests/certs/test-cert.p12
new file mode 100644
index 00000000..ae4a6830
--- /dev/null
+++ b/libnm-core/tests/certs/test-cert.p12
Binary files differdiff --git a/libnm-core/tests/certs/test-key-only-decrypted.der b/libnm-core/tests/certs/test-key-only-decrypted.der
new file mode 100644
index 00000000..c8652537
--- /dev/null
+++ b/libnm-core/tests/certs/test-key-only-decrypted.der
Binary files differdiff --git a/libnm-core/tests/certs/test-key-only-decrypted.pem b/libnm-core/tests/certs/test-key-only-decrypted.pem
new file mode 100644
index 00000000..1a25da5e
--- /dev/null
+++ b/libnm-core/tests/certs/test-key-only-decrypted.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAztLp+/SkzmaHzIst0sO4+r7qUwiVnidKBHgxoTbS5UL1dvck
+cbjTEP23V4ZoKQIb6ZMrr8B+PVgWNBAlhX4oLUL8NH/WTwrntrlAUcjliWDNc1Fj
+Z+FZNjFe0IdLXZeKQiLTQvKDYnmERVvYIJfi0TQjXuy/ikF8rYBQ85scUV3kKRzB
+xnyhAHAP9nl3AyL1S6t2yiCr4U5TbIZo6dYPbpVLtbXP02zUc9vAPR0gIHKrPiW7
+P81fLXf91wuo6wxzwD90JxdWzzGaqe3BOSfHqul3SPRtVok1XHlb9i+Mn5O8ExzQ
+dF8wGxVDcY7/Gt9lZWnCilqrBEqA3iApjUgcgwIDAQABAoIBAQC77HCmepf04ryp
+Yhz00NoXG7mWUMqBtXlPrlaKAWKG5dxbiBwZKLK/UYlxgbLK8BuklBCx1Nnfq1Yh
+YDp3nTWsSp0WpsF3eJUqNhD3Pu8xcD+9dEo6bUu+LgXUu9oC5Fq/1RzYS7qNk5RX
+4Sf0FY4GQLWS3tL7MJ20mE71yg5k7qRbDydOyhTh1m1CpRYONWxSsWVLM8KGRDJp
+iF0cdPfD5yoPFpgDk8gwzrnXJH2Wqzv8GvyYykRK5AW7tE50y0rTAM42WZ7YS6aZ
+FNMmtYxeyzXLY3LgPP0uko5anz3OXRcqCfHfFANG0y7B9MehbrjMgI6S1BbzFl07
+V1zVQVqhAoGBAPIfrWMlh1fHlRh4iRGXK2Hvxyv2oNz9KvQ4qRaLV9ejRDzdt7Pi
+/utbi5LGBuDw9016nXM3I77b6PukHzsHFnWGRnyRSbkMMt6mE17nggmNqcpFWfE8
+E7HcKMhk4gbuo5AHD3Ee1Gac2AUDnzYiE+sS6WI3O9d77cc5ych5jZ+nAoGBANqt
+VZCttjY0E+hEyTP37eaE8u0jfdK8AflTJlNUHWKXglES525iu8I/Bso8KaQYsYF3
+SezGRd3KQepQhtMjFKfSpF+tbnboP57Y3XGo8xhbxqV4kRX+XGsVoW3Vg2nPKBrR
++dIY5nMwua+gkHWp9RDcemD2reiIZBVx95fK8dfFAoGAdCSH2pBs/MlrFqLzNTHr
+iH4pb0hN39O9YAsx6POMfo79s6izbyHLIID4Ub6WHB7ashrIHjVr+yin+NXAeWMr
+/dIcS7Kxx4c3e5/0mMi6kvSWZsWfoF0uIVo3YfEqjyK36OXKHXwpbNN9t+IF5ESy
+g0e+FfPiy7nR1Ig+5+CO8+8CgYEAp/75+Ug677FaidouaMpT7gC9UAkwJLFjItQK
+YYIBgTi8WOSY/2jCrhwVb1CA/RwrYjbuiARasGUt9oEe0x3kRHnC5e4rKxaJqdMZ
+bLRK7a+0EHNrouXiwjG/7s1VQ/ht6wzdS9btVBlezdogoQSMzQNU0SExwa7mlMMV
+X3v+B7ECgYAK+Yt4jnLH1LNWoDTU0Ug5hyXsQXV8lVBSnrkvS7GtP6ZA/4OqG7lJ
+/bTYFZGoiAGzOnC+YlAqSIu45CEnpr2xBsThQiWUVxspmQD1lEWWFcd77DPUwn3C
+59pLgx0AqJE3n6lBOwehiXbFKBdVzX8PfPZpuCK6qc/RiTILktwURA==
+-----END RSA PRIVATE KEY-----
diff --git a/libnm-core/tests/certs/test-key-only.pem b/libnm-core/tests/certs/test-key-only.pem
new file mode 100644
index 00000000..5ef530e9
--- /dev/null
+++ b/libnm-core/tests/certs/test-key-only.pem
@@ -0,0 +1,92 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,B29FCA6ECB7C0C48
+
+KuRV4sEVQkY0r0E+E81Se2qpm54HeboUMIJcMVqAt/HIeYwpjEzmXHUywXgayA5k
+r5Uvru95vymFz80q/rl6i4Mt3ckEQ3/VHmBI4pPj/JeRbiDhqTyLqpB5zMgbuti+
+PsEemlbiaCMZFdJk8rJBWADTkirGbXs5ciLwTJyrJXhkBVTqoHtphSWMELxcrnQj
+5bAXZ+rnApWA7LR3yCY1UE0Nj39Yu8lkzDJtbsSXPJVO//OQiGuQRcY6roAUzeS/
+amLdIYqoZm3OF83Ro88XZCIDCG6XjgKoqojtekClVIytB6mHWk+IHhI7DgU/pDBj
+yOskzVRMja9ECnqaVX+bmlmJGZBgcd7+XiebCXNY9IAx/ZQDMbDJDoJusvH6npJR
+PBgag8QBSzwpFyEP/1LrlyVyggZcGuXDWfUiM2rt2UvLm8QYeT5WGfUI+QwW6JRV
+xEz2QwRiPsmj0uK2fXLKHbY0Pv79IMLqgesCAUbndWsi94kjAhpJGa/WfKVb8Dpg
+T+mVa2OT0pgewPWJ3h5f47ag27WDJthsIUHAvNZ03uM23DIqDh6o03/B3/4r1Uab
+HzsLWhUOzbLihO08qcPk/JqtDVCv579mpgvy7bL2ZsZUzefnmg+ah+1bhLguryZu
+Zrt1hTu5WTz27UbYwWNtkxWnWcM9sSF9y+KVwumYhIUGTvg3Jds/jmp/Z5ad8tev
+0RQuWmqnXVD51Y92tOXobJH7JwGbQ4GeRNG/UX7DS9Lvb6rPgmmxvGbXMcjEMapB
+m5DLjCD7Lz4++sfzhCic3/nL8e8fjoYZmCbL/SpYjGjTrfoNaGYaT0De8MxCSjPf
+rNT+ldWFD0oAOTmT0uqOFkeIx3vxczSQUyRfzGOLqtb9mAXk8lvdb8Myb5atfe8f
+FNBL5ocz6Szv2AmKmjZE5P6NKSllyryCYl+H2QU0e3OyY8S9aG2aG8fqeVKaA01S
+uOOjsK6IKMpkit+VFDP7RWvS8p1FTwTVRdbMZzASW8+D98OHsTlOENtQuuFyvNaN
+vPHrbHltTkwDlYVab9UpFr/ZRW3cNJrmcl0hyeCJxk5u8B9UwW6yZmd24hxda2xt
+1QjnxfWlX0i5KTmfWFyPmRYt1WH9rdVaH6wqRbGNbMRT7Lez0E/2+LXjFiiEe0Vh
+ZuryhyhUXpHY8yyHxFY92XT504Z3wPUaJ1tQxGhdziZ7HcqFT8f4oTNJdBNtzqNw
+l63gSTaKUkSB14CBOyR84cqpgSMwZvWZb3RQFYY4GSALWwhnn6PWeRhjWAXPms2v
+tRmfEyDUCyPxDarezvS9kUir3XbvnCkoJOrK/lw4a8ygGBCBqRKOdI0SRUf1Nnjm
+aZBrKrXHv5vP66fyC7cGMTq35+iiHbE//rRDGPrf9vpmw3ki3FlDMyAXOC5yWDco
+0n+cNDyHJDdIW3+3nfZvSgPPMwmTdfNO90X3YczSmMTGjnIuhQMf7FMFmMZOSrqD
+u234vYCjIIlph3aVpbzjOqKg3d4nuP9oouyAgRAr+vShgHRmq0jvsAiGH3Q6RqEj
+DvkM1NgoloMy5RhKF4hIeaQM/UlgoXrcEx0RGCJHykQcQmVa5cf5EwjrO7b+w2Lg
+-----END RSA PRIVATE KEY-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+        Signature Algorithm: md5WithRSAEncryption
+        Issuer: C=US, ST=Berkshire, L=Newbury, O=My Company Ltd, OU=test, CN=test/emailAddress=test@test.com
+        Validity
+            Not Before: Feb  2 02:22:25 2009 GMT
+            Not After : Jan 31 02:22:25 2019 GMT
+        Subject: C=US, ST=Berkshire, O=My Company Ltd, OU=test-client, CN=test-client/emailAddress=test-client@test.com
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:ce:d2:e9:fb:f4:a4:ce:66:87:cc:8b:2d:d2:c3:
+                    b8:fa:be:ea:53:08:95:9e:27:4a:04:78:31:a1:36:
+                    d2:e5:42:f5:76:f7:24:71:b8:d3:10:fd:b7:57:86:
+                    68:29:02:1b:e9:93:2b:af:c0:7e:3d:58:16:34:10:
+                    25:85:7e:28:2d:42:fc:34:7f:d6:4f:0a:e7:b6:b9:
+                    40:51:c8:e5:89:60:cd:73:51:63:67:e1:59:36:31:
+                    5e:d0:87:4b:5d:97:8a:42:22:d3:42:f2:83:62:79:
+                    84:45:5b:d8:20:97:e2:d1:34:23:5e:ec:bf:8a:41:
+                    7c:ad:80:50:f3:9b:1c:51:5d:e4:29:1c:c1:c6:7c:
+                    a1:00:70:0f:f6:79:77:03:22:f5:4b:ab:76:ca:20:
+                    ab:e1:4e:53:6c:86:68:e9:d6:0f:6e:95:4b:b5:b5:
+                    cf:d3:6c:d4:73:db:c0:3d:1d:20:20:72:ab:3e:25:
+                    bb:3f:cd:5f:2d:77:fd:d7:0b:a8:eb:0c:73:c0:3f:
+                    74:27:17:56:cf:31:9a:a9:ed:c1:39:27:c7:aa:e9:
+                    77:48:f4:6d:56:89:35:5c:79:5b:f6:2f:8c:9f:93:
+                    bc:13:1c:d0:74:5f:30:1b:15:43:71:8e:ff:1a:df:
+                    65:65:69:c2:8a:5a:ab:04:4a:80:de:20:29:8d:48:
+                    1c:83
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            Netscape Comment: 
+                OpenSSL Generated Certificate
+            X509v3 Subject Key Identifier: 
+                34:E9:5C:D8:FC:C7:AF:F7:5D:F4:13:D3:82:1A:CD:52:0F:4A:BB:0B
+            X509v3 Authority Key Identifier: 
+                keyid:52:33:2E:22:66:79:82:E5:41:2E:8D:3B:B2:E5:CC:FA:BE:99:33:8E
+                DirName:/C=US/ST=Berkshire/L=Newbury/O=My Company Ltd/OU=test/CN=test/emailAddress=test@test.com
+                serial:E6:4C:5C:96:26:5E:D6:D0
+
+    Signature Algorithm: md5WithRSAEncryption
+        88:c4:dd:c5:4a:a6:8e:1f:36:62:80:31:6b:2b:85:34:0d:6c:
+        a7:dc:e1:5a:3c:dd:74:57:db:59:be:8b:f2:79:40:2d:bd:9b:
+        e1:ab:0e:03:75:20:75:2f:ea:97:f9:d4:7e:15:75:c2:82:f5:
+        b1:37:e4:8b:24:d4:ef:02:3b:19:6a:56:bb:9f:c3:a5:b4:c4:
+        39:a0:64:96:5b:c3:a8:19:74:ec:0b:cf:33:df:f3:12:f3:e2:
+        ab:1d:7d:de:21:64:cd:b1:a0:6f:7a:77:84:d4:62:8a:50:e6:
+        76:5d:af:3a:ef:1a:87:0e:1a:38:c4:f9:0d:2f:14:e0:20:32:
+        4c:2e:70:d2:71:82:d5:e5:c9:13:2c:4e:b4:c8:63:65:1d:48:
+        e8:c3:56:6d:88:84:57:65:13:1e:42:48:b4:03:25:71:4e:12:
+        9d:1a:88:65:d5:71:21:3b:0e:be:37:1c:f0:88:6b:45:0c:0e:
+        6c:e5:60:cb:86:bf:bf:40:30:c4:cf:94:f8:1c:60:d4:1b:df:
+        88:02:7a:45:7e:d1:c6:f3:07:b9:b1:8f:2a:55:2f:be:77:9f:
+        d1:46:64:05:b7:67:c5:b2:ac:8c:42:8f:6a:51:a4:0d:2b:16:
+        a4:d6:39:a5:f8:25:ed:68:25:13:b5:19:ac:6c:e9:ec:ee:03:
+        6b:80:38:6e
+
diff --git a/libnm-core/tests/certs/test2-cert.p12 b/libnm-core/tests/certs/test2-cert.p12
new file mode 100644
index 00000000..9d5732b0
--- /dev/null
+++ b/libnm-core/tests/certs/test2-cert.p12
Binary files differdiff --git a/libnm-core/tests/certs/test2_ca_cert.pem b/libnm-core/tests/certs/test2_ca_cert.pem
new file mode 100644
index 00000000..9a487ca4
--- /dev/null
+++ b/libnm-core/tests/certs/test2_ca_cert.pem
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEpDCCA4ygAwIBAgIJANDnVhixAO1GMA0GCSqGSIb3DQEBBQUAMIGSMQswCQYD
+VQQGEwJVUzEWMBQGA1UECBMNTWFzc2FjaHVzZXR0czERMA8GA1UEBxMIV2VzdGZv
+cmQxFjAUBgNVBAoTDVJlZCBIYXQsIEluYy4xFDASBgNVBAsTC0VuZ2luZWVyaW5n
+MRAwDgYDVQQDEwdlYXB0ZXN0MRgwFgYJKoZIhvcNAQkBFglpdEBpdC5jb20wHhcN
+MDcxMTA5MTU0ODI1WhcNMTcxMTA2MTU0ODI1WjCBkjELMAkGA1UEBhMCVVMxFjAU
+BgNVBAgTDU1hc3NhY2h1c2V0dHMxETAPBgNVBAcTCFdlc3Rmb3JkMRYwFAYDVQQK
+Ew1SZWQgSGF0LCBJbmMuMRQwEgYDVQQLEwtFbmdpbmVlcmluZzEQMA4GA1UEAxMH
+ZWFwdGVzdDEYMBYGCSqGSIb3DQEJARYJaXRAaXQuY29tMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAz9zRLSiQyQangDgEliEP8xSpnPJS7GjXzrkZS3sk
+gZLuVuwoFeZRq3Hsrq/wGd/vM0KUFNmEaMc+47jnuv0UHQcQ45ZACO7s4/Aflhzj
+lkmud/z06hVknIzjXmvS6q2ttCviHsXnfokl+wAxuUhsd+le0xjP9H1jXny4YBuS
+jP+yGUz7PL4w1sFFghKIPrlB7m4GkFbQRqvH7FSJg86GWopPwJvNvIzhOZiO1a1D
+CAAL4Ru3jxtNFxqWT87C/qUEe/2Qb7jtNyqFcKfwZyZh4u1bo0c8bjErlUZERbWz
+zM3hTFypuw+i2v+0h3A8/Xb0hTjcHkUoJgfSdbsOLC5TOwIDAQABo4H6MIH3MB0G
+A1UdDgQWBBR+UOaH4e8nrEuMcEXJl7UN5r/wDTCBxwYDVR0jBIG/MIG8gBR+UOaH
+4e8nrEuMcEXJl7UN5r/wDaGBmKSBlTCBkjELMAkGA1UEBhMCVVMxFjAUBgNVBAgT
+DU1hc3NhY2h1c2V0dHMxETAPBgNVBAcTCFdlc3Rmb3JkMRYwFAYDVQQKEw1SZWQg
+SGF0LCBJbmMuMRQwEgYDVQQLEwtFbmdpbmVlcmluZzEQMA4GA1UEAxMHZWFwdGVz
+dDEYMBYGCSqGSIb3DQEJARYJaXRAaXQuY29tggkA0OdWGLEA7UYwDAYDVR0TBAUw
+AwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAmE2jqUymfxN2Vv7bPafoK/EpZwGPxu+z
+phRFsgUgWVzidc/GtOxN81LduJ+ow8MEbQIabo4JV/MdKzuPuhAHToAQdeb0LIWa
+p59vTIZiVhUt0cMAbQwKcTnfmDnXw9wytvtKgeAXJq0Jd6F+uNXTiR1btlYLZqmF
+oSu54cHQlXpUT9z0BnQ8eXd7m0TwfzGQkTHQI7xBa87lZDAkJaTlhv7fR5vPmJYY
+0LiXii71ce+4hxdlp7hQfwQ2sb8FPY3RlVboTRD0CvGaWypWhdSZnS790dBXgZOs
+NCge6NGuHzW5LtiZE9ppuv8qJysVcIFdAqt8dkx58ksOqFcARCerXw==
+-----END CERTIFICATE-----
diff --git a/libnm-core/tests/certs/test2_key_and_cert.pem b/libnm-core/tests/certs/test2_key_and_cert.pem
new file mode 100644
index 00000000..a668596e
--- /dev/null
+++ b/libnm-core/tests/certs/test2_key_and_cert.pem
@@ -0,0 +1,119 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,5FA2D6D6242C26D0
+
+dyNdbh115sczbUEhiaGYJ6fazyvJss5thPFEmkP6aftYlvXY6vPtc++xFCCktiSd
+qFVEyi6oDyV4iGPmX7pCJ0e+pSI6uFNXKFtxh5/+/wXZcOEMCvfu7w2IrvYF2LHY
+qJDljcISSRxeINuYO7TETD5fLLRKj2X9vwwkwVN02b2N5jsrm6Bt//WbatqSB3ln
+FHyQhVKkvdl9Hr1XNmEfgGfZSxxDoPu1DjhtZ5ja2LZj64C2CXdI0oq2wcAVvQNn
+rZeeg9sinQJkz9rwsNaWqlYw4X+YD2JRSwZuvwkWRydYMwgb1XS/jCxtuFF8NXWP
+RBAOAZZUy7onzohsJHVVa05wCKQ4klo+PEfI3vn7BeuHyciCc0eFqGRvz8eFDybH
+ZdPbU/3vGp+mOB7gd27TptttTCQQy9uM5CIyovNSYsAIw1Z583Ea4q8eXgzkgD6D
+isCqkGXMfPbNXU3myQGDnQwWRi2CqX+rXM8PJUhdewLAlmHRz/aYSuql2BRixJKx
+eASzmFBYdAjrvafda5D+xTyJwXEwdq/HlqMK9cY28ZbNrzA2Kor2X23EKC1+VG8k
+B67OsfUhW27j4u6aV5JdLf87OtF3mHFRR+Lzs7i7LYvJ8ACE+jiIi7PboZjK5Oiv
+JqTK0BwDaeNYjkd6jiJh8It/ReMbLk65J3eldOklN0VMPYiqcQnHvSPC2DD1YAy+
+Rv/JVj6TvzvgEAj+hgH6MAAF6u3ARj6+10DlvhUubkOC5RztLKReu8B+427TuuDb
+T03gFpHD6X9IqSiq/QfYFyHFojCVSrv6wDZOcHc1s71kpJ8R14YIVe+DrrZN/0D4
+M631jdNg3JARMZXcXTHrghGIdPmOtrsRyTTRZuGoVup/DW9MRzOzCTMSNCX8T+eq
+13HMSNQEO9lMwy0sYeO5c7sjHY4K1ubZuVE1mvXq4JLz3YxXJIvgp8TUvqDnAsK+
+Fv63bDoTg5Tq63XvnaKc7Lawneyg5ZAMzPN3nM0/1EZcn/2ICI5c4Yepc5t63EI5
+KytuXx86Mcx234enj3uMeuM22POQ1SnKOef6dFzK/CE8J8eUEY/aDhX4eBl/s3nd
+U4+aaFKYz3HTazePayt2SC6rP/KKMmS14q59bOQA1DiWxCvmA2ypRyP87fV5DstH
+I53RD5xp1P38iaO8U/divD0W2dkv748s9DQqYrHPtWALT9esxNU07CgB8Zt070si
+7pzjQ8FDCZ8ygDmwWGNSBz1nA90Cpd6gAFDrep7HAtDE4qgNfokycpaJZkXBei/U
+tC4tWYRbqDEsEbeBHvQRJzzqWzk9e/P4fQoelM3aryKzKLG5z7KvywVifKMLECQ+
+tIpzoRp06nuTA/O+iLFdkCy3JEWszfvvOwTwtIIV6+3s8TU0k9MmzEe3rGL+QqT/
+Tf+9/dN5LK+LWyc99BfmCOrBuFtQmHyEXkfe6EuFYEwj0B2ZfnLCon6cdRujjK7H
+IJslC1B/cBVqG3KCrbBzjeygKfJ5Ijo72oXZJOCFTLeJefZKGGWJCp9nG9h9Wrcf
+fEN/mj3wBvTa90/PYFj9NuaBtrvMF8Rn9XDeYPq2JGL8YkNdPuO8A+2Yko8wcvST
+-----END RSA PRIVATE KEY-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 2 (0x2)
+        Signature Algorithm: md5WithRSAEncryption
+        Issuer: C=US, ST=Massachusetts, L=Westford, O=Red Hat, Inc., OU=Engineering, CN=eaptest/emailAddress=it@it.com
+        Validity
+            Not Before: Nov  9 15:50:14 2007 GMT
+            Not After : Nov  6 15:50:14 2017 GMT
+        Subject: C=US, ST=Massachusetts, O=Red Hat, Inc., OU=Engineering, CN=client/emailAddress=it@it.com
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:b0:8f:4f:1c:93:d4:43:e7:87:b7:22:33:55:a8:
+                    35:a1:c4:01:b0:f1:ed:26:23:96:ab:65:c2:c2:54:
+                    db:79:22:03:ad:3f:6f:22:e3:63:3f:f4:21:6d:fa:
+                    88:c8:8f:1a:ce:55:49:7c:98:33:6a:67:8a:8d:d9:
+                    34:b0:c3:42:f4:72:a4:45:43:05:72:5d:0c:d3:42:
+                    f8:9c:66:3b:b8:f8:77:ea:f6:b6:94:d7:cc:5d:62:
+                    34:2a:14:48:0a:bc:65:94:f5:7a:63:98:6c:88:4c:
+                    25:d8:95:f1:40:3d:00:d2:fb:43:28:fa:02:fb:2c:
+                    80:b3:e1:33:e7:8c:ce:8a:a0:1b:3d:04:4d:bc:a1:
+                    b6:a2:42:8b:8e:f3:5b:4a:72:34:7d:8d:ba:d8:46:
+                    22:35:da:5c:f8:dd:fc:6d:9e:59:22:b7:6b:e7:78:
+                    56:54:9f:4c:d1:e2:4a:23:a3:bc:04:ea:46:6b:70:
+                    8a:fb:fe:8a:73:ca:36:d5:f3:e9:17:e3:22:d5:b3:
+                    70:05:e7:f7:37:b7:21:b5:90:53:27:27:ea:36:9b:
+                    00:ff:35:b0:66:3d:dc:a9:2f:95:d2:21:18:98:4f:
+                    28:07:09:70:20:a8:b1:82:aa:a5:df:ae:0f:e3:36:
+                    be:68:8c:9e:80:d3:33:d0:f5:84:17:d9:0f:eb:9d:
+                    af:0b
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            Netscape Comment: 
+                OpenSSL Generated Certificate
+            X509v3 Subject Key Identifier: 
+                71:AB:BB:91:B7:04:DE:43:35:36:07:8A:35:CA:BE:5C:3E:EB:B1:09
+            X509v3 Authority Key Identifier: 
+                keyid:7E:50:E6:87:E1:EF:27:AC:4B:8C:70:45:C9:97:B5:0D:E6:BF:F0:0D
+                DirName:/C=US/ST=Massachusetts/L=Westford/O=Red Hat, Inc./OU=Engineering/CN=eaptest/emailAddress=it@it.com
+                serial:D0:E7:56:18:B1:00:ED:46
+
+    Signature Algorithm: md5WithRSAEncryption
+        ce:43:6d:f7:f8:4a:66:fd:8a:2c:41:a6:e0:03:0e:60:30:d4:
+        41:01:ba:46:ba:81:97:64:68:83:25:9c:e1:2c:03:8b:2d:ca:
+        85:cf:bc:fa:ca:22:c4:59:28:23:8f:ff:50:94:60:1c:90:dd:
+        75:f4:d4:ea:8c:fa:61:61:08:35:4a:8f:aa:a7:e9:3d:76:e9:
+        08:28:55:01:c4:03:42:c7:ad:58:bb:ee:94:f7:09:b3:9a:9b:
+        8b:d0:25:95:18:a6:22:d5:2c:fc:b7:bb:91:0c:7c:03:7f:9b:
+        85:de:b0:e4:95:a8:73:94:27:0a:11:4e:e3:67:ae:2b:cc:e7:
+        51:29:10:23:57:5c:3e:e7:ea:47:e0:f0:8f:5b:a2:9f:26:cf:
+        7f:b5:7c:44:b1:7b:83:67:3c:41:ae:c6:66:64:e0:d2:ef:57:
+        a4:5c:1b:94:11:ce:28:e5:91:51:ef:e1:98:b7:3b:9a:cc:f7:
+        b9:85:76:eb:a8:2b:15:4a:cc:1a:a3:42:fa:be:1c:ce:b8:eb:
+        ee:12:d7:2f:e4:a8:cf:eb:2a:8f:78:e8:91:88:fa:c2:98:75:
+        6a:4c:92:3f:2e:0d:e1:20:39:36:c6:2c:be:67:30:c3:f3:c3:
+        65:81:ac:e3:3c:19:6a:21:ee:ea:f5:22:66:74:b2:07:53:7c:
+        9a:0c:24:a6
+-----BEGIN CERTIFICATE-----
+MIIEtDCCA5ygAwIBAgIBAjANBgkqhkiG9w0BAQQFADCBkjELMAkGA1UEBhMCVVMx
+FjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxETAPBgNVBAcTCFdlc3Rmb3JkMRYwFAYD
+VQQKEw1SZWQgSGF0LCBJbmMuMRQwEgYDVQQLEwtFbmdpbmVlcmluZzEQMA4GA1UE
+AxMHZWFwdGVzdDEYMBYGCSqGSIb3DQEJARYJaXRAaXQuY29tMB4XDTA3MTEwOTE1
+NTAxNFoXDTE3MTEwNjE1NTAxNFowfjELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDU1h
+c3NhY2h1c2V0dHMxFjAUBgNVBAoTDVJlZCBIYXQsIEluYy4xFDASBgNVBAsTC0Vu
+Z2luZWVyaW5nMQ8wDQYDVQQDEwZjbGllbnQxGDAWBgkqhkiG9w0BCQEWCWl0QGl0
+LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALCPTxyT1EPnh7ci
+M1WoNaHEAbDx7SYjlqtlwsJU23kiA60/byLjYz/0IW36iMiPGs5VSXyYM2pnio3Z
+NLDDQvRypEVDBXJdDNNC+JxmO7j4d+r2tpTXzF1iNCoUSAq8ZZT1emOYbIhMJdiV
+8UA9ANL7Qyj6AvssgLPhM+eMzoqgGz0ETbyhtqJCi47zW0pyNH2NuthGIjXaXPjd
+/G2eWSK3a+d4VlSfTNHiSiOjvATqRmtwivv+inPKNtXz6RfjItWzcAXn9ze3IbWQ
+Uycn6jabAP81sGY93KkvldIhGJhPKAcJcCCosYKqpd+uD+M2vmiMnoDTM9D1hBfZ
+D+udrwsCAwEAAaOCASYwggEiMAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9w
+ZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBRxq7uRtwTeQzU2
+B4o1yr5cPuuxCTCBxwYDVR0jBIG/MIG8gBR+UOaH4e8nrEuMcEXJl7UN5r/wDaGB
+mKSBlTCBkjELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxETAP
+BgNVBAcTCFdlc3Rmb3JkMRYwFAYDVQQKEw1SZWQgSGF0LCBJbmMuMRQwEgYDVQQL
+EwtFbmdpbmVlcmluZzEQMA4GA1UEAxMHZWFwdGVzdDEYMBYGCSqGSIb3DQEJARYJ
+aXRAaXQuY29tggkA0OdWGLEA7UYwDQYJKoZIhvcNAQEEBQADggEBAM5Dbff4Smb9
+iixBpuADDmAw1EEBuka6gZdkaIMlnOEsA4styoXPvPrKIsRZKCOP/1CUYByQ3XX0
+1OqM+mFhCDVKj6qn6T126QgoVQHEA0LHrVi77pT3CbOam4vQJZUYpiLVLPy3u5EM
+fAN/m4XesOSVqHOUJwoRTuNnrivM51EpECNXXD7n6kfg8I9bop8mz3+1fESxe4Nn
+PEGuxmZk4NLvV6RcG5QRzijlkVHv4Zi3O5rM97mFduuoKxVKzBqjQvq+HM646+4S
+1y/kqM/rKo946JGI+sKYdWpMkj8uDeEgOTbGLL5nMMPzw2WBrOM8GWoh7ur1ImZ0
+sgdTfJoMJKY=
+-----END CERTIFICATE-----
diff --git a/libnm-core/tests/certs/test_ca_cert.der b/libnm-core/tests/certs/test_ca_cert.der
new file mode 100644
index 00000000..e844f65b
--- /dev/null
+++ b/libnm-core/tests/certs/test_ca_cert.der
Binary files differdiff --git a/libnm-core/tests/certs/test_ca_cert.pem b/libnm-core/tests/certs/test_ca_cert.pem
new file mode 100644
index 00000000..faa3fc29
--- /dev/null
+++ b/libnm-core/tests/certs/test_ca_cert.pem
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEhjCCA26gAwIBAgIJAOZMXJYmXtbQMA0GCSqGSIb3DQEBBQUAMIGIMQswCQYD
+VQQGEwJVUzESMBAGA1UECBMJQmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcw
+FQYDVQQKEw5NeSBDb21wYW55IEx0ZDENMAsGA1UECxMEdGVzdDENMAsGA1UEAxME
+dGVzdDEcMBoGCSqGSIb3DQEJARYNdGVzdEB0ZXN0LmNvbTAeFw0wOTAyMDIwMjIx
+NTJaFw0xOTAxMzEwMjIxNTJaMIGIMQswCQYDVQQGEwJVUzESMBAGA1UECBMJQmVy
+a3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcwFQYDVQQKEw5NeSBDb21wYW55IEx0
+ZDENMAsGA1UECxMEdGVzdDENMAsGA1UEAxMEdGVzdDEcMBoGCSqGSIb3DQEJARYN
+dGVzdEB0ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANZz
+iHfFR6Gqdz5Gq1elSaf7J2tznfialPyMkRoqngSItrM3JWlkfBu3ZIpGSYG8+Z8H
+JjaKh/zkCCH73HcjADCocm/XtgxlOlccDtBvfDqifb2dBikcmcfh0tX0o4JU9L+z
+WP7sVcUkJG7C5811lA5pAsLVooJxrZnrta6XstGvFgTSxI2Y4Jowf0syM5b/AHIQ
++htsVhSyj1DWM9day3QsEMZl55SCxCLTB6ZIJLF6NmTYwdnzWWTQf4k7kcptZJU8
+Fqv60b/ATvvUf7S+ZMGLopFIIlmc1Kkn7VTseIKy4ycYuDpyimQy3Yw4flC00vhl
+hTijH+5dlVOUFrRh0bsCAwEAAaOB8DCB7TAdBgNVHQ4EFgQUUjMuImZ5guVBLo07
+suXM+r6ZM44wgb0GA1UdIwSBtTCBsoAUUjMuImZ5guVBLo07suXM+r6ZM46hgY6k
+gYswgYgxCzAJBgNVBAYTAlVTMRIwEAYDVQQIEwlCZXJrc2hpcmUxEDAOBgNVBAcT
+B05ld2J1cnkxFzAVBgNVBAoTDk15IENvbXBhbnkgTHRkMQ0wCwYDVQQLEwR0ZXN0
+MQ0wCwYDVQQDEwR0ZXN0MRwwGgYJKoZIhvcNAQkBFg10ZXN0QHRlc3QuY29tggkA
+5kxcliZe1tAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAZsWzGp9D
+10NWf8ts3A9mhcEb8oDgKNpCOZF9gqr2usZygJjY9MX2n0n81T8XaWDk1wZLlcDW
+hzIalCY8rpE57Dj3MEmdCmYr3BrAy6GVlc/MO7ffTHxogl9ouScSYo8ETTtNMKCg
+zwkDnXjGzmb1e59DIXMVHBBbTmJXJbM8XP9A2azJkVUyE2fSdWksXMP0XklGbW2p
+DksJ+8G1IWkyRhnINV5GZLLNAT5gBA6sUv/iqQKwk8r2dsweMPtLoLWZPAaZErYh
+sthGy00Q0GJkmkJpQl8QIlPq5vylNcMUhvc8tmzwk+rDVUj3jTJWqFwMtnHAaNyC
+FXl9ynWpe5J28w==
+-----END CERTIFICATE-----
diff --git a/libnm-core/tests/certs/test_key_and_cert.pem b/libnm-core/tests/certs/test_key_and_cert.pem
new file mode 100644
index 00000000..c00495d0
--- /dev/null
+++ b/libnm-core/tests/certs/test_key_and_cert.pem
@@ -0,0 +1,119 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,B29FCA6ECB7C0C48
+
+KuRV4sEVQkY0r0E+E81Se2qpm54HeboUMIJcMVqAt/HIeYwpjEzmXHUywXgayA5k
+r5Uvru95vymFz80q/rl6i4Mt3ckEQ3/VHmBI4pPj/JeRbiDhqTyLqpB5zMgbuti+
+PsEemlbiaCMZFdJk8rJBWADTkirGbXs5ciLwTJyrJXhkBVTqoHtphSWMELxcrnQj
+5bAXZ+rnApWA7LR3yCY1UE0Nj39Yu8lkzDJtbsSXPJVO//OQiGuQRcY6roAUzeS/
+amLdIYqoZm3OF83Ro88XZCIDCG6XjgKoqojtekClVIytB6mHWk+IHhI7DgU/pDBj
+yOskzVRMja9ECnqaVX+bmlmJGZBgcd7+XiebCXNY9IAx/ZQDMbDJDoJusvH6npJR
+PBgag8QBSzwpFyEP/1LrlyVyggZcGuXDWfUiM2rt2UvLm8QYeT5WGfUI+QwW6JRV
+xEz2QwRiPsmj0uK2fXLKHbY0Pv79IMLqgesCAUbndWsi94kjAhpJGa/WfKVb8Dpg
+T+mVa2OT0pgewPWJ3h5f47ag27WDJthsIUHAvNZ03uM23DIqDh6o03/B3/4r1Uab
+HzsLWhUOzbLihO08qcPk/JqtDVCv579mpgvy7bL2ZsZUzefnmg+ah+1bhLguryZu
+Zrt1hTu5WTz27UbYwWNtkxWnWcM9sSF9y+KVwumYhIUGTvg3Jds/jmp/Z5ad8tev
+0RQuWmqnXVD51Y92tOXobJH7JwGbQ4GeRNG/UX7DS9Lvb6rPgmmxvGbXMcjEMapB
+m5DLjCD7Lz4++sfzhCic3/nL8e8fjoYZmCbL/SpYjGjTrfoNaGYaT0De8MxCSjPf
+rNT+ldWFD0oAOTmT0uqOFkeIx3vxczSQUyRfzGOLqtb9mAXk8lvdb8Myb5atfe8f
+FNBL5ocz6Szv2AmKmjZE5P6NKSllyryCYl+H2QU0e3OyY8S9aG2aG8fqeVKaA01S
+uOOjsK6IKMpkit+VFDP7RWvS8p1FTwTVRdbMZzASW8+D98OHsTlOENtQuuFyvNaN
+vPHrbHltTkwDlYVab9UpFr/ZRW3cNJrmcl0hyeCJxk5u8B9UwW6yZmd24hxda2xt
+1QjnxfWlX0i5KTmfWFyPmRYt1WH9rdVaH6wqRbGNbMRT7Lez0E/2+LXjFiiEe0Vh
+ZuryhyhUXpHY8yyHxFY92XT504Z3wPUaJ1tQxGhdziZ7HcqFT8f4oTNJdBNtzqNw
+l63gSTaKUkSB14CBOyR84cqpgSMwZvWZb3RQFYY4GSALWwhnn6PWeRhjWAXPms2v
+tRmfEyDUCyPxDarezvS9kUir3XbvnCkoJOrK/lw4a8ygGBCBqRKOdI0SRUf1Nnjm
+aZBrKrXHv5vP66fyC7cGMTq35+iiHbE//rRDGPrf9vpmw3ki3FlDMyAXOC5yWDco
+0n+cNDyHJDdIW3+3nfZvSgPPMwmTdfNO90X3YczSmMTGjnIuhQMf7FMFmMZOSrqD
+u234vYCjIIlph3aVpbzjOqKg3d4nuP9oouyAgRAr+vShgHRmq0jvsAiGH3Q6RqEj
+DvkM1NgoloMy5RhKF4hIeaQM/UlgoXrcEx0RGCJHykQcQmVa5cf5EwjrO7b+w2Lg
+-----END RSA PRIVATE KEY-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+        Signature Algorithm: md5WithRSAEncryption
+        Issuer: C=US, ST=Berkshire, L=Newbury, O=My Company Ltd, OU=test, CN=test/emailAddress=test@test.com
+        Validity
+            Not Before: Feb  2 02:22:25 2009 GMT
+            Not After : Jan 31 02:22:25 2019 GMT
+        Subject: C=US, ST=Berkshire, O=My Company Ltd, OU=test-client, CN=test-client/emailAddress=test-client@test.com
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:ce:d2:e9:fb:f4:a4:ce:66:87:cc:8b:2d:d2:c3:
+                    b8:fa:be:ea:53:08:95:9e:27:4a:04:78:31:a1:36:
+                    d2:e5:42:f5:76:f7:24:71:b8:d3:10:fd:b7:57:86:
+                    68:29:02:1b:e9:93:2b:af:c0:7e:3d:58:16:34:10:
+                    25:85:7e:28:2d:42:fc:34:7f:d6:4f:0a:e7:b6:b9:
+                    40:51:c8:e5:89:60:cd:73:51:63:67:e1:59:36:31:
+                    5e:d0:87:4b:5d:97:8a:42:22:d3:42:f2:83:62:79:
+                    84:45:5b:d8:20:97:e2:d1:34:23:5e:ec:bf:8a:41:
+                    7c:ad:80:50:f3:9b:1c:51:5d:e4:29:1c:c1:c6:7c:
+                    a1:00:70:0f:f6:79:77:03:22:f5:4b:ab:76:ca:20:
+                    ab:e1:4e:53:6c:86:68:e9:d6:0f:6e:95:4b:b5:b5:
+                    cf:d3:6c:d4:73:db:c0:3d:1d:20:20:72:ab:3e:25:
+                    bb:3f:cd:5f:2d:77:fd:d7:0b:a8:eb:0c:73:c0:3f:
+                    74:27:17:56:cf:31:9a:a9:ed:c1:39:27:c7:aa:e9:
+                    77:48:f4:6d:56:89:35:5c:79:5b:f6:2f:8c:9f:93:
+                    bc:13:1c:d0:74:5f:30:1b:15:43:71:8e:ff:1a:df:
+                    65:65:69:c2:8a:5a:ab:04:4a:80:de:20:29:8d:48:
+                    1c:83
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            Netscape Comment: 
+                OpenSSL Generated Certificate
+            X509v3 Subject Key Identifier: 
+                34:E9:5C:D8:FC:C7:AF:F7:5D:F4:13:D3:82:1A:CD:52:0F:4A:BB:0B
+            X509v3 Authority Key Identifier: 
+                keyid:52:33:2E:22:66:79:82:E5:41:2E:8D:3B:B2:E5:CC:FA:BE:99:33:8E
+                DirName:/C=US/ST=Berkshire/L=Newbury/O=My Company Ltd/OU=test/CN=test/emailAddress=test@test.com
+                serial:E6:4C:5C:96:26:5E:D6:D0
+
+    Signature Algorithm: md5WithRSAEncryption
+        88:c4:dd:c5:4a:a6:8e:1f:36:62:80:31:6b:2b:85:34:0d:6c:
+        a7:dc:e1:5a:3c:dd:74:57:db:59:be:8b:f2:79:40:2d:bd:9b:
+        e1:ab:0e:03:75:20:75:2f:ea:97:f9:d4:7e:15:75:c2:82:f5:
+        b1:37:e4:8b:24:d4:ef:02:3b:19:6a:56:bb:9f:c3:a5:b4:c4:
+        39:a0:64:96:5b:c3:a8:19:74:ec:0b:cf:33:df:f3:12:f3:e2:
+        ab:1d:7d:de:21:64:cd:b1:a0:6f:7a:77:84:d4:62:8a:50:e6:
+        76:5d:af:3a:ef:1a:87:0e:1a:38:c4:f9:0d:2f:14:e0:20:32:
+        4c:2e:70:d2:71:82:d5:e5:c9:13:2c:4e:b4:c8:63:65:1d:48:
+        e8:c3:56:6d:88:84:57:65:13:1e:42:48:b4:03:25:71:4e:12:
+        9d:1a:88:65:d5:71:21:3b:0e:be:37:1c:f0:88:6b:45:0c:0e:
+        6c:e5:60:cb:86:bf:bf:40:30:c4:cf:94:f8:1c:60:d4:1b:df:
+        88:02:7a:45:7e:d1:c6:f3:07:b9:b1:8f:2a:55:2f:be:77:9f:
+        d1:46:64:05:b7:67:c5:b2:ac:8c:42:8f:6a:51:a4:0d:2b:16:
+        a4:d6:39:a5:f8:25:ed:68:25:13:b5:19:ac:6c:e9:ec:ee:03:
+        6b:80:38:6e
+-----BEGIN CERTIFICATE-----
+MIIErjCCA5agAwIBAgIBATANBgkqhkiG9w0BAQQFADCBiDELMAkGA1UEBhMCVVMx
+EjAQBgNVBAgTCUJlcmtzaGlyZTEQMA4GA1UEBxMHTmV3YnVyeTEXMBUGA1UEChMO
+TXkgQ29tcGFueSBMdGQxDTALBgNVBAsTBHRlc3QxDTALBgNVBAMTBHRlc3QxHDAa
+BgkqhkiG9w0BCQEWDXRlc3RAdGVzdC5jb20wHhcNMDkwMjAyMDIyMjI1WhcNMTkw
+MTMxMDIyMjI1WjCBizELMAkGA1UEBhMCVVMxEjAQBgNVBAgTCUJlcmtzaGlyZTEX
+MBUGA1UEChMOTXkgQ29tcGFueSBMdGQxFDASBgNVBAsTC3Rlc3QtY2xpZW50MRQw
+EgYDVQQDEwt0ZXN0LWNsaWVudDEjMCEGCSqGSIb3DQEJARYUdGVzdC1jbGllbnRA
+dGVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDO0un79KTO
+ZofMiy3Sw7j6vupTCJWeJ0oEeDGhNtLlQvV29yRxuNMQ/bdXhmgpAhvpkyuvwH49
+WBY0ECWFfigtQvw0f9ZPCue2uUBRyOWJYM1zUWNn4Vk2MV7Qh0tdl4pCItNC8oNi
+eYRFW9ggl+LRNCNe7L+KQXytgFDzmxxRXeQpHMHGfKEAcA/2eXcDIvVLq3bKIKvh
+TlNshmjp1g9ulUu1tc/TbNRz28A9HSAgcqs+Jbs/zV8td/3XC6jrDHPAP3QnF1bP
+MZqp7cE5J8eq6XdI9G1WiTVceVv2L4yfk7wTHNB0XzAbFUNxjv8a32VlacKKWqsE
+SoDeICmNSByDAgMBAAGjggEcMIIBGDAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQf
+Fh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUNOlc2PzH
+r/dd9BPTghrNUg9Kuwswgb0GA1UdIwSBtTCBsoAUUjMuImZ5guVBLo07suXM+r6Z
+M46hgY6kgYswgYgxCzAJBgNVBAYTAlVTMRIwEAYDVQQIEwlCZXJrc2hpcmUxEDAO
+BgNVBAcTB05ld2J1cnkxFzAVBgNVBAoTDk15IENvbXBhbnkgTHRkMQ0wCwYDVQQL
+EwR0ZXN0MQ0wCwYDVQQDEwR0ZXN0MRwwGgYJKoZIhvcNAQkBFg10ZXN0QHRlc3Qu
+Y29tggkA5kxcliZe1tAwDQYJKoZIhvcNAQEEBQADggEBAIjE3cVKpo4fNmKAMWsr
+hTQNbKfc4Vo83XRX21m+i/J5QC29m+GrDgN1IHUv6pf51H4VdcKC9bE35Isk1O8C
+OxlqVrufw6W0xDmgZJZbw6gZdOwLzzPf8xLz4qsdfd4hZM2xoG96d4TUYopQ5nZd
+rzrvGocOGjjE+Q0vFOAgMkwucNJxgtXlyRMsTrTIY2UdSOjDVm2IhFdlEx5CSLQD
+JXFOEp0aiGXVcSE7Dr43HPCIa0UMDmzlYMuGv79AMMTPlPgcYNQb34gCekV+0cbz
+B7mxjypVL753n9FGZAW3Z8WyrIxCj2pRpA0rFqTWOaX4Je1oJRO1Gaxs6ezuA2uA
+OG4=
+-----END CERTIFICATE-----
diff --git a/libnm-core/tests/test-compare.c b/libnm-core/tests/test-compare.c
new file mode 100644
index 00000000..12db9c23
--- /dev/null
+++ b/libnm-core/tests/test-compare.c
@@ -0,0 +1,248 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2007 - 2014 Red Hat, Inc.
+ * Copyright 2007 - 2008 Novell, Inc.
+ */
+
+#include "config.h"
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "nm-glib-compat.h"
+
+#include "nm-property-compare.h"
+
+#include "nm-test-utils.h"
+
+static void
+compare_ints (void)
+{
+	GVariant *value1, *value2;
+
+	value1 = g_variant_new_int32 (5);
+	value2 = g_variant_new_int32 (5);
+	g_assert (nm_property_compare (value1, value2) == 0);
+
+	g_variant_unref (value2);
+	value2 = g_variant_new_int32 (10);
+	g_assert (nm_property_compare (value1, value2) < 0);
+
+	g_variant_unref (value2);
+	value2 = g_variant_new_int32 (-1);
+	g_assert (nm_property_compare (value1, value2) > 0);
+
+	g_variant_unref (value1);
+	g_variant_unref (value2);
+}
+
+static void
+compare_strings (void)
+{
+	GVariant *value1, *value2;
+	const char *str1 = "hello";
+	const char *str2 = "world";
+
+	value1 = g_variant_new_string (str1);
+	value2 = g_variant_new_string (str1);
+	g_assert (nm_property_compare (value1, value2) == 0);
+
+	g_variant_unref (value2);
+	value2 = g_variant_new_string (str2);
+	g_assert (nm_property_compare (value1, value2) < 0);
+
+	g_assert (nm_property_compare (value2, value1) > 0);
+
+	g_variant_unref (value1);
+	g_variant_unref (value2);
+}
+
+static void
+compare_strv (void)
+{
+	GVariant *value1, *value2;
+	const char * const strv1[] = { "foo", "bar", "baz", NULL };
+	const char * const strv2[] = { "foo", "bar", "bar", NULL };
+	const char * const strv3[] = { "foo", "bar", NULL };
+	const char * const strv4[] = { "foo", "bar", "baz", "bam", NULL };
+
+	value1 = g_variant_new_strv (strv1, -1);
+	value2 = g_variant_new_strv (strv1, -1);
+	g_assert (nm_property_compare (value1, value2) == 0);
+
+	g_variant_unref (value2);
+	value2 = g_variant_new_strv (strv2, -1);
+	g_assert (nm_property_compare (value1, value2) != 0);
+
+	g_variant_unref (value2);
+	value2 = g_variant_new_strv (strv3, -1);
+	g_assert (nm_property_compare (value1, value2) != 0);
+
+	g_variant_unref (value2);
+	value2 = g_variant_new_strv (strv4, -1);
+	g_assert (nm_property_compare (value1, value2) != 0);
+
+	g_variant_unref (value1);
+	g_variant_unref (value2);
+}
+
+static void
+compare_arrays (void)
+{
+	GVariant *value1, *value2;
+	guint32 array[] = { 0, 1, 2, 3, 4 };
+
+	value1 = g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32,
+	                                    array, G_N_ELEMENTS (array),
+	                                    sizeof (guint32));
+	value2 = g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32,
+	                                    array, G_N_ELEMENTS (array),
+	                                    sizeof (guint32));
+
+	g_assert (nm_property_compare (value1, value2) == 0);
+
+	g_variant_unref (value2);
+	value2 = g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32,
+	                                    array + 1, G_N_ELEMENTS (array) - 1,
+	                                    sizeof (guint32));
+	g_assert (nm_property_compare (value1, value2) != 0);
+
+	array[0] = 7;
+	g_variant_unref (value2);
+	value2 = g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32,
+	                                    array, G_N_ELEMENTS (array),
+	                                    sizeof (guint32));
+	g_assert (nm_property_compare (value1, value2) != 0);
+
+	g_variant_unref (value1);
+	g_variant_unref (value2);
+}
+
+static void
+compare_str_hash (void)
+{
+	GVariant *value1, *value2;
+	GVariantBuilder builder;
+
+	g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
+	g_variant_builder_add (&builder, "{ss}", "key1", "hello");
+	g_variant_builder_add (&builder, "{ss}", "key2", "world");
+	g_variant_builder_add (&builder, "{ss}", "key3", "!");
+	value1 = g_variant_builder_end (&builder);
+
+	g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
+	g_variant_builder_add (&builder, "{ss}", "key3", "!");
+	g_variant_builder_add (&builder, "{ss}", "key2", "world");
+	g_variant_builder_add (&builder, "{ss}", "key1", "hello");
+	value2 = g_variant_builder_end (&builder);
+
+	g_assert (nm_property_compare (value1, value2) == 0);
+
+	g_variant_unref (value2);
+	g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
+	g_variant_builder_add (&builder, "{ss}", "key1", "hello");
+	g_variant_builder_add (&builder, "{ss}", "key3", "!");
+	value2 = g_variant_builder_end (&builder);
+
+	g_assert (nm_property_compare (value1, value2) != 0);
+	g_assert (nm_property_compare (value2, value1) != 0);
+
+	g_variant_unref (value2);
+	g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
+	g_variant_builder_add (&builder, "{ss}", "key1", "hello");
+	g_variant_builder_add (&builder, "{ss}", "key2", "moon");
+	g_variant_builder_add (&builder, "{ss}", "key3", "!");
+	value2 = g_variant_builder_end (&builder);
+
+	g_assert (nm_property_compare (value1, value2) != 0);
+
+	g_variant_unref (value1);
+	g_variant_unref (value2);
+}
+
+static void
+compare_ip6_addresses (void)
+{
+	GVariant *value1, *value2;
+	struct in6_addr addr1;
+	struct in6_addr addr2;
+	struct in6_addr addr3;
+	guint32 prefix1 = 64;
+	guint32 prefix2 = 64;
+	guint32 prefix3 = 0;
+
+	inet_pton (AF_INET6, "1:2:3:4:5:6:7:8", &addr1);
+	inet_pton (AF_INET6, "ffff:2:3:4:5:6:7:8", &addr2);
+	inet_pton (AF_INET6, "::", &addr3);
+
+	value1 = g_variant_new ("(@ayu@ay)",
+	                        g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
+	                                                   (guint8 *) addr1.s6_addr, 16, 1),
+	                        prefix1,
+	                        g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
+	                                                   (guint8 *) addr3.s6_addr, 16, 1));
+
+	value2 = g_variant_new ("(@ayu@ay)",
+	                        g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
+	                                                   (guint8 *) addr1.s6_addr, 16, 1),
+	                        prefix1,
+	                        g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
+	                                                   (guint8 *) addr3.s6_addr, 16, 1));
+
+	g_assert (nm_property_compare (value1, value2) == 0);
+
+	g_variant_unref (value2);
+	value2 = g_variant_new ("(@ayu@ay)",
+	                        g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
+	                                                   (guint8 *) addr2.s6_addr, 16, 1),
+	                        prefix2,
+	                        g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
+	                                                   (guint8 *) addr3.s6_addr, 16, 1));
+
+	g_assert (nm_property_compare (value1, value2) != 0);
+
+	g_variant_unref (value2);
+	value2 = g_variant_new ("(@ayu@ay)",
+	                        g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
+	                                                   (guint8 *) addr3.s6_addr, 16, 1),
+	                        prefix3,
+	                        g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
+	                                                   (guint8 *) addr3.s6_addr, 16, 1));
+
+	g_assert (nm_property_compare (value1, value2) != 0);
+
+	g_variant_unref (value1);
+	g_variant_unref (value2);
+}
+
+NMTST_DEFINE ();
+
+int
+main (int argc, char *argv[])
+{
+	nmtst_init (&argc, &argv, TRUE);
+
+	g_test_add_func ("/libnm/compare/ints", compare_ints);
+	g_test_add_func ("/libnm/compare/strings", compare_strings);
+	g_test_add_func ("/libnm/compare/strv", compare_strv);
+	g_test_add_func ("/libnm/compare/arrays", compare_arrays);
+	g_test_add_func ("/libnm/compare/str_hash", compare_str_hash);
+	g_test_add_func ("/libnm/compare/ip6_addresses", compare_ip6_addresses);
+
+	return g_test_run ();
+}
diff --git a/libnm-core/tests/test-crypto.c b/libnm-core/tests/test-crypto.c
new file mode 100644
index 00000000..1c8ae477
--- /dev/null
+++ b/libnm-core/tests/test-crypto.c
@@ -0,0 +1,501 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+/*
+ * Dan Williams <dcbw@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2007 - 2011 Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <glib/gi18n.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "crypto.h"
+#include "nm-utils.h"
+#include "nm-errors.h"
+#include "nm-core-internal.h"
+
+#include "nm-test-utils.h"
+
+#if 0
+static const char *pem_rsa_key_begin = "-----BEGIN RSA PRIVATE KEY-----";
+static const char *pem_rsa_key_end = "-----END RSA PRIVATE KEY-----";
+
+static const char *pem_dsa_key_begin = "-----BEGIN DSA PRIVATE KEY-----";
+static const char *pem_dsa_key_end = "-----END DSA PRIVATE KEY-----";
+
+static void
+dump_key_to_pem (const char *key, gsize key_len, int key_type)
+{
+	char *b64 = NULL;
+	GString *str = NULL;
+	const char *start_tag;
+	const char *end_tag;
+	char *p;
+
+	switch (key_type) {
+	case NM_CRYPTO_KEY_TYPE_RSA:
+		start_tag = pem_rsa_key_begin;
+		end_tag = pem_rsa_key_end;
+		break;
+	case NM_CRYPTO_KEY_TYPE_DSA:
+		start_tag = pem_dsa_key_begin;
+		end_tag = pem_dsa_key_end;
+		break;
+	default:
+		g_warning ("Unknown key type %d", key_type);
+		return;
+	}
+
+	b64 = g_base64_encode ((const unsigned char *) key, key_len);
+	if (!b64) {
+		g_warning ("Couldn't base64 encode the key.");
+		goto out;
+	}
+
+	str = g_string_new (NULL);
+
+	g_string_append (str, start_tag);
+	g_string_append_c (str, '\n');
+
+	for (p = b64; p < (b64 + strlen (b64)); p += 64) {
+		g_string_append_len (str, p, strnlen (p, 64));
+		g_string_append_c (str, '\n');
+	}
+
+	g_string_append (str, end_tag);
+	g_string_append_c (str, '\n');
+
+	g_message ("Decrypted private key:\n\n%s", str->str);
+
+out:
+	g_free (b64);
+	if (str)
+		g_string_free (str, TRUE);
+}
+#endif
+
+static void
+test_cert (gconstpointer test_data)
+{
+	char *path;
+	GByteArray *array;
+	NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
+	GError *error = NULL;
+
+	path = g_build_filename (TEST_CERT_DIR, (const char *) test_data, NULL);
+
+	array = crypto_load_and_verify_certificate (path, &format, &error);
+	g_assert_no_error (error);
+	g_assert_cmpint (format, ==, NM_CRYPTO_FILE_FORMAT_X509);
+
+	g_byte_array_free (array, TRUE);
+
+	g_assert (nm_utils_file_is_certificate (path));
+}
+
+static GByteArray *
+file_to_byte_array (const char *filename)
+{
+	char *contents;
+	GByteArray *array = NULL;
+	gsize length = 0;
+
+	if (g_file_get_contents (filename, &contents, &length, NULL)) {
+		array = g_byte_array_sized_new (length);
+		g_byte_array_append (array, (guint8 *) contents, length);
+		g_assert (array->len == length);
+		g_free (contents);
+	}
+	return array;
+}
+
+static void
+test_load_private_key (const char *path,
+                       const char *password,
+                       const char *decrypted_path,
+                       int expected_error)
+{
+	NMCryptoKeyType key_type = NM_CRYPTO_KEY_TYPE_UNKNOWN;
+	gboolean is_encrypted = FALSE;
+	GByteArray *array, *decrypted;
+	GError *error = NULL;
+
+	g_assert (nm_utils_file_is_private_key (path, &is_encrypted));
+	g_assert (is_encrypted);
+
+	array = crypto_decrypt_openssl_private_key (path, password, &key_type, &error);
+	/* Even if the password is wrong, we should determine the key type */
+	g_assert_cmpint (key_type, ==, NM_CRYPTO_KEY_TYPE_RSA);
+
+	if (expected_error != -1) {
+		g_assert (array == NULL);
+		g_assert_error (error, NM_CRYPTO_ERROR, expected_error);
+		g_clear_error (&error);
+		return;
+	}
+
+	if (password == NULL) {
+		g_assert (array == NULL);
+		g_assert_no_error (error);
+		return;
+	}
+
+	g_assert (array != NULL);
+
+	if (decrypted_path) {
+		/* Compare the crypto decrypted key against a known-good decryption */
+		decrypted = file_to_byte_array (decrypted_path);
+		g_assert (decrypted != NULL);
+		g_assert (decrypted->len == array->len);
+		g_assert (memcmp (decrypted->data, array->data, array->len) == 0);
+
+		g_byte_array_free (decrypted, TRUE);
+	}
+
+	g_byte_array_free (array, TRUE);
+}
+
+static void
+test_load_pkcs12 (const char *path,
+                  const char *password,
+                  int expected_error)
+{
+	NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
+	gboolean is_encrypted = FALSE;
+	GError *error = NULL;
+
+	g_assert (nm_utils_file_is_private_key (path, NULL));
+
+	format = crypto_verify_private_key (path, password, &is_encrypted, &error);
+	if (expected_error != -1) {
+		g_assert_error (error, NM_CRYPTO_ERROR, expected_error);
+		g_assert_cmpint (format, ==, NM_CRYPTO_FILE_FORMAT_UNKNOWN);
+		g_clear_error (&error);
+	} else {
+		g_assert_no_error (error);
+		g_assert_cmpint (format, ==, NM_CRYPTO_FILE_FORMAT_PKCS12);
+		g_assert (is_encrypted);
+	}
+}
+
+static void
+test_load_pkcs12_no_password (const char *path)
+{
+	NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
+	gboolean is_encrypted = FALSE;
+	GError *error = NULL;
+
+	g_assert (nm_utils_file_is_private_key (path, NULL));
+
+	/* We should still get a valid returned crypto file format */
+	format = crypto_verify_private_key (path, NULL, &is_encrypted, &error);
+	g_assert_no_error (error);
+	g_assert_cmpint (format, ==, NM_CRYPTO_FILE_FORMAT_PKCS12);
+	g_assert (is_encrypted);
+}
+
+static void
+test_is_pkcs12 (const char *path, gboolean expect_fail)
+{
+	gboolean is_pkcs12;
+	GError *error = NULL;
+
+	is_pkcs12 = crypto_is_pkcs12_file (path, &error);
+
+	if (expect_fail) {
+		g_assert_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_INVALID_DATA);
+		g_assert (!is_pkcs12);
+	} else {
+		g_assert_no_error (error);
+		g_assert (is_pkcs12);
+	}
+}
+
+static void
+test_load_pkcs8 (const char *path,
+                 const char *password,
+                 int expected_error)
+{
+	NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
+	gboolean is_encrypted = FALSE;
+	GError *error = NULL;
+
+	g_assert (nm_utils_file_is_private_key (path, NULL));
+
+	format = crypto_verify_private_key (path, password, &is_encrypted, &error);
+	if (expected_error != -1) {
+		g_assert_error (error, NM_CRYPTO_ERROR, expected_error);
+		g_assert_cmpint (format, ==, NM_CRYPTO_FILE_FORMAT_UNKNOWN);
+		g_clear_error (&error);
+	} else {
+		g_assert_no_error (error);
+		g_assert_cmpint (format, ==, NM_CRYPTO_FILE_FORMAT_RAW_KEY);
+		g_assert (is_encrypted);
+	}
+}
+
+static void
+test_encrypt_private_key (const char *path,
+                          const char *password)
+{
+	NMCryptoKeyType key_type = NM_CRYPTO_KEY_TYPE_UNKNOWN;
+	GByteArray *array, *encrypted, *re_decrypted;
+	GError *error = NULL;
+
+	array = crypto_decrypt_openssl_private_key (path, password, &key_type, &error);
+	g_assert_no_error (error);
+	g_assert (array != NULL);
+	g_assert_cmpint (key_type, ==, NM_CRYPTO_KEY_TYPE_RSA);
+
+	/* Now re-encrypt the private key */
+	encrypted = nm_utils_rsa_key_encrypt (array->data, array->len, password, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (encrypted != NULL);
+
+	/* Then re-decrypt the private key */
+	key_type = NM_CRYPTO_KEY_TYPE_UNKNOWN;
+	re_decrypted = crypto_decrypt_openssl_private_key_data (encrypted->data, encrypted->len,
+	                                                        password, &key_type, &error);
+	g_assert_no_error (error);
+	g_assert (re_decrypted != NULL);
+	g_assert_cmpint (key_type, ==, NM_CRYPTO_KEY_TYPE_RSA);
+
+	/* Compare the original decrypted key with the re-decrypted key */
+	g_assert_cmpint (array->len, ==, re_decrypted->len);
+	g_assert (!memcmp (array->data, re_decrypted->data, array->len));
+
+	g_byte_array_free (re_decrypted, TRUE);
+	g_byte_array_free (encrypted, TRUE);
+	g_byte_array_free (array, TRUE);
+}
+
+static void
+test_key (gconstpointer test_data)
+{
+	char **parts, *path, *password, *decrypted_path;
+	int len;
+
+	parts = g_strsplit ((const char *) test_data, ", ", -1);
+	len = g_strv_length (parts);
+	if (len != 2 && len != 3)
+		g_error ("wrong number of arguments (<key file>, <password>, [<decrypted key file>])");
+
+	path = g_build_filename (TEST_CERT_DIR, parts[0], NULL);
+	password = parts[1];
+	decrypted_path = parts[2] ? g_build_filename (TEST_CERT_DIR, parts[2], NULL) : NULL;
+
+	test_is_pkcs12 (path, TRUE);
+	test_load_private_key (path, password, decrypted_path, -1);
+	test_load_private_key (path, "blahblahblah", NULL, NM_CRYPTO_ERROR_DECRYPTION_FAILED);
+	test_load_private_key (path, NULL, NULL, -1);
+	test_encrypt_private_key (path, password);
+
+	g_free (path);
+	g_free (decrypted_path);
+	g_strfreev (parts);
+}
+
+static void
+test_key_decrypted (gconstpointer test_data)
+{
+	const char *file = (const char *) test_data;
+	gboolean is_encrypted = FALSE;
+	char *path;
+
+	path = g_build_filename (TEST_CERT_DIR, file, NULL);
+
+	g_assert (nm_utils_file_is_private_key (path, &is_encrypted));
+	g_assert (!is_encrypted);
+
+	g_free (path);
+}
+
+static void
+test_pkcs12 (gconstpointer test_data)
+{
+	char **parts, *path, *password;
+
+	parts = g_strsplit ((const char *) test_data, ", ", -1);
+	if (g_strv_length (parts) != 2)
+		g_error ("wrong number of arguments (<file>, <password>)");
+
+	path = g_build_filename (TEST_CERT_DIR, parts[0], NULL);
+	password = parts[1];
+
+	test_is_pkcs12 (path, FALSE);
+	test_load_pkcs12 (path, password, -1);
+	test_load_pkcs12 (path, "blahblahblah", NM_CRYPTO_ERROR_DECRYPTION_FAILED);
+	test_load_pkcs12_no_password (path);
+
+	g_free (path);
+	g_strfreev (parts);
+}
+
+static void
+test_pkcs8 (gconstpointer test_data)
+{
+	char **parts, *path, *password;
+
+	parts = g_strsplit ((const char *) test_data, ", ", -1);
+	if (g_strv_length (parts) != 2)
+		g_error ("wrong number of arguments (<file>, <password>)");
+
+	path = g_build_filename (TEST_CERT_DIR, parts[0], NULL);
+	password = parts[1];
+
+	test_is_pkcs12 (path, TRUE);
+	test_load_pkcs8 (path, password, -1);
+	/* Until gnutls and NSS grow support for all the ciphers that openssl
+	 * can use with PKCS#8, we can't actually verify the password.  So we
+	 * expect a bad password to work for the time being.
+	 */
+	test_load_pkcs8 (path, "blahblahblah", -1);
+
+	g_free (path);
+	g_strfreev (parts);
+}
+
+#define SALT "sodium chloride"
+#define SHORT_PASSWORD "short"
+#define LONG_PASSWORD "this is a longer password than the short one"
+#define SHORT_DIGEST 16
+#define LONG_DIGEST 57
+
+struct {
+	const char *salt, *password;
+	gsize digest_size;
+	const char *result;
+} md5_tests[] = {
+	{ NULL, SHORT_PASSWORD, SHORT_DIGEST,
+	  "4f09daa9d95bcb166a302407a0e0babe" },
+	{ NULL, SHORT_PASSWORD, LONG_DIGEST,
+	  "4f09daa9d95bcb166a302407a0e0babeb7d62e5baf706830d007c253f0fe7584ad7e92dc00a599ec277293c298ae70ee3904c348e23be61c91" },
+	{ SALT, SHORT_PASSWORD, SHORT_DIGEST,
+	  "774771f7292210233b5724991d1f9894" },
+	{ SALT, SHORT_PASSWORD, LONG_DIGEST,
+	  "774771f7292210233b5724991d1f98941a6ffdb45e4dc7fa04b1fa6aceed379c1ade0577bc8f261d109942ed5736921c052664d72e0d5bade9" },
+	{ NULL, LONG_PASSWORD, SHORT_DIGEST,
+	  "e9c03517f81ff29bb777dac21fb1699c" },
+	{ NULL, LONG_PASSWORD, LONG_DIGEST,
+	  "e9c03517f81ff29bb777dac21fb1699c50968c7ccd8db4f0a59d00ffd87b05876d45f25a927d51a8400c35af60fbd64584349a8b7435d62fd9" },
+	{ SALT, LONG_PASSWORD, SHORT_DIGEST,
+	  "4e5c076e2f85f5e03994acbf3a9e10d6" },
+	{ SALT, LONG_PASSWORD, LONG_DIGEST,
+	  "4e5c076e2f85f5e03994acbf3a9e10d61a6969c9fdf47ae8b1f7e2725b3767b05cc974bfcb5344b630c91761e015e09d7794b5065662533bc9" },
+	{ NULL, "", SHORT_DIGEST,
+	  "d41d8cd98f00b204e9800998ecf8427e" },
+	{ SALT, "", SHORT_DIGEST,
+	  "7df1e0494c977195005d82a1809685e4" },
+};
+
+static void
+test_md5 (void)
+{
+	char digest[LONG_DIGEST], *hex;
+	int i;
+
+	for (i = 0; i < G_N_ELEMENTS (md5_tests); i++) {
+		memset (digest, 0, sizeof (digest));
+		crypto_md5_hash (md5_tests[i].salt,
+		                 /* crypto_md5_hash() used to clamp salt_len to 8.  It
+		                  * doesn't any more, so we need to do it here now to
+		                  * get output that matches md5_tests[i].result.
+		                  */
+		                 md5_tests[i].salt ? 8 : 0,
+		                 md5_tests[i].password,
+		                 strlen (md5_tests[i].password),
+		                 digest, md5_tests[i].digest_size);
+
+		hex = nm_utils_bin2hexstr (digest, md5_tests[i].digest_size, -1);
+		g_assert_cmpstr (hex, ==, md5_tests[i].result);
+		g_free (hex);
+	}
+}
+
+NMTST_DEFINE ();
+
+int
+main (int argc, char **argv)
+{
+	GError *error = NULL;
+	int ret;
+
+	nmtst_init (&argc, &argv, TRUE);
+
+	if (!crypto_init (&error))
+		FAIL ("crypto-init", "failed to initialize crypto: %s", error->message);
+
+	g_test_add_data_func ("/libnm/crypto/cert/pem",
+	                      "test_ca_cert.pem",
+	                      test_cert);
+	g_test_add_data_func ("/libnm/crypto/cert/pem-2",
+	                      "test2_ca_cert.pem",
+	                      test_cert);
+	g_test_add_data_func ("/libnm/crypto/cert/der",
+	                      "test_ca_cert.der",
+	                      test_cert);
+	g_test_add_data_func ("/libnm/crypto/cert/pem-no-ending-newline",
+	                      "ca-no-ending-newline.pem",
+	                      test_cert);
+	g_test_add_data_func ("/libnm/crypto/cert/pem-combined",
+	                      "test_key_and_cert.pem",
+	                      test_cert);
+	g_test_add_data_func ("/libnm/crypto/cert/pem-combined-2",
+	                      "test2_key_and_cert.pem",
+	                      test_cert);
+
+	g_test_add_data_func ("/libnm/crypto/key/padding-6",
+	                      "test_key_and_cert.pem, test, test-key-only-decrypted.der",
+	                      test_key);
+	g_test_add_data_func ("/libnm/crypto/key/key-only",
+	                      "test-key-only.pem, test, test-key-only-decrypted.der",
+	                      test_key);
+	g_test_add_data_func ("/libnm/crypto/key/padding-8",
+	                      "test2_key_and_cert.pem, 12345testing",
+	                      test_key);
+	g_test_add_data_func ("/libnm/crypto/key/aes",
+	                      "test-aes-key.pem, test-aes-password",
+	                      test_key);
+	g_test_add_data_func ("/libnm/crypto/key/decrypted",
+	                      "test-key-only-decrypted.pem",
+	                      test_key_decrypted);
+
+	g_test_add_data_func ("/libnm/crypto/PKCS#12/1",
+	                      "test-cert.p12, test",
+	                      test_pkcs12);
+	g_test_add_data_func ("/libnm/crypto/PKCS#12/2",
+	                      "test2-cert.p12, 12345testing",
+	                      test_pkcs12);
+
+	g_test_add_data_func ("/libnm/crypto/PKCS#8",
+	                      "pkcs8-enc-key.pem, 1234567890",
+	                      test_pkcs8);
+
+	g_test_add_func ("/libnm/crypto/md5", test_md5);
+
+	ret = g_test_run ();
+
+	return ret;
+}
+
diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c
new file mode 100644
index 00000000..d309c800
--- /dev/null
+++ b/libnm-core/tests/test-general.c
@@ -0,0 +1,3961 @@
+/* -*- 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 2008 - 2011 Red Hat, Inc.
+ *
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <string.h>
+
+#include <nm-utils.h>
+
+#include "nm-setting-private.h"
+#include "nm-utils.h"
+#include "nm-core-internal.h"
+
+#include "nm-setting-8021x.h"
+#include "nm-setting-adsl.h"
+#include "nm-setting-bluetooth.h"
+#include "nm-setting-bond.h"
+#include "nm-setting-bridge.h"
+#include "nm-setting-bridge-port.h"
+#include "nm-setting-cdma.h"
+#include "nm-setting-connection.h"
+#include "nm-setting-generic.h"
+#include "nm-setting-gsm.h"
+#include "nm-setting-infiniband.h"
+#include "nm-setting-ip4-config.h"
+#include "nm-setting-ip6-config.h"
+#include "nm-setting-olpc-mesh.h"
+#include "nm-setting-ppp.h"
+#include "nm-setting-pppoe.h"
+#include "nm-setting-serial.h"
+#include "nm-setting-team.h"
+#include "nm-setting-team-port.h"
+#include "nm-setting-vlan.h"
+#include "nm-setting-vpn.h"
+#include "nm-setting-wimax.h"
+#include "nm-setting-wired.h"
+#include "nm-setting-wireless.h"
+#include "nm-setting-wireless-security.h"
+#include "nm-simple-connection.h"
+
+#include "nm-test-utils.h"
+
+static void
+vpn_check_func (const char *key, const char *value, gpointer user_data)
+{
+	const char *test = user_data;
+
+	if (!strcmp (key, "foobar1")) {
+		ASSERT (strcmp (value, "blahblah1") == 0,
+				test, "unexpected vpn item '%s' / '%s'", key, value);
+		return;
+	}
+
+	if (!strcmp (key, "foobar2")) {
+		ASSERT (strcmp (value, "blahblah2") == 0,
+				test, "unexpected vpn item '%s' / '%s'", key, value);
+		return;
+	}
+
+	if (!strcmp (key, "foobar3")) {
+		ASSERT (strcmp (value, "blahblah3") == 0,
+				test, "unexpected vpn item '%s' / '%s'", key, value);
+		return;
+	}
+
+	if (!strcmp (key, "foobar4")) {
+		ASSERT (strcmp (value, "blahblah4") == 0,
+				test, "unexpected vpn item '%s' / '%s'", key, value);
+		return;
+	}
+
+	ASSERT (FALSE, test, "unexpected vpn item '%s'", key);
+}
+
+static void
+vpn_check_empty_func (const char *key, const char *value, gpointer user_data)
+{
+	const char *test = user_data;
+
+	/* We don't expect any values */
+	ASSERT (FALSE, test, "unexpected vpn item '%s'", key);
+}
+
+static void
+test_setting_vpn_items (void)
+{
+	NMSettingVpn *s_vpn;
+
+	s_vpn = (NMSettingVpn *) nm_setting_vpn_new ();
+	ASSERT (s_vpn != NULL,
+	        "vpn-items",
+	        "error creating vpn setting");
+
+	nm_setting_vpn_add_data_item (s_vpn, "foobar1", "blahblah1");
+	nm_setting_vpn_add_data_item (s_vpn, "foobar2", "blahblah2");
+	nm_setting_vpn_add_data_item (s_vpn, "foobar3", "blahblah3");
+	nm_setting_vpn_add_data_item (s_vpn, "foobar4", "blahblah4");
+
+	/* Ensure that added values are all present */
+	nm_setting_vpn_foreach_data_item (s_vpn, vpn_check_func, "vpn-data");
+	nm_setting_vpn_remove_data_item (s_vpn, "foobar1");
+	nm_setting_vpn_remove_data_item (s_vpn, "foobar2");
+	nm_setting_vpn_remove_data_item (s_vpn, "foobar3");
+	nm_setting_vpn_remove_data_item (s_vpn, "foobar4");
+
+	nm_setting_vpn_add_secret (s_vpn, "foobar1", "blahblah1");
+	nm_setting_vpn_add_secret (s_vpn, "foobar2", "blahblah2");
+	nm_setting_vpn_add_secret (s_vpn, "foobar3", "blahblah3");
+	nm_setting_vpn_add_secret (s_vpn, "foobar4", "blahblah4");
+
+	/* Ensure that added values are all present */
+	nm_setting_vpn_foreach_secret (s_vpn, vpn_check_func, "vpn-secrets");
+	nm_setting_vpn_remove_secret (s_vpn, "foobar1");
+	nm_setting_vpn_remove_secret (s_vpn, "foobar2");
+	nm_setting_vpn_remove_secret (s_vpn, "foobar3");
+	nm_setting_vpn_remove_secret (s_vpn, "foobar4");
+
+	/* Try to add some blank values and make sure they are rejected */
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*key != NULL*");
+	nm_setting_vpn_add_data_item (s_vpn, NULL, NULL);
+	g_test_assert_expected_messages ();
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*strlen (key) > 0*");
+	nm_setting_vpn_add_data_item (s_vpn, "", "");
+	g_test_assert_expected_messages ();
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*item != NULL*");
+	nm_setting_vpn_add_data_item (s_vpn, "foobar1", NULL);
+	g_test_assert_expected_messages ();
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*strlen (item) > 0*");
+	nm_setting_vpn_add_data_item (s_vpn, "foobar1", "");
+	g_test_assert_expected_messages ();
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*key != NULL*");
+	nm_setting_vpn_add_data_item (s_vpn, NULL, "blahblah1");
+	g_test_assert_expected_messages ();
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*strlen (key) > 0*");
+	nm_setting_vpn_add_data_item (s_vpn, "", "blahblah1");
+	g_test_assert_expected_messages ();
+
+	nm_setting_vpn_foreach_data_item (s_vpn, vpn_check_empty_func, "vpn-data-empty");
+
+	/* Try to add some blank secrets and make sure they are rejected */
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*key != NULL*");
+	nm_setting_vpn_add_secret (s_vpn, NULL, NULL);
+	g_test_assert_expected_messages ();
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*strlen (key) > 0*");
+	nm_setting_vpn_add_secret (s_vpn, "", "");
+	g_test_assert_expected_messages ();
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*secret != NULL*");
+	nm_setting_vpn_add_secret (s_vpn, "foobar1", NULL);
+	g_test_assert_expected_messages ();
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*strlen (secret) > 0*");
+	nm_setting_vpn_add_secret (s_vpn, "foobar1", "");
+	g_test_assert_expected_messages ();
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*key != NULL*");
+	nm_setting_vpn_add_secret (s_vpn, NULL, "blahblah1");
+	g_test_assert_expected_messages ();
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*strlen (key) > 0*");
+	nm_setting_vpn_add_secret (s_vpn, "", "blahblah1");
+	g_test_assert_expected_messages ();
+
+	nm_setting_vpn_foreach_secret (s_vpn, vpn_check_empty_func, "vpn-secrets-empty");
+
+	g_object_unref (s_vpn);
+}
+
+static void
+test_setting_vpn_update_secrets (void)
+{
+	NMConnection *connection;
+	NMSettingVpn *s_vpn;
+	GVariantBuilder settings_builder, vpn_builder, secrets_builder;
+	GVariant *settings;
+	gboolean success;
+	GError *error = NULL;
+	const char *tmp;
+	const char *key1 = "foobar";
+	const char *key2 = "blahblah";
+	const char *val1 = "value1";
+	const char *val2 = "value2";
+
+	connection = nm_simple_connection_new ();
+	ASSERT (connection != NULL,
+	        "vpn-update-secrets",
+	        "error creating connection");
+
+	s_vpn = (NMSettingVpn *) nm_setting_vpn_new ();
+	ASSERT (s_vpn != NULL,
+	        "vpn-update-secrets",
+	        "error creating vpn setting");
+	nm_connection_add_setting (connection, NM_SETTING (s_vpn));
+
+	g_variant_builder_init (&settings_builder, NM_VARIANT_TYPE_CONNECTION);
+	g_variant_builder_init (&vpn_builder, NM_VARIANT_TYPE_SETTING);
+	g_variant_builder_init (&secrets_builder, G_VARIANT_TYPE ("a{ss}"));
+
+	g_variant_builder_add (&secrets_builder, "{ss}", key1, val1);
+	g_variant_builder_add (&secrets_builder, "{ss}", key2, val2);
+
+	g_variant_builder_add (&vpn_builder, "{sv}",
+	                       NM_SETTING_VPN_SECRETS,
+	                       g_variant_builder_end (&secrets_builder));
+	g_variant_builder_add (&settings_builder, "{sa{sv}}",
+	                       NM_SETTING_VPN_SETTING_NAME,
+	                       &vpn_builder);
+	settings = g_variant_builder_end (&settings_builder);
+
+	success = nm_connection_update_secrets (connection, NM_SETTING_VPN_SETTING_NAME, settings, &error);
+	ASSERT (success == TRUE,
+	        "vpn-update-secrets", "failed to update VPN secrets: %s", error->message);
+
+	/* Read the secrets back out */
+	tmp = nm_setting_vpn_get_secret (s_vpn, key1);
+	ASSERT (tmp != NULL,
+	        "vpn-update-secrets", "unexpected failure getting key #1");
+	ASSERT (strcmp (tmp, val1) == 0,
+	        "vpn-update-secrets", "unexpected key #1 value");
+
+	tmp = nm_setting_vpn_get_secret (s_vpn, key2);
+	ASSERT (tmp != NULL,
+	        "vpn-update-secrets", "unexpected failure getting key #2");
+	ASSERT (strcmp (tmp, val2) == 0,
+	        "vpn-update-secrets", "unexpected key #2 value");
+
+	g_variant_unref (settings);
+	g_object_unref (connection);
+}
+
+#define TO_DEL_NUM 50
+typedef struct {
+	NMSettingVpn *s_vpn;
+	char *to_del[TO_DEL_NUM];
+	guint called;
+} IterInfo;
+
+static void
+del_iter_func (const char *key, const char *value, gpointer user_data)
+{
+	IterInfo *info = user_data;
+	int i;
+
+	/* Record how many times this function gets called; it should get called
+	 * exactly as many times as there are keys in the hash table, regardless
+	 * of what keys we delete from the table.
+	 */
+	info->called++;
+
+	/* During the iteration, remove a bunch of stuff from the table */
+	if (info->called == 1) {
+		for (i = 0; i < TO_DEL_NUM; i++)
+			nm_setting_vpn_remove_data_item (info->s_vpn, info->to_del[i]);
+	}
+}
+
+static void
+test_setting_vpn_modify_during_foreach (void)
+{
+	NMSettingVpn *s_vpn;
+	IterInfo info;
+	char *key, *val;
+	int i, u = 0;
+
+	s_vpn = (NMSettingVpn *) nm_setting_vpn_new ();
+	g_assert (s_vpn);
+
+	for (i = 0; i < TO_DEL_NUM * 2; i++) {
+		key = g_strdup_printf ("adsfasdfadf%d", i);
+		val = g_strdup_printf ("42263236236awt%d", i);
+		nm_setting_vpn_add_data_item (s_vpn, key, val);
+
+		/* Cache some keys to delete */
+		if (i % 2)
+			info.to_del[u++] = g_strdup (key);
+
+		g_free (key);
+		g_free (val);
+	}
+
+	/* Iterate over current table keys */
+	info.s_vpn = s_vpn;
+	info.called = 0;
+	nm_setting_vpn_foreach_data_item (s_vpn, del_iter_func, &info);
+
+	/* Make sure all the things we removed during iteration are really gone */
+	for (i = 0; i < TO_DEL_NUM; i++) {
+		g_assert_cmpstr (nm_setting_vpn_get_data_item (s_vpn, info.to_del[i]), ==, NULL);
+		g_free (info.to_del[i]);
+	}
+
+	/* And make sure the foreach callback was called the same number of times
+	 * as there were keys in the table at the beginning of the foreach.
+	 */
+	g_assert_cmpint (info.called, ==, TO_DEL_NUM * 2);
+
+	g_object_unref (s_vpn);
+}
+
+static void
+test_setting_ip4_config_labels (void)
+{
+	NMSettingIPConfig *s_ip4;
+	NMIPAddress *addr;
+	GVariant *label;
+	GPtrArray *addrs;
+	char **labels;
+	NMConnection *conn;
+	GVariant *dict, *dict2, *setting_dict, *value;
+	GError *error = NULL;
+
+	s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
+	g_object_set (G_OBJECT (s_ip4),
+	              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
+	              NULL);
+
+	/* addr 1 */
+	addr = nm_ip_address_new (AF_INET, "1.2.3.4", 24, &error);
+	g_assert_no_error (error);
+
+	nm_setting_ip_config_add_address (s_ip4, addr);
+	nm_ip_address_unref (addr);
+	nmtst_assert_setting_verifies (NM_SETTING (s_ip4));
+
+	addr = nm_setting_ip_config_get_address (s_ip4, 0);
+	label = nm_ip_address_get_attribute (addr, "label");
+	g_assert (label == NULL);
+
+	/* The 'address-labels' property should be omitted from the serialization if
+	 * there are no non-NULL labels.
+	 */
+	conn = nmtst_create_minimal_connection ("label test", NULL, NM_SETTING_WIRED_SETTING_NAME, NULL);
+	nm_connection_add_setting (conn, nm_setting_duplicate (NM_SETTING (s_ip4)));
+	dict = nm_connection_to_dbus (conn, NM_CONNECTION_SERIALIZE_ALL);
+	g_object_unref (conn);
+
+	setting_dict = g_variant_lookup_value (dict, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
+	g_assert (setting_dict != NULL);
+
+	value = g_variant_lookup_value (setting_dict, "address-labels", NULL);
+	g_assert (value == NULL);
+
+	g_variant_unref (setting_dict);
+	g_variant_unref (dict);
+
+	/* Now back to constructing the original s_ip4... */
+
+	/* addr 2 */
+	addr = nm_ip_address_new (AF_INET, "2.3.4.5", 24, &error);
+	g_assert_no_error (error);
+	nm_ip_address_set_attribute (addr, "label", g_variant_new_string ("eth0:1"));
+
+	nm_setting_ip_config_add_address (s_ip4, addr);
+	nm_ip_address_unref (addr);
+	nmtst_assert_setting_verifies (NM_SETTING (s_ip4));
+
+	addr = nm_setting_ip_config_get_address (s_ip4, 1);
+	label = nm_ip_address_get_attribute (addr, "label");
+	g_assert (label != NULL);
+	g_assert_cmpstr (g_variant_get_string (label, NULL), ==, "eth0:1");
+
+	/* addr 3 */
+	addr = nm_ip_address_new (AF_INET, "3.4.5.6", 24, &error);
+	g_assert_no_error (error);
+	nm_ip_address_set_attribute (addr, "label", NULL);
+
+	nm_setting_ip_config_add_address (s_ip4, addr);
+	nm_ip_address_unref (addr);
+	nmtst_assert_setting_verifies (NM_SETTING (s_ip4));
+
+	addr = nm_setting_ip_config_get_address (s_ip4, 2);
+	label = nm_ip_address_get_attribute (addr, "label");
+	g_assert (label == NULL);
+
+	/* Remove addr 1 and re-verify remaining addresses */
+	nm_setting_ip_config_remove_address (s_ip4, 0);
+	nmtst_assert_setting_verifies (NM_SETTING (s_ip4));
+
+	addr = nm_setting_ip_config_get_address (s_ip4, 0);
+	g_assert_cmpstr (nm_ip_address_get_address (addr), ==, "2.3.4.5");
+	label = nm_ip_address_get_attribute (addr, "label");
+	g_assert (label != NULL);
+	g_assert_cmpstr (g_variant_get_string (label, NULL), ==, "eth0:1");
+
+	addr = nm_setting_ip_config_get_address (s_ip4, 1);
+	g_assert_cmpstr (nm_ip_address_get_address (addr), ==, "3.4.5.6");
+	label = nm_ip_address_get_attribute (addr, "label");
+	g_assert (label == NULL);
+
+	/* If we serialize as the daemon, the labels should appear in the D-Bus
+	 * serialization under both 'address-labels' and 'address-data'.
+	 */
+	conn = nmtst_create_minimal_connection ("label test", NULL, NM_SETTING_WIRED_SETTING_NAME, NULL);
+	nm_connection_add_setting (conn, NM_SETTING (s_ip4));
+	_nm_utils_is_manager_process = TRUE;
+	dict = nm_connection_to_dbus (conn, NM_CONNECTION_SERIALIZE_ALL);
+	_nm_utils_is_manager_process = FALSE;
+	g_object_unref (conn);
+
+	setting_dict = g_variant_lookup_value (dict, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
+	g_assert (setting_dict != NULL);
+
+	value = g_variant_lookup_value (setting_dict, "address-labels", G_VARIANT_TYPE_STRING_ARRAY);
+	g_assert (value != NULL);
+	g_variant_get (value, "^as", &labels);
+	g_assert_cmpint (g_strv_length (labels), ==, 2);
+	g_assert_cmpstr (labels[0], ==, "eth0:1");
+	g_assert_cmpstr (labels[1], ==, "");
+	g_variant_unref (value);
+	g_strfreev (labels);
+
+	value = g_variant_lookup_value (setting_dict, "address-data", G_VARIANT_TYPE ("aa{sv}"));
+	addrs = nm_utils_ip_addresses_from_variant (value, AF_INET);
+	g_variant_unref (value);
+	g_assert (addrs != NULL);
+	g_assert_cmpint (addrs->len, ==, 2);
+	addr = addrs->pdata[0];
+	label = nm_ip_address_get_attribute (addr, "label");
+	g_assert (label != NULL);
+	g_assert_cmpstr (g_variant_get_string (label, NULL), ==, "eth0:1");
+	addr = addrs->pdata[1];
+	label = nm_ip_address_get_attribute (addr, "label");
+	g_assert (label == NULL);
+	g_ptr_array_unref (addrs);
+
+	g_variant_unref (setting_dict);
+
+	/* We should be able to deserialize the labels from either 'address-labels'
+	 * or 'address-data'.
+	 */
+	dict2 = g_variant_ref (dict);
+
+	NMTST_VARIANT_EDITOR (dict,
+	                      NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_IP4_CONFIG_SETTING_NAME,
+	                                                   "address-data");
+	                      );
+	conn = nm_simple_connection_new_from_dbus (dict, &error);
+	g_assert_no_error (error);
+	g_variant_unref (dict);
+
+	s_ip4 = nm_connection_get_setting_ip4_config (conn);
+
+	addr = nm_setting_ip_config_get_address (s_ip4, 0);
+	g_assert_cmpstr (nm_ip_address_get_address (addr), ==, "2.3.4.5");
+	label = nm_ip_address_get_attribute (addr, "label");
+	g_assert (label != NULL);
+	g_assert_cmpstr (g_variant_get_string (label, NULL), ==, "eth0:1");
+
+	addr = nm_setting_ip_config_get_address (s_ip4, 1);
+	g_assert_cmpstr (nm_ip_address_get_address (addr), ==, "3.4.5.6");
+	label = nm_ip_address_get_attribute (addr, "label");
+	g_assert (label == NULL);
+
+	g_object_unref (conn);
+
+	NMTST_VARIANT_EDITOR (dict2,
+	                      NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_IP4_CONFIG_SETTING_NAME,
+	                                                   "address-labels");
+	                      );
+	conn = nm_simple_connection_new_from_dbus (dict2, &error);
+	g_assert_no_error (error);
+	g_variant_unref (dict2);
+
+	s_ip4 = nm_connection_get_setting_ip4_config (conn);
+
+	addr = nm_setting_ip_config_get_address (s_ip4, 0);
+	g_assert_cmpstr (nm_ip_address_get_address (addr), ==, "2.3.4.5");
+	label = nm_ip_address_get_attribute (addr, "label");
+	g_assert_cmpstr (g_variant_get_string (label, NULL), ==, "eth0:1");
+
+	addr = nm_setting_ip_config_get_address (s_ip4, 1);
+	g_assert_cmpstr (nm_ip_address_get_address (addr), ==, "3.4.5.6");
+	label = nm_ip_address_get_attribute (addr, "label");
+	g_assert (label == NULL);
+
+	/* Test explicit property assignment */
+	g_object_get (G_OBJECT (s_ip4),
+	              NM_SETTING_IP_CONFIG_ADDRESSES, &addrs,
+	              NULL);
+
+	nm_setting_ip_config_clear_addresses (s_ip4);
+	g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 0);
+
+	g_object_set (G_OBJECT (s_ip4),
+	              NM_SETTING_IP_CONFIG_ADDRESSES, addrs,
+	              NULL);
+	g_ptr_array_unref (addrs);
+	nmtst_assert_setting_verifies (NM_SETTING (s_ip4));
+	g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 2);
+
+	addr = nm_setting_ip_config_get_address (s_ip4, 0);
+	g_assert_cmpstr (nm_ip_address_get_address (addr), ==, "2.3.4.5");
+	label = nm_ip_address_get_attribute (addr, "label");
+	g_assert (label != NULL);
+	g_assert_cmpstr (g_variant_get_string (label, NULL), ==, "eth0:1");
+
+	addr = nm_setting_ip_config_get_address (s_ip4, 1);
+	g_assert_cmpstr (nm_ip_address_get_address (addr), ==, "3.4.5.6");
+	label = nm_ip_address_get_attribute (addr, "label");
+	g_assert (label == NULL);
+
+	g_object_unref (conn);
+}
+
+static void
+test_setting_ip4_config_address_data (void)
+{
+	NMSettingIPConfig *s_ip4;
+	NMIPAddress *addr;
+	GPtrArray *addrs;
+	NMConnection *conn;
+	GVariant *dict, *setting_dict, *value;
+	GError *error = NULL;
+
+	s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
+	g_object_set (G_OBJECT (s_ip4),
+	              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
+	              NULL);
+
+	/* addr 1 */
+	addr = nm_ip_address_new (AF_INET, "1.2.3.4", 24, &error);
+	g_assert_no_error (error);
+	nm_ip_address_set_attribute (addr, "one", g_variant_new_string ("foo"));
+	nm_ip_address_set_attribute (addr, "two", g_variant_new_int32 (42));
+
+	nm_setting_ip_config_add_address (s_ip4, addr);
+	nm_ip_address_unref (addr);
+	nmtst_assert_setting_verifies (NM_SETTING (s_ip4));
+
+	/* addr 2 */
+	addr = nm_ip_address_new (AF_INET, "2.3.4.5", 24, &error);
+	g_assert_no_error (error);
+
+	nm_setting_ip_config_add_address (s_ip4, addr);
+	nm_ip_address_unref (addr);
+	nmtst_assert_setting_verifies (NM_SETTING (s_ip4));
+
+	/* The client-side D-Bus serialization should include the attributes in
+	 * "address-data", and should not have an "addresses" property.
+	 */
+	conn = nmtst_create_minimal_connection ("address-data test", NULL, NM_SETTING_WIRED_SETTING_NAME, NULL);
+	nm_connection_add_setting (conn, NM_SETTING (s_ip4));
+	dict = nm_connection_to_dbus (conn, NM_CONNECTION_SERIALIZE_ALL);
+
+	setting_dict = g_variant_lookup_value (dict, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
+	g_assert (setting_dict != NULL);
+
+	value = g_variant_lookup_value (setting_dict, "addresses", NULL);
+	g_assert (value == NULL);
+
+	value = g_variant_lookup_value (setting_dict, "address-data", G_VARIANT_TYPE ("aa{sv}"));
+	addrs = nm_utils_ip_addresses_from_variant (value, AF_INET);
+	g_variant_unref (value);
+	g_assert (addrs != NULL);
+	g_assert_cmpint (addrs->len, ==, 2);
+
+	addr = addrs->pdata[0];
+	g_assert_cmpstr (nm_ip_address_get_address (addr), ==, "1.2.3.4");
+	value = nm_ip_address_get_attribute (addr, "one");
+	g_assert (value != NULL);
+	g_assert_cmpstr (g_variant_get_string (value, NULL), ==, "foo");
+	value = nm_ip_address_get_attribute (addr, "two");
+	g_assert (value != NULL);
+	g_assert_cmpint (g_variant_get_int32 (value), ==, 42);
+
+	g_ptr_array_unref (addrs);
+	g_variant_unref (setting_dict);
+	g_variant_unref (dict);
+
+	/* The daemon-side serialization should include both 'addresses' and 'address-data' */
+	_nm_utils_is_manager_process = TRUE;
+	dict = nm_connection_to_dbus (conn, NM_CONNECTION_SERIALIZE_ALL);
+	_nm_utils_is_manager_process = FALSE;
+
+	setting_dict = g_variant_lookup_value (dict, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
+	g_assert (setting_dict != NULL);
+
+	value = g_variant_lookup_value (setting_dict, "addresses", G_VARIANT_TYPE ("aau"));
+	g_assert (value != NULL);
+	g_variant_unref (value);
+
+	value = g_variant_lookup_value (setting_dict, "address-data", G_VARIANT_TYPE ("aa{sv}"));
+	g_assert (value != NULL);
+	g_variant_unref (value);
+
+	g_variant_unref (setting_dict);
+	g_object_unref (conn);
+
+	/* When we reserialize that dictionary as a client, 'address-data' will be preferred. */
+	conn = nm_simple_connection_new_from_dbus (dict, &error);
+	g_assert_no_error (error);
+
+	s_ip4 = nm_connection_get_setting_ip4_config (conn);
+
+	addr = nm_setting_ip_config_get_address (s_ip4, 0);
+	g_assert_cmpstr (nm_ip_address_get_address (addr), ==, "1.2.3.4");
+	value = nm_ip_address_get_attribute (addr, "one");
+	g_assert (value != NULL);
+	g_assert_cmpstr (g_variant_get_string (value, NULL), ==, "foo");
+	value = nm_ip_address_get_attribute (addr, "two");
+	g_assert (value != NULL);
+	g_assert_cmpint (g_variant_get_int32 (value), ==, 42);
+
+	/* But on the server side, 'addresses' will have precedence. */
+	_nm_utils_is_manager_process = TRUE;
+	conn = nm_simple_connection_new_from_dbus (dict, &error);
+	_nm_utils_is_manager_process = FALSE;
+	g_assert_no_error (error);
+	g_variant_unref (dict);
+
+	s_ip4 = nm_connection_get_setting_ip4_config (conn);
+
+	addr = nm_setting_ip_config_get_address (s_ip4, 0);
+	g_assert_cmpstr (nm_ip_address_get_address (addr), ==, "1.2.3.4");
+	value = nm_ip_address_get_attribute (addr, "one");
+	g_assert (value == NULL);
+	value = nm_ip_address_get_attribute (addr, "two");
+	g_assert (value == NULL);
+
+	g_object_unref (conn);
+}
+
+static void
+test_setting_gsm_apn_spaces (void)
+{
+	NMSettingGsm *s_gsm;
+	const char *tmp;
+
+	s_gsm = (NMSettingGsm *) nm_setting_gsm_new ();
+	ASSERT (s_gsm != NULL,
+	        "gsm-apn-spaces",
+	        "error creating GSM setting");
+
+	/* Trailing space */
+	g_object_set (s_gsm, NM_SETTING_GSM_APN, "foobar ", NULL);
+	tmp = nm_setting_gsm_get_apn (s_gsm);
+	ASSERT (tmp != NULL,
+	        "gsm-apn-spaces", "empty APN");
+	ASSERT (strcmp (tmp, "foobar") == 0,
+	        "gsm-apn-spaces", "unexpected APN");
+
+	/* Leading space */
+	g_object_set (s_gsm, NM_SETTING_GSM_APN, " foobar", NULL);
+	tmp = nm_setting_gsm_get_apn (s_gsm);
+	ASSERT (tmp != NULL,
+	        "gsm-apn-spaces", "empty APN");
+	ASSERT (strcmp (tmp, "foobar") == 0,
+	        "gsm-apn-spaces", "unexpected APN");
+}
+
+static void
+test_setting_gsm_apn_bad_chars (void)
+{
+	NMSettingGsm *s_gsm;
+
+	s_gsm = (NMSettingGsm *) nm_setting_gsm_new ();
+	ASSERT (s_gsm != NULL,
+	        "gsm-apn-bad-chars",
+	        "error creating GSM setting");
+
+	g_object_set (s_gsm, NM_SETTING_GSM_NUMBER, "*99#", NULL);
+
+	/* Make sure a valid APN works */
+	g_object_set (s_gsm, NM_SETTING_GSM_APN, "foobar123.-baz", NULL);
+	ASSERT (nm_setting_verify (NM_SETTING (s_gsm), NULL, NULL) == TRUE,
+	        "gsm-apn-bad-chars", "unexpectedly invalid GSM setting");
+
+	/* Random invalid chars */
+	g_object_set (s_gsm, NM_SETTING_GSM_APN, "@#%$@#%@#%", NULL);
+	ASSERT (nm_setting_verify (NM_SETTING (s_gsm), NULL, NULL) == FALSE,
+	        "gsm-apn-bad-chars", "unexpectedly valid GSM setting");
+
+	/* Spaces */
+	g_object_set (s_gsm, NM_SETTING_GSM_APN, "foobar baz", NULL);
+	ASSERT (nm_setting_verify (NM_SETTING (s_gsm), NULL, NULL) == FALSE,
+	        "gsm-apn-bad-chars", "unexpectedly valid GSM setting");
+
+	/* 0 characters long */
+	g_object_set (s_gsm, NM_SETTING_GSM_APN, "", NULL);
+	ASSERT (nm_setting_verify (NM_SETTING (s_gsm), NULL, NULL) == FALSE,
+	        "gsm-apn-bad-chars", "unexpectedly valid GSM setting");
+
+	/* 65-character long */
+	g_object_set (s_gsm, NM_SETTING_GSM_APN, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl1", NULL);
+	ASSERT (nm_setting_verify (NM_SETTING (s_gsm), NULL, NULL) == FALSE,
+	        "gsm-apn-bad-chars", "unexpectedly valid GSM setting");
+}
+
+static void
+test_setting_gsm_apn_underscore (void)
+{
+	NMSettingGsm *s_gsm;
+
+	s_gsm = (NMSettingGsm *) nm_setting_gsm_new ();
+	g_assert (s_gsm);
+
+	g_object_set (s_gsm, NM_SETTING_GSM_NUMBER, "*99#", NULL);
+
+	/* 65-character long */
+	g_object_set (s_gsm, NM_SETTING_GSM_APN, "foobar_baz", NULL);
+	nmtst_assert_setting_verifies (NM_SETTING (s_gsm));
+}
+
+static void
+test_setting_gsm_without_number (void)
+{
+	NMSettingGsm *s_gsm;
+
+	s_gsm = (NMSettingGsm *) nm_setting_gsm_new ();
+	g_assert (s_gsm);
+
+	g_object_set (s_gsm, NM_SETTING_GSM_NUMBER, NULL, NULL);
+	nmtst_assert_setting_verifies (NM_SETTING (s_gsm));
+
+	g_object_set (s_gsm, NM_SETTING_GSM_NUMBER, "", NULL);
+	nmtst_assert_setting_verify_fails (NM_SETTING (s_gsm), NM_CONNECTION_ERROR,
+	                                   NM_CONNECTION_ERROR_INVALID_PROPERTY);
+}
+
+static NMSettingWirelessSecurity *
+make_test_wsec_setting (const char *detail)
+{
+	NMSettingWirelessSecurity *s_wsec;
+
+	s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+	ASSERT (s_wsec != NULL, detail, "error creating setting");
+
+	g_object_set (s_wsec,
+	              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk",
+	              NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, "foobarbaz",
+	              NM_SETTING_WIRELESS_SECURITY_PSK, "random psk",
+	              NM_SETTING_WIRELESS_SECURITY_PSK_FLAGS, NM_SETTING_SECRET_FLAG_NOT_SAVED,
+	              NM_SETTING_WIRELESS_SECURITY_WEP_KEY0, "aaaaaaaaaa",
+	              NULL);
+
+	return s_wsec;
+}
+
+#define ASSERT_CONTAINS(vardict, key, test_name, msg) \
+	{ \
+		GVariant *value; \
+		value = g_variant_lookup_value (vardict, key, NULL); \
+		ASSERT (value != NULL, test_name, msg); \
+		g_variant_unref (value); \
+	}
+
+#define ASSERT_NOT_CONTAINS(vardict, key, test_name, msg) \
+	{ \
+		GVariant *value; \
+		value = g_variant_lookup_value (vardict, key, NULL); \
+		ASSERT (value == NULL, test_name, msg); \
+	}
+
+static void
+test_setting_to_dbus_all (void)
+{
+	NMSettingWirelessSecurity *s_wsec;
+	GVariant *dict;
+
+	s_wsec = make_test_wsec_setting ("setting-to-dbus-all");
+
+	dict = _nm_setting_to_dbus (NM_SETTING (s_wsec), NULL, NM_CONNECTION_SERIALIZE_ALL);
+
+	/* Make sure all keys are there */
+	ASSERT_CONTAINS (dict, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
+	        "setting-to-dbus-all", "unexpectedly missing " NM_SETTING_WIRELESS_SECURITY_KEY_MGMT);
+	ASSERT_CONTAINS (dict, NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME,
+	        "setting-to-dbus-all", "unexpectedly missing " NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME);
+	ASSERT_CONTAINS (dict, NM_SETTING_WIRELESS_SECURITY_PSK,
+	        "setting-to-dbus-all", "unexpectedly missing " NM_SETTING_WIRELESS_SECURITY_PSK);
+	ASSERT_CONTAINS (dict, NM_SETTING_WIRELESS_SECURITY_WEP_KEY0,
+	        "setting-to-dbus-all", "unexpectedly missing " NM_SETTING_WIRELESS_SECURITY_WEP_KEY0);
+
+	g_variant_unref (dict);
+	g_object_unref (s_wsec);
+}
+
+static void
+test_setting_to_dbus_no_secrets (void)
+{
+	NMSettingWirelessSecurity *s_wsec;
+	GVariant *dict;
+
+	s_wsec = make_test_wsec_setting ("setting-to-dbus-no-secrets");
+
+	dict = _nm_setting_to_dbus (NM_SETTING (s_wsec), NULL, NM_CONNECTION_SERIALIZE_NO_SECRETS);
+
+	/* Make sure non-secret keys are there */
+	ASSERT_CONTAINS (dict, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
+	                 "setting-to-dbus-no-secrets", "unexpectedly missing " NM_SETTING_WIRELESS_SECURITY_KEY_MGMT);
+	ASSERT_CONTAINS (dict, NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME,
+	                 "setting-to-dbus-no-secrets", "unexpectedly missing " NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME);
+
+	/* Make sure secrets are not there */
+	ASSERT_NOT_CONTAINS (dict, NM_SETTING_WIRELESS_SECURITY_PSK,
+	                     "setting-to-dbus-no-secrets", "unexpectedly present " NM_SETTING_WIRELESS_SECURITY_PSK);
+	ASSERT_NOT_CONTAINS (dict, NM_SETTING_WIRELESS_SECURITY_WEP_KEY0,
+	                     "setting-to-dbus-no-secrets", "unexpectedly present " NM_SETTING_WIRELESS_SECURITY_WEP_KEY0);
+
+	g_variant_unref (dict);
+	g_object_unref (s_wsec);
+}
+
+static void
+test_setting_to_dbus_only_secrets (void)
+{
+	NMSettingWirelessSecurity *s_wsec;
+	GVariant *dict;
+
+	s_wsec = make_test_wsec_setting ("setting-to-dbus-only-secrets");
+
+	dict = _nm_setting_to_dbus (NM_SETTING (s_wsec), NULL, NM_CONNECTION_SERIALIZE_ONLY_SECRETS);
+
+	/* Make sure non-secret keys are not there */
+	ASSERT_NOT_CONTAINS (dict, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
+	                     "setting-to-dbus-only-secrets", "unexpectedly present " NM_SETTING_WIRELESS_SECURITY_KEY_MGMT);
+	ASSERT_NOT_CONTAINS (dict, NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME,
+	                     "setting-to-dbus-only-secrets", "unexpectedly present " NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME);
+
+	/* Make sure secrets are there */
+	ASSERT_CONTAINS (dict, NM_SETTING_WIRELESS_SECURITY_PSK,
+	                 "setting-to-dbus-only-secrets", "unexpectedly missing " NM_SETTING_WIRELESS_SECURITY_PSK);
+	ASSERT_CONTAINS (dict, NM_SETTING_WIRELESS_SECURITY_WEP_KEY0,
+	                 "setting-to-dbus-only-secrets", "unexpectedly missing " NM_SETTING_WIRELESS_SECURITY_WEP_KEY0);
+
+	g_variant_unref (dict);
+	g_object_unref (s_wsec);
+}
+
+static void
+test_setting_to_dbus_transform (void)
+{
+	NMSetting *s_wired;
+	GVariant *dict, *val;
+	const char *test_mac_address = "11:22:33:44:55:66";
+	const guint8 *dbus_mac_address;
+	guint8 cmp_mac_address[ETH_ALEN];
+	gsize len;
+
+	s_wired = nm_setting_wired_new ();
+	g_object_set (s_wired,
+	              NM_SETTING_WIRED_MAC_ADDRESS, test_mac_address,
+	              NULL);
+
+	g_assert_cmpstr (nm_setting_wired_get_mac_address (NM_SETTING_WIRED (s_wired)), ==, test_mac_address);
+
+	dict = _nm_setting_to_dbus (s_wired, NULL, NM_CONNECTION_SERIALIZE_ALL);
+	g_assert (dict != NULL);
+
+	val = g_variant_lookup_value (dict, NM_SETTING_WIRED_MAC_ADDRESS, G_VARIANT_TYPE_BYTESTRING);
+	g_assert (val != NULL);
+
+	dbus_mac_address = g_variant_get_fixed_array (val, &len, 1);
+	g_assert_cmpint (len, ==, ETH_ALEN);
+
+	nm_utils_hwaddr_aton (test_mac_address, cmp_mac_address, ETH_ALEN);
+	g_assert (memcmp (dbus_mac_address, cmp_mac_address, ETH_ALEN) == 0);
+
+	g_variant_unref (val);
+	g_variant_unref (dict);
+	g_object_unref (s_wired);
+}
+
+static void
+test_setting_to_dbus_enum (void)
+{
+	NMSetting *s_ip6, *s_wsec, *s_serial;
+	GVariant *dict, *val;
+
+	/* enum */
+	s_ip6 = nm_setting_ip6_config_new ();
+	g_object_set (s_ip6,
+	              NM_SETTING_IP6_CONFIG_IP6_PRIVACY, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR,
+	              NULL);
+
+	dict = _nm_setting_to_dbus (s_ip6, NULL, NM_CONNECTION_SERIALIZE_ALL);
+	g_assert (dict != NULL);
+
+	val = g_variant_lookup_value (dict, NM_SETTING_IP6_CONFIG_IP6_PRIVACY, G_VARIANT_TYPE_INT32);
+	g_assert (val != NULL);
+	g_assert_cmpint (g_variant_get_int32 (val), ==, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR);
+	g_variant_unref (val);
+
+	g_variant_unref (dict);
+	g_object_unref (s_ip6);
+
+	/* flags (and a transformed enum) */
+	s_wsec = nm_setting_wireless_security_new ();
+	g_object_set (s_wsec,
+	              NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_KEY,
+	              NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS, (NM_SETTING_SECRET_FLAG_AGENT_OWNED |
+	                                                           NM_SETTING_SECRET_FLAG_NOT_SAVED),
+	              NULL);
+
+	dict = _nm_setting_to_dbus (s_wsec, NULL, NM_CONNECTION_SERIALIZE_ALL);
+	g_assert (dict != NULL);
+
+	val = g_variant_lookup_value (dict, NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, G_VARIANT_TYPE_UINT32);
+	g_assert (val != NULL);
+	g_assert_cmpint (g_variant_get_uint32 (val), ==, NM_WEP_KEY_TYPE_KEY);
+	g_variant_unref (val);
+
+	val = g_variant_lookup_value (dict, NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS, G_VARIANT_TYPE_UINT32);
+	g_assert (val != NULL);
+	g_assert_cmpint (g_variant_get_uint32 (val), ==, (NM_SETTING_SECRET_FLAG_AGENT_OWNED |
+	                                                  NM_SETTING_SECRET_FLAG_NOT_SAVED));
+	g_variant_unref (val);
+
+	g_variant_unref (dict);
+	g_object_unref (s_wsec);
+
+	/* another transformed enum */
+	s_serial = nm_setting_serial_new ();
+	g_object_set (s_serial,
+	              NM_SETTING_SERIAL_PARITY, NM_SETTING_SERIAL_PARITY_ODD,
+	              NULL);
+
+	dict = _nm_setting_to_dbus (s_serial, NULL, NM_CONNECTION_SERIALIZE_ALL);
+	g_assert (dict != NULL);
+
+	val = g_variant_lookup_value (dict, NM_SETTING_SERIAL_PARITY, G_VARIANT_TYPE_BYTE);
+	g_assert (val != NULL);
+	g_assert_cmpint (g_variant_get_byte (val), ==, 'o');
+	g_variant_unref (val);
+
+	g_variant_unref (dict);
+	g_object_unref (s_serial);
+}
+
+static void
+test_connection_to_dbus_setting_name (void)
+{
+	NMConnection *connection;
+	NMSettingWirelessSecurity *s_wsec;
+	GVariant *dict;
+
+	connection = nm_simple_connection_new ();
+	s_wsec = make_test_wsec_setting ("connection-to-dbus-setting-name");
+	nm_connection_add_setting (connection, NM_SETTING (s_wsec));
+
+	dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL);
+
+	/* Make sure the keys of the first level dict are setting names, not
+	 * the GType name of the setting objects.
+	 */
+	ASSERT_CONTAINS (dict, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
+	                 "connection-to-dbus-setting-name", "unexpectedly missing " NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
+
+	g_variant_unref (dict);
+	g_object_unref (connection);
+}
+
+static void
+test_connection_to_dbus_deprecated_props (void)
+{
+	NMConnection *connection;
+	NMSetting *s_wireless;
+	GBytes *ssid;
+	NMSettingWirelessSecurity *s_wsec;
+	GVariant *dict, *wireless_dict, *sec_val;
+
+	connection = nmtst_create_minimal_connection ("test-connection-to-dbus-deprecated-props",
+	                                              NULL,
+	                                              NM_SETTING_WIRELESS_SETTING_NAME,
+	                                              NULL);
+
+	s_wireless = nm_setting_wireless_new ();
+	ssid = g_bytes_new ("1234567", 7);
+	g_object_set (s_wireless,
+	              NM_SETTING_WIRELESS_SSID, ssid,
+	              NULL);
+	g_bytes_unref (ssid);
+	nm_connection_add_setting (connection, s_wireless);
+
+	/* Serialization should not have an 802-11-wireless.security property */
+	dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL);
+	g_assert (dict != NULL);
+
+	wireless_dict = g_variant_lookup_value (dict, NM_SETTING_WIRELESS_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
+	g_assert (wireless_dict != NULL);
+
+	sec_val = g_variant_lookup_value (wireless_dict, "security", NULL);
+	g_assert (sec_val == NULL);
+
+	g_variant_unref (wireless_dict);
+	g_variant_unref (dict);
+
+	/* Now add an NMSettingWirelessSecurity and try again */
+	s_wsec = make_test_wsec_setting ("test-connection-to-dbus-deprecated-props");
+	nm_connection_add_setting (connection, NM_SETTING (s_wsec));
+
+	dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL);
+	g_assert (dict != NULL);
+
+	wireless_dict = g_variant_lookup_value (dict, NM_SETTING_WIRELESS_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
+	g_assert (wireless_dict != NULL);
+
+	sec_val = g_variant_lookup_value (wireless_dict, "security", NULL);
+	g_assert (g_variant_is_of_type (sec_val, G_VARIANT_TYPE_STRING));
+	g_assert_cmpstr (g_variant_get_string (sec_val, NULL), ==, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
+
+	g_variant_unref (sec_val);
+	g_variant_unref (wireless_dict);
+	g_variant_unref (dict);
+	g_object_unref (connection);
+}
+
+static void
+test_setting_new_from_dbus (void)
+{
+	NMSettingWirelessSecurity *s_wsec;
+	GVariant *dict;
+
+	s_wsec = make_test_wsec_setting ("setting-new-from-dbus");
+	dict = _nm_setting_to_dbus (NM_SETTING (s_wsec), NULL, NM_CONNECTION_SERIALIZE_ALL);
+	g_object_unref (s_wsec);
+
+	s_wsec = (NMSettingWirelessSecurity *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_WIRELESS_SECURITY, dict, NULL, NULL);
+	g_variant_unref (dict);
+
+	g_assert (s_wsec);
+	g_assert_cmpstr (nm_setting_wireless_security_get_key_mgmt (s_wsec), ==, "wpa-psk");
+	g_assert_cmpstr (nm_setting_wireless_security_get_leap_username (s_wsec), ==, "foobarbaz");
+	g_assert_cmpstr (nm_setting_wireless_security_get_psk (s_wsec), ==, "random psk");
+	g_object_unref (s_wsec);
+}
+
+static void
+test_setting_new_from_dbus_transform (void)
+{
+	NMSetting *s_wired;
+	GVariant *dict;
+	GVariantBuilder builder;
+	const char *test_mac_address = "11:22:33:44:55:66";
+	guint8 dbus_mac_address[ETH_ALEN];
+	GError *error = NULL;
+
+	nm_utils_hwaddr_aton (test_mac_address, dbus_mac_address, ETH_ALEN);
+
+	g_variant_builder_init (&builder, NM_VARIANT_TYPE_SETTING);
+	g_variant_builder_add (&builder, "{sv}",
+	                       NM_SETTING_WIRED_MAC_ADDRESS,
+	                       g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
+	                                                  dbus_mac_address, ETH_ALEN, 1));
+	dict = g_variant_builder_end (&builder);
+
+	s_wired = _nm_setting_new_from_dbus (NM_TYPE_SETTING_WIRED, dict, NULL, &error);
+	g_assert_no_error (error);
+
+	g_assert_cmpstr (nm_setting_wired_get_mac_address (NM_SETTING_WIRED (s_wired)), ==, test_mac_address);
+
+	g_variant_unref (dict);
+	g_object_unref (s_wired);
+}
+
+static void
+test_setting_new_from_dbus_enum (void)
+{
+	NMSettingIP6Config *s_ip6;
+	NMSettingWirelessSecurity *s_wsec;
+	NMSettingSerial *s_serial;
+	GVariant *dict;
+	GVariantBuilder builder;
+	GError *error = NULL;
+
+	/* enum */
+	g_variant_builder_init (&builder, NM_VARIANT_TYPE_SETTING);
+	g_variant_builder_add (&builder, "{sv}",
+	                       NM_SETTING_IP6_CONFIG_IP6_PRIVACY,
+	                       g_variant_new_int32 (NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR));
+	dict = g_variant_builder_end (&builder);
+
+	s_ip6 = (NMSettingIP6Config *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_IP6_CONFIG, dict, NULL, &error);
+	g_assert_no_error (error);
+
+	g_assert_cmpint (nm_setting_ip6_config_get_ip6_privacy (s_ip6), ==, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR);
+
+	g_variant_unref (dict);
+	g_object_unref (s_ip6);
+
+	/* flags (and a transformed enum) */
+	g_variant_builder_init (&builder, NM_VARIANT_TYPE_SETTING);
+	g_variant_builder_add (&builder, "{sv}",
+	                       NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE,
+	                       g_variant_new_uint32 (NM_WEP_KEY_TYPE_KEY));
+	g_variant_builder_add (&builder, "{sv}",
+	                       NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS,
+	                       g_variant_new_uint32 (NM_SETTING_SECRET_FLAG_AGENT_OWNED |
+	                                             NM_SETTING_SECRET_FLAG_NOT_SAVED));
+	dict = g_variant_builder_end (&builder);
+
+	s_wsec = (NMSettingWirelessSecurity *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_WIRELESS_SECURITY, dict, NULL, &error);
+	g_assert_no_error (error);
+
+	g_assert_cmpint (nm_setting_wireless_security_get_wep_key_type (s_wsec), ==, NM_WEP_KEY_TYPE_KEY);
+	g_assert_cmpint (nm_setting_wireless_security_get_wep_key_flags (s_wsec), ==, (NM_SETTING_SECRET_FLAG_AGENT_OWNED |
+	                                                                               NM_SETTING_SECRET_FLAG_NOT_SAVED));
+
+	g_variant_unref (dict);
+	g_object_unref (s_wsec);
+
+	/* another transformed enum */
+	g_variant_builder_init (&builder, NM_VARIANT_TYPE_SETTING);
+	g_variant_builder_add (&builder, "{sv}",
+	                       NM_SETTING_SERIAL_PARITY,
+	                       g_variant_new_byte ('E'));
+	dict = g_variant_builder_end (&builder);
+
+	s_serial = (NMSettingSerial *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_SERIAL, dict, NULL, &error);
+	g_assert_no_error (error);
+
+	g_assert_cmpint (nm_setting_serial_get_parity (s_serial), ==, NM_SETTING_SERIAL_PARITY_EVEN);
+
+	g_variant_unref (dict);
+	g_object_unref (s_serial);
+}
+
+static NMConnection *
+new_test_connection (void)
+{
+	NMConnection *connection;
+	NMSetting *setting;
+	char *uuid;
+	guint64 timestamp = time (NULL);
+
+	connection = nm_simple_connection_new ();
+
+	setting = nm_setting_connection_new ();
+	uuid = nm_utils_uuid_generate ();
+	g_object_set (G_OBJECT (setting),
+	              NM_SETTING_CONNECTION_ID, "foobar",
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
+	              NM_SETTING_CONNECTION_TIMESTAMP, timestamp,
+	              NULL);
+	g_free (uuid);
+	nm_connection_add_setting (connection, setting);
+
+	setting = nm_setting_wired_new ();
+	g_object_set (G_OBJECT (setting),
+	              NM_SETTING_WIRED_MTU, 1592,
+	              NULL);
+	nm_connection_add_setting (connection, setting);
+
+	setting = nm_setting_ip4_config_new ();
+	g_object_set (G_OBJECT (setting),
+	              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO,
+	              NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, "eyeofthetiger",
+	              NULL);
+	nm_connection_add_setting (connection, setting);
+
+	return connection;
+}
+
+static GVariant *
+new_connection_dict (char **out_uuid,
+                     const char **out_expected_id,
+                     const char **out_expected_ip6_method)
+{
+	GVariantBuilder conn_builder, setting_builder;
+
+	g_variant_builder_init (&conn_builder, NM_VARIANT_TYPE_CONNECTION);
+
+	*out_uuid = nm_utils_uuid_generate ();
+	*out_expected_id = "My happy connection";
+	*out_expected_ip6_method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL;
+
+	/* Connection setting */
+	g_variant_builder_init (&setting_builder, NM_VARIANT_TYPE_SETTING);
+	g_variant_builder_add (&setting_builder, "{sv}",
+	                       NM_SETTING_NAME,
+	                       g_variant_new_string (NM_SETTING_CONNECTION_SETTING_NAME));
+	g_variant_builder_add (&setting_builder, "{sv}",
+	                       NM_SETTING_CONNECTION_ID,
+	                       g_variant_new_string (*out_expected_id));
+	g_variant_builder_add (&setting_builder, "{sv}",
+	                       NM_SETTING_CONNECTION_UUID,
+	                       g_variant_new_string (*out_uuid));
+	g_variant_builder_add (&setting_builder, "{sv}",
+	                       NM_SETTING_CONNECTION_TYPE,
+	                       g_variant_new_string (NM_SETTING_WIRED_SETTING_NAME));
+
+	g_variant_builder_add (&conn_builder, "{sa{sv}}",
+	                       NM_SETTING_CONNECTION_SETTING_NAME,
+	                       &setting_builder);
+
+	/* Wired setting */
+	g_variant_builder_init (&setting_builder, NM_VARIANT_TYPE_SETTING);
+	g_variant_builder_add (&conn_builder, "{sa{sv}}",
+	                       NM_SETTING_WIRED_SETTING_NAME,
+	                       &setting_builder);
+
+	/* IP6 */
+	g_variant_builder_init (&setting_builder, NM_VARIANT_TYPE_SETTING);
+	g_variant_builder_add (&setting_builder, "{sv}",
+	                       NM_SETTING_IP_CONFIG_METHOD,
+	                       g_variant_new_string (*out_expected_ip6_method));
+	g_variant_builder_add (&conn_builder, "{sa{sv}}",
+	                       NM_SETTING_IP6_CONFIG_SETTING_NAME,
+	                       &setting_builder);
+
+	return g_variant_builder_end (&conn_builder);
+}
+
+static void
+test_connection_replace_settings (void)
+{
+	NMConnection *connection;
+	GVariant *new_settings;
+	GError *error = NULL;
+	gboolean success;
+	NMSettingConnection *s_con;
+	NMSettingIPConfig *s_ip6;
+	char *uuid = NULL;
+	const char *expected_id = NULL, *expected_method = NULL;
+
+	connection = new_test_connection ();
+
+	new_settings = new_connection_dict (&uuid, &expected_id, &expected_method);
+	g_assert (new_settings);
+
+	/* Replace settings and test */
+	success = nm_connection_replace_settings (connection, new_settings, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+	g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, expected_id);
+	g_assert_cmpstr (nm_setting_connection_get_uuid (s_con), ==, uuid);
+
+	g_assert (nm_connection_get_setting_wired (connection));
+	g_assert (!nm_connection_get_setting_ip4_config (connection));
+
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
+	g_assert (s_ip6);
+	g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, expected_method);
+
+	g_free (uuid);
+	g_variant_unref (new_settings);
+	g_object_unref (connection);
+}
+
+static void
+test_connection_replace_settings_from_connection (void)
+{
+	NMConnection *connection, *replacement;
+	NMSettingConnection *s_con;
+	NMSetting *setting;
+	GBytes *ssid;
+	char *uuid = NULL;
+	const char *expected_id = "Awesome connection";
+
+	connection = new_test_connection ();
+	g_assert (connection);
+
+	replacement = nm_simple_connection_new ();
+	g_assert (replacement);
+
+	/* New connection setting */
+	setting = nm_setting_connection_new ();
+	g_assert (setting);
+
+	uuid = nm_utils_uuid_generate ();
+	g_object_set (setting,
+	              NM_SETTING_CONNECTION_ID, expected_id,
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME,
+	              NULL);
+	nm_connection_add_setting (replacement, setting);
+
+	/* New wifi setting */
+	setting = nm_setting_wireless_new ();
+	g_assert (setting);
+
+	ssid = g_bytes_new ("1234567", 7);
+	g_object_set (setting,
+	              NM_SETTING_WIRELESS_SSID, ssid,
+	              NM_SETTING_WIRELESS_MODE, "infrastructure",
+	              NULL);
+	g_bytes_unref (ssid);
+	nm_connection_add_setting (replacement, setting);
+
+	/* Replace settings and test */
+	nm_connection_replace_settings_from_connection (connection, replacement);
+
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+	g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, expected_id);
+	g_assert_cmpstr (nm_setting_connection_get_uuid (s_con), ==, uuid);
+
+	g_assert (!nm_connection_get_setting_wired (connection));
+	g_assert (!nm_connection_get_setting_ip6_config (connection));
+	g_assert (nm_connection_get_setting_wireless (connection));
+
+	g_free (uuid);
+	g_object_unref (replacement);
+	g_object_unref (connection);
+}
+
+static void
+test_connection_replace_settings_bad (void)
+{
+	NMConnection *connection, *new_connection;
+	GVariant *new_settings;
+	GVariantBuilder builder, setting_builder;
+	GError *error = NULL;
+	gboolean success;
+	NMSettingConnection *s_con;
+
+	new_connection = new_test_connection ();
+	g_assert (nm_connection_verify (new_connection, NULL));
+	s_con = nm_connection_get_setting_connection (new_connection);
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_UUID, NULL,
+	              NM_SETTING_CONNECTION_ID, "bad-connection",
+	              NULL);
+	g_assert (!nm_connection_verify (new_connection, NULL));
+
+	/* nm_connection_replace_settings_from_connection() should succeed */
+	connection = new_test_connection ();
+	nm_connection_replace_settings_from_connection (connection, new_connection);
+	g_assert_cmpstr (nm_connection_get_id (connection), ==, "bad-connection");
+	g_assert (!nm_connection_verify (connection, NULL));
+	g_object_unref (connection);
+
+	/* nm_connection_replace_settings() should succeed */
+	new_settings = nm_connection_to_dbus (new_connection, NM_CONNECTION_SERIALIZE_ALL);
+	g_assert (new_settings != NULL);
+
+	connection = new_test_connection ();
+	success = nm_connection_replace_settings (connection, new_settings, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	g_assert_cmpstr (nm_connection_get_id (connection), ==, "bad-connection");
+	g_assert (!nm_connection_verify (connection, NULL));
+	g_object_unref (connection);
+	g_variant_unref (new_settings);
+
+	/* But given an invalid dict, it should fail */
+	g_variant_builder_init (&builder, NM_VARIANT_TYPE_CONNECTION);
+	g_variant_builder_init (&setting_builder, NM_VARIANT_TYPE_SETTING);
+	g_variant_builder_add (&builder, "{sa{sv}}",
+	                       "ip-over-avian-carrier",
+	                       &setting_builder);
+	new_settings = g_variant_builder_end (&builder);
+
+	connection = new_test_connection ();
+	success = nm_connection_replace_settings (connection, new_settings, &error);
+	g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING);
+	g_assert (!success);
+
+	g_assert (nm_connection_verify (connection, NULL));
+	g_object_unref (connection);
+
+	g_variant_unref (new_settings);
+	g_object_unref (new_connection);
+}
+
+static void
+test_connection_new_from_dbus (void)
+{
+	NMConnection *connection;
+	GVariant *new_settings;
+	GError *error = NULL;
+	NMSettingConnection *s_con;
+	NMSettingIPConfig *s_ip6;
+	char *uuid = NULL;
+	const char *expected_id = NULL, *expected_method = NULL;
+
+	new_settings = new_connection_dict (&uuid, &expected_id, &expected_method);
+	g_assert (new_settings);
+
+	/* Replace settings and test */
+	connection = nm_simple_connection_new_from_dbus (new_settings, &error);
+	g_assert_no_error (error);
+	g_assert (connection);
+
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+	g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, expected_id);
+	g_assert_cmpstr (nm_setting_connection_get_uuid (s_con), ==, uuid);
+
+	g_assert (nm_connection_get_setting_wired (connection));
+	g_assert (nm_connection_get_setting_ip4_config (connection));
+
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
+	g_assert (s_ip6);
+	g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, expected_method);
+
+	g_free (uuid);
+	g_variant_unref (new_settings);
+	g_object_unref (connection);
+}
+
+static void
+check_permission (NMSettingConnection *s_con,
+                  guint32 idx,
+                  const char *expected_uname,
+                  const char *tag)
+{
+	gboolean success;
+	const char *ptype = NULL, *pitem = NULL, *detail = NULL;
+
+	success = nm_setting_connection_get_permission (s_con, 0, &ptype, &pitem, &detail);
+	ASSERT (success == TRUE, tag, "unexpected failure getting added permission");
+
+	/* Permission type */
+	ASSERT (ptype != NULL, tag, "unexpected failure getting permission type");
+	ASSERT (strcmp (ptype, "user") == 0, tag, "retrieved unexpected permission type");
+
+	/* Permission item */
+	ASSERT (pitem != NULL, tag, "unexpected failure getting permission item");
+	ASSERT (strcmp (pitem, expected_uname) == 0, tag, "retrieved unexpected permission item");
+
+	ASSERT (detail == NULL, tag, "unexpected success getting permission detail");
+}
+
+#define TEST_UNAME "asdfasfasdf"
+
+static void
+test_setting_connection_permissions_helpers (void)
+{
+	NMSettingConnection *s_con;
+	gboolean success;
+	char buf[9] = { 0x61, 0x62, 0x63, 0xff, 0xfe, 0xfd, 0x23, 0x01, 0x00 };
+	char **perms;
+	const char *expected_perm = "user:" TEST_UNAME ":";
+
+	s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
+
+	/* Ensure a bad [type] is rejected */
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*strcmp (ptype, \"user\") == 0*");
+	success = nm_setting_connection_add_permission (s_con, "foobar", "blah", NULL);
+	g_test_assert_expected_messages ();
+	ASSERT (success == FALSE,
+	        "setting-connection-permissions-helpers", "unexpected success adding bad permission type #1");
+
+	/* Ensure a bad [type] is rejected */
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*ptype*");
+	success = nm_setting_connection_add_permission (s_con, NULL, "blah", NULL);
+	g_test_assert_expected_messages ();
+	ASSERT (success == FALSE,
+	        "setting-connection-permissions-helpers", "unexpected success adding bad permission type #2");
+
+	/* Ensure a bad [item] is rejected */
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*uname*");
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*p != NULL*");
+	success = nm_setting_connection_add_permission (s_con, "user", NULL, NULL);
+	g_test_assert_expected_messages ();
+	ASSERT (success == FALSE,
+	        "setting-connection-permissions-helpers", "unexpected success adding bad permission item #1");
+
+	/* Ensure a bad [item] is rejected */
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*uname[0] != '\\0'*");
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*p != NULL*");
+	success = nm_setting_connection_add_permission (s_con, "user", "", NULL);
+	g_test_assert_expected_messages ();
+	ASSERT (success == FALSE,
+	        "setting-connection-permissions-helpers", "unexpected success adding bad permission item #2");
+
+	/* Ensure an [item] with ':' is rejected */
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*strchr (uname, ':')*");
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*p != NULL*");
+	success = nm_setting_connection_add_permission (s_con, "user", "ad:asdf", NULL);
+	g_test_assert_expected_messages ();
+	ASSERT (success == FALSE,
+	        "setting-connection-permissions-helpers", "unexpected success adding bad permission item #3");
+
+	/* Ensure a non-UTF-8 [item] is rejected */
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*g_utf8_validate (uname, -1, NULL)*");
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*p != NULL*");
+	success = nm_setting_connection_add_permission (s_con, "user", buf, NULL);
+	g_test_assert_expected_messages ();
+	ASSERT (success == FALSE,
+	        "setting-connection-permissions-helpers", "unexpected success adding bad permission item #4");
+
+	/* Ensure a non-NULL [detail] is rejected */
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*detail == NULL*");
+	success = nm_setting_connection_add_permission (s_con, "user", "dafasdf", "asdf");
+	g_test_assert_expected_messages ();
+	ASSERT (success == FALSE,
+	        "setting-connection-permissions-helpers", "unexpected success adding bad detail");
+
+	/* Ensure a valid call results in success */
+	success = nm_setting_connection_add_permission (s_con, "user", TEST_UNAME, NULL);
+	ASSERT (success == TRUE,
+	        "setting-connection-permissions-helpers", "unexpected failure adding valid user permisson");
+
+	ASSERT (nm_setting_connection_get_num_permissions (s_con) == 1,
+	        "setting-connection-permissions-helpers", "unexpected failure getting number of permissions");
+
+	check_permission (s_con, 0, TEST_UNAME, "setting-connection-permissions-helpers");
+
+	/* Check the actual GObject property just to be paranoid */
+	g_object_get (G_OBJECT (s_con), NM_SETTING_CONNECTION_PERMISSIONS, &perms, NULL);
+	ASSERT (perms != NULL,
+	        "setting-connection-permissions-helpers", "unexpected failure getting permissions");
+	ASSERT (g_strv_length (perms) == 1,
+	        "setting-connection-permissions-helpers", "unexpected failure getting number of permissions");
+	ASSERT (strcmp (perms[0], expected_perm) == 0,
+	        "setting-connection-permissions-helpers", "unexpected permission property data");
+	g_strfreev (perms);
+
+	/* Now remove that permission and ensure we have 0 permissions */
+	nm_setting_connection_remove_permission (s_con, 0);
+	ASSERT (nm_setting_connection_get_num_permissions (s_con) == 0,
+	        "setting-connection-permissions-helpers", "unexpected failure removing permission");
+
+	g_object_unref (s_con);
+}
+
+static void
+add_permission_property (NMSettingConnection *s_con,
+                         const char *ptype,
+                         const char *pitem,
+                         int pitem_len,
+                         const char *detail)
+{
+	GString *str;
+	char *perms[2];
+
+	str = g_string_sized_new (50);
+	if (ptype)
+		g_string_append (str, ptype);
+	g_string_append_c (str, ':');
+
+	if (pitem) {
+		if (pitem_len >= 0)
+			g_string_append_len (str, pitem, pitem_len);
+		else
+			g_string_append (str, pitem);
+	}
+
+	g_string_append_c (str, ':');
+
+	if (detail)
+		g_string_append (str, detail);
+
+	perms[0] = str->str;
+	perms[1] = NULL;
+	g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_PERMISSIONS, perms, NULL);
+
+	g_string_free (str, TRUE);
+}
+
+static void
+test_setting_connection_permissions_property (void)
+{
+	NMSettingConnection *s_con;
+	gboolean success;
+	char buf[9] = { 0x61, 0x62, 0x63, 0xff, 0xfe, 0xfd, 0x23, 0x01, 0x00 };
+
+	s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
+
+	/* Ensure a bad [type] is rejected */
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*strncmp (str, PERM_USER_PREFIX, strlen (PERM_USER_PREFIX)) == 0*");
+	add_permission_property (s_con, "foobar", "blah", -1, NULL);
+	g_test_assert_expected_messages ();
+	ASSERT (nm_setting_connection_get_num_permissions (s_con) == 0,
+	        "setting-connection-permissions-property", "unexpected success adding bad permission type #1");
+
+	/* Ensure a bad [type] is rejected */
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*strncmp (str, PERM_USER_PREFIX, strlen (PERM_USER_PREFIX)) == 0*");
+	add_permission_property (s_con, NULL, "blah", -1, NULL);
+	g_test_assert_expected_messages ();
+	ASSERT (nm_setting_connection_get_num_permissions (s_con) == 0,
+	        "setting-connection-permissions-property", "unexpected success adding bad permission type #2");
+
+	/* Ensure a bad [item] is rejected */
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*last_colon > str*");
+	add_permission_property (s_con, "user", NULL, -1, NULL);
+	g_test_assert_expected_messages ();
+	ASSERT (nm_setting_connection_get_num_permissions (s_con) == 0,
+	        "setting-connection-permissions-property", "unexpected success adding bad permission item #1");
+
+	/* Ensure a bad [item] is rejected */
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*last_colon > str*");
+	add_permission_property (s_con, "user", "", -1, NULL);
+	g_test_assert_expected_messages ();
+	ASSERT (nm_setting_connection_get_num_permissions (s_con) == 0,
+	        "setting-connection-permissions-property", "unexpected success adding bad permission item #2");
+
+	/* Ensure an [item] with ':' in the middle is rejected */
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*str[i] != ':'*");
+	add_permission_property (s_con, "user", "ad:asdf", -1, NULL);
+	g_test_assert_expected_messages ();
+	ASSERT (nm_setting_connection_get_num_permissions (s_con) == 0,
+	        "setting-connection-permissions-property", "unexpected success adding bad permission item #3");
+
+	/* Ensure an [item] with ':' at the end is rejected */
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*str[i] != ':'*");
+	add_permission_property (s_con, "user", "adasdfaf:", -1, NULL);
+	g_test_assert_expected_messages ();
+	ASSERT (nm_setting_connection_get_num_permissions (s_con) == 0,
+	        "setting-connection-permissions-property", "unexpected success adding bad permission item #4");
+
+	/* Ensure a non-UTF-8 [item] is rejected */
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*g_utf8_validate (str, -1, NULL)*");
+	add_permission_property (s_con, "user", buf, (int) sizeof (buf), NULL);
+	g_test_assert_expected_messages ();
+	ASSERT (nm_setting_connection_get_num_permissions (s_con) == 0,
+	        "setting-connection-permissions-property", "unexpected success adding bad permission item #5");
+
+	/* Ensure a non-NULL [detail] is rejected */
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*(last_colon + 1) == '\\0'*");
+	add_permission_property (s_con, "user", "dafasdf", -1, "asdf");
+	g_test_assert_expected_messages ();
+	ASSERT (nm_setting_connection_get_num_permissions (s_con) == 0,
+	        "setting-connection-permissions-property", "unexpected success adding bad detail");
+
+	/* Ensure a valid call results in success */
+	success = nm_setting_connection_add_permission (s_con, "user", TEST_UNAME, NULL);
+	ASSERT (nm_setting_connection_get_num_permissions (s_con) == 1,
+	        "setting-connection-permissions-property", "unexpected failure adding valid user permisson");
+
+	check_permission (s_con, 0, TEST_UNAME, "setting-connection-permissions-property");
+
+	/* Now remove that permission and ensure we have 0 permissions */
+	nm_setting_connection_remove_permission (s_con, 0);
+	ASSERT (nm_setting_connection_get_num_permissions (s_con) == 0,
+	        "setting-connection-permissions-property", "unexpected failure removing permission");
+
+	g_object_unref (s_con);
+}
+
+static void
+test_connection_compare_same (void)
+{
+	NMConnection *a, *b;
+
+	a = new_test_connection ();
+	b = nm_simple_connection_new_clone (a);
+	g_assert (nm_connection_compare (a, b, NM_SETTING_COMPARE_FLAG_EXACT));
+	g_object_unref (a);
+	g_object_unref (b);
+}
+
+static void
+test_connection_compare_key_only_in_a (void)
+{
+	NMConnection *a, *b;
+	NMSettingConnection *s_con;
+
+	a = new_test_connection ();
+	b = nm_simple_connection_new_clone (a);
+	s_con = (NMSettingConnection *) nm_connection_get_setting (b, NM_TYPE_SETTING_CONNECTION);
+	g_assert (s_con);
+	g_object_set (s_con, NM_SETTING_CONNECTION_TIMESTAMP, (guint64) 0, NULL);
+
+	g_assert (!nm_connection_compare (a, b, NM_SETTING_COMPARE_FLAG_EXACT));
+	g_object_unref (a);
+	g_object_unref (b);
+}
+
+static void
+test_connection_compare_setting_only_in_a (void)
+{
+	NMConnection *a, *b;
+
+	a = new_test_connection ();
+	b = nm_simple_connection_new_clone (a);
+	nm_connection_remove_setting (b, NM_TYPE_SETTING_IP4_CONFIG);
+	g_assert (!nm_connection_compare (a, b, NM_SETTING_COMPARE_FLAG_EXACT));
+	g_object_unref (a);
+	g_object_unref (b);
+}
+
+static void
+test_connection_compare_key_only_in_b (void)
+{
+	NMConnection *a, *b;
+	NMSettingConnection *s_con;
+
+	a = new_test_connection ();
+	b = nm_simple_connection_new_clone (a);
+	s_con = (NMSettingConnection *) nm_connection_get_setting (b, NM_TYPE_SETTING_CONNECTION);
+	g_assert (s_con);
+	g_object_set (s_con, NM_SETTING_CONNECTION_TIMESTAMP, (guint64) 0, NULL);
+
+	g_assert (!nm_connection_compare (a, b, NM_SETTING_COMPARE_FLAG_EXACT));
+	g_object_unref (a);
+	g_object_unref (b);
+}
+
+static void
+test_connection_compare_setting_only_in_b (void)
+{
+	NMConnection *a, *b;
+
+	a = new_test_connection ();
+	b = nm_simple_connection_new_clone (a);
+	nm_connection_remove_setting (a, NM_TYPE_SETTING_IP4_CONFIG);
+	g_assert (!nm_connection_compare (a, b, NM_SETTING_COMPARE_FLAG_EXACT));
+	g_object_unref (a);
+	g_object_unref (b);
+}
+
+typedef struct {
+	const char *key_name;
+	guint32 result;
+} DiffKey;
+
+typedef struct {
+	const char *name;
+	DiffKey keys[30];
+} DiffSetting;
+
+#define ARRAY_LEN(a)  (sizeof (a) / sizeof (a[0]))
+
+static void
+ensure_diffs (GHashTable *diffs, const DiffSetting *check, gsize n_check)
+{
+	guint i;
+
+	g_assert (g_hash_table_size (diffs) == n_check);
+
+	/* Loop through the settings */
+	for (i = 0; i < n_check; i++) {
+		GHashTable *setting_hash;
+		guint z = 0;
+
+		setting_hash = g_hash_table_lookup (diffs, check[i].name);
+		g_assert (setting_hash);
+
+		/* Get the number of keys to check */
+		while (check[i].keys[z].key_name)
+			z++;
+		g_assert (g_hash_table_size (setting_hash) == z);
+
+		/* Now compare the actual keys */
+		for (z = 0; check[i].keys[z].key_name; z++) {
+			NMSettingDiffResult result;
+
+			result = GPOINTER_TO_UINT (g_hash_table_lookup (setting_hash, check[i].keys[z].key_name));
+			g_assert (result == check[i].keys[z].result);
+		}
+	}
+}
+
+static void
+test_connection_diff_a_only (void)
+{
+	NMConnection *connection;
+	GHashTable *out_diffs = NULL;
+	gboolean same;
+	const DiffSetting settings[] = {
+		{ NM_SETTING_CONNECTION_SETTING_NAME, {
+			{ NM_SETTING_CONNECTION_ID,                   NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_CONNECTION_UUID,                 NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_CONNECTION_INTERFACE_NAME,       NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_CONNECTION_TYPE,                 NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_CONNECTION_TIMESTAMP,            NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_CONNECTION_AUTOCONNECT,          NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY, NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_CONNECTION_READ_ONLY,            NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_CONNECTION_PERMISSIONS,          NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_CONNECTION_ZONE,                 NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_CONNECTION_MASTER,               NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_CONNECTION_SLAVE_TYPE,           NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_CONNECTION_SECONDARIES,          NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT, NM_SETTING_DIFF_RESULT_IN_A },
+			{ NULL, NM_SETTING_DIFF_RESULT_UNKNOWN }
+		} },
+		{ NM_SETTING_WIRED_SETTING_NAME, {
+			{ NM_SETTING_WIRED_PORT,                  NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_WIRED_SPEED,                 NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_WIRED_DUPLEX,                NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_WIRED_AUTO_NEGOTIATE,        NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_WIRED_MAC_ADDRESS,           NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_WIRED_CLONED_MAC_ADDRESS,    NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST, NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_WIRED_MTU,                   NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_WIRED_S390_SUBCHANNELS,      NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_WIRED_S390_NETTYPE,          NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_WIRED_S390_OPTIONS,          NM_SETTING_DIFF_RESULT_IN_A },
+			{ NULL, NM_SETTING_DIFF_RESULT_UNKNOWN },
+		} },
+		{ NM_SETTING_IP4_CONFIG_SETTING_NAME, {
+			{ NM_SETTING_IP_CONFIG_METHOD,             NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_IP_CONFIG_DNS,                NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_IP_CONFIG_DNS_SEARCH,         NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_IP_CONFIG_ADDRESSES,          NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_IP_CONFIG_GATEWAY,            NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_IP_CONFIG_ROUTES,             NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_IP_CONFIG_ROUTE_METRIC,       NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS,    NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID,    NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_IP_CONFIG_DHCP_HOSTNAME,      NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_IP_CONFIG_NEVER_DEFAULT,      NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_IP_CONFIG_MAY_FAIL,           NM_SETTING_DIFF_RESULT_IN_A },
+			{ NULL, NM_SETTING_DIFF_RESULT_UNKNOWN },
+		} },
+	};
+
+	connection = new_test_connection ();
+
+	same = nm_connection_diff (connection, NULL, NM_SETTING_COMPARE_FLAG_EXACT, &out_diffs);
+	g_assert (same == FALSE);
+	g_assert (out_diffs != NULL);
+	g_assert (g_hash_table_size (out_diffs) > 0);
+
+	ensure_diffs (out_diffs, settings, ARRAY_LEN (settings));
+
+	g_hash_table_destroy (out_diffs);
+	g_object_unref (connection);
+}
+
+static void
+test_connection_diff_same (void)
+{
+	NMConnection *a, *b;
+	GHashTable *out_diffs = NULL;
+	gboolean same;
+
+	a = new_test_connection ();
+	b = nm_simple_connection_new_clone (a);
+
+	same = nm_connection_diff (a, b, NM_SETTING_COMPARE_FLAG_EXACT, &out_diffs);
+	g_assert (same == TRUE);
+	g_assert (out_diffs == NULL);
+	g_object_unref (a);
+	g_object_unref (b);
+}
+
+static void
+test_connection_diff_different (void)
+{
+	NMConnection *a, *b;
+	GHashTable *out_diffs = NULL;
+	NMSettingIPConfig *s_ip4;
+	gboolean same;
+	const DiffSetting settings[] = {
+		{ NM_SETTING_IP4_CONFIG_SETTING_NAME, {
+			{ NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_DIFF_RESULT_IN_A | NM_SETTING_DIFF_RESULT_IN_B },
+			{ NULL, NM_SETTING_DIFF_RESULT_UNKNOWN },
+		} },
+	};
+
+	a = new_test_connection ();
+	b = nm_simple_connection_new_clone (a);
+	s_ip4 = nm_connection_get_setting_ip4_config (a);
+	g_assert (s_ip4);
+	g_object_set (G_OBJECT (s_ip4),
+	              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
+	              NULL);
+
+	same = nm_connection_diff (a, b, NM_SETTING_COMPARE_FLAG_EXACT, &out_diffs);
+	g_assert (same == FALSE);
+	g_assert (out_diffs != NULL);
+	g_assert (g_hash_table_size (out_diffs) > 0);
+
+	ensure_diffs (out_diffs, settings, ARRAY_LEN (settings));
+
+	g_hash_table_destroy (out_diffs);
+	g_object_unref (a);
+	g_object_unref (b);
+}
+
+static void
+test_connection_diff_no_secrets (void)
+{
+	NMConnection *a, *b;
+	GHashTable *out_diffs = NULL;
+	NMSetting *s_pppoe;
+	gboolean same;
+	const DiffSetting settings[] = {
+		{ NM_SETTING_PPPOE_SETTING_NAME, {
+			{ NM_SETTING_PPPOE_PASSWORD, NM_SETTING_DIFF_RESULT_IN_B },
+			{ NULL, NM_SETTING_DIFF_RESULT_UNKNOWN },
+		} },
+	};
+
+	a = new_test_connection ();
+	s_pppoe = nm_setting_pppoe_new ();
+	g_object_set (G_OBJECT (s_pppoe),
+	              NM_SETTING_PPPOE_USERNAME, "thomas",
+	              NULL);
+	nm_connection_add_setting (a, s_pppoe);
+
+	b = nm_simple_connection_new_clone (a);
+
+	/* Add a secret to B */
+	s_pppoe = NM_SETTING (nm_connection_get_setting_pppoe (b));
+	g_assert (s_pppoe);
+	g_object_set (G_OBJECT (s_pppoe),
+	              NM_SETTING_PPPOE_PASSWORD, "secretpassword",
+	              NULL);
+
+	/* Make sure the diff returns no results as secrets are ignored */
+	same = nm_connection_diff (a, b, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS, &out_diffs);
+	g_assert (same == TRUE);
+	g_assert (out_diffs == NULL);
+
+	/* Now make sure the diff returns results if secrets are not ignored */
+	same = nm_connection_diff (a, b, NM_SETTING_COMPARE_FLAG_EXACT, &out_diffs);
+	g_assert (same == FALSE);
+	g_assert (out_diffs != NULL);
+	g_assert (g_hash_table_size (out_diffs) > 0);
+
+	ensure_diffs (out_diffs, settings, ARRAY_LEN (settings));
+
+	g_hash_table_destroy (out_diffs);
+	g_object_unref (a);
+	g_object_unref (b);
+}
+
+static void
+test_connection_diff_inferrable (void)
+{
+	NMConnection *a, *b;
+	GHashTable *out_diffs = NULL;
+	gboolean same;
+	NMSettingConnection *s_con;
+	NMSettingWired *s_wired;
+	NMSettingIPConfig *s_ip4;
+	char *uuid;
+	const DiffSetting settings[] = {
+		{ NM_SETTING_CONNECTION_SETTING_NAME, {
+			{ NM_SETTING_CONNECTION_INTERFACE_NAME, NM_SETTING_DIFF_RESULT_IN_A },
+			{ NULL, NM_SETTING_DIFF_RESULT_UNKNOWN },
+		} },
+	};
+
+	a = new_test_connection ();
+	b = nm_simple_connection_new_clone (a);
+
+	/* Change the UUID, wired MTU, and set ignore-auto-dns */
+	s_con = nm_connection_get_setting_connection (a);
+	g_assert (s_con);
+	uuid = nm_utils_uuid_generate ();
+	g_object_set (G_OBJECT (s_con),
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_ID, "really neat connection",
+	              NULL);
+	g_free (uuid);
+
+	s_wired = nm_connection_get_setting_wired (a);
+	g_assert (s_wired);
+	g_object_set (G_OBJECT (s_wired), NM_SETTING_WIRED_MTU, 300, NULL);
+
+	s_ip4 = nm_connection_get_setting_ip4_config (a);
+	g_assert (s_ip4);
+	g_object_set (G_OBJECT (s_ip4), NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, TRUE, NULL);
+
+	/* Make sure the diff returns no results as secrets are ignored */
+	same = nm_connection_diff (a, b, NM_SETTING_COMPARE_FLAG_INFERRABLE, &out_diffs);
+	g_assert (same == TRUE);
+	g_assert (out_diffs == NULL);
+
+	/* And change a INFERRABLE property to ensure that it shows up in the diff results */
+	g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_INTERFACE_NAME, "usb0", NULL);
+
+	/* Make sure the diff returns no results as secrets are ignored */
+	same = nm_connection_diff (a, b, NM_SETTING_COMPARE_FLAG_INFERRABLE, &out_diffs);
+	g_assert (same == FALSE);
+	g_assert (out_diffs != NULL);
+	g_assert (g_hash_table_size (out_diffs) > 0);
+
+	ensure_diffs (out_diffs, settings, ARRAY_LEN (settings));
+
+	g_hash_table_destroy (out_diffs);
+	g_object_unref (a);
+	g_object_unref (b);
+}
+
+static void
+add_generic_settings (NMConnection *connection, const char *ctype)
+{
+	NMSetting *setting;
+	char *uuid;
+
+	uuid = nm_utils_uuid_generate ();
+
+	setting = nm_setting_connection_new ();
+	g_object_set (setting,
+	              NM_SETTING_CONNECTION_ID, "asdfasdfadf",
+	              NM_SETTING_CONNECTION_TYPE, ctype,
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NULL);
+	nm_connection_add_setting (connection, setting);
+
+	g_free (uuid);
+
+	setting = nm_setting_ip4_config_new ();
+	g_object_set (setting, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
+	nm_connection_add_setting (connection, setting);
+
+	setting = nm_setting_ip6_config_new ();
+	g_object_set (setting, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL);
+	nm_connection_add_setting (connection, setting);
+}
+
+static void
+test_connection_good_base_types (void)
+{
+	NMConnection *connection;
+	NMSetting *setting;
+	gboolean success;
+	GError *error = NULL;
+	GBytes *ssid;
+	const char *bdaddr = "11:22:33:44:55:66";
+
+	/* Try a basic wired connection */
+	connection = nm_simple_connection_new ();
+	add_generic_settings (connection, NM_SETTING_WIRED_SETTING_NAME);
+	setting = nm_setting_wired_new ();
+	nm_connection_add_setting (connection, setting);
+
+	success = nm_connection_verify (connection, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+	g_object_unref (connection);
+
+	/* Try a wired PPPoE connection */
+	connection = nm_simple_connection_new ();
+	add_generic_settings (connection, NM_SETTING_PPPOE_SETTING_NAME);
+	setting = nm_setting_pppoe_new ();
+	g_object_set (setting, NM_SETTING_PPPOE_USERNAME, "bob smith", NULL);
+	nm_connection_add_setting (connection, setting);
+
+	success = nm_connection_verify (connection, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+	g_object_unref (connection);
+
+	/* Wifi connection */
+	connection = nm_simple_connection_new ();
+	add_generic_settings (connection, NM_SETTING_WIRELESS_SETTING_NAME);
+
+	setting = nm_setting_wireless_new ();
+	ssid = g_bytes_new ("1234567", 7);
+	g_object_set (setting,
+	              NM_SETTING_WIRELESS_SSID, ssid,
+	              NM_SETTING_WIRELESS_MODE, "infrastructure",
+	              NULL);
+	g_bytes_unref (ssid);
+	nm_connection_add_setting (connection, setting);
+
+	success = nm_connection_verify (connection, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+	g_object_unref (connection);
+
+	/* Bluetooth connection */
+	connection = nm_simple_connection_new ();
+	add_generic_settings (connection, NM_SETTING_BLUETOOTH_SETTING_NAME);
+
+	setting = nm_setting_bluetooth_new ();
+	g_object_set (setting,
+	              NM_SETTING_BLUETOOTH_BDADDR, bdaddr,
+	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_BLUETOOTH_TYPE_PANU,
+	              NULL);
+	nm_connection_add_setting (connection, setting);
+
+	success = nm_connection_verify (connection, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+	g_object_unref (connection);
+
+	/* WiMAX connection */
+	connection = nm_simple_connection_new ();
+	add_generic_settings (connection, NM_SETTING_WIMAX_SETTING_NAME);
+	setting = nm_setting_wimax_new ();
+	g_object_set (setting, NM_SETTING_WIMAX_NETWORK_NAME, "CLEAR", NULL);
+	nm_connection_add_setting (connection, setting);
+
+	success = nm_connection_verify (connection, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+	g_object_unref (connection);
+
+	/* GSM connection */
+	connection = nm_simple_connection_new ();
+	add_generic_settings (connection, NM_SETTING_GSM_SETTING_NAME);
+
+	setting = nm_setting_gsm_new ();
+	g_object_set (setting,
+	              NM_SETTING_GSM_NUMBER, "*99#",
+	              NM_SETTING_GSM_APN, "metered.billing.sucks",
+	              NULL);
+	nm_connection_add_setting (connection, setting);
+
+	/* CDMA connection */
+	connection = nm_simple_connection_new ();
+	add_generic_settings (connection, NM_SETTING_CDMA_SETTING_NAME);
+
+	setting = nm_setting_cdma_new ();
+	g_object_set (setting,
+	              NM_SETTING_CDMA_NUMBER, "#777",
+	              NM_SETTING_CDMA_USERNAME, "foobar@vzw.com",
+	              NULL);
+	nm_connection_add_setting (connection, setting);
+
+	success = nm_connection_verify (connection, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+	g_object_unref (connection);
+}
+
+static void
+test_connection_bad_base_types (void)
+{
+	NMConnection *connection;
+	NMSetting *setting;
+	gboolean success;
+	GError *error = NULL;
+
+	/* Test various non-base connection types to make sure they are rejected;
+	 * using a fake 'wired' connection so the rest of it verifies
+	 */
+
+	/* Connection setting */
+	connection = nm_simple_connection_new ();
+	add_generic_settings (connection, NM_SETTING_CONNECTION_SETTING_NAME);
+	setting = nm_setting_wired_new ();
+	nm_connection_add_setting (connection, setting);
+
+	success = nm_connection_verify (connection, &error);
+	g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
+	g_assert (g_str_has_prefix (error->message, "connection.type: "));
+	g_assert (success == FALSE);
+	g_object_unref (connection);
+	g_clear_error (&error);
+
+	/* PPP setting */
+	connection = nm_simple_connection_new ();
+	add_generic_settings (connection, NM_SETTING_PPP_SETTING_NAME);
+	setting = nm_setting_wired_new ();
+	nm_connection_add_setting (connection, setting);
+	setting = nm_setting_ppp_new ();
+	nm_connection_add_setting (connection, setting);
+
+	success = nm_connection_verify (connection, &error);
+	g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
+	g_assert (g_str_has_prefix (error->message, "connection.type: "));
+	g_assert (success == FALSE);
+	g_object_unref (connection);
+	g_clear_error (&error);
+
+	/* Serial setting */
+	connection = nm_simple_connection_new ();
+	add_generic_settings (connection, NM_SETTING_SERIAL_SETTING_NAME);
+	setting = nm_setting_wired_new ();
+	nm_connection_add_setting (connection, setting);
+	setting = nm_setting_serial_new ();
+	nm_connection_add_setting (connection, setting);
+
+	success = nm_connection_verify (connection, &error);
+	g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
+	g_assert (g_str_has_prefix (error->message, "connection.type: "));
+	g_assert (success == FALSE);
+	g_object_unref (connection);
+	g_clear_error (&error);
+
+	/* IP4 setting */
+	connection = nm_simple_connection_new ();
+	add_generic_settings (connection, NM_SETTING_IP4_CONFIG_SETTING_NAME);
+	setting = nm_setting_wired_new ();
+	nm_connection_add_setting (connection, setting);
+
+	success = nm_connection_verify (connection, &error);
+	g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
+	g_assert (g_str_has_prefix (error->message, "connection.type: "));
+	g_assert (success == FALSE);
+	g_object_unref (connection);
+	g_clear_error (&error);
+
+	/* IP6 setting */
+	connection = nm_simple_connection_new ();
+	add_generic_settings (connection, NM_SETTING_IP6_CONFIG_SETTING_NAME);
+	setting = nm_setting_wired_new ();
+	nm_connection_add_setting (connection, setting);
+
+	success = nm_connection_verify (connection, &error);
+	g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
+	g_assert (g_str_has_prefix (error->message, "connection.type: "));
+	g_assert (success == FALSE);
+	g_object_unref (connection);
+	g_clear_error (&error);
+}
+
+static void
+test_setting_compare_id (void)
+{
+	NMSetting *old, *new;
+	gboolean success;
+
+	old = nm_setting_connection_new ();
+	g_object_set (old,
+	              NM_SETTING_CONNECTION_ID, "really awesome cool connection",
+	              NM_SETTING_CONNECTION_UUID, "fbbd59d5-acab-4e30-8f86-258d272617e7",
+	              NM_SETTING_CONNECTION_AUTOCONNECT, FALSE,
+	              NULL);
+
+	new = nm_setting_duplicate (old);
+	g_object_set (new, NM_SETTING_CONNECTION_ID, "some different connection id", NULL);
+
+	/* First make sure they are different */
+	success = nm_setting_compare (old, new, NM_SETTING_COMPARE_FLAG_EXACT);
+	g_assert (success == FALSE);
+
+	success = nm_setting_compare (old, new, NM_SETTING_COMPARE_FLAG_IGNORE_ID);
+	g_assert (success);
+}
+
+static void
+test_setting_compare_timestamp (void)
+{
+	NMSetting *old, *new;
+	gboolean success;
+
+	old = nm_setting_connection_new ();
+	g_object_set (old,
+	              NM_SETTING_CONNECTION_ID, "ignore timestamp connection",
+	              NM_SETTING_CONNECTION_UUID, "b047a198-0e0a-4f0e-a653-eea09bb35e40",
+	              NM_SETTING_CONNECTION_AUTOCONNECT, FALSE,
+	              NM_SETTING_CONNECTION_TIMESTAMP, (guint64) 1234567890,
+	              NULL);
+
+	new = nm_setting_duplicate (old);
+	g_object_set (new, NM_SETTING_CONNECTION_TIMESTAMP, (guint64) 1416316539, NULL);
+
+	/* First make sure they are different */
+	success = nm_setting_compare (old, new, NM_SETTING_COMPARE_FLAG_EXACT);
+	g_assert (success == FALSE);
+
+	success = nm_setting_compare (old, new, NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP);
+	g_assert (success);
+}
+
+typedef struct {
+	NMSettingSecretFlags secret_flags;
+	NMSettingCompareFlags comp_flags;
+	gboolean remove_secret;
+} TestDataCompareSecrets;
+
+static TestDataCompareSecrets *
+test_data_compare_secrets_new (NMSettingSecretFlags secret_flags,
+                               NMSettingCompareFlags comp_flags,
+                               gboolean remove_secret)
+{
+	TestDataCompareSecrets *data = g_new0 (TestDataCompareSecrets, 1);
+
+	data->secret_flags = secret_flags;
+	data->comp_flags = comp_flags;
+	data->remove_secret = remove_secret;
+	return data;
+}
+
+static void
+test_setting_compare_secrets (gconstpointer test_data)
+{
+	const TestDataCompareSecrets *data = test_data;
+	NMSetting *old, *new;
+	gboolean success;
+
+	/* Make sure that a connection with transient/unsaved secrets compares
+	 * successfully to the same connection without those secrets.
+	 */
+
+	old = nm_setting_wireless_security_new ();
+	g_object_set (old,
+	              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk",
+	              NM_SETTING_WIRELESS_SECURITY_PSK, "really cool psk",
+	              NULL);
+	nm_setting_set_secret_flags (old, NM_SETTING_WIRELESS_SECURITY_PSK, data->secret_flags, NULL);
+
+	/* Clear the PSK from the duplicated setting */
+	new = nm_setting_duplicate (old);
+	if (data->remove_secret) {
+		g_object_set (new, NM_SETTING_WIRELESS_SECURITY_PSK, NULL, NULL);
+
+		success = nm_setting_compare (old, new, NM_SETTING_COMPARE_FLAG_EXACT);
+		g_assert (success == FALSE);
+	}
+
+	success = nm_setting_compare (old, new, data->comp_flags);
+	g_assert (success);
+}
+
+static void
+test_setting_compare_vpn_secrets (gconstpointer test_data)
+{
+	const TestDataCompareSecrets *data = test_data;
+	NMSetting *old, *new;
+	gboolean success;
+
+	/* Make sure that a connection with transient/unsaved secrets compares
+	 * successfully to the same connection without those secrets.
+	 */
+
+	old = nm_setting_vpn_new ();
+	nm_setting_vpn_add_secret (NM_SETTING_VPN (old), "foobarbaz", "really secret password");
+	nm_setting_vpn_add_secret (NM_SETTING_VPN (old), "asdfasdfasdf", "really adfasdfasdfasdf");
+	nm_setting_vpn_add_secret (NM_SETTING_VPN (old), "0123456778", "abcdefghijklmnpqrstuvqxyz");
+	nm_setting_vpn_add_secret (NM_SETTING_VPN (old), "borkbork", "yet another really secret password");
+	nm_setting_set_secret_flags (old, "borkbork", data->secret_flags, NULL);
+
+	/* Clear "borkbork" from the duplicated setting */
+	new = nm_setting_duplicate (old);
+	if (data->remove_secret) {
+		nm_setting_vpn_remove_secret (NM_SETTING_VPN (new), "borkbork");
+
+		/* First make sure they are different */
+		success = nm_setting_compare (old, new, NM_SETTING_COMPARE_FLAG_EXACT);
+		g_assert (success == FALSE);
+	}
+
+	success = nm_setting_compare (old, new, data->comp_flags);
+	g_assert (success);
+}
+
+static void
+test_hwaddr_aton_ether_normal (void)
+{
+	guint8 buf[100];
+	guint8 expected[ETH_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
+
+	g_assert (nm_utils_hwaddr_aton ("00:11:22:33:44:55", buf, ETH_ALEN) != NULL);
+	g_assert (memcmp (buf, expected, sizeof (expected)) == 0);
+}
+
+static void
+test_hwaddr_aton_ib_normal (void)
+{
+	guint8 buf[100];
+	const char *source = "00:11:22:33:44:55:66:77:88:99:01:12:23:34:45:56:67:78:89:90";
+	guint8 expected[INFINIBAND_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
+		0x77, 0x88, 0x99, 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89,
+		0x90 };
+
+	g_assert (nm_utils_hwaddr_aton (source, buf, INFINIBAND_ALEN) != NULL);
+	g_assert (memcmp (buf, expected, sizeof (expected)) == 0);
+}
+
+static void
+test_hwaddr_aton_no_leading_zeros (void)
+{
+	guint8 buf[100];
+	guint8 expected[ETH_ALEN] = { 0x00, 0x1A, 0x2B, 0x03, 0x44, 0x05 };
+
+	g_assert (nm_utils_hwaddr_aton ("0:1a:2B:3:44:5", buf, ETH_ALEN) != NULL);
+	g_assert (memcmp (buf, expected, sizeof (expected)) == 0);
+}
+
+static void
+test_hwaddr_aton_malformed (void)
+{
+	guint8 buf[100];
+
+	g_assert (nm_utils_hwaddr_aton ("0:1a:2B:3:a@%%", buf, ETH_ALEN) == NULL);
+}
+
+static void
+test_hwaddr_equal (void)
+{
+	const char *string = "00:1a:2b:03:44:05";
+	const char *upper_string = "00:1A:2B:03:44:05";
+	const char *bad_string = "0:1a:2b:3:44:5";
+	const guint8 binary[ETH_ALEN] = { 0x00, 0x1A, 0x2B, 0x03, 0x44, 0x05 };
+	const char *other_string = "1a:2b:03:44:05:00";
+	const guint8 other_binary[ETH_ALEN] = { 0x1A, 0x2B, 0x03, 0x44, 0x05, 0x00 };
+	const char *long_string = "00:1a:2b:03:44:05:06:07";
+	const guint8 long_binary[8] = { 0x00, 0x1A, 0x2B, 0x03, 0x44, 0x05, 0x06, 0x07 };
+	const char *null_string = "00:00:00:00:00:00";
+	const guint8 null_binary[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+	g_assert (nm_utils_hwaddr_matches (string, -1, string, -1));
+	g_assert (nm_utils_hwaddr_matches (string, -1, upper_string, -1));
+	g_assert (nm_utils_hwaddr_matches (string, -1, bad_string, -1));
+	g_assert (nm_utils_hwaddr_matches (string, -1, binary, sizeof (binary)));
+	g_assert (!nm_utils_hwaddr_matches (string, -1, other_string, -1));
+	g_assert (!nm_utils_hwaddr_matches (string, -1, other_binary, sizeof (other_binary)));
+	g_assert (!nm_utils_hwaddr_matches (string, -1, long_string, -1));
+	g_assert (!nm_utils_hwaddr_matches (string, -1, long_binary, sizeof (long_binary)));
+	g_assert (!nm_utils_hwaddr_matches (string, -1, null_string, -1));
+	g_assert (!nm_utils_hwaddr_matches (string, -1, null_binary, sizeof (null_binary)));
+	g_assert (!nm_utils_hwaddr_matches (string, -1, NULL, ETH_ALEN));
+
+	g_assert (nm_utils_hwaddr_matches (binary, sizeof (binary), string, -1));
+	g_assert (nm_utils_hwaddr_matches (binary, sizeof (binary), upper_string, -1));
+	g_assert (nm_utils_hwaddr_matches (binary, sizeof (binary), bad_string, -1));
+	g_assert (nm_utils_hwaddr_matches (binary, sizeof (binary), binary, sizeof (binary)));
+	g_assert (!nm_utils_hwaddr_matches (binary, sizeof (binary), other_string, -1));
+	g_assert (!nm_utils_hwaddr_matches (binary, sizeof (binary), other_binary, sizeof (other_binary)));
+	g_assert (!nm_utils_hwaddr_matches (binary, sizeof (binary), long_string, -1));
+	g_assert (!nm_utils_hwaddr_matches (binary, sizeof (binary), long_binary, sizeof (long_binary)));
+	g_assert (!nm_utils_hwaddr_matches (binary, sizeof (binary), null_string, -1));
+	g_assert (!nm_utils_hwaddr_matches (binary, sizeof (binary), null_binary, sizeof (null_binary)));
+	g_assert (!nm_utils_hwaddr_matches (binary, sizeof (binary), NULL, ETH_ALEN));
+
+	g_assert (!nm_utils_hwaddr_matches (null_string, -1, string, -1));
+	g_assert (!nm_utils_hwaddr_matches (null_string, -1, upper_string, -1));
+	g_assert (!nm_utils_hwaddr_matches (null_string, -1, bad_string, -1));
+	g_assert (!nm_utils_hwaddr_matches (null_string, -1, binary, sizeof (binary)));
+	g_assert (!nm_utils_hwaddr_matches (null_string, -1, other_string, -1));
+	g_assert (!nm_utils_hwaddr_matches (null_string, -1, other_binary, sizeof (other_binary)));
+	g_assert (!nm_utils_hwaddr_matches (null_string, -1, long_string, -1));
+	g_assert (!nm_utils_hwaddr_matches (null_string, -1, long_binary, sizeof (long_binary)));
+	g_assert (nm_utils_hwaddr_matches (null_string, -1, null_string, -1));
+	g_assert (nm_utils_hwaddr_matches (null_string, -1, null_binary, sizeof (null_binary)));
+	g_assert (nm_utils_hwaddr_matches (null_string, -1, NULL, ETH_ALEN));
+
+	g_assert (!nm_utils_hwaddr_matches (null_binary, sizeof (null_binary), string, -1));
+	g_assert (!nm_utils_hwaddr_matches (null_binary, sizeof (null_binary), upper_string, -1));
+	g_assert (!nm_utils_hwaddr_matches (null_binary, sizeof (null_binary), bad_string, -1));
+	g_assert (!nm_utils_hwaddr_matches (null_binary, sizeof (null_binary), binary, sizeof (binary)));
+	g_assert (!nm_utils_hwaddr_matches (null_binary, sizeof (null_binary), other_string, -1));
+	g_assert (!nm_utils_hwaddr_matches (null_binary, sizeof (null_binary), other_binary, sizeof (other_binary)));
+	g_assert (!nm_utils_hwaddr_matches (null_binary, sizeof (null_binary), long_string, -1));
+	g_assert (!nm_utils_hwaddr_matches (null_binary, sizeof (null_binary), long_binary, sizeof (long_binary)));
+	g_assert (nm_utils_hwaddr_matches (null_binary, sizeof (null_binary), null_string, -1));
+	g_assert (nm_utils_hwaddr_matches (null_binary, sizeof (null_binary), null_binary, sizeof (null_binary)));
+	g_assert (nm_utils_hwaddr_matches (null_binary, sizeof (null_binary), NULL, ETH_ALEN));
+}
+
+static void
+test_hwaddr_canonical (void)
+{
+	const char *string = "00:1A:2B:03:44:05";
+	const char *lower_string = "00:1a:2b:03:44:05";
+	const char *short_string = "0:1a:2b:3:44:5";
+	const char *hyphen_string = "00-1a-2b-03-44-05";
+	const char *invalid_string = "00:1A:2B";
+	char *canonical;
+
+	canonical = nm_utils_hwaddr_canonical (string, ETH_ALEN);
+	g_assert_cmpstr (canonical, ==, string);
+	g_free (canonical);
+
+	canonical = nm_utils_hwaddr_canonical (lower_string, ETH_ALEN);
+	g_assert_cmpstr (canonical, ==, string);
+	g_free (canonical);
+
+	canonical = nm_utils_hwaddr_canonical (short_string, ETH_ALEN);
+	g_assert_cmpstr (canonical, ==, string);
+	g_free (canonical);
+
+	canonical = nm_utils_hwaddr_canonical (hyphen_string, ETH_ALEN);
+	g_assert_cmpstr (canonical, ==, string);
+	g_free (canonical);
+
+	canonical = nm_utils_hwaddr_canonical (invalid_string, ETH_ALEN);
+	g_assert_cmpstr (canonical, ==, NULL);
+
+	canonical = nm_utils_hwaddr_canonical (invalid_string, -1);
+	g_assert_cmpstr (canonical, ==, invalid_string);
+	g_free (canonical);
+}
+
+static void
+test_connection_changed_cb (NMConnection *connection, gboolean *data)
+{
+	*data = TRUE;
+}
+
+static void
+test_ip4_prefix_to_netmask (void)
+{
+	int i;
+
+	for (i = 0; i<=32; i++) {
+		guint32 netmask = nm_utils_ip4_prefix_to_netmask (i);
+		int plen = nm_utils_ip4_netmask_to_prefix (netmask);
+
+		g_assert_cmpint (i, ==, plen);
+		{
+			guint32 msk = 0x80000000;
+			guint32 netmask2 = 0;
+			guint32 prefix = i;
+			while (prefix > 0) {
+				netmask2 |= msk;
+				msk >>= 1;
+				prefix--;
+			}
+			g_assert_cmpint (netmask, ==, (guint32) htonl (netmask2));
+		}
+	}
+}
+
+static void
+test_ip4_netmask_to_prefix (void)
+{
+	int i, j;
+
+	GRand *rand = g_rand_new ();
+
+	g_rand_set_seed (rand, 1);
+
+	for (i = 2; i<=32; i++) {
+		guint32 netmask = nm_utils_ip4_prefix_to_netmask (i);
+		guint32 netmask_lowest_bit = netmask & ~nm_utils_ip4_prefix_to_netmask (i-1);
+
+		g_assert_cmpint (i, ==, nm_utils_ip4_netmask_to_prefix (netmask));
+
+		for (j = 0; j < 2*i; j++) {
+			guint32 r = g_rand_int (rand);
+			guint32 netmask_holey;
+			guint32 prefix_holey;
+
+			netmask_holey = (netmask & r) | netmask_lowest_bit;
+
+			if (netmask_holey == netmask)
+				continue;
+
+			/* create an invalid netmask with holes and check that the function
+			 * returns the longest prefix. */
+			prefix_holey = nm_utils_ip4_netmask_to_prefix (netmask_holey);
+
+			g_assert_cmpint (i, ==, prefix_holey);
+		}
+	}
+
+	g_rand_free (rand);
+}
+
+#define ASSERT_CHANGED(statement) \
+{ \
+	changed = FALSE; \
+	statement; \
+	g_assert (changed); \
+}
+
+#define ASSERT_UNCHANGED(statement) \
+{ \
+	changed = FALSE; \
+	statement; \
+	g_assert (!changed); \
+}
+
+static void
+test_connection_changed_signal (void)
+{
+	NMConnection *connection;
+	gboolean changed = FALSE;
+
+	connection = new_test_connection ();
+	g_signal_connect (connection,
+	                  NM_CONNECTION_CHANGED,
+	                  (GCallback) test_connection_changed_cb,
+	                  &changed);
+
+	/* Add new setting */
+	ASSERT_CHANGED (nm_connection_add_setting (connection, nm_setting_vlan_new ()));
+
+	/* Remove existing setting */
+	ASSERT_CHANGED (nm_connection_remove_setting (connection, NM_TYPE_SETTING_VLAN));
+
+	/* Remove non-existing setting */
+	ASSERT_UNCHANGED (nm_connection_remove_setting (connection, NM_TYPE_SETTING_VLAN));
+
+	g_object_unref (connection);
+}
+
+static void
+test_setting_connection_changed_signal (void)
+{
+	NMConnection *connection;
+	gboolean changed = FALSE;
+	NMSettingConnection *s_con;
+	char *uuid;
+
+	connection = nm_simple_connection_new ();
+	g_signal_connect (connection,
+	                  NM_CONNECTION_CHANGED,
+	                  (GCallback) test_connection_changed_cb,
+	                  &changed);
+
+	s_con = (NMSettingConnection *) nm_setting_connection_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+	ASSERT_CHANGED (g_object_set (s_con, NM_SETTING_CONNECTION_ID, "adfadfasdfaf", NULL));
+
+	ASSERT_CHANGED (nm_setting_connection_add_permission (s_con, "user", "billsmith", NULL));
+	ASSERT_CHANGED (nm_setting_connection_remove_permission (s_con, 0));
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*iter != NULL*");
+	ASSERT_UNCHANGED (nm_setting_connection_remove_permission (s_con, 1));
+	g_test_assert_expected_messages ();
+
+	uuid = nm_utils_uuid_generate ();
+	ASSERT_CHANGED (nm_setting_connection_add_secondary (s_con, uuid));
+	ASSERT_CHANGED (nm_setting_connection_remove_secondary (s_con, 0));
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*elt != NULL*");
+	ASSERT_UNCHANGED (nm_setting_connection_remove_secondary (s_con, 1));
+	g_test_assert_expected_messages ();
+
+	g_object_unref (connection);
+}
+
+static void
+test_setting_bond_changed_signal (void)
+{
+	NMConnection *connection;
+	gboolean changed = FALSE;
+	NMSettingBond *s_bond;
+
+	connection = nm_simple_connection_new ();
+	g_signal_connect (connection,
+	                  NM_CONNECTION_CHANGED,
+	                  (GCallback) test_connection_changed_cb,
+	                  &changed);
+
+	s_bond = (NMSettingBond *) nm_setting_bond_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_bond));
+
+	ASSERT_CHANGED (nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY, "10"));
+	ASSERT_CHANGED (nm_setting_bond_remove_option (s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY));
+	ASSERT_UNCHANGED (nm_setting_bond_remove_option (s_bond, NM_SETTING_BOND_OPTION_UPDELAY));
+
+	g_object_unref (connection);
+}
+
+static void
+test_setting_ip4_changed_signal (void)
+{
+	NMConnection *connection;
+	gboolean changed = FALSE;
+	NMSettingIPConfig *s_ip4;
+	NMIPAddress *addr;
+	NMIPRoute *route;
+	GError *error = NULL;
+
+	connection = nm_simple_connection_new ();
+	g_signal_connect (connection,
+	                  NM_CONNECTION_CHANGED,
+	                  (GCallback) test_connection_changed_cb,
+	                  &changed);
+
+	s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+
+	ASSERT_CHANGED (nm_setting_ip_config_add_dns (s_ip4, "11.22.0.0"));
+	ASSERT_CHANGED (nm_setting_ip_config_remove_dns (s_ip4, 0));
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*i < priv->dns->len*");
+	ASSERT_UNCHANGED (nm_setting_ip_config_remove_dns (s_ip4, 1));
+	g_test_assert_expected_messages ();
+
+	nm_setting_ip_config_add_dns (s_ip4, "33.44.0.0");
+	ASSERT_CHANGED (nm_setting_ip_config_clear_dns (s_ip4));
+
+	ASSERT_CHANGED (nm_setting_ip_config_add_dns_search (s_ip4, "foobar.com"));
+	ASSERT_CHANGED (nm_setting_ip_config_remove_dns_search (s_ip4, 0));
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*i < priv->dns_search->len*");
+	ASSERT_UNCHANGED (nm_setting_ip_config_remove_dns_search (s_ip4, 1));
+	g_test_assert_expected_messages ();
+
+	ASSERT_CHANGED (nm_setting_ip_config_add_dns_search (s_ip4, "foobar.com"));
+	ASSERT_CHANGED (nm_setting_ip_config_clear_dns_searches (s_ip4));
+
+	addr = nm_ip_address_new (AF_INET, "22.33.0.0", 24, &error);
+	g_assert_no_error (error);
+	ASSERT_CHANGED (nm_setting_ip_config_add_address (s_ip4, addr));
+	ASSERT_CHANGED (nm_setting_ip_config_remove_address (s_ip4, 0));
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*i < priv->addresses->len*");
+	ASSERT_UNCHANGED (nm_setting_ip_config_remove_address (s_ip4, 1));
+	g_test_assert_expected_messages ();
+
+	nm_setting_ip_config_add_address (s_ip4, addr);
+	ASSERT_CHANGED (nm_setting_ip_config_clear_addresses (s_ip4));
+
+	route = nm_ip_route_new (AF_INET, "22.33.0.0", 24, NULL, 0, &error);
+	g_assert_no_error (error);
+
+	ASSERT_CHANGED (nm_setting_ip_config_add_route (s_ip4, route));
+	ASSERT_CHANGED (nm_setting_ip_config_remove_route (s_ip4, 0));
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*i < priv->routes->len*");
+	ASSERT_UNCHANGED (nm_setting_ip_config_remove_route (s_ip4, 1));
+	g_test_assert_expected_messages ();
+
+	nm_setting_ip_config_add_route (s_ip4, route);
+	ASSERT_CHANGED (nm_setting_ip_config_clear_routes (s_ip4));
+
+	nm_ip_address_unref (addr);
+	nm_ip_route_unref (route);
+	g_object_unref (connection);
+}
+
+static void
+test_setting_ip6_changed_signal (void)
+{
+	NMConnection *connection;
+	gboolean changed = FALSE;
+	NMSettingIPConfig *s_ip6;
+	NMIPAddress *addr;
+	NMIPRoute *route;
+	GError *error = NULL;
+
+	connection = nm_simple_connection_new ();
+	g_signal_connect (connection,
+	                  NM_CONNECTION_CHANGED,
+	                  (GCallback) test_connection_changed_cb,
+	                  &changed);
+
+	s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_ip6));
+
+	ASSERT_CHANGED (nm_setting_ip_config_add_dns (s_ip6, "1:2:3::4:5:6"));
+	ASSERT_CHANGED (nm_setting_ip_config_remove_dns (s_ip6, 0));
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*i < priv->dns->len*");
+	ASSERT_UNCHANGED (nm_setting_ip_config_remove_dns (s_ip6, 1));
+	g_test_assert_expected_messages ();
+
+	nm_setting_ip_config_add_dns (s_ip6, "1:2:3::4:5:6");
+	ASSERT_CHANGED (nm_setting_ip_config_clear_dns (s_ip6));
+
+	ASSERT_CHANGED (nm_setting_ip_config_add_dns_search (s_ip6, "foobar.com"));
+	ASSERT_CHANGED (nm_setting_ip_config_remove_dns_search (s_ip6, 0));
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*i < priv->dns_search->len*");
+	ASSERT_UNCHANGED (nm_setting_ip_config_remove_dns_search (s_ip6, 1));
+	g_test_assert_expected_messages ();
+
+	nm_setting_ip_config_add_dns_search (s_ip6, "foobar.com");
+	ASSERT_CHANGED (nm_setting_ip_config_clear_dns_searches (s_ip6));
+
+	addr = nm_ip_address_new (AF_INET6, "1:2:3::4:5:6", 64, &error);
+	g_assert_no_error (error);
+
+	ASSERT_CHANGED (nm_setting_ip_config_add_address (s_ip6, addr));
+	ASSERT_CHANGED (nm_setting_ip_config_remove_address (s_ip6, 0));
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*i < priv->addresses->len*");
+	ASSERT_UNCHANGED (nm_setting_ip_config_remove_address (s_ip6, 1));
+	g_test_assert_expected_messages ();
+
+	nm_setting_ip_config_add_address (s_ip6, addr);
+	ASSERT_CHANGED (nm_setting_ip_config_clear_addresses (s_ip6));
+
+	route = nm_ip_route_new (AF_INET6, "1:2:3::4:5:6", 128, NULL, 0, &error);
+	g_assert_no_error (error);
+
+	ASSERT_CHANGED (nm_setting_ip_config_add_route (s_ip6, route));
+	ASSERT_CHANGED (nm_setting_ip_config_remove_route (s_ip6, 0));
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*i < priv->routes->len*");
+	ASSERT_UNCHANGED (nm_setting_ip_config_remove_route (s_ip6, 1));
+	g_test_assert_expected_messages ();
+
+	nm_setting_ip_config_add_route (s_ip6, route);
+	ASSERT_CHANGED (nm_setting_ip_config_clear_routes (s_ip6));
+
+	nm_ip_address_unref (addr);
+	nm_ip_route_unref (route);
+	g_object_unref (connection);
+}
+
+static void
+test_setting_vlan_changed_signal (void)
+{
+	NMConnection *connection;
+	gboolean changed = FALSE;
+	NMSettingVlan *s_vlan;
+
+	connection = nm_simple_connection_new ();
+	g_signal_connect (connection,
+	                  NM_CONNECTION_CHANGED,
+	                  (GCallback) test_connection_changed_cb,
+	                  &changed);
+
+	s_vlan = (NMSettingVlan *) nm_setting_vlan_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_vlan));
+
+	ASSERT_CHANGED (nm_setting_vlan_add_priority (s_vlan, NM_VLAN_INGRESS_MAP, 1, 3));
+	ASSERT_CHANGED (nm_setting_vlan_remove_priority (s_vlan, NM_VLAN_INGRESS_MAP, 0));
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*idx < g_slist_length (list)*");
+	ASSERT_UNCHANGED (nm_setting_vlan_remove_priority (s_vlan, NM_VLAN_INGRESS_MAP, 1));
+	g_test_assert_expected_messages ();
+	ASSERT_CHANGED (nm_setting_vlan_add_priority_str (s_vlan, NM_VLAN_INGRESS_MAP, "1:3"));
+	ASSERT_CHANGED (nm_setting_vlan_clear_priorities (s_vlan, NM_VLAN_INGRESS_MAP));
+
+	ASSERT_CHANGED (nm_setting_vlan_add_priority (s_vlan, NM_VLAN_EGRESS_MAP, 1, 3));
+	ASSERT_CHANGED (nm_setting_vlan_remove_priority (s_vlan, NM_VLAN_EGRESS_MAP, 0));
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*idx < g_slist_length (list)*");
+	ASSERT_UNCHANGED (nm_setting_vlan_remove_priority (s_vlan, NM_VLAN_EGRESS_MAP, 1));
+	g_test_assert_expected_messages ();
+	ASSERT_CHANGED (nm_setting_vlan_add_priority_str (s_vlan, NM_VLAN_EGRESS_MAP, "1:3"));
+	ASSERT_CHANGED (nm_setting_vlan_clear_priorities (s_vlan, NM_VLAN_EGRESS_MAP));
+
+	g_object_unref (connection);
+}
+
+static void
+test_setting_vpn_changed_signal (void)
+{
+	NMConnection *connection;
+	gboolean changed = FALSE;
+	NMSettingVpn *s_vpn;
+
+	connection = nm_simple_connection_new ();
+	g_signal_connect (connection,
+	                  NM_CONNECTION_CHANGED,
+	                  (GCallback) test_connection_changed_cb,
+	                  &changed);
+
+	s_vpn = (NMSettingVpn *) nm_setting_vpn_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_vpn));
+
+	ASSERT_CHANGED (nm_setting_vpn_add_data_item (s_vpn, "foobar", "baz"));
+	ASSERT_CHANGED (nm_setting_vpn_remove_data_item (s_vpn, "foobar"));
+	ASSERT_UNCHANGED (nm_setting_vpn_remove_data_item (s_vpn, "not added"));
+
+	ASSERT_CHANGED (nm_setting_vpn_add_secret (s_vpn, "foobar", "baz"));
+	ASSERT_CHANGED (nm_setting_vpn_remove_secret (s_vpn, "foobar"));
+	ASSERT_UNCHANGED (nm_setting_vpn_remove_secret (s_vpn, "not added"));
+
+	g_object_unref (connection);
+}
+
+static void
+test_setting_wired_changed_signal (void)
+{
+	NMConnection *connection;
+	gboolean changed = FALSE;
+	NMSettingWired *s_wired;
+
+	connection = nm_simple_connection_new ();
+	g_signal_connect (connection,
+	                  NM_CONNECTION_CHANGED,
+	                  (GCallback) test_connection_changed_cb,
+	                  &changed);
+
+	s_wired = (NMSettingWired *) nm_setting_wired_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_wired));
+
+	ASSERT_CHANGED (nm_setting_wired_add_s390_option (s_wired, "portno", "1"));
+	ASSERT_CHANGED (nm_setting_wired_remove_s390_option (s_wired, "portno"));
+	ASSERT_UNCHANGED (nm_setting_wired_remove_s390_option (s_wired, "layer2"));
+
+	g_object_unref (connection);
+}
+
+static void
+test_setting_wireless_changed_signal (void)
+{
+	NMConnection *connection;
+	gboolean changed = FALSE;
+	NMSettingWireless *s_wifi;
+
+	connection = nm_simple_connection_new ();
+	g_signal_connect (connection,
+	                  NM_CONNECTION_CHANGED,
+	                  (GCallback) test_connection_changed_cb,
+	                  &changed);
+
+	s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_wifi));
+
+	ASSERT_CHANGED (nm_setting_wireless_add_seen_bssid (s_wifi, "00:11:22:33:44:55"));
+
+	g_object_unref (connection);
+}
+
+static void
+test_setting_wireless_security_changed_signal (void)
+{
+	NMConnection *connection;
+	gboolean changed = FALSE;
+	NMSettingWirelessSecurity *s_wsec;
+
+	connection = nm_simple_connection_new ();
+	g_signal_connect (connection,
+	                  NM_CONNECTION_CHANGED,
+	                  (GCallback) test_connection_changed_cb,
+	                  &changed);
+
+	s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_wsec));
+
+	/* Protos */
+	ASSERT_CHANGED (nm_setting_wireless_security_add_proto (s_wsec, "wpa"));
+	ASSERT_CHANGED (nm_setting_wireless_security_remove_proto (s_wsec, 0));
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*elt != NULL*");
+	ASSERT_UNCHANGED (nm_setting_wireless_security_remove_proto (s_wsec, 1));
+	g_test_assert_expected_messages ();
+
+	nm_setting_wireless_security_add_proto (s_wsec, "wep");
+	ASSERT_CHANGED (nm_setting_wireless_security_clear_protos (s_wsec));
+
+	/* Pairwise ciphers */
+	ASSERT_CHANGED (nm_setting_wireless_security_add_pairwise (s_wsec, "tkip"));
+	ASSERT_CHANGED (nm_setting_wireless_security_remove_pairwise (s_wsec, 0));
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*elt != NULL*");
+	ASSERT_UNCHANGED (nm_setting_wireless_security_remove_pairwise (s_wsec, 1));
+	g_test_assert_expected_messages ();
+
+	nm_setting_wireless_security_add_pairwise (s_wsec, "tkip");
+	ASSERT_CHANGED (nm_setting_wireless_security_clear_pairwise (s_wsec));
+
+	/* Group ciphers */
+	ASSERT_CHANGED (nm_setting_wireless_security_add_group (s_wsec, "ccmp"));
+	ASSERT_CHANGED (nm_setting_wireless_security_remove_group (s_wsec, 0));
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*elt != NULL*");
+	ASSERT_UNCHANGED (nm_setting_wireless_security_remove_group (s_wsec, 1));
+	g_test_assert_expected_messages ();
+
+	nm_setting_wireless_security_add_group (s_wsec, "tkip");
+	ASSERT_CHANGED (nm_setting_wireless_security_clear_groups (s_wsec));
+
+	/* WEP key secret flags */
+	ASSERT_CHANGED (g_assert (nm_setting_set_secret_flags (NM_SETTING (s_wsec), "wep-key0", NM_SETTING_SECRET_FLAG_AGENT_OWNED, NULL)));
+	ASSERT_CHANGED (g_assert (nm_setting_set_secret_flags (NM_SETTING (s_wsec), "wep-key1", NM_SETTING_SECRET_FLAG_AGENT_OWNED, NULL)));
+	ASSERT_CHANGED (g_assert (nm_setting_set_secret_flags (NM_SETTING (s_wsec), "wep-key2", NM_SETTING_SECRET_FLAG_AGENT_OWNED, NULL)));
+	ASSERT_CHANGED (g_assert (nm_setting_set_secret_flags (NM_SETTING (s_wsec), "wep-key3", NM_SETTING_SECRET_FLAG_AGENT_OWNED, NULL)));
+
+	g_object_unref (connection);
+}
+
+static void
+test_setting_802_1x_changed_signal (void)
+{
+	NMConnection *connection;
+	gboolean changed = FALSE;
+	NMSetting8021x *s_8021x;
+
+	connection = nm_simple_connection_new ();
+	g_signal_connect (connection,
+	                  NM_CONNECTION_CHANGED,
+	                  (GCallback) test_connection_changed_cb,
+	                  &changed);
+
+	s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_8021x));
+
+	/* EAP methods */
+	ASSERT_CHANGED (nm_setting_802_1x_add_eap_method (s_8021x, "tls"));
+	ASSERT_CHANGED (nm_setting_802_1x_remove_eap_method (s_8021x, 0));
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*elt != NULL*");
+	ASSERT_UNCHANGED (nm_setting_802_1x_remove_eap_method (s_8021x, 1));
+	g_test_assert_expected_messages ();
+
+	nm_setting_802_1x_add_eap_method (s_8021x, "ttls");
+	ASSERT_CHANGED (nm_setting_802_1x_clear_eap_methods (s_8021x));
+
+	/* alternate subject matches */
+	ASSERT_CHANGED (nm_setting_802_1x_add_altsubject_match (s_8021x, "EMAIL:server@example.com"));
+	ASSERT_CHANGED (nm_setting_802_1x_remove_altsubject_match (s_8021x, 0));
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*elt != NULL*");
+	ASSERT_UNCHANGED (nm_setting_802_1x_remove_altsubject_match (s_8021x, 1));
+	g_test_assert_expected_messages ();
+
+	nm_setting_802_1x_add_altsubject_match (s_8021x, "EMAIL:server@example.com");
+	ASSERT_CHANGED (nm_setting_802_1x_clear_altsubject_matches (s_8021x));
+
+	/* phase2 alternate subject matches */
+	ASSERT_CHANGED (nm_setting_802_1x_add_phase2_altsubject_match (s_8021x, "EMAIL:server@example.com"));
+	ASSERT_CHANGED (nm_setting_802_1x_remove_phase2_altsubject_match (s_8021x, 0));
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*elt != NULL*");
+	ASSERT_UNCHANGED (nm_setting_802_1x_remove_phase2_altsubject_match (s_8021x, 1));
+	g_test_assert_expected_messages ();
+
+	nm_setting_802_1x_add_phase2_altsubject_match (s_8021x, "EMAIL:server@example.com");
+	ASSERT_CHANGED (nm_setting_802_1x_clear_phase2_altsubject_matches (s_8021x));
+
+	g_object_unref (connection);
+}
+
+static void
+test_setting_old_uuid (void)
+{
+	NMSetting *setting;
+
+	/* NetworkManager-0.9.4.0 generated 40-character UUIDs with no dashes,
+	 * like this one. Test that we maintain compatibility. */
+	const char *uuid = "f43bec2cdd60e5da381ebb1eb1fa39f3cc52660c";
+
+	setting = nm_setting_connection_new ();
+	g_object_set (G_OBJECT (setting),
+	              NM_SETTING_CONNECTION_ID, "uuidtest",
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
+	              NULL);
+
+	nmtst_assert_setting_verifies (NM_SETTING (setting));
+}
+
+/******************************************************************************/
+
+static void
+test_connection_normalize_uuid (void)
+{
+	gs_unref_object NMConnection *con = NULL;
+
+	con = nmtst_create_minimal_connection ("test1", NULL, NM_SETTING_WIRED_SETTING_NAME, NULL);
+
+	nmtst_assert_connection_verifies_and_normalizable (con);
+
+	g_object_set (nm_connection_get_setting_connection (con),
+	              NM_SETTING_CONNECTION_UUID, NULL,
+	              NULL);
+	nmtst_assert_connection_verifies_after_normalization (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_PROPERTY);
+}
+
+/******************************************************************************/
+
+/*
+ * Test normalization of interface-name
+ */
+static void
+test_connection_normalize_virtual_iface_name (void)
+{
+	NMConnection *con = NULL;
+	NMSettingConnection *s_con;
+	NMSettingVlan *s_vlan;
+	GVariant *connection_dict, *setting_dict, *var;
+	GError *error = NULL;
+	const char *IFACE_NAME = "iface";
+	const char *IFACE_VIRT = "iface-X";
+
+	con = nmtst_create_minimal_connection ("test1",
+	                                       "22001632-bbb4-4616-b277-363dce3dfb5b",
+	                                       NM_SETTING_VLAN_SETTING_NAME,
+	                                       &s_con);
+
+	nm_connection_add_setting (con,
+	    g_object_new (NM_TYPE_SETTING_IP4_CONFIG,
+	                  NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO,
+	                  NULL));
+
+	nm_connection_add_setting (con,
+	    g_object_new (NM_TYPE_SETTING_IP6_CONFIG,
+	                  NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO,
+	                  NULL));
+
+	s_vlan = nm_connection_get_setting_vlan (con);
+
+	g_object_set (G_OBJECT (s_vlan),
+	              NM_SETTING_VLAN_PARENT, "eth0",
+	              NULL);
+
+	g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_INTERFACE_NAME, IFACE_NAME, NULL);
+
+	g_assert_cmpstr (nm_connection_get_interface_name (con), ==, IFACE_NAME);
+
+	connection_dict = nm_connection_to_dbus (con, NM_CONNECTION_SERIALIZE_ALL);
+	g_object_unref (con);
+
+	/* Serialized form should include vlan.interface-name as well. */
+	setting_dict = g_variant_lookup_value (connection_dict, NM_SETTING_VLAN_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
+	g_assert (setting_dict != NULL);
+	var = g_variant_lookup_value (setting_dict, "interface-name", NULL);
+	g_assert (var != NULL);
+	g_assert (g_variant_is_of_type (var, G_VARIANT_TYPE_STRING));
+	g_assert_cmpstr (g_variant_get_string (var, NULL), ==, IFACE_NAME);
+
+	g_variant_unref (setting_dict);
+	g_variant_unref (var);
+
+	/* If vlan.interface-name is invalid, deserialization will fail. */
+	NMTST_VARIANT_EDITOR (connection_dict,
+	                      NMTST_VARIANT_CHANGE_PROPERTY (NM_SETTING_VLAN_SETTING_NAME,
+	                                                     "interface-name",
+	                                                     "s",
+	                                                     ":::this-is-not-a-valid-interface-name:::");
+	                      );
+
+	con = nm_simple_connection_new_from_dbus (connection_dict, &error);
+	g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
+	g_clear_error (&error);
+
+	/* If vlan.interface-name is valid, but doesn't match, it will be ignored. */
+	NMTST_VARIANT_EDITOR (connection_dict,
+	                      NMTST_VARIANT_CHANGE_PROPERTY (NM_SETTING_VLAN_SETTING_NAME,
+	                                                     "interface-name",
+	                                                     "s",
+	                                                     IFACE_VIRT);
+	                      );
+
+	con = nm_simple_connection_new_from_dbus (connection_dict, &error);
+	g_assert_no_error (error);
+
+	g_assert_cmpstr (nm_connection_get_interface_name (con), ==, IFACE_NAME);
+	s_con = nm_connection_get_setting_connection (con);
+	g_assert_cmpstr (nm_setting_connection_get_interface_name (s_con), ==, IFACE_NAME);
+	g_object_unref (con);
+
+	/* But removing connection.interface-name should result in vlan.connection-name
+	 * being "promoted".
+	 */
+	NMTST_VARIANT_EDITOR (connection_dict,
+	                      NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_CONNECTION_SETTING_NAME,
+	                                                   NM_SETTING_CONNECTION_INTERFACE_NAME);
+	                      );
+
+	con = nm_simple_connection_new_from_dbus (connection_dict, &error);
+	g_assert_no_error (error);
+
+	g_assert_cmpstr (nm_connection_get_interface_name (con), ==, IFACE_VIRT);
+	s_con = nm_connection_get_setting_connection (con);
+	g_assert_cmpstr (nm_setting_connection_get_interface_name (s_con), ==, IFACE_VIRT);
+	g_object_unref (con);
+
+	g_variant_unref (connection_dict);
+}
+
+static void
+_test_connection_normalize_type_normalizable_setting (const char *type,
+                                                      void (*prepare_normalizable_fcn) (NMConnection *con))
+{
+	NMSettingConnection *s_con;
+	NMSetting *s_base;
+	GType base_type;
+	gs_unref_object NMConnection *con = NULL;
+	gs_free char *id = g_strdup_printf ("%s[%s]", G_STRFUNC, type);
+
+	base_type = nm_setting_lookup_type (type);
+	g_assert (base_type != G_TYPE_INVALID);
+	g_assert (_nm_setting_type_is_base_type (base_type));
+
+	con = nmtst_create_minimal_connection (id, NULL, NULL, &s_con);
+
+	nmtst_assert_connection_unnormalizable (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_PROPERTY);
+
+	g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, type, NULL);
+
+	if (prepare_normalizable_fcn)
+		prepare_normalizable_fcn (con);
+
+	g_assert (!nm_connection_get_setting_by_name (con, type));
+	nmtst_assert_connection_verifies_after_normalization (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_SETTING);
+
+	s_base = nm_connection_get_setting_by_name (con, type);
+	g_assert (s_base);
+	g_assert (G_OBJECT_TYPE (s_base) == base_type);
+}
+
+static void
+_test_connection_normalize_type_unnormalizable_setting (const char *type)
+{
+	NMSettingConnection *s_con;
+	GType base_type;
+	gs_unref_object NMConnection *con = NULL;
+	gs_free char *id = g_strdup_printf ("%s[%s]", G_STRFUNC, type);
+
+	base_type = nm_setting_lookup_type (type);
+	g_assert (base_type != G_TYPE_INVALID);
+	g_assert (_nm_setting_type_is_base_type (base_type));
+
+	con = nmtst_create_minimal_connection (id, NULL, NULL, &s_con);
+
+	nmtst_assert_connection_unnormalizable (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_PROPERTY);
+
+	g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, type, NULL);
+
+	nmtst_assert_connection_unnormalizable (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_SETTING);
+}
+
+static void
+_test_connection_normalize_type_normalizable_type (const char *type,
+                                                   NMSetting *(*add_setting_fcn) (NMConnection *con))
+{
+	NMSettingConnection *s_con;
+	NMSetting *s_base;
+	GType base_type;
+	gs_unref_object NMConnection *con = NULL;
+	gs_free char *id = g_strdup_printf ("%s[%s]", G_STRFUNC, type);
+
+	base_type = nm_setting_lookup_type (type);
+	g_assert (base_type != G_TYPE_INVALID);
+	g_assert (_nm_setting_type_is_base_type (base_type));
+
+	con = nmtst_create_minimal_connection (id, NULL, NULL, &s_con);
+
+	nmtst_assert_connection_unnormalizable (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_PROPERTY);
+
+	if (add_setting_fcn)
+		s_base = add_setting_fcn (con);
+	else {
+		s_base = NM_SETTING (g_object_new (base_type, NULL));
+		nm_connection_add_setting (con, s_base);
+	}
+
+	g_assert (!nm_connection_get_connection_type (con));
+	g_assert (nm_connection_get_setting_by_name (con, type) == s_base);
+
+	nmtst_assert_connection_verifies_after_normalization (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_PROPERTY);
+
+	g_assert_cmpstr (nm_connection_get_connection_type (con), ==, type);
+	g_assert (nm_connection_get_setting_by_name (con, type) == s_base);
+}
+
+static NMSetting *
+_add_setting_fcn_adsl (NMConnection *con)
+{
+	NMSetting *setting;
+
+	setting = g_object_new (NM_TYPE_SETTING_ADSL,
+	                        NM_SETTING_ADSL_USERNAME, "test-user",
+	                        NM_SETTING_ADSL_PROTOCOL, NM_SETTING_ADSL_PROTOCOL_PPPOA,
+	                        NM_SETTING_ADSL_ENCAPSULATION, NM_SETTING_ADSL_ENCAPSULATION_VCMUX,
+	                        NULL);
+
+	nm_connection_add_setting (con, setting);
+	return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_bluetooth (NMConnection *con)
+{
+	NMSetting *setting;
+
+	setting = g_object_new (NM_TYPE_SETTING_BLUETOOTH,
+	                        NM_SETTING_BLUETOOTH_BDADDR, "11:22:33:44:55:66",
+	                        NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_PANU,
+	                        NULL);
+
+	nm_connection_add_setting (con, setting);
+	return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_bond (NMConnection *con)
+{
+	NMSetting *setting;
+	NMSettingConnection *s_con;
+
+	setting = g_object_new (NM_TYPE_SETTING_BOND, NULL);
+
+	nm_connection_add_setting (con, setting);
+
+	s_con = nm_connection_get_setting_connection (con);
+
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_INTERFACE_NAME, "test-bond",
+	              NULL);
+
+	return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_bridge (NMConnection *con)
+{
+	NMSetting *setting;
+	NMSettingConnection *s_con;
+
+	setting = g_object_new (NM_TYPE_SETTING_BRIDGE, NULL);
+
+	nm_connection_add_setting (con, setting);
+
+	s_con = nm_connection_get_setting_connection (con);
+
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_INTERFACE_NAME, "test-bridge",
+	              NULL);
+
+	return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_cdma (NMConnection *con)
+{
+	NMSetting *setting;
+
+	setting = g_object_new (NM_TYPE_SETTING_CDMA,
+	                        NM_SETTING_CDMA_NUMBER, "test-number",
+	                        NULL);
+
+	nm_connection_add_setting (con, setting);
+	return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_infiniband (NMConnection *con)
+{
+	NMSetting *setting;
+
+	setting = g_object_new (NM_TYPE_SETTING_INFINIBAND,
+	                        NM_SETTING_INFINIBAND_TRANSPORT_MODE, "connected",
+	                        NULL);
+
+	nm_connection_add_setting (con, setting);
+	return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_olpc_mesh (NMConnection *con)
+{
+	NMSetting *setting;
+	const char *ssid_data = "ssid-test";
+	GBytes *ssid;
+
+	ssid = g_bytes_new (ssid_data, strlen (ssid_data));
+	setting = g_object_new (NM_TYPE_SETTING_OLPC_MESH,
+	                        NM_SETTING_OLPC_MESH_SSID, ssid,
+	                        NM_SETTING_OLPC_MESH_CHANNEL, 1,
+	                        NULL);
+	g_bytes_unref (ssid);
+
+	nm_connection_add_setting (con, setting);
+	return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_team (NMConnection *con)
+{
+	NMSetting *setting;
+	NMSettingConnection *s_con;
+
+	setting = g_object_new (NM_TYPE_SETTING_TEAM, NULL);
+
+	nm_connection_add_setting (con, setting);
+
+	s_con = nm_connection_get_setting_connection (con);
+
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_INTERFACE_NAME, "test-team",
+	              NULL);
+
+	return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_vlan (NMConnection *con)
+{
+	NMSetting *setting;
+
+	setting = g_object_new (NM_TYPE_SETTING_VLAN,
+	                        NM_SETTING_VLAN_PARENT, "test-parent",
+	                        NULL);
+
+	nm_connection_add_setting (con, setting);
+	return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_vpn (NMConnection *con)
+{
+	NMSetting *setting;
+
+	setting = g_object_new (NM_TYPE_SETTING_VPN,
+	                        NM_SETTING_VPN_SERVICE_TYPE, "test-vpn-service-type",
+	                        NULL);
+
+	nm_connection_add_setting (con, setting);
+	return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_wimax (NMConnection *con)
+{
+	NMSetting *setting;
+
+	setting = g_object_new (NM_TYPE_SETTING_WIMAX,
+	                        NM_SETTING_WIMAX_NETWORK_NAME, "test-network",
+	                        NULL);
+
+	nm_connection_add_setting (con, setting);
+	return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_wireless (NMConnection *con)
+{
+	NMSetting *setting;
+	const char *ssid_data = "ssid-test";
+	GBytes *ssid;
+
+	ssid = g_bytes_new (ssid_data, strlen (ssid_data));
+	setting = g_object_new (NM_TYPE_SETTING_WIRELESS,
+	                        NM_SETTING_WIRELESS_SSID, ssid,
+	                        NULL);
+	g_bytes_unref (ssid);
+
+	nm_connection_add_setting (con, setting);
+	return setting;
+}
+
+static void
+_prepare_normalizable_fcn_vlan (NMConnection *con)
+{
+	nm_connection_add_setting (con, g_object_new (NM_TYPE_SETTING_WIRED,
+	                                              NM_SETTING_WIRED_MAC_ADDRESS, "11:22:33:44:55:66",
+	                                              NULL));
+}
+
+static void
+test_connection_normalize_type (void)
+{
+	guint i;
+	struct {
+		const char *type;
+		gboolean normalizable;
+		NMSetting *(*add_setting_fcn) (NMConnection *con);
+		void (*prepare_normalizable_fcn) (NMConnection *con);
+	} types[] = {
+		{ NM_SETTING_GENERIC_SETTING_NAME, TRUE },
+		{ NM_SETTING_GSM_SETTING_NAME, TRUE },
+		{ NM_SETTING_WIRED_SETTING_NAME, TRUE },
+		{ NM_SETTING_VLAN_SETTING_NAME, TRUE, _add_setting_fcn_vlan, _prepare_normalizable_fcn_vlan },
+
+		{ NM_SETTING_ADSL_SETTING_NAME, FALSE, _add_setting_fcn_adsl },
+		{ NM_SETTING_BLUETOOTH_SETTING_NAME, FALSE, _add_setting_fcn_bluetooth },
+		{ NM_SETTING_BOND_SETTING_NAME, FALSE, _add_setting_fcn_bond },
+		{ NM_SETTING_BRIDGE_SETTING_NAME, FALSE, _add_setting_fcn_bridge },
+		{ NM_SETTING_CDMA_SETTING_NAME, FALSE, _add_setting_fcn_cdma },
+		{ NM_SETTING_INFINIBAND_SETTING_NAME, FALSE, _add_setting_fcn_infiniband },
+		{ NM_SETTING_OLPC_MESH_SETTING_NAME, FALSE, _add_setting_fcn_olpc_mesh },
+		{ NM_SETTING_TEAM_SETTING_NAME, FALSE, _add_setting_fcn_team },
+		{ NM_SETTING_VLAN_SETTING_NAME, FALSE, _add_setting_fcn_vlan },
+		{ NM_SETTING_VPN_SETTING_NAME, FALSE, _add_setting_fcn_vpn },
+		{ NM_SETTING_WIMAX_SETTING_NAME, FALSE, _add_setting_fcn_wimax },
+		{ NM_SETTING_WIRELESS_SETTING_NAME, FALSE, _add_setting_fcn_wireless },
+		{ 0 },
+	};
+
+	for (i = 0; types[i].type; i++) {
+		const char *type = types[i].type;
+
+		if (types[i].normalizable)
+			_test_connection_normalize_type_normalizable_setting (type, types[i].prepare_normalizable_fcn);
+		else
+			_test_connection_normalize_type_unnormalizable_setting (type);
+		_test_connection_normalize_type_normalizable_type (type, types[i].add_setting_fcn);
+	}
+}
+
+static void
+test_connection_normalize_slave_type_1 (void)
+{
+	gs_unref_object NMConnection *con = NULL;
+	NMSettingConnection *s_con;
+
+	con = nmtst_create_minimal_connection ("test_connection_normalize_slave_type_1",
+	                                       "cc4cd5df-45dc-483e-b291-6b76c2338ecb",
+	                                       NM_SETTING_WIRED_SETTING_NAME, &s_con);
+
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_MASTER, "master0",
+	              NM_SETTING_CONNECTION_SLAVE_TYPE, "invalid-type",
+	              NULL);
+
+	nmtst_assert_connection_unnormalizable (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
+	g_assert (!nm_connection_get_setting_by_name (con, NM_SETTING_BRIDGE_PORT_SETTING_NAME));
+
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_SLAVE_TYPE, "bridge",
+	              NULL);
+
+	g_assert (!nm_connection_get_setting_by_name (con, NM_SETTING_BRIDGE_PORT_SETTING_NAME));
+	nmtst_assert_connection_verifies_after_normalization (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_SETTING);
+	g_assert (nm_connection_get_setting_by_name (con, NM_SETTING_BRIDGE_PORT_SETTING_NAME));
+	g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NM_SETTING_BRIDGE_SETTING_NAME);
+}
+
+static void
+test_connection_normalize_slave_type_2 (void)
+{
+	gs_unref_object NMConnection *con = NULL;
+	NMSettingConnection *s_con;
+
+	con = nmtst_create_minimal_connection ("test_connection_normalize_slave_type_2",
+	                                       "40bea008-ca72-439a-946b-e65f827656f9",
+	                                       NM_SETTING_WIRED_SETTING_NAME, &s_con);
+
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_MASTER, "master0",
+	              NM_SETTING_CONNECTION_SLAVE_TYPE, "invalid-type",
+	              NULL);
+
+	nmtst_assert_connection_unnormalizable (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
+	g_assert (!nm_connection_get_setting_by_name (con, NM_SETTING_BRIDGE_PORT_SETTING_NAME));
+
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_SLAVE_TYPE, NULL,
+	              NULL);
+	nm_connection_add_setting (con, nm_setting_bridge_port_new ());
+
+	g_assert (nm_connection_get_setting_by_name (con, NM_SETTING_BRIDGE_PORT_SETTING_NAME));
+	g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NULL);
+	nmtst_assert_connection_verifies_after_normalization (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_PROPERTY);
+	g_assert (nm_connection_get_setting_by_name (con, NM_SETTING_BRIDGE_PORT_SETTING_NAME));
+	g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NM_SETTING_BRIDGE_SETTING_NAME);
+}
+
+static void
+test_connection_normalize_infiniband_mtu (void)
+{
+	gs_unref_object NMConnection *con = NULL;
+	NMSettingInfiniband *s_infini;
+
+	con = nmtst_create_minimal_connection ("test_connection_normalize_infiniband_mtu", NULL,
+	                                       NM_SETTING_INFINIBAND_SETTING_NAME, NULL);
+
+	s_infini = nm_connection_get_setting_infiniband (con);
+	g_object_set (s_infini,
+	              NM_SETTING_INFINIBAND_TRANSPORT_MODE, "connected",
+	              NULL);
+	nmtst_assert_connection_verifies_and_normalizable (con);
+
+	g_object_set (s_infini,
+	              NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram",
+	              NM_SETTING_INFINIBAND_MTU, (guint) 2044,
+	              NULL);
+	nmtst_assert_connection_verifies_without_normalization (con);
+	g_assert_cmpint (2044, ==, nm_setting_infiniband_get_mtu (s_infini));
+
+	g_object_set (s_infini,
+	              NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram",
+	              NM_SETTING_INFINIBAND_MTU, (guint) 2045,
+	              NULL);
+	nmtst_assert_connection_verifies_after_normalization (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
+	g_assert_cmpint (2044, ==, nm_setting_infiniband_get_mtu (s_infini));
+
+	g_object_set (s_infini,
+	              NM_SETTING_INFINIBAND_TRANSPORT_MODE, "connected",
+	              NM_SETTING_INFINIBAND_MTU, (guint) 65520,
+	              NULL);
+	nmtst_assert_connection_verifies_without_normalization (con);
+	g_assert_cmpint (65520, ==, nm_setting_infiniband_get_mtu (s_infini));
+
+	g_object_set (s_infini,
+	              NM_SETTING_INFINIBAND_TRANSPORT_MODE, "connected",
+	              NM_SETTING_INFINIBAND_MTU, (guint) 65521,
+	              NULL);
+	nmtst_assert_connection_verifies_after_normalization (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
+	g_assert_cmpint (65520, ==, nm_setting_infiniband_get_mtu (s_infini));
+}
+
+static void
+test_setting_ip4_gateway (void)
+{
+	NMConnection *conn;
+	NMSettingIPConfig *s_ip4;
+	NMIPAddress *addr;
+	GVariant *conn_dict, *ip4_dict, *value;
+	GVariantIter iter;
+	GVariant *addr_var;
+	guint32 addr_vals_0[] = { htonl (0xc0a8010a), 0x00000018, htonl (0x00000000) };
+	guint32 addr_vals_1[] = { htonl (0xc0a8010b), 0x00000018, htonl (0xc0a80101) };
+	GVariantBuilder addrs_builder;
+	GError *error = NULL;
+
+	g_assert_cmpstr (nm_utils_inet4_ntop (addr_vals_0[0], NULL), ==, "192.168.1.10");
+
+	/* When serializing on the daemon side, ipv4.gateway is copied to the first
+	 * entry of ipv4.addresses
+	 */
+	conn = nmtst_create_minimal_connection ("test_setting_ip4_gateway", NULL,
+	                                        NM_SETTING_WIRED_SETTING_NAME, NULL);
+	s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
+	g_object_set (s_ip4,
+	              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
+	              NM_SETTING_IP_CONFIG_GATEWAY, "192.168.1.1",
+	              NULL);
+	nm_connection_add_setting (conn, NM_SETTING (s_ip4));
+
+	addr = nm_ip_address_new (AF_INET, "192.168.1.10", 24, &error);
+	g_assert_no_error (error);
+	nm_setting_ip_config_add_address (s_ip4, addr);
+	nm_ip_address_unref (addr);
+
+	_nm_utils_is_manager_process = TRUE;
+	conn_dict = nm_connection_to_dbus (conn, NM_CONNECTION_SERIALIZE_ALL);
+	_nm_utils_is_manager_process = FALSE;
+	g_object_unref (conn);
+
+	ip4_dict = g_variant_lookup_value (conn_dict, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
+	g_assert (ip4_dict != NULL);
+
+	value = g_variant_lookup_value (ip4_dict, NM_SETTING_IP_CONFIG_GATEWAY, G_VARIANT_TYPE_STRING);
+	g_assert (value != NULL);
+	g_assert_cmpstr (g_variant_get_string (value, NULL), ==, "192.168.1.1");
+	g_variant_unref (value);
+
+	value = g_variant_lookup_value (ip4_dict, NM_SETTING_IP_CONFIG_ADDRESSES, G_VARIANT_TYPE ("aau"));
+	g_assert (value != NULL);
+
+	g_variant_iter_init (&iter, value);
+	while (g_variant_iter_next (&iter, "@au", &addr_var)) {
+		const guint32 *addr_array;
+		gsize length;
+
+		addr_array = g_variant_get_fixed_array (addr_var, &length, sizeof (guint32));
+		g_assert_cmpint (length, ==, 3);
+		g_assert_cmpstr (nm_utils_inet4_ntop (addr_array[2], NULL), ==, "192.168.1.1");
+		g_variant_unref (addr_var);
+	}
+	g_variant_unref (value);
+
+	g_variant_unref (ip4_dict);
+
+	/* When deserializing an old-style connection, the first non-0 gateway in
+	 * ipv4.addresses is copied to :gateway.
+	 */
+	NMTST_VARIANT_EDITOR (conn_dict,
+	                      NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_IP4_CONFIG_SETTING_NAME,
+	                                                   NM_SETTING_IP_CONFIG_GATEWAY);
+	                      NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_IP4_CONFIG_SETTING_NAME,
+	                                                   "address-data");
+	                      );
+
+	conn = nm_simple_connection_new_from_dbus (conn_dict, &error);
+	g_assert_no_error (error);
+
+	s_ip4 = (NMSettingIPConfig *) nm_connection_get_setting_ip4_config (conn);
+	g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, "192.168.1.1");
+
+	g_object_unref (conn);
+
+	/* Try again with the gateway in the second address. */
+	g_variant_builder_init (&addrs_builder, G_VARIANT_TYPE ("aau"));
+	g_variant_builder_add (&addrs_builder, "@au",
+	                       g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32,
+	                                                  addr_vals_0, 3, 4));
+	g_variant_builder_add (&addrs_builder, "@au",
+	                       g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32,
+	                                                  addr_vals_1, 3, 4));
+
+	NMTST_VARIANT_EDITOR (conn_dict,
+	                      NMTST_VARIANT_CHANGE_PROPERTY (NM_SETTING_IP4_CONFIG_SETTING_NAME,
+	                                                     "addresses", "aau", &addrs_builder);
+	                      );
+
+	conn = nm_simple_connection_new_from_dbus (conn_dict, &error);
+	g_assert_no_error (error);
+	g_variant_unref (conn_dict);
+
+	s_ip4 = (NMSettingIPConfig *) nm_connection_get_setting_ip4_config (conn);
+	g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, "192.168.1.1");
+
+	g_object_unref (conn);
+}
+
+static void
+test_setting_ip6_gateway (void)
+{
+	NMConnection *conn;
+	NMSettingIPConfig *s_ip6;
+	NMIPAddress *addr;
+	GVariant *conn_dict, *ip6_dict, *value;
+	GVariantIter iter;
+	GVariant *gateway_var;
+	GVariantBuilder addrs_builder;
+	guint8 addr_bytes_0[] = { 0xab, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a };
+	guint8 addr_bytes_1[] = { 0xab, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b };
+	guint8 gateway_bytes_1[] = { 0xab, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	                             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
+	GError *error = NULL;
+
+	/* When serializing on the daemon side, ipv6.gateway is copied to the first
+	 * entry of ipv6.addresses
+	 */
+	conn = nmtst_create_minimal_connection ("test_setting_ip6_gateway", NULL,
+	                                        NM_SETTING_WIRED_SETTING_NAME, NULL);
+	s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new ();
+	g_object_set (s_ip6,
+	              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
+	              NM_SETTING_IP_CONFIG_GATEWAY, "abcd::1",
+	              NULL);
+	nm_connection_add_setting (conn, NM_SETTING (s_ip6));
+
+	addr = nm_ip_address_new (AF_INET6, "abcd::10", 64, &error);
+	g_assert_no_error (error);
+	nm_setting_ip_config_add_address (s_ip6, addr);
+	nm_ip_address_unref (addr);
+
+	_nm_utils_is_manager_process = TRUE;
+	conn_dict = nm_connection_to_dbus (conn, NM_CONNECTION_SERIALIZE_ALL);
+	_nm_utils_is_manager_process = FALSE;
+	g_object_unref (conn);
+
+	ip6_dict = g_variant_lookup_value (conn_dict, NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
+	g_assert (ip6_dict != NULL);
+
+	value = g_variant_lookup_value (ip6_dict, NM_SETTING_IP_CONFIG_GATEWAY, G_VARIANT_TYPE_STRING);
+	g_assert (value != NULL);
+	g_assert_cmpstr (g_variant_get_string (value, NULL), ==, "abcd::1");
+
+	value = g_variant_lookup_value (ip6_dict, NM_SETTING_IP_CONFIG_ADDRESSES, G_VARIANT_TYPE ("a(ayuay)"));
+	g_assert (value != NULL);
+
+	g_variant_iter_init (&iter, value);
+	while (g_variant_iter_next (&iter, "(@ayu@ay)", NULL, NULL, &gateway_var)) {
+		const guint8 *gateway_bytes;
+		gsize length;
+
+		gateway_bytes = g_variant_get_fixed_array (gateway_var, &length, 1);
+		g_assert_cmpint (length, ==, 16);
+		g_assert_cmpstr (nm_utils_inet6_ntop ((struct in6_addr *) gateway_bytes, NULL), ==, "abcd::1");
+		g_variant_unref (gateway_var);
+	}
+	g_variant_unref (value);
+
+	g_variant_unref (ip6_dict);
+
+	/* When deserializing an old-style connection, the first non-0 gateway in
+	 * ipv6.addresses is copied to :gateway.
+	 */
+	NMTST_VARIANT_EDITOR (conn_dict,
+	                      NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_IP6_CONFIG_SETTING_NAME,
+	                                                   NM_SETTING_IP_CONFIG_GATEWAY);
+	                      NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_IP6_CONFIG_SETTING_NAME,
+	                                                   "address-data");
+	                      );
+
+	conn = nm_simple_connection_new_from_dbus (conn_dict, &error);
+	g_assert_no_error (error);
+
+	s_ip6 = (NMSettingIPConfig *) nm_connection_get_setting_ip6_config (conn);
+	g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip6), ==, "abcd::1");
+
+	g_object_unref (conn);
+
+	/* Try again with the gateway in the second address. */
+	g_variant_builder_init (&addrs_builder, G_VARIANT_TYPE ("a(ayuay)"));
+	g_variant_builder_add (&addrs_builder, "(@ayu@ay)",
+	                       g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
+	                                                  addr_bytes_0, 16, 1),
+	                       64,
+	                       g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
+	                                                  &in6addr_any, 16, 1));
+	g_variant_builder_add (&addrs_builder, "(@ayu@ay)",
+	                       g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
+	                                                  addr_bytes_1, 16, 1),
+	                       64,
+	                       g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
+	                                                  gateway_bytes_1, 16, 1));
+
+	NMTST_VARIANT_EDITOR (conn_dict,
+	                      NMTST_VARIANT_CHANGE_PROPERTY (NM_SETTING_IP6_CONFIG_SETTING_NAME,
+	                                                     "addresses", "a(ayuay)", &addrs_builder);
+	                      );
+
+	conn = nm_simple_connection_new_from_dbus (conn_dict, &error);
+	g_assert_no_error (error);
+	g_variant_unref (conn_dict);
+
+	s_ip6 = (NMSettingIPConfig *) nm_connection_get_setting_ip6_config (conn);
+	g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip6), ==, "abcd::1");
+
+	g_object_unref (conn);
+}
+
+typedef struct {
+	const char *str;
+	const guint8 expected[20];
+	const guint expected_len;
+} HexItem;
+
+static void
+test_hexstr2bin (void)
+{
+	static const HexItem items[] = {
+		{ "aaBBCCddDD10496a",     { 0xaa, 0xbb, 0xcc, 0xdd, 0xdd, 0x10, 0x49, 0x6a }, 8 },
+		{ "aa:bb:cc:dd:10:49:6a", { 0xaa, 0xbb, 0xcc, 0xdd, 0x10, 0x49, 0x6a },       7 },
+		{ "0xccddeeff",           { 0xcc, 0xdd, 0xee, 0xff },                         4 },
+		{ "1:2:66:77:80",         { 0x01, 0x02, 0x66, 0x77, 0x80 },                   5 },
+		{ "e",                    { 0x0e },                                           1 },
+		{ "aabb1199:" },
+		{ ":aabb1199" },
+		{ "aabb$$dd" },
+		{ "aab:ccc:ddd" },
+		{ "aab::ccc:ddd" },
+	};
+	GBytes *b;
+	guint i;
+
+	for (i = 0; i < G_N_ELEMENTS (items); i++) {
+		b = nm_utils_hexstr2bin (items[i].str);
+		if (items[i].expected_len) {
+			g_assert (b);
+			g_assert_cmpint (g_bytes_get_size (b), ==, items[i].expected_len);
+			g_assert (memcmp (g_bytes_get_data (b, NULL), items[i].expected, g_bytes_get_size (b)) == 0);
+		} else
+			g_assert (b == NULL);
+	}
+}
+
+/******************************************************************************/
+
+#define UUID_NIL        "00000000-0000-0000-0000-000000000000"
+#define UUID_NS_DNS     "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
+
+static void
+_test_uuid (int uuid_type, const char *expected_uuid, const char *str, gssize slen, gpointer type_args)
+{
+	gs_free char *uuid_test = NULL;
+
+	uuid_test = nm_utils_uuid_generate_from_string (str, slen, uuid_type, type_args);
+
+	g_assert (uuid_test);
+	g_assert (nm_utils_is_uuid (uuid_test));
+
+	if (strcmp (uuid_test, expected_uuid)) {
+		g_error ("UUID test failed: type=%d; text=%s, len=%lld, uuid=%s, expected=%s", uuid_type,
+		         str, (long long) slen, uuid_test, expected_uuid);
+	}
+
+	if (slen < 0) {
+		/* also test that passing slen==-1 yields the same result as passing strlen(str). */
+		_test_uuid (uuid_type, expected_uuid, str, strlen (str), type_args);
+	} else if (str && slen == 0) {
+		/* also test if we accept NULL for slen==0 */
+		_test_uuid (uuid_type, expected_uuid, NULL, 0, type_args);
+	}
+
+	if (uuid_type == NM_UTILS_UUID_TYPE_VARIANT3 && !type_args) {
+		/* For NM_UTILS_UUID_TYPE_VARIANT3, a missing @type_args is equal to UUID_NIL */
+		_test_uuid (uuid_type, expected_uuid, str, slen, UUID_NIL);
+	}
+}
+
+static void
+test_nm_utils_uuid_generate_from_string (void)
+{
+	_test_uuid (NM_UTILS_UUID_TYPE_LEGACY, "d41d8cd9-8f00-b204-e980-0998ecf8427e", "", -1, NULL);
+	_test_uuid (NM_UTILS_UUID_TYPE_LEGACY, "0cc175b9-c0f1-b6a8-31c3-99e269772661", "a", -1, NULL);
+	_test_uuid (NM_UTILS_UUID_TYPE_LEGACY, "098f6bcd-4621-d373-cade-4e832627b4f6", "test", -1, NULL);
+	_test_uuid (NM_UTILS_UUID_TYPE_LEGACY, "70350f60-27bc-e371-3f6b-76473084309b", "a\0b", 3, NULL);
+	_test_uuid (NM_UTILS_UUID_TYPE_LEGACY, "59c0547b-7fe2-1c15-2cce-e328e8bf6742", "/etc/NetworkManager/system-connections/em1", -1, NULL);
+
+	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "4ae71336-e44b-39bf-b9d2-752e234818a5", "", -1, NULL);
+	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "0531103a-d8fc-3dd4-b972-d98e4750994e", "a", -1, NULL);
+	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "96e17d7a-ac89-38cf-95e1-bf5098da34e1", "test", -1, NULL);
+	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "8156568e-4ae6-3f34-a93e-18e2c6cbbf78", "a\0b", 3, NULL);
+
+	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "c87ee674-4ddc-3efe-a74e-dfe25da5d7b3", "", -1, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "4c104dd0-4821-30d5-9ce3-0e7a1f8b7c0d", "a", -1, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "45a113ac-c7f2-30b0-90a5-a399ab912716", "test", -1, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "002a0ada-f547-375a-bab5-896a11d1927e", "a\0b", 3, UUID_NS_DNS);
+}
+
+/******************************************************************************/
+
+NMTST_DEFINE ();
+
+int main (int argc, char **argv)
+{
+	nmtst_init (&argc, &argv, TRUE);
+
+	/* The tests */
+	g_test_add_func ("/core/general/test_setting_vpn_items", test_setting_vpn_items);
+	g_test_add_func ("/core/general/test_setting_vpn_update_secrets", test_setting_vpn_update_secrets);
+	g_test_add_func ("/core/general/test_setting_vpn_modify_during_foreach", test_setting_vpn_modify_during_foreach);
+	g_test_add_func ("/core/general/test_setting_ip4_config_labels", test_setting_ip4_config_labels);
+	g_test_add_func ("/core/general/test_setting_ip4_config_address_data", test_setting_ip4_config_address_data);
+	g_test_add_func ("/core/general/test_setting_gsm_apn_spaces", test_setting_gsm_apn_spaces);
+	g_test_add_func ("/core/general/test_setting_gsm_apn_bad_chars", test_setting_gsm_apn_bad_chars);
+	g_test_add_func ("/core/general/test_setting_gsm_apn_underscore", test_setting_gsm_apn_underscore);
+	g_test_add_func ("/core/general/test_setting_gsm_without_number", test_setting_gsm_without_number);
+	g_test_add_func ("/core/general/test_setting_to_dbus_all", test_setting_to_dbus_all);
+	g_test_add_func ("/core/general/test_setting_to_dbus_no_secrets", test_setting_to_dbus_no_secrets);
+	g_test_add_func ("/core/general/test_setting_to_dbus_only_secrets", test_setting_to_dbus_only_secrets);
+	g_test_add_func ("/core/general/test_setting_to_dbus_transform", test_setting_to_dbus_transform);
+	g_test_add_func ("/core/general/test_setting_to_dbus_enum", test_setting_to_dbus_enum);
+	g_test_add_func ("/core/general/test_setting_compare_id", test_setting_compare_id);
+	g_test_add_func ("/core/general/test_setting_compare_timestamp", test_setting_compare_timestamp);
+#define ADD_FUNC(func, secret_flags, comp_flags, remove_secret) \
+	g_test_add_data_func_full ("/core/general/" G_STRINGIFY (func), \
+	                           test_data_compare_secrets_new (secret_flags, comp_flags, remove_secret), \
+	                           func, g_free)
+	ADD_FUNC (test_setting_compare_secrets, NM_SETTING_SECRET_FLAG_AGENT_OWNED, NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS, TRUE);
+	ADD_FUNC (test_setting_compare_secrets, NM_SETTING_SECRET_FLAG_NOT_SAVED, NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS, TRUE);
+	ADD_FUNC (test_setting_compare_secrets, NM_SETTING_SECRET_FLAG_NONE, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS, TRUE);
+	ADD_FUNC (test_setting_compare_secrets, NM_SETTING_SECRET_FLAG_NONE, NM_SETTING_COMPARE_FLAG_EXACT, FALSE);
+	ADD_FUNC (test_setting_compare_vpn_secrets, NM_SETTING_SECRET_FLAG_AGENT_OWNED, NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS, TRUE);
+	ADD_FUNC (test_setting_compare_vpn_secrets, NM_SETTING_SECRET_FLAG_NOT_SAVED, NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS, TRUE);
+	ADD_FUNC (test_setting_compare_vpn_secrets, NM_SETTING_SECRET_FLAG_NONE, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS, TRUE);
+	ADD_FUNC (test_setting_compare_vpn_secrets, NM_SETTING_SECRET_FLAG_NONE, NM_SETTING_COMPARE_FLAG_EXACT, FALSE);
+	g_test_add_func ("/core/general/test_setting_old_uuid", test_setting_old_uuid);
+
+	g_test_add_func ("/core/general/test_connection_to_dbus_setting_name", test_connection_to_dbus_setting_name);
+	g_test_add_func ("/core/general/test_connection_to_dbus_deprecated_props", test_connection_to_dbus_deprecated_props);
+	g_test_add_func ("/core/general/test_setting_new_from_dbus", test_setting_new_from_dbus);
+	g_test_add_func ("/core/general/test_setting_new_from_dbus_transform", test_setting_new_from_dbus_transform);
+	g_test_add_func ("/core/general/test_setting_new_from_dbus_enum", test_setting_new_from_dbus_enum);
+	g_test_add_func ("/core/general/test_connection_replace_settings", test_connection_replace_settings);
+	g_test_add_func ("/core/general/test_connection_replace_settings_from_connection", test_connection_replace_settings_from_connection);
+	g_test_add_func ("/core/general/test_connection_replace_settings_bad", test_connection_replace_settings_bad);
+	g_test_add_func ("/core/general/test_connection_new_from_dbus", test_connection_new_from_dbus);
+	g_test_add_func ("/core/general/test_connection_normalize_virtual_iface_name", test_connection_normalize_virtual_iface_name);
+	g_test_add_func ("/core/general/test_connection_normalize_uuid", test_connection_normalize_uuid);
+	g_test_add_func ("/core/general/test_connection_normalize_type", test_connection_normalize_type);
+	g_test_add_func ("/core/general/test_connection_normalize_slave_type_1", test_connection_normalize_slave_type_1);
+	g_test_add_func ("/core/general/test_connection_normalize_slave_type_2", test_connection_normalize_slave_type_2);
+	g_test_add_func ("/core/general/test_connection_normalize_infiniband_mtu", test_connection_normalize_infiniband_mtu);
+
+	g_test_add_func ("/core/general/test_setting_connection_permissions_helpers", test_setting_connection_permissions_helpers);
+	g_test_add_func ("/core/general/test_setting_connection_permissions_property", test_setting_connection_permissions_property);
+
+	g_test_add_func ("/core/general/test_connection_compare_same", test_connection_compare_same);
+	g_test_add_func ("/core/general/test_connection_compare_key_only_in_a", test_connection_compare_key_only_in_a);
+	g_test_add_func ("/core/general/test_connection_compare_setting_only_in_a", test_connection_compare_setting_only_in_a);
+	g_test_add_func ("/core/general/test_connection_compare_key_only_in_b", test_connection_compare_key_only_in_b);
+	g_test_add_func ("/core/general/test_connection_compare_setting_only_in_b", test_connection_compare_setting_only_in_b);
+
+	g_test_add_func ("/core/general/test_connection_diff_a_only", test_connection_diff_a_only);
+	g_test_add_func ("/core/general/test_connection_diff_same", test_connection_diff_same);
+	g_test_add_func ("/core/general/test_connection_diff_different", test_connection_diff_different);
+	g_test_add_func ("/core/general/test_connection_diff_no_secrets", test_connection_diff_no_secrets);
+	g_test_add_func ("/core/general/test_connection_diff_inferrable", test_connection_diff_inferrable);
+	g_test_add_func ("/core/general/test_connection_good_base_types", test_connection_good_base_types);
+	g_test_add_func ("/core/general/test_connection_bad_base_types", test_connection_bad_base_types);
+
+	g_test_add_func ("/core/general/test_hwaddr_aton_ether_normal", test_hwaddr_aton_ether_normal);
+	g_test_add_func ("/core/general/test_hwaddr_aton_ib_normal", test_hwaddr_aton_ib_normal);
+	g_test_add_func ("/core/general/test_hwaddr_aton_no_leading_zeros", test_hwaddr_aton_no_leading_zeros);
+	g_test_add_func ("/core/general/test_hwaddr_aton_malformed", test_hwaddr_aton_malformed);
+	g_test_add_func ("/core/general/test_hwaddr_equal", test_hwaddr_equal);
+	g_test_add_func ("/core/general/test_hwaddr_canonical", test_hwaddr_canonical);
+
+	g_test_add_func ("/core/general/test_ip4_prefix_to_netmask", test_ip4_prefix_to_netmask);
+	g_test_add_func ("/core/general/test_ip4_netmask_to_prefix", test_ip4_netmask_to_prefix);
+
+	g_test_add_func ("/core/general/test_connection_changed_signal", test_connection_changed_signal);
+	g_test_add_func ("/core/general/test_setting_connection_changed_signal", test_setting_connection_changed_signal);
+	g_test_add_func ("/core/general/test_setting_bond_changed_signal", test_setting_bond_changed_signal);
+	g_test_add_func ("/core/general/test_setting_ip4_changed_signal", test_setting_ip4_changed_signal);
+	g_test_add_func ("/core/general/test_setting_ip6_changed_signal", test_setting_ip6_changed_signal);
+	g_test_add_func ("/core/general/test_setting_vlan_changed_signal", test_setting_vlan_changed_signal);
+	g_test_add_func ("/core/general/test_setting_vpn_changed_signal", test_setting_vpn_changed_signal);
+	g_test_add_func ("/core/general/test_setting_wired_changed_signal", test_setting_wired_changed_signal);
+	g_test_add_func ("/core/general/test_setting_wireless_changed_signal", test_setting_wireless_changed_signal);
+	g_test_add_func ("/core/general/test_setting_wireless_security_changed_signal", test_setting_wireless_security_changed_signal);
+	g_test_add_func ("/core/general/test_setting_802_1x_changed_signal", test_setting_802_1x_changed_signal);
+	g_test_add_func ("/core/general/test_setting_ip4_gateway", test_setting_ip4_gateway);
+	g_test_add_func ("/core/general/test_setting_ip6_gateway", test_setting_ip6_gateway);
+
+	g_test_add_func ("/core/general/hexstr2bin", test_hexstr2bin);
+	g_test_add_func ("/core/general/test_nm_utils_uuid_generate_from_string", test_nm_utils_uuid_generate_from_string);
+
+	return g_test_run ();
+}
+
diff --git a/libnm-core/tests/test-secrets.c b/libnm-core/tests/test-secrets.c
new file mode 100644
index 00000000..1254dfff
--- /dev/null
+++ b/libnm-core/tests/test-secrets.c
@@ -0,0 +1,766 @@
+/* -*- 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 2008 - 2011 Red Hat, Inc.
+ *
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <string.h>
+
+#include "nm-setting-8021x.h"
+#include "nm-setting-cdma.h"
+#include "nm-setting-connection.h"
+#include "nm-setting-gsm.h"
+#include "nm-setting-ip4-config.h"
+#include "nm-setting-ppp.h"
+#include "nm-setting-pppoe.h"
+#include "nm-setting-vpn.h"
+#include "nm-setting-wired.h"
+#include "nm-setting-wireless-security.h"
+#include "nm-setting-wireless.h"
+#include "nm-simple-connection.h"
+#include "nm-utils.h"
+
+#include "nm-test-utils.h"
+
+#define TEST_NEED_SECRETS_EAP_TLS_CA_CERT TEST_CERT_DIR "/test_ca_cert.pem"
+#define TEST_NEED_SECRETS_EAP_TLS_CLIENT_CERT TEST_CERT_DIR "/test_key_and_cert.pem"
+#define TEST_NEED_SECRETS_EAP_TLS_PRIVATE_KEY TEST_CERT_DIR "/test_key_and_cert.pem"
+
+static gboolean
+find_hints_item (GPtrArray *hints, const char *item)
+{
+	int i;
+
+	for (i = 0; i < hints->len; i++) {
+		if (!strcmp (item, (const char *) g_ptr_array_index (hints, i)))
+			return TRUE;
+	}
+	return FALSE;
+}
+
+static NMConnection *
+make_tls_connection (const char *detail, NMSetting8021xCKScheme scheme)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSetting8021x *s_8021x;
+	NMSettingWired *s_wired;
+	NMSettingIP4Config *s_ip4;
+	char *uuid;
+	gboolean success;
+	GError *error = NULL;
+
+	connection = nm_simple_connection_new ();
+
+	/* Connection setting */
+	s_con = (NMSettingConnection *) nm_setting_connection_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+	uuid = nm_utils_uuid_generate ();
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_ID, "Test Need TLS Secrets",
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
+	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
+	              NULL);
+	g_free (uuid);
+
+	/* Wired setting */
+	s_wired = (NMSettingWired *) nm_setting_wired_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_wired));
+
+	/* Wireless security setting */
+	s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_8021x));
+
+	g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, "Bill Smith", NULL);
+
+	nm_setting_802_1x_add_eap_method (s_8021x, "tls");
+
+	success = nm_setting_802_1x_set_ca_cert (s_8021x,
+	                                         TEST_NEED_SECRETS_EAP_TLS_CA_CERT,
+	                                         scheme,
+	                                         NULL,
+	                                         &error);
+	ASSERT (success == TRUE,
+	        detail, "failed to set CA certificate '%s': %s",
+	        TEST_NEED_SECRETS_EAP_TLS_CA_CERT, error->message);
+
+	success = nm_setting_802_1x_set_client_cert (s_8021x,
+	                                             TEST_NEED_SECRETS_EAP_TLS_CLIENT_CERT,
+	                                             scheme,
+	                                             NULL,
+	                                             &error);
+	ASSERT (success == TRUE,
+	        detail, "failed to set client certificate '%s': %s",
+	        TEST_NEED_SECRETS_EAP_TLS_CLIENT_CERT, error->message);
+
+	success = nm_setting_802_1x_set_private_key (s_8021x,
+	                                             TEST_NEED_SECRETS_EAP_TLS_PRIVATE_KEY,
+	                                             "test",
+	                                             scheme,
+	                                             NULL,
+	                                             &error);
+	ASSERT (success == TRUE,
+	        detail, "failed to set private key '%s': %s",
+	        TEST_NEED_SECRETS_EAP_TLS_PRIVATE_KEY, error->message);
+
+	/* IP4 setting */
+	s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+
+	g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
+
+	ASSERT (nm_connection_verify (connection, &error) == TRUE,
+	        detail, "failed to verify connection: %s",
+	        (error && error->message) ? error->message : "(unknown)");
+
+	return connection;
+}
+
+static void
+test_need_tls_secrets_path (void)
+{
+	NMConnection *connection;
+	const char *setting_name;
+	GPtrArray *hints = NULL;
+
+	connection = make_tls_connection ("need-tls-secrets-path-key", NM_SETTING_802_1X_CK_SCHEME_PATH);
+	ASSERT (connection != NULL,
+	        "need-tls-secrets-path-key",
+	        "error creating test connection");
+
+	/* Ensure we don't need any secrets since we just set up the connection */
+	setting_name = nm_connection_need_secrets (connection, &hints);
+	ASSERT (setting_name == NULL,
+	        "need-tls-secrets-path-key",
+	        "secrets are unexpectedly required");
+	ASSERT (hints == NULL,
+	        "need-tls-secrets-path-key",
+	        "hints should be NULL since no secrets were required");
+
+	/* Connection is good; clear secrets and ensure private key password is then required */
+	nm_connection_clear_secrets (connection);
+
+	hints = NULL;
+	setting_name = nm_connection_need_secrets (connection, &hints);
+	ASSERT (setting_name != NULL,
+	        "need-tls-secrets-path-key-password",
+	        "unexpected secrets success");
+	ASSERT (strcmp (setting_name, NM_SETTING_802_1X_SETTING_NAME) == 0,
+			"need-tls-secrets-path-key-password",
+			"unexpected setting secrets required");
+
+	ASSERT (hints != NULL,
+	        "need-tls-secrets-path-key-password",
+	        "expected returned secrets hints");
+	ASSERT (find_hints_item (hints, NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD),
+			"need-tls-secrets-path-key-password",
+			"expected to require private key password, but it wasn't");
+
+	g_object_unref (connection);
+}
+
+static void
+test_need_tls_secrets_blob (void)
+{
+	NMConnection *connection;
+	const char *setting_name;
+	GPtrArray *hints = NULL;
+
+	connection = make_tls_connection ("need-tls-secrets-blob-key", NM_SETTING_802_1X_CK_SCHEME_BLOB);
+	ASSERT (connection != NULL,
+	        "need-tls-secrets-blob-key",
+	        "error creating test connection");
+
+	/* Ensure we don't need any secrets since we just set up the connection */
+	setting_name = nm_connection_need_secrets (connection, &hints);
+	ASSERT (setting_name == NULL,
+	        "need-tls-secrets-blob-key",
+	        "secrets are unexpectedly required");
+	ASSERT (hints == NULL,
+	        "need-tls-secrets-blob-key",
+	        "hints should be NULL since no secrets were required");
+
+	/* Clear secrets and ensure password is again required */
+	nm_connection_clear_secrets (connection);
+
+	hints = NULL;
+	setting_name = nm_connection_need_secrets (connection, &hints);
+	ASSERT (setting_name != NULL,
+	        "need-tls-secrets-blob-key-password",
+	        "unexpected secrets success");
+	ASSERT (strcmp (setting_name, NM_SETTING_802_1X_SETTING_NAME) == 0,
+			"need-tls-secrets-blob-key-password",
+			"unexpected setting secrets required");
+
+	ASSERT (hints != NULL,
+	        "need-tls-secrets-blob-key-password",
+	        "expected returned secrets hints");
+	ASSERT (find_hints_item (hints, NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD),
+			"need-tls-secrets-blob-key-password",
+			"expected to require private key password, but it wasn't");
+
+	g_object_unref (connection);
+}
+
+static NMConnection *
+make_tls_phase2_connection (const char *detail, NMSetting8021xCKScheme scheme)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSetting8021x *s_8021x;
+	NMSettingWired *s_wired;
+	NMSettingIP4Config *s_ip4;
+	char *uuid;
+	gboolean success;
+	GError *error = NULL;
+
+	connection = nm_simple_connection_new ();
+
+	/* Connection setting */
+	s_con = (NMSettingConnection *) nm_setting_connection_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+	uuid = nm_utils_uuid_generate ();
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_ID, "Test Need TLS Secrets",
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
+	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
+	              NULL);
+	g_free (uuid);
+
+	/* Wired setting */
+	s_wired = (NMSettingWired *) nm_setting_wired_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_wired));
+
+	/* Wireless security setting */
+	s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_8021x));
+
+	g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, "blahblah", NULL);
+	g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, "Bill Smith", NULL);
+
+	nm_setting_802_1x_add_eap_method (s_8021x, "ttls");
+	g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, "tls", NULL);
+
+	success = nm_setting_802_1x_set_phase2_ca_cert (s_8021x,
+	                                                TEST_NEED_SECRETS_EAP_TLS_CA_CERT,
+	                                                scheme,
+	                                                NULL,
+	                                                &error);
+	ASSERT (success == TRUE,
+	        detail, "failed to set phase2 CA certificate '%s': %s",
+	        TEST_NEED_SECRETS_EAP_TLS_CA_CERT, error->message);
+
+	success = nm_setting_802_1x_set_phase2_client_cert (s_8021x,
+	                                                    TEST_NEED_SECRETS_EAP_TLS_CLIENT_CERT,
+	                                                    scheme,
+	                                                    NULL,
+	                                                    &error);
+	ASSERT (success == TRUE,
+	        detail, "failed to set phase2 client certificate '%s': %s",
+	        TEST_NEED_SECRETS_EAP_TLS_CLIENT_CERT, error->message);
+
+	success = nm_setting_802_1x_set_phase2_private_key (s_8021x,
+	                                                    TEST_NEED_SECRETS_EAP_TLS_PRIVATE_KEY,
+	                                                    "test",
+	                                                    scheme,
+	                                                    NULL,
+	                                                    &error);
+	ASSERT (success == TRUE,
+	        detail, "failed to set phase2 private key '%s': %s",
+	        TEST_NEED_SECRETS_EAP_TLS_PRIVATE_KEY, error->message);
+
+	/* IP4 setting */
+	s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+
+	g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
+
+	ASSERT (nm_connection_verify (connection, &error) == TRUE,
+	        detail, "failed to verify connection: %s",
+	        (error && error->message) ? error->message : "(unknown)");
+
+	return connection;
+}
+
+static void
+test_need_tls_phase2_secrets_path (void)
+{
+	NMConnection *connection;
+	const char *setting_name;
+	GPtrArray *hints = NULL;
+
+	connection = make_tls_phase2_connection ("need-tls-phase2-secrets-path-key",
+	                                         NM_SETTING_802_1X_CK_SCHEME_PATH);
+	ASSERT (connection != NULL,
+	        "need-tls-phase2-secrets-path-key",
+	        "error creating test connection");
+
+	/* Ensure we don't need any secrets since we just set up the connection */
+	setting_name = nm_connection_need_secrets (connection, &hints);
+	ASSERT (setting_name == NULL,
+	        "need-tls-phase2-secrets-path-key",
+	        "secrets are unexpectedly required");
+	ASSERT (hints == NULL,
+	        "need-tls-phase2-secrets-path-key",
+	        "hints should be NULL since no secrets were required");
+
+	/* Connection is good; clear secrets and ensure private key password is then required */
+	nm_connection_clear_secrets (connection);
+
+	hints = NULL;
+	setting_name = nm_connection_need_secrets (connection, &hints);
+	ASSERT (setting_name != NULL,
+	        "need-tls-phase2-secrets-path-key-password",
+	        "unexpected secrets success");
+	ASSERT (strcmp (setting_name, NM_SETTING_802_1X_SETTING_NAME) == 0,
+			"need-tls-phase2-secrets-path-key-password",
+			"unexpected setting secrets required");
+
+	ASSERT (hints != NULL,
+	        "need-tls-phase2-secrets-path-key-password",
+	        "expected returned secrets hints");
+	ASSERT (find_hints_item (hints, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD),
+			"need-tls-phase2-secrets-path-key-password",
+			"expected to require private key password, but it wasn't");
+
+	g_object_unref (connection);
+}
+
+static void
+test_need_tls_phase2_secrets_blob (void)
+{
+	NMConnection *connection;
+	const char *setting_name;
+	GPtrArray *hints = NULL;
+
+	connection = make_tls_phase2_connection ("need-tls-phase2-secrets-blob-key",
+	                                         NM_SETTING_802_1X_CK_SCHEME_BLOB);
+	ASSERT (connection != NULL,
+	        "need-tls-phase2-secrets-blob-key",
+	        "error creating test connection");
+
+	/* Ensure we don't need any secrets since we just set up the connection */
+	setting_name = nm_connection_need_secrets (connection, &hints);
+	ASSERT (setting_name == NULL,
+	        "need-tls-phase2-secrets-blob-key",
+	        "secrets are unexpectedly required");
+	ASSERT (hints == NULL,
+	        "need-tls-phase2-secrets-blob-key",
+	        "hints should be NULL since no secrets were required");
+
+	/* Connection is good; clear secrets and ensure private key password is then required */
+	nm_connection_clear_secrets (connection);
+
+	hints = NULL;
+	setting_name = nm_connection_need_secrets (connection, &hints);
+	ASSERT (setting_name != NULL,
+	        "need-tls-phase2-secrets-blob-key-password",
+	        "unexpected secrets success");
+	ASSERT (strcmp (setting_name, NM_SETTING_802_1X_SETTING_NAME) == 0,
+			"need-tls-phase2-secrets-blob-key-password",
+			"unexpected setting secrets required");
+
+	ASSERT (hints != NULL,
+	        "need-tls-phase2-secrets-blob-key-password",
+	        "expected returned secrets hints");
+	ASSERT (find_hints_item (hints, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD),
+			"need-tls-phase2-secrets-blob-key-password",
+			"expected to require private key password, but it wasn't");
+
+	g_object_unref (connection);
+}
+
+static NMConnection *
+wifi_connection_new (void)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSettingWireless *s_wifi;
+	NMSettingWirelessSecurity *s_wsec;
+	unsigned char tmpssid[] = { 0x31, 0x33, 0x33, 0x37 };
+	char *uuid;
+	GBytes *ssid;
+
+	connection = nm_simple_connection_new ();
+	g_assert (connection);
+
+	/* Connection setting */
+	s_con = (NMSettingConnection *) nm_setting_connection_new ();
+	g_assert (s_con);
+
+	uuid = nm_utils_uuid_generate ();
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_ID, "Test Wireless",
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_AUTOCONNECT, FALSE,
+	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME,
+	              NULL);
+	g_free (uuid);
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+	/* Wireless setting */
+	s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
+	g_assert (s_wifi);
+
+	ssid = g_bytes_new (tmpssid, sizeof (tmpssid));
+	g_object_set (s_wifi,
+	              NM_SETTING_WIRELESS_SSID, ssid,
+	              NULL);
+	g_bytes_unref (ssid);
+	nm_connection_add_setting (connection, NM_SETTING (s_wifi));
+
+	/* Wifi security */
+	s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+	g_assert (s_wsec);
+
+	g_object_set (G_OBJECT (s_wsec),
+	              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none",
+	              NULL);
+	nm_connection_add_setting (connection, NM_SETTING (s_wsec));
+
+	return connection;
+}
+
+static GVariant *
+build_wep_secrets (const char *wepkey)
+{
+	GVariantBuilder builder;
+
+	g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+	g_variant_builder_add (&builder, "{sv}",
+	                       NM_SETTING_WIRELESS_SECURITY_WEP_KEY0,
+	                       g_variant_new_string (wepkey));
+	g_variant_builder_add (&builder, "{sv}",
+	                       NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE,
+	                       g_variant_new_uint32 (NM_WEP_KEY_TYPE_KEY));
+
+	return g_variant_builder_end (&builder);
+}
+
+static void
+test_update_secrets_wifi_single_setting (void)
+{
+	NMConnection *connection;
+	NMSettingWirelessSecurity *s_wsec;
+	GVariant *secrets;
+	GError *error = NULL;
+	gboolean success;
+	const char *wepkey = "11111111111111111111111111";
+	const char *tmp;
+
+	/* Test update with a hashed setting of 802-11-wireless secrets */
+
+	connection = wifi_connection_new ();
+
+	secrets = build_wep_secrets (wepkey);
+	success = nm_connection_update_secrets (connection,
+	                                        NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
+	                                        secrets,
+	                                        &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	g_variant_unref (secrets);
+
+	/* Make sure the secret is now in the connection */
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
+	g_assert (s_wsec);
+	tmp = nm_setting_wireless_security_get_wep_key (s_wsec, 0);
+	g_assert_cmpstr (tmp, ==, wepkey);
+
+	g_object_unref (connection);
+}
+
+static void
+test_update_secrets_wifi_full_hash (void)
+{
+	NMConnection *connection;
+	NMSettingWirelessSecurity *s_wsec;
+	GVariantBuilder builder;
+	GVariant *all;
+	GError *error = NULL;
+	gboolean success;
+	const char *wepkey = "11111111111111111111111111";
+	const char *tmp;
+
+	/* Test update with a hashed connection containing only 802-11-wireless
+	 * setting and secrets.
+	 */
+
+	connection = wifi_connection_new ();
+
+	g_variant_builder_init (&builder, NM_VARIANT_TYPE_CONNECTION);
+	g_variant_builder_add (&builder, "{s@a{sv}}",
+	                       NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
+	                       build_wep_secrets (wepkey));
+	all = g_variant_builder_end (&builder);
+
+	success = nm_connection_update_secrets (connection,
+	                                        NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
+	                                        all,
+	                                        &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	g_variant_unref (all);
+
+	/* Make sure the secret is now in the connection */
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
+	g_assert (s_wsec);
+	tmp = nm_setting_wireless_security_get_wep_key (s_wsec, 0);
+	g_assert_cmpstr (tmp, ==, wepkey);
+
+	g_object_unref (connection);
+}
+
+static void
+test_update_secrets_wifi_bad_setting_name (void)
+{
+	NMConnection *connection;
+	GVariant *secrets;
+	GError *error = NULL;
+	gboolean success;
+	const char *wepkey = "11111111111111111111111111";
+
+	/* Test that passing an invalid setting name to
+	 * nm_connection_update_secrets() fails with the correct error.
+	 */
+
+	connection = wifi_connection_new ();
+
+	secrets = build_wep_secrets (wepkey);
+
+	success = nm_connection_update_secrets (connection,
+	                                        "asdfasdfasdfasf",
+	                                        secrets,
+	                                        &error);
+	g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND);
+	g_assert (success == FALSE);
+
+	g_variant_unref (secrets);
+
+	g_object_unref (connection);
+}
+
+static void
+test_update_secrets_whole_connection (void)
+{
+	NMConnection *connection;
+	NMSettingWirelessSecurity *s_wsec;
+	GVariant *secrets;
+	GError *error = NULL;
+	gboolean success;
+	const char *wepkey = "11111111111111111111111111";
+
+	/* Test calling nm_connection_update_secrets() with an entire hashed
+	 * connection including non-secrets.
+	 */
+
+	connection = wifi_connection_new ();
+
+	/* Build up the secrets dictionary */
+	secrets = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL);
+	NMTST_VARIANT_EDITOR (secrets,
+	                      NMTST_VARIANT_ADD_PROPERTY (NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
+	                                                  NM_SETTING_WIRELESS_SECURITY_WEP_KEY0,
+	                                                  "s",
+	                                                  wepkey);
+	                      );
+
+	success = nm_connection_update_secrets (connection, NULL, secrets, &error);
+	g_assert_no_error (error);
+	g_assert (success == TRUE);
+
+	g_variant_unref (secrets);
+
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
+	g_assert (s_wsec);
+	g_assert_cmpstr (nm_setting_wireless_security_get_wep_key (s_wsec, 0), ==, wepkey);
+
+	g_object_unref (connection);
+}
+
+static void
+test_update_secrets_whole_connection_empty_hash (void)
+{
+	NMConnection *connection;
+	GVariant *secrets;
+	GError *error = NULL;
+	gboolean success;
+
+	/* Test that updating secrets with an empty connection hash returns success */
+
+	connection = wifi_connection_new ();
+	secrets = g_variant_new_array (G_VARIANT_TYPE ("{sa{sv}}"), NULL, 0);
+	success = nm_connection_update_secrets (connection, NULL, secrets, &error);
+	g_assert_no_error (error);
+	g_assert (success == TRUE);
+	g_variant_unref (secrets);
+	g_object_unref (connection);
+}
+
+static void
+test_update_secrets_whole_connection_bad_setting (void)
+{
+	NMConnection *connection;
+	NMSettingWirelessSecurity *s_wsec;
+	GVariant *secrets, *copy, *setting_hash;
+	const char *setting_name;
+	GVariantBuilder conn_builder;
+	GVariantIter conn_iter;
+	GError *error = NULL;
+	gboolean success;
+	const char *wepkey = "11111111111111111111111111";
+
+	/* Test that sending a hashed connection containing an invalid setting
+	 * name fails with the right error.
+	 */
+
+	connection = wifi_connection_new ();
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
+	g_assert (s_wsec != NULL);
+	g_object_set (G_OBJECT (s_wsec),
+	              NM_SETTING_WIRELESS_SECURITY_WEP_KEY0, wepkey,
+	              NULL);
+
+	/* Build up the secrets hash */
+	secrets = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL);
+
+	/* Copy the dict, renaming the wireless-security setting in the process
+	 * (so we ensure libnm is returning the right error when it finds an entry
+	 * in the connection hash that doesn't match any setting in the connection).
+	 */
+	g_variant_builder_init (&conn_builder, NM_VARIANT_TYPE_CONNECTION);
+	g_variant_iter_init (&conn_iter, secrets);
+	while (g_variant_iter_next (&conn_iter, "{&s@a{sv}}", &setting_name, &setting_hash)) {
+		if (strcmp (setting_name, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME) == 0)
+			setting_name = "asdfasdfasdfasdf";
+
+		g_variant_builder_add (&conn_builder, "{s@a{sv}}", setting_name, setting_hash);
+		g_variant_unref (setting_hash);
+	}
+	copy = g_variant_builder_end (&conn_builder);
+	g_variant_unref (secrets);
+
+	success = nm_connection_update_secrets (connection, NULL, copy, &error);
+	g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND);
+	g_assert (success == FALSE);
+
+	g_variant_unref (copy);
+	g_object_unref (connection);
+}
+
+static void
+test_update_secrets_whole_connection_empty_base_setting (void)
+{
+	NMConnection *connection;
+	GVariant *secrets, *setting;
+	GError *error = NULL;
+	gboolean success;
+
+	/* Test that a hashed connection which does not have any hashed secrets
+	 * for the requested setting returns success.
+	 */
+
+	connection = wifi_connection_new ();
+	secrets = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ONLY_SECRETS);
+	g_assert_cmpint (g_variant_n_children (secrets), ==, 3);
+
+	setting = g_variant_lookup_value (secrets, NM_SETTING_WIRELESS_SETTING_NAME, NULL);
+	g_assert (setting != NULL);
+	g_variant_unref (setting);
+
+	success = nm_connection_update_secrets (connection,
+	                                        NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
+	                                        secrets,
+	                                        &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	g_variant_unref (secrets);
+	g_object_unref (connection);
+}
+
+static void
+test_update_secrets_null_setting_name_with_setting_hash (void)
+{
+	NMConnection *connection;
+	GVariant *secrets;
+	GError *error = NULL;
+	gboolean success;
+	const char *wepkey = "11111111111111111111111111";
+
+	/* Ensure that a NULL setting name and only a hashed setting fails */
+
+	connection = wifi_connection_new ();
+
+	secrets = build_wep_secrets (wepkey);
+
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL,
+	                       "*nm_connection_update_secrets*setting_name != NULL || full_connection*");
+	success = nm_connection_update_secrets (connection, NULL, secrets, &error);
+	g_test_assert_expected_messages ();
+	g_assert_no_error (error);
+	g_assert (!success);
+
+	g_variant_unref (secrets);
+	g_object_unref (connection);
+}
+
+NMTST_DEFINE ();
+
+int
+main (int argc, char **argv)
+{
+	char *base;
+
+#if !GLIB_CHECK_VERSION (2, 35, 0)
+	g_type_init ();
+#endif
+
+	nmtst_init (&argc, &argv, TRUE);
+
+	/* The tests */
+	test_need_tls_secrets_path ();
+	test_need_tls_secrets_blob ();
+	test_need_tls_phase2_secrets_path ();
+	test_need_tls_phase2_secrets_blob ();
+
+	test_update_secrets_wifi_single_setting ();
+	test_update_secrets_wifi_full_hash ();
+	test_update_secrets_wifi_bad_setting_name ();
+
+	test_update_secrets_whole_connection ();
+	test_update_secrets_whole_connection_empty_hash ();
+	test_update_secrets_whole_connection_bad_setting ();
+	test_update_secrets_whole_connection_empty_base_setting ();
+	test_update_secrets_null_setting_name_with_setting_hash ();
+
+	base = g_path_get_basename (argv[0]);
+	fprintf (stdout, "%s: SUCCESS\n", base);
+	g_free (base);
+	return 0;
+}
+
diff --git a/libnm-core/tests/test-setting-8021x.c b/libnm-core/tests/test-setting-8021x.c
new file mode 100644
index 00000000..637ab81c
--- /dev/null
+++ b/libnm-core/tests/test-setting-8021x.c
@@ -0,0 +1,458 @@
+/* -*- 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 2008 - 2011 Red Hat, Inc.
+ *
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <string.h>
+
+#include <nm-utils.h>
+
+#include "nm-setting-connection.h"
+#include "nm-setting-8021x.h"
+
+#include "nm-test-utils.h"
+
+static void
+compare_blob_data (const char *test,
+                   const char *key_path,
+                   GBytes *key)
+{
+	char *contents = NULL;
+	gsize len = 0;
+	GError *error = NULL;
+	gboolean success;
+
+	success = g_file_get_contents (key_path, &contents, &len, &error);
+	ASSERT (success == TRUE,
+	        test, "failed to read blob key file: %s", error->message);
+
+	ASSERT (len > 0, test, "blob key file invalid (size 0)");
+
+	ASSERT (len == g_bytes_get_size (key),
+	        test, "blob key file (%d) and setting key data (%d) lengths don't match",
+	        len, g_bytes_get_size (key));
+
+	ASSERT (memcmp (contents, g_bytes_get_data (key, NULL), len) == 0,
+	        test, "blob key file and blob key data don't match");
+
+	g_free (contents);
+}
+
+#define SCHEME_PATH "file://"
+
+static void
+check_scheme_path (GBytes *value, const char *path)
+{
+	const guint8 *p = g_bytes_get_data (value, NULL);
+
+	g_assert (memcmp (p, SCHEME_PATH, strlen (SCHEME_PATH)) == 0);
+	p += strlen (SCHEME_PATH);
+	g_assert (memcmp (p, path, strlen (path)) == 0);
+	p += strlen (path);
+	g_assert (*p == '\0');
+}
+
+static void
+test_private_key_import (const char *path,
+                         const char *password,
+                         NMSetting8021xCKScheme scheme)
+{
+	NMSetting8021x *s_8021x;
+	gboolean success;
+	NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+	NMSetting8021xCKFormat tmp_fmt;
+	GError *error = NULL;
+	GBytes *tmp_key = NULL, *client_cert = NULL;
+	const char *pw;
+
+	s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
+	ASSERT (s_8021x != NULL, "private-key-import", "setting was NULL");
+
+	success = nm_setting_802_1x_set_private_key (s_8021x,
+	                                             path,
+	                                             password,
+	                                             scheme,
+	                                             &format,
+	                                             &error);
+	ASSERT (success == TRUE,
+	        "private-key-import", "error reading private key: %s", error->message);
+	ASSERT (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN,
+	        "private-key-import", "unexpected private key format (got %d)", format);
+	tmp_fmt = nm_setting_802_1x_get_private_key_format (s_8021x);
+	ASSERT (tmp_fmt == format,
+	        "private-key-import", "unexpected re-read private key format (expected %d, got %d)",
+	        format, tmp_fmt);
+
+	/* Make sure the password is what we expect */
+	pw = nm_setting_802_1x_get_private_key_password (s_8021x);
+	ASSERT (pw != NULL,
+	        "private-key-import", "failed to get previous private key password");
+	ASSERT (strcmp (pw, password) == 0,
+	        "private-key-import", "failed to compare private key password");
+
+	if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
+		tmp_key = nm_setting_802_1x_get_private_key_blob (s_8021x);
+		ASSERT (tmp_key != NULL, "private-key-import", "missing private key blob");
+		compare_blob_data ("private-key-import", path, tmp_key);
+	} else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) {
+		g_object_get (s_8021x, NM_SETTING_802_1X_PRIVATE_KEY, &tmp_key, NULL);
+		ASSERT (tmp_key != NULL, "private-key-import", "missing private key value");
+		check_scheme_path (tmp_key, path);
+		g_bytes_unref (tmp_key);
+	} else
+		g_assert_not_reached ();
+
+	/* If it's PKCS#12 ensure the client cert is the same value */
+	if (format == NM_SETTING_802_1X_CK_FORMAT_PKCS12) {
+		g_object_get (s_8021x, NM_SETTING_802_1X_PRIVATE_KEY, &tmp_key, NULL);
+		ASSERT (tmp_key != NULL, "private-key-import", "missing private key value");
+
+		g_object_get (s_8021x, NM_SETTING_802_1X_CLIENT_CERT, &client_cert, NULL);
+		ASSERT (client_cert != NULL, "private-key-import", "missing client certificate value");
+
+		/* make sure they are the same */
+		ASSERT (g_bytes_equal (tmp_key, client_cert),
+		        "private-key-import", "unexpected different private key and client cert data");
+
+		g_bytes_unref (tmp_key);
+		g_bytes_unref (client_cert);
+	}
+
+	g_object_unref (s_8021x);
+}
+
+static void
+test_phase2_private_key_import (const char *path,
+                                const char *password,
+                                NMSetting8021xCKScheme scheme)
+{
+	NMSetting8021x *s_8021x;
+	gboolean success;
+	NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+	NMSetting8021xCKFormat tmp_fmt;
+	GError *error = NULL;
+	GBytes *tmp_key = NULL, *client_cert = NULL;
+	const char *pw;
+
+	s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
+	ASSERT (s_8021x != NULL, "phase2-private-key-import", "setting was NULL");
+
+	success = nm_setting_802_1x_set_phase2_private_key (s_8021x,
+	                                                    path,
+	                                                    password,
+	                                                    scheme,
+	                                                    &format,
+	                                                    &error);
+	ASSERT (success == TRUE,
+	        "phase2-private-key-import", "error reading private key: %s", error->message);
+	ASSERT (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN,
+	        "phase2-private-key-import", "unexpected private key format");
+	tmp_fmt = nm_setting_802_1x_get_phase2_private_key_format (s_8021x);
+	ASSERT (tmp_fmt == format,
+	        "phase2-private-key-import", "unexpected re-read private key format (expected %d, got %d)",
+	        format, tmp_fmt);
+
+	/* Make sure the password is what we expect */
+	pw = nm_setting_802_1x_get_phase2_private_key_password (s_8021x);
+	ASSERT (pw != NULL,
+	        "phase2-private-key-import", "failed to get previous private key password");
+	ASSERT (strcmp (pw, password) == 0,
+	        "phase2-private-key-import", "failed to compare private key password");
+
+	if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
+		tmp_key = nm_setting_802_1x_get_phase2_private_key_blob (s_8021x);
+		ASSERT (tmp_key != NULL, "phase2-private-key-import", "missing private key blob");
+		compare_blob_data ("phase2-private-key-import", path, tmp_key);
+	} else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) {
+		g_object_get (s_8021x, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, &tmp_key, NULL);
+		ASSERT (tmp_key != NULL, "phase2-private-key-import", "missing private key value");
+		check_scheme_path (tmp_key, path);
+	} else
+		g_assert_not_reached ();
+
+	/* If it's PKCS#12 ensure the client cert is the same value */
+	if (format == NM_SETTING_802_1X_CK_FORMAT_PKCS12) {
+		g_object_get (s_8021x, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, &tmp_key, NULL);
+		ASSERT (tmp_key != NULL, "private-key-import", "missing private key value");
+
+		g_object_get (s_8021x, NM_SETTING_802_1X_PHASE2_CLIENT_CERT, &client_cert, NULL);
+		ASSERT (client_cert != NULL, "private-key-import", "missing client certificate value");
+
+		/* make sure they are the same */
+		ASSERT (g_bytes_equal (tmp_key, client_cert),
+		        "private-key-import", "unexpected different private key and client cert data");
+
+		g_bytes_unref (tmp_key);
+		g_bytes_unref (client_cert);
+	}
+
+	g_object_unref (s_8021x);
+}
+
+static void
+test_wrong_password_keeps_data (const char *path, const char *password)
+{
+	NMSetting8021x *s_8021x;
+	gboolean success;
+	NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+	GError *error = NULL;
+	const char *pw;
+
+	s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
+	ASSERT (s_8021x != NULL, "wrong-password-keeps-data", "setting was NULL");
+
+	success = nm_setting_802_1x_set_private_key (s_8021x,
+	                                             path,
+	                                             password,
+	                                             NM_SETTING_802_1X_CK_SCHEME_BLOB,
+	                                             &format,
+	                                             &error);
+	ASSERT (success == TRUE,
+	        "wrong-password-keeps-data", "error reading private key: %s", error->message);
+	ASSERT (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN,
+	        "wrong-password-keeps-data", "unexpected private key format (got %d)", format);
+
+	/* Now try to set it to something that's not a certificate */
+	format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+	success = nm_setting_802_1x_set_private_key (s_8021x,
+	                                             "Makefile.am",
+	                                             password,
+	                                             NM_SETTING_802_1X_CK_SCHEME_BLOB,
+	                                             &format,
+	                                             &error);
+	ASSERT (success == FALSE,
+	        "wrong-password-keeps-data", "unexpected success reading private key");
+	ASSERT (error != NULL,
+	        "wrong-password-keeps-data", "unexpected missing error");
+	ASSERT (format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN,
+	        "wrong-password-keeps-data", "unexpected success reading private key format");
+
+	/* Make sure the password hasn't changed */
+	pw = nm_setting_802_1x_get_private_key_password (s_8021x);
+	ASSERT (pw != NULL,
+	        "wrong-password-keeps-data", "failed to get previous private key password");
+	ASSERT (strcmp (pw, password) == 0,
+	        "wrong-password-keeps-data", "failed to compare private key password");
+
+	g_object_unref (s_8021x);
+}
+
+static void
+test_clear_private_key (const char *path, const char *password)
+{
+	NMSetting8021x *s_8021x;
+	gboolean success;
+	NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+	GError *error = NULL;
+	const char *pw;
+
+	s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
+	ASSERT (s_8021x != NULL, "clear-private-key", "setting was NULL");
+
+	success = nm_setting_802_1x_set_private_key (s_8021x,
+	                                             path,
+	                                             password,
+	                                             NM_SETTING_802_1X_CK_SCHEME_BLOB,
+	                                             &format,
+	                                             &error);
+	ASSERT (success == TRUE,
+	        "clear-private-key", "error reading private key: %s", error->message);
+	ASSERT (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN,
+	        "clear-private-key", "unexpected private key format (got %d)", format);
+
+	/* Make sure the password is what we expect */
+	pw = nm_setting_802_1x_get_private_key_password (s_8021x);
+	ASSERT (pw != NULL,
+	        "clear-private-key", "failed to get previous private key password");
+	ASSERT (strcmp (pw, password) == 0,
+	        "clear-private-key", "failed to compare private key password");
+
+	/* Now clear it */
+	success = nm_setting_802_1x_set_private_key (s_8021x,
+	                                             NULL,
+	                                             NULL,
+	                                             NM_SETTING_802_1X_CK_SCHEME_BLOB,
+	                                             NULL,
+	                                             &error);
+	ASSERT (success == TRUE,
+	        "clear-private-key", "unexpected failure clearing private key");
+	ASSERT (error == NULL,
+	        "clear-private-key", "unexpected error clearing private key");
+
+	/* Ensure the password is also now clear */
+	ASSERT (nm_setting_802_1x_get_private_key_password (s_8021x) == NULL,
+	        "clear-private-key", "unexpected private key password");
+
+	g_object_unref (s_8021x);
+}
+
+static void
+test_wrong_phase2_password_keeps_data (const char *path, const char *password)
+{
+	NMSetting8021x *s_8021x;
+	gboolean success;
+	NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+	GError *error = NULL;
+	const char *pw;
+
+	s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
+	ASSERT (s_8021x != NULL, "wrong-phase2-password-keeps-data", "setting was NULL");
+
+	success = nm_setting_802_1x_set_phase2_private_key (s_8021x,
+	                                                    path,
+	                                                    password,
+	                                                    NM_SETTING_802_1X_CK_SCHEME_BLOB,
+	                                                    &format,
+	                                                    &error);
+	ASSERT (success == TRUE,
+	        "wrong-phase2-password-keeps-data", "error reading private key: %s", error->message);
+	ASSERT (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN,
+	        "wrong-phase2-password-keeps-data", "unexpected private key format (got %d)", format);
+
+	/* Now try to set it to something that's not a certificate */
+	format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+	success = nm_setting_802_1x_set_phase2_private_key (s_8021x,
+	                                                    "Makefile.am",
+	                                                    password,
+	                                                    NM_SETTING_802_1X_CK_SCHEME_BLOB,
+	                                                    &format,
+	                                                    &error);
+	ASSERT (success == FALSE,
+	        "wrong-phase2-password-keeps-data", "unexpected success reading private key");
+	ASSERT (error != NULL,
+	        "wrong-phase2-password-keeps-data", "unexpected missing error");
+	ASSERT (format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN,
+	        "wrong-phase2-password-keeps-data", "unexpected success reading private key format");
+
+	/* Make sure the password hasn't changed */
+	pw = nm_setting_802_1x_get_phase2_private_key_password (s_8021x);
+	ASSERT (pw != NULL,
+	        "wrong-phase2-password-keeps-data", "failed to get previous private key password");
+	ASSERT (strcmp (pw, password) == 0,
+	        "wrong-phase2-password-keeps-data", "failed to compare private key password");
+
+	g_object_unref (s_8021x);
+}
+
+static void
+test_clear_phase2_private_key (const char *path, const char *password)
+{
+	NMSetting8021x *s_8021x;
+	gboolean success;
+	NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+	GError *error = NULL;
+	const char *pw;
+
+	s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
+	ASSERT (s_8021x != NULL, "clear-phase2-private-key", "setting was NULL");
+
+	success = nm_setting_802_1x_set_phase2_private_key (s_8021x,
+	                                                    path,
+	                                                    password,
+	                                                    NM_SETTING_802_1X_CK_SCHEME_BLOB,
+	                                                    &format,
+	                                                    &error);
+	ASSERT (success == TRUE,
+	        "clear-phase2-private-key", "error reading private key: %s", error->message);
+	ASSERT (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN,
+	        "clear-phase2-private-key", "unexpected private key format (got %d)", format);
+
+	/* Make sure the password is what we expect */
+	pw = nm_setting_802_1x_get_phase2_private_key_password (s_8021x);
+	ASSERT (pw != NULL,
+	        "clear-phase2-private-key", "failed to get previous private key password");
+	ASSERT (strcmp (pw, password) == 0,
+	        "clear-phase2-private-key", "failed to compare private key password");
+
+	/* Now clear it */
+	success = nm_setting_802_1x_set_phase2_private_key (s_8021x,
+	                                                    NULL,
+	                                                    NULL,
+	                                                    NM_SETTING_802_1X_CK_SCHEME_BLOB,
+	                                                    NULL,
+	                                                    &error);
+	ASSERT (success == TRUE,
+	        "clear-phase2-private-key", "unexpected failure clearing private key");
+	ASSERT (error == NULL,
+	        "clear-phase2-private-key", "unexpected error clearing private key");
+
+	/* Ensure the password is also now clear */
+	ASSERT (nm_setting_802_1x_get_phase2_private_key_password (s_8021x) == NULL,
+	        "clear-phase2-private-key", "unexpected private key password");
+
+	g_object_unref (s_8021x);
+}
+
+static void
+do_8021x_test (gconstpointer test_data)
+{
+	char **parts, *path, *password;
+
+	parts = g_strsplit ((const char *) test_data, ", ", -1);
+	g_assert_cmpint (g_strv_length (parts), ==, 2);
+
+	path = g_build_filename (TEST_CERT_DIR, parts[0], NULL);
+	password = parts[1];
+
+	/* Test phase1 and phase2 path scheme */
+	test_private_key_import (path, password, NM_SETTING_802_1X_CK_SCHEME_PATH);
+	test_phase2_private_key_import (path, password, NM_SETTING_802_1X_CK_SCHEME_PATH);
+
+	/* Test phase1 and phase2 blob scheme */
+	test_private_key_import (path, password, NM_SETTING_802_1X_CK_SCHEME_BLOB);
+	test_phase2_private_key_import (path, password, NM_SETTING_802_1X_CK_SCHEME_BLOB);
+
+	/* Test that using a wrong password does not change existing data */
+	test_wrong_password_keeps_data (path, password);
+	test_wrong_phase2_password_keeps_data (path, password);
+
+	/* Test clearing the private key */
+	test_clear_private_key (path, password);
+	test_clear_phase2_private_key (path, password);
+
+	g_free (path);
+	g_strfreev (parts);
+}
+
+NMTST_DEFINE ();
+
+int
+main (int argc, char **argv)
+{
+	nmtst_init (&argc, &argv, TRUE);
+
+	g_test_add_data_func ("/libnm/setting-8021x/key-and-cert",
+	                      "test_key_and_cert.pem, test",
+	                      do_8021x_test);
+	g_test_add_data_func ("/libnm/setting-8021x/key-only",
+	                      "test-key-only.pem, test",
+	                      do_8021x_test);
+	g_test_add_data_func ("/libnm/setting-8021x/pkcs8-enc-key",
+	                      "pkcs8-enc-key.pem, 1234567890",
+	                      do_8021x_test);
+	g_test_add_data_func ("/libnm/setting-8021x/pkcs12",
+	                      "test-cert.p12, test",
+	                      do_8021x_test);
+
+	return g_test_run ();
+}
+
diff --git a/libnm-core/tests/test-setting-dcb.c b/libnm-core/tests/test-setting-dcb.c
new file mode 100644
index 00000000..8adab8ce
--- /dev/null
+++ b/libnm-core/tests/test-setting-dcb.c
@@ -0,0 +1,326 @@
+/* -*- 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 2013 Red Hat, Inc.
+ *
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <string.h>
+#include <nm-utils.h>
+#include <nm-glib-compat.h>
+#include "nm-setting-dcb.h"
+#include "nm-connection.h"
+#include "nm-errors.h"
+
+#define DCB_FLAGS_ALL (NM_SETTING_DCB_FLAG_ENABLE | \
+                       NM_SETTING_DCB_FLAG_ADVERTISE | \
+                       NM_SETTING_DCB_FLAG_WILLING)
+
+static void
+test_dcb_flags_valid (void)
+{
+	NMSettingDcb *s_dcb;
+	GError *error = NULL;
+	gboolean success;
+	guint i;
+
+	s_dcb = (NMSettingDcb *) nm_setting_dcb_new ();
+	g_assert (s_dcb);
+
+	g_assert_cmpint (nm_setting_dcb_get_app_fcoe_flags (s_dcb), ==, 0);
+	g_assert_cmpint (nm_setting_dcb_get_app_iscsi_flags (s_dcb), ==, 0);
+	g_assert_cmpint (nm_setting_dcb_get_app_fip_flags (s_dcb), ==, 0);
+	g_assert_cmpint (nm_setting_dcb_get_priority_flow_control_flags (s_dcb), ==, 0);
+	g_assert_cmpint (nm_setting_dcb_get_priority_group_flags (s_dcb), ==, 0);
+
+	g_object_set (G_OBJECT (s_dcb),
+	              NM_SETTING_DCB_APP_FCOE_FLAGS, DCB_FLAGS_ALL,
+	              NM_SETTING_DCB_APP_ISCSI_FLAGS, DCB_FLAGS_ALL,
+	              NM_SETTING_DCB_APP_FIP_FLAGS, DCB_FLAGS_ALL,
+	              NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, DCB_FLAGS_ALL,
+	              NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, DCB_FLAGS_ALL,
+	              NULL);
+	/* Priority Group Bandwidth must total 100% */
+	for (i = 0; i < 7; i++)
+		nm_setting_dcb_set_priority_group_bandwidth (s_dcb, i, 12);
+	nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 7, 16);
+
+	success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	g_assert_cmpint (nm_setting_dcb_get_app_fcoe_flags (s_dcb), ==, DCB_FLAGS_ALL);
+	g_assert_cmpint (nm_setting_dcb_get_app_iscsi_flags (s_dcb), ==, DCB_FLAGS_ALL);
+	g_assert_cmpint (nm_setting_dcb_get_app_fip_flags (s_dcb), ==, DCB_FLAGS_ALL);
+	g_assert_cmpint (nm_setting_dcb_get_priority_flow_control_flags (s_dcb), ==, DCB_FLAGS_ALL);
+	g_assert_cmpint (nm_setting_dcb_get_priority_group_flags (s_dcb), ==, DCB_FLAGS_ALL);
+}
+
+#define TEST_FLAG(p, f, v) \
+{ \
+	/* GObject property min/max should ensure the property does not get set to \
+	 * the invalid value, so we ensure the value we just tried to set is 0 and \
+	 * that verify is successful since the property never got set. \
+	 */ \
+	g_object_set (G_OBJECT (s_dcb), p, v, NULL); \
+	g_assert_cmpint (f (s_dcb), ==, 0); \
+	success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); \
+	g_assert_no_error (error); \
+	g_assert (success); \
+}
+
+static void
+test_dcb_flags_invalid (void)
+{
+	NMSettingDcb *s_dcb;
+	GError *error = NULL;
+	gboolean success;
+
+	s_dcb = (NMSettingDcb *) nm_setting_dcb_new ();
+	g_assert (s_dcb);
+
+	g_test_expect_message ("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*");
+	TEST_FLAG (NM_SETTING_DCB_APP_FCOE_FLAGS, nm_setting_dcb_get_app_fcoe_flags, 0x332523);
+	g_test_assert_expected_messages ();
+
+	g_test_expect_message ("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*");
+	TEST_FLAG (NM_SETTING_DCB_APP_ISCSI_FLAGS, nm_setting_dcb_get_app_iscsi_flags, 0xFF);
+	g_test_assert_expected_messages ();
+
+	g_test_expect_message ("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*");
+	TEST_FLAG (NM_SETTING_DCB_APP_FIP_FLAGS, nm_setting_dcb_get_app_fip_flags, 0x1111);
+	g_test_assert_expected_messages ();
+
+	g_test_expect_message ("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*");
+	TEST_FLAG (NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, nm_setting_dcb_get_priority_flow_control_flags, G_MAXUINT32);
+	g_test_assert_expected_messages ();
+
+	g_test_expect_message ("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*");
+	TEST_FLAG (NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, nm_setting_dcb_get_priority_group_flags,
+	           (NM_SETTING_DCB_FLAG_ENABLE | NM_SETTING_DCB_FLAG_ADVERTISE | NM_SETTING_DCB_FLAG_WILLING) + 1);
+	g_test_assert_expected_messages ();
+}
+
+#define TEST_APP_PRIORITY(lcprop, ucprop, v) \
+{ \
+	g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_##ucprop##_FLAGS, NM_SETTING_DCB_FLAG_NONE, NULL); \
+ \
+	g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_##ucprop##_PRIORITY, v, NULL); \
+	g_assert_cmpint (nm_setting_dcb_get_app_##lcprop##_priority (s_dcb), ==, v); \
+ \
+	/* Assert that the setting is invalid while the app is disabled unless v is default */ \
+	success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); \
+	if (v >= 0) { \
+		g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); \
+		g_assert (success == FALSE); \
+	} else { \
+		g_assert_no_error (error); \
+		g_assert (success); \
+	} \
+	g_clear_error (&error); \
+ \
+	/* Set the enable flag and re-verify, this time it should be valid */ \
+	g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_##ucprop##_FLAGS, NM_SETTING_DCB_FLAG_ENABLE, NULL); \
+	success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); \
+	g_assert_no_error (error); \
+	g_assert (success); \
+ \
+	g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_##ucprop##_PRIORITY, 0, NULL); \
+}
+
+static void
+test_dcb_app_priorities (void)
+{
+	NMSettingDcb *s_dcb;
+	GError *error = NULL;
+	gboolean success;
+
+	s_dcb = (NMSettingDcb *) nm_setting_dcb_new ();
+	g_assert (s_dcb);
+
+	/* Defaults */
+	g_assert_cmpint (nm_setting_dcb_get_app_fcoe_priority (s_dcb), ==, -1);
+	g_assert_cmpint (nm_setting_dcb_get_app_iscsi_priority (s_dcb), ==, -1);
+	g_assert_cmpint (nm_setting_dcb_get_app_fip_priority (s_dcb), ==, -1);
+
+	TEST_APP_PRIORITY (fcoe, FCOE, 6);
+	TEST_APP_PRIORITY (iscsi, ISCSI, 5);
+	TEST_APP_PRIORITY (fip, FIP, 4);
+
+	TEST_APP_PRIORITY (fcoe, FCOE, -1);
+	TEST_APP_PRIORITY (iscsi, ISCSI, -1);
+	TEST_APP_PRIORITY (fip, FIP, -1);
+}
+
+#define TEST_PRIORITY_VALID(fn, id, val, flagsprop, verify) \
+{ \
+	/* Assert that setting the value gets the same value back out */ \
+	nm_setting_dcb_set_priority_##fn (s_dcb, id, val); \
+	g_assert_cmpint (nm_setting_dcb_get_priority_##fn (s_dcb, id), ==, val); \
+ \
+	if (verify) { \
+		if (val != 0) { \
+			/* Assert that verify fails because the flags do not include 'enabled' \
+			 * and a value has been set. \
+			 */ \
+			success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); \
+			g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); \
+			g_assert (success == FALSE); \
+			g_clear_error (&error); \
+		} \
+ \
+		/* Assert that adding the 'enabled' flag verifies the setting */ \
+		g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_##flagsprop##_FLAGS, NM_SETTING_DCB_FLAG_ENABLE, NULL); \
+		success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); \
+		g_assert_no_error (error); \
+		g_assert (success); \
+	} \
+ \
+	/* Reset everything */ \
+	g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_##flagsprop##_FLAGS, NM_SETTING_DCB_FLAG_NONE, NULL); \
+	nm_setting_dcb_set_priority_##fn (s_dcb, id, 0); \
+}
+
+/* If Priority Groups are enabled, PG bandwidth must equal 100% */
+#define SET_VALID_PRIORITY_GROUP_BANDWIDTH \
+{ \
+	guint x; \
+	for (x = 0; x < 7; x++) \
+		nm_setting_dcb_set_priority_group_bandwidth (s_dcb, x, 12); \
+	nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 7, 16); \
+}
+
+static void
+test_dcb_priorities_valid (void)
+{
+	NMSettingDcb *s_dcb;
+	GError *error = NULL;
+	gboolean success;
+	guint i;
+
+	s_dcb = (NMSettingDcb *) nm_setting_dcb_new ();
+	g_assert (s_dcb);
+
+	for (i = 0; i < 8; i++)
+		TEST_PRIORITY_VALID (flow_control, i, TRUE, FLOW_CONTROL, TRUE);
+
+	SET_VALID_PRIORITY_GROUP_BANDWIDTH
+	for (i = 0; i < 8; i++) {
+		TEST_PRIORITY_VALID (group_id, i, i, GROUP, TRUE);
+		TEST_PRIORITY_VALID (group_id, i, 7 - i, GROUP, TRUE);
+	}
+
+	/* Clear PG bandwidth from earlier tests */
+	for (i = 0; i < 8; i++)
+		nm_setting_dcb_set_priority_group_bandwidth (s_dcb, i, 0);
+
+	/* Priority Group Bandwidth must add up to 100% if enabled, which requires
+	 * some dancing for verifying individual values here.
+	 */
+	for (i = 0; i < 8; i++) {
+		guint other = 7 - (i % 8);
+
+		/* Set another priority group to the remaining bandwidth */
+		nm_setting_dcb_set_priority_group_bandwidth (s_dcb, other, 100 - i);
+		TEST_PRIORITY_VALID (group_bandwidth, i, i, GROUP, TRUE);
+
+		/* Set another priority group to the remaining bandwidth */
+		nm_setting_dcb_set_priority_group_bandwidth (s_dcb, other, 100 - (7 - i));
+		TEST_PRIORITY_VALID (group_bandwidth, i, 7 - i, GROUP, TRUE);
+
+		/* Clear remaining bandwidth */
+		nm_setting_dcb_set_priority_group_bandwidth (s_dcb, other, 0);
+	}
+
+	SET_VALID_PRIORITY_GROUP_BANDWIDTH
+	for (i = 0; i < 8; i++) {
+		TEST_PRIORITY_VALID (bandwidth, i, i, GROUP, TRUE);
+		TEST_PRIORITY_VALID (bandwidth, i, 7 - i, GROUP, TRUE);
+	}
+
+	SET_VALID_PRIORITY_GROUP_BANDWIDTH
+	for (i = 0; i < 8; i++)
+		TEST_PRIORITY_VALID (strict_bandwidth, i, TRUE, GROUP, TRUE);
+
+	SET_VALID_PRIORITY_GROUP_BANDWIDTH
+	for (i = 0; i < 8; i++) {
+		TEST_PRIORITY_VALID (traffic_class, i, i, GROUP, TRUE);
+		TEST_PRIORITY_VALID (traffic_class, i, 7 - i, GROUP, TRUE);
+	}
+}
+
+static void
+test_dcb_bandwidth_sums (void)
+{
+	NMSettingDcb *s_dcb;
+	GError *error = NULL;
+	gboolean success;
+
+	s_dcb = (NMSettingDcb *) nm_setting_dcb_new ();
+	g_assert (s_dcb);
+
+	/* Assert that setting the value gets the same value back out */
+	nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 0, 9);
+	nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 1, 10);
+	nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 2, 11);
+	nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 3, 12);
+	nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 4, 13);
+	nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 5, 14);
+	nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 6, 15);
+	nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 7, 16);
+
+	/* Assert verify success when sums total 100% */
+	g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, NM_SETTING_DCB_FLAG_ENABLE, NULL);
+	success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	/* Assert verify fails when sums do not total 100% */
+	nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 4, 20);
+	success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error);
+	g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
+	g_assert (success == FALSE);
+	g_clear_error (&error);
+}
+
+#define TPATH "/libnm/settings/dcb/"
+
+int
+main (int argc, char **argv)
+{
+	g_test_init (&argc, &argv, NULL);
+
+#if !GLIB_CHECK_VERSION (2, 35, 0)
+	g_type_init ();
+#endif
+
+#if !GLIB_CHECK_VERSION(2,34,0)
+	g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL);
+#endif
+
+	g_test_add_func (TPATH "flags-valid", test_dcb_flags_valid);
+	g_test_add_func (TPATH "flags-invalid", test_dcb_flags_invalid);
+	g_test_add_func (TPATH "app-priorities", test_dcb_app_priorities);
+	g_test_add_func (TPATH "priorities", test_dcb_priorities_valid);
+	g_test_add_func (TPATH "bandwidth-sums", test_dcb_bandwidth_sums);
+
+	return g_test_run ();
+}
+
diff --git a/libnm-core/tests/test-settings-defaults.c b/libnm-core/tests/test-settings-defaults.c
new file mode 100644
index 00000000..0e786187
--- /dev/null
+++ b/libnm-core/tests/test-settings-defaults.c
@@ -0,0 +1,133 @@
+/* -*- 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 2008 - 2011 Red Hat, Inc.
+ *
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <string.h>
+
+#include <nm-utils.h>
+
+#include "nm-setting-8021x.h"
+#include "nm-setting-cdma.h"
+#include "nm-setting-connection.h"
+#include "nm-setting-gsm.h"
+#include "nm-setting-ip4-config.h"
+#include "nm-setting-ip6-config.h"
+#include "nm-setting-ppp.h"
+#include "nm-setting-pppoe.h"
+#include "nm-setting-serial.h"
+#include "nm-setting-vpn.h"
+#include "nm-setting-wired.h"
+#include "nm-setting-wireless.h"
+#include "nm-setting-wireless-security.h"
+
+#include "nm-test-utils.h"
+
+static void
+test_defaults (GType type, const char *name)
+{
+	GParamSpec **property_specs;
+	guint n_property_specs;
+	GObject *setting;
+	int i;
+
+	setting = g_object_new (type, NULL);
+
+	property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs);
+	ASSERT (property_specs != NULL,
+	        name, "couldn't find property specs for object of type '%s'",
+	        g_type_name (G_OBJECT_TYPE (setting)));
+
+	for (i = 0; i < n_property_specs; i++) {
+		GParamSpec *prop_spec = property_specs[i];
+		GValue value = G_VALUE_INIT;
+		GValue defvalue = G_VALUE_INIT;
+		char *actual, *expected;
+		gboolean ok = FALSE;
+
+		/* Ignore non-fundamental types since they won't really have
+		 * defaults.
+		 */
+		if (!G_TYPE_IS_FUNDAMENTAL (prop_spec->value_type))
+			continue;
+
+		g_value_init (&value, prop_spec->value_type);
+		g_object_get_property (G_OBJECT (setting), prop_spec->name, &value);
+
+		g_value_init (&defvalue, prop_spec->value_type);
+		g_param_value_set_default (prop_spec, &defvalue);
+
+		actual = g_strdup_value_contents (&value);
+		expected = g_strdup_value_contents (&defvalue);
+
+		if (!strcmp (prop_spec->name, NM_SETTING_NAME)) {
+			/* 'name' is always the setting name, not the default value */
+			ok = !strcmp (nm_setting_get_name (NM_SETTING (setting)), name);
+			g_free (expected);
+			expected = g_strdup (name);
+		} else
+			ok = g_param_value_defaults (prop_spec, &value);
+
+		ASSERT (ok,
+		        name, "property '%s' value '%s' not the expected default value '%s'",
+		        prop_spec->name, actual, expected);
+
+		g_free (actual);
+		g_free (expected);
+		g_value_unset (&value);
+		g_value_unset (&defvalue);
+	}
+
+	g_free (property_specs);
+	g_object_unref (setting);
+}
+
+int
+main (int argc, char **argv)
+{
+	char *base;
+
+#if !GLIB_CHECK_VERSION (2, 35, 0)
+	g_type_init ();
+#endif
+
+	/* The tests */
+	test_defaults (NM_TYPE_SETTING_CONNECTION, NM_SETTING_CONNECTION_SETTING_NAME);
+	test_defaults (NM_TYPE_SETTING_802_1X, NM_SETTING_802_1X_SETTING_NAME);
+	test_defaults (NM_TYPE_SETTING_CDMA, NM_SETTING_CDMA_SETTING_NAME);
+	test_defaults (NM_TYPE_SETTING_GSM, NM_SETTING_GSM_SETTING_NAME);
+	test_defaults (NM_TYPE_SETTING_IP4_CONFIG, NM_SETTING_IP4_CONFIG_SETTING_NAME);
+	test_defaults (NM_TYPE_SETTING_IP6_CONFIG, NM_SETTING_IP6_CONFIG_SETTING_NAME);
+	test_defaults (NM_TYPE_SETTING_PPP, NM_SETTING_PPP_SETTING_NAME);
+	test_defaults (NM_TYPE_SETTING_PPPOE, NM_SETTING_PPPOE_SETTING_NAME);
+	test_defaults (NM_TYPE_SETTING_SERIAL, NM_SETTING_SERIAL_SETTING_NAME);
+	test_defaults (NM_TYPE_SETTING_VPN, NM_SETTING_VPN_SETTING_NAME);
+	test_defaults (NM_TYPE_SETTING_WIRED, NM_SETTING_WIRED_SETTING_NAME);
+	test_defaults (NM_TYPE_SETTING_WIRELESS, NM_SETTING_WIRELESS_SETTING_NAME);
+	test_defaults (NM_TYPE_SETTING_WIRELESS_SECURITY, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
+
+	base = g_path_get_basename (argv[0]);
+	fprintf (stdout, "%s: SUCCESS\n", base);
+	g_free (base);
+	return 0;
+}
+