summaryrefslogtreecommitdiff
path: root/usr/src/test/os-tests
diff options
context:
space:
mode:
authorRob Johnston <rob.johnston@joyent.com>2020-02-20 16:38:42 -0800
committerDan McDonald <danmcd@joyent.com>2020-04-03 15:03:01 -0400
commitc559157643fef9f9afb0414e00a3579407ba3052 (patch)
tree108a39e69361244fbd351d0ad1994bc50c3f6025 /usr/src/test/os-tests
parent3afb2a2ae94e9183977495f0d248b766e58e4016 (diff)
downloadillumos-gate-c559157643fef9f9afb0414e00a3579407ba3052.tar.gz
12330 libtopo: add support for directed graph based topologies
Portions contributed by: Kody Kantor <kody.kantor@joyent.com> Reviewed by: Robert Mustacchi <rm@fingolfin.org> Approved by: Dan McDonald <danmcd@joyent.com>
Diffstat (limited to 'usr/src/test/os-tests')
-rw-r--r--usr/src/test/os-tests/runfiles/default.run4
-rw-r--r--usr/src/test/os-tests/tests/Makefile1
-rw-r--r--usr/src/test/os-tests/tests/libtopo/Makefile58
-rw-r--r--usr/src/test/os-tests/tests/libtopo/digraph-test-in-badedge.xml46
-rw-r--r--usr/src/test/os-tests/tests/libtopo/digraph-test-in-badelement.xml42
-rw-r--r--usr/src/test/os-tests/tests/libtopo/digraph-test-in-badnum.xml42
-rw-r--r--usr/src/test/os-tests/tests/libtopo/digraph-test-in-badscheme.xml42
-rw-r--r--usr/src/test/os-tests/tests/libtopo/digraph-test-in.xml308
-rw-r--r--usr/src/test/os-tests/tests/libtopo/digraph-test.c380
9 files changed, 923 insertions, 0 deletions
diff --git a/usr/src/test/os-tests/runfiles/default.run b/usr/src/test/os-tests/runfiles/default.run
index 650f023d77..f3f7c14a0e 100644
--- a/usr/src/test/os-tests/runfiles/default.run
+++ b/usr/src/test/os-tests/runfiles/default.run
@@ -90,3 +90,7 @@ arch = i86pc
[/opt/os-tests/tests/uccid]
arch = i86pc
tests = ['atrparse']
+
+[/opt/os-tests/tests/libtopo]
+user = root
+tests = ['digraph-test']
diff --git a/usr/src/test/os-tests/tests/Makefile b/usr/src/test/os-tests/tests/Makefile
index f923125d5e..37c9a2029f 100644
--- a/usr/src/test/os-tests/tests/Makefile
+++ b/usr/src/test/os-tests/tests/Makefile
@@ -19,6 +19,7 @@ SUBDIRS_i386 = i386 imc
SUBDIRS = \
ddi_ufm \
file-locking \
+ libtopo \
pf_key \
poll \
sdevfs \
diff --git a/usr/src/test/os-tests/tests/libtopo/Makefile b/usr/src/test/os-tests/tests/libtopo/Makefile
new file mode 100644
index 0000000000..8b7fe43bb7
--- /dev/null
+++ b/usr/src/test/os-tests/tests/libtopo/Makefile
@@ -0,0 +1,58 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2020 Joyent, Inc.
+#
+
+include $(SRC)/Makefile.master
+
+ROOTOPTPKG = $(ROOT)/opt/os-tests
+TESTDIR = $(ROOTOPTPKG)/tests/libtopo
+
+PROGS = digraph-test
+
+XML = digraph-test-in.xml \
+ digraph-test-in-badscheme.xml \
+ digraph-test-in-badnum.xml \
+ digraph-test-in-badedge.xml \
+ digraph-test-in-badelement.xml
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+LDLIBS += -L$(ROOT)/usr/lib/fm -ltopo -R/usr/lib/fm
+CFLAGS += -I$(SRC)/lib/fm/topo/libtopo/
+CSTD= $(CSTD_GNU99)
+
+CMDS = $(PROGS:%=$(TESTDIR)/%)
+$(CMDS) := FILEMODE = 0555
+
+FILES = $(XML:%=$(TESTDIR)/%)
+$(FILES) := FILEMODE = 0444
+
+all: $(PROGS)
+
+install: all $(CMDS) $(FILES)
+
+clobber: clean
+ -$(RM) $(PROGS) $(FILES)
+
+clean:
+ -$(RM) *.o
+
+$(CMDS): $(TESTDIR) $(PROGS)
+
+$(TESTDIR):
+ $(INS.dir)
+
+$(TESTDIR)/%: %
+ $(INS.file)
diff --git a/usr/src/test/os-tests/tests/libtopo/digraph-test-in-badedge.xml b/usr/src/test/os-tests/tests/libtopo/digraph-test-in-badedge.xml
new file mode 100644
index 0000000000..db86874817
--- /dev/null
+++ b/usr/src/test/os-tests/tests/libtopo/digraph-test-in-badedge.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!DOCTYPE topology SYSTEM "/usr/share/lib/xml/dtd/digraph-topology.dtd.1">
+
+<!--
+ Copyright 2020 Joyent, Inc.
+
+-->
+
+<topo-digraph fmri-scheme='hc' nodename='test-nodename' os-version='test-os-version' product-id='test-product-id' timestamp='2019-12-20T01:51:26Z'>
+<vertices>
+<vertex name='node' instance='0x0' fmri='hc:///node=0'>
+
+ <nvpair name='property-groups' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='property-group-name' type='string' value='protocol' />
+ <nvpair name='property-values' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='property-name' type='string' value='resource' />
+ <nvpair name='property-type' type='uint32' value='9' />
+ <nvpair name='property-value' type='nvlist'>
+ <nvlist>
+ <nvpair name='scheme' type='string' value='hc' />
+ <nvpair name='version' type='uint8' value='0' />
+ <nvpair name='hc-list' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='hc-name' type='string' value='node' />
+ <nvpair name='hc-id' type='string' value='0' />
+ </nvlist>
+ </nvpair>
+ </nvlist>
+ </nvpair> <!-- property-value -->
+ </nvlist>
+ </nvpair> <!-- property-values -->
+ </nvlist>
+
+ </nvpair> <!-- property-groups -->
+
+ <outgoing-edges>
+ <!-- non-existent edge -->
+ <edge fmri='hc:///node=1' />
+ </outgoing-edges>
+
+</vertex>
+
+</vertices>
+</topo-digraph>
diff --git a/usr/src/test/os-tests/tests/libtopo/digraph-test-in-badelement.xml b/usr/src/test/os-tests/tests/libtopo/digraph-test-in-badelement.xml
new file mode 100644
index 0000000000..374bcc85cc
--- /dev/null
+++ b/usr/src/test/os-tests/tests/libtopo/digraph-test-in-badelement.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!DOCTYPE topology SYSTEM "/usr/share/lib/xml/dtd/digraph-topology.dtd.1">
+
+<!--
+ Copyright 2020 Joyent, Inc.
+
+-->
+
+<topo-digraph fmri-scheme='hc' nodename='test-nodename' os-version='test-os-version' product-id='test-product-id' timestamp='2019-12-20T01:51:26Z'>
+<vertices>
+<vertex name='node' instance='0x0' fmri='hc:///node=0'>
+
+ <nvpair name='property-groups' type='nvlist-array'>
+ <!-- DTD violation: bad element -->
+ <badelement>
+ <nvpair name='property-group-name' type='string' value='protocol' />
+ <nvpair name='property-values' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='property-name' type='string' value='resource' />
+ <nvpair name='property-type' type='uint32' value='9' />
+ <nvpair name='property-value' type='nvlist'>
+ <nvlist>
+ <nvpair name='scheme' type='string' value='hc' />
+ <nvpair name='version' type='uint8' value='0' />
+ <nvpair name='hc-list' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='hc-name' type='string' value='node' />
+ <nvpair name='hc-id' type='string' value='0' />
+ </nvlist>
+ </nvpair>
+ </nvlist>
+ </nvpair> <!-- property-value -->
+ </nvlist>
+ </nvpair> <!-- property-values -->
+ </nvlist>
+
+ </nvpair> <!-- property-groups -->
+
+</vertex>
+
+</vertices>
+</topo-digraph>
diff --git a/usr/src/test/os-tests/tests/libtopo/digraph-test-in-badnum.xml b/usr/src/test/os-tests/tests/libtopo/digraph-test-in-badnum.xml
new file mode 100644
index 0000000000..28f737dfb6
--- /dev/null
+++ b/usr/src/test/os-tests/tests/libtopo/digraph-test-in-badnum.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!DOCTYPE topology SYSTEM "/usr/share/lib/xml/dtd/digraph-topology.dtd.1">
+
+<!--
+ Copyright 2020 Joyent, Inc.
+
+-->
+
+<topo-digraph fmri-scheme='hc' nodename='test-nodename' os-version='test-os-version' product-id='test-product-id' timestamp='2019-12-20T01:51:26Z'>
+<vertices>
+<vertex name='node' instance='0x0' fmri='hc:///node=0'>
+
+ <nvpair name='property-groups' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='property-group-name' type='string' value='protocol' />
+ <nvpair name='property-values' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='property-name' type='string' value='resource' />
+ <!-- bad numeric value -->
+ <nvpair name='property-type' type='uint32' value='gdfgdfgdffg' />
+ <nvpair name='property-value' type='nvlist'>
+ <nvlist>
+ <nvpair name='scheme' type='string' value='hc' />
+ <nvpair name='version' type='uint8' value='0' />
+ <nvpair name='hc-list' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='hc-name' type='string' value='node' />
+ <nvpair name='hc-id' type='string' value='0' />
+ </nvlist>
+ </nvpair>
+ </nvlist>
+ </nvpair> <!-- property-value -->
+ </nvlist>
+ </nvpair> <!-- property-values -->
+ </nvlist>
+
+ </nvpair> <!-- property-groups -->
+
+</vertex>
+
+</vertices>
+</topo-digraph>
diff --git a/usr/src/test/os-tests/tests/libtopo/digraph-test-in-badscheme.xml b/usr/src/test/os-tests/tests/libtopo/digraph-test-in-badscheme.xml
new file mode 100644
index 0000000000..254519692d
--- /dev/null
+++ b/usr/src/test/os-tests/tests/libtopo/digraph-test-in-badscheme.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!DOCTYPE topology SYSTEM "/usr/share/lib/xml/dtd/digraph-topology.dtd.1">
+
+<!--
+ Copyright 2020 Joyent, Inc.
+
+-->
+
+<!-- invalid fmri-scheme value -->
+<topo-digraph fmri-scheme='badscheme' nodename='test-nodename' os-version='test-os-version' product-id='test-product-id' timestamp='2019-12-20T01:51:26Z'>
+<vertices>
+<vertex name='node' instance='0x0' fmri='hc:///node=0'>
+
+ <nvpair name='property-groups' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='property-group-name' type='string' value='protocol' />
+ <nvpair name='property-values' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='property-name' type='string' value='resource' />
+ <nvpair name='property-type' type='uint32' value='9' />
+ <nvpair name='property-value' type='nvlist'>
+ <nvlist>
+ <nvpair name='scheme' type='string' value='hc' />
+ <nvpair name='version' type='uint8' value='0' />
+ <nvpair name='hc-list' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='hc-name' type='string' value='node' />
+ <nvpair name='hc-id' type='string' value='0' />
+ </nvlist>
+ </nvpair>
+ </nvlist>
+ </nvpair> <!-- property-value -->
+ </nvlist>
+ </nvpair> <!-- property-values -->
+ </nvlist>
+
+ </nvpair> <!-- property-groups -->
+
+</vertex>
+
+</vertices>
+</topo-digraph>
diff --git a/usr/src/test/os-tests/tests/libtopo/digraph-test-in.xml b/usr/src/test/os-tests/tests/libtopo/digraph-test-in.xml
new file mode 100644
index 0000000000..679e1f834b
--- /dev/null
+++ b/usr/src/test/os-tests/tests/libtopo/digraph-test-in.xml
@@ -0,0 +1,308 @@
+<?xml version="1.0"?>
+<!DOCTYPE topology SYSTEM "/usr/share/lib/xml/dtd/digraph-topology.dtd.1">
+
+<!--
+ Copyright 2020 Joyent, Inc.
+
+ This XML represents a directed graph that looks like the following:
+
+ |===> node=2 ===
+ | |
+ node=0 ====> node=1 === |===> node=4 ==
+ | | |
+ |===> node=3 === |
+ ^ ^ |
+ node=5 | | |
+ | | |
+ node=6 ======================= ======================
+
+-->
+
+<topo-digraph fmri-scheme='hc' nodename='test-nodename' os-version='test-os-version' product-id='test-product-id' timestamp='2019-12-20T01:51:26Z'>
+<vertices>
+<vertex name='node' instance='0x0' fmri='hc:///node=0'>
+
+ <nvpair name='property-groups' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='property-group-name' type='string' value='test-pg-1' />
+ <nvpair name='property-values' type='nvlist-array'>
+
+ <nvlist>
+ <nvpair name='property-name' type='string' value='string-prop' />
+ <nvpair name='property-type' type='uint32' value='6' />
+ <nvpair name='property-value' type='string' value='blahblahblah' />
+ </nvlist>
+
+ <nvlist>
+ <nvpair name='property-name' type='string' value='uint64-array-prop' />
+ <nvpair name='property-type' type='uint32' value='13' />
+ <nvpair name='property-value' type='uint64-array'>
+ <nvpair value='0x1' />
+ <nvpair value='0x2' />
+ </nvpair>
+ </nvlist>
+
+ <nvlist>
+ <nvpair name='property-name' type='string' value='int64-array-prop' />
+ <nvpair name='property-type' type='uint32' value='12' />
+ <nvpair name='property-value' type='int64-array'>
+ <nvpair value='1' />
+ <nvpair value='2' />
+ </nvpair>
+ </nvlist>
+
+ <nvlist>
+ <nvpair name='property-name' type='string' value='uint32-array-prop' />
+ <nvpair name='property-type' type='uint32' value='11' />
+ <nvpair name='property-value' type='uint32-array'>
+ <nvpair value='1' />
+ <nvpair value='2' />
+ </nvpair>
+ </nvlist>
+
+ <nvlist>
+ <nvpair name='property-name' type='string' value='int32-array-prop' />
+ <nvpair name='property-type' type='uint32' value='10' />
+ <nvpair name='property-value' type='int32-array'>
+ <nvpair value='1' />
+ <nvpair value='2' />
+ </nvpair>
+ </nvlist>
+
+ <nvlist>
+ <nvpair name='property-name' type='string' value='uint64-prop' />
+ <nvpair name='property-type' type='uint32' value='5' />
+ <nvpair name='property-value' type='uint64' value='0x5003048023567a00' />
+ </nvlist>
+
+ <nvlist>
+ <nvpair name='property-name' type='string' value='uint32-prop' />
+ <nvpair name='property-type' type='uint32' value='3' />
+ <nvpair name='property-value' type='uint32' value='1' />
+ </nvlist>
+
+ </nvpair> <!-- property-values -->
+ </nvlist>
+ <nvlist>
+ <nvpair name='property-group-name' type='string' value='protocol' />
+ <nvpair name='property-values' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='property-name' type='string' value='resource' />
+ <nvpair name='property-type' type='uint32' value='9' />
+ <nvpair name='property-value' type='nvlist'>
+ <nvlist>
+ <nvpair name='scheme' type='string' value='hc' />
+ <nvpair name='version' type='uint8' value='0' />
+ <nvpair name='hc-list' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='hc-name' type='string' value='node' />
+ <nvpair name='hc-id' type='string' value='0' />
+ </nvlist>
+ </nvpair>
+ </nvlist>
+ </nvpair> <!-- property-value -->
+ </nvlist>
+ </nvpair> <!-- property-values -->
+ </nvlist>
+
+ </nvpair> <!-- property-groups -->
+ <outgoing-edges>
+ <edge fmri='hc:///node=1' />
+ </outgoing-edges>
+
+</vertex>
+
+<vertex name='node' instance='0x1' fmri='hc:///node=1'>
+
+ <nvpair name='property-groups' type='nvlist-array'>
+
+ <nvlist>
+ <nvpair name='property-group-name' type='string' value='protocol' />
+ <nvpair name='property-values' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='property-name' type='string' value='resource' />
+ <nvpair name='property-type' type='uint32' value='9' />
+ <nvpair name='property-value' type='nvlist'>
+ <nvlist>
+ <nvpair name='scheme' type='string' value='hc' />
+ <nvpair name='version' type='uint8' value='0' />
+ <nvpair name='hc-list' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='hc-name' type='string' value='node' />
+ <nvpair name='hc-id' type='string' value='1' />
+ </nvlist>
+ </nvpair>
+ </nvlist>
+ </nvpair> <!-- property-value -->
+ </nvlist>
+ </nvpair> <!-- property-values -->
+ </nvlist>
+ </nvpair> <!-- property-groups -->
+ <outgoing-edges>
+ <edge fmri='hc:///node=2' />
+ <edge fmri='hc:///node=3' />
+ </outgoing-edges>
+
+</vertex>
+
+<vertex name='node' instance='0x2' fmri='hc:///node=2'>
+
+ <nvpair name='property-groups' type='nvlist-array'>
+
+ <nvlist>
+ <nvpair name='property-group-name' type='string' value='protocol' />
+ <nvpair name='property-values' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='property-name' type='string' value='resource' />
+ <nvpair name='property-type' type='uint32' value='9' />
+ <nvpair name='property-value' type='nvlist'>
+ <nvlist>
+ <nvpair name='scheme' type='string' value='hc' />
+ <nvpair name='version' type='uint8' value='0' />
+ <nvpair name='hc-list' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='hc-name' type='string' value='node' />
+ <nvpair name='hc-id' type='string' value='2' />
+ </nvlist>
+ </nvpair>
+ </nvlist>
+ </nvpair> <!-- property-value -->
+ </nvlist>
+ </nvpair> <!-- property-values -->
+ </nvlist>
+
+ </nvpair> <!-- property-groups -->
+ <outgoing-edges>
+ <edge fmri='hc:///node=4' />
+ </outgoing-edges>
+
+</vertex>
+
+<vertex name='node' instance='0x3' fmri='hc:///node=3'>
+
+ <nvpair name='property-groups' type='nvlist-array'>
+
+ <nvlist>
+ <nvpair name='property-group-name' type='string' value='protocol' />
+ <nvpair name='property-values' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='property-name' type='string' value='resource' />
+ <nvpair name='property-type' type='uint32' value='9' />
+ <nvpair name='property-value' type='nvlist'>
+ <nvlist>
+ <nvpair name='scheme' type='string' value='hc' />
+ <nvpair name='version' type='uint8' value='0' />
+ <nvpair name='hc-list' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='hc-name' type='string' value='node' />
+ <nvpair name='hc-id' type='string' value='3' />
+ </nvlist>
+ </nvpair>
+ </nvlist>
+ </nvpair> <!-- property-value -->
+ </nvlist>
+ </nvpair> <!-- property-values -->
+ </nvlist>
+
+ </nvpair> <!-- property-groups -->
+ <outgoing-edges>
+ <edge fmri='hc:///node=4' />
+ </outgoing-edges>
+
+</vertex>
+
+<vertex name='node' instance='0x4' fmri='hc:///node=4'>
+
+ <nvpair name='property-groups' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='property-group-name' type='string' value='protocol' />
+ <nvpair name='property-values' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='property-name' type='string' value='resource' />
+ <nvpair name='property-type' type='uint32' value='9' />
+ <nvpair name='property-value' type='nvlist'>
+ <nvlist>
+ <nvpair name='scheme' type='string' value='hc' />
+ <nvpair name='version' type='uint8' value='0' />
+ <nvpair name='hc-list' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='hc-name' type='string' value='node' />
+ <nvpair name='hc-id' type='string' value='4' />
+ </nvlist>
+ </nvpair>
+ </nvlist>
+ </nvpair> <!-- property-value -->
+ </nvlist>
+ </nvpair> <!-- property-values -->
+ </nvlist>
+
+ </nvpair> <!-- property-groups -->
+ <outgoing-edges>
+ <edge fmri='hc:///node=3' />
+ </outgoing-edges>
+
+</vertex>
+
+<vertex name='node' instance='0x5' fmri='hc:///node=5'>
+
+ <nvpair name='property-groups' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='property-group-name' type='string' value='protocol' />
+ <nvpair name='property-values' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='property-name' type='string' value='resource' />
+ <nvpair name='property-type' type='uint32' value='9' />
+ <nvpair name='property-value' type='nvlist'>
+ <nvlist>
+ <nvpair name='scheme' type='string' value='hc' />
+ <nvpair name='version' type='uint8' value='0' />
+ <nvpair name='hc-list' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='hc-name' type='string' value='node' />
+ <nvpair name='hc-id' type='string' value='5' />
+ </nvlist>
+ </nvpair>
+ </nvlist>
+ </nvpair> <!-- property-value -->
+ </nvlist>
+ </nvpair> <!-- property-values -->
+ </nvlist>
+
+ </nvpair> <!-- property-groups -->
+
+</vertex>
+
+<vertex name='node' instance='0x6' fmri='hc:///node=6'>
+
+ <nvpair name='property-groups' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='property-group-name' type='string' value='protocol' />
+ <nvpair name='property-values' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='property-name' type='string' value='resource' />
+ <nvpair name='property-type' type='uint32' value='9' />
+ <nvpair name='property-value' type='nvlist'>
+ <nvlist>
+ <nvpair name='scheme' type='string' value='hc' />
+ <nvpair name='version' type='uint8' value='0' />
+ <nvpair name='hc-list' type='nvlist-array'>
+ <nvlist>
+ <nvpair name='hc-name' type='string' value='node' />
+ <nvpair name='hc-id' type='string' value='6' />
+ </nvlist>
+ </nvpair>
+ </nvlist>
+ </nvpair> <!-- property-value -->
+ </nvlist>
+ </nvpair> <!-- property-values -->
+ </nvlist>
+
+ </nvpair> <!-- property-groups -->
+ <outgoing-edges>
+ <edge fmri='hc:///node=3' />
+ </outgoing-edges>
+
+</vertex>
+
+</vertices>
+</topo-digraph>
diff --git a/usr/src/test/os-tests/tests/libtopo/digraph-test.c b/usr/src/test/os-tests/tests/libtopo/digraph-test.c
new file mode 100644
index 0000000000..b829f0bb8f
--- /dev/null
+++ b/usr/src/test/os-tests/tests/libtopo/digraph-test.c
@@ -0,0 +1,380 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2020 Joyent, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libnvpair.h>
+#include <string.h>
+#include <stropts.h>
+#include <unistd.h>
+#include <fm/libtopo.h>
+#include <sys/debug.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/varargs.h>
+
+
+#define TEST_HOME "/opt/os-tests/tests/libtopo/"
+#define TEST_XML_IN "digraph-test-in.xml"
+#define TEST_XML_IN_BADSCHEME "digraph-test-in-badscheme.xml"
+#define TEST_XML_IN_BADNUM "digraph-test-in-badnum.xml"
+#define TEST_XML_IN_BADEDGE "digraph-test-in-badedge.xml"
+#define TEST_XML_IN_BADELEMENT "digraph-test-in-badelement.xml"
+#define TEST_GRAPH_SZ 7
+#define TEST_XML_OUT_DIR "/var/tmp"
+#define TEST_XML_OUT_PREFIX "digraph-test-out"
+
+static const char *pname;
+
+extern int topo_hdl_errno(topo_hdl_t *);
+
+/*
+ * Generate an ISO 8601 timestamp
+ */
+static void
+get_timestamp(char *buf, size_t bufsize)
+{
+ time_t utc_time;
+ struct tm *p_tm;
+
+ (void) time(&utc_time);
+ p_tm = localtime(&utc_time);
+
+ (void) strftime(buf, bufsize, "%FT%TZ", p_tm);
+}
+
+/* PRINTFLIKE1 */
+static void
+logmsg(const char *format, ...)
+{
+ char timestamp[128];
+ va_list ap;
+
+ get_timestamp(timestamp, sizeof (timestamp));
+ (void) fprintf(stdout, "%s ", timestamp);
+ va_start(ap, format);
+ (void) vfprintf(stdout, format, ap);
+ va_end(ap);
+ (void) fprintf(stdout, "\n");
+ (void) fflush(stdout);
+}
+
+static topo_digraph_t *
+test_deserialize(topo_hdl_t *thp, const char *path)
+{
+ struct stat statbuf = { 0 };
+ char *buf = NULL;
+ int fd = -1;
+ topo_digraph_t *tdg = NULL;
+
+ logmsg("\tOpening test XML topology");
+ if ((fd = open(path, O_RDONLY)) < 0) {
+ logmsg("\tfailed to open %s (%s)", path, strerror(errno));
+ goto out;
+ }
+ if (fstat(fd, &statbuf) != 0) {
+ logmsg("\tfailed to stat %s (%s)", path, strerror(errno));
+ goto out;
+ }
+ if ((buf = malloc(statbuf.st_size)) == NULL) {
+ logmsg("\tfailed to alloc read buffer: (%s)", strerror(errno));
+ goto out;
+ }
+ if (read(fd, buf, statbuf.st_size) != statbuf.st_size) {
+ logmsg("\tfailed to read file: (%s)", strerror(errno));
+ goto out;
+ }
+
+ logmsg("\tDeserializing XML topology");
+ tdg = topo_digraph_deserialize(thp, buf, statbuf.st_size);
+ if (tdg == NULL) {
+ logmsg("\ttopo_digraph_deserialize() failed!");
+ goto out;
+ }
+ logmsg("\ttopo_digraph_deserialize() succeeded");
+out:
+ free(buf);
+ if (fd > 0) {
+ (void) close(fd);
+ }
+ return (tdg);
+}
+
+struct cb_arg {
+ topo_vertex_t **vertices;
+};
+
+static int
+test_paths_cb(topo_hdl_t *thp, topo_vertex_t *vtx, boolean_t last_vtx,
+ void *arg)
+{
+ struct cb_arg *cbarg = arg;
+ uint_t idx = topo_node_instance(topo_vertex_node(vtx));
+
+ cbarg->vertices[idx] = vtx;
+
+ return (TOPO_WALK_NEXT);
+}
+
+static int
+test_paths(topo_hdl_t *thp, topo_digraph_t *tdg)
+{
+ topo_vertex_t *vertices[TEST_GRAPH_SZ];
+ struct cb_arg cbarg = { 0 };
+ int ret = -1;
+ topo_path_t **paths;
+ uint_t np;
+
+ cbarg.vertices = vertices;
+ if (topo_vertex_iter(thp, tdg, test_paths_cb, &cbarg) != 0) {
+ logmsg("\tfailed to iterate over graph vertices");
+ goto out;
+ }
+
+ logmsg("\tCalculating number of paths between node 0 and node 4");
+ if (topo_digraph_paths(thp, tdg, vertices[0], vertices[4], &paths,
+ &np) < 0) {
+ logmsg("\ttopo_digraph_paths() failed");
+ goto out;
+ }
+ if (np != 2) {
+ logmsg("\t%d paths found (expected 2)", np);
+ goto out;
+ }
+ for (uint_t i = 0; i < np; i++) {
+ topo_path_destroy(thp, paths[i]);
+ }
+ topo_hdl_free(thp, paths, np * sizeof (topo_path_t *));
+
+ logmsg("\tCalculating number of paths between node 6 and node 4");
+ if (topo_digraph_paths(thp, tdg, vertices[6], vertices[4], &paths,
+ &np) < 0) {
+ logmsg("\ttopo_digraph_paths() failed");
+ goto out;
+ }
+ if (np != 1) {
+ logmsg("\t%d paths found (expected 1)", np);
+ goto out;
+ }
+ for (uint_t i = 0; i < np; i++) {
+ topo_path_destroy(thp, paths[i]);
+ }
+ topo_hdl_free(thp, paths, np * sizeof (topo_path_t *));
+
+ logmsg("\tCalculating number of paths between node 5 and node 1");
+ if (topo_digraph_paths(thp, tdg, vertices[5], vertices[1], &paths,
+ &np) < 0) {
+ logmsg("\ttopo_digraph_paths() failed");
+ goto out;
+ }
+ if (np != 0) {
+ logmsg("\t%d paths found (expected 0)", np);
+ goto out;
+ }
+ ret = 0;
+
+out:
+ if (np > 0) {
+ for (uint_t i = 0; i < np; i++) {
+ topo_path_destroy(thp, paths[i]);
+ }
+ topo_hdl_free(thp, paths, np * sizeof (topo_path_t *));
+ }
+ return (ret);
+}
+
+static int
+test_serialize(topo_hdl_t *thp, topo_digraph_t *tdg, const char *path)
+{
+ FILE *xml_out;
+
+ if ((xml_out = fopen(path, "w")) == NULL) {
+ logmsg("\tfailed to open %s for writing (%s)",
+ strerror(errno));
+ return (-1);
+ }
+ logmsg("\tSerializing topology to XML (%s)", path);
+ if (topo_digraph_serialize(thp, tdg, xml_out) != 0) {
+ logmsg("\ttopo_digraph_serialize() failed!");
+ (void) fclose(xml_out);
+ return (-1);
+ }
+ (void) fclose(xml_out);
+ return (0);
+}
+
+int
+main(int argc, char **argv)
+{
+ topo_hdl_t *thp = NULL;
+ topo_digraph_t *tdg;
+ char *root = "/", *out_path = NULL;
+ boolean_t abort_on_exit = B_FALSE;
+ int err, status = EXIT_FAILURE;
+
+ pname = argv[0];
+
+ /*
+ * Setting DIGRAPH_TEST_CORE causes us to abort and dump core before
+ * exiting. This is useful for examining for memory leaks.
+ */
+ if (getenv("DIGRAPH_TEST_CORE") != NULL) {
+ abort_on_exit = B_TRUE;
+ }
+
+ logmsg("Opening libtopo");
+ if ((thp = topo_open(TOPO_VERSION, root, &err)) == NULL) {
+ logmsg("failed to get topo handle: %s", topo_strerror(err));
+ goto out;
+ }
+
+ logmsg("TEST: Deserialize directed graph topology");
+ if ((tdg = test_deserialize(thp, TEST_HOME TEST_XML_IN)) == NULL) {
+ logmsg("FAIL");
+ goto out;
+ }
+ logmsg("PASS");
+
+ logmsg("TEST: Serialize directed graph topology");
+ if ((out_path = tempnam(TEST_XML_OUT_DIR, TEST_XML_OUT_PREFIX)) ==
+ NULL) {
+ logmsg("\tFailed to create temporary file name under %s (%s)",
+ TEST_XML_OUT_DIR, strerror(errno));
+ logmsg("FAIL");
+ goto out;
+ }
+ if (test_serialize(thp, tdg, out_path) != 0) {
+ logmsg("FAIL");
+ goto out;
+ }
+ logmsg("PASS");
+
+ logmsg("Closing libtopo");
+ topo_close(thp);
+
+ logmsg("Reopening libtopo");
+ if ((thp = topo_open(TOPO_VERSION, root, &err)) == NULL) {
+ logmsg("failed to get topo handle: %s", topo_strerror(err));
+ goto out;
+ }
+
+ logmsg("TEST: Deserialize directed graph topology (pass 2)");
+ if ((tdg = test_deserialize(thp, out_path)) == NULL) {
+ logmsg("FAIL");
+ goto out;
+ }
+ logmsg("PASS");
+
+ logmsg("TEST: Calculating paths between vertices");
+ if (test_paths(thp, tdg) != 0) {
+ logmsg("FAIL");
+ goto out;
+ }
+ logmsg("PASS");
+
+ logmsg("Closing libtopo");
+ topo_close(thp);
+
+ logmsg("Reopening libtopo");
+ if ((thp = topo_open(TOPO_VERSION, root, &err)) == NULL) {
+ logmsg("failed to get topo handle: %s", topo_strerror(err));
+ goto out;
+ }
+
+ /*
+ * The following tests attempt to deserialize XML files that either
+ * violate the DTD or contain invalid attribute values.
+ *
+ * The expection is that topo_digraph_deserialize() should fail
+ * gracefully (i.e. not segfault) and topo_errno should be set.
+ */
+ logmsg("TEST: Deserialize directed graph topology (bad scheme)");
+ if ((tdg = test_deserialize(thp, TEST_HOME TEST_XML_IN_BADSCHEME)) !=
+ NULL) {
+ logmsg("FAIL");
+ goto out;
+ } else if (topo_hdl_errno(thp) == 0) {
+ logmsg("\texpected topo_errno to be non-zero");
+ logmsg("FAIL");
+ goto out;
+ } else {
+ logmsg("PASS");
+ }
+
+ logmsg("TEST: Deserialize directed graph topology (bad number)");
+ if ((tdg = test_deserialize(thp, TEST_HOME TEST_XML_IN_BADNUM)) !=
+ NULL) {
+ logmsg("FAIL");
+ goto out;
+ } else if (topo_hdl_errno(thp) == 0) {
+ logmsg("\texpected topo_errno to be non-zero");
+ logmsg("FAIL");
+ goto out;
+ } else {
+ logmsg("PASS");
+ }
+
+ logmsg("TEST: Deserialize directed graph topology (bad edge)");
+ if ((tdg = test_deserialize(thp, TEST_HOME TEST_XML_IN_BADEDGE)) !=
+ NULL) {
+ logmsg("FAIL");
+ goto out;
+ } else if (topo_hdl_errno(thp) == 0) {
+ logmsg("\texpected topo_errno to be non-zero");
+ logmsg("FAIL");
+ goto out;
+ } else {
+ logmsg("PASS");
+ }
+
+ logmsg("TEST: Deserialize directed graph topology (bad element)");
+ if ((tdg = test_deserialize(thp, TEST_HOME TEST_XML_IN_BADELEMENT)) !=
+ NULL) {
+ logmsg("FAIL");
+ goto out;
+ } else if (topo_hdl_errno(thp) == 0) {
+ logmsg("\texpected topo_errno to be non-zero");
+ logmsg("FAIL");
+ goto out;
+ } else {
+ logmsg("PASS");
+ }
+
+ /*
+ * If any tests failed, we don't unlink the temp file, as its contents
+ * may be useful for root-causing the test failure.
+ */
+ if (unlink(out_path) != 0) {
+ logmsg("Failed to unlink temp file: %s (%s)", out_path,
+ strerror(errno));
+ }
+ status = EXIT_SUCCESS;
+out:
+ if (thp != NULL) {
+ topo_close(thp);
+ }
+ if (out_path != NULL) {
+ free(out_path);
+ }
+ logmsg("digraph tests %s",
+ status == EXIT_SUCCESS ? "passed" : "failed");
+
+ if (abort_on_exit) {
+ abort();
+ }
+ return (status);
+}