public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [tests/selinux] pr775-checkpolicy-revdeps: Add libsemanage sanity test
@ 2026-09-11 13:17 Jan Zarsky
  0 siblings, 0 replies; only message in thread
From: Jan Zarsky @ 2026-09-11 13:17 UTC (permalink / raw)
  To: git-commits

            A new commit has been pushed.

            Repo   : tests/selinux
            Branch : pr775-checkpolicy-revdeps
            Commit : 4a646221891f0d893e926fb79a243a3d1b74bbd8
            Author : Jan Zarsky <jzarsky@redhat.com>
            Date   : 2018-04-27T14:22:33+02:00
            Stats  : +10460/-0 in 32 file(s)
            URL    : https://src.fedoraproject.org/tests/selinux/c/4a646221891f0d893e926fb79a243a3d1b74bbd8?branch=pr775-checkpolicy-revdeps

            Log:
            Add libsemanage sanity test

This test suite written in CUnit aims for 100 % function coverage of
libsemanage API and provides basic sanity tests. All common uses of
libsemanage should be covered.

---
diff --git a/libsemanage/sanity-tests/Makefile b/libsemanage/sanity-tests/Makefile
new file mode 100644
index 0000000..23ef6ac
--- /dev/null
+++ b/libsemanage/sanity-tests/Makefile
@@ -0,0 +1,63 @@
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+#   Makefile of /CoreOS/libsemanage/Sanity/sanity-tests
+#   Description: Test libsemanage functions
+#   Author: Jan Zarsky <jzarsky@redhat.com>
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+#   Copyright (c) 2017 Red Hat, Inc.
+#
+#   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 of
+#   the License, 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, see http://www.gnu.org/licenses/.
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+export TEST=/CoreOS/libsemanage/Sanity/sanity-tests
+export TESTVERSION=1.0
+
+BUILT_FILES=
+
+FILES=$(METADATA) runtest.sh Makefile PURPOSE tests/
+
+.PHONY: all install download clean
+
+run: $(FILES) build
+	./runtest.sh
+
+build: $(BUILT_FILES)
+	test -x runtest.sh || chmod a+x runtest.sh
+
+clean:
+	rm -f *~ $(BUILT_FILES)
+
+
+include /usr/share/rhts/lib/rhts-make.include
+
+$(METADATA): Makefile
+	@echo "Owner:           Jan Zarsky <jzarsky@redhat.com>" > $(METADATA)
+	@echo "Name:            $(TEST)" >> $(METADATA)
+	@echo "TestVersion:     $(TESTVERSION)" >> $(METADATA)
+	@echo "Path:            $(TEST_DIR)" >> $(METADATA)
+	@echo "Description:     Test libsemanage functions" >> $(METADATA)
+	@echo "Type:            Sanity" >> $(METADATA)
+	@echo "TestTime:        60m" >> $(METADATA)
+	@echo "RunFor:          libsemanage" >> $(METADATA)
+	@echo "Requires:        libsemanage libsemanage-devel gcc CUnit CUnit-devel checkpolicy policycoreutils-python-utils" >> $(METADATA)
+	@echo "Priority:        Normal" >> $(METADATA)
+	@echo "License:         GPLv2+" >> $(METADATA)
+	@echo "Confidential:    no" >> $(METADATA)
+	@echo "Destructive:     no" >> $(METADATA)
+	@echo "Releases:        -RHEL4 -RHELClient5 -RHELServer5" >> $(METADATA)
+
+	rhts-lint $(METADATA)

diff --git a/libsemanage/sanity-tests/PURPOSE b/libsemanage/sanity-tests/PURPOSE
new file mode 100644
index 0000000..043b1cc
--- /dev/null
+++ b/libsemanage/sanity-tests/PURPOSE
@@ -0,0 +1,3 @@
+PURPOSE of /CoreOS/libsemanage/Sanity/sanity-tests
+Description: Test libsemanage functions
+Author: Jan Zarsky <jzarsky@redhat.com>

diff --git a/libsemanage/sanity-tests/runtest.sh b/libsemanage/sanity-tests/runtest.sh
new file mode 100755
index 0000000..0b1785b
--- /dev/null
+++ b/libsemanage/sanity-tests/runtest.sh
@@ -0,0 +1,71 @@
+#!/bin/bash
+# vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+#   runtest.sh of /CoreOS/libsemanage/Sanity/sanity-tests
+#   Description: Test libsemanage functions
+#   Author: Jan Zarsky <jzarsky@redhat.com>
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+#   Copyright (c) 2017 Red Hat, Inc.
+#
+#   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 of
+#   the License, 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, see http://www.gnu.org/licenses/.
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+# Include Beaker environment
+. /usr/bin/rhts-environment.sh || exit 1
+. /usr/share/beakerlib/beakerlib.sh || exit 1
+
+PACKAGE="libsemanage"
+
+rlJournalStart
+    rlPhaseStartSetup
+        rlRun "rlImport --all" || rlDie
+
+        rlRun "rlCheckMakefileRequires" || rlDie
+
+        VERS=$(rpm -q $PACKAGE | cut -f 2 -d '-')
+        VERS_MAJOR=$(echo $VERS | cut -f 1 -d '.')
+        VERS_MINOR=$(echo $VERS | cut -f 2 -d '.')
+        VERS_RELEASE=$(rpm -q $PACKAGE | cut -f 3 -d '-' | cut -f 1 -d '.')
+
+        rlRun "cd tests"
+
+        rlRun "make VERS_MAJOR=$VERS_MAJOR VERS_MINOR=$VERS_MINOR VERS_RELEASE=$VERS_RELEASE"
+
+        rlRun "./libsemanage-tests list > list"
+    rlPhaseEnd
+
+    for suite in $(cat list); do
+        rlPhaseStartTest "$suite"
+            rlRun "./libsemanage-tests suite $suite >rawoutput 2>erroutput" 0 "Run test suite $suite"
+
+            rlRun "cat rawoutput | sed 1,5d" 0 "stdout"
+            rlRun "cat erroutput" 0 "stderr"
+
+            rlRun "grep -v 'Run Summary:' rawoutput > output"
+
+            rlRun "! grep -i failed output" 0 "Fails"
+            rlRun "! grep -i error output" 0 "Errors"
+        rlPhaseEnd
+    done;
+
+    rlPhaseStartCleanup
+        rlRun "make clean"
+        rlRun "rm -f output rawoutput erroutput list"
+    rlPhaseEnd
+rlJournalPrintText
+rlJournalEnd

diff --git a/libsemanage/sanity-tests/tests/.gitignore b/libsemanage/sanity-tests/tests/.gitignore
new file mode 100644
index 0000000..f07111d
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/.gitignore
@@ -0,0 +1 @@
+libsemanage-tests

diff --git a/libsemanage/sanity-tests/tests/Makefile b/libsemanage/sanity-tests/tests/Makefile
new file mode 100644
index 0000000..d77a092
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/Makefile
@@ -0,0 +1,35 @@
+SOURCES = $(wildcard *.c)
+
+###########################################################################
+
+EXECUTABLE = libsemanage-tests
+CFLAGS += -g -Wall -Werror -std=gnu99
+LDFLAGS += -lcunit -lsemanage -lselinux
+OBJECTS = $(SOURCES:.c=.o) 
+
+ifdef VERS_MAJOR
+DEFINES += -D VERS_MAJOR=$(VERS_MAJOR)
+endif
+
+ifdef VERS_MINOR
+DEFINES += -D VERS_MINOR=$(VERS_MINOR)
+endif
+
+ifdef VERS_RELEASE
+DEFINES += -D VERS_RELEASE=$(VERS_RELEASE)
+endif
+
+all: $(EXECUTABLE) 
+
+$(EXECUTABLE): $(OBJECTS)
+	$(CC) $(OBJECTS) $(LIBS) $(LDFLAGS) -o $@
+
+%.o: %.c
+	$(CC) $(CFLAGS) $(DEFINES) -c $*.c -o $*.o
+
+clean distclean: 
+	rm -rf $(OBJECTS) $(EXECUTABLE)
+
+test: all 
+	./$(EXECUTABLE)
+

diff --git a/libsemanage/sanity-tests/tests/functions.c b/libsemanage/sanity-tests/tests/functions.c
new file mode 100644
index 0000000..5e62061
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/functions.c
@@ -0,0 +1,771 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <semanage/handle.h>
+#include <semanage/semanage.h>
+
+#include <CUnit/Basic.h>
+
+#include "functions.h"
+
+int result;
+
+semanage_handle_t *sh = NULL;
+
+void stderr_callback(void *varg, semanage_handle_t *sh, const char *fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+
+    vfprintf(stderr, fmt, args);
+
+    fprintf(stderr, "\n");
+
+    va_end(args);
+}
+
+void helper_handle_create(void) {
+    sh = semanage_handle_create();
+    
+    CU_ASSERT_PTR_NOT_NULL(sh);
+
+    semanage_msg_set_callback(sh, stderr_callback, NULL);
+}
+
+void helper_handle_destroy(void) {
+    semanage_handle_destroy(sh);
+}
+
+void helper_connect(void) {
+    CU_ASSERT(semanage_connect(sh) >= 0);
+}
+
+void helper_disconnect(void) {
+    CU_ASSERT(semanage_disconnect(sh) >= 0);
+}
+
+void helper_begin_transaction(void) {
+    CU_ASSERT(semanage_begin_transaction(sh) >= 0);
+}
+
+void helper_commit(void) {
+    CU_ASSERT(semanage_commit(sh) >= 0);
+}
+
+void setup_handle(level_t level) {
+    if (level >= SH_NULL)
+        sh = NULL;
+
+    if (level >= SH_HANDLE)
+        helper_handle_create();
+
+    if (level >= SH_CONNECT)
+        helper_connect();
+
+    if (level >= SH_TRANS)
+        helper_begin_transaction();
+}
+
+void cleanup_handle(level_t level) {
+    if (level >= SH_TRANS)
+        helper_commit();
+
+    if (level >= SH_CONNECT)
+        helper_disconnect();
+
+    if (level >= SH_HANDLE)
+        helper_handle_destroy();
+
+    if (level >= SH_NULL)
+        sh = NULL;
+}
+
+void setup_handle_invalid_store(level_t level) {
+    CU_ASSERT(level >= SH_HANDLE);
+
+    helper_handle_create();
+    
+    semanage_select_store(sh, "", SEMANAGE_CON_INVALID);
+
+    if (level >= SH_CONNECT)
+        helper_connect();
+
+    if (level >= SH_TRANS)
+        helper_begin_transaction();
+}
+
+int context_compare(semanage_context_t *con, const char *str) {
+    char *con_str = NULL;
+    int rc;
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(con);
+
+    CU_ASSERT(semanage_context_to_string(sh, con, &con_str) >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(con_str);
+
+    rc = strcmp(con_str, str);
+
+    free(con_str);
+    return rc;
+}
+
+semanage_seuser_t *get_seuser_nth(int index) {
+    int result;
+    semanage_seuser_t **records;
+    semanage_seuser_t *seuser;
+    unsigned int count;
+
+    if (index == I_NULL)
+        return NULL;
+
+    result = semanage_seuser_list(sh, &records, &count);
+    
+    CU_ASSERT_FATAL(result >= 0);
+    CU_ASSERT_FATAL(count >= index + 1);
+
+    seuser = records[index];
+
+    for (unsigned int i = 0; i < count; i++) {
+        if (i != index)
+            semanage_seuser_free(records[i]);
+    }
+
+    return seuser;
+}
+
+semanage_seuser_t *get_seuser_new() {
+    int result;
+    semanage_seuser_t *seuser;
+
+    result = semanage_seuser_create(sh, &seuser);
+    
+    CU_ASSERT_FATAL(result >= 0);
+
+    return seuser;
+}
+
+semanage_seuser_key_t *get_seuser_key_nth(int index) {
+    semanage_seuser_key_t *key;
+    semanage_seuser_t *seuser;
+    int result;
+
+    if (index == I_NULL)
+        return NULL;
+
+    seuser = get_seuser_nth(index);
+
+    result = semanage_seuser_key_extract(sh, seuser, &key);
+
+    CU_ASSERT_FATAL(result >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+
+    return key;
+}
+
+semanage_seuser_key_t *get_seuser_key_from_str(const char *str) {
+    semanage_seuser_key_t *key;
+    int result;
+
+    if (str == NULL)
+        return NULL;
+
+    result = semanage_seuser_key_create(sh, str, &key);
+
+    CU_ASSERT_FATAL(result >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+
+    return key;
+}
+
+void add_local_seuser(int seuser_index) {
+    semanage_seuser_t *seuser;
+    semanage_seuser_key_t *key = NULL;
+
+    CU_ASSERT_FATAL(seuser_index != I_NULL);
+
+    seuser = get_seuser_nth(seuser_index);
+
+    CU_ASSERT_FATAL(semanage_seuser_key_extract(sh, seuser, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+
+    CU_ASSERT_FATAL(semanage_seuser_modify_local(sh, key, seuser) >= 0);
+
+    semanage_seuser_key_free(key);
+    semanage_seuser_free(seuser);
+}
+
+void delete_local_seuser(int seuser_index) {
+    semanage_seuser_key_t *key = NULL;
+
+    CU_ASSERT_FATAL(seuser_index != I_NULL);
+
+    key = get_seuser_key_nth(seuser_index);
+
+    CU_ASSERT_FATAL(semanage_seuser_del_local(sh, key) >= 0);
+
+    semanage_seuser_key_free(key);
+}
+
+semanage_bool_t *get_bool_nth(int index) {
+    int result;
+    semanage_bool_t **records;
+    semanage_bool_t *boolean;
+    unsigned int count;
+
+    if (index == I_NULL)
+        return NULL;
+
+    result = semanage_bool_list(sh, &records, &count);
+    
+    CU_ASSERT_FATAL(result >= 0);
+    CU_ASSERT_FATAL(count >= index + 1);
+
+    boolean = records[index];
+
+    for (unsigned int i = 0; i < count; i++) {
+        if (i != index)
+            semanage_bool_free(records[i]);
+    }
+
+    return boolean;
+}
+
+semanage_bool_t *get_bool_new() {
+    int result;
+    semanage_bool_t *boolean;
+
+    result = semanage_bool_create(sh, &boolean);
+    
+    CU_ASSERT_FATAL(result >= 0);
+
+    return boolean;
+}
+
+semanage_bool_key_t *get_bool_key_nth(int index) {
+    semanage_bool_key_t *key;
+    semanage_bool_t *boolean;
+    int result;
+
+    if (index == I_NULL)
+        return NULL;
+
+    boolean = get_bool_nth(index);
+
+    result = semanage_bool_key_extract(sh, boolean, &key);
+
+    CU_ASSERT_FATAL(result >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+
+    return key;
+}
+
+semanage_bool_key_t *get_bool_key_from_str(const char *str) {
+    semanage_bool_key_t *key;
+    int result;
+
+    if (str == NULL)
+        return NULL;
+
+    result = semanage_bool_key_create(sh, str, &key);
+
+    CU_ASSERT_FATAL(result >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+
+    return key;
+}
+
+void add_local_bool(int bool_index) {
+    semanage_bool_t *boolean;
+    semanage_bool_key_t *key = NULL;
+
+    CU_ASSERT_FATAL(bool_index != I_NULL);
+
+    boolean = get_bool_nth(bool_index);
+
+    CU_ASSERT_FATAL(semanage_bool_key_extract(sh, boolean, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+
+    CU_ASSERT_FATAL(semanage_bool_modify_local(sh, key, boolean) >= 0);
+}
+
+void delete_local_bool(int bool_index) {
+    semanage_bool_key_t *key = NULL;
+
+    CU_ASSERT_FATAL(bool_index != I_NULL);
+
+    key = get_bool_key_nth(bool_index);
+
+    CU_ASSERT_FATAL(semanage_bool_del_local(sh, key) >= 0);
+}
+
+semanage_fcontext_t *get_fcontext_new() {
+    int result;
+    semanage_fcontext_t *fcontext;
+
+    result = semanage_fcontext_create(sh, &fcontext);
+    
+    CU_ASSERT_FATAL(result >= 0);
+
+    return fcontext;
+}
+
+semanage_fcontext_t *get_fcontext_nth(int index) {
+    int result;
+    semanage_fcontext_t **records;
+    semanage_fcontext_t *fcontext;
+    unsigned int count;
+
+    if (index == I_NULL)
+        return NULL;
+
+    result = semanage_fcontext_list(sh, &records, &count);
+    
+    CU_ASSERT_FATAL(result >= 0);
+    CU_ASSERT_FATAL(count >= index + 1);
+
+    fcontext = records[index];
+
+    for (unsigned int i = 0; i < count; i++) {
+        if (i != index)
+            semanage_fcontext_free(records[i]);
+    }
+
+    return fcontext;
+}
+
+semanage_fcontext_key_t *get_fcontext_key_nth(int index) {
+    semanage_fcontext_key_t *key;
+    semanage_fcontext_t *fcontext;
+    int result;
+
+    if (index == I_NULL)
+        return NULL;
+
+    fcontext = get_fcontext_nth(index);
+
+    result = semanage_fcontext_key_extract(sh, fcontext, &key);
+
+    CU_ASSERT_FATAL(result >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+
+    return key;
+}
+
+semanage_fcontext_key_t *get_fcontext_key_from_str(const char *str, int type) {
+    semanage_fcontext_key_t *key;
+    int result;
+
+    if (str == NULL)
+        return NULL;
+
+    result = semanage_fcontext_key_create(sh, str, type, &key);
+
+    CU_ASSERT_FATAL(result >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+
+    return key;
+}
+
+void add_local_fcontext(int fcontext_index) {
+    semanage_fcontext_t *fcontext;
+    semanage_fcontext_key_t *key = NULL;
+
+    CU_ASSERT_FATAL(fcontext_index != I_NULL);
+
+    fcontext = get_fcontext_nth(fcontext_index);
+
+    CU_ASSERT_FATAL(semanage_fcontext_key_extract(sh, fcontext, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+
+    CU_ASSERT_FATAL(semanage_fcontext_modify_local(sh, key, fcontext) >= 0);
+}
+
+void delete_local_fcontext(int fcontext_index) {
+    semanage_fcontext_key_t *key = NULL;
+
+    CU_ASSERT_FATAL(fcontext_index != I_NULL);
+
+    key = get_fcontext_key_nth(fcontext_index);
+
+    CU_ASSERT_FATAL(semanage_fcontext_del_local(sh, key) >= 0);
+}
+
+#if VERS_CHECK(2, 5)
+
+semanage_module_info_t *get_module_info_nth(int index, semanage_module_info_t **modinfo_free) {
+    int result;
+    semanage_module_info_t *records = NULL;
+    semanage_module_info_t *modinfo;
+    int count;
+
+    if (index == I_NULL)
+        return NULL;
+
+    result = semanage_module_list_all(sh, &records, &count);
+    
+    CU_ASSERT_FATAL(result >= 0);
+    CU_ASSERT_FATAL(records != NULL);
+    CU_ASSERT_FATAL(count >= index + 1);
+
+    modinfo = semanage_module_list_nth(records, index);
+
+    CU_ASSERT_FATAL(modinfo != NULL);
+
+    for (unsigned int i = 0; i < count; i++) {
+        if (i != index) {
+            semanage_module_info_t *tmp = semanage_module_list_nth(records, i);
+            semanage_module_info_destroy(sh, tmp);
+        }
+    }
+
+    *modinfo_free = records;
+
+    return modinfo;
+}
+
+semanage_module_key_t *get_module_key_nth(int index) {
+    semanage_module_key_t *modkey = NULL;
+    semanage_module_info_t *modinfo = NULL;
+    semanage_module_info_t *modinfo_free = NULL;
+    const char *name = NULL;
+    uint16_t priority = 0;
+
+    CU_ASSERT(semanage_module_key_create(sh, &modkey) >= 0);
+
+    modinfo = get_module_info_nth(index, &modinfo_free);
+
+    CU_ASSERT(semanage_module_info_get_name(sh, modinfo, &name) >= 0);
+    CU_ASSERT(semanage_module_key_set_name(sh, modkey, name) >= 0);
+
+    CU_ASSERT(semanage_module_info_get_priority(sh, modinfo, &priority) >= 0);
+    CU_ASSERT(semanage_module_key_set_priority(sh, modkey, priority) >= 0);
+
+    free(modinfo_free);
+
+    return modkey;
+}
+
+int module_exists(const char *name) {
+    const char *bools_path = "/sys/fs/selinux/booleans/";
+    char *path = NULL;
+    struct stat buf;
+
+    path = malloc(strlen(bools_path) + strlen(name) + 1);
+
+    CU_ASSERT_PTR_NOT_NULL(path);
+
+    strcpy(path, bools_path);
+    strcat(path, name);
+
+    if (stat(path, &buf) != 0) {
+        CU_ASSERT(errno == ENOENT);
+
+        return 0;
+    }
+    else {
+        return 1;
+    }
+}
+
+#endif
+
+semanage_port_t *get_port_nth(int index) {
+    int result;
+    semanage_port_t **records;
+    semanage_port_t *port;
+    unsigned int count;
+
+    if (index == I_NULL)
+        return NULL;
+
+    result = semanage_port_list(sh, &records, &count);
+    
+    CU_ASSERT_FATAL(result >= 0);
+    CU_ASSERT_FATAL(count >= index + 1);
+
+    port = records[index];
+
+    for (unsigned int i = 0; i < count; i++) {
+        if (i != index)
+            semanage_port_free(records[i]);
+    }
+
+    return port;
+}
+
+semanage_port_key_t *get_port_key_nth(int index) {
+    semanage_port_key_t *key;
+    semanage_port_t *port;
+    int result;
+
+    if (index == I_NULL)
+        return NULL;
+
+    port = get_port_nth(index);
+
+    result = semanage_port_key_extract(sh, port, &key);
+
+    CU_ASSERT_FATAL(result >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+
+    return key;
+}
+
+void add_local_port(int port_index) {
+    semanage_port_t *port;
+    semanage_port_key_t *key = NULL;
+
+    CU_ASSERT_FATAL(port_index != I_NULL);
+
+    port = get_port_nth(port_index);
+
+    CU_ASSERT_FATAL(semanage_port_key_extract(sh, port, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+
+    CU_ASSERT_FATAL(semanage_port_modify_local(sh, key, port) >= 0);
+}
+
+void delete_local_port(int port_index) {
+    semanage_port_key_t *key = NULL;
+
+    CU_ASSERT_FATAL(port_index != I_NULL);
+
+    key = get_port_key_nth(port_index);
+
+    CU_ASSERT_FATAL(semanage_port_del_local(sh, key) >= 0);
+}
+
+semanage_iface_t *get_iface() {
+    semanage_iface_t *iface = NULL;
+    semanage_context_t *ifcon = NULL;
+    semanage_context_t *msgcon = NULL;
+
+    CU_ASSERT_FATAL(semanage_iface_create(sh, &iface) >= 0);
+
+    CU_ASSERT_FATAL(semanage_iface_set_name(sh, iface, "asdf") >= 0);
+
+    CU_ASSERT_FATAL(semanage_context_from_string(sh, "system_u:object_r:tmp_t:s0", &ifcon) >= 0);
+    CU_ASSERT_FATAL(semanage_iface_set_ifcon(sh, iface, ifcon) >= 0);
+
+    CU_ASSERT_FATAL(semanage_context_from_string(sh, "system_u:object_r:tmp_t:s0", &msgcon) >= 0);
+    CU_ASSERT_FATAL(semanage_iface_set_msgcon(sh, iface, msgcon) >= 0);
+
+    return iface;
+}
+
+semanage_iface_key_t *get_iface_key() {
+    semanage_iface_key_t *key;
+
+    CU_ASSERT_FATAL(semanage_iface_key_create(sh, "asdf", &key) >= 0);
+
+    return key;
+}
+
+void add_local_iface(int index) {
+    semanage_iface_t *iface;
+    semanage_iface_key_t *key = NULL;
+    char name[50] = {};
+
+    snprintf(name, 50, "asdf%d", index);
+
+    iface = get_iface();
+
+    CU_ASSERT_FATAL(semanage_iface_set_name(sh, iface, name) >= 0);
+
+    CU_ASSERT_FATAL(semanage_iface_key_extract(sh, iface, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+
+    CU_ASSERT_FATAL(semanage_iface_modify_local(sh, key, iface) >= 0);
+}
+
+void delete_local_iface(int index) {
+    semanage_iface_key_t *key = NULL;
+    char name[50] = {};
+
+    snprintf(name, 50, "asdf%d", index);
+
+    CU_ASSERT_FATAL(semanage_iface_key_create(sh, name, &key) >= 0);
+
+    CU_ASSERT_FATAL(semanage_iface_del_local(sh, key) >= 0);
+}
+
+semanage_node_t *get_node() {
+    semanage_node_t *node = NULL;
+    semanage_context_t *con = NULL;
+
+    CU_ASSERT_FATAL(semanage_node_create(sh, &node) >= 0);
+
+    CU_ASSERT_FATAL(semanage_node_set_addr(sh, node, SEMANAGE_PROTO_IP4,
+                                           "127.0.0.1") >= 0);
+
+    CU_ASSERT_FATAL(semanage_node_set_mask(sh, node, SEMANAGE_PROTO_IP4,
+                                           "255.255.255.0") >= 0);
+
+    semanage_node_set_proto(node, SEMANAGE_PROTO_IP4);
+
+    CU_ASSERT_FATAL(semanage_context_from_string(sh,
+                                      "system_u:object_r:tmp_t:s0", &con) >= 0);
+    CU_ASSERT_FATAL(semanage_node_set_con(sh, node, con) >= 0);
+
+    return node;
+}
+
+semanage_node_key_t *get_node_key() {
+    semanage_node_key_t *key;
+
+    CU_ASSERT_FATAL(semanage_node_key_create(sh, "127.0.0.1", "255.255.255.0",
+                                             SEMANAGE_PROTO_IP4, &key) >= 0);
+
+    return key;
+}
+
+void add_local_node(int index) {
+    semanage_node_t *node;
+    semanage_node_key_t *key = NULL;
+    char addr[50] = {};
+
+    CU_ASSERT(index >= 0 && index <= 255);
+
+    snprintf(addr, 50, "192.168.0.%d", index);
+
+    node = get_node();
+
+    CU_ASSERT_FATAL(semanage_node_set_addr(sh, node, SEMANAGE_PROTO_IP4,
+                                           addr) >= 0);
+    CU_ASSERT_FATAL(semanage_node_set_mask(sh, node, SEMANAGE_PROTO_IP4,
+                                           "255.255.0.0") >= 0);
+
+    CU_ASSERT_FATAL(semanage_node_key_extract(sh, node, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+
+    CU_ASSERT_FATAL(semanage_node_modify_local(sh, key, node) >= 0);
+}
+
+void delete_local_node(int index) {
+    semanage_node_key_t *key = NULL;
+    char addr[50] = {};
+
+    CU_ASSERT(index >= 0 && index <= 255);
+
+    snprintf(addr, 50, "192.168.0.%d", index);
+
+    CU_ASSERT_FATAL(semanage_node_key_create(sh, addr, "255.255.0.0",
+                                             SEMANAGE_PROTO_IP4, &key) >= 0);
+
+    CU_ASSERT_FATAL(semanage_node_del_local(sh, key) >= 0);
+}
+
+semanage_user_t *get_user_nth(int index) {
+    int result;
+    semanage_user_t **records;
+    semanage_user_t *user;
+    unsigned int count;
+
+    if (index == I_NULL)
+        return NULL;
+
+    result = semanage_user_list(sh, &records, &count);
+    
+    CU_ASSERT_FATAL(result >= 0);
+    CU_ASSERT_FATAL(count >= index + 1);
+
+    user = records[index];
+
+    for (unsigned int i = 0; i < count; i++) {
+        if (i != index)
+            semanage_user_free(records[i]);
+    }
+
+    return user;
+}
+
+semanage_user_key_t *get_user_key_nth(int index) {
+    semanage_user_key_t *key;
+    semanage_user_t *user;
+    int result;
+
+    if (index == I_NULL)
+        return NULL;
+
+    user = get_user_nth(index);
+
+    result = semanage_user_key_extract(sh, user, &key);
+
+    CU_ASSERT_FATAL(result >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+
+    return key;
+}
+
+void add_local_user(int user_index) {
+    semanage_user_t *user;
+    semanage_user_key_t *key = NULL;
+
+    CU_ASSERT_FATAL(user_index != I_NULL);
+
+    user = get_user_nth(user_index);
+
+    CU_ASSERT_FATAL(semanage_user_key_extract(sh, user, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+
+    CU_ASSERT_FATAL(semanage_user_modify_local(sh, key, user) >= 0);
+}
+
+void delete_local_user(int user_index) {
+    semanage_user_key_t *key = NULL;
+
+    CU_ASSERT_FATAL(user_index != I_NULL);
+
+    key = get_user_key_nth(user_index);
+
+    CU_ASSERT_FATAL(semanage_user_del_local(sh, key) >= 0);
+}
+
+#ifdef FEATURE_INFINIBAND
+
+void add_local_ibendport(int index) {
+    semanage_ibendport_t *ibendport;
+    semanage_ibendport_key_t *key = NULL;
+    semanage_context_t *con = NULL;
+    char name[50];
+
+    CU_ASSERT(index >= 0 && index <= 255);
+
+    snprintf(name, 50, "ibendport%d", index);
+
+    CU_ASSERT_FATAL(semanage_ibendport_key_create(sh, name, 0, &key) >= 0);
+
+    CU_ASSERT_FATAL(semanage_ibendport_create(sh, &ibendport) >= 0);
+    CU_ASSERT_FATAL(semanage_ibendport_set_ibdev_name(sh, ibendport,
+                                                      name) >= 0);
+    semanage_ibendport_set_port(ibendport, 0);
+    CU_ASSERT_FATAL(semanage_context_from_string(sh,
+                                      "system_u:object_r:bin_t:s0", &con) >= 0);
+    CU_ASSERT_FATAL(semanage_ibendport_set_con(sh, ibendport, con) >= 0);
+
+    CU_ASSERT_FATAL(semanage_ibendport_modify_local(sh, key, ibendport) >= 0);
+
+    semanage_context_free(con);
+    semanage_ibendport_key_free(key);
+    semanage_ibendport_free(ibendport);
+}
+
+void delete_local_ibendport(int index) {
+    semanage_ibendport_key_t *key = NULL;
+    char name[50];
+
+    CU_ASSERT(index >= 0 && index <= 255);
+
+    snprintf(name, 50, "ibendport%d", index);
+
+    CU_ASSERT_FATAL(semanage_ibendport_key_create(sh, name, 0, &key) >= 0);
+
+    CU_ASSERT_FATAL(semanage_ibendport_del_local(sh, key) >= 0);
+
+    semanage_ibendport_key_free(key);
+}
+
+#endif

diff --git a/libsemanage/sanity-tests/tests/functions.h b/libsemanage/sanity-tests/tests/functions.h
new file mode 100644
index 0000000..94dc517
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/functions.h
@@ -0,0 +1,163 @@
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <semanage/handle.h>
+#include <semanage/semanage.h>
+
+#ifndef __FUNCTIONS_H__
+#define __FUNCTIONS_H__
+
+#if defined(VERS_MAJOR) && defined(VERS_MINOR)
+
+#define VERS_CHECK(major, minor) \
+    ((VERS_MAJOR > major) || ((VERS_MAJOR == major) && (VERS_MINOR >= minor)))
+
+#else
+
+#define VERS_CHECK(major, minor) 1
+
+#endif
+
+#if defined(VERS_MAJOR) && defined(VERS_MINOR) && defined(VERS_RELEASE)
+
+#define VERS_CHECK_REL(major, minor, release) \
+    ((VERS_MAJOR == major) && (VERS_MINOR == minor) && (VERS_RELEASE >= release))
+
+#else
+
+#define VERS_CHECK_REL(major, minor, release) 0
+
+#endif
+
+#if VERS_CHECK(2, 7) || VERS_CHECK_REL(2, 5, 9)
+#define FEATURE_INFINIBAND
+#endif
+
+typedef enum { SH_NULL, SH_HANDLE, SH_CONNECT, SH_TRANS } level_t;
+
+void setup_handle(level_t level);
+void cleanup_handle(level_t level);
+void setup_handle_invalid_store(level_t level);
+
+void helper_handle_create(void);
+void helper_handle_destroy(void);
+void helper_connect(void);
+void helper_disconnect(void);
+void helper_begin_transaction(void);
+void helper_commit(void);
+
+int context_compare(semanage_context_t *con, const char *str);
+
+// forks, runs code and checks signal returned by child process
+#define CU_ASSERT_SIGNAL(CODE,SIGNAL) \
+    do { \
+        pid_t pid = fork(); \
+        if (pid == 0) { \
+            CODE; \
+            exit(0); \
+        } else { \
+            int stat_val; \
+            wait(&stat_val); \
+            CU_ASSERT_FALSE(WIFEXITED(stat_val)); \
+            CU_ASSERT_EQUAL(WTERMSIG(stat_val), SIGNAL); \
+        } \
+    } while(0)
+
+#define CU_ASSERT_CONTEXT(CON1,CON2,EQUAL) \
+    do { \
+        char *str; \
+        char *str2; \
+        CU_ASSERT_PTR_NOT_NULL(CON1); \
+        CU_ASSERT_PTR_NOT_NULL(CON2); \
+        CU_ASSERT(semanage_context_to_string(sh, CON1, &str) >= 0); \
+        CU_ASSERT(semanage_context_to_string(sh, CON2, &str2) >= 0); \
+        if (EQUAL) {\
+            CU_ASSERT_STRING_EQUAL(str, str2); \
+        } else {\
+            CU_ASSERT_STRING_NOT_EQUAL(str, str2); \
+        } \
+    } while(0)
+
+#define CU_ASSERT_CONTEXT_EQUAL(CON1,CON2) CU_ASSERT_CONTEXT(CON1,CON2,1)
+#define CU_ASSERT_CONTEXT_NOT_EQUAL(CON1,CON2) CU_ASSERT_CONTEXT(CON1,CON2,0)
+
+#define I_NULL  -1
+#define I_FIRST  0
+#define I_SECOND 1
+#define I_THIRD  2
+
+// seusers
+semanage_seuser_t *get_seuser_nth(int index);
+semanage_seuser_t *get_seuser_new();
+
+semanage_seuser_key_t *get_seuser_key_nth(int index);
+semanage_seuser_key_t *get_seuser_key_from_str(const char *str);
+
+void add_local_seuser(int seuser_index);
+void delete_local_seuser(int seuser_index);
+
+// booleans
+semanage_bool_t *get_bool_nth(int index);
+semanage_bool_t *get_bool_new();
+
+semanage_bool_key_t *get_bool_key_nth(int index);
+semanage_bool_key_t *get_bool_key_from_str(const char *str);
+
+void add_local_bool(int bool_index);
+void delete_local_bool(int bool_index);
+
+// fcontext
+semanage_fcontext_t *get_fcontext_nth(int index);
+semanage_fcontext_t *get_fcontext_new();
+
+semanage_fcontext_key_t *get_fcontext_key_nth(int index);
+semanage_fcontext_key_t *get_fcontext_key_from_str(const char *str, int type);
+
+void add_local_fcontext(int fcontext_index);
+void delete_local_fcontext(int fcontext_index);
+
+// module
+#if VERS_CHECK(2, 5)
+semanage_module_info_t *get_module_info_nth(int index, semanage_module_info_t **modinfo_free);
+semanage_module_key_t *get_module_key_nth(int index);
+int module_exists(const char *name);
+#endif
+
+// port
+semanage_port_t *get_port_nth(int index);
+semanage_port_key_t *get_port_key_nth(int index);
+
+void add_local_port(int port_index);
+void delete_local_port(int port_index);
+
+// iface
+semanage_iface_t *get_iface();
+semanage_iface_key_t *get_iface_key();
+
+void add_local_iface(int index);
+void delete_local_iface(int index);
+
+// node
+
+semanage_node_t *get_node();
+semanage_node_key_t *get_node_key();
+
+void add_local_node(int index);
+void delete_local_node(int index);
+
+// user
+
+semanage_user_t *get_user_nth(int index);
+semanage_user_key_t *get_user_key_nth(int index);
+
+void add_local_user(int index);
+void delete_local_user(int index);
+
+// ibendport
+#ifdef FEATURE_INFINIBAND
+void add_local_ibendport(int index);
+void delete_local_ibendport(int index);
+#endif
+
+#endif

diff --git a/libsemanage/sanity-tests/tests/libsemanage-tests.c b/libsemanage/sanity-tests/tests/libsemanage-tests.c
new file mode 100644
index 0000000..ad3cc28
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/libsemanage-tests.c
@@ -0,0 +1,110 @@
+/* Authors: Christopher Ashworth <cashworth@tresys.com>
+ *          Caleb Case <ccase@tresys.com>
+ *          Chad Sellers <csellers@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ *  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.1 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdio.h>
+
+#include "test_handle.h"
+#include "test_seuser.h"
+#include "test_bool.h"
+#include "test_fcontext.h"
+#include "test_module.h"
+#include "test_port.h"
+#include "test_iface.h"
+#include "test_node.h"
+#include "test_other.h"
+#include "test_user.h"
+#include "test_ibendport.h"
+
+#include <CUnit/Basic.h>
+#include <CUnit/Console.h>
+#include <CUnit/TestDB.h>
+
+#define DECLARE_SUITE(name) \
+    suites[suite_index] = CU_add_suite(#name, name##_test_init, name##_test_cleanup); \
+    if (NULL == suites[suite_index]) { \
+        CU_cleanup_registry(); \
+        return CU_get_error(); } \
+    if (name##_add_tests(suites[suite_index])) { \
+        CU_cleanup_registry(); \
+        return CU_get_error(); } \
+    suites_names[suite_index] = #name; \
+    suite_index++;
+
+#define SUITE_NUM 11
+
+CU_pSuite suites[SUITE_NUM] = { NULL };
+const char *suites_names[SUITE_NUM] = { NULL };
+
+int suite_index = 0;
+
+int main(int argc, char **argv)
+{
+    if (CUE_SUCCESS != CU_initialize_registry())
+        return CU_get_error();
+
+    // when adding new suite, update SUITE_NUM and include header file
+    DECLARE_SUITE(handle);
+    DECLARE_SUITE(seuser);
+    DECLARE_SUITE(fcontext);
+    DECLARE_SUITE(module);
+    DECLARE_SUITE(bool);
+    DECLARE_SUITE(port);
+    DECLARE_SUITE(iface);
+    DECLARE_SUITE(node);
+    DECLARE_SUITE(other);
+    DECLARE_SUITE(user);
+    DECLARE_SUITE(ibendport);
+
+    CU_basic_set_mode(CU_BRM_VERBOSE);
+
+    if (argc == 1) {
+        CU_basic_run_tests();
+    }
+    else if (argc == 2 && strcmp(argv[1], "list") == 0) {
+        for (int i = 0; i < suite_index; i++)
+            printf("%s ", suites_names[i]);
+    }
+    else if (argc == 3 && strcmp(argv[1], "suite") == 0) {
+        int i;
+
+        for (i = 0; i < suite_index; i++) {
+            if (strcmp(argv[2], suites_names[i]) == 0) {
+                CU_basic_run_suite(suites[i]);
+                break;
+            }
+        }
+        
+        if (i == suite_index) {
+            fprintf(stderr, "Invalid suite name\n");
+            CU_cleanup_registry();
+            return 1;
+        }
+    }
+    else {
+        fprintf(stderr, "Invalid arguments\n");
+        CU_cleanup_registry();
+        return 1;
+    }
+
+    CU_cleanup_registry();
+
+    return 0;
+}

diff --git a/libsemanage/sanity-tests/tests/test_bool.c b/libsemanage/sanity-tests/tests/test_bool.c
new file mode 100644
index 0000000..839f596
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_bool.c
@@ -0,0 +1,1231 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <semanage/semanage.h>
+#include <semanage/handle.h>
+#include <selinux/selinux.h>
+#include <CUnit/Basic.h>
+
+#include "test_bool.h"
+#include "functions.h"
+
+/*  The following functions does not have 100 % code coverage because we do not
+ *  test bad mallocs:
+ *  bool_read_list
+ *  bool_activedb_base_init
+ */
+
+// TODO: test semanage_bool_compare2_qsort
+// TODO: bool_commit_list: for loop after continue
+// TODO: bool_commit_list: make security_set_boolean_list return error
+// TODO: bool_commit_list: free blist loop
+// TODO: test bool_print
+// TODO: test bool_parse
+// TODO: bool_file_dbase_init: make dbase_file_init return error
+// TODO: bool_policydb_dbase_init: make dbase_policydb_init return error
+
+extern semanage_handle_t *sh;
+
+char *BOOL;
+char *BOOL2;
+char *BOOL_NONEXISTENT;
+unsigned int BOOLS_COUNT;
+
+int bool_test_init(void) {
+#if VERS_CHECK(2, 5)
+    char *bools_path = "/sys/fs/selinux/booleans";
+
+    DIR *dp;
+    struct dirent *ep;
+
+    dp = opendir(bools_path);
+
+    if (dp == NULL) {
+        fprintf(stderr, "Error reading booleans\n");
+        return 1;
+    }
+
+    BOOLS_COUNT = 0;
+
+    while ((ep = readdir(dp))) {
+        BOOLS_COUNT++;
+
+        if (BOOLS_COUNT == 3) {
+            BOOL = strdup(ep->d_name);
+        }
+        else if (BOOLS_COUNT == 4) {
+            BOOL2 = strdup(ep->d_name);
+        }
+    }
+    
+    // ignore . and ..
+    BOOLS_COUNT -= 2;
+
+    BOOL_NONEXISTENT = "nonexistentbool";
+
+    closedir(dp);
+
+    if (BOOLS_COUNT == 0) {
+        fprintf(stderr, "BOOLS_COUNT is zero\n");
+        return 1;
+    }
+#else
+    BOOL = "secure_mode";
+    BOOL2 = "httpd_tmp_exec";
+    BOOL_NONEXISTENT = "nonexistentbool";
+#endif
+
+	return 0;
+}
+
+int bool_test_cleanup(void) {
+	return 0;
+}
+
+int bool_add_tests(CU_pSuite suite) {
+    CU_add_test(suite, "bool_key_create", test_bool_key_create);
+    CU_add_test(suite, "bool_key_extract", test_bool_key_extract);
+    CU_add_test(suite, "bool_compare", test_bool_compare);
+    CU_add_test(suite, "bool_compare2", test_bool_compare2);
+    CU_add_test(suite, "bool_get_set_name", test_bool_get_set_name);
+    CU_add_test(suite, "bool_get_set_value", test_bool_get_set_value);
+    CU_add_test(suite, "bool_create", test_bool_create);
+    CU_add_test(suite, "bool_clone", test_bool_clone);
+                                 
+    CU_add_test(suite, "bool_query", test_bool_query);
+    CU_add_test(suite, "bool_exists", test_bool_exists);
+    CU_add_test(suite, "bool_count", test_bool_count);
+    CU_add_test(suite, "bool_iterate", test_bool_iterate);
+    CU_add_test(suite, "bool_list", test_bool_list);
+
+    CU_add_test(suite, "bool_modify_del_local", test_bool_modify_del_local);
+    CU_add_test(suite, "bool_query_local", test_bool_query_local);
+    CU_add_test(suite, "bool_exists_local", test_bool_exists_local);
+    CU_add_test(suite, "bool_count_local", test_bool_count_local);
+    CU_add_test(suite, "bool_iterate_local", test_bool_iterate_local);
+    CU_add_test(suite, "bool_list_local", test_bool_list_local);
+                                 
+    CU_add_test(suite, "bool_set_active", test_bool_set_active);
+    CU_add_test(suite, "bool_query_active", test_bool_query_active);
+    CU_add_test(suite, "bool_exists_active", test_bool_exists_active);
+    CU_add_test(suite, "bool_count_active", test_bool_count_active);
+    CU_add_test(suite, "bool_iterate_active", test_bool_iterate_active);
+    CU_add_test(suite, "bool_list_active", test_bool_list_active);
+     
+	return 0;
+}
+
+// Function bool_key_create
+
+void helper_bool_key_create(level_t level) {
+    semanage_bool_key_t *key = NULL;
+
+    setup_handle(level);
+
+    CU_ASSERT(semanage_bool_key_create(sh, "", &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    semanage_bool_key_free(key);
+
+    key = NULL;
+
+    CU_ASSERT(semanage_bool_key_create(sh, "testbool", &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    semanage_bool_key_free(key);
+
+    CU_ASSERT_SIGNAL(semanage_bool_key_create(sh, "testbool", NULL), SIGSEGV);
+
+    cleanup_handle(level);
+}
+
+void test_bool_key_create(void) {
+    helper_bool_key_create(SH_CONNECT);
+    helper_bool_key_create(SH_TRANS);
+}
+
+// Function bool_key_extract
+
+#define SK_NULL 1
+#define SK_NEW 2
+#define SK_INDEX 3
+#define SK_KEY_NULL 4
+void helper_bool_key_extract(level_t level, int mode) {
+    semanage_bool_t *boolean;
+    semanage_bool_key_t *key;
+    int result;
+    
+    setup_handle(level);
+
+    switch (mode) {
+        case SK_NULL:
+            boolean = NULL;
+            break;
+        case SK_NEW:
+            boolean = get_bool_new();
+            break;
+        case SK_INDEX:
+            boolean = get_bool_nth(0);
+            break;
+        case SK_KEY_NULL:
+            boolean = get_bool_nth(0);
+            break;
+        default:
+            CU_FAIL_FATAL("Invalid mode\n");
+    }
+
+    if (mode == SK_KEY_NULL)
+        result = semanage_bool_key_extract(sh, boolean, NULL);
+    else
+        result = semanage_bool_key_extract(sh, boolean, &key);
+
+    CU_ASSERT(result >= 0);
+
+    result = semanage_bool_compare(boolean, key);
+
+    CU_ASSERT(result == 0);
+
+    semanage_bool_key_free(key);
+    semanage_bool_free(boolean);
+
+    cleanup_handle(level);
+}
+
+void test_bool_key_extract(void) {
+    CU_ASSERT_SIGNAL(helper_bool_key_extract(SH_CONNECT, SK_NULL), SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_bool_key_extract(SH_CONNECT, SK_KEY_NULL), SIGSEGV);
+
+    // FIXME
+    //helper_bool_key_extract(SH_CONNECT, SK_NEW);
+    CU_ASSERT_SIGNAL(helper_bool_key_extract(SH_CONNECT, SK_NEW), SIGSEGV);
+
+    helper_bool_key_extract(SH_CONNECT, SK_INDEX);
+
+    CU_ASSERT_SIGNAL(helper_bool_key_extract(SH_TRANS, SK_NULL), SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_bool_key_extract(SH_TRANS, SK_KEY_NULL), SIGSEGV);
+
+    // FIXME
+    //helper_bool_key_extract(SH_TRANS, SK_NEW);
+    CU_ASSERT_SIGNAL(helper_bool_key_extract(SH_TRANS, SK_NEW), SIGSEGV);
+
+    helper_bool_key_extract(SH_TRANS, SK_INDEX);
+}
+#undef SK_NULL
+#undef SK_NEW
+#undef SK_INDEX
+#undef SK_KEY_NULL
+
+// Function bool_compare
+
+void helper_bool_compare(level_t level, int bool_index1, int bool_index2) {
+    semanage_bool_t *boolean;
+    semanage_bool_key_t *key;
+    int result;
+
+    setup_handle(level);
+
+    boolean = get_bool_nth(bool_index1);
+    key = get_bool_key_nth(bool_index2);
+
+    result = semanage_bool_compare(boolean, key);
+
+    if (bool_index1 == bool_index2) {
+        CU_ASSERT(result == 0);
+    }
+    else {
+        CU_ASSERT(result != 0);
+    }
+
+    semanage_bool_free(boolean);
+    semanage_bool_key_free(key);
+    cleanup_handle(level);
+}
+
+void test_bool_compare(void) {
+    helper_bool_compare(SH_CONNECT, I_FIRST,  I_FIRST);
+    helper_bool_compare(SH_CONNECT, I_FIRST,  I_SECOND);
+    helper_bool_compare(SH_CONNECT, I_SECOND, I_FIRST);
+    helper_bool_compare(SH_CONNECT, I_SECOND, I_SECOND);
+
+    CU_ASSERT_SIGNAL(helper_bool_compare(SH_CONNECT, I_NULL, I_FIRST), SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_bool_compare(SH_CONNECT, I_FIRST, I_NULL), SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_bool_compare(SH_CONNECT, I_NULL,  I_NULL), SIGSEGV);
+
+    helper_bool_compare(SH_TRANS, I_FIRST,  I_FIRST);
+    helper_bool_compare(SH_TRANS, I_FIRST,  I_SECOND);
+    helper_bool_compare(SH_TRANS, I_SECOND, I_FIRST);
+    helper_bool_compare(SH_TRANS, I_SECOND, I_SECOND);
+
+    CU_ASSERT_SIGNAL(helper_bool_compare(SH_TRANS, I_NULL,  I_FIRST), SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_bool_compare(SH_TRANS, I_FIRST, I_NULL), SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_bool_compare(SH_TRANS, I_NULL,  I_NULL), SIGSEGV);
+}
+
+// Function bool_compare2
+
+void helper_bool_compare2(level_t level, int bool_index1, int bool_index2) {
+    semanage_bool_t *bool1;
+    semanage_bool_t *bool2;
+    int result;
+
+    setup_handle(level);
+
+    bool1 = get_bool_nth(bool_index1);
+    bool2 = get_bool_nth(bool_index2);
+
+    result = semanage_bool_compare2(bool1, bool2);
+
+    if (bool_index1 == bool_index2) {
+        CU_ASSERT(result == 0);
+    }
+    else {
+        CU_ASSERT(result != 0);
+    }
+
+    semanage_bool_free(bool1);
+    semanage_bool_free(bool2); 
+    cleanup_handle(level);
+}
+
+void test_bool_compare2(void) {
+    helper_bool_compare2(SH_CONNECT, I_FIRST,  I_FIRST);
+    helper_bool_compare2(SH_CONNECT, I_FIRST,  I_SECOND);
+    helper_bool_compare2(SH_CONNECT, I_SECOND, I_FIRST);
+    helper_bool_compare2(SH_CONNECT, I_SECOND, I_SECOND);
+
+    CU_ASSERT_SIGNAL(helper_bool_compare2(SH_CONNECT, I_NULL, I_FIRST),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_bool_compare2(SH_CONNECT, I_FIRST, I_NULL),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_bool_compare2(SH_CONNECT, I_NULL, I_NULL),
+                     SIGSEGV);
+
+    helper_bool_compare2(SH_TRANS, I_FIRST,  I_FIRST);
+    helper_bool_compare2(SH_TRANS, I_FIRST,  I_SECOND);
+    helper_bool_compare2(SH_TRANS, I_SECOND, I_FIRST);
+    helper_bool_compare2(SH_TRANS, I_SECOND, I_SECOND);
+
+    CU_ASSERT_SIGNAL(helper_bool_compare2(SH_TRANS, I_NULL, I_FIRST), SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_bool_compare2(SH_TRANS, I_FIRST, I_NULL), SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_bool_compare2(SH_TRANS, I_NULL, I_NULL), SIGSEGV);
+}
+
+// Function bool_get_name, bool_set_name
+
+void helper_bool_get_set_name(level_t level, int bool_index, const char *name) {
+    semanage_bool_t *boolean;
+    const char *new_name = NULL;
+    
+    setup_handle(level);
+
+    boolean = get_bool_nth(bool_index);
+
+    CU_ASSERT(semanage_bool_set_name(sh, boolean, name) >= 0);
+
+    new_name = semanage_bool_get_name(boolean);
+
+    CU_ASSERT_PTR_NOT_NULL(new_name);
+    CU_ASSERT_STRING_EQUAL(new_name, name);
+
+    semanage_bool_free(boolean);
+    cleanup_handle(level);
+}
+
+void test_bool_get_set_name(void) {
+    CU_ASSERT_SIGNAL(helper_bool_get_set_name(SH_CONNECT, I_FIRST, NULL),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_bool_get_set_name(SH_CONNECT, I_NULL, "testbool"),
+                     SIGSEGV);
+
+    helper_bool_get_set_name(SH_CONNECT, I_FIRST, "testbool");
+    helper_bool_get_set_name(SH_CONNECT, I_FIRST, "");
+    helper_bool_get_set_name(SH_CONNECT, I_SECOND, "testbool");
+    helper_bool_get_set_name(SH_CONNECT, I_SECOND, "");
+
+    CU_ASSERT_SIGNAL(helper_bool_get_set_name(SH_TRANS, I_FIRST, NULL),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_bool_get_set_name(SH_TRANS, I_NULL, "testbool"),
+                     SIGSEGV);
+
+    helper_bool_get_set_name(SH_TRANS, I_FIRST, "testbool");
+    helper_bool_get_set_name(SH_TRANS, I_FIRST, "");
+    helper_bool_get_set_name(SH_TRANS, I_SECOND, "testbool");
+    helper_bool_get_set_name(SH_TRANS, I_SECOND, "");
+}
+
+// Function bool_get_value, bool_set_value
+
+void helper_bool_get_set_value(int bool_index, int value) {
+    semanage_bool_t *boolean;
+    int new_value = 0;
+
+    setup_handle(SH_CONNECT);
+    boolean = get_bool_nth(bool_index);
+    cleanup_handle(SH_CONNECT);
+
+    semanage_bool_set_value(boolean, value);
+
+    new_value = semanage_bool_get_value(boolean);
+
+    CU_ASSERT(new_value == value);
+
+    semanage_bool_free(boolean);
+}
+
+void test_bool_get_set_value(void) {
+    CU_ASSERT_SIGNAL(helper_bool_get_set_value(I_NULL, 0), SIGSEGV);
+
+    helper_bool_get_set_value(I_FIRST, 1);
+    helper_bool_get_set_value(I_FIRST, 0);
+    helper_bool_get_set_value(I_SECOND, 1);
+    helper_bool_get_set_value(I_SECOND, 0);
+}
+
+// Function bool_create
+
+void helper_bool_create(level_t level) {
+    semanage_bool_t *boolean;
+    
+    setup_handle(level);
+
+    CU_ASSERT(semanage_bool_create(sh, &boolean) >= 0);
+
+    CU_ASSERT_PTR_NULL(semanage_bool_get_name(boolean));
+    CU_ASSERT(semanage_bool_get_value(boolean) == 0);
+
+    cleanup_handle(level);
+}
+
+void test_bool_create(void) {
+    CU_ASSERT_SIGNAL(helper_bool_create(SH_NULL), SIGSEGV);
+    helper_bool_create(SH_HANDLE);
+    helper_bool_create(SH_CONNECT);
+    helper_bool_create(SH_TRANS);
+}
+
+// Function bool_clone
+
+void helper_bool_clone(level_t level, int bool_index) {
+    semanage_bool_t *boolean;
+    semanage_bool_t *boolean_clone;
+    const char *str;
+    const char *str_clone;
+    int value;
+    int value_clone;
+    
+    setup_handle(level);
+
+    boolean = get_bool_nth(bool_index);
+
+    CU_ASSERT(semanage_bool_clone(sh, boolean, &boolean_clone) >= 0);
+
+    str = semanage_bool_get_name(boolean);
+    str_clone = semanage_bool_get_name(boolean_clone);
+
+    CU_ASSERT_STRING_EQUAL(str, str_clone);
+
+    value = semanage_bool_get_value(boolean);
+    value_clone = semanage_bool_get_value(boolean_clone);
+
+    CU_ASSERT_EQUAL(value, value_clone);
+
+    cleanup_handle(level);
+}
+
+void test_bool_clone(void) {
+    CU_ASSERT_SIGNAL(helper_bool_clone(SH_CONNECT, I_NULL), SIGSEGV);
+    helper_bool_clone(SH_CONNECT, I_FIRST);
+    helper_bool_clone(SH_CONNECT, I_SECOND);
+
+    CU_ASSERT_SIGNAL(helper_bool_clone(SH_TRANS, I_NULL), SIGSEGV);
+    helper_bool_clone(SH_TRANS, I_FIRST);
+    helper_bool_clone(SH_TRANS, I_SECOND);
+}
+
+// Function bool_query
+
+void helper_bool_query(level_t level, const char *bool_str, int exp_result) {
+    semanage_bool_key_t *key;
+    // some non-null value
+    semanage_bool_t *response = (void *) 42;
+    const char *name;
+
+    setup_handle(level);
+
+    key = get_bool_key_from_str(bool_str);
+
+    CU_ASSERT(semanage_bool_query(sh, key, &response) >= 0);
+
+    if (exp_result >= 0) {
+        name = semanage_bool_get_name(response);
+
+        CU_ASSERT_STRING_EQUAL(name, bool_str);
+    }
+    else {
+        CU_ASSERT_PTR_NULL(response);
+    }
+
+    cleanup_handle(level);
+}
+
+void test_bool_query(void) {
+    CU_ASSERT_SIGNAL(helper_bool_query(SH_CONNECT, NULL, -1), SIGSEGV);
+
+    helper_bool_query(SH_CONNECT, BOOL,  1);
+    helper_bool_query(SH_CONNECT, BOOL2, 1);
+    helper_bool_query(SH_CONNECT, BOOL_NONEXISTENT, -1);
+
+    CU_ASSERT_SIGNAL(helper_bool_query(SH_TRANS, NULL, -1), SIGSEGV);
+
+    helper_bool_query(SH_TRANS, BOOL,  1);
+    helper_bool_query(SH_TRANS, BOOL2, 1);
+    helper_bool_query(SH_TRANS, BOOL_NONEXISTENT, -1);
+}
+
+// Functon bool_exists
+
+void helper_bool_exists(level_t level, char * bool_str, int exp_response) {
+    semanage_bool_key_t *key;
+    int response;
+
+    setup_handle(level);
+
+    key = get_bool_key_from_str(bool_str);
+
+    CU_ASSERT(semanage_bool_exists(sh, key, &response) >= 0);
+    CU_ASSERT(response == exp_response);
+
+    CU_ASSERT_SIGNAL(semanage_bool_exists(sh, key, NULL), SIGSEGV);
+
+    semanage_bool_key_free(key);
+
+    cleanup_handle(level);
+}
+
+void test_bool_exists(void) {
+    CU_ASSERT_SIGNAL(helper_bool_exists(SH_CONNECT, NULL, 0), SIGSEGV);
+
+    helper_bool_exists(SH_CONNECT, BOOL,  1);
+    helper_bool_exists(SH_CONNECT, BOOL2, 1);
+    helper_bool_exists(SH_CONNECT, BOOL_NONEXISTENT, 0);
+
+    CU_ASSERT_SIGNAL(helper_bool_exists(SH_TRANS, NULL, 0), SIGSEGV);
+
+    helper_bool_exists(SH_TRANS, BOOL,  1);
+    helper_bool_exists(SH_TRANS, BOOL2, 1);
+    helper_bool_exists(SH_TRANS, BOOL_NONEXISTENT, 0);
+}
+
+// Function bool_count
+
+void test_bool_count(void) {
+    unsigned int response;
+
+    CU_ASSERT_SIGNAL(semanage_bool_count(NULL, &response), SIGSEGV);
+
+    //handle
+    setup_handle(SH_HANDLE);
+
+    CU_ASSERT(semanage_bool_count(sh, &response) < 0);
+
+    CU_ASSERT(semanage_bool_count(sh, NULL) < 0);
+    
+    cleanup_handle(SH_HANDLE);
+    
+    //connect
+    response = 0;
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_bool_count(sh, &response) >= 0);
+#if VERS_CHECK(2, 5)
+    CU_ASSERT(response == BOOLS_COUNT);
+#else
+    CU_ASSERT(response > 0);
+#endif
+
+    CU_ASSERT_SIGNAL(semanage_bool_count(sh, NULL), SIGSEGV);
+
+    cleanup_handle(SH_CONNECT);
+
+    //trans
+    response = 0;
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_bool_count(sh, &response) >= 0);
+#if VERS_CHECK(2, 5)
+    CU_ASSERT(response == BOOLS_COUNT);
+#else
+    CU_ASSERT(response > 0);
+#endif
+
+    CU_ASSERT_SIGNAL(semanage_bool_count(sh, NULL), SIGSEGV);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function bool_iterate
+
+unsigned int counter_bool_iterate = 0;
+
+int handler_bool_iterate(const semanage_bool_t *record, void *varg) {
+    counter_bool_iterate++;
+    return 0;
+}
+
+void helper_bool_iterate_invalid(void) {
+    CU_ASSERT_SIGNAL(semanage_bool_iterate(NULL, &handler_bool_iterate, NULL),
+                     SIGSEGV);
+
+    setup_handle(SH_HANDLE);
+
+    CU_ASSERT(semanage_bool_iterate(sh, &handler_bool_iterate, NULL) < 0);
+
+    CU_ASSERT(semanage_bool_iterate(sh, NULL, NULL) < 0);
+
+    cleanup_handle(SH_HANDLE);
+}
+
+void helper_bool_iterate(level_t level) {
+    setup_handle(level);
+
+    counter_bool_iterate = 0;
+
+    CU_ASSERT(semanage_bool_iterate(sh, &handler_bool_iterate, NULL) >= 0);
+#if VERS_CHECK(2, 5)
+    CU_ASSERT(counter_bool_iterate == BOOLS_COUNT);
+#else
+    CU_ASSERT(counter_bool_iterate > 0);
+#endif
+
+    CU_ASSERT_SIGNAL(semanage_bool_iterate(sh, NULL, NULL), SIGSEGV);
+
+    cleanup_handle(level);
+}
+
+void test_bool_iterate(void) {
+    helper_bool_iterate_invalid();
+    helper_bool_iterate(SH_CONNECT);
+    helper_bool_iterate(SH_TRANS);
+}
+
+// Function bool_list
+
+void helper_bool_list_invalid(void) {
+    semanage_bool_t **records;
+    unsigned int count;
+
+    CU_ASSERT_SIGNAL(semanage_bool_list(NULL, &records, &count), SIGSEGV);
+
+    setup_handle(SH_HANDLE);
+    
+    CU_ASSERT(semanage_bool_list(sh, &records, &count) < 0);
+
+    CU_ASSERT(semanage_bool_list(sh, NULL, &count) < 0);
+    CU_ASSERT(semanage_bool_list(sh, &records, NULL) < 0);
+
+    cleanup_handle(SH_HANDLE);
+}
+
+void helper_bool_list(level_t level) {
+    semanage_bool_t **records;
+    unsigned int count;
+
+    setup_handle(level);
+    
+    CU_ASSERT(semanage_bool_list(sh, &records, &count) >= 0);
+#if VERS_CHECK(2, 5)
+    CU_ASSERT(count == BOOLS_COUNT);
+#else
+    CU_ASSERT(count > 0);
+#endif
+
+    for (unsigned int i = 0; i < count; i++) {
+        CU_ASSERT_PTR_NOT_NULL(records[i]);
+    }
+
+    for (unsigned int i = 0; i < count; i++) {
+        semanage_bool_free(records[i]);
+    }
+
+    CU_ASSERT_SIGNAL(semanage_bool_list(sh, NULL, &count), SIGSEGV);
+    CU_ASSERT_SIGNAL(semanage_bool_list(sh, &records, NULL), SIGSEGV);
+
+    cleanup_handle(level);
+}
+
+void test_bool_list(void) {
+    helper_bool_list_invalid();
+    helper_bool_list(SH_CONNECT);
+    helper_bool_list(SH_TRANS);
+}
+
+// Function bool_modify_local, bool_del_local
+
+void helper_bool_modify_del_local(level_t level, int bool_index,
+                                  int exp_result) {
+    semanage_bool_t *boolean;
+    semanage_bool_t *boolean_local;
+    semanage_bool_key_t *key = NULL;
+    int result;
+    int new_value;
+
+    setup_handle(level);
+
+    boolean = get_bool_nth(bool_index);
+
+    CU_ASSERT(semanage_bool_key_extract(sh, boolean, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    new_value = !semanage_bool_get_value(boolean);
+    semanage_bool_set_value(boolean, new_value);
+
+    result = semanage_bool_modify_local(sh, key, boolean);
+
+    if (exp_result < 0) {
+        CU_ASSERT(result < 0);
+    }
+    else {
+        CU_ASSERT(result >= 0);
+
+        // write changes to file
+        if (level == SH_TRANS) {
+            helper_commit();
+            helper_begin_transaction();
+        }
+
+        CU_ASSERT(semanage_bool_query_local(sh, key, &boolean_local) >= 0);
+        CU_ASSERT(semanage_bool_compare2(boolean_local, boolean) == 0);
+
+        CU_ASSERT(semanage_bool_del_local(sh, key) >= 0);
+
+        CU_ASSERT(semanage_bool_query_local(sh, key, &boolean_local) < 0);
+    }
+
+    semanage_bool_key_free(key);
+    semanage_bool_free(boolean);
+
+    cleanup_handle(level);
+}
+
+void test_bool_modify_del_local(void) {
+    helper_bool_modify_del_local(SH_CONNECT, I_FIRST,  -1);
+    helper_bool_modify_del_local(SH_CONNECT, I_SECOND, -1);
+
+    helper_bool_modify_del_local(SH_TRANS, I_FIRST,  1);
+    helper_bool_modify_del_local(SH_TRANS, I_SECOND, 1);
+}
+
+// Function bool_query_local
+
+void test_bool_query_local(void) {
+    semanage_bool_key_t *key = NULL;
+    semanage_bool_t *response = NULL;
+
+    // connect
+    setup_handle(SH_CONNECT);
+
+    key = get_bool_key_nth(I_FIRST);
+
+    CU_ASSERT(semanage_bool_query_local(sh, key, &response) < 0);
+    CU_ASSERT_PTR_NULL(response);
+
+    cleanup_handle(SH_CONNECT);
+
+    // transaction
+    setup_handle(SH_TRANS);
+
+    key = get_bool_key_nth(I_FIRST);
+
+    CU_ASSERT(semanage_bool_query_local(sh, key, &response) < 0);
+    CU_ASSERT_PTR_NULL(response);
+
+    add_local_bool(I_FIRST);
+
+    CU_ASSERT(semanage_bool_query_local(sh, key, &response) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(response);
+
+    semanage_bool_key_free(key);
+    key = get_bool_key_nth(I_SECOND);
+
+    add_local_bool(I_SECOND);
+
+    CU_ASSERT(semanage_bool_query_local(sh, key, &response) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(response);
+
+    delete_local_bool(I_FIRST);
+    delete_local_bool(I_SECOND);
+    cleanup_handle(SH_TRANS);
+}
+
+// Function bool_exists_local
+
+void test_bool_exists_local(void) {
+    int response = -1;
+    semanage_bool_key_t *key;
+    setup_handle(SH_TRANS);
+
+    key = get_bool_key_nth(I_FIRST);
+
+    CU_ASSERT(semanage_bool_exists_local(sh, key, &response) >= 0);
+    CU_ASSERT(response == 0);
+
+    add_local_bool(I_FIRST);
+    response = -1;
+
+    CU_ASSERT(semanage_bool_exists_local(sh, key, &response) >= 0);
+    CU_ASSERT(response == 1);
+
+    delete_local_bool(I_FIRST);
+    response = -1;
+
+    CU_ASSERT(semanage_bool_exists_local(sh, key, &response) >= 0);
+    CU_ASSERT(response == 0);
+
+    response = -1;
+
+    //CU_ASSERT(semanage_bool_exists_local(sh, NULL, &response) >= 0);
+    //CU_ASSERT(response == 0);
+
+    //CU_ASSERT_SIGNAL(semanage_bool_exists_local(sh, key, NULL), SIGSEGV);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function bool_count_local
+
+void test_bool_count_local(void) {
+    unsigned int response;
+    unsigned int init_count;
+
+    // null
+    CU_ASSERT_SIGNAL(semanage_bool_count_local(NULL, &response), SIGSEGV);
+
+    // handle
+    setup_handle(SH_HANDLE);
+
+    CU_ASSERT(semanage_bool_count_local(sh, &response) < 0);
+
+    cleanup_handle(SH_HANDLE);
+    
+    // connect
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_bool_count_local(sh, &init_count) >= 0);
+
+    CU_ASSERT_SIGNAL(semanage_bool_count_local(sh, NULL), SIGSEGV);
+
+    cleanup_handle(SH_CONNECT);
+    
+    // transaction
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_bool_count_local(sh, &response) >= 0);
+    CU_ASSERT(response == init_count);
+
+    add_local_bool(I_FIRST);
+
+    CU_ASSERT(semanage_bool_count_local(sh, &response) >= 0);
+    CU_ASSERT(response == init_count + 1);
+
+    add_local_bool(I_SECOND);
+
+    CU_ASSERT(semanage_bool_count_local(sh, &response) >= 0);
+    CU_ASSERT(response == init_count + 2);
+    
+    delete_local_bool(I_SECOND);
+
+    CU_ASSERT(semanage_bool_count_local(sh, &response) >= 0);
+    CU_ASSERT(response == init_count + 1);
+
+    delete_local_bool(I_FIRST);
+
+    CU_ASSERT_SIGNAL(semanage_bool_count_local(sh, NULL), SIGSEGV);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function bool_iterate_local
+
+unsigned int counter_bool_iterate_local = 0;
+
+int handler_bool_iterate_local(const semanage_bool_t *record, void *varg) {
+    counter_bool_iterate_local++;
+    return 0;
+}
+
+void test_bool_iterate_local(void) {
+    unsigned int init_count;
+
+    // null
+    CU_ASSERT_SIGNAL(semanage_bool_iterate_local(NULL,
+                                   &handler_bool_iterate_local, NULL), SIGSEGV);
+
+    // handle
+    setup_handle(SH_HANDLE);
+
+    CU_ASSERT(semanage_bool_iterate_local(sh, &handler_bool_iterate_local,
+                                          NULL) < 0);
+
+    CU_ASSERT(semanage_bool_iterate_local(sh, NULL, NULL) < 0);
+
+    cleanup_handle(SH_HANDLE);
+    
+    // connect
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_bool_count_local(sh, &init_count) >= 0);
+
+    counter_bool_iterate_local = 0;
+    CU_ASSERT(semanage_bool_iterate_local(sh, &handler_bool_iterate_local,
+                                          NULL) >= 0);
+    CU_ASSERT(counter_bool_iterate_local == init_count);
+
+    cleanup_handle(SH_CONNECT);
+
+    // transaction
+    setup_handle(SH_TRANS);
+
+    counter_bool_iterate_local = 0;
+    CU_ASSERT(semanage_bool_iterate_local(sh, &handler_bool_iterate_local,
+                                          NULL) >= 0);
+    CU_ASSERT(counter_bool_iterate_local == init_count);
+
+    add_local_bool(I_FIRST);
+
+    counter_bool_iterate_local = 0;
+    CU_ASSERT(semanage_bool_iterate_local(sh, &handler_bool_iterate_local,
+                                          NULL) >= 0);
+    CU_ASSERT(counter_bool_iterate_local == init_count + 1);
+
+    add_local_bool(I_SECOND);
+
+    counter_bool_iterate_local = 0;
+    CU_ASSERT(semanage_bool_iterate_local(sh, &handler_bool_iterate_local,
+                                          NULL) >= 0);
+    CU_ASSERT(counter_bool_iterate_local == init_count + 2);
+
+    //CU_ASSERT_SIGNAL(semanage_bool_iterate_local(sh, NULL, NULL), SIGSEGV);
+
+    delete_local_bool(I_FIRST);
+    delete_local_bool(I_SECOND);
+    cleanup_handle(SH_TRANS);
+}
+
+// Functtion bool_list_local
+
+void test_bool_list_local(void) {
+    semanage_bool_t **records;
+    unsigned int count;
+    unsigned int init_count;
+
+    // null
+    CU_ASSERT_SIGNAL(semanage_bool_list_local(NULL, &records, &count), SIGSEGV);
+
+    // handle
+    setup_handle(SH_HANDLE);
+
+    CU_ASSERT(semanage_bool_list_local(sh, &records, &count) < 0);
+
+    CU_ASSERT(semanage_bool_list_local(sh, NULL, &count) < 0);
+    CU_ASSERT(semanage_bool_list_local(sh, &records, NULL) < 0);
+
+    cleanup_handle(SH_HANDLE);
+
+    // connect
+    setup_handle(SH_CONNECT);
+    
+    CU_ASSERT(semanage_bool_count_local(sh, &init_count) >= 0);
+
+    CU_ASSERT(semanage_bool_list_local(sh, &records, &count) >= 0);
+    CU_ASSERT(count == init_count);
+
+    CU_ASSERT_SIGNAL(semanage_bool_list_local(sh, NULL, &count), SIGSEGV);
+    CU_ASSERT_SIGNAL(semanage_bool_list_local(sh, &records, NULL), SIGSEGV);
+
+    cleanup_handle(SH_CONNECT);
+
+    // transaction
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_bool_list_local(sh, &records, &count) >= 0);
+    CU_ASSERT(count == init_count);
+
+    add_local_bool(I_FIRST);
+    
+    CU_ASSERT(semanage_bool_list_local(sh, &records, &count) >= 0);
+    CU_ASSERT(count == init_count + 1);
+    CU_ASSERT_PTR_NOT_NULL(records[0]);
+
+    add_local_bool(I_SECOND);
+    
+    CU_ASSERT(semanage_bool_list_local(sh, &records, &count) >= 0);
+    CU_ASSERT(count == init_count + 2);
+    CU_ASSERT_PTR_NOT_NULL(records[0]);
+    CU_ASSERT_PTR_NOT_NULL(records[1]);
+
+    CU_ASSERT_SIGNAL(semanage_bool_list_local(sh, NULL, &count), SIGSEGV);
+    CU_ASSERT_SIGNAL(semanage_bool_list_local(sh, &records, NULL), SIGSEGV);
+
+    delete_local_bool(I_FIRST);
+    delete_local_bool(I_SECOND);
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_bool_set_active
+
+void test_bool_set_active(void) {
+    semanage_bool_key_t *key;
+    semanage_bool_t *boolean;
+    int response;
+
+    setup_handle(SH_TRANS);
+
+    key = get_bool_key_nth(0);
+    boolean = get_bool_nth(0);
+
+    semanage_bool_set_value(boolean, !semanage_bool_get_value(boolean));
+
+    CU_ASSERT(semanage_bool_set_active(sh, key, boolean) >= 0);
+
+    CU_ASSERT(semanage_bool_exists_active(sh, key, &response) >= 0);
+    CU_ASSERT(response == 1);
+
+    semanage_bool_set_value(boolean, !semanage_bool_get_value(boolean));
+
+    CU_ASSERT(semanage_bool_set_active(sh, key, boolean) >= 0);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_bool_query_active
+
+void helper_bool_query_active(level_t level, const char *bool_str,
+                              int exp_result) {
+    semanage_bool_key_t *key;
+    // some non-null value
+    semanage_bool_t *response = (void *) 42;
+    const char *name;
+    int result;
+
+    setup_handle(level);
+
+    key = get_bool_key_from_str(bool_str);
+
+    result = semanage_bool_query_active(sh, key, &response);
+
+    if (exp_result >= 0) {
+        CU_ASSERT(result >= 0);
+
+        name = semanage_bool_get_name(response);
+
+        CU_ASSERT_STRING_EQUAL(name, bool_str);
+    }
+    else {
+        CU_ASSERT(result < 0);
+    }
+
+    cleanup_handle(level);
+}
+
+void test_bool_query_active(void) {
+    CU_ASSERT_SIGNAL(helper_bool_query_active(SH_CONNECT, NULL, -1), SIGSEGV);
+
+    helper_bool_query_active(SH_CONNECT, BOOL,  1);
+    helper_bool_query_active(SH_CONNECT, BOOL2, 1);
+    helper_bool_query_active(SH_CONNECT, BOOL_NONEXISTENT, -1);
+
+    CU_ASSERT_SIGNAL(helper_bool_query_active(SH_TRANS, NULL, -1), SIGSEGV);
+
+    helper_bool_query_active(SH_TRANS, BOOL,  1);
+    helper_bool_query_active(SH_TRANS, BOOL2, 1);
+    helper_bool_query_active(SH_TRANS, BOOL_NONEXISTENT, -1);
+}
+
+// Function bool_exists_active
+
+void helper_bool_exists_active(level_t level, char * bool_str,
+                               int exp_response) {
+    semanage_bool_key_t *key;
+    int response;
+
+    setup_handle(level);
+
+    key = get_bool_key_from_str(bool_str);
+
+    CU_ASSERT(semanage_bool_exists_active(sh, key, &response) >= 0);
+    CU_ASSERT(response == exp_response);
+
+    CU_ASSERT_SIGNAL(semanage_bool_exists_active(sh, key, NULL), SIGSEGV);
+
+    semanage_bool_key_free(key);
+
+    cleanup_handle(level);
+}
+
+void test_bool_exists_active(void) {
+    CU_ASSERT_SIGNAL(helper_bool_exists_active(SH_CONNECT, NULL, 0), SIGSEGV);
+
+    helper_bool_exists_active(SH_CONNECT, BOOL,  1);
+    helper_bool_exists_active(SH_CONNECT, BOOL2, 1);
+    helper_bool_exists_active(SH_CONNECT, BOOL_NONEXISTENT, 0);
+
+    CU_ASSERT_SIGNAL(helper_bool_exists_active(SH_TRANS, NULL, 0), SIGSEGV);
+
+    helper_bool_exists_active(SH_TRANS, BOOL,  1);
+    helper_bool_exists_active(SH_TRANS, BOOL2, 1);
+    helper_bool_exists_active(SH_TRANS, BOOL_NONEXISTENT, 0);
+}
+
+// Function semanage_bool_count_active
+
+void test_bool_count_active(void) {
+    unsigned int response;
+
+    // null
+    CU_ASSERT_SIGNAL(semanage_bool_count_active(NULL, &response), SIGSEGV);
+
+    // handle
+    setup_handle(SH_HANDLE);
+
+    CU_ASSERT(semanage_bool_count_active(sh, &response) < 0);
+
+    cleanup_handle(SH_HANDLE);
+    
+    // connect
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_bool_count_active(sh, &response) >= 0);
+#if VERS_CHECK(2, 5)
+    CU_ASSERT(response == BOOLS_COUNT);
+#else
+    CU_ASSERT(response > 0);
+#endif
+
+    CU_ASSERT_SIGNAL(semanage_bool_count_active(sh, NULL), SIGSEGV);
+
+    cleanup_handle(SH_CONNECT);
+    
+    // transaction
+    setup_handle(SH_TRANS);
+    
+    CU_ASSERT(semanage_bool_count_active(sh, &response) >= 0);
+#if VERS_CHECK(2, 5)
+    CU_ASSERT(response == BOOLS_COUNT);
+#else
+    CU_ASSERT(response > 0);
+#endif
+
+    CU_ASSERT_SIGNAL(semanage_bool_count_active(sh, NULL), SIGSEGV);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_bool_iterate_active
+unsigned int counter_bool_iterate_active = 0;
+
+int handler_bool_iterate_active(const semanage_bool_t *record, void *varg) {
+    counter_bool_iterate_active++;
+    return 0;
+}
+
+void test_bool_iterate_active(void) {
+    // null
+    CU_ASSERT_SIGNAL(semanage_bool_iterate_active(NULL,
+                                  &handler_bool_iterate_active, NULL), SIGSEGV);
+
+    // handle
+    setup_handle(SH_HANDLE);
+
+    CU_ASSERT(semanage_bool_iterate_active(sh, &handler_bool_iterate_active,
+                                           NULL) < 0);
+
+    CU_ASSERT(semanage_bool_iterate_active(sh, NULL, NULL) < 0);
+
+    cleanup_handle(SH_HANDLE);
+
+    // connect
+    setup_handle(SH_CONNECT);
+
+    counter_bool_iterate_active = 0;
+    CU_ASSERT(semanage_bool_iterate_active(sh, &handler_bool_iterate_active,
+                                           NULL) >= 0);
+#if VERS_CHECK(2, 5)
+    CU_ASSERT(counter_bool_iterate_active == BOOLS_COUNT);
+#else
+    CU_ASSERT(counter_bool_iterate_active > 0);
+#endif
+
+    CU_ASSERT_SIGNAL(semanage_bool_iterate_active(sh, NULL, NULL), SIGSEGV);
+
+    cleanup_handle(SH_CONNECT);
+
+    // transaction
+    setup_handle(SH_TRANS);
+
+    counter_bool_iterate_active = 0;
+    CU_ASSERT(semanage_bool_iterate_active(sh, &handler_bool_iterate_active,
+                                           NULL) >= 0);
+#if VERS_CHECK(2, 5)
+    CU_ASSERT(counter_bool_iterate_active == BOOLS_COUNT);
+#else
+    CU_ASSERT(counter_bool_iterate_active > 0);
+#endif
+
+    CU_ASSERT_SIGNAL(semanage_bool_iterate_active(sh, NULL, NULL), SIGSEGV);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_bool_list_active
+
+void helper_bool_list_active_invalid(void) {
+    semanage_bool_t **records;
+    unsigned int count;
+
+    CU_ASSERT_SIGNAL(semanage_bool_list_active(NULL, &records, &count),
+                     SIGSEGV);
+
+    setup_handle(SH_HANDLE);
+    
+    CU_ASSERT(semanage_bool_list_active(sh, &records, &count) < 0);
+
+    CU_ASSERT(semanage_bool_list_active(sh, NULL, &count) < 0);
+    CU_ASSERT(semanage_bool_list_active(sh, &records, NULL) < 0);
+
+    cleanup_handle(SH_HANDLE);
+}
+
+void helper_bool_list_active(level_t level) {
+    semanage_bool_t **records;
+    unsigned int count;
+
+    setup_handle(level);
+    
+    CU_ASSERT(semanage_bool_list_active(sh, &records, &count) >= 0);
+#if VERS_CHECK(2, 5)
+    CU_ASSERT(count == BOOLS_COUNT);
+#else
+    CU_ASSERT(count > 0);
+#endif
+
+    for (unsigned int i = 0; i < count; i++) {
+        CU_ASSERT_PTR_NOT_NULL(records[i]);
+    }
+
+    for (unsigned int i = 0; i < count; i++) {
+        semanage_bool_free(records[i]);
+    }
+
+    CU_ASSERT_SIGNAL(semanage_bool_list_active(sh, NULL, &count), SIGSEGV);
+    CU_ASSERT_SIGNAL(semanage_bool_list_active(sh, &records, NULL), SIGSEGV);
+
+    cleanup_handle(level);
+}
+
+void test_bool_list_active(void) {
+    helper_bool_list_active_invalid();
+    helper_bool_list_active(SH_CONNECT);
+    helper_bool_list_active(SH_TRANS);
+}

diff --git a/libsemanage/sanity-tests/tests/test_bool.h b/libsemanage/sanity-tests/tests/test_bool.h
new file mode 100644
index 0000000..a725836
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_bool.h
@@ -0,0 +1,48 @@
+#ifndef __TEST_BOOL_H__
+#define __TEST_BOOL_H__
+
+#include <CUnit/Basic.h>
+
+int bool_test_init(void);
+int bool_test_cleanup(void);
+int bool_add_tests(CU_pSuite suite);
+
+// boolean_record.h
+
+void test_bool_key_create(void);
+void test_bool_key_extract(void);
+void test_bool_compare(void);
+void test_bool_compare2(void);
+void test_bool_get_set_name(void);
+void test_bool_get_set_value(void);
+void test_bool_create(void);
+void test_bool_clone(void);
+
+// booleans_policy.h
+
+void test_bool_query(void);
+void test_bool_exists(void);
+void test_bool_count(void);
+void test_bool_iterate(void);
+void test_bool_list(void);
+
+// booleans_local.h
+
+void test_bool_modify_del_local(void);
+void test_bool_query_local(void);
+void test_bool_exists_local(void);
+void test_bool_count_local(void);
+void test_bool_iterate_local(void);
+void test_bool_list_local(void);
+
+// booleans_active.h
+
+void test_bool_set_active(void);
+void test_bool_query_active(void);
+void test_bool_exists_active(void);
+void test_bool_count_active(void);
+void test_bool_iterate_active(void);
+void test_bool_list_active(void);
+
+#endif
+

diff --git a/libsemanage/sanity-tests/tests/test_fcontext.c b/libsemanage/sanity-tests/tests/test_fcontext.c
new file mode 100644
index 0000000..cf5d43e
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_fcontext.c
@@ -0,0 +1,1189 @@
+#include <stdio.h>
+#include <string.h>
+#include <semanage/semanage.h>
+#include <semanage/handle.h>
+#include <selinux/selinux.h>
+#include <CUnit/Basic.h>
+
+#include "test_fcontext.h"
+#include "functions.h"
+
+/* TODO: test function type_str
+ * TODO: test function fcontext_print
+ * TODO: function fcontext_parse, error gotos
+ * TODO: test function validate_handler
+ */
+
+extern semanage_handle_t *sh;
+
+char *FCONTEXT_EXPR;
+int FCONTEXT_TYPE;
+char *FCONTEXT_CON;
+
+char *FCONTEXT2_EXPR;
+int FCONTEXT2_TYPE;
+char *FCONTEXT2_CON;
+
+char *FCONTEXT_NONEXISTENT_EXPR;
+int FCONTEXT_NONEXISTENT_TYPE;
+
+unsigned int FCONTEXTS_COUNT;
+
+int get_type(char *t) {
+    if (strcmp(t, "--") == 0)
+        return SEMANAGE_FCONTEXT_ALL;
+    else if (strcmp(t, "-f") == 0)
+        return SEMANAGE_FCONTEXT_REG;
+    else if (strcmp(t, "-d") == 0)
+        return SEMANAGE_FCONTEXT_DIR;
+    else if (strcmp(t, "-c") == 0)
+        return SEMANAGE_FCONTEXT_CHAR;
+    else if (strcmp(t, "-b") == 0)
+        return SEMANAGE_FCONTEXT_BLOCK;
+    else if (strcmp(t, "-s") == 0)
+        return SEMANAGE_FCONTEXT_SOCK;
+    else if (strcmp(t, "-l") == 0)
+        return SEMANAGE_FCONTEXT_LINK;
+    else if (strcmp(t, "-p") == 0)
+        return SEMANAGE_FCONTEXT_PIPE;
+    else
+        return -1;
+}
+
+int fcontext_test_init(void) {
+    char *policy_type;
+    char *fcontexts_path;
+
+    selinux_getpolicytype(&policy_type);
+
+    fcontexts_path = malloc(strlen("/etc/selinux/") + strlen(policy_type)
+                     + strlen("/contexts/files/file_contexts") + 1);
+
+    strcpy(fcontexts_path, "/etc/selinux/");
+    strcat(fcontexts_path, policy_type);
+    strcat(fcontexts_path, "/contexts/files/file_contexts");
+
+    FILE *f = fopen(fcontexts_path, "r");
+
+    if (f == NULL) {
+        fprintf(stderr, "Error opening file %s\n", fcontexts_path);
+        return 1;
+    }
+
+    char line[512];
+    unsigned int line_counter = 0;
+    char *p1;
+    char *p2;
+    char *p3;
+    //char fcontexts_tmp[512];
+
+    while (fgets(line, sizeof(line), f)) {
+        if (line[0] == '#' || line[0] == '\n')
+            continue;
+
+        p1 = strtok(line, "\t");
+        p2 = strtok(NULL, "\t");
+        p3 = strtok(NULL, "\t");
+        //strcat(seusers_tmp, " ");
+        //strcat(seusers_tmp, p);
+
+        if (line_counter == 0) {
+            FCONTEXT_EXPR = strdup(p1);
+
+            if (p3 == NULL) {
+                FCONTEXT_TYPE = SEMANAGE_FCONTEXT_ALL;
+                FCONTEXT_CON = strdup(p2);
+            }
+            else {
+                FCONTEXT_TYPE = get_type(p2);
+                FCONTEXT_CON = strdup(p3);
+            }
+        }
+        // chose entry with type != ALL
+        else if (p3 != NULL && strcmp(p2, "--") != 0) {
+            FCONTEXT2_EXPR = strdup(p1);
+            FCONTEXT2_TYPE = get_type(p2);
+            FCONTEXT2_CON = strdup(p3);
+        }
+
+        line_counter++;
+    }
+
+    //FCONTEXTS = strdup(seusers_tmp);
+    
+    FCONTEXT_NONEXISTENT_EXPR = "/non/existent/path";
+    FCONTEXT_NONEXISTENT_TYPE = SEMANAGE_FCONTEXT_ALL;
+
+    FCONTEXTS_COUNT = line_counter;
+
+    if (FCONTEXTS_COUNT == 0) {
+        fprintf(stderr, "FCONTEXTS_COUNT is zero\n");
+        return 1;
+    }
+
+    free(fcontexts_path);
+
+	return 0;
+}
+
+int fcontext_test_cleanup(void) {
+	return 0;
+}
+
+int fcontext_add_tests(CU_pSuite suite) {
+    CU_add_test(suite, "test_fcontext_compare",     test_fcontext_compare);
+    CU_add_test(suite, "test_fcontext_compare2",    test_fcontext_compare2);
+    CU_add_test(suite, "test_fcontext_key_create",  test_fcontext_key_create);
+    CU_add_test(suite, "test_fcontext_key_extract", test_fcontext_key_extract);
+    CU_add_test(suite, "test_fcontext_get_set_expr",test_fcontext_get_set_expr);
+    CU_add_test(suite, "test_fcontext_get_set_type",test_fcontext_get_set_type);
+    CU_add_test(suite, "test_fcontext_get_type_str",test_fcontext_get_type_str);
+    CU_add_test(suite, "test_fcontext_get_set_con", test_fcontext_get_set_con);
+    CU_add_test(suite, "test_fcontext_create",      test_fcontext_create);
+    CU_add_test(suite, "test_fcontext_clone",       test_fcontext_clone);
+
+    CU_add_test(suite, "test_fcontext_query",       test_fcontext_query);
+    CU_add_test(suite, "test_fcontext_exists",      test_fcontext_exists);
+    CU_add_test(suite, "test_fcontext_count",       test_fcontext_count);
+    CU_add_test(suite, "test_fcontext_iterate",     test_fcontext_iterate);
+    CU_add_test(suite, "test_fcontext_list",        test_fcontext_list);
+    
+    CU_add_test(suite, "test_fcontext_modify_del_local",
+                test_fcontext_modify_del_local);
+    CU_add_test(suite, "test_fcontext_query_local", test_fcontext_query_local);
+    CU_add_test(suite, "test_fcontext_exists_local",test_fcontext_exists_local);
+    CU_add_test(suite, "test_fcontext_count_local", test_fcontext_count_local);
+    CU_add_test(suite, "test_fcontext_iterate_local",
+                test_fcontext_iterate_local);
+    CU_add_test(suite, "test_fcontext_list_local",  test_fcontext_list_local);
+
+	return 0;
+}
+
+// Function semanage_fcontext_compare
+
+void helper_fcontext_compare(level_t level, int fcontext_index1,
+                             int fcontext_index2) {
+    semanage_fcontext_t *fcontext;
+    semanage_fcontext_key_t *key;
+    int result;
+
+    setup_handle(level);
+
+    fcontext = get_fcontext_nth(fcontext_index1);
+    key = get_fcontext_key_nth(fcontext_index2);
+
+    result = semanage_fcontext_compare(fcontext, key);
+
+    if (fcontext_index1 == fcontext_index2) {
+        CU_ASSERT(result == 0);
+    }
+    else {
+        CU_ASSERT(result != 0);
+    }
+
+    semanage_fcontext_free(fcontext);
+    semanage_fcontext_key_free(key);
+    cleanup_handle(level);
+}
+
+void helper_fcontext_compare_type(level_t level, int index, int increase) {
+    semanage_fcontext_t *fcontext = NULL;
+    semanage_fcontext_t *fcontext2 = NULL;
+    semanage_fcontext_key_t *key = NULL;
+    int type = 42;
+
+    // setup
+    setup_handle(level);
+
+    fcontext = get_fcontext_nth(index);
+    fcontext2 = get_fcontext_nth(index);
+
+    type = semanage_fcontext_get_type(fcontext2);
+
+    if (increase) {
+        type += 1;
+
+        if (type > SEMANAGE_FCONTEXT_PIPE)
+            type = SEMANAGE_FCONTEXT_ALL;
+    }
+    else {
+        type -= 1;
+
+        if (type < SEMANAGE_FCONTEXT_ALL)
+            type = SEMANAGE_FCONTEXT_PIPE;
+    }
+
+    semanage_fcontext_set_type(fcontext2, type);
+
+    CU_ASSERT(semanage_fcontext_key_extract(sh, fcontext2, &key) >= 0);
+
+    // test
+    CU_ASSERT(semanage_fcontext_compare(fcontext, key) != 0);
+
+    // cleanup
+    semanage_fcontext_free(fcontext);
+    semanage_fcontext_key_free(key);
+    cleanup_handle(level);
+}
+
+void test_fcontext_compare(void) {
+    helper_fcontext_compare(SH_CONNECT, I_FIRST,  I_FIRST);
+    helper_fcontext_compare(SH_CONNECT, I_FIRST,  I_SECOND);
+    helper_fcontext_compare(SH_CONNECT, I_SECOND, I_FIRST);
+    helper_fcontext_compare(SH_CONNECT, I_SECOND, I_SECOND);
+
+    CU_ASSERT_SIGNAL(helper_fcontext_compare(SH_CONNECT, I_NULL,  I_FIRST),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_fcontext_compare(SH_CONNECT, I_FIRST, I_NULL),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_fcontext_compare(SH_CONNECT, I_NULL,  I_NULL),
+                     SIGSEGV);
+
+    helper_fcontext_compare_type(SH_CONNECT, I_FIRST, -1);
+    helper_fcontext_compare_type(SH_CONNECT, I_FIRST, 1);
+
+    helper_fcontext_compare(SH_TRANS, I_FIRST,  I_FIRST);
+    helper_fcontext_compare(SH_TRANS, I_FIRST,  I_SECOND);
+    helper_fcontext_compare(SH_TRANS, I_SECOND, I_FIRST);
+    helper_fcontext_compare(SH_TRANS, I_SECOND, I_SECOND);
+
+    CU_ASSERT_SIGNAL(helper_fcontext_compare(SH_TRANS, I_NULL,  I_FIRST),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_fcontext_compare(SH_TRANS, I_FIRST, I_NULL),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_fcontext_compare(SH_TRANS, I_NULL,  I_NULL),
+                     SIGSEGV);
+
+    helper_fcontext_compare_type(SH_TRANS, I_FIRST, -1);
+    helper_fcontext_compare_type(SH_TRANS, I_FIRST, 1);
+}
+
+// Function semanage_fcontext_compare2
+// TODO: test same expr, different type
+// TODO: test function semanage_fcontext_compare2_qsort
+
+void helper_fcontext_compare2(level_t level, int fcontext_index1,
+                              int fcontext_index2) {
+    semanage_fcontext_t *fcontext1;
+    semanage_fcontext_t *fcontext2;
+    int result;
+
+    setup_handle(level);
+
+    fcontext1 = get_fcontext_nth(fcontext_index1);
+    fcontext2 = get_fcontext_nth(fcontext_index2);
+
+    result = semanage_fcontext_compare2(fcontext1, fcontext2);
+
+    if (fcontext_index1 == fcontext_index2) {
+        CU_ASSERT(result == 0);
+    }
+    else {
+        CU_ASSERT(result != 0);
+    }
+
+    semanage_fcontext_free(fcontext1);
+    semanage_fcontext_free(fcontext2); 
+    cleanup_handle(level);
+}
+
+void test_fcontext_compare2(void) {
+    helper_fcontext_compare2(SH_CONNECT, I_FIRST,  I_FIRST);
+    helper_fcontext_compare2(SH_CONNECT, I_FIRST,  I_SECOND);
+    helper_fcontext_compare2(SH_CONNECT, I_SECOND, I_FIRST);
+    helper_fcontext_compare2(SH_CONNECT, I_SECOND, I_SECOND);
+
+    CU_ASSERT_SIGNAL(helper_fcontext_compare2(SH_CONNECT, I_NULL,  I_FIRST),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_fcontext_compare2(SH_CONNECT, I_FIRST, I_NULL),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_fcontext_compare2(SH_CONNECT, I_NULL,  I_NULL),
+                     SIGSEGV);
+
+    helper_fcontext_compare2(SH_TRANS, I_FIRST,  I_FIRST);
+    helper_fcontext_compare2(SH_TRANS, I_FIRST,  I_SECOND);
+    helper_fcontext_compare2(SH_TRANS, I_SECOND, I_FIRST);
+    helper_fcontext_compare2(SH_TRANS, I_SECOND, I_SECOND);
+
+    CU_ASSERT_SIGNAL(helper_fcontext_compare2(SH_TRANS, I_NULL,  I_FIRST),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_fcontext_compare2(SH_TRANS, I_FIRST, I_NULL),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_fcontext_compare2(SH_TRANS, I_NULL,  I_NULL),
+                     SIGSEGV);
+}
+
+// Function semanage_fcontext_key_create
+
+void helper_fcontext_key_create(level_t level) {
+    semanage_fcontext_key_t *key = NULL;
+
+    setup_handle(level);
+
+    CU_ASSERT(semanage_fcontext_key_create(sh, "", SEMANAGE_FCONTEXT_ALL,
+                                           &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    semanage_fcontext_key_free(key);
+
+    key = NULL;
+
+    CU_ASSERT(semanage_fcontext_key_create(sh, "testfcontext",
+                                           SEMANAGE_FCONTEXT_ALL, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    semanage_fcontext_key_free(key);
+
+    CU_ASSERT_SIGNAL(semanage_fcontext_key_create(sh, "testfcontext",
+                                         SEMANAGE_FCONTEXT_ALL, NULL), SIGSEGV);
+
+    cleanup_handle(level);
+}
+
+void test_fcontext_key_create(void) {
+    helper_fcontext_key_create(SH_NULL);
+    helper_fcontext_key_create(SH_HANDLE);
+    helper_fcontext_key_create(SH_CONNECT);
+    helper_fcontext_key_create(SH_TRANS);
+}
+
+// Function semanage_fcontext_key_extract
+// TODO: make semanage_fcontext_key_create return error
+
+#define SK_NULL 1
+#define SK_NEW 2
+#define SK_INDEX 3
+#define SK_KEY_NULL 4
+void helper_fcontext_key_extract(level_t level, int mode) {
+    semanage_fcontext_t *fcontext;
+    semanage_fcontext_key_t *key;
+    int result;
+    
+    setup_handle(level);
+
+    switch (mode) {
+        case SK_NULL:
+            fcontext = NULL;
+            break;
+        case SK_NEW:
+            fcontext = get_fcontext_new();
+            break;
+        case SK_INDEX:
+            fcontext = get_fcontext_nth(0);
+            break;
+        case SK_KEY_NULL:
+            fcontext = get_fcontext_nth(0);
+            break;
+        default:
+            CU_FAIL_FATAL("Invalid mode\n");
+    }
+
+    if (mode == SK_KEY_NULL)
+        result = semanage_fcontext_key_extract(sh, fcontext, NULL);
+    else
+        result = semanage_fcontext_key_extract(sh, fcontext, &key);
+
+    CU_ASSERT(result >= 0);
+
+    result = semanage_fcontext_compare(fcontext, key);
+
+    CU_ASSERT(result == 0);
+
+    semanage_fcontext_key_free(key);
+    semanage_fcontext_free(fcontext);
+
+    cleanup_handle(level);
+}
+
+void test_fcontext_key_extract(void) {
+    CU_ASSERT_SIGNAL(helper_fcontext_key_extract(SH_CONNECT, SK_NULL), SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_fcontext_key_extract(SH_CONNECT, SK_KEY_NULL),
+                     SIGSEGV);
+
+    // FIXME
+    //helper_fcontext_key_extract(SH_CONNECT, SK_NEW);
+    CU_ASSERT_SIGNAL(helper_fcontext_key_extract(SH_CONNECT, SK_NEW), SIGSEGV);
+
+    helper_fcontext_key_extract(SH_CONNECT, SK_INDEX);
+
+    CU_ASSERT_SIGNAL(helper_fcontext_key_extract(SH_TRANS, SK_NULL), SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_fcontext_key_extract(SH_TRANS, SK_KEY_NULL),
+                     SIGSEGV);
+
+    // FIXME
+    //helper_fcontext_key_extract(SH_TRANS, SK_NEW);
+    CU_ASSERT_SIGNAL(helper_fcontext_key_extract(SH_TRANS, SK_NEW), SIGSEGV);
+
+    helper_fcontext_key_extract(SH_TRANS, SK_INDEX);
+}
+#undef SK_NULL
+#undef SK_NEW
+#undef SK_INDEX
+#undef SK_KEY_NULL
+
+// Function semanage_fcontext_get_expr, semanage_fcontext_set_expr
+
+void helper_fcontext_get_set_expr(level_t level, int fcontext_index,
+                                  const char *name) {
+    semanage_fcontext_t *fcontext;
+    const char *new_name = NULL;
+    
+    setup_handle(level);
+
+    fcontext = get_fcontext_nth(fcontext_index);
+
+    CU_ASSERT(semanage_fcontext_set_expr(sh, fcontext, name) >= 0);
+
+    new_name = semanage_fcontext_get_expr(fcontext);
+
+    CU_ASSERT_PTR_NOT_NULL(new_name);
+    CU_ASSERT_STRING_EQUAL(new_name, name);
+
+    semanage_fcontext_free(fcontext);
+    cleanup_handle(level);
+}
+
+void test_fcontext_get_set_expr(void) {
+    CU_ASSERT_SIGNAL(helper_fcontext_get_set_expr(SH_CONNECT, I_FIRST, NULL),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_fcontext_get_set_expr(SH_CONNECT, I_NULL,
+                                                  "testfcontext"), SIGSEGV);
+
+    helper_fcontext_get_set_expr(SH_CONNECT, I_FIRST, "testfcontext");
+    helper_fcontext_get_set_expr(SH_CONNECT, I_FIRST, "");
+    helper_fcontext_get_set_expr(SH_CONNECT, I_SECOND, "testfcontext");
+    helper_fcontext_get_set_expr(SH_CONNECT, I_SECOND, "");
+
+    CU_ASSERT_SIGNAL(helper_fcontext_get_set_expr(SH_TRANS, I_FIRST, NULL),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_fcontext_get_set_expr(SH_TRANS, I_NULL,
+                                                  "testfcontext"), SIGSEGV);
+
+    helper_fcontext_get_set_expr(SH_TRANS, I_FIRST, "testfcontext");
+    helper_fcontext_get_set_expr(SH_TRANS, I_FIRST, "");
+    helper_fcontext_get_set_expr(SH_TRANS, I_SECOND, "testfcontext");
+    helper_fcontext_get_set_expr(SH_TRANS, I_SECOND, "");
+}
+
+// Function semanage_fcontext_get_type, semanage_fcontext_set_type
+
+void helper_fcontext_get_set_type(int fcontext_index, int type) {
+    semanage_fcontext_t *fcontext;
+    int new_type = -1;
+    
+    setup_handle(SH_CONNECT);
+
+    fcontext = get_fcontext_nth(fcontext_index);
+
+    semanage_fcontext_set_type(fcontext, type);
+
+    new_type = semanage_fcontext_get_type(fcontext);
+
+    CU_ASSERT(new_type == type);
+
+    semanage_fcontext_free(fcontext);
+    cleanup_handle(SH_CONNECT);
+}
+
+void test_fcontext_get_set_type(void) {
+    helper_fcontext_get_set_type(I_FIRST, SEMANAGE_FCONTEXT_ALL - 1);
+    helper_fcontext_get_set_type(I_FIRST, SEMANAGE_FCONTEXT_ALL);
+    helper_fcontext_get_set_type(I_FIRST, SEMANAGE_FCONTEXT_DIR);
+    helper_fcontext_get_set_type(I_FIRST, SEMANAGE_FCONTEXT_PIPE);
+    helper_fcontext_get_set_type(I_FIRST, SEMANAGE_FCONTEXT_PIPE + 1);
+
+    helper_fcontext_get_set_type(I_SECOND, SEMANAGE_FCONTEXT_ALL);
+}
+
+// Function semanage_fcontext_get_type_str
+
+void helper_fcontext_get_type_str(int type, const char *exp_str) {
+    CU_ASSERT_STRING_EQUAL(semanage_fcontext_get_type_str(type), exp_str);
+}
+
+void test_fcontext_get_type_str(void) {
+    helper_fcontext_get_type_str(SEMANAGE_FCONTEXT_ALL,   "all files");
+    helper_fcontext_get_type_str(SEMANAGE_FCONTEXT_REG,   "regular file");
+    helper_fcontext_get_type_str(SEMANAGE_FCONTEXT_DIR,   "directory");
+    helper_fcontext_get_type_str(SEMANAGE_FCONTEXT_CHAR,  "character device");
+    helper_fcontext_get_type_str(SEMANAGE_FCONTEXT_BLOCK, "block device");
+    helper_fcontext_get_type_str(SEMANAGE_FCONTEXT_SOCK,  "socket");
+    helper_fcontext_get_type_str(SEMANAGE_FCONTEXT_LINK,  "symbolic link");
+    helper_fcontext_get_type_str(SEMANAGE_FCONTEXT_PIPE,  "named pipe");
+
+    helper_fcontext_get_type_str(SEMANAGE_FCONTEXT_ALL - 1,  "????");
+    helper_fcontext_get_type_str(SEMANAGE_FCONTEXT_PIPE + 1, "????");
+}
+
+// Function semanage_fcontext_get_con, semanage_fcontext_set_con
+
+void helper_fcontext_get_set_con(level_t level, int fcontext_index,
+                                 const char *con_str) {
+    semanage_fcontext_t *fcontext;
+    semanage_context_t *con = NULL;
+    semanage_context_t *new_con = NULL;
+    
+    setup_handle(level);
+
+    fcontext = get_fcontext_nth(fcontext_index);
+
+    if (con_str != NULL) {
+        CU_ASSERT(semanage_context_from_string(sh, con_str, &con) >= 0);
+        CU_ASSERT_PTR_NOT_NULL(con);
+    }
+    else {
+        con = NULL;
+    }
+
+    // set con
+    CU_ASSERT(semanage_fcontext_set_con(sh, fcontext, con) >= 0);
+
+    // get con
+    new_con = semanage_fcontext_get_con(fcontext);
+
+    if (con_str != NULL) {
+        CU_ASSERT_CONTEXT_EQUAL(con, new_con);
+    }
+    else {
+        CU_ASSERT_PTR_NULL(new_con);
+    }
+
+    semanage_fcontext_free(fcontext);
+    cleanup_handle(level);
+}
+
+void test_fcontext_get_set_con(void) {
+    CU_ASSERT_SIGNAL(helper_fcontext_get_set_con(SH_CONNECT, I_NULL,
+                                           "user_u:role_r:type_t:s0"), SIGSEGV);
+    helper_fcontext_get_set_con(SH_CONNECT, I_FIRST, NULL);
+
+    helper_fcontext_get_set_con(SH_CONNECT, I_FIRST, "user_u:role_r:type_t:s0");
+    helper_fcontext_get_set_con(SH_CONNECT, I_SECOND,
+                                "user_u:role_r:type_t:s0");
+
+    helper_fcontext_get_set_con(SH_TRANS, I_FIRST, NULL);
+    CU_ASSERT_SIGNAL(helper_fcontext_get_set_con(SH_TRANS, I_NULL,
+                                           "user_u:role_r:type_t:s0"), SIGSEGV);
+
+    helper_fcontext_get_set_con(SH_TRANS, I_FIRST,  "user_u:role_r:type_t:s0");
+    helper_fcontext_get_set_con(SH_TRANS, I_SECOND, "user_u:role_r:type_t:s0");
+}
+
+// Function semanage_fcontext_create
+
+void helper_fcontext_create(level_t level) {
+    semanage_fcontext_t *fcontext;
+    
+    setup_handle(level);
+
+    CU_ASSERT(semanage_fcontext_create(sh, &fcontext) >= 0);
+
+    CU_ASSERT_PTR_NULL(semanage_fcontext_get_expr(fcontext));
+    CU_ASSERT(semanage_fcontext_get_type(fcontext) == SEMANAGE_FCONTEXT_ALL);
+    CU_ASSERT_PTR_NULL(semanage_fcontext_get_con(fcontext));
+
+    semanage_fcontext_free(fcontext);
+    cleanup_handle(level);
+}
+
+void test_fcontext_create(void) {
+    helper_fcontext_create(SH_NULL);
+    helper_fcontext_create(SH_HANDLE);
+    helper_fcontext_create(SH_CONNECT);
+    helper_fcontext_create(SH_TRANS);
+}
+
+// Function semanage_fcontext_clone
+// TODO: error gotos
+
+void helper_fcontext_clone(level_t level, int fcontext_index) {
+    semanage_fcontext_t *fcontext;
+    semanage_fcontext_t *fcontext_clone;
+    const char *expr;
+    const char *expr_clone;
+    int type;
+    int type_clone;
+    semanage_context_t *con;
+    semanage_context_t *con_clone;
+    
+    setup_handle(level);
+
+    fcontext = get_fcontext_nth(fcontext_index);
+
+    // clone
+    CU_ASSERT(semanage_fcontext_clone(sh, fcontext, &fcontext_clone) >= 0);
+
+    // compare expr
+    expr = semanage_fcontext_get_expr(fcontext);
+    expr_clone = semanage_fcontext_get_expr(fcontext_clone);
+
+    CU_ASSERT_STRING_EQUAL(expr, expr_clone);
+
+    // compare type
+    type = semanage_fcontext_get_type(fcontext);
+    type_clone = semanage_fcontext_get_type(fcontext_clone);
+
+    CU_ASSERT_EQUAL(type, type_clone);
+
+    // compare context
+    con = semanage_fcontext_get_con(fcontext);
+    con_clone = semanage_fcontext_get_con(fcontext_clone);
+
+    CU_ASSERT_CONTEXT_EQUAL(con, con_clone);
+
+    semanage_fcontext_free(fcontext);
+    semanage_fcontext_free(fcontext_clone);
+    cleanup_handle(level);
+}
+
+void test_fcontext_clone(void) {
+    CU_ASSERT_SIGNAL(helper_fcontext_clone(SH_CONNECT, I_NULL), SIGSEGV);
+    helper_fcontext_clone(SH_CONNECT, I_FIRST);
+    helper_fcontext_clone(SH_CONNECT, I_SECOND);
+
+    CU_ASSERT_SIGNAL(helper_fcontext_clone(SH_TRANS, I_NULL), SIGSEGV);
+    helper_fcontext_clone(SH_TRANS, I_FIRST);
+    helper_fcontext_clone(SH_TRANS, I_SECOND);
+}
+
+// Function semanage_fcontext_query
+
+void helper_fcontext_query(level_t level, const char *fcontext_expr,
+                           int fcontext_type, int exp_result) {
+    semanage_fcontext_key_t *key;
+    // some non-null value
+    semanage_fcontext_t *response = (void *) 42;
+    const char *expr;
+    int result;
+
+    setup_handle(level);
+
+    key = get_fcontext_key_from_str(fcontext_expr, fcontext_type);
+
+    result = semanage_fcontext_query(sh, key, &response);
+
+    if (exp_result >= 0) {
+        CU_ASSERT(result >= 0);
+
+        expr = semanage_fcontext_get_expr(response);
+
+        CU_ASSERT_STRING_EQUAL(expr, fcontext_expr);
+    }
+    else {
+        CU_ASSERT(result < 0);
+        CU_ASSERT(response == (void *) 42);
+    }
+
+    cleanup_handle(level);
+}
+
+void test_fcontext_query(void) {
+    CU_ASSERT_SIGNAL(helper_fcontext_query(SH_CONNECT, NULL, 0, -1), SIGSEGV);
+    helper_fcontext_query(SH_CONNECT, FCONTEXT_NONEXISTENT_EXPR,
+                          FCONTEXT_NONEXISTENT_TYPE, -1);
+    // different type
+    helper_fcontext_query(SH_CONNECT, FCONTEXT2_EXPR, FCONTEXT_TYPE, -1);
+
+    helper_fcontext_query(SH_CONNECT, FCONTEXT_EXPR,  FCONTEXT_TYPE,  1);
+    helper_fcontext_query(SH_CONNECT, FCONTEXT2_EXPR, FCONTEXT2_TYPE, 1);
+
+    CU_ASSERT_SIGNAL(helper_fcontext_query(SH_TRANS, NULL, 0, -1), SIGSEGV);
+    helper_fcontext_query(SH_TRANS, FCONTEXT_NONEXISTENT_EXPR,
+                          FCONTEXT_NONEXISTENT_TYPE, -1);
+    // different type
+    helper_fcontext_query(SH_TRANS, FCONTEXT2_EXPR, FCONTEXT_TYPE, -1);
+
+    helper_fcontext_query(SH_TRANS, FCONTEXT_EXPR,  FCONTEXT_TYPE,  1);
+    helper_fcontext_query(SH_TRANS, FCONTEXT2_EXPR, FCONTEXT2_TYPE, 1);
+}
+
+// Function semanage_fcontext_exists
+
+void helper_fcontext_exists(level_t level, char * fcontext_expr,
+                            int fcontext_type, int exp_response) {
+    semanage_fcontext_key_t *key;
+    int response;
+
+    setup_handle(level);
+
+    key = get_fcontext_key_from_str(fcontext_expr, fcontext_type);
+
+    CU_ASSERT(semanage_fcontext_exists(sh, key, &response) >= 0);
+    CU_ASSERT(response == exp_response);
+
+    CU_ASSERT_SIGNAL(semanage_fcontext_exists(sh, key, NULL), SIGSEGV);
+
+    semanage_fcontext_key_free(key);
+
+    cleanup_handle(level);
+}
+
+void test_fcontext_exists(void) {
+    CU_ASSERT_SIGNAL(helper_fcontext_exists(SH_CONNECT, NULL, 0, 0), SIGSEGV);
+    helper_fcontext_exists(SH_CONNECT, FCONTEXT_NONEXISTENT_EXPR,
+                           FCONTEXT_NONEXISTENT_TYPE, 0);
+    // different type
+    helper_fcontext_exists(SH_CONNECT, FCONTEXT2_EXPR, FCONTEXT_TYPE, 0);
+
+    helper_fcontext_exists(SH_CONNECT, FCONTEXT_EXPR,  FCONTEXT_TYPE,  1);
+    helper_fcontext_exists(SH_CONNECT, FCONTEXT2_EXPR, FCONTEXT2_TYPE, 1);
+
+    CU_ASSERT_SIGNAL(helper_fcontext_exists(SH_TRANS, NULL, 0, 0), SIGSEGV);
+    helper_fcontext_exists(SH_TRANS, FCONTEXT_NONEXISTENT_EXPR,
+                           FCONTEXT_NONEXISTENT_TYPE, 0);
+    // different type
+    helper_fcontext_exists(SH_TRANS, FCONTEXT2_EXPR, FCONTEXT_TYPE,  0);
+
+    helper_fcontext_exists(SH_TRANS, FCONTEXT_EXPR,  FCONTEXT_TYPE,  1);
+    helper_fcontext_exists(SH_TRANS, FCONTEXT2_EXPR, FCONTEXT2_TYPE, 1);
+}
+
+// Function semanage_fcontext_count
+
+void test_fcontext_count(void) {
+    unsigned int response;
+
+    CU_ASSERT_SIGNAL(semanage_fcontext_count(NULL, &response), SIGSEGV);
+
+    //handle
+    setup_handle(SH_HANDLE);
+
+    CU_ASSERT(semanage_fcontext_count(sh, &response) < 0);
+
+    CU_ASSERT(semanage_fcontext_count(sh, NULL) < 0);
+    
+    cleanup_handle(SH_HANDLE);
+    
+    //connect
+    response = 0;
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_fcontext_count(sh, &response) >= 0);
+    CU_ASSERT(response == FCONTEXTS_COUNT);
+
+    CU_ASSERT_SIGNAL(semanage_fcontext_count(sh, NULL), SIGSEGV);
+
+    cleanup_handle(SH_CONNECT);
+
+    //trans
+    response = 0;
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_fcontext_count(sh, &response) >= 0);
+    CU_ASSERT(response == FCONTEXTS_COUNT);
+
+    CU_ASSERT_SIGNAL(semanage_fcontext_count(sh, NULL), SIGSEGV);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_fcontext_iterate
+
+unsigned int counter_fcontext_iterate = 0;
+
+int handler_fcontext_iterate(const semanage_fcontext_t *record, void *varg) {
+    counter_fcontext_iterate++;
+    return 0;
+}
+
+void helper_fcontext_iterate_invalid(void) {
+    CU_ASSERT_SIGNAL(semanage_fcontext_iterate(NULL, &handler_fcontext_iterate,
+                                               NULL), SIGSEGV);
+
+    setup_handle(SH_HANDLE);
+
+    CU_ASSERT(semanage_fcontext_iterate(sh, &handler_fcontext_iterate,
+                                        NULL) < 0);
+
+    CU_ASSERT(semanage_fcontext_iterate(sh, NULL, NULL) < 0);
+
+    cleanup_handle(SH_HANDLE);
+}
+
+void helper_fcontext_iterate(level_t level) {
+    setup_handle(level);
+
+    counter_fcontext_iterate = 0;
+
+    CU_ASSERT(semanage_fcontext_iterate(sh, &handler_fcontext_iterate,
+                                        NULL) >= 0);
+    CU_ASSERT(counter_fcontext_iterate == FCONTEXTS_COUNT);
+
+    CU_ASSERT_SIGNAL(semanage_fcontext_iterate(sh, NULL, NULL), SIGSEGV);
+
+    cleanup_handle(level);
+}
+
+void test_fcontext_iterate(void) {
+    helper_fcontext_iterate_invalid();
+    helper_fcontext_iterate(SH_CONNECT);
+    helper_fcontext_iterate(SH_TRANS);
+}
+
+// Function semanage_fcontext_list
+
+void helper_fcontext_list_invalid(void) {
+    semanage_fcontext_t **records;
+    unsigned int count;
+
+    CU_ASSERT_SIGNAL(semanage_fcontext_list(NULL, &records, &count), SIGSEGV);
+
+    setup_handle(SH_HANDLE);
+    
+    CU_ASSERT(semanage_fcontext_list(sh, &records, &count) < 0);
+
+    CU_ASSERT(semanage_fcontext_list(sh, NULL, &count) < 0);
+    CU_ASSERT(semanage_fcontext_list(sh, &records, NULL) < 0);
+
+    cleanup_handle(SH_HANDLE);
+}
+
+void helper_fcontext_list(level_t level) {
+    semanage_fcontext_t **records;
+    unsigned int count;
+
+    setup_handle(level);
+    
+    CU_ASSERT(semanage_fcontext_list(sh, &records, &count) >= 0);
+    CU_ASSERT(count == FCONTEXTS_COUNT);
+
+    for (unsigned int i = 0; i < count; i++) {
+        CU_ASSERT_PTR_NOT_NULL(records[i]);
+    }
+
+    for (unsigned int i = 0; i < count; i++) {
+        semanage_fcontext_free(records[i]);
+    }
+
+    CU_ASSERT_SIGNAL(semanage_fcontext_list(sh, NULL, &count), SIGSEGV);
+    CU_ASSERT_SIGNAL(semanage_fcontext_list(sh, &records, NULL), SIGSEGV);
+
+    cleanup_handle(level);
+}
+
+void test_fcontext_list(void) {
+    helper_fcontext_list_invalid();
+    helper_fcontext_list(SH_CONNECT);
+    helper_fcontext_list(SH_TRANS);
+}
+
+// Function semanage_fcontext_modify_local, semanage_fcontext_del_local
+
+void helper_fcontext_modify_del_local(level_t level, int fcontext_index,
+                                      const char *con_str, int exp_result) {
+    semanage_fcontext_t *fcontext;
+    semanage_fcontext_t *fcontext_local;
+    semanage_fcontext_key_t *key = NULL;
+    semanage_context_t *con = NULL;
+    int result;
+
+    setup_handle(level);
+
+    fcontext = get_fcontext_nth(fcontext_index);
+
+    CU_ASSERT(semanage_fcontext_key_extract(sh, fcontext, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    if (con_str != NULL) {
+        CU_ASSERT(semanage_context_from_string(sh, con_str, &con) >= 0);
+        CU_ASSERT_PTR_NOT_NULL(con);
+    }
+    else {
+        con = NULL;
+    }
+
+    CU_ASSERT(semanage_fcontext_set_con(sh, fcontext, con) >= 0);
+
+    result = semanage_fcontext_modify_local(sh, key, fcontext);
+
+    if (exp_result < 0) {
+        CU_ASSERT(result < 0);
+    }
+    else {
+        CU_ASSERT(result >= 0);
+
+        if (level == SH_TRANS) {
+            helper_commit();
+            helper_begin_transaction();
+        }
+
+        CU_ASSERT(semanage_fcontext_query_local(sh, key, &fcontext_local) >= 0);
+        CU_ASSERT(semanage_fcontext_compare2(fcontext_local, fcontext) == 0);
+
+        CU_ASSERT(semanage_fcontext_del_local(sh, key) >= 0);
+
+        CU_ASSERT(semanage_fcontext_query_local(sh, key, &fcontext_local) < 0);
+    }
+
+    semanage_fcontext_key_free(key);
+    semanage_fcontext_free(fcontext);
+
+    cleanup_handle(level);
+}
+
+void test_fcontext_modify_del_local(void) {
+    helper_fcontext_modify_del_local(SH_CONNECT, I_FIRST,
+                                     "system_u:object_r:tmp_t:s0", -1);
+    helper_fcontext_modify_del_local(SH_CONNECT, I_SECOND,
+                                     "system_u:object_r:tmp_t:s0", -1);
+
+    helper_fcontext_modify_del_local(SH_TRANS, I_FIRST,
+                                     "system_u:object_r:tmp_t:s0", 1);
+    helper_fcontext_modify_del_local(SH_TRANS, I_SECOND,
+                                     "system_u:object_r:tmp_t:s0", 1);
+}
+
+// Function semanage_fcontext_query_local
+
+void test_fcontext_query_local(void) {
+    semanage_fcontext_key_t *key = NULL;
+    semanage_fcontext_t *response = NULL;
+
+    // connect
+    setup_handle(SH_CONNECT);
+
+    key = get_fcontext_key_nth(I_FIRST);
+
+    CU_ASSERT(semanage_fcontext_query_local(sh, key, &response) < 0);
+    CU_ASSERT_PTR_NULL(response);
+
+    cleanup_handle(SH_CONNECT);
+
+    // transaction
+    setup_handle(SH_TRANS);
+
+    key = get_fcontext_key_nth(I_FIRST);
+
+    CU_ASSERT(semanage_fcontext_query_local(sh, key, &response) < 0);
+    CU_ASSERT_PTR_NULL(response);
+
+    add_local_fcontext(I_FIRST);
+
+    CU_ASSERT(semanage_fcontext_query_local(sh, key, &response) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(response);
+
+    semanage_fcontext_key_free(key);
+    key = get_fcontext_key_nth(I_SECOND);
+
+    add_local_fcontext(I_SECOND);
+
+    CU_ASSERT(semanage_fcontext_query_local(sh, key, &response) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(response);
+
+    delete_local_fcontext(I_FIRST);
+    delete_local_fcontext(I_SECOND);
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_fcontext_exists_local
+
+void test_fcontext_exists_local(void) {
+    int response = -1;
+    semanage_fcontext_key_t *key;
+    setup_handle(SH_TRANS);
+
+    key = get_fcontext_key_nth(I_FIRST);
+
+    CU_ASSERT(semanage_fcontext_exists_local(sh, key, &response) >= 0);
+    CU_ASSERT(response == 0);
+
+    add_local_fcontext(I_FIRST);
+    response = -1;
+
+    CU_ASSERT(semanage_fcontext_exists_local(sh, key, &response) >= 0);
+    CU_ASSERT(response == 1);
+
+    delete_local_fcontext(I_FIRST);
+    response = -1;
+
+    CU_ASSERT(semanage_fcontext_exists_local(sh, key, &response) >= 0);
+    CU_ASSERT(response == 0);
+
+    response = -1;
+
+    CU_ASSERT(semanage_fcontext_exists_local(sh, NULL, &response) >= 0);
+    CU_ASSERT(response == 0);
+
+    CU_ASSERT_SIGNAL(semanage_fcontext_exists_local(sh, key, NULL), SIGSEGV);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_fcontext_count_local
+
+void test_fcontext_count_local(void) {
+    unsigned int response;
+
+    // null
+    CU_ASSERT_SIGNAL(semanage_fcontext_count_local(NULL, &response), SIGSEGV);
+
+    // handle
+    setup_handle(SH_HANDLE);
+
+    CU_ASSERT(semanage_fcontext_count_local(sh, &response) < 0);
+
+    cleanup_handle(SH_HANDLE);
+    
+    // connect
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_fcontext_count_local(sh, &response) >= 0);
+    CU_ASSERT(response == 0);
+
+    CU_ASSERT_SIGNAL(semanage_fcontext_count_local(sh, NULL), SIGSEGV);
+
+    cleanup_handle(SH_CONNECT);
+    
+    // transaction
+    setup_handle(SH_TRANS);
+    
+    CU_ASSERT(semanage_fcontext_count_local(sh, &response) >= 0);
+    CU_ASSERT(response == 0);
+
+    add_local_fcontext(I_FIRST);
+
+    CU_ASSERT(semanage_fcontext_count_local(sh, &response) >= 0);
+    CU_ASSERT(response == 1);
+
+    add_local_fcontext(I_SECOND);
+
+    CU_ASSERT(semanage_fcontext_count_local(sh, &response) >= 0);
+    CU_ASSERT(response == 2);
+
+    delete_local_fcontext(I_SECOND);
+
+    CU_ASSERT(semanage_fcontext_count_local(sh, &response) >= 0);
+    CU_ASSERT(response == 1);
+
+    delete_local_fcontext(I_FIRST);
+
+    CU_ASSERT_SIGNAL(semanage_fcontext_count_local(sh, NULL), SIGSEGV);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_fcontext_iterate_local
+
+unsigned int counter_fcontext_iterate_local = 0;
+
+int handler_fcontext_iterate_local(const semanage_fcontext_t *record,
+                                   void *varg) {
+    counter_fcontext_iterate_local++;
+    return 0;
+}
+
+void test_fcontext_iterate_local(void) {
+    // null
+    CU_ASSERT_SIGNAL(semanage_fcontext_iterate_local(NULL,
+                               &handler_fcontext_iterate_local, NULL), SIGSEGV);
+
+    // handle
+    setup_handle(SH_HANDLE);
+
+    CU_ASSERT(semanage_fcontext_iterate_local(sh,
+                                    &handler_fcontext_iterate_local, NULL) < 0);
+
+    CU_ASSERT(semanage_fcontext_iterate_local(sh, NULL, NULL) < 0);
+
+    cleanup_handle(SH_HANDLE);
+    
+    // connect
+    setup_handle(SH_CONNECT);
+
+    counter_fcontext_iterate_local = 0;
+    CU_ASSERT(semanage_fcontext_iterate_local(sh,
+                                   &handler_fcontext_iterate_local, NULL) >= 0);
+    CU_ASSERT(counter_fcontext_iterate_local == 0);
+
+    // FIXME
+    CU_ASSERT(semanage_fcontext_iterate_local(sh, NULL, NULL) >= 0);
+
+    cleanup_handle(SH_CONNECT);
+
+    // transaction
+    setup_handle(SH_TRANS);
+
+    counter_fcontext_iterate_local = 0;
+    CU_ASSERT(semanage_fcontext_iterate_local(sh,
+                                   &handler_fcontext_iterate_local, NULL) >= 0);
+    CU_ASSERT(counter_fcontext_iterate_local == 0);
+
+    add_local_fcontext(I_FIRST);
+
+    counter_fcontext_iterate_local = 0;
+    CU_ASSERT(semanage_fcontext_iterate_local(sh,
+                                   &handler_fcontext_iterate_local, NULL) >= 0);
+    CU_ASSERT(counter_fcontext_iterate_local == 1);
+
+    add_local_fcontext(I_SECOND);
+
+    counter_fcontext_iterate_local = 0;
+    CU_ASSERT(semanage_fcontext_iterate_local(sh,
+                                   &handler_fcontext_iterate_local, NULL) >= 0);
+    CU_ASSERT(counter_fcontext_iterate_local == 2);
+
+    CU_ASSERT_SIGNAL(semanage_fcontext_iterate_local(sh, NULL, NULL), SIGSEGV);
+
+    delete_local_fcontext(I_FIRST);
+    delete_local_fcontext(I_SECOND);
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_fcontext_list_local
+
+void test_fcontext_list_local(void) {
+    semanage_fcontext_t **records;
+    unsigned int count;
+
+    // null
+    CU_ASSERT_SIGNAL(semanage_fcontext_list_local(NULL, &records, &count),
+                     SIGSEGV);
+
+    // handle
+    setup_handle(SH_HANDLE);
+    
+    CU_ASSERT(semanage_fcontext_list_local(sh, &records, &count) < 0);
+
+    CU_ASSERT(semanage_fcontext_list_local(sh, NULL, &count) < 0);
+    CU_ASSERT(semanage_fcontext_list_local(sh, &records, NULL) < 0);
+
+    cleanup_handle(SH_HANDLE);
+
+    // connect
+    setup_handle(SH_CONNECT);
+    
+    CU_ASSERT(semanage_fcontext_list_local(sh, &records, &count) >= 0);
+    CU_ASSERT(count == 0);
+
+    CU_ASSERT_SIGNAL(semanage_fcontext_list_local(sh, NULL, &count), SIGSEGV);
+    CU_ASSERT_SIGNAL(semanage_fcontext_list_local(sh, &records, NULL), SIGSEGV);
+
+    cleanup_handle(SH_CONNECT);
+
+    // transaction
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_fcontext_list_local(sh, &records, &count) >= 0);
+    CU_ASSERT(count == 0);
+
+    add_local_fcontext(I_FIRST);
+    
+    CU_ASSERT(semanage_fcontext_list_local(sh, &records, &count) >= 0);
+    CU_ASSERT(count == 1);
+    CU_ASSERT_PTR_NOT_NULL(records[0]);
+
+    add_local_fcontext(I_SECOND);
+    
+    CU_ASSERT(semanage_fcontext_list_local(sh, &records, &count) >= 0);
+    CU_ASSERT(count == 2);
+    CU_ASSERT_PTR_NOT_NULL(records[0]);
+    CU_ASSERT_PTR_NOT_NULL(records[1]);
+
+    CU_ASSERT_SIGNAL(semanage_fcontext_list_local(sh, NULL, &count), SIGSEGV);
+    CU_ASSERT_SIGNAL(semanage_fcontext_list_local(sh, &records, NULL), SIGSEGV);
+
+    delete_local_fcontext(I_FIRST);
+    delete_local_fcontext(I_SECOND);
+    cleanup_handle(SH_TRANS);
+}

diff --git a/libsemanage/sanity-tests/tests/test_fcontext.h b/libsemanage/sanity-tests/tests/test_fcontext.h
new file mode 100644
index 0000000..80a5490
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_fcontext.h
@@ -0,0 +1,41 @@
+#ifndef __TEST_FCONTEXT_H__
+#define __TEST_FCONTEXT_H__
+
+#include <CUnit/Basic.h>
+
+int fcontext_test_init(void);
+int fcontext_test_cleanup(void);
+int fcontext_add_tests(CU_pSuite suite);
+
+// fcontext_record.h
+
+void test_fcontext_compare(void);
+void test_fcontext_compare2(void);
+void test_fcontext_key_create(void);
+void test_fcontext_key_extract(void);
+void test_fcontext_get_set_expr(void);
+void test_fcontext_get_set_type(void);
+void test_fcontext_get_type_str(void);
+void test_fcontext_get_set_con(void);
+void test_fcontext_create(void);
+void test_fcontext_clone(void);
+
+// fcontext_policy.h
+
+void test_fcontext_query(void);
+void test_fcontext_exists(void);
+void test_fcontext_count(void);
+void test_fcontext_iterate(void);
+void test_fcontext_list(void);
+
+// fcontext_local.h
+
+void test_fcontext_modify_del_local(void);
+void test_fcontext_query_local(void);
+void test_fcontext_exists_local(void);
+void test_fcontext_count_local(void);
+void test_fcontext_iterate_local(void);
+void test_fcontext_list_local(void);
+
+#endif
+

diff --git a/libsemanage/sanity-tests/tests/test_handle.c b/libsemanage/sanity-tests/tests/test_handle.c
new file mode 100644
index 0000000..810014d
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_handle.c
@@ -0,0 +1,432 @@
+#include <sys/wait.h>
+
+#include <semanage/semanage.h>
+#include <semanage/handle.h>
+
+#include <CUnit/Basic.h>
+
+#include "test_handle.h"
+#include "functions.h"
+
+extern semanage_handle_t *sh;
+
+int handle_test_init(void)
+{
+	return 0;
+}
+
+int handle_test_cleanup(void)
+{
+	return 0;
+}
+
+int handle_add_tests(CU_pSuite suite)
+{
+    CU_add_test(suite, "test_handle_create",    test_handle_create);
+    CU_add_test(suite, "test_connect",          test_connect);
+    CU_add_test(suite, "test_disconnect",       test_disconnect);
+    CU_add_test(suite, "test_transaction",      test_transaction);
+    CU_add_test(suite, "test_commit",           test_commit);
+    CU_add_test(suite, "test_is_connected",     test_is_connected);
+    CU_add_test(suite, "test_access_check",     test_access_check);
+    CU_add_test(suite, "test_is_managed",       test_is_managed);
+    CU_add_test(suite, "test_mls_enabled",      test_mls_enabled);
+    CU_add_test(suite, "msg_set_callback",      test_msg_set_callback);
+
+#if VERS_CHECK(2, 5)
+    CU_add_test(suite, "test_root",         test_root);
+#endif
+
+    CU_add_test(suite, "test_select_store", test_select_store);
+
+	return 0;
+}
+
+// Function semanage_handle_create
+
+void test_handle_create(void) {
+    sh = semanage_handle_create();
+
+    CU_ASSERT_PTR_NOT_NULL(sh);
+
+    semanage_handle_destroy(sh);
+}
+
+// Function semanage_connect
+// TODO: make semanage_direct_connect(sh) return error
+// TODO: make semanage_check_init return error
+// TODO: make semanage_create_store return error
+// TODO: make other functions return error
+// TODO: try all values of disable dontaudit (add file)
+
+void test_connect(void) {
+    // test without handle
+    setup_handle(SH_NULL);
+
+    CU_ASSERT_SIGNAL(semanage_connect(sh), SIGABRT);
+
+    // test handle created
+    helper_handle_create();
+
+    CU_ASSERT(semanage_connect(sh) >= 0);
+    CU_ASSERT(semanage_disconnect(sh) >= 0);
+
+    cleanup_handle(SH_HANDLE);
+
+    // test invalid store
+    setup_handle_invalid_store(SH_HANDLE);
+
+    CU_ASSERT(semanage_connect(sh) < 0);
+
+    cleanup_handle(SH_HANDLE);
+
+    // test normal use
+    setup_handle(SH_HANDLE);
+
+    CU_ASSERT(semanage_connect(sh) >= 0);
+
+    // test connecting twice
+    // TODO: connecting twice creates memory leaks
+    //CU_ASSERT(semanage_connect(sh) < 0);
+    CU_ASSERT(semanage_connect(sh) >= 0);
+
+    CU_ASSERT(semanage_disconnect(sh) >= 0);
+
+    cleanup_handle(SH_HANDLE);
+}
+
+// Function semanage_disconnect
+// TODO: disconnect when disconnect function not set
+// TODO: make semanage_remove_directory return error (twice)
+
+void test_disconnect(void) {
+    setup_handle(SH_NULL);
+
+    CU_ASSERT_SIGNAL(semanage_disconnect(sh), SIGABRT);
+
+    helper_handle_create();
+
+    CU_ASSERT_SIGNAL(semanage_disconnect(sh), SIGABRT);
+
+    helper_connect();
+
+    CU_ASSERT(semanage_disconnect(sh) >= 0);
+
+    cleanup_handle(SH_HANDLE);
+}
+
+// Function semanage_begin_transaction
+// TODO: make semanage_get_trans_lock return error
+// TODO: make semanage_make_sandbow return error
+// TODO: make semanage_make_final return error
+// TODO: there is a memory leak in semanage_begin_transaction()
+/*
+==24810== 101 (80 direct, 21 indirect) bytes in 1 blocks are definitely lost in loss record 26 of 31
+==24810==    at 0x4C30A1E: calloc (vg_replace_malloc.c:711)
+==24810==    by 0x5062AF8: semanage_genhomedircon (genhomedircon.c:1351)
+==24810==    by 0x505FAF4: semanage_direct_commit (direct_api.c:1567)
+==24810==    by 0x5064C6C: semanage_commit (handle.c:426)
+==24810==    by 0x41032E: test_transaction (test_handle.c:146)
+==24810==    by 0x4E3F106: ??? (in /usr/lib64/libcunit.so.1.0.1)
+==24810==    by 0x4E3F33C: ??? (in /usr/lib64/libcunit.so.1.0.1)
+==24810==    by 0x4E3F855: CU_run_suite (in /usr/lib64/libcunit.so.1.0.1)
+==24810==    by 0x42085A: main (libsemanage-tests.c:90)
+*/
+
+void test_transaction(void) {
+    // test without handle
+    setup_handle(SH_NULL);
+
+    CU_ASSERT_SIGNAL(semanage_begin_transaction(sh), SIGABRT);
+
+    // test with handle
+    helper_handle_create();
+
+    CU_ASSERT_SIGNAL(semanage_begin_transaction(sh), SIGABRT);
+
+    // test disconnected
+    helper_connect();
+    helper_disconnect();
+
+    CU_ASSERT(semanage_begin_transaction(sh) < 0);
+
+    cleanup_handle(SH_HANDLE);
+
+    // test normal use
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_begin_transaction(sh) >= 0);
+    CU_ASSERT(semanage_commit(sh) >= 0);
+
+    // test beginning transaction twice
+    // FIXME
+    //CU_ASSERT(semanage_begin_transaction(sh) >= 0);
+    //CU_ASSERT(semanage_begin_transaction(sh) >= 0);
+    //CU_ASSERT(semanage_commit(sh) >= 0);
+
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_commit
+// TODO: try other values of disable dontaudit
+// TODO: try other values of preserve tunables
+// TODO: make users->dtable->is_modified return true
+// TODO: try missing paths (lines 1236-1272)
+// TODO: error gotos (lines 1299-1514)
+// TODO: make sh->conf->disable_genhomedircon return true
+// TODO: make semanage_genhomedircon return error
+
+void test_commit(void) {
+    setup_handle(SH_NULL);
+
+    CU_ASSERT_SIGNAL(semanage_commit(sh), SIGABRT);
+
+    helper_handle_create();
+
+    CU_ASSERT_SIGNAL(semanage_commit(sh), SIGABRT);
+
+    helper_connect();
+
+    CU_ASSERT(semanage_commit(sh) < 0);
+
+    helper_begin_transaction();
+
+    // FIXME: memory leaks
+    CU_ASSERT(semanage_commit(sh) >= 0);
+
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_is_connected
+
+void test_is_connected(void) {
+    setup_handle(SH_NULL);
+
+    CU_ASSERT_SIGNAL(semanage_is_connected(sh), SIGABRT);
+
+    helper_handle_create();
+
+    CU_ASSERT(semanage_is_connected(sh) == 0);
+
+    helper_connect();
+
+    CU_ASSERT(semanage_is_connected(sh) == 1);
+
+    helper_begin_transaction();
+
+    CU_ASSERT(semanage_is_connected(sh) == 1);
+
+    // FIXME: memory leaks (semanage_commit)
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_access_check
+
+void test_access_check(void) {
+    int result = 0;
+
+    // test without handle
+    setup_handle(SH_NULL);
+
+    CU_ASSERT_SIGNAL(semanage_access_check(sh), SIGABRT);
+
+    // test with handle
+    helper_handle_create();
+
+    result = semanage_access_check(sh);
+
+    CU_ASSERT(result == 0 || result == SEMANAGE_CAN_READ
+              || result == SEMANAGE_CAN_WRITE);
+
+    cleanup_handle(SH_HANDLE);
+    
+    // test with invalid store
+    setup_handle_invalid_store(SH_HANDLE);
+
+    CU_ASSERT(semanage_access_check(sh) < 0);
+
+    cleanup_handle(SH_HANDLE);
+    
+    // test normal use
+    setup_handle(SH_CONNECT);
+
+    result = semanage_access_check(sh);
+
+    CU_ASSERT(result == 0 || result == SEMANAGE_CAN_READ
+              || result == SEMANAGE_CAN_WRITE);
+
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_is_managed
+// TODO: make semanage_check_init return error
+// TODO: make semanage_access_check return error
+
+void test_is_managed(void) {
+    int result = 0;
+    
+    // test without handle
+    setup_handle(SH_NULL);
+
+    CU_ASSERT_SIGNAL(semanage_is_managed(sh), SIGABRT);
+
+    // test with handle
+    helper_handle_create();
+
+    result = semanage_is_managed(sh);
+
+    CU_ASSERT(result == 0 || result == 1);
+
+    // test connected
+    helper_connect();
+
+    result = semanage_is_managed(sh);
+
+    CU_ASSERT(result < 0);
+
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_mls_enabled
+
+void test_mls_enabled(void) {
+    int result = 0;
+
+    // test without handle
+    setup_handle(SH_NULL);
+
+    CU_ASSERT_SIGNAL(semanage_mls_enabled(sh), SIGABRT);
+
+    // test with handle
+    helper_handle_create();
+
+    result = semanage_mls_enabled(sh);
+
+    CU_ASSERT(result == 0 || result == 1);
+
+    cleanup_handle(SH_HANDLE);
+    
+    // test with invalid store
+    setup_handle_invalid_store(SH_HANDLE);
+
+    CU_ASSERT(semanage_mls_enabled(sh) < 0);
+
+    cleanup_handle(SH_HANDLE);
+
+    // test connected
+    setup_handle(SH_CONNECT);
+
+    result = semanage_mls_enabled(sh);
+
+    CU_ASSERT(result == 0 || result == 1);
+
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_set_callback
+
+int msg_set_callback_count = 0;
+
+void helper_msg_set_callback(void *varg, semanage_handle_t *sh,
+                             const char *fmt, ...) {
+    msg_set_callback_count++;
+}
+
+void test_msg_set_callback(void) {
+    setup_handle(SH_CONNECT);
+
+    semanage_msg_set_callback(sh, helper_msg_set_callback, NULL);
+
+    // produce error message
+    semanage_commit(sh);
+
+    CU_ASSERT(msg_set_callback_count == 1);
+
+    semanage_msg_set_callback(sh, NULL, NULL);
+
+    // produce error message
+    semanage_commit(sh);
+
+    CU_ASSERT(msg_set_callback_count == 1);
+
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_root, semanage_set_root
+
+#if VERS_CHECK(2, 5)
+
+void helper_root(void) {
+    const char *root = semanage_root();
+
+    CU_ASSERT_STRING_EQUAL(root, "");
+
+    CU_ASSERT(semanage_set_root("asdf") >= 0);
+
+    root = semanage_root();
+
+    CU_ASSERT_STRING_EQUAL(root, "asdf");
+
+    CU_ASSERT(semanage_set_root("") >= 0);
+
+    root = semanage_root();
+
+    CU_ASSERT_STRING_EQUAL(root, "");
+}
+
+void test_root(void) {
+    // test without handle
+    setup_handle(SH_NULL);
+
+    helper_root();
+
+    // test with handle
+    helper_handle_create();
+
+    helper_root();
+
+    // test connected
+    helper_connect();
+
+    helper_root();
+
+    cleanup_handle(SH_CONNECT);
+}
+
+#endif
+
+// Function semanage_select_store
+
+void helper_select_store(char *name, enum semanage_connect_type type,
+                         int exp_result) {
+    setup_handle(SH_HANDLE);
+
+    semanage_select_store(sh, name, type);
+
+    int result = semanage_connect(sh);
+
+    if (exp_result < 0) {
+        CU_ASSERT(result < 0);
+    }
+    else {
+        CU_ASSERT(result >= 0);
+    }
+
+    if (result >= 0)
+        cleanup_handle(SH_CONNECT);
+    else
+        cleanup_handle(SH_HANDLE);
+}
+
+void test_select_store(void) {
+    helper_select_store("asdf", SEMANAGE_CON_INVALID - 1, -1);
+    helper_select_store("asdf", SEMANAGE_CON_POLSERV_REMOTE + 1, -1);
+    helper_select_store("", SEMANAGE_CON_DIRECT, 0);
+    CU_ASSERT_SIGNAL(helper_select_store(NULL, SEMANAGE_CON_DIRECT, -1),
+                     SIGSEGV);
+
+    helper_select_store("asdf", SEMANAGE_CON_INVALID, -1);
+    helper_select_store("asdf", SEMANAGE_CON_DIRECT, 0);
+    helper_select_store("asdf", SEMANAGE_CON_POLSERV_LOCAL, -1);
+    helper_select_store("asdf", SEMANAGE_CON_POLSERV_REMOTE, -1);
+}

diff --git a/libsemanage/sanity-tests/tests/test_handle.h b/libsemanage/sanity-tests/tests/test_handle.h
new file mode 100644
index 0000000..f6af4c5
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_handle.h
@@ -0,0 +1,30 @@
+#ifndef __TEST_HANDLE_H__
+#define __TEST_HANDLE_H__
+
+#include <CUnit/Basic.h>
+
+#include "functions.h"
+
+int handle_test_init(void);
+int handle_test_cleanup(void);
+int handle_add_tests(CU_pSuite suite);
+
+void test_handle_create(void);
+void test_connect(void);
+void test_disconnect(void);
+void test_transaction(void);
+void test_commit(void);
+void test_is_connected(void);
+void test_access_check(void);
+void test_is_managed(void);
+void test_mls_enabled(void);
+void test_msg_set_callback(void);
+
+#if VERS_CHECK(2, 5)
+void test_root(void);
+#endif
+
+void test_select_store(void);
+
+#endif
+

diff --git a/libsemanage/sanity-tests/tests/test_ibendport.c b/libsemanage/sanity-tests/tests/test_ibendport.c
new file mode 100644
index 0000000..1c3b36e
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_ibendport.c
@@ -0,0 +1,542 @@
+#include <stdio.h>
+#include <string.h>
+#include <semanage/semanage.h>
+#include <semanage/handle.h>
+#include <CUnit/Basic.h>
+
+#include "test_ibendport.h"
+#include "test_ibendport_module.h"
+#include "functions.h"
+
+extern semanage_handle_t *sh;
+
+int ibendport_test_init(void) {
+#ifdef FEATURE_INFINIBAND
+
+    semanage_handle_t *sh;
+
+    sh = semanage_handle_create();
+
+    if (semanage_connect(sh) < 0) {
+        semanage_handle_destroy(sh);
+        return -1;
+    }
+
+    if (semanage_begin_transaction(sh) < 0)
+        goto err;
+
+    if (semanage_module_install(sh, (char *) test_ibendport_module,
+                                test_ibendport_module_len, "test_ibendport",
+                                "cil") < 0) {
+        semanage_disconnect(sh);
+        semanage_handle_destroy(sh);
+        return -1;
+    }
+
+    if (semanage_commit(sh) < 0) {
+        semanage_disconnect(sh);
+        semanage_handle_destroy(sh);
+        return -1;
+    }
+
+    return 0;
+
+err:
+    semanage_disconnect(sh);
+    semanage_handle_destroy(sh);
+    return -1;
+
+#else
+
+    return 0;
+
+#endif
+}
+
+int ibendport_test_cleanup(void) {
+#ifdef FEATURE_INFINIBAND
+
+    semanage_handle_t *sh;
+
+    sh = semanage_handle_create();
+
+    if (semanage_connect(sh) < 0)
+        return -1;
+
+    if (semanage_begin_transaction(sh) < 0) {
+        semanage_disconnect(sh);
+        semanage_handle_destroy(sh);
+        return -1;
+    }
+
+    if (semanage_module_remove(sh, "test_ibendport") < 0) {
+        semanage_disconnect(sh);
+        semanage_handle_destroy(sh);
+        return -1;
+    }
+
+    if (semanage_commit(sh) < 0) {
+        semanage_disconnect(sh);
+        semanage_handle_destroy(sh);
+        return -1;
+    }
+
+    semanage_disconnect(sh);
+    semanage_handle_destroy(sh);
+
+#endif
+
+    return 0;
+}
+
+int ibendport_add_tests(CU_pSuite suite) {
+#ifdef FEATURE_INFINIBAND
+    CU_add_test(suite, "ibendport_query", test_ibendport_query);
+    CU_add_test(suite, "ibendport_exists", test_ibendport_exists);
+    CU_add_test(suite, "ibendport_count", test_ibendport_count);
+    CU_add_test(suite, "ibendport_iterate", test_ibendport_iterate);
+    CU_add_test(suite, "ibendport_list", test_ibendport_list);
+
+    CU_add_test(suite, "ibendport_modify_del_query_local",
+                test_ibendport_modify_del_query_local);
+    CU_add_test(suite, "ibendport_exists_local", test_ibendport_exists_local);
+    CU_add_test(suite, "ibendport_count_local", test_ibendport_count_local);
+    CU_add_test(suite, "ibendport_iterate_local", test_ibendport_iterate_local);
+    CU_add_test(suite, "ibendport_list_local", test_ibendport_list_local);
+#endif
+
+    return 0;
+}
+
+#ifdef FEATURE_INFINIBAND
+
+// Function semanage_ibendport_query
+
+void test_ibendport_query(void) {
+    semanage_ibendport_key_t *key1 = NULL;
+    semanage_ibendport_key_t *key2 = NULL;
+    semanage_ibendport_t *response1 = NULL;
+    semanage_ibendport_t *response2 = NULL;
+    char *name = NULL;
+    semanage_context_t *con = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_ibendport_key_create(sh, IBENDPORT_INV_NAME,
+                                            IBENDPORT_INV_PORT, &key1) >= 0);
+
+    CU_ASSERT(semanage_ibendport_key_create(sh, IBENDPORT_1_NAME,
+                                            IBENDPORT_1_PORT, &key2) >= 0);
+
+    // test nonexisting ibendport
+    CU_ASSERT(semanage_ibendport_query(sh, key1, &response1) >= 0);
+    CU_ASSERT(response1 == NULL);
+
+    // test existing ibendport
+    CU_ASSERT(semanage_ibendport_query(sh, key2, &response2) >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(response2);
+
+    CU_ASSERT(semanage_ibendport_get_ibdev_name(sh, response2, &name) >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(name);
+    CU_ASSERT_STRING_EQUAL(name, IBENDPORT_1_NAME);
+
+    CU_ASSERT(semanage_ibendport_get_port(response2) == IBENDPORT_1_PORT);
+
+    con = semanage_ibendport_get_con(response2);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(con);
+    CU_ASSERT(context_compare(con, IBENDPORT_1_CON) == 0);
+
+    // cleanup
+    free(name);
+    semanage_ibendport_key_free(key1);
+    semanage_ibendport_key_free(key2);
+    semanage_ibendport_free(response1);
+    semanage_ibendport_free(response2);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_ibendport_exists
+
+void test_ibendport_exists(void) {
+    semanage_ibendport_key_t *key1 = NULL;
+    semanage_ibendport_key_t *key2 = NULL;
+    int response = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_ibendport_key_create(sh, IBENDPORT_INV_NAME,
+                                            IBENDPORT_INV_PORT, &key1) >= 0);
+
+    CU_ASSERT(semanage_ibendport_key_create(sh, IBENDPORT_1_NAME,
+                                            IBENDPORT_1_PORT, &key2) >= 0);
+
+    // test nonexisting ibendport
+    CU_ASSERT(semanage_ibendport_exists(sh, key1, &response) >= 0);
+    CU_ASSERT(!response);
+
+    // test existing ibendport
+    CU_ASSERT(semanage_ibendport_exists(sh, key2, &response) >= 0);
+    CU_ASSERT(response);
+
+    // cleanup
+    semanage_ibendport_key_free(key1);
+    semanage_ibendport_key_free(key2);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_ibendport_count
+
+void test_ibendport_count(void) {
+    unsigned int count = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    // test
+    CU_ASSERT(semanage_ibendport_count(sh, &count) >= 0);
+
+    CU_ASSERT(count == IBENDPORT_COUNT);
+
+    // cleanup
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_ibendport_iterate
+
+unsigned int helper_ibendport_iterate_counter = 0;
+
+int helper_ibendport_iterate(const semanage_ibendport_t *ibendport,
+                             void *fn_arg) {
+    CU_ASSERT(fn_arg == (void *) 42);
+
+    helper_ibendport_iterate_counter++;
+
+    return 0;
+}
+
+int helper_ibendport_iterate_error(const semanage_ibendport_t *ibendport,
+                                   void *fn_arg) {
+    CU_ASSERT(fn_arg == (void *) 42);
+
+    helper_ibendport_iterate_counter++;
+
+    return -1;
+}
+
+int helper_ibendport_iterate_break(const semanage_ibendport_t *ibendport,
+                                   void *fn_arg) {
+    CU_ASSERT(fn_arg == (void *) 42);
+
+    helper_ibendport_iterate_counter++;
+
+    return 1;
+}
+
+void test_ibendport_iterate(void) {
+    // setup
+    setup_handle(SH_CONNECT);
+
+    // test
+    helper_ibendport_iterate_counter = 0;
+
+    CU_ASSERT(semanage_ibendport_iterate(sh, helper_ibendport_iterate,
+                                         (void *) 42) >= 0);
+    CU_ASSERT(helper_ibendport_iterate_counter == IBENDPORT_COUNT);
+
+    // test function which returns error
+    helper_ibendport_iterate_counter = 0;
+
+    CU_ASSERT(semanage_ibendport_iterate(sh, helper_ibendport_iterate_error,
+                                         (void *) 42) < 0);
+    CU_ASSERT(helper_ibendport_iterate_counter == 1);
+
+    // test function which requests break
+    helper_ibendport_iterate_counter = 0;
+
+    CU_ASSERT(semanage_ibendport_iterate(sh, helper_ibendport_iterate_break,
+                                         (void *) 42) >= 0);
+    CU_ASSERT(helper_ibendport_iterate_counter == 1);
+
+    // cleanup
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_ibendport_list
+
+void test_ibendport_list(void) {
+    semanage_ibendport_t **records = NULL;
+    unsigned int count = 42;
+    char *name = NULL;
+    semanage_context_t *con = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    // test
+    CU_ASSERT(semanage_ibendport_list(sh, &records, &count) >= 0);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(records);
+    CU_ASSERT(count == IBENDPORT_COUNT);
+
+    for (unsigned int i = 0; i < count; i++) {
+        CU_ASSERT_PTR_NOT_NULL_FATAL(records[i]);
+
+        CU_ASSERT(semanage_ibendport_get_ibdev_name(sh, records[i],
+                                                    &name) >= 0);
+
+        con = semanage_ibendport_get_con(records[i]);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(con);
+
+        free(name);
+    }
+
+    // cleanup
+    for (unsigned int i = 0; i < count; i++) {
+        semanage_ibendport_free(records[i]);
+    }
+
+    free(records);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_ibendport_modify_local, semanage_ibendport_del_local,
+// semanage_ibendport_query_local
+
+void test_ibendport_modify_del_query_local(void) {
+    semanage_ibendport_t *ibendport;
+    semanage_ibendport_t *ibendport_local;
+    semanage_ibendport_t *ibendport_tmp;
+    semanage_ibendport_key_t *key = NULL;
+    semanage_ibendport_key_t *key_tmp = NULL;
+    semanage_context_t *con = NULL;
+    semanage_context_t *con_tmp = NULL;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_ibendport_key_create(sh, "asdf", 1, &key) >= 0);
+
+    CU_ASSERT(semanage_ibendport_create(sh, &ibendport) >= 0);
+    CU_ASSERT(semanage_ibendport_set_ibdev_name(sh, ibendport, "asdf") >= 0);
+    semanage_ibendport_set_port(ibendport, 1);
+    CU_ASSERT(semanage_context_from_string(sh, "system_u:object_r:bin_t:s0",
+                                           &con) >= 0);
+    CU_ASSERT(semanage_ibendport_set_con(sh, ibendport, con) >= 0);
+
+    // add second record, so that semanage_ibendport_compare2_qsort will be
+    // called
+    CU_ASSERT(semanage_ibendport_key_create(sh, "qwerty", 2, &key_tmp) >= 0);
+
+    CU_ASSERT(semanage_ibendport_create(sh, &ibendport_tmp) >= 0);
+    CU_ASSERT(semanage_ibendport_set_ibdev_name(sh, ibendport_tmp,
+                                                "qwerty") >= 0);
+    semanage_ibendport_set_port(ibendport_tmp, 2);
+    CU_ASSERT(semanage_context_from_string(sh, "system_u:object_r:bin_t:s0",
+                                           &con_tmp) >= 0);
+    CU_ASSERT(semanage_ibendport_set_con(sh, ibendport_tmp, con_tmp) >= 0);
+
+    // test
+    CU_ASSERT(semanage_ibendport_modify_local(sh, key, ibendport) >= 0);
+    CU_ASSERT(semanage_ibendport_modify_local(sh, key_tmp, ibendport_tmp) >= 0);
+
+    // write changes to file
+    helper_commit();
+    helper_begin_transaction();
+
+    CU_ASSERT(semanage_ibendport_query_local(sh, key, &ibendport_local) >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(ibendport_local);
+
+    CU_ASSERT(semanage_ibendport_del_local(sh, key) >= 0);
+    CU_ASSERT(semanage_ibendport_del_local(sh, key_tmp) >= 0);
+
+    CU_ASSERT(semanage_ibendport_query_local(sh, key, &ibendport_local) < 0);
+
+    // cleanup
+    semanage_context_free(con);
+    semanage_context_free(con_tmp);
+    semanage_ibendport_key_free(key);
+    semanage_ibendport_key_free(key_tmp);
+    semanage_ibendport_free(ibendport);
+    semanage_ibendport_free(ibendport_local);
+    semanage_ibendport_free(ibendport_tmp);
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_ibendport_exists_local
+
+void test_ibendport_exists_local(void) {
+    semanage_ibendport_key_t *key1 = NULL;
+    semanage_ibendport_key_t *key2 = NULL;
+    int response = 42;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    add_local_ibendport(I_FIRST);
+
+    CU_ASSERT(semanage_ibendport_key_create(sh, IBENDPORT_INV_NAME,
+                                            IBENDPORT_INV_PORT, &key1) >= 0);
+
+    CU_ASSERT(semanage_ibendport_key_create(sh, "ibendport0", 0, &key2) >= 0);
+
+    // test nonexisting ibendport
+    CU_ASSERT(semanage_ibendport_exists_local(sh, key1, &response) >= 0);
+    CU_ASSERT(!response);
+
+    // test existing ibendport
+    CU_ASSERT(semanage_ibendport_exists_local(sh, key2, &response) >= 0);
+    CU_ASSERT(response);
+
+    // cleanup
+    
+    delete_local_ibendport(I_FIRST);
+
+    semanage_ibendport_key_free(key1);
+    semanage_ibendport_key_free(key2);
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_ibendport_count_local
+
+void test_ibendport_count_local(void) {
+    unsigned int count = 42;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    add_local_ibendport(I_FIRST);
+    add_local_ibendport(I_SECOND);
+    add_local_ibendport(I_THIRD);
+
+    // test
+    CU_ASSERT(semanage_ibendport_count_local(sh, &count) >= 0);
+
+    CU_ASSERT(count == 3);
+
+    // cleanup
+    delete_local_ibendport(I_FIRST);
+    delete_local_ibendport(I_SECOND);
+    delete_local_ibendport(I_THIRD);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_ibendport_iterate_local
+
+unsigned int helper_ibendport_iterate_local_counter = 0;
+
+int helper_ibendport_iterate_local(const semanage_ibendport_t *ibendport,
+                                   void *fn_arg) {
+    CU_ASSERT(fn_arg == (void *) 42);
+
+    helper_ibendport_iterate_local_counter++;
+
+    return 0;
+}
+
+int helper_ibendport_iterate_local_error(const semanage_ibendport_t *ibendport,
+                                         void *fn_arg) {
+    CU_ASSERT(fn_arg == (void *) 42);
+
+    helper_ibendport_iterate_local_counter++;
+
+    return -1;
+}
+
+int helper_ibendport_iterate_local_break(const semanage_ibendport_t *ibendport,
+                                         void *fn_arg) {
+    CU_ASSERT(fn_arg == (void *) 42);
+
+    helper_ibendport_iterate_local_counter++;
+
+    return 1;
+}
+
+void test_ibendport_iterate_local(void) {
+    // setup
+    setup_handle(SH_TRANS);
+
+    add_local_ibendport(I_FIRST);
+    add_local_ibendport(I_SECOND);
+    add_local_ibendport(I_THIRD);
+
+    // test
+    helper_ibendport_iterate_local_counter = 0;
+
+    CU_ASSERT(semanage_ibendport_iterate_local(sh,
+                             helper_ibendport_iterate_local, (void *) 42) >= 0);
+    CU_ASSERT(helper_ibendport_iterate_local_counter == 3);
+
+    // test function which returns error
+    helper_ibendport_iterate_local_counter = 0;
+
+    CU_ASSERT(semanage_ibendport_iterate_local(sh,
+                        helper_ibendport_iterate_local_error, (void *) 42) < 0);
+    CU_ASSERT(helper_ibendport_iterate_local_counter == 1);
+
+    // test function which requests break
+    helper_ibendport_iterate_local_counter = 0;
+
+    CU_ASSERT(semanage_ibendport_iterate_local(sh,
+                       helper_ibendport_iterate_local_break, (void *) 42) >= 0);
+    // TODO: there is a bug
+    //CU_ASSERT(helper_ibendport_iterate_local_counter == 1);
+
+    // cleanup
+    delete_local_ibendport(I_FIRST);
+    delete_local_ibendport(I_SECOND);
+    delete_local_ibendport(I_THIRD);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_ibendport_list_local
+
+void test_ibendport_list_local(void) {
+    semanage_ibendport_t **records = NULL;
+    unsigned int count = 42;
+    char *name = NULL;
+    semanage_context_t *con = NULL;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    add_local_ibendport(I_FIRST);
+    add_local_ibendport(I_SECOND);
+    add_local_ibendport(I_THIRD);
+
+    // test
+    CU_ASSERT(semanage_ibendport_list_local(sh, &records, &count) >= 0);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(records);
+    CU_ASSERT(count == 3);
+
+    for (unsigned int i = 0; i < count; i++) {
+        CU_ASSERT_PTR_NOT_NULL_FATAL(records[i]);
+
+        CU_ASSERT(semanage_ibendport_get_ibdev_name(sh, records[i],
+                                                    &name) >= 0);
+
+        con = semanage_ibendport_get_con(records[i]);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(con);
+
+        free(name);
+    }
+
+    // cleanup
+    for (unsigned int i = 0; i < count; i++) {
+        semanage_ibendport_free(records[i]);
+    }
+
+    free(records);
+
+    delete_local_ibendport(I_FIRST);
+    delete_local_ibendport(I_SECOND);
+    delete_local_ibendport(I_THIRD);
+
+    cleanup_handle(SH_TRANS);
+}
+
+#endif

diff --git a/libsemanage/sanity-tests/tests/test_ibendport.h b/libsemanage/sanity-tests/tests/test_ibendport.h
new file mode 100644
index 0000000..7bb75c3
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_ibendport.h
@@ -0,0 +1,32 @@
+#ifndef __TEST_IBENDPORT_H__
+#define __TEST_IBENDPORT_H__
+
+#include <CUnit/Basic.h>
+
+#include "functions.h"
+
+int ibendport_test_init(void);
+int ibendport_test_cleanup(void);
+int ibendport_add_tests(CU_pSuite suite);
+
+#if VERS_CHECK(2, 5)
+
+// ibendports_policy.h
+
+void test_ibendport_query(void);
+void test_ibendport_exists(void);
+void test_ibendport_count(void);
+void test_ibendport_iterate(void);
+void test_ibendport_list(void);
+
+// ibendports_local.h
+
+void test_ibendport_modify_del_query_local(void);
+void test_ibendport_exists_local(void);
+void test_ibendport_count_local(void);
+void test_ibendport_iterate_local(void);
+void test_ibendport_list_local(void);
+
+#endif
+
+#endif

diff --git a/libsemanage/sanity-tests/tests/test_ibendport.te b/libsemanage/sanity-tests/tests/test_ibendport.te
new file mode 100644
index 0000000..0746f0b
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_ibendport.te
@@ -0,0 +1,34 @@
+policy_module(test_ibendport,1.0)
+
+gen_require(`
+        type bin_t;
+        type infiniband_mgmt_device_t;
+')
+
+attribute ibendportdomain;
+
+# Domain for process.
+type test_ibendport_manage_subnet_t;
+domain_type(test_ibendport_manage_subnet_t)
+typeattribute test_ibendport_manage_subnet_t ibendportdomain;
+
+type test_ibendport_t;
+ifdef(`corenet_ib_endport',`
+corenet_ib_endport(test_ibendport_t)
+')
+
+dev_rw_infiniband_dev(test_ibendport_manage_subnet_t)
+dev_rw_sysfs(test_ibendport_manage_subnet_t)
+
+corecmd_bin_entry_type(test_ibendport_manage_subnet_t)
+
+allow test_ibendport_manage_subnet_t infiniband_mgmt_device_t:chr_file { read write open ioctl};
+
+ifdef(`corenet_ib_access_unlabeled_pkeys',`
+corenet_ib_access_unlabeled_pkeys(test_ibendport_manage_subnet_t)
+')
+
+allow test_ibendport_manage_subnet_t test_ibendport_t:infiniband_endport manage_subnet;
+
+# Allow all of these domains to be entered from the sysadm domain.
+miscfiles_domain_entry_test_files(ibendportdomain)

diff --git a/libsemanage/sanity-tests/tests/test_ibendport_module.h b/libsemanage/sanity-tests/tests/test_ibendport_module.h
new file mode 100644
index 0000000..0fdd922
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_ibendport_module.h
@@ -0,0 +1,23 @@
+#define IBENDPORT_COUNT 2
+
+#define IBENDPORT_MODULE_SOURCE \
+    "(type test_ibendport_t)\n" \
+    "(type test_ibendport_second_t)\n" \
+    "(roletype object_r test_ibendport_t)\n" \
+    "(roletype object_r test_ibendport_second_t)\n" \
+    "(ibendportcon mlx4_0 1 (system_u object_r test_ibendport_t ((s0) (s0))))\n" \
+    "(ibendportcon mlx4_1 2 (system_u object_r test_ibendport_second_t ((s0) (s0))))\n"
+
+#define IBENDPORT_INV_NAME "mlx4_42"
+#define IBENDPORT_INV_PORT 42
+
+#define IBENDPORT_1_NAME "mlx4_0"
+#define IBENDPORT_1_PORT 1
+#define IBENDPORT_1_CON "system_u:object_r:test_ibendport_t:s0"
+
+#define IBENDPORT_2_NAME "mlx4_1"
+#define IBENDPORT_2_PORT 2
+#define IBENDPORT_2_CON "system_u:object_r:test_ibendport_second_t:s0"
+
+const char *test_ibendport_module = IBENDPORT_MODULE_SOURCE;
+size_t test_ibendport_module_len = (sizeof IBENDPORT_MODULE_SOURCE) - 1;

diff --git a/libsemanage/sanity-tests/tests/test_iface.c b/libsemanage/sanity-tests/tests/test_iface.c
new file mode 100644
index 0000000..e43c366
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_iface.c
@@ -0,0 +1,566 @@
+#include <stdio.h>
+#include <semanage/semanage.h>
+#include <semanage/handle.h>
+#include <CUnit/Basic.h>
+
+#include "test_iface.h"
+#include "functions.h"
+
+extern semanage_handle_t *sh;
+
+// TODO: current policies does not have any netifcon rules
+#define IFACE_COUNT 0
+
+int iface_test_init(void) {
+	return 0;
+}
+
+int iface_test_cleanup(void) {
+	return 0;
+}
+
+int iface_add_tests(CU_pSuite suite) {
+    CU_add_test(suite, "iface_compare", test_iface_compare);
+    CU_add_test(suite, "iface_compare2", test_iface_compare2);
+    CU_add_test(suite, "iface_key_create", test_iface_key_create);
+    CU_add_test(suite, "iface_key_extract", test_iface_key_extract);
+    CU_add_test(suite, "iface_get_set_name", test_iface_get_set_name);
+    CU_add_test(suite, "iface_get_set_ifcon", test_iface_get_set_ifcon);
+    CU_add_test(suite, "iface_get_set_msgcon", test_iface_get_set_msgcon);
+    CU_add_test(suite, "iface_create)", test_iface_create);
+    CU_add_test(suite, "iface_clone);", test_iface_clone);
+
+    CU_add_test(suite, "iface_query", test_iface_query);
+    CU_add_test(suite, "iface_exists", test_iface_exists);
+    CU_add_test(suite, "iface_count", test_iface_count);
+    CU_add_test(suite, "iface_iterate", test_iface_iterate);
+    CU_add_test(suite, "iface_list", test_iface_list);
+
+    CU_add_test(suite, "iface_modify_del_query_local",
+                test_iface_modify_del_query_local);
+    CU_add_test(suite, "iface_exists_local", test_iface_exists_local);
+    CU_add_test(suite, "iface_count_local", test_iface_count_local);
+    CU_add_test(suite, "iface_iterate_local", test_iface_iterate_local);
+    CU_add_test(suite, "iface_list_local", test_iface_list_local);
+
+	return 0;
+}
+
+// Function semanage_iface_compare
+
+void test_iface_compare(void) {
+    semanage_iface_t *iface = NULL;
+    semanage_iface_key_t *key1 = NULL;
+    semanage_iface_key_t *key2 = NULL;
+    int result = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    iface = get_iface();
+
+    key1 = get_iface_key();
+
+    CU_ASSERT(semanage_iface_key_create(sh, "qwerty", &key2) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key2);
+
+    // test
+    result = semanage_iface_compare(iface, key1);
+
+    CU_ASSERT(result == 0);
+
+    result = semanage_iface_compare(iface, key2);
+
+    CU_ASSERT(result != 0);
+
+    // cleanup
+    semanage_iface_free(iface);
+    semanage_iface_key_free(key1);
+    semanage_iface_key_free(key2);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_iface_compare2
+
+void test_iface_compare2(void) {
+    semanage_iface_t *iface1 = NULL;
+    semanage_iface_t *iface2 = NULL;
+    semanage_iface_t *iface3 = NULL;
+    int result = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    iface1 = get_iface();
+    iface2 = get_iface();
+
+    iface3 = get_iface();
+    CU_ASSERT(semanage_iface_set_name(sh, iface3, "qwerty") >= 0);
+
+    // test
+    result = semanage_iface_compare2(iface1, iface2);
+
+    CU_ASSERT(result == 0);
+
+    result = semanage_iface_compare2(iface1, iface3);
+
+    CU_ASSERT(result != 0);
+
+    // cleanup
+    semanage_iface_free(iface1);
+    semanage_iface_free(iface2);
+    semanage_iface_free(iface3);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_iface_create
+
+void test_iface_key_create(void) {
+    semanage_iface_key_t *key = NULL;
+
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_iface_key_create(sh, "asdf", &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    semanage_iface_key_free(key);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_iface_extract
+
+void test_iface_key_extract(void) {
+    semanage_iface_t *iface = NULL;
+    semanage_iface_key_t *key = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    iface = get_iface();
+
+    // test
+    CU_ASSERT(semanage_iface_key_extract(sh, iface, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    // cleanup
+    semanage_iface_free(iface);
+    semanage_iface_key_free(key);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_iface_get_name, semanage_iface_set_name
+
+void test_iface_get_set_name(void) {
+    semanage_iface_t *iface = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    iface = get_iface();
+
+    // test
+    CU_ASSERT(semanage_iface_set_name(sh, iface, "my_asdf") == 0);
+
+    CU_ASSERT_STRING_EQUAL(semanage_iface_get_name(iface), "my_asdf");
+
+    // cleanup
+    semanage_iface_free(iface);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_iface_get_ifcon, semanage_iface_set_ifcon
+
+void test_iface_get_set_ifcon(void) {
+    semanage_iface_t *iface = NULL;
+    semanage_context_t *con1 = NULL;
+    semanage_context_t *con2 = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    iface = get_iface();
+
+    CU_ASSERT(semanage_context_from_string(sh,
+                               "my_user_u:my_role_r:my_type_t:s0", &con1) >= 0);
+
+    // test
+    CU_ASSERT(semanage_iface_set_ifcon(sh, iface, con1) == 0);
+
+    con2 = semanage_iface_get_ifcon(iface);
+
+    CU_ASSERT_CONTEXT_EQUAL(con1, con2);
+
+    // cleanup
+    semanage_iface_free(iface);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_iface_get_msgcon, semanage_iface_set_msgcon
+
+void test_iface_get_set_msgcon(void) {
+    semanage_iface_t *iface = NULL;
+    semanage_context_t *con1 = NULL;
+    semanage_context_t *con2 = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    iface = get_iface();
+
+    CU_ASSERT(semanage_context_from_string(sh,
+                              "my_user_u:my_role_r:my_type_t:s0", &con1) >= 0);
+
+    // test
+    CU_ASSERT(semanage_iface_set_msgcon(sh, iface, con1) == 0);
+
+    con2 = semanage_iface_get_msgcon(iface);
+
+    CU_ASSERT_CONTEXT_EQUAL(con1, con2);
+
+    // cleanup
+    semanage_iface_free(iface);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_iface_create
+
+void test_iface_create(void) {
+    semanage_iface_t *iface = NULL;
+    semanage_context_t *ifcon = NULL;
+    semanage_context_t *msgcon = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    // test
+    CU_ASSERT(semanage_iface_create(sh, &iface) >= 0);
+
+    CU_ASSERT(semanage_iface_set_name(sh, iface, "asdf") >= 0);
+
+    CU_ASSERT(semanage_context_from_string(sh, "user_u:role_r:type_t:s0",
+                                           &ifcon) >= 0);
+    CU_ASSERT(semanage_iface_set_ifcon(sh, iface, ifcon) >= 0);
+
+    CU_ASSERT(semanage_context_from_string(sh, "user_u:role_r:type_t:s0",
+                                           &msgcon) >= 0);
+    CU_ASSERT(semanage_iface_set_msgcon(sh, iface, msgcon) >= 0);
+
+    // cleanup
+    semanage_iface_free(iface);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_iface_clone
+
+void test_iface_clone(void) {
+    semanage_iface_t *iface = NULL;
+    semanage_iface_t *iface_clone = NULL;
+    semanage_context_t *ifcon = NULL;
+    semanage_context_t *ifcon2 = NULL;
+    semanage_context_t *msgcon = NULL;
+    semanage_context_t *msgcon2 = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_iface_create(sh, &iface) >= 0);
+
+    CU_ASSERT(semanage_iface_set_name(sh, iface, "asdf") >= 0);
+
+    CU_ASSERT(semanage_context_from_string(sh, "user_u:role_r:if_type_t:s0",
+                                           &ifcon) >= 0);
+    CU_ASSERT(semanage_iface_set_ifcon(sh, iface, ifcon) >= 0);
+
+    CU_ASSERT(semanage_context_from_string(sh, "user_u:role_r:msg_type_t:s0",
+                                           &msgcon) >= 0);
+    CU_ASSERT(semanage_iface_set_msgcon(sh, iface, msgcon) >= 0);
+
+    // test
+    CU_ASSERT(semanage_iface_clone(sh, iface, &iface_clone) >= 0);
+
+    CU_ASSERT_STRING_EQUAL(semanage_iface_get_name(iface_clone), "asdf");
+
+    ifcon2 = semanage_iface_get_ifcon(iface_clone);
+    
+    CU_ASSERT_CONTEXT_EQUAL(ifcon, ifcon2);
+
+    msgcon2 = semanage_iface_get_msgcon(iface_clone);
+
+    CU_ASSERT_CONTEXT_EQUAL(msgcon, msgcon2);
+
+    // cleanup
+    semanage_iface_free(iface);
+    semanage_iface_free(iface_clone);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_iface_query
+
+void test_iface_query(void) {
+    semanage_iface_t *iface = NULL;
+    semanage_iface_key_t *key = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    key = get_iface_key();
+
+    // test
+    CU_ASSERT(semanage_iface_query(sh, key, &iface) >= 0);
+
+    CU_ASSERT(iface == NULL);
+
+    // cleanup
+    semanage_iface_free(iface);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_iface_exists
+
+void test_iface_exists(void) {
+    semanage_iface_key_t *key = NULL;
+    int response = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    key = get_iface_key();
+
+    // test
+    CU_ASSERT(semanage_iface_exists(sh, key, &response) >= 0);
+
+    CU_ASSERT(!response);
+
+    // cleanup
+    semanage_iface_key_free(key);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_iface_count
+
+void test_iface_count(void) {
+    unsigned int count = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    // test
+    CU_ASSERT(semanage_iface_count(sh, &count) >= 0);
+
+    CU_ASSERT(count == IFACE_COUNT);
+
+    // cleanup
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_iface_iterate
+
+unsigned int counter_iface_iterate = 0;
+
+int handler_iface_iterate(const semanage_iface_t *record, void *varg) {
+    counter_iface_iterate++;
+    return 0;
+}
+
+void test_iface_iterate(void) {
+    // setup
+    setup_handle(SH_CONNECT);
+
+    // test
+    semanage_iface_iterate(sh, handler_iface_iterate, NULL);
+
+    CU_ASSERT(counter_iface_iterate == IFACE_COUNT);
+
+    // cleanup
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_iface_list
+
+void test_iface_list(void) {
+    semanage_iface_t **records = NULL;
+    unsigned int count = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    // test
+    CU_ASSERT(semanage_iface_list(sh, &records, &count) >= 0);
+
+    CU_ASSERT(count == IFACE_COUNT);
+
+    for (unsigned int i = 0; i < count; i++) {
+        CU_ASSERT_PTR_NOT_NULL(records[i]);
+    }
+
+    for (unsigned int i = 0; i < count; i++) {
+        semanage_iface_free(records[i]);
+    }
+
+    // cleanup
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_iface_modify_local, semanage_iface_del_local,
+// semanage_iface_query_local
+
+void test_iface_modify_del_query_local(void) {
+    semanage_iface_t *iface;
+    semanage_iface_t *iface_local;
+    semanage_iface_key_t *key = NULL;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    iface = get_iface();
+
+    CU_ASSERT(semanage_iface_key_extract(sh, iface, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    // test
+    CU_ASSERT(semanage_iface_modify_local(sh, key, iface) >= 0);
+
+    // write changes to file
+    helper_commit();
+    helper_begin_transaction();
+
+    CU_ASSERT(semanage_iface_query_local(sh, key, &iface_local) >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(iface_local);
+
+    CU_ASSERT(semanage_iface_del_local(sh, key) >= 0);
+
+    CU_ASSERT(semanage_iface_query_local(sh, key, &iface_local) < 0);
+
+    // cleanup
+    semanage_iface_free(iface);
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_iface_exists_local
+
+void test_iface_exists_local(void) {
+    semanage_iface_t *iface1 = NULL;
+    semanage_iface_key_t *key1 = NULL;
+    semanage_iface_key_t *key2 = NULL;
+    int response = 42;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_iface_create(sh, &iface1) >= 0);
+    CU_ASSERT(semanage_iface_set_name(sh, iface1, "asdf") >= 0);
+
+    CU_ASSERT(semanage_iface_key_extract(sh, iface1, &key1) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key1);
+
+    CU_ASSERT(semanage_iface_modify_local(sh, key1, iface1) >= 0);
+
+    CU_ASSERT(semanage_iface_key_create(sh, "qwerty", &key2) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key2);
+
+    // test existing
+    CU_ASSERT(semanage_iface_exists_local(sh, key1, &response) >= 0);
+
+    CU_ASSERT(response);
+
+    // test nonexistent
+    CU_ASSERT(semanage_iface_exists_local(sh, key2, &response) >= 0);
+
+    CU_ASSERT(!response);
+
+    // cleanup
+    CU_ASSERT(semanage_iface_del_local(sh, key1) >= 0);
+    semanage_iface_free(iface1);
+    semanage_iface_key_free(key1);
+    semanage_iface_key_free(key2);
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_iface_count_local
+
+void test_iface_count_local(void) {
+    unsigned int count = 42;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    add_local_iface(I_FIRST);
+    add_local_iface(I_SECOND);
+    add_local_iface(I_THIRD);
+
+    // test
+    CU_ASSERT(semanage_iface_count_local(sh, &count) >= 0);
+
+    CU_ASSERT(count == 3);
+
+    // cleanup
+    delete_local_iface(I_FIRST);
+    delete_local_iface(I_SECOND);
+    delete_local_iface(I_THIRD);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_iface_iterate_local
+
+unsigned int counter_iface_iterate_local = 0;
+
+int handler_iface_iterate_local(const semanage_iface_t *record, void *varg) {
+    counter_iface_iterate_local++;
+    return 0;
+}
+
+void test_iface_iterate_local(void) {
+    // setup
+    setup_handle(SH_TRANS);
+
+    add_local_iface(I_FIRST);
+    add_local_iface(I_SECOND);
+    add_local_iface(I_THIRD);
+
+    // test
+    semanage_iface_iterate_local(sh, handler_iface_iterate_local, NULL);
+
+    CU_ASSERT(counter_iface_iterate_local == 3);
+
+    // cleanup
+    delete_local_iface(I_FIRST);
+    delete_local_iface(I_SECOND);
+    delete_local_iface(I_THIRD);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_iface_list_local
+
+void test_iface_list_local(void) {
+    semanage_iface_t **records = NULL;
+    unsigned int count = 42;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    add_local_iface(I_FIRST);
+    add_local_iface(I_SECOND);
+    add_local_iface(I_THIRD);
+
+    // test
+    CU_ASSERT(semanage_iface_list_local(sh, &records, &count) >= 0);
+
+    CU_ASSERT(count == 3);
+
+    for (unsigned int i = 0; i < count; i++) {
+        CU_ASSERT_PTR_NOT_NULL(records[i]);
+    }
+
+    // cleanup
+    for (unsigned int i = 0; i < count; i++) {
+        semanage_iface_free(records[i]);
+    }
+
+    delete_local_iface(I_FIRST);
+    delete_local_iface(I_SECOND);
+    delete_local_iface(I_THIRD);
+
+    cleanup_handle(SH_TRANS);
+}

diff --git a/libsemanage/sanity-tests/tests/test_iface.h b/libsemanage/sanity-tests/tests/test_iface.h
new file mode 100644
index 0000000..f03da4f
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_iface.h
@@ -0,0 +1,39 @@
+#ifndef __TEST_IFACE_H__
+#define __TEST_IFACE_H__
+
+#include <CUnit/Basic.h>
+
+int iface_test_init(void);
+int iface_test_cleanup(void);
+int iface_add_tests(CU_pSuite suite);
+
+// iface_record.h
+
+void test_iface_compare(void);
+void test_iface_compare2(void);
+void test_iface_key_create(void);
+void test_iface_key_extract(void);
+void test_iface_get_set_name(void);
+void test_iface_get_set_ifcon(void);
+void test_iface_get_set_msgcon(void);
+void test_iface_create(void);
+void test_iface_clone(void);
+
+// iterfaces_policy.h
+
+void test_iface_query(void);
+void test_iface_exists(void);
+void test_iface_count(void);
+void test_iface_iterate(void);
+void test_iface_list(void);
+
+// interfaces_local.h
+
+void test_iface_modify_del_query_local(void);
+void test_iface_exists_local(void);
+void test_iface_count_local(void);
+void test_iface_iterate_local(void);
+void test_iface_list_local(void);
+
+#endif
+

diff --git a/libsemanage/sanity-tests/tests/test_module.c b/libsemanage/sanity-tests/tests/test_module.c
new file mode 100644
index 0000000..8a5aca9
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_module.c
@@ -0,0 +1,1347 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <semanage/semanage.h>
+#include <semanage/handle.h>
+#include <selinux/selinux.h>
+#include <CUnit/Basic.h>
+
+#include "test_module.h"
+#include "functions.h"
+
+extern semanage_handle_t *sh;
+
+#define CIL_NAME "my_cil_module"
+#define CIL_LANG_EXT "cil"
+#define CIL_FILE CIL_NAME "." CIL_LANG_EXT
+#define CIL_TEXT "(boolean " CIL_NAME " true)"
+
+#define BZIP_NAME "my_bzip_module"
+#define BZIP_LANG_EXT "cil"
+#define BZIP_FILE BZIP_NAME "." BZIP_LANG_EXT
+#define BZIP_TEXT_UNCOMPRESSED "(boolean my_bzip_module true)"
+const char BZIP_TEXT[] = {
+    0x42, 0x5a, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26, 0x53, 0x59, 0x43, 0x62,
+    0x86, 0x35, 0x00, 0x00, 0x01, 0x13, 0x80, 0x40, 0x60, 0x00, 0x00, 0xb6,
+    0x27, 0xd6, 0x30, 0x20, 0x00, 0x31, 0x4c, 0x98, 0x99, 0x06, 0x46, 0x14,
+    0xd1, 0xa6, 0x43, 0x46, 0x99, 0xa8, 0xd9, 0x32, 0x97, 0xb2, 0x2b, 0xf6,
+    0x48, 0x5a, 0xe6, 0xdc, 0x83, 0x78, 0x08, 0x02, 0xa7, 0xc5, 0xdc, 0x91,
+    0x4e, 0x14, 0x24, 0x10, 0xd8, 0xa1, 0x8d, 0x40 };
+
+#define BZIP_INVALID_FILE "my_invalid_bzip_module"
+#define BZIP_INVALID_TEXT BZIP_TEXT
+
+#define HLL_NAME "my_hll_module"
+#define HLL_LANG_EXT "pp"
+#define HLL_FILE HLL_NAME "." HLL_LANG_EXT
+#define HLL_TEXT "module " HLL_NAME " 1.0;\nrequire {\nrole system_r;\n" \
+                 "}\nbool " HLL_NAME " true;\n"
+char *HLL_DATA = NULL;
+size_t HLL_DATA_LEN = 0;
+
+#define INVALID_NAME "my_invalid_module"
+#define INVALID_FILE INVALID_NAME
+#define INVALID_TEXT "(boolean " INVALID_NAME " true)"
+
+#define PRIORITY_NAME "my_cil_module"
+#define PRIORITY_FILE "priority/" PRIORITY_NAME ".cil"
+#define PRIORITY_BOOL "my_priority_module"
+#define PRIORITY_TEXT "(boolean " PRIORITY_BOOL " true)"
+
+int module_test_init(void) {
+    // CIL module
+    FILE *cil_file = fopen(CIL_FILE, "w");
+
+    if (cil_file == NULL)
+        return -1;
+
+    if (fprintf(cil_file, CIL_TEXT) != strlen(CIL_TEXT))
+        return -1;
+
+    fclose(cil_file);
+
+    // bzipped cil module
+    FILE *bzip_file = fopen(BZIP_FILE, "w");
+
+    if (bzip_file == NULL)
+        return -1;
+
+    if (fwrite(&BZIP_TEXT, sizeof(char), sizeof(BZIP_TEXT), bzip_file)
+            != sizeof(BZIP_TEXT))
+        return -1;
+
+    fclose(bzip_file);
+
+    // bzipped cil module with invalid file extension
+    FILE *bzip_invalid_file = fopen(BZIP_INVALID_FILE, "w");
+
+    if (bzip_invalid_file == NULL)
+        return -1;
+
+    if (fwrite(&BZIP_INVALID_TEXT, sizeof(char), sizeof(BZIP_INVALID_TEXT),
+               bzip_invalid_file) != sizeof(BZIP_INVALID_TEXT))
+        return -1;
+
+    fclose(bzip_invalid_file);
+
+    // hll module
+    FILE *te_file = fopen(HLL_NAME ".te", "w");
+
+    if (te_file == NULL)
+        return -1;
+
+    if (fprintf(te_file, HLL_TEXT) != strlen(HLL_TEXT))
+        return -1;
+
+    fclose(te_file);
+
+    if (system("checkmodule -M -m -o " HLL_NAME ".mod " HLL_NAME ".te") != 0)
+        return -1;
+
+    if (system("semodule_package -m " HLL_NAME ".mod -o " HLL_FILE) != 0)
+        return -1;
+
+    FILE *pp_file = fopen(HLL_FILE, "r");
+    
+    if (pp_file == NULL)
+        return -1;
+
+    fseek(pp_file, 0, SEEK_END);
+    HLL_DATA_LEN = ftell(pp_file);
+    rewind(pp_file);
+
+    HLL_DATA = malloc(HLL_DATA_LEN);
+
+    if (HLL_DATA == NULL)
+        return -1;
+
+    if (fread(HLL_DATA, 1, HLL_DATA_LEN, pp_file) != HLL_DATA_LEN)
+        return -1;
+
+    fclose(pp_file);
+
+    // CIL module with invalid lang ext
+    FILE *invalid_lang_ext_file = fopen(INVALID_FILE, "w");
+
+    if (invalid_lang_ext_file == NULL)
+        return -1;
+
+    if (fprintf(invalid_lang_ext_file, INVALID_TEXT) != strlen(INVALID_TEXT))
+        return -1;
+
+    fclose(invalid_lang_ext_file);
+
+    // CIL module with same name as existing module
+    if (mkdir("priority", 0700) != 0)
+        return -1;
+
+    FILE *priority_file = fopen(PRIORITY_FILE, "w");
+
+    if (priority_file == NULL)
+        return -1;
+
+    if (fprintf(priority_file, PRIORITY_TEXT) != strlen(PRIORITY_TEXT))
+        return -1;
+
+    fclose(priority_file);
+
+	return 0;
+}
+
+int module_test_cleanup(void) {
+    int status = 0;
+
+    if (unlink(CIL_FILE) < 0)
+        status = -1;
+
+    if (unlink(BZIP_FILE) < 0)
+        status = -1;
+
+    if (unlink(BZIP_INVALID_FILE) < 0)
+        status = -1;
+
+    if (unlink(HLL_FILE) < 0)
+        status = -1;
+
+    if (unlink(HLL_NAME ".mod") < 0)
+        status = -1;
+
+    if (unlink(HLL_NAME ".te") < 0)
+        status = -1;
+
+    if (unlink(INVALID_FILE) < 0)
+        status = -1;
+
+    if (unlink(PRIORITY_FILE) < 0)
+        status = -1;
+
+    if (rmdir("priority") != 0)
+        status = -1;
+
+    return status;
+}
+
+int module_add_tests(CU_pSuite suite) {
+#if VERS_CHECK(2, 5)
+    CU_add_test(suite, "module_install", test_module_install);
+    CU_add_test(suite, "module_install_file", test_module_install_file);
+    CU_add_test(suite, "module_install_info", test_module_install_info);
+    CU_add_test(suite, "module_remove", test_module_remove);
+    CU_add_test(suite, "module_remove_key", test_module_remove_key);
+
+    CU_add_test(suite, "module_extract", test_module_extract);
+    CU_add_test(suite, "module_list_all", test_module_list_all);
+#endif
+
+    CU_add_test(suite, "module_list", test_module_list);
+
+#if VERS_CHECK(2, 5)
+    CU_add_test(suite, "module_get_name", test_module_get_name);
+    CU_add_test(suite, "module_get_module_info",
+                test_module_get_module_info);
+
+    CU_add_test(suite, "module_info_create", test_module_info_create);
+    CU_add_test(suite, "module_info_get_set_priority",
+                test_module_info_get_set_priority);
+    CU_add_test(suite, "module_info_get_set_name",
+                test_module_info_get_set_name);
+    CU_add_test(suite, "module_info_get_set_lang_ext",
+                test_module_info_get_set_lang_ext);
+    CU_add_test(suite, "module_info_get_set_enabled",
+                test_module_info_get_set_enabled);
+
+    CU_add_test(suite, "module_key_create", test_module_key_create);
+    CU_add_test(suite, "module_key_get_set_name", test_module_key_get_set_name);
+    CU_add_test(suite, "module_key_get_set_priority",
+                test_module_key_get_set_priority);
+
+    CU_add_test(suite, "module_get_set_enabled", test_module_get_set_enabled);
+#endif
+
+	return 0;
+}
+
+#if VERS_CHECK(2, 5)
+
+// Function semanage_module_install
+
+void helper_module_install_invalid(void) {
+    // disconnected
+    setup_handle(SH_CONNECT);
+    helper_disconnect();
+
+    CU_ASSERT(semanage_module_install(sh, CIL_TEXT, strlen(CIL_TEXT),
+                                      CIL_NAME, CIL_LANG_EXT) < 0);
+
+    cleanup_handle(SH_HANDLE);
+
+    // not in transaction
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_module_install(sh, CIL_TEXT, strlen(CIL_TEXT),
+                                      CIL_NAME, CIL_LANG_EXT) >= 0);
+    CU_ASSERT(semanage_module_remove(sh, CIL_NAME) >= 0);
+
+    cleanup_handle(SH_TRANS);
+
+    // invalid name
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_module_install(sh, CIL_TEXT, strlen(CIL_TEXT),
+                                      "#invalid", CIL_LANG_EXT) < 0);
+
+    // invalid lang ext
+    CU_ASSERT(semanage_module_install(sh, CIL_TEXT, strlen(CIL_TEXT),
+                                      CIL_NAME, "#invalid") < 0);
+
+    cleanup_handle(SH_TRANS);
+}
+
+void helper_module_install_cil(void) {
+    // setup
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_module_install(sh, CIL_TEXT, strlen(CIL_TEXT),
+                                      CIL_NAME, CIL_LANG_EXT) >= 0);
+
+    helper_commit();
+    
+    // test
+    CU_ASSERT(module_exists(CIL_NAME));
+
+    // cleanup
+    helper_begin_transaction();
+
+    CU_ASSERT(semanage_module_remove(sh, CIL_NAME) >= 0);
+
+    cleanup_handle(SH_TRANS);
+}
+
+void helper_module_install_hll(void) {
+    // setup
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_module_install(sh, HLL_DATA, HLL_DATA_LEN, HLL_NAME,
+                                      HLL_LANG_EXT) >= 0);
+
+    helper_commit();
+    
+    // test
+    CU_ASSERT(module_exists(HLL_NAME));
+
+    // cleanup
+    helper_begin_transaction();
+
+    CU_ASSERT(semanage_module_remove(sh, HLL_NAME) >= 0);
+
+    cleanup_handle(SH_TRANS);
+}
+
+void test_module_install(void) {
+    helper_module_install_invalid();
+    helper_module_install_cil();
+    helper_module_install_hll();
+}
+
+// Function semanage_module_install_file
+
+void helper_module_install_file_invalid(void) {
+    // disconnected
+    setup_handle(SH_CONNECT);
+    helper_disconnect();
+
+    CU_ASSERT(semanage_module_install_file(sh, CIL_FILE) < 0);
+
+    cleanup_handle(SH_HANDLE);
+
+    // not in transaction
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_module_install_file(sh, CIL_FILE) >= 0);
+    CU_ASSERT(semanage_module_remove(sh, CIL_NAME) >= 0);
+
+    // nonexisting module
+    CU_ASSERT(semanage_module_install_file(sh, "nonexisting") < 0);
+
+    // module with invalid lang ext
+    CU_ASSERT(semanage_module_install_file(sh, INVALID_FILE) < 0);
+
+    // compressed module with invalid lang ext
+    CU_ASSERT(semanage_module_install_file(sh, BZIP_INVALID_FILE) < 0);
+
+    cleanup_handle(SH_TRANS);
+}
+
+void helper_module_install_file_cil(void) {
+    // setup
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_module_install_file(sh, CIL_FILE) >= 0);
+
+    helper_commit();
+    
+    // test
+    CU_ASSERT(module_exists(CIL_NAME));
+
+    // cleanup
+    helper_begin_transaction();
+
+    CU_ASSERT(semanage_module_remove(sh, CIL_NAME) >= 0);
+
+    cleanup_handle(SH_TRANS);
+}
+
+void helper_module_install_file_bzip(void) {
+    // setup
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_module_install_file(sh, BZIP_FILE) >= 0);
+
+    helper_commit();
+    
+    // test
+    CU_ASSERT(module_exists(BZIP_NAME));
+
+    // cleanup
+    helper_begin_transaction();
+
+    CU_ASSERT(semanage_module_remove(sh, BZIP_NAME) >= 0);
+
+    cleanup_handle(SH_TRANS);
+}
+
+void helper_module_install_file_hll(void) {
+    // setup
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_module_install_file(sh, HLL_FILE) >= 0);
+
+    helper_commit();
+    
+    // test
+    CU_ASSERT(module_exists(HLL_NAME));
+
+    // cleanup
+    helper_begin_transaction();
+
+    CU_ASSERT(semanage_module_remove(sh, HLL_NAME) >= 0);
+
+    cleanup_handle(SH_TRANS);
+}
+
+void helper_module_install_file_overridden(void) {
+    // setup
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_set_default_priority(sh, 400) >= 0);
+    CU_ASSERT(semanage_module_install_file(sh, CIL_FILE) >= 0);
+
+    CU_ASSERT(semanage_set_default_priority(sh, 1) >= 0);
+    CU_ASSERT(semanage_module_install_file(sh, PRIORITY_FILE) >= 0);
+
+    helper_commit();
+    
+    // test
+    CU_ASSERT(!module_exists(PRIORITY_BOOL));
+
+    // cleanup
+    helper_begin_transaction();
+
+    CU_ASSERT(semanage_set_default_priority(sh, 1) >= 0);
+    CU_ASSERT(semanage_module_remove(sh, PRIORITY_NAME) >= 0);
+
+    CU_ASSERT(semanage_set_default_priority(sh, 400) >= 0);
+    CU_ASSERT(semanage_module_remove(sh, CIL_NAME) >= 0);
+
+    cleanup_handle(SH_TRANS);
+}
+
+void helper_module_install_file_override(void) {
+    // setup
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_set_default_priority(sh, 400) >= 0);
+    CU_ASSERT(semanage_module_install_file(sh, CIL_FILE) >= 0);
+
+    CU_ASSERT(semanage_set_default_priority(sh, 999) >= 0);
+    CU_ASSERT(semanage_module_install_file(sh, PRIORITY_FILE) >= 0);
+
+    helper_commit();
+    
+    // test
+    CU_ASSERT(module_exists(PRIORITY_BOOL));
+
+    // cleanup
+    helper_begin_transaction();
+
+    CU_ASSERT(semanage_set_default_priority(sh, 999) >= 0);
+    CU_ASSERT(semanage_module_remove(sh, PRIORITY_NAME) >= 0);
+
+    CU_ASSERT(semanage_set_default_priority(sh, 400) >= 0);
+    CU_ASSERT(semanage_module_remove(sh, CIL_NAME) >= 0);
+
+    cleanup_handle(SH_TRANS);
+}
+
+void helper_module_install_file_conflict(void) {
+    // setup
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_module_install_file(sh, CIL_FILE) >= 0);
+
+    CU_ASSERT(semanage_module_install_file(sh, PRIORITY_FILE) >= 0);
+
+    helper_commit();
+    
+    // test
+    CU_ASSERT(module_exists(PRIORITY_BOOL));
+
+    // cleanup
+    helper_begin_transaction();
+    
+    CU_ASSERT(semanage_module_remove(sh, PRIORITY_NAME) >= 0);
+
+    cleanup_handle(SH_TRANS);
+}
+
+void test_module_install_file(void) {
+    helper_module_install_file_invalid();
+    helper_module_install_file_cil();
+    helper_module_install_file_bzip();
+    helper_module_install_file_hll();
+    helper_module_install_file_overridden();
+    helper_module_install_file_override();
+    helper_module_install_file_conflict();
+}
+
+// Function semanage_module_install_info
+
+void test_module_install_info(void) {
+    semanage_module_info_t *modinfo = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_module_info_create(sh, &modinfo) >= 0);
+    CU_ASSERT(semanage_module_info_set_priority(sh, modinfo, 400) >= 0);
+    CU_ASSERT(semanage_module_info_set_name(sh, modinfo, CIL_NAME) >= 0);
+    CU_ASSERT(semanage_module_info_set_lang_ext(sh, modinfo,
+                                                CIL_LANG_EXT) >= 0);
+    CU_ASSERT(semanage_module_info_set_enabled(sh, modinfo, 1) >= 0);
+
+    // test disconnected
+    helper_disconnect();
+
+    CU_ASSERT(semanage_module_install_info(sh, modinfo, CIL_TEXT,
+                                           strlen(CIL_TEXT)) < 0);
+
+    // test not in transaction
+    helper_connect();
+
+    CU_ASSERT(semanage_module_install_info(sh, modinfo, CIL_TEXT,
+                                           strlen(CIL_TEXT)) >= 0);
+
+    helper_commit();
+
+    CU_ASSERT(module_exists(CIL_NAME));
+
+    // cleanup
+    helper_begin_transaction();
+    CU_ASSERT(semanage_module_remove(sh, CIL_NAME) >= 0);
+    helper_commit();
+
+    semanage_module_info_destroy(sh, modinfo);
+    free(modinfo);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_module_remove
+// TODO: fix memory leak in semanage_direct_remove (missing
+// semanage_module_key_free)
+
+void test_module_remove(void) {
+    // setup
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_module_install_file(sh, CIL_FILE) >= 0);
+
+    helper_commit();
+
+    // test disconnected
+    helper_disconnect();
+
+    CU_ASSERT(semanage_module_remove(sh, CIL_NAME) < 0);
+
+    // test not in transaction
+    helper_connect();
+
+    CU_ASSERT(semanage_module_remove(sh, CIL_NAME) >= 0);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_module_remove_key
+
+void test_module_remove_key(void) {
+    semanage_module_key_t *modkey = NULL;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_set_default_priority(sh, 400) >= 0);
+    CU_ASSERT(semanage_module_install_file(sh, CIL_FILE) >= 0);
+
+    CU_ASSERT(semanage_module_key_create(sh, &modkey) >= 0);
+    CU_ASSERT(semanage_module_key_set_name(sh, modkey, CIL_NAME) >= 0);
+    CU_ASSERT(semanage_module_key_set_priority(sh, modkey, 400) >= 0);
+
+    helper_commit();
+
+    // test disconnected
+    helper_disconnect();
+
+    CU_ASSERT(semanage_module_remove_key(sh, modkey) < 0);
+
+    // test not in transaction
+    helper_connect();
+
+    CU_ASSERT(semanage_module_remove_key(sh, modkey) >= 0);
+
+    helper_commit();
+
+    semanage_module_key_destroy(sh, modkey);
+    free(modkey);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_module_extract
+
+void helper_module_extract_invalid() {
+    semanage_module_key_t *modkey = NULL;
+    semanage_module_info_t *modinfo = NULL;
+    void *mapped_data = NULL;
+    size_t data_len = 0;
+
+    setup_handle(SH_CONNECT);
+
+    modkey = get_module_key_nth(I_FIRST);
+
+    CU_ASSERT_SIGNAL(semanage_module_extract(NULL, modkey, 0, &mapped_data,
+                                             &data_len, &modinfo), SIGSEGV);
+    CU_ASSERT_SIGNAL(semanage_module_extract(sh, NULL, 0, &mapped_data,
+                                             &data_len, &modinfo), SIGABRT);
+    CU_ASSERT_SIGNAL(semanage_module_extract(sh, modkey, 0, &mapped_data,
+                                             &data_len, NULL), SIGSEGV);
+    CU_ASSERT_SIGNAL(semanage_module_extract(sh, modkey, 0, &mapped_data, NULL,
+                                             &modinfo), SIGSEGV);
+    CU_ASSERT_SIGNAL(semanage_module_extract(sh, modkey, 0, NULL, &data_len,
+                                             &modinfo), SIGSEGV);
+
+    helper_disconnect();
+
+    CU_ASSERT(semanage_module_extract(sh, modkey, 0, &mapped_data, &data_len,
+                                      &modinfo) < 0);
+
+    helper_connect();
+    helper_begin_transaction();
+
+    CU_ASSERT(semanage_module_key_set_name(sh, modkey,
+                                           "my_nonexisting_module") >= 0);
+    CU_ASSERT(semanage_module_key_set_priority(sh, modkey, 400) >= 0);
+
+    CU_ASSERT(semanage_module_extract(sh, modkey, 0, &mapped_data, &data_len,
+                                      &modinfo) < 0);
+
+    cleanup_handle(SH_TRANS);
+}
+
+void helper_module_extract() {
+    semanage_module_key_t *modkey1 = NULL;
+    semanage_module_key_t *modkey2 = NULL;
+    semanage_module_info_t *modinfo = NULL;
+    void *mapped_data = NULL;
+    size_t data_len = 0;
+    const char *name = NULL;
+    uint16_t priority = 42;
+    const char *lang_ext = NULL;
+    int enabled = 42;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_set_default_priority(sh, 400) >= 0);
+    CU_ASSERT(semanage_module_install_file(sh, CIL_FILE) >= 0);
+    CU_ASSERT(semanage_module_install_file(sh, BZIP_FILE) >= 0);
+
+    helper_commit();
+
+    CU_ASSERT(semanage_module_key_create(sh, &modkey1) >= 0);
+    CU_ASSERT(semanage_module_key_set_name(sh, modkey1, CIL_NAME) >= 0);
+    CU_ASSERT(semanage_module_key_set_priority(sh, modkey1, 400) >= 0);
+
+    CU_ASSERT(semanage_module_key_create(sh, &modkey2) >= 0);
+    CU_ASSERT(semanage_module_key_set_name(sh, modkey2, BZIP_NAME) >= 0);
+    CU_ASSERT(semanage_module_key_set_priority(sh, modkey2, 400) >= 0);
+
+    // test CIL module
+    CU_ASSERT(semanage_module_extract(sh, modkey1, 0, &mapped_data, &data_len,
+                                      &modinfo) >= 0);
+
+    CU_ASSERT(mapped_data != NULL);
+    CU_ASSERT(data_len == strlen(CIL_TEXT));
+    CU_ASSERT(memcmp(mapped_data, CIL_TEXT, data_len) == 0);
+
+    CU_ASSERT(modinfo != NULL);
+
+    CU_ASSERT(semanage_module_info_get_priority(sh, modinfo, &priority) >= 0);
+    CU_ASSERT(priority == 400);
+    
+    CU_ASSERT(semanage_module_info_get_name(sh, modinfo, &name) >= 0);
+    CU_ASSERT_STRING_EQUAL(name, CIL_NAME);
+    
+    CU_ASSERT(semanage_module_info_get_lang_ext(sh, modinfo, &lang_ext) >= 0);
+    CU_ASSERT_STRING_EQUAL(lang_ext, CIL_LANG_EXT);
+
+    CU_ASSERT(semanage_module_info_get_enabled(sh, modinfo, &enabled) >= 0);
+    CU_ASSERT(enabled == 1);
+
+    CU_ASSERT(semanage_module_info_destroy(sh, modinfo) >= 0);
+    free(modinfo);
+
+    // test compressed module
+    CU_ASSERT(semanage_module_extract(sh, modkey2, 1, &mapped_data, &data_len,
+                                      &modinfo) >= 0);
+
+    CU_ASSERT(mapped_data != NULL);
+    CU_ASSERT(data_len == strlen(BZIP_TEXT_UNCOMPRESSED));
+    CU_ASSERT(memcmp(mapped_data, BZIP_TEXT_UNCOMPRESSED, data_len) == 0);
+
+    CU_ASSERT(modinfo != NULL);
+
+    CU_ASSERT(semanage_module_info_get_priority(sh, modinfo, &priority) >= 0);
+    CU_ASSERT(priority == 400);
+    
+    CU_ASSERT(semanage_module_info_get_name(sh, modinfo, &name) >= 0);
+    CU_ASSERT_STRING_EQUAL(name, BZIP_NAME);
+    
+    CU_ASSERT(semanage_module_info_get_lang_ext(sh, modinfo, &lang_ext) >= 0);
+    CU_ASSERT_STRING_EQUAL(lang_ext, BZIP_LANG_EXT);
+
+    CU_ASSERT(semanage_module_info_get_enabled(sh, modinfo, &enabled) >= 0);
+    CU_ASSERT(enabled == 1);
+
+    // cleanup
+    CU_ASSERT(semanage_module_info_destroy(sh, modinfo) >= 0);
+    free(modinfo);
+    cleanup_handle(SH_CONNECT);
+}
+
+void test_module_extract(void) {
+    helper_module_extract_invalid();
+    helper_module_extract();
+}
+
+// Function semanage_module_list_all, semanage_module_list_nth,
+// semanage_info_destroy
+
+void helper_module_list_all_invalid() {
+    semanage_module_info_t *records;
+    int count = -1;
+
+    setup_handle(SH_CONNECT);
+    helper_disconnect();
+
+    CU_ASSERT(semanage_module_list_all(sh, &records, &count) < 0);
+
+    cleanup_handle(SH_HANDLE);
+}
+
+void helper_module_list_all(level_t level) {
+    semanage_module_info_t *records;
+    int count = -1;
+
+    setup_handle(level);
+    
+    CU_ASSERT(semanage_module_list_all(sh, &records, &count) >= 0);
+
+    // TODO: check real count
+    CU_ASSERT(count > 0);
+
+    for (int i = 0; i < count; i++) {
+        semanage_module_info_t *info = semanage_module_list_nth(records, i);
+
+        // TODO: check real names
+        CU_ASSERT_STRING_NOT_EQUAL(semanage_module_get_name(info), "");
+        
+        semanage_module_info_destroy(sh, info);
+    }
+
+    free(records);
+
+    cleanup_handle(level);
+}
+
+void test_module_list_all(void) {
+    helper_module_list_all_invalid();
+    helper_module_list_all(SH_CONNECT);
+    helper_module_list_all(SH_TRANS);
+}
+#endif
+
+// Function semanage_module_list, semanage_module_list_nth,
+// semanage_info_datum_destroy, semanage_info_destroy
+
+void helper_module_list_invalid() {
+    semanage_module_info_t *records;
+    int count = -1;
+
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_disconnect(sh) >= 0);
+
+    CU_ASSERT(semanage_module_list(sh, &records, &count) < 0);
+
+    cleanup_handle(SH_HANDLE);
+}
+
+void helper_module_list(level_t level) {
+    semanage_module_info_t *records;
+    int count = -1;
+
+    setup_handle(level);
+    
+    CU_ASSERT(semanage_module_list(sh, &records, &count) >= 0);
+
+    // TODO: check real count
+    CU_ASSERT(count > 0);
+
+    for (int i = 0; i < count; i++) {
+        semanage_module_info_t *info = semanage_module_list_nth(records, i);
+
+        // TODO: check real names
+        CU_ASSERT_STRING_NOT_EQUAL(semanage_module_get_name(info), "");
+        
+#if VERS_CHECK(2, 5)
+        semanage_module_info_destroy(sh, info);
+#else
+        semanage_module_info_datum_destroy(info);
+#endif
+    }
+
+    free(records);
+
+    cleanup_handle(level);
+}
+
+void test_module_list(void) {
+    helper_module_list_invalid();
+    
+    helper_module_list(SH_CONNECT);
+    helper_module_list(SH_TRANS);
+}
+
+#if VERS_CHECK(2, 5)
+
+// Function semanage_module_get_name
+
+void test_module_get_name(void) {
+    const char *name = NULL;
+    semanage_module_info_t *modinfo = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_module_info_create(sh, &modinfo) >= 0);
+    CU_ASSERT(semanage_module_info_set_name(sh, modinfo, "module_name") >= 0);
+
+    // test
+    name = semanage_module_get_name(modinfo);
+
+    CU_ASSERT_STRING_EQUAL(name, "module_name");
+
+    // test modinfo == NULL
+    CU_ASSERT_SIGNAL(semanage_module_get_name(NULL), SIGSEGV);
+
+    // cleanup
+    CU_ASSERT(semanage_module_info_destroy(sh, modinfo) >= 0);
+    free(modinfo);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_get_module_info
+
+void test_module_get_module_info(void) {
+    semanage_module_key_t *modkey = NULL;
+    semanage_module_info_t *modinfo = NULL;
+    const char *name = NULL;
+    uint16_t priority = 42;
+
+    // test invalid parameters
+    CU_ASSERT_SIGNAL(semanage_module_get_module_info(NULL, NULL, NULL),
+                     SIGABRT);
+
+    setup_handle(SH_HANDLE);
+
+    CU_ASSERT_SIGNAL(semanage_module_get_module_info(sh, NULL, NULL),
+                     SIGABRT);
+
+    CU_ASSERT(semanage_module_key_create(sh, &modkey) >= 0);
+
+    CU_ASSERT_SIGNAL(semanage_module_get_module_info(sh, modkey, NULL),
+                     SIGABRT);
+
+    // test disconnected
+    helper_connect();
+    helper_disconnect();
+
+    CU_ASSERT(semanage_module_get_module_info(sh, modkey, &modinfo) < 0);
+
+    // test nonexisting module
+
+    helper_connect();
+
+    CU_ASSERT(semanage_module_key_set_name(sh, modkey,
+                                           "my_nonexisting_module") >= 0);
+
+    CU_ASSERT(semanage_module_get_module_info(sh, modkey, &modinfo) < 0);
+
+    // test existing module
+
+    helper_connect();
+    helper_begin_transaction();
+    
+    CU_ASSERT(semanage_module_install_file(sh, CIL_FILE) >= 0);
+
+    helper_commit();
+
+    CU_ASSERT(semanage_module_key_set_name(sh, modkey, CIL_NAME) >= 0);
+    CU_ASSERT(semanage_module_key_set_priority(sh, modkey, 400) >= 0);
+
+    CU_ASSERT(semanage_module_get_module_info(sh, modkey, &modinfo) >= 0);
+
+    CU_ASSERT(semanage_module_info_get_name(sh, modinfo, &name) >= 0);
+    CU_ASSERT_STRING_EQUAL(name, CIL_NAME);
+
+    CU_ASSERT(semanage_module_info_get_priority(sh, modinfo, &priority) >= 0);
+    CU_ASSERT(priority == 400);
+
+    helper_begin_transaction();
+
+    CU_ASSERT(semanage_module_remove(sh, CIL_NAME) >= 0);
+
+    // cleanup
+    semanage_module_key_destroy(sh, modkey);
+    free(modkey);
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_module_get_name, semanage_module_info_destroy
+
+void helper_module_info_create(level_t level) {
+    semanage_module_info_t *modinfo;
+    uint16_t priority = 42;
+    const char *name = "asdf";
+    const char *lang_ext = "asdf";
+    int enabled = 42;
+
+    setup_handle(level);
+
+    CU_ASSERT(semanage_module_info_create(sh, &modinfo) >= 0);
+
+    CU_ASSERT(semanage_module_info_get_priority(sh, modinfo, &priority) >= 0);
+    CU_ASSERT(priority == 0);
+    
+    CU_ASSERT(semanage_module_info_get_name(sh, modinfo, &name) >= 0);
+    CU_ASSERT(name == NULL);
+    
+    CU_ASSERT(semanage_module_info_get_lang_ext(sh, modinfo, &lang_ext) >= 0);
+    CU_ASSERT(lang_ext == NULL);
+
+    CU_ASSERT(semanage_module_info_get_enabled(sh, modinfo, &enabled) >= 0);
+    CU_ASSERT(enabled == -1);
+
+    CU_ASSERT(semanage_module_info_destroy(sh, modinfo) >= 0);
+    free(modinfo);
+
+    cleanup_handle(level);
+}
+
+void test_module_info_create(void) {
+    helper_module_info_create(SH_CONNECT);
+    helper_module_info_create(SH_TRANS);
+}
+
+// Function semanage_module_info_get_priority,
+// semanage_module_info_set_priority
+
+void helper_module_info_get_set_priority_invalid() {
+    semanage_module_info_t *modinfo = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_module_info_create(sh, &modinfo) >= 0);
+
+    // test
+    CU_ASSERT(semanage_module_info_set_priority(sh, modinfo, -42) < 0);
+    CU_ASSERT(semanage_module_info_set_priority(sh, modinfo, -1) < 0);
+    CU_ASSERT(semanage_module_info_set_priority(sh, modinfo, 0) < 0);
+
+    CU_ASSERT(semanage_module_info_set_priority(sh, modinfo, 1) >= 0);
+    CU_ASSERT(semanage_module_info_set_priority(sh, modinfo, 123) >= 0);
+    CU_ASSERT(semanage_module_info_set_priority(sh, modinfo, 999) >= 0);
+
+    CU_ASSERT(semanage_module_info_set_priority(sh, modinfo, 1000) < 0);
+    CU_ASSERT(semanage_module_info_set_priority(sh, modinfo, 1234) < 0);
+
+    // cleanup
+    CU_ASSERT(semanage_module_info_destroy(sh, modinfo) >= 0);
+    free(modinfo);
+    cleanup_handle(SH_CONNECT);
+}
+
+void helper_module_info_get_set_priority() {
+    uint16_t priority = 42;
+    semanage_module_info_t *modinfo = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_module_info_create(sh, &modinfo) >= 0);
+
+    // test
+    CU_ASSERT(semanage_module_info_set_priority(sh, modinfo, 123) >= 0);
+
+    CU_ASSERT(semanage_module_info_get_priority(sh, modinfo, &priority) >= 0);
+    CU_ASSERT(priority == 123);
+
+    // cleanup
+    CU_ASSERT(semanage_module_info_destroy(sh, modinfo) >= 0);
+    free(modinfo);
+    cleanup_handle(SH_CONNECT);
+}
+
+void test_module_info_get_set_priority(void) {
+    helper_module_info_get_set_priority_invalid();
+    helper_module_info_get_set_priority();
+}
+
+// Function semanage_module_info_get_name, semanage_module_info_set_name
+
+void helper_module_info_get_set_name_invalid() {
+    semanage_module_info_t *modinfo = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_module_info_create(sh, &modinfo) >= 0);
+
+    // test
+    CU_ASSERT_SIGNAL(semanage_module_info_set_name(sh, modinfo, NULL), SIGABRT); 
+
+    CU_ASSERT(semanage_module_info_set_name(sh, modinfo, "") < 0); 
+    CU_ASSERT(semanage_module_info_set_name(sh, modinfo, "4asdf") < 0); 
+    CU_ASSERT(semanage_module_info_set_name(sh, modinfo, "asdf%") < 0); 
+    CU_ASSERT(semanage_module_info_set_name(sh, modinfo, "asdf.") < 0); 
+
+    CU_ASSERT(semanage_module_info_set_name(sh, modinfo, "a") >= 0); 
+    CU_ASSERT(semanage_module_info_set_name(sh, modinfo,
+                                            "asdf_asdf-1234.asdf.asdf") >= 0); 
+
+    // cleanup
+    CU_ASSERT(semanage_module_info_destroy(sh, modinfo) >= 0);
+    free(modinfo);
+    cleanup_handle(SH_CONNECT);
+}
+
+void helper_module_info_get_set_name() {
+    const char *name = NULL;
+    semanage_module_info_t *modinfo = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_module_info_create(sh, &modinfo) >= 0);
+
+    // test
+    CU_ASSERT(semanage_module_info_set_name(sh, modinfo, "asdf") >= 0);
+
+    CU_ASSERT(semanage_module_info_get_name(sh, modinfo, &name) >= 0); 
+    CU_ASSERT_STRING_EQUAL(name, "asdf");
+
+    // cleanup
+    CU_ASSERT(semanage_module_info_destroy(sh, modinfo) >= 0);
+    free(modinfo);
+    cleanup_handle(SH_CONNECT);
+}
+
+void test_module_info_get_set_name(void) {
+    helper_module_info_get_set_name_invalid();
+    helper_module_info_get_set_name();
+}
+
+// Function semanage_module_info_get_lang_ext,
+// semanage_module_info_set_lang_ext
+
+void helper_module_info_get_set_lang_ext_invalid() {
+    semanage_module_info_t *modinfo = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_module_info_create(sh, &modinfo) >= 0);
+
+    // test
+    CU_ASSERT_SIGNAL(semanage_module_info_set_lang_ext(sh, modinfo, NULL),
+                     SIGABRT); 
+    CU_ASSERT(semanage_module_info_set_lang_ext(sh, modinfo, "") < 0); 
+    CU_ASSERT(semanage_module_info_set_lang_ext(sh, modinfo, "_asdf") < 0); 
+    CU_ASSERT(semanage_module_info_set_lang_ext(sh, modinfo, "a#asdf") < 0); 
+    CU_ASSERT(semanage_module_info_set_lang_ext(sh, modinfo, "as#asdf") < 0); 
+    CU_ASSERT(semanage_module_info_set_lang_ext(sh, modinfo, "asdf#") < 0); 
+
+    CU_ASSERT(semanage_module_info_set_lang_ext(sh, modinfo, "a") >= 0); 
+    CU_ASSERT(semanage_module_info_set_lang_ext(sh, modinfo,
+                                                "asdf-1234_ASDF") >= 0); 
+    CU_ASSERT(semanage_module_info_set_lang_ext(sh, modinfo,
+                                                "1234_asdf-ASDF") >= 0); 
+    
+    // cleanup
+    CU_ASSERT(semanage_module_info_destroy(sh, modinfo) >= 0);
+    free(modinfo);
+    
+    cleanup_handle(SH_CONNECT);
+}
+
+void helper_module_info_get_set_lang_ext() {
+    const char *lang_ext = NULL;
+    semanage_module_info_t *modinfo = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_module_info_create(sh, &modinfo) >= 0);
+
+    // test
+    CU_ASSERT(semanage_module_info_set_lang_ext(sh, modinfo, "asdf") >= 0); 
+
+    CU_ASSERT(semanage_module_info_get_lang_ext(sh, modinfo, &lang_ext) >= 0); 
+
+    CU_ASSERT_STRING_EQUAL(lang_ext, "asdf");
+
+    // cleanup
+    CU_ASSERT(semanage_module_info_destroy(sh, modinfo) >= 0);
+    free(modinfo);
+    cleanup_handle(SH_CONNECT);
+}
+
+void test_module_info_get_set_lang_ext(void) {
+    helper_module_info_get_set_lang_ext_invalid();
+    helper_module_info_get_set_lang_ext();
+}
+
+// Function semanage_module_info_get_enabled, semanage_module_info_set_enabled
+
+void helper_module_info_get_set_enabled_invalid() {
+    semanage_module_info_t *modinfo = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_module_info_create(sh, &modinfo) >= 0);
+
+    // test
+    CU_ASSERT(semanage_module_info_set_enabled(sh, modinfo, -123) < 0); 
+    CU_ASSERT(semanage_module_info_set_enabled(sh, modinfo, -2) < 0); 
+    
+    CU_ASSERT(semanage_module_info_set_enabled(sh, modinfo, -1) >= 0); 
+    CU_ASSERT(semanage_module_info_set_enabled(sh, modinfo, 0) >= 0); 
+    CU_ASSERT(semanage_module_info_set_enabled(sh, modinfo, 1) >= 0); 
+
+    CU_ASSERT(semanage_module_info_set_enabled(sh, modinfo, 2) < 0); 
+    CU_ASSERT(semanage_module_info_set_enabled(sh, modinfo, 123) < 0); 
+
+    // cleanup
+    CU_ASSERT(semanage_module_info_destroy(sh, modinfo) >= 0);
+    free(modinfo);
+    cleanup_handle(SH_CONNECT);
+}
+
+void helper_module_info_get_set_enabled() {
+    int enabled;
+    semanage_module_info_t *modinfo = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_module_info_create(sh, &modinfo) >= 0);
+
+    // test enabled == 0
+    CU_ASSERT(semanage_module_info_set_enabled(sh, modinfo, 0) >= 0);
+
+    CU_ASSERT(semanage_module_info_get_enabled(sh, modinfo, &enabled) >= 0); 
+    CU_ASSERT(enabled == 0);
+
+    // test enabled == 1
+    CU_ASSERT(semanage_module_info_set_enabled(sh, modinfo, 1) >= 0);
+
+    CU_ASSERT(semanage_module_info_get_enabled(sh, modinfo, &enabled) >= 0); 
+    CU_ASSERT(enabled == 1);
+
+    // test enabled == -1
+    CU_ASSERT(semanage_module_info_set_enabled(sh, modinfo, -1) >= 0);
+
+    CU_ASSERT(semanage_module_info_get_enabled(sh, modinfo, &enabled) >= 0); 
+    CU_ASSERT(enabled == -1);
+
+    // cleanup
+    CU_ASSERT(semanage_module_info_destroy(sh, modinfo) >= 0);
+    free(modinfo);
+    cleanup_handle(SH_CONNECT);
+}
+
+void test_module_info_get_set_enabled(void) {
+    helper_module_info_get_set_enabled_invalid();
+    helper_module_info_get_set_enabled();
+}
+
+// Function semanage_module_key_create, semanage_module_key_destroy
+
+void helper_module_key_create(level_t level) {
+    semanage_module_key_t *modkey = NULL;
+    const char *name = NULL;
+    uint16_t priority = 42;
+
+    setup_handle(level);
+
+    CU_ASSERT(semanage_module_key_create(sh, &modkey) >= 0);
+
+    CU_ASSERT(semanage_module_key_get_name(sh, modkey, &name) >= 0);
+    CU_ASSERT(name == NULL);
+
+    CU_ASSERT(semanage_module_key_get_priority(sh, modkey, &priority) >= 0);
+    CU_ASSERT(priority == 0);
+
+    CU_ASSERT(semanage_module_key_destroy(sh, modkey) >= 0);
+    free(modkey);
+
+    CU_ASSERT(semanage_module_key_destroy(sh, NULL) >= 0);
+
+    cleanup_handle(level);
+}
+
+void test_module_key_create(void) {
+    helper_module_key_create(SH_CONNECT);
+    helper_module_key_create(SH_TRANS);
+}
+
+// Function semanage_module_key_get_name, semanage_module_key_set_name
+
+void helper_module_key_get_set_name_invalid(level_t level) {
+    semanage_module_key_t *modkey = NULL;
+
+    // setup
+    setup_handle(level);
+
+    CU_ASSERT(semanage_module_key_create(sh, &modkey) >= 0);
+
+    // test
+    CU_ASSERT_SIGNAL(semanage_module_key_set_name(sh, modkey, NULL), SIGABRT); 
+
+    CU_ASSERT(semanage_module_key_set_name(sh, modkey, "") < 0); 
+    CU_ASSERT(semanage_module_key_set_name(sh, modkey, "4asdf") < 0); 
+    CU_ASSERT(semanage_module_key_set_name(sh, modkey, "asdf%") < 0); 
+    CU_ASSERT(semanage_module_key_set_name(sh, modkey, "asdf.") < 0); 
+
+    CU_ASSERT(semanage_module_key_set_name(sh, modkey, "a") >= 0); 
+    CU_ASSERT(semanage_module_key_set_name(sh, modkey,
+                                           "asdf_asdf-1234.asdf.asdf") >= 0); 
+
+    // cleanup
+    CU_ASSERT(semanage_module_key_destroy(sh, modkey) >= 0);
+    free(modkey);
+
+    cleanup_handle(level);
+}
+
+void helper_module_key_get_set_name(level_t level) {
+    semanage_module_key_t *modkey;
+    const char *name = NULL;
+
+    setup_handle(level);
+
+    CU_ASSERT(semanage_module_key_create(sh, &modkey) >= 0);
+
+    CU_ASSERT(semanage_module_key_set_name(sh, modkey, "asdf") >= 0);
+
+    CU_ASSERT(semanage_module_key_get_name(sh, modkey, &name) >= 0);
+
+    CU_ASSERT(name != NULL);
+    CU_ASSERT_STRING_EQUAL(name, "asdf");
+    
+    CU_ASSERT(semanage_module_key_destroy(sh, modkey) >= 0);
+    free(modkey);
+
+    cleanup_handle(level);
+}
+
+void test_module_key_get_set_name(void) {
+    helper_module_key_get_set_name_invalid(SH_CONNECT);
+    helper_module_key_get_set_name(SH_CONNECT);
+    helper_module_key_get_set_name(SH_CONNECT);
+
+    helper_module_key_get_set_name_invalid(SH_TRANS);
+    helper_module_key_get_set_name(SH_TRANS);
+    helper_module_key_get_set_name(SH_TRANS);
+}
+
+// Function semanage_module_key_get_priority, semanage_module_key_set_priority
+
+void helper_module_key_get_set_priority_invalid(level_t level) {
+    semanage_module_key_t *modkey = NULL;
+
+    setup_handle(level);
+
+    CU_ASSERT(semanage_module_key_create(sh, &modkey) >= 0);
+
+    CU_ASSERT(semanage_module_key_set_priority(sh, modkey, -42) < 0);
+    CU_ASSERT(semanage_module_key_set_priority(sh, modkey, -1) < 0);
+    CU_ASSERT(semanage_module_key_set_priority(sh, modkey, 0) < 0);
+
+    CU_ASSERT(semanage_module_key_set_priority(sh, modkey, 1) >= 0);
+    CU_ASSERT(semanage_module_key_set_priority(sh, modkey, 123) >= 0);
+    CU_ASSERT(semanage_module_key_set_priority(sh, modkey, 999) >= 0);
+
+    CU_ASSERT(semanage_module_key_set_priority(sh, modkey, 1000) < 0);
+    CU_ASSERT(semanage_module_key_set_priority(sh, modkey, 1234) < 0);
+
+    CU_ASSERT(semanage_module_key_destroy(sh, modkey) >= 0);
+    free(modkey);
+    cleanup_handle(level);
+}
+
+void helper_module_key_get_set_priority(level_t level) {
+    semanage_module_key_t *modkey;
+    uint16_t priority = 42;
+
+    setup_handle(level);
+
+    CU_ASSERT(semanage_module_key_create(sh, &modkey) >= 0);
+
+    CU_ASSERT(semanage_module_key_set_priority(sh, modkey, 200) >= 0);
+
+    CU_ASSERT(semanage_module_key_get_priority(sh, modkey, &priority) >= 0);
+
+    CU_ASSERT(priority == 200);
+    
+    CU_ASSERT(semanage_module_key_destroy(sh, modkey) >= 0);
+    free(modkey);
+
+    cleanup_handle(level);
+}
+
+void test_module_key_get_set_priority(void) {
+    helper_module_key_get_set_priority_invalid(SH_CONNECT);
+    helper_module_key_get_set_priority(SH_CONNECT);
+    helper_module_key_get_set_priority(SH_CONNECT);
+
+    helper_module_key_get_set_priority_invalid(SH_TRANS);
+    helper_module_key_get_set_priority(SH_TRANS);
+    helper_module_key_get_set_priority(SH_TRANS);
+}
+
+// Function semanage_module_get_enabled, semanage_module_set_enabled
+
+void helper_module_get_set_enabled(level_t level, int index) {
+    semanage_module_key_t *modkey = NULL;
+    int enabled_old = 42;
+    int enabled_new = 42;
+    int enabled = 42;
+
+    setup_handle(level);
+
+    modkey = get_module_key_nth(index);
+
+    CU_ASSERT(semanage_module_get_enabled(sh, modkey, &enabled_old) >= 0);
+
+    CU_ASSERT(enabled_old == 0 || enabled_old == 1);
+
+    enabled_new = !enabled_old;
+
+    CU_ASSERT(semanage_module_set_enabled(sh, modkey, enabled_new) >= 0);
+
+    CU_ASSERT(semanage_module_get_enabled(sh, modkey, &enabled) >= 0);
+
+    CU_ASSERT(enabled == enabled_new);
+
+    cleanup_handle(level);
+}
+
+void test_module_get_set_enabled(void) {
+    helper_module_get_set_enabled(SH_CONNECT, I_FIRST);
+    helper_module_get_set_enabled(SH_TRANS, I_FIRST);
+}
+
+#endif

diff --git a/libsemanage/sanity-tests/tests/test_module.h b/libsemanage/sanity-tests/tests/test_module.h
new file mode 100644
index 0000000..7e7a8aa
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_module.h
@@ -0,0 +1,42 @@
+#ifndef __TEST_MODULE_H__
+#define __TEST_MODULE_H__
+
+#include <CUnit/Basic.h>
+
+#include "functions.h"
+
+int module_test_init(void);
+int module_test_cleanup(void);
+int module_add_tests(CU_pSuite suite);
+
+// modules.h
+
+void test_module_list(void);
+
+#if VERS_CHECK(2, 5)
+void test_module_install(void);
+void test_module_install_file(void);
+void test_module_install_info(void);
+void test_module_remove(void);
+void test_module_remove_key(void);
+
+void test_module_extract(void);
+void test_module_list_all(void);
+
+void test_module_get_name(void);
+void test_module_get_module_info(void);
+
+void test_module_info_create(void);
+void test_module_info_get_set_priority(void);
+void test_module_info_get_set_name(void);
+void test_module_info_get_set_lang_ext(void);
+void test_module_info_get_set_enabled(void);
+
+void test_module_key_create(void);
+void test_module_key_get_set_name(void);
+void test_module_key_get_set_priority(void);
+void test_module_get_set_enabled(void);
+#endif
+
+#endif
+

diff --git a/libsemanage/sanity-tests/tests/test_node.c b/libsemanage/sanity-tests/tests/test_node.c
new file mode 100644
index 0000000..c9c2ae2
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_node.c
@@ -0,0 +1,697 @@
+#include <stdio.h>
+#include <semanage/semanage.h>
+#include <semanage/handle.h>
+#include <CUnit/Basic.h>
+
+#include "test_node.h"
+#include "functions.h"
+
+extern semanage_handle_t *sh;
+
+// TODO: current policies does not have any nodecon rules
+#define NODE_COUNT 0
+
+int node_test_init(void) {
+    return 0;
+}
+
+int node_test_cleanup(void) {
+    return 0;
+}
+
+int node_add_tests(CU_pSuite suite) {
+    CU_add_test(suite, "node_compare", test_node_compare);
+    CU_add_test(suite, "node_compare2", test_node_compare2);
+    CU_add_test(suite, "node_key_create", test_node_key_create);
+    CU_add_test(suite, "node_key_extract", test_node_key_extract);
+    CU_add_test(suite, "node_get_set_addr", test_node_get_set_addr);
+    CU_add_test(suite, "node_get_set_addr_bytes", test_node_get_set_addr_bytes);
+    CU_add_test(suite, "node_get_set_mask", test_node_get_set_mask);
+    CU_add_test(suite, "node_get_set_mask_bytes", test_node_get_set_mask_bytes);
+    CU_add_test(suite, "node_get_set_proto", test_node_get_set_proto);
+    CU_add_test(suite, "node_get_proto_str", test_node_get_proto_str);
+    CU_add_test(suite, "node_get_set_con", test_node_get_set_con);
+    CU_add_test(suite, "node_create", test_node_create);
+    CU_add_test(suite, "node_clone", test_node_clone);
+
+    CU_add_test(suite, "node_query", test_node_query);
+    CU_add_test(suite, "node_exists", test_node_exists);
+    CU_add_test(suite, "node_count", test_node_count);
+    CU_add_test(suite, "node_iterate", test_node_iterate);
+    CU_add_test(suite, "node_list", test_node_list);
+
+    CU_add_test(suite, "node_modify_del_query_local",
+                test_node_modify_del_query_local);
+    CU_add_test(suite, "node_exists_local", test_node_exists_local);
+    CU_add_test(suite, "node_count_local", test_node_count_local);
+    CU_add_test(suite, "node_iterate_local", test_node_iterate_local);
+    CU_add_test(suite, "node_list_local", test_node_list_local);
+
+    return 0;
+}
+
+// Function semanage_node_compare
+
+void test_node_compare(void) {
+    semanage_node_t *node = NULL;
+    semanage_node_key_t *key1 = NULL;
+    semanage_node_key_t *key2 = NULL;
+    int result = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    node = get_node();
+
+    key1 = get_node_key();
+
+    CU_ASSERT(semanage_node_key_create(sh, "192.168.0.1", "255.255.0.0",
+                                       SEMANAGE_PROTO_IP4, &key2) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key2);
+
+    // test
+    result = semanage_node_compare(node, key1);
+
+    CU_ASSERT(result == 0);
+
+    result = semanage_node_compare(node, key2);
+
+    CU_ASSERT(result != 0);
+
+    // cleanup
+    semanage_node_free(node);
+    semanage_node_key_free(key1);
+    semanage_node_key_free(key2);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_node_compare2
+
+void test_node_compare2(void) {
+    semanage_node_t *node1 = NULL;
+    semanage_node_t *node2 = NULL;
+    semanage_node_t *node3 = NULL;
+    int result = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    node1 = get_node();
+    node2 = get_node();
+
+    node3 = get_node();
+    CU_ASSERT(semanage_node_set_addr(sh, node3, SEMANAGE_PROTO_IP4,
+                                     "192.168.0.1") >= 0);
+
+    // test
+    result = semanage_node_compare2(node1, node2);
+
+    CU_ASSERT(result == 0);
+
+    result = semanage_node_compare2(node1, node3);
+
+    CU_ASSERT(result != 0);
+
+    // cleanup
+    semanage_node_free(node1);
+    semanage_node_free(node2);
+    semanage_node_free(node3);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_node_key_create
+
+void test_node_key_create(void) {
+    semanage_node_key_t *key = NULL;
+
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_node_key_create(sh, "127.0.0.1", "255.255.255.255",
+                                       SEMANAGE_PROTO_IP4, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    semanage_node_key_free(key);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_node_key_extract
+
+void test_node_key_extract(void) {
+    semanage_node_t *node = NULL;
+    semanage_node_key_t *key = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    node = get_node();
+
+    // test
+    CU_ASSERT(semanage_node_key_extract(sh, node, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    // cleanup
+    semanage_node_free(node);
+    semanage_node_key_free(key);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_node_get_addr, semanage_node_set_addr
+
+void test_node_get_set_addr(void) {
+    semanage_node_t *node = NULL;
+    char *addr = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_node_create(sh, &node) >= 0);
+
+    // test
+    CU_ASSERT(semanage_node_set_addr(sh, node, SEMANAGE_PROTO_IP4,
+                                     "192.168.0.1") == 0);
+
+    CU_ASSERT(semanage_node_get_addr(sh, node, &addr) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(addr);
+    CU_ASSERT_STRING_EQUAL(addr, "192.168.0.1");
+
+    // cleanup
+    semanage_node_free(node);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_node_get_addr_bytes, semanage_node_set_addr_bytes
+
+void test_node_get_set_addr_bytes(void) {
+    semanage_node_t *node = NULL;
+    char addr1[] = { 192, 168, 0, 1 };
+    size_t addr1_size = sizeof(addr1);
+    char *addr2 = NULL;
+    size_t addr2_size = 0;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_node_create(sh, &node) >= 0);
+
+    // test
+    CU_ASSERT(semanage_node_set_addr_bytes(sh, node, addr1, addr1_size) == 0);
+
+    CU_ASSERT(semanage_node_get_addr_bytes(sh, node, &addr2, &addr2_size) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(addr2);
+
+    for (size_t i = 0; i < addr2_size; i++) {
+        CU_ASSERT(addr1[i] == addr2[i]);
+    }
+
+    // cleanup
+    semanage_node_free(node);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_node_get_mask, semanage_node_set_mask
+
+void test_node_get_set_mask(void) {
+    semanage_node_t *node = NULL;
+    char *mask = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_node_create(sh, &node) >= 0);
+
+    // test
+    CU_ASSERT(semanage_node_set_mask(sh, node, SEMANAGE_PROTO_IP4,
+                                     "255.255.255.0") == 0);
+
+    CU_ASSERT(semanage_node_get_mask(sh, node, &mask) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(mask);
+    CU_ASSERT_STRING_EQUAL(mask, "255.255.255.0");
+
+    // cleanup
+    semanage_node_free(node);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_node_get_mask_bytes, semanage_node_set_mask_bytes
+
+void test_node_get_set_mask_bytes(void) {
+    semanage_node_t *node = NULL;
+    char mask1[] = { 255, 255, 255, 0 };
+    size_t mask1_size = sizeof(mask1);
+    char *mask2 = NULL;
+    size_t mask2_size = 0;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_node_create(sh, &node) >= 0);
+
+    // test
+    CU_ASSERT(semanage_node_set_mask_bytes(sh, node, mask1, mask1_size) == 0);
+
+    CU_ASSERT(semanage_node_get_mask_bytes(sh, node, &mask2, &mask2_size) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(mask2);
+
+    for (size_t i = 0; i < mask2_size; i++) {
+        CU_ASSERT(mask1[i] == mask2[i]);
+    }
+
+    // cleanup
+    semanage_node_free(node);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_node_get_proto, semanage_node_set_proto
+
+void test_node_get_set_proto(void) {
+    semanage_node_t *node = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_node_create(sh, &node) >= 0);
+
+    // test
+    semanage_node_set_proto(node, SEMANAGE_PROTO_IP4);
+
+    CU_ASSERT(semanage_node_get_proto(node) == SEMANAGE_PROTO_IP4);
+
+    // cleanup
+    semanage_node_free(node);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_node_get_proto_str
+
+void test_node_get_proto_str(void) {
+    CU_ASSERT_STRING_EQUAL(semanage_node_get_proto_str(SEMANAGE_PROTO_IP4),
+                           "ipv4");
+    CU_ASSERT_STRING_EQUAL(semanage_node_get_proto_str(SEMANAGE_PROTO_IP6),
+                           "ipv6");
+}
+
+// Function semanage_node_get_con, semanage_node_set_con
+
+void test_node_get_set_con(void) {
+    semanage_node_t *node = NULL;
+    semanage_context_t *con1 = NULL;
+    semanage_context_t *con2 = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_node_create(sh, &node) >= 0);
+
+    CU_ASSERT(semanage_context_from_string(sh,
+                               "my_user_u:my_role_r:my_type_t:s0", &con1) >= 0);
+
+    // test
+    CU_ASSERT(semanage_node_set_con(sh, node, con1) == 0);
+
+    con2 = semanage_node_get_con(node);
+
+    CU_ASSERT_CONTEXT_EQUAL(con1, con2);
+
+    // cleanup
+    semanage_node_free(node);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_node_create
+
+void test_node_create(void) {
+    semanage_node_t *node = NULL;
+    semanage_context_t *con = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    // test
+    CU_ASSERT(semanage_node_create(sh, &node) >= 0);
+
+    CU_ASSERT(semanage_node_set_addr(sh, node, SEMANAGE_PROTO_IP4,
+                                     "127.0.0.1") >= 0);
+
+    CU_ASSERT(semanage_node_set_mask(sh, node, SEMANAGE_PROTO_IP4,
+                                     "255.255.255.0") >= 0);
+
+    semanage_node_set_proto(node, SEMANAGE_PROTO_IP4);
+
+    CU_ASSERT(semanage_context_from_string(sh, "user_u:role_r:type_t:s0",
+                                           &con) >= 0);
+    CU_ASSERT(semanage_node_set_con(sh, node, con) >= 0);
+
+    // cleanup
+    semanage_node_free(node);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_node_clone
+
+void test_node_clone(void) {
+    semanage_node_t *node = NULL;
+    semanage_node_t *node_clone = NULL;
+    semanage_context_t *con = NULL;
+    semanage_context_t *con2 = NULL;
+    const char *addr1 = "127.0.0.1";
+    char *addr2 = NULL;
+    const char *mask1 = "255.255.255.0";
+    char *mask2 = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_node_create(sh, &node) >= 0);
+
+    CU_ASSERT(semanage_node_set_addr(sh, node, SEMANAGE_PROTO_IP4,
+                                     addr1) >= 0);
+
+    CU_ASSERT(semanage_node_set_mask(sh, node, SEMANAGE_PROTO_IP4,
+                                     mask1) >= 0);
+
+    semanage_node_set_proto(node, SEMANAGE_PROTO_IP4);
+
+    CU_ASSERT(semanage_context_from_string(sh, "user_u:role_r:type_t:s0",
+                                           &con) >= 0);
+    CU_ASSERT(semanage_node_set_con(sh, node, con) >= 0);
+
+    // test
+    CU_ASSERT(semanage_node_clone(sh, node, &node_clone) >= 0);
+
+    CU_ASSERT(semanage_node_get_addr(sh, node_clone, &addr2) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(addr2);
+    CU_ASSERT_STRING_EQUAL(addr1, addr2);
+
+    CU_ASSERT(semanage_node_get_mask(sh, node_clone, &mask2) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(mask2);
+    CU_ASSERT_STRING_EQUAL(mask1, mask2);
+
+    CU_ASSERT(semanage_node_get_proto(node_clone) == SEMANAGE_PROTO_IP4);
+
+    con2 = semanage_node_get_con(node_clone);
+    
+    CU_ASSERT_CONTEXT_EQUAL(con, con2);
+
+    // cleanup
+    semanage_node_free(node);
+    semanage_node_free(node_clone);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_node_query
+
+void test_node_query(void) {
+    semanage_node_t *node = NULL;
+    semanage_node_key_t *key = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    key = get_node_key();
+
+    // test
+    CU_ASSERT(semanage_node_query(sh, key, &node) >= 0);
+
+    CU_ASSERT(node == NULL);
+
+    // cleanup
+    semanage_node_free(node);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_node_exists
+
+void test_node_exists(void) {
+    semanage_node_key_t *key = NULL;
+    int response = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    key = get_node_key();
+
+    // test
+    CU_ASSERT(semanage_node_exists(sh, key, &response) >= 0);
+
+    CU_ASSERT(!response);
+
+    // cleanup
+    semanage_node_key_free(key);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_node_count
+
+void test_node_count(void) {
+    unsigned int count = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    // test
+    CU_ASSERT(semanage_node_count(sh, &count) >= 0);
+
+    CU_ASSERT(count == NODE_COUNT);
+
+    // cleanup
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_node_iterate
+
+unsigned int counter_node_iterate = 0;
+
+int handler_node_iterate(const semanage_node_t *record, void *varg) {
+    counter_node_iterate++;
+    return 0;
+}
+
+void test_node_iterate(void) {
+    // setup
+    setup_handle(SH_CONNECT);
+
+    // test
+    semanage_node_iterate(sh, handler_node_iterate, NULL);
+
+    CU_ASSERT(counter_node_iterate == NODE_COUNT);
+
+    // cleanup
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_node_list
+
+void test_node_list(void) {
+    semanage_node_t **records = NULL;
+    unsigned int count = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    // test
+    CU_ASSERT(semanage_node_list(sh, &records, &count) >= 0);
+
+    CU_ASSERT(count == NODE_COUNT);
+
+    for (unsigned int i = 0; i < count; i++) {
+        CU_ASSERT_PTR_NOT_NULL(records[i]);
+    }
+
+    for (unsigned int i = 0; i < count; i++) {
+        semanage_node_free(records[i]);
+    }
+
+    // cleanup
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_node_modify_local, semanage_node_del_local,
+// semanage_node_query_local
+
+void test_node_modify_del_query_local(void) {
+    semanage_node_t *node;
+    semanage_node_t *node_local;
+    semanage_node_t *node_tmp;
+    semanage_node_key_t *key = NULL;
+    semanage_node_key_t *key_tmp = NULL;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    node = get_node();
+
+    CU_ASSERT(semanage_node_key_extract(sh, node, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    // add second record, so that semanage_node_compare2_qsort will be called
+    node_tmp = get_node();
+
+    CU_ASSERT(semanage_node_set_addr(sh, node_tmp, SEMANAGE_PROTO_IP4,
+                                     "10.0.0.1") >= 0);
+
+    CU_ASSERT(semanage_node_key_extract(sh, node_tmp, &key_tmp) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key_tmp);
+
+    // test
+    CU_ASSERT(semanage_node_modify_local(sh, key, node) >= 0);
+    CU_ASSERT(semanage_node_modify_local(sh, key_tmp, node_tmp) >= 0);
+
+    // write changes to file
+    helper_commit();
+    helper_begin_transaction();
+
+    CU_ASSERT(semanage_node_query_local(sh, key, &node_local) >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(node_local);
+
+    CU_ASSERT(semanage_node_del_local(sh, key) >= 0);
+    CU_ASSERT(semanage_node_del_local(sh, key_tmp) >= 0);
+
+    CU_ASSERT(semanage_node_query_local(sh, key, &node_local) < 0);
+
+    // cleanup
+    semanage_node_free(node);
+    semanage_node_free(node_tmp);
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_node_exists_local
+
+void test_node_exists_local(void) {
+    semanage_node_t *node = NULL;
+    semanage_node_key_t *key1 = NULL;
+    semanage_node_key_t *key2 = NULL;
+    semanage_context_t *con = NULL;
+    int response = 42;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_node_create(sh, &node) >= 0);
+
+    CU_ASSERT(semanage_node_set_addr(sh, node, SEMANAGE_PROTO_IP4,
+                                     "127.0.0.1") >= 0);
+
+    CU_ASSERT(semanage_node_set_mask(sh, node, SEMANAGE_PROTO_IP4,
+                                     "255.255.255.0") >= 0);
+
+    semanage_node_set_proto(node, SEMANAGE_PROTO_IP4);
+
+    CU_ASSERT(semanage_context_from_string(sh, "user_u:role_r:type_t:s0",
+                                           &con) >= 0);
+    CU_ASSERT(semanage_node_set_con(sh, node, con) >= 0);
+
+    CU_ASSERT(semanage_node_key_extract(sh, node, &key1) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key1);
+
+    CU_ASSERT(semanage_node_modify_local(sh, key1, node) >= 0);
+
+    CU_ASSERT(semanage_node_key_create(sh, "192.168.0.1", "255.255.0.0",
+                                       SEMANAGE_PROTO_IP4, &key2) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key2);
+
+    // test existing
+    CU_ASSERT(semanage_node_exists_local(sh, key1, &response) >= 0);
+
+    CU_ASSERT(response);
+
+    // test nonexistent
+    CU_ASSERT(semanage_node_exists_local(sh, key2, &response) >= 0);
+
+    CU_ASSERT(!response);
+
+    // cleanup
+    CU_ASSERT(semanage_node_del_local(sh, key1) >= 0);
+    semanage_node_free(node);
+    semanage_node_key_free(key1);
+    semanage_node_key_free(key2);
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_node_count_local
+
+void test_node_count_local(void) {
+    unsigned int count = 42;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    add_local_node(I_FIRST);
+    add_local_node(I_SECOND);
+    add_local_node(I_THIRD);
+
+    // test
+    CU_ASSERT(semanage_node_count_local(sh, &count) >= 0);
+
+    CU_ASSERT(count == 3);
+
+    // cleanup
+    delete_local_node(I_FIRST);
+    delete_local_node(I_SECOND);
+    delete_local_node(I_THIRD);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_node_iterate_local
+
+unsigned int counter_node_iterate_local = 0;
+
+int handler_node_iterate_local(const semanage_node_t *record, void *varg) {
+    counter_node_iterate_local++;
+    return 0;
+}
+
+void test_node_iterate_local(void) {
+    // setup
+    setup_handle(SH_TRANS);
+
+    add_local_node(I_FIRST);
+    add_local_node(I_SECOND);
+    add_local_node(I_THIRD);
+
+    // test
+    semanage_node_iterate_local(sh, handler_node_iterate_local, NULL);
+
+    CU_ASSERT(counter_node_iterate_local == 3);
+
+    // cleanup
+    delete_local_node(I_FIRST);
+    delete_local_node(I_SECOND);
+    delete_local_node(I_THIRD);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_node_list_local
+
+void test_node_list_local(void) {
+    semanage_node_t **records = NULL;
+    unsigned int count = 42;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    add_local_node(I_FIRST);
+    add_local_node(I_SECOND);
+    add_local_node(I_THIRD);
+
+    // test
+    CU_ASSERT(semanage_node_list_local(sh, &records, &count) >= 0);
+
+    CU_ASSERT(count == 3);
+
+    for (unsigned int i = 0; i < count; i++) {
+        CU_ASSERT_PTR_NOT_NULL(records[i]);
+    }
+
+    // cleanup
+    for (unsigned int i = 0; i < count; i++) {
+        semanage_node_free(records[i]);
+    }
+
+    delete_local_node(I_FIRST);
+    delete_local_node(I_SECOND);
+    delete_local_node(I_THIRD);
+
+    cleanup_handle(SH_TRANS);
+}

diff --git a/libsemanage/sanity-tests/tests/test_node.h b/libsemanage/sanity-tests/tests/test_node.h
new file mode 100644
index 0000000..d500ca7
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_node.h
@@ -0,0 +1,43 @@
+#ifndef __TEST_NODE_H__
+#define __TEST_NODE_H__
+
+#include <CUnit/Basic.h>
+
+int node_test_init(void);
+int node_test_cleanup(void);
+int node_add_tests(CU_pSuite suite);
+
+// node_record.h
+
+void test_node_compare(void);
+void test_node_compare2(void);
+void test_node_key_create(void);
+void test_node_key_extract(void);
+void test_node_get_set_addr(void);
+void test_node_get_set_addr_bytes(void);
+void test_node_get_set_mask(void);
+void test_node_get_set_mask_bytes(void);
+void test_node_get_set_proto(void);
+void test_node_get_proto_str(void);
+void test_node_get_set_con(void);
+void test_node_create(void);
+void test_node_clone(void);
+
+// nodes_policy.h
+
+void test_node_query(void);
+void test_node_exists(void);
+void test_node_count(void);
+void test_node_iterate(void);
+void test_node_list(void);
+
+// nodes_local.h
+
+void test_node_modify_del_query_local(void);
+void test_node_exists_local(void);
+void test_node_count_local(void);
+void test_node_iterate_local(void);
+void test_node_list_local(void);
+
+#endif
+

diff --git a/libsemanage/sanity-tests/tests/test_other.c b/libsemanage/sanity-tests/tests/test_other.c
new file mode 100644
index 0000000..baaf49f
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_other.c
@@ -0,0 +1,108 @@
+#include <stdio.h>
+#include <semanage/semanage.h>
+#include <semanage/handle.h>
+#include <CUnit/Basic.h>
+
+#include "test_other.h"
+#include "functions.h"
+
+extern semanage_handle_t *sh;
+
+int other_test_init(void) {
+	return 0;
+}
+
+int other_test_cleanup(void) {
+	return 0;
+}
+
+int other_add_tests(CU_pSuite suite) {
+    CU_add_test(suite, "semanage_context", test_semanage_context);
+
+#if VERS_CHECK(2, 5)
+    CU_add_test(suite, "debug", test_debug);
+#endif
+
+	return 0;
+}
+
+// Function semanage_context_get_user, semanage_context_set_user,
+// semanage_context_get_role, semanage_context_set_role,
+// semanage_context_get_type, semanage_context_set_type,
+// semanage_context_get_mls, semanage_context_set_mls,
+// semanage_context_create, semanage_context_clone,
+// semanage_context_free, semanage_context_from_string
+// semanage_context_to_string
+
+void test_semanage_context(void) {
+    semanage_context_t *con = NULL;
+    semanage_context_t *con_clone = NULL;
+    char *str = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    // test
+    CU_ASSERT(semanage_context_create(sh, &con) >= 0);
+
+    CU_ASSERT(semanage_context_set_user(sh, con, "user_u") >= 0);
+    CU_ASSERT_STRING_EQUAL(semanage_context_get_user(con), "user_u");
+
+    CU_ASSERT(semanage_context_set_role(sh, con, "role_r") >= 0);
+    CU_ASSERT_STRING_EQUAL(semanage_context_get_role(con), "role_r");
+    
+    CU_ASSERT(semanage_context_set_type(sh, con, "type_t") >= 0);
+    CU_ASSERT_STRING_EQUAL(semanage_context_get_type(con), "type_t");
+    
+    CU_ASSERT(semanage_context_set_mls(sh, con, "s0") >= 0);
+    CU_ASSERT_STRING_EQUAL(semanage_context_get_mls(con), "s0");
+
+    CU_ASSERT(semanage_context_to_string(sh, con, &str) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(str);
+    CU_ASSERT_STRING_EQUAL(str, "user_u:role_r:type_t:s0");
+
+    CU_ASSERT(semanage_context_from_string(sh, "my_u:my_r:my_t:s0",
+                                           &con) >= 0);
+    
+    CU_ASSERT_STRING_EQUAL(semanage_context_get_user(con), "my_u");
+    CU_ASSERT_STRING_EQUAL(semanage_context_get_role(con), "my_r");
+    CU_ASSERT_STRING_EQUAL(semanage_context_get_type(con), "my_t");
+    CU_ASSERT_STRING_EQUAL(semanage_context_get_mls(con), "s0");
+
+    CU_ASSERT(semanage_context_clone(sh, con, &con_clone) >= 0);
+
+    CU_ASSERT_STRING_EQUAL(semanage_context_get_user(con_clone), "my_u");
+    CU_ASSERT_STRING_EQUAL(semanage_context_get_role(con_clone), "my_r");
+    CU_ASSERT_STRING_EQUAL(semanage_context_get_type(con_clone), "my_t");
+    CU_ASSERT_STRING_EQUAL(semanage_context_get_mls(con_clone), "s0");
+
+    // cleanup
+    semanage_context_free(con);
+    semanage_context_free(con_clone);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_msg_default_handler
+
+#if VERS_CHECK(2, 5)
+
+void test_debug(void) {
+    semanage_module_info_t *modinfo = NULL;
+
+    // setup
+    sh = semanage_handle_create();
+    CU_ASSERT_PTR_NOT_NULL(sh);
+
+    CU_ASSERT(semanage_connect(sh) >= 0);
+
+    CU_ASSERT(semanage_module_info_create(sh, &modinfo) >= 0);
+
+    // test
+    CU_ASSERT(semanage_module_info_set_priority(sh, modinfo, -42) < 0);
+
+    // cleanup
+    CU_ASSERT(semanage_disconnect(sh) >= 0);
+    semanage_handle_destroy(sh);
+}
+
+#endif

diff --git a/libsemanage/sanity-tests/tests/test_other.h b/libsemanage/sanity-tests/tests/test_other.h
new file mode 100644
index 0000000..3ed3c2b
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_other.h
@@ -0,0 +1,25 @@
+#ifndef __TEST_OTHER_H__
+#define __TEST_OTHER_H__
+
+#include <CUnit/Basic.h>
+
+#include "functions.h"
+
+int other_test_init(void);
+int other_test_cleanup(void);
+int other_add_tests(CU_pSuite suite);
+
+// context_record.h
+
+void test_semanage_context(void);
+
+// debug.h
+
+#if VERS_CHECK(2, 5)
+
+void test_debug(void);
+
+#endif
+
+#endif
+

diff --git a/libsemanage/sanity-tests/tests/test_port.c b/libsemanage/sanity-tests/tests/test_port.c
new file mode 100644
index 0000000..3e625a9
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_port.c
@@ -0,0 +1,843 @@
+#include <stdio.h>
+#include <semanage/semanage.h>
+#include <semanage/handle.h>
+#include <CUnit/Basic.h>
+
+#include "test_port.h"
+#include "functions.h"
+
+extern semanage_handle_t *sh;
+
+int port_test_init(void) {
+	return 0;
+}
+
+int port_test_cleanup(void) {
+	return 0;
+}
+
+int port_add_tests(CU_pSuite suite) {
+    CU_add_test(suite, "port_compare", test_port_compare);
+    CU_add_test(suite, "port_compare2", test_port_compare2);
+    CU_add_test(suite, "port_key_create", test_port_key_create);
+    CU_add_test(suite, "port_key_extract", test_port_key_extract);
+    CU_add_test(suite, "port_get_set_proto", test_port_get_set_proto);
+    CU_add_test(suite, "port_get_proto_str", test_port_get_proto_str);
+    CU_add_test(suite, "port_get_set_port", test_port_get_set_port);
+    CU_add_test(suite, "port_get_set_con", test_port_get_set_con);
+    CU_add_test(suite, "port_create", test_port_create);
+    CU_add_test(suite, "port_clone", test_port_clone);
+
+    CU_add_test(suite, "port_query", test_port_query);
+    CU_add_test(suite, "port_exists", test_port_exists);
+    CU_add_test(suite, "port_count", test_port_count);
+    CU_add_test(suite, "port_iterate", test_port_iterate);
+    CU_add_test(suite, "port_list", test_port_list);
+
+    CU_add_test(suite, "port_modify_del_local", test_port_modify_del_local);
+    CU_add_test(suite, "port_query_local", test_port_query_local);
+    CU_add_test(suite, "port_exists_local", test_port_exists_local);
+    CU_add_test(suite, "port_count_local", test_port_count_local);
+    CU_add_test(suite, "port_iterate_local", test_port_iterate_local);
+    CU_add_test(suite, "port_list_local", test_port_list_local);
+
+    CU_add_test(suite, "port_validate_local", test_port_validate_local);
+
+	return 0;
+}
+
+// Function semanage_port_compare
+
+void helper_port_compare(int index1, int index2) {
+    semanage_port_t *port = NULL;
+    semanage_port_key_t *key = NULL;
+    int result = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    port = get_port_nth(index1);
+    key = get_port_key_nth(index2);
+
+    // test
+    result = semanage_port_compare(port, key);
+
+    if (index1 == index2) {
+        CU_ASSERT(result == 0);
+    }
+    else {
+        CU_ASSERT(result != 0);
+    }
+
+    // cleanup
+    semanage_port_free(port);
+    semanage_port_key_free(key);
+    cleanup_handle(SH_CONNECT);
+}
+
+void test_port_compare(void) {
+    helper_port_compare(I_FIRST,  I_FIRST);
+    helper_port_compare(I_FIRST,  I_SECOND);
+    helper_port_compare(I_SECOND, I_FIRST);
+    helper_port_compare(I_SECOND, I_SECOND);
+
+    CU_ASSERT_SIGNAL(helper_port_compare(I_NULL,  I_FIRST), SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_port_compare(I_FIRST, I_NULL), SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_port_compare(I_NULL,  I_NULL), SIGSEGV);
+}
+
+// Function semanage_port_compare2
+
+void helper_port_compare2(int index1, int index2) {
+    semanage_port_t *port1 = NULL;
+    semanage_port_t *port2 = NULL;
+    int result = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    port1 = get_port_nth(index1);
+    port2 = get_port_nth(index2);
+
+    // test
+    result = semanage_port_compare2(port1, port2);
+
+    if (index1 == index2) {
+        CU_ASSERT(result == 0);
+    }
+    else {
+        CU_ASSERT(result != 0);
+    }
+
+    // cleanup
+    semanage_port_free(port1);
+    semanage_port_free(port2);
+    cleanup_handle(SH_CONNECT);
+}
+
+void test_port_compare2(void) {
+    helper_port_compare2(I_FIRST,  I_FIRST);
+    helper_port_compare2(I_FIRST,  I_SECOND);
+    helper_port_compare2(I_SECOND, I_FIRST);
+    helper_port_compare2(I_SECOND, I_SECOND);
+
+    CU_ASSERT_SIGNAL(helper_port_compare2(I_NULL,  I_FIRST), SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_port_compare2(I_FIRST, I_NULL), SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_port_compare2(I_NULL,  I_NULL), SIGSEGV);
+}
+
+// Function semanage_port_create
+
+void test_port_key_create(void) {
+    semanage_port_key_t *key = NULL;
+
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_port_key_create(sh, 1000, 1200, 0, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    semanage_port_key_free(key);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_port_extract
+
+void test_port_key_extract(void) {
+    semanage_port_t *port = NULL;
+    semanage_port_key_t *key = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    port = get_port_nth(I_FIRST);
+
+    // test
+    CU_ASSERT(semanage_port_key_extract(sh, port, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    // cleanup
+    semanage_port_free(port);
+    semanage_port_key_free(key);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_port_get_proto, semanage_port_set_proto
+
+void helper_port_get_set_proto(int index) {
+    semanage_port_t *port = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    port = get_port_nth(index);
+
+    // test
+    semanage_port_set_proto(port, 0);
+
+    CU_ASSERT(semanage_port_get_proto(port) == 0);
+
+    semanage_port_set_proto(port, 1);
+
+    CU_ASSERT(semanage_port_get_proto(port) == 1);
+
+    // cleanup
+    semanage_port_free(port);
+    cleanup_handle(SH_CONNECT);
+}
+
+void test_port_get_set_proto(void) {
+    helper_port_get_set_proto(I_FIRST);
+    helper_port_get_set_proto(I_SECOND);
+}
+
+// Function semanage_port_get_proto_str
+
+void test_port_get_proto_str(void) {
+    const char *str = NULL;
+
+    str = semanage_port_get_proto_str(-1);
+    CU_ASSERT_STRING_EQUAL(str, "???");
+
+    str = semanage_port_get_proto_str(0);
+    CU_ASSERT_STRING_EQUAL(str, "udp");
+
+    str = semanage_port_get_proto_str(1);
+    CU_ASSERT_STRING_EQUAL(str, "tcp");
+
+    str = semanage_port_get_proto_str(2);
+#if VERS_CHECK(2, 5)
+    CU_ASSERT_STRING_EQUAL(str, "dccp");
+#else
+    CU_ASSERT_STRING_EQUAL(str, "???");
+#endif
+
+    str = semanage_port_get_proto_str(3);
+#if VERS_CHECK(2, 8) || VERS_CHECK_REL(2, 7, 6)
+    CU_ASSERT_STRING_EQUAL(str, "sctp");
+#else
+    CU_ASSERT_STRING_EQUAL(str, "???");
+#endif
+
+    str = semanage_port_get_proto_str(4);
+    CU_ASSERT_STRING_EQUAL(str, "???");
+}
+
+// Function semanage_port_get_low, semanage_port_get_high,
+// semanage_port_set_port, semanage_port_set_range
+
+void test_port_get_set_port(void) {
+    semanage_port_t *port = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    port = get_port_nth(I_FIRST);
+
+    // test
+    semanage_port_set_port(port, 1000);
+
+    CU_ASSERT(semanage_port_get_low(port) == 1000);
+    CU_ASSERT(semanage_port_get_high(port) == 1000);
+
+    semanage_port_set_range(port, 1000, 1200);
+
+    CU_ASSERT(semanage_port_get_low(port) == 1000);
+    CU_ASSERT(semanage_port_get_high(port) == 1200);
+    
+    // cleanup
+    semanage_port_free(port);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_port_get_con, semanage_port_set_con
+
+void test_port_get_set_con(void) {
+    semanage_port_t *port = NULL;
+    semanage_port_t *port_tmp = NULL;
+    semanage_context_t *con = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    port = get_port_nth(I_FIRST);
+    port_tmp = get_port_nth(I_SECOND);
+
+    con = semanage_port_get_con(port_tmp);
+
+    // test
+    CU_ASSERT(semanage_port_set_con(sh, port, con) >= 0);
+
+    CU_ASSERT(semanage_port_get_con(port) != NULL);
+
+    // TODO: check the context
+
+    // cleanup
+    semanage_port_free(port);
+    semanage_port_free(port_tmp);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_port_create
+
+void test_port_create(void) {
+    semanage_port_t *port = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    // test
+    CU_ASSERT(semanage_port_create(sh, &port) >= 0);
+
+    CU_ASSERT(semanage_port_get_low(port) == 0);
+    CU_ASSERT(semanage_port_get_high(port) == 0);
+    CU_ASSERT(semanage_port_get_con(port) == NULL);
+    CU_ASSERT(semanage_port_get_proto(port) == 0);
+
+    // cleanup
+    semanage_port_free(port);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_port_clone
+
+void test_port_clone(void) {
+    semanage_port_t *port = NULL;
+    semanage_port_t *port_clone = NULL;
+    semanage_context_t *con = NULL;
+    semanage_context_t *con2 = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_port_create(sh, &port) >= 0);
+
+    semanage_port_set_range(port, 1000, 1200);
+    semanage_port_set_proto(port, 1);
+
+    semanage_context_from_string(sh, "user_u:role_r:type_t:s0", &con);
+    semanage_port_set_con(sh, port, con);
+
+    // test
+    CU_ASSERT(semanage_port_clone(sh, port, &port_clone) >= 0);
+
+    CU_ASSERT(semanage_port_get_low(port_clone) == 1000);
+    CU_ASSERT(semanage_port_get_high(port_clone) == 1200);
+    CU_ASSERT(semanage_port_get_proto(port_clone) == 1);
+
+    con2 = semanage_port_get_con(port_clone);
+    CU_ASSERT_CONTEXT_EQUAL(con, con2);
+
+    // cleanup
+    semanage_port_free(port);
+    semanage_port_free(port_clone);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_port_query
+
+void test_port_query(void) {
+    semanage_port_t *port = NULL;
+    semanage_port_t *port_exp = NULL;
+    semanage_port_key_t *key = NULL;
+    semanage_context_t *con = NULL;
+    semanage_context_t *con_exp = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    key = get_port_key_nth(I_FIRST);
+
+    port_exp = get_port_nth(I_FIRST);
+
+    // test
+    CU_ASSERT(semanage_port_query(sh, key, &port) >= 0);
+
+    CU_ASSERT(semanage_port_get_low(port) ==
+              semanage_port_get_low(port_exp));
+    CU_ASSERT(semanage_port_get_high(port) ==
+              semanage_port_get_high(port_exp));
+    CU_ASSERT(semanage_port_get_proto(port) ==
+              semanage_port_get_proto(port_exp));
+
+    con = semanage_port_get_con(port);
+    con_exp = semanage_port_get_con(port_exp);
+
+    CU_ASSERT_CONTEXT_EQUAL(con, con_exp);
+
+    // cleanup
+    semanage_port_free(port);
+    semanage_port_free(port_exp);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_port_exists
+
+void test_port_exists(void) {
+    semanage_port_key_t *key1 = NULL;
+    semanage_port_key_t *key2 = NULL;
+    int response = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    key1 = get_port_key_nth(I_FIRST);
+    
+    CU_ASSERT(semanage_port_key_create(sh, 123, 456, 0, &key2) >= 0);
+
+    // test existing
+    CU_ASSERT(semanage_port_exists(sh, key1, &response) >= 0);
+
+    CU_ASSERT(response);
+
+    // test nonexistent
+    CU_ASSERT(semanage_port_exists(sh, key2, &response) >= 0);
+
+    CU_ASSERT(!response);
+
+    // cleanup
+    semanage_port_key_free(key1);
+    semanage_port_key_free(key2);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_port_count
+
+void test_port_count(void) {
+    unsigned int count = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    // test
+    CU_ASSERT(semanage_port_count(sh, &count) >= 0);
+
+    // TODO: check real count
+    CU_ASSERT(count > 0);
+
+    // cleanup
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_port_iterate
+
+unsigned int counter_port_iterate = 0;
+
+int handler_port_iterate(const semanage_port_t *record, void *varg) {
+    counter_port_iterate++;
+    return 0;
+}
+
+void test_port_iterate(void) {
+    // setup
+    setup_handle(SH_CONNECT);
+
+    // test
+    semanage_port_iterate(sh, handler_port_iterate, NULL);
+
+    // TODO: check real count
+    CU_ASSERT(counter_port_iterate > 0);
+
+    // cleanup
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_port_list
+
+void test_port_list(void) {
+    semanage_port_t **records = NULL;
+    unsigned int count = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    // test
+    CU_ASSERT(semanage_port_list(sh, &records, &count) >= 0);
+
+    CU_ASSERT(count > 0);
+
+    for (unsigned int i = 0; i < count; i++) {
+        CU_ASSERT_PTR_NOT_NULL(records[i]);
+    }
+
+    // cleanup
+    for (unsigned int i = 0; i < count; i++) {
+        semanage_port_free(records[i]);
+    }
+
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_port_modify_local, semanage_port_del_local
+
+void test_port_modify_del_local(void) {
+    semanage_port_t *port;
+    semanage_port_t *port_local;
+    semanage_port_key_t *key = NULL;
+    semanage_context_t *con = NULL;
+    semanage_context_t *con_local = NULL;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    port = get_port_nth(I_FIRST);
+
+    semanage_context_from_string(sh, "user_u:role_r:type_t:s0", &con);
+    semanage_port_set_con(sh, port, con);
+
+    CU_ASSERT(semanage_port_key_extract(sh, port, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    // test
+    CU_ASSERT(semanage_port_modify_local(sh, key, port) >= 0);
+
+    CU_ASSERT(semanage_port_query_local(sh, key, &port_local) >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(port_local);
+
+    con_local = semanage_port_get_con(port_local);
+
+    CU_ASSERT_CONTEXT_EQUAL(con, con_local);
+
+    CU_ASSERT(semanage_port_del_local(sh, key) >= 0);
+
+    CU_ASSERT(semanage_port_query_local(sh, key, &port_local) < 0);
+
+    // cleanup
+    semanage_port_free(port);
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_port_query_local
+
+void test_port_query_local(void) {
+    semanage_port_t *port = NULL;
+    semanage_port_t *port_exp = NULL;
+    semanage_port_key_t *key = NULL;
+    semanage_context_t *con = NULL;
+    semanage_context_t *con_exp = NULL;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    add_local_port(I_FIRST);
+
+    key = get_port_key_nth(I_FIRST);
+
+    port_exp = get_port_nth(I_FIRST);
+
+    // test
+    CU_ASSERT(semanage_port_query_local(sh, key, &port) >= 0);
+
+    CU_ASSERT(semanage_port_get_low(port) ==
+              semanage_port_get_low(port_exp));
+    CU_ASSERT(semanage_port_get_high(port) ==
+              semanage_port_get_high(port_exp));
+    CU_ASSERT(semanage_port_get_proto(port) ==
+              semanage_port_get_proto(port_exp));
+
+    con = semanage_port_get_con(port);
+    con_exp = semanage_port_get_con(port_exp);
+
+    CU_ASSERT_CONTEXT_EQUAL(con, con_exp);
+
+    // cleanup
+    delete_local_port(I_FIRST);
+    semanage_port_free(port);
+    semanage_port_free(port_exp);
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_port_exists_local
+
+void test_port_exists_local(void) {
+    semanage_port_key_t *key1 = NULL;
+    semanage_port_key_t *key2 = NULL;
+    int response = 42;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    add_local_port(I_FIRST);
+
+    key1 = get_port_key_nth(I_FIRST);
+    key2 = get_port_key_nth(I_SECOND);
+
+    // test existing
+    CU_ASSERT(semanage_port_exists_local(sh, key1, &response) >= 0);
+
+    CU_ASSERT(response);
+
+    // test nonexistent
+    CU_ASSERT(semanage_port_exists_local(sh, key2, &response) >= 0);
+
+    CU_ASSERT(!response);
+
+    // cleanup
+    delete_local_port(I_FIRST);
+    semanage_port_key_free(key1);
+    semanage_port_key_free(key2);
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_port_count_local
+
+void test_port_count_local(void) {
+    unsigned int count = 42;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    // test 0 local ports
+    CU_ASSERT(semanage_port_count_local(sh, &count) >= 0);
+    CU_ASSERT(count == 0);
+
+    // test 1 local port
+    add_local_port(I_FIRST);
+
+    CU_ASSERT(semanage_port_count_local(sh, &count) >= 0);
+    CU_ASSERT(count == 1);
+
+    // test 2 local ports
+    add_local_port(I_SECOND);
+
+    CU_ASSERT(semanage_port_count_local(sh, &count) >= 0);
+    CU_ASSERT(count == 2);
+
+    // test 1 local port
+    delete_local_port(I_SECOND);
+
+    CU_ASSERT(semanage_port_count_local(sh, &count) >= 0);
+    CU_ASSERT(count == 1);
+
+    // test 0 local ports
+    delete_local_port(I_FIRST);
+
+    CU_ASSERT(semanage_port_count_local(sh, &count) >= 0);
+    CU_ASSERT(count == 0);
+
+    // cleanup
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_port_iterate_local
+
+unsigned int counter_port_iterate_local = 0;
+
+int handler_port_iterate_local(const semanage_port_t *record, void *varg) {
+    counter_port_iterate_local++;
+    return 0;
+}
+
+void test_port_iterate_local(void) {
+    // setup
+    setup_handle(SH_TRANS);
+
+    add_local_port(I_FIRST);
+    add_local_port(I_SECOND);
+    add_local_port(I_THIRD);
+
+    // test
+    semanage_port_iterate_local(sh, handler_port_iterate_local, NULL);
+
+    CU_ASSERT(counter_port_iterate_local == 3);
+
+    // cleanup
+    delete_local_port(I_FIRST);
+    delete_local_port(I_SECOND);
+    delete_local_port(I_THIRD);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_port_list_local
+
+void test_port_list_local(void) {
+    semanage_port_t **records = NULL;
+    unsigned int count = 42;
+    // setup
+    setup_handle(SH_TRANS);
+
+    add_local_port(I_FIRST);
+    add_local_port(I_SECOND);
+    add_local_port(I_THIRD);
+
+    // test
+    CU_ASSERT(semanage_port_list_local(sh, &records, &count) >= 0);
+
+    CU_ASSERT(count == 3);
+
+    for (unsigned int i = 0; i < count; i++) {
+        CU_ASSERT_PTR_NOT_NULL(records[i]);
+    }
+
+    // cleanup
+    for (unsigned int i = 0; i < count; i++) {
+        semanage_port_free(records[i]);
+    }
+
+    delete_local_port(I_FIRST);
+    delete_local_port(I_SECOND);
+    delete_local_port(I_THIRD);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Internal function semanage_port_validate_local
+// TODO: test all corner cases
+
+void helper_port_validate_local_noport(void) {
+    semanage_port_key_t *key = NULL;
+    int response = 42;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    add_local_port(I_FIRST);
+
+    helper_commit();
+
+    key = get_port_key_nth(I_FIRST);
+
+    CU_ASSERT(semanage_port_exists_local(sh, key, &response) >= 0);
+    CU_ASSERT(response);
+
+    // test
+    helper_begin_transaction();
+
+    delete_local_port(I_FIRST);
+
+    helper_commit();
+
+    // cleanup
+    helper_begin_transaction();
+    delete_local_port(I_FIRST);
+    cleanup_handle(SH_TRANS);
+}
+
+void helper_port_validate_local_oneport(void) {
+    // setup
+    setup_handle(SH_TRANS);
+
+    add_local_port(I_FIRST);
+
+    // test
+    helper_commit();
+
+    // cleanup
+    helper_begin_transaction();
+    delete_local_port(I_FIRST);
+    cleanup_handle(SH_TRANS);
+}
+
+void helper_port_validate_local_twoports(void) {
+    semanage_port_key_t *key1 = NULL;
+    semanage_port_key_t *key2 = NULL;
+    semanage_port_t *port1 = NULL;
+    semanage_port_t *port2 = NULL;
+    semanage_context_t *con1 = NULL;
+    semanage_context_t *con2 = NULL;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_port_key_create(sh, 101, 200, 0, &key1) >= 0);
+    CU_ASSERT(semanage_port_key_create(sh, 201, 300, 0, &key2) >= 0);
+
+    CU_ASSERT(semanage_port_create(sh, &port1) >= 0);
+    CU_ASSERT(semanage_port_create(sh, &port2) >= 0);
+
+    semanage_port_set_range(port1, 101, 200);
+    semanage_port_set_range(port2, 201, 300);
+    semanage_port_set_proto(port1, 0);
+    semanage_port_set_proto(port2, 0);
+
+    CU_ASSERT(semanage_context_from_string(sh,
+                "system_u:object_r:user_home_t:s0", &con1) >= 0);
+    CU_ASSERT(semanage_context_from_string(sh,
+                "system_u:object_r:user_tmp_t:s0", &con2) >= 0);
+
+    semanage_port_set_con(sh, port1, con1);
+    semanage_port_set_con(sh, port2, con2);
+
+    CU_ASSERT(semanage_port_modify_local(sh, key1, port1) >= 0);
+    CU_ASSERT(semanage_port_modify_local(sh, key2, port2) >= 0);
+
+    // test
+    helper_commit();
+
+    // cleanup
+    helper_begin_transaction();
+    CU_ASSERT(semanage_port_del_local(sh, key1) >= 0);
+    CU_ASSERT(semanage_port_del_local(sh, key2) >= 0);
+    semanage_port_key_free(key1);
+    semanage_port_key_free(key2);
+    semanage_port_free(port1);
+    semanage_port_free(port2);
+    cleanup_handle(SH_TRANS);
+}
+
+void helper_port_validate_local_proto(void) {
+    semanage_port_key_t *key1 = NULL;
+    semanage_port_key_t *key2 = NULL;
+    semanage_port_key_t *key3 = NULL;
+    semanage_port_t *port1 = NULL;
+    semanage_port_t *port2 = NULL;
+    semanage_port_t *port3 = NULL;
+    semanage_context_t *con1 = NULL;
+    semanage_context_t *con2 = NULL;
+    semanage_context_t *con3 = NULL;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    CU_ASSERT(semanage_port_key_create(sh, 101, 200, 0, &key1) >= 0);
+    CU_ASSERT(semanage_port_key_create(sh,  51, 250, 1, &key2) >= 0);
+    CU_ASSERT(semanage_port_key_create(sh, 201, 300, 0, &key3) >= 0);
+
+    CU_ASSERT(semanage_port_create(sh, &port1) >= 0);
+    CU_ASSERT(semanage_port_create(sh, &port2) >= 0);
+    CU_ASSERT(semanage_port_create(sh, &port3) >= 0);
+
+    semanage_port_set_range(port1, 101, 200);
+    semanage_port_set_range(port2,  51, 250);
+    semanage_port_set_range(port3, 201, 300);
+    
+    semanage_port_set_proto(port1, 0);
+    semanage_port_set_proto(port2, 0);
+    semanage_port_set_proto(port3, 0);
+
+    CU_ASSERT(semanage_context_from_string(sh,
+                "system_u:object_r:user_home_t:s0", &con1) >= 0);
+    CU_ASSERT(semanage_context_from_string(sh,
+                "system_u:object_r:user_home_t:s0", &con2) >= 0);
+    CU_ASSERT(semanage_context_from_string(sh,
+                "system_u:object_r:user_tmp_t:s0", &con3) >= 0);
+
+    semanage_port_set_con(sh, port1, con1);
+    semanage_port_set_con(sh, port2, con2);
+    semanage_port_set_con(sh, port3, con3);
+
+    CU_ASSERT(semanage_port_modify_local(sh, key1, port1) >= 0);
+    CU_ASSERT(semanage_port_modify_local(sh, key2, port2) >= 0);
+    CU_ASSERT(semanage_port_modify_local(sh, key3, port3) >= 0);
+
+    // test
+    helper_commit();
+
+    // cleanup
+    CU_ASSERT(semanage_port_del_local(sh, key1) >= 0);
+    CU_ASSERT(semanage_port_del_local(sh, key2) >= 0);
+    CU_ASSERT(semanage_port_del_local(sh, key3) >= 0);
+    semanage_port_key_free(key1);
+    semanage_port_key_free(key2);
+    semanage_port_key_free(key3);
+    semanage_port_free(port1);
+    semanage_port_free(port2);
+    semanage_port_free(port3);
+    cleanup_handle(SH_TRANS);
+}
+
+void test_port_validate_local(void) {
+    helper_port_validate_local_noport();
+    helper_port_validate_local_oneport();
+    helper_port_validate_local_twoports();
+}

diff --git a/libsemanage/sanity-tests/tests/test_port.h b/libsemanage/sanity-tests/tests/test_port.h
new file mode 100644
index 0000000..520f492
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_port.h
@@ -0,0 +1,43 @@
+#ifndef __TEST_PORT_H__
+#define __TEST_PORT_H__
+
+#include <CUnit/Basic.h>
+
+int port_test_init(void);
+int port_test_cleanup(void);
+int port_add_tests(CU_pSuite suite);
+
+// port_record.h
+
+void test_port_compare(void);
+void test_port_compare2(void);
+void test_port_key_create(void);
+void test_port_key_extract(void);
+void test_port_get_set_proto(void);
+void test_port_get_proto_str(void);
+void test_port_get_set_port(void);
+void test_port_get_set_con(void);
+void test_port_create(void);
+void test_port_clone(void);
+
+// ports_policy.h
+
+void test_port_query(void);
+void test_port_exists(void);
+void test_port_count(void);
+void test_port_iterate(void);
+void test_port_list(void);
+
+// ports_local.h
+
+void test_port_modify_del_local(void);
+void test_port_query_local(void);
+void test_port_exists_local(void);
+void test_port_count_local(void);
+void test_port_iterate_local(void);
+void test_port_list_local(void);
+// internal
+void test_port_validate_local(void);
+
+#endif
+

diff --git a/libsemanage/sanity-tests/tests/test_seuser.c b/libsemanage/sanity-tests/tests/test_seuser.c
new file mode 100644
index 0000000..b58aee1
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_seuser.c
@@ -0,0 +1,1203 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <semanage/semanage.h>
+#include <semanage/handle.h>
+#include <selinux/selinux.h>
+#include <CUnit/Basic.h>
+
+#include "test_seuser.h"
+#include "functions.h"
+
+// TODO: test function semanage_seuser_compare2_qsort
+// TODO: seuser_print: error gotos
+// TODO: seuser_parse: error gotos
+// TODO: seuser_file_dbase_init: make dbase_file_init return error
+// TODO: semanage_seuser_audit: lines 88-90, 93-94
+// TODO: semanage_seuser_audit: make audit_open return error
+// TODO: validate_handler: error gotos
+
+extern semanage_handle_t *sh;
+
+#define SEUSER_NONEXISTENT "nonuser"
+#define SEUSER_DEFAULT "__default__"
+
+char *SEUSER;
+char *SEUSER_SENAME;
+char *SEUSER_MLSRANGE;
+char *SEUSER2;
+char *SEUSER2_SENAME;
+char *SEUSER2_MLSRANGE;
+unsigned int SEUSERS_COUNT;
+char *SEUSERS;
+
+int prepare_paths(char **p1, char **p2, char **p3) {
+#define POLICY_STORE1 "/var/lib/selinux/"
+#define POLICY_STORE2 "/etc/selinux/"
+#define PATH1 "/active/seusers"
+#define PATH2 "/seusers"
+
+    char *policy_type;
+
+    selinux_getpolicytype(&policy_type);
+
+    *p1 = malloc(strlen(POLICY_STORE1) + strlen(policy_type)
+                           + strlen(PATH1) + 1);
+
+    if (*p1 == NULL)
+        return -1;
+
+    *p2 = malloc(strlen(POLICY_STORE2) + strlen(policy_type)
+                           + strlen(PATH1) + 1);
+    
+    if (*p2 == NULL) {
+        free(*p1);
+        return -1;
+    }
+
+    *p3 = malloc(strlen(POLICY_STORE2) + strlen(policy_type)
+                           + strlen(PATH2) + 1);
+    
+    if (*p3 == NULL) {
+        free(*p1);
+        free(*p2);
+        return -1;
+    }
+
+    strcpy(*p1, POLICY_STORE1);
+    strcat(*p1, policy_type);
+    strcat(*p1, PATH1);
+
+    strcpy(*p2, POLICY_STORE2);
+    strcat(*p2, policy_type);
+    strcat(*p2, PATH1);
+
+    strcpy(*p3, POLICY_STORE2);
+    strcat(*p3, policy_type);
+    strcat(*p3, PATH2);
+
+    free(policy_type);
+
+    return 0;
+
+#undef POLICY_STORE1
+#undef POLICY_STORE2
+#undef PATH1
+#undef PATH2
+}
+
+int seuser_test_init(void)
+{
+    char *seusers_path1;
+    char *seusers_path2;
+    char *seusers_path3;
+    FILE *f;
+
+    if (prepare_paths(&seusers_path1, &seusers_path2, &seusers_path3) < 0) {
+        return 1;
+    }
+
+    f = fopen(seusers_path1, "r");
+
+    if (f == NULL) {
+        f = fopen(seusers_path2, "r");
+
+        if (f == NULL) {
+            f = fopen(seusers_path3, "r");
+            
+            if (f == NULL) {
+                fprintf(stderr, "Unable to open seusers file\n");
+                return 1;
+            }
+        }
+    }
+
+    char line[512];
+    unsigned int line_counter = 0;
+    char *p;
+    char seusers_tmp[512];
+
+    while (fgets(line, sizeof(line), f)) {
+        if (line[0] == '#' || line[0] == '\n')
+            continue;
+
+        p = strtok(line, ":");
+        strcat(seusers_tmp, " ");
+        strcat(seusers_tmp, p);
+
+        if (line_counter == 0) {
+            SEUSER = strdup(p);
+
+            p = strtok(NULL, ":");
+            SEUSER_SENAME = strdup(p);
+
+            p = strtok(NULL, ":");
+            SEUSER_MLSRANGE = strdup(p);
+        }
+        else if (line_counter == 1) {
+            SEUSER2 = strdup(p);
+
+            p = strtok(NULL, ":");
+            SEUSER2_SENAME = strdup(p);
+
+            p = strtok(NULL, ":");
+            SEUSER2_MLSRANGE = strdup(p);
+        }
+
+        line_counter++;
+    }
+
+    SEUSERS = strdup(seusers_tmp);
+    
+    SEUSERS_COUNT = line_counter;
+
+    if (SEUSERS_COUNT == 0) {
+        fprintf(stderr, "SEUSERS_COUNT is zero\n");
+        return 1;
+    }
+
+    // delete local seusers (written because of RHEL 6)
+    semanage_seuser_key_t *key = NULL;
+    semanage_seuser_t **records = NULL;
+    unsigned int count = 0;
+    
+    if ((sh = semanage_handle_create()) == NULL) {
+        fprintf(stderr, "Error deleting local seusers\n");
+        return 1;
+    }
+
+    if (semanage_connect(sh) < 0) {
+        fprintf(stderr, "Error deleting local seusers\n");
+        return 1;
+    }
+
+    if (semanage_begin_transaction(sh) < 0) {
+        fprintf(stderr, "Error deleting local seusers\n");
+        return 1;
+    }
+
+    if (semanage_seuser_list_local(sh, &records, &count) < 0) {
+        fprintf(stderr, "Error deleting local seusers\n");
+        return 1;
+    }
+
+    for (unsigned int i = 0; i < count; i++) {
+        if (semanage_seuser_key_extract(sh, records[i], &key) < 0) {
+            fprintf(stderr, "Error deleting local seusers\n");
+            return 1;
+        }
+
+        if (semanage_seuser_del_local(sh, key) < 0) {
+            fprintf(stderr, "Error deleting local seusers\n");
+            return 1;
+        }
+    }
+
+    if (semanage_seuser_count_local(sh, &count) < 0) {
+        fprintf(stderr, "Error deleting local seusers\n");
+        return 1;
+    }
+    
+    if (count != 0) {
+        fprintf(stderr, "Error deleting local seusers\n");
+        return 1;
+    }
+    
+    if (semanage_commit(sh) < 0) {
+        fprintf(stderr, "Error deleting local seusers\n");
+        return 1;
+    }
+
+    if (semanage_disconnect(sh) < 0) {
+        fprintf(stderr, "Error deleting local seusers\n");
+        return 1;
+    }
+
+    semanage_handle_destroy(sh);
+    free(seusers_path1);
+    free(seusers_path2);
+    free(seusers_path3);
+
+	return 0;
+}
+
+int seuser_test_cleanup(void)
+{
+	return 0;
+}
+
+int seuser_add_tests(CU_pSuite suite)
+{
+    CU_add_test(suite, "seuser_key_create",         test_seuser_key_create);
+    CU_add_test(suite, "seuser_key_extract",        test_seuser_key_extract);
+    CU_add_test(suite, "seuser_compare",            test_seuser_compare);
+    CU_add_test(suite, "seuser_compare2",           test_seuser_compare2);
+    CU_add_test(suite, "seuser_get_set_name",       test_seuser_get_set_name);
+    CU_add_test(suite, "seuser_get_set_sename",     test_seuser_get_set_sename);
+    CU_add_test(suite, "seuser_get_set_mlsrange", test_seuser_get_set_mlsrange);
+    CU_add_test(suite, "seuser_clone",              test_seuser_clone);
+    CU_add_test(suite, "seuser_create",             test_seuser_create);
+
+    CU_add_test(suite, "seuser_query",              test_seuser_query);
+    CU_add_test(suite, "seuser_exists",             test_seuser_exists);
+    CU_add_test(suite, "seuser_count",              test_seuser_count);
+    CU_add_test(suite, "seuser_iterate",            test_seuser_iterate);
+    CU_add_test(suite, "seuser_list",               test_seuser_list);
+
+    CU_add_test(suite, "seuser_modify_del_local", test_seuser_modify_del_local);
+    CU_add_test(suite, "seuser_query_local",        test_seuser_query_local);
+    CU_add_test(suite, "seuser_exists_local",       test_seuser_exists_local);
+    CU_add_test(suite, "seuser_count_local",        test_seuser_count_local);
+    CU_add_test(suite, "seuser_iterate_local",      test_seuser_iterate_local);
+    CU_add_test(suite, "seuser_list_local",         test_seuser_list_local);
+     
+	return 0;
+}
+
+// Function seuser_key_create
+
+void helper_seuser_key_create(level_t level) {
+    semanage_seuser_key_t *key = NULL;
+
+    setup_handle(level);
+
+    // name == ""
+    key = NULL;
+
+    CU_ASSERT(semanage_seuser_key_create(sh, "", &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    semanage_seuser_key_free(key);
+
+    // name == "testuser"
+    key = NULL;
+
+    CU_ASSERT(semanage_seuser_key_create(sh, "testuser", &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    semanage_seuser_key_free(key);
+
+    // &key == NULL
+    CU_ASSERT_SIGNAL(semanage_seuser_key_create(sh, "testuser", NULL), SIGSEGV);
+
+    cleanup_handle(level);
+}
+
+void test_seuser_key_create(void) {
+    helper_seuser_key_create(SH_CONNECT);
+    helper_seuser_key_create(SH_TRANS);
+}
+
+// Function seuser_key_extract
+// TODO: make semanage_seuser_key_create return error
+
+#define SK_NULL 1
+#define SK_NEW 2
+#define SK_INDEX 3
+#define SK_KEY_NULL 4
+void helper_seuser_key_extract(level_t level, int mode) {
+    semanage_seuser_t *seuser;
+    semanage_seuser_key_t *key;
+    int result;
+    
+    setup_handle(level);
+
+    switch (mode) {
+        case SK_NULL:
+            seuser = NULL;
+            break;
+        case SK_NEW:
+            seuser = get_seuser_new();
+            break;
+        case SK_INDEX:
+            seuser = get_seuser_nth(0);
+            break;
+        case SK_KEY_NULL:
+            seuser = get_seuser_nth(0);
+            break;
+        default:
+            CU_FAIL_FATAL("Invalid mode\n");
+    }
+
+    if (mode == SK_KEY_NULL)
+        result = semanage_seuser_key_extract(sh, seuser, NULL);
+    else
+        result = semanage_seuser_key_extract(sh, seuser, &key);
+
+    CU_ASSERT(result >= 0);
+
+    result = semanage_seuser_compare(seuser, key);
+
+    CU_ASSERT(result == 0);
+
+    semanage_seuser_key_free(key);
+    semanage_seuser_free(seuser);
+
+    cleanup_handle(level);
+}
+
+void test_seuser_key_extract(void) {
+    CU_ASSERT_SIGNAL(helper_seuser_key_extract(SH_CONNECT, SK_NULL), SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_seuser_key_extract(SH_CONNECT, SK_KEY_NULL),
+                     SIGSEGV);
+
+    // FIXME
+    //helper_seuser_key_extract(SH_CONNECT, SK_NEW);
+    CU_ASSERT_SIGNAL(helper_seuser_key_extract(SH_CONNECT, SK_NEW), SIGSEGV);
+
+    helper_seuser_key_extract(SH_CONNECT, SK_INDEX);
+
+    CU_ASSERT_SIGNAL(helper_seuser_key_extract(SH_TRANS, SK_NULL), SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_seuser_key_extract(SH_TRANS, SK_KEY_NULL), SIGSEGV);
+
+    // FIXME
+    //helper_seuser_key_extract(SH_TRANS, SK_NEW);
+    CU_ASSERT_SIGNAL(helper_seuser_key_extract(SH_TRANS, SK_NEW), SIGSEGV);
+
+    helper_seuser_key_extract(SH_TRANS, SK_INDEX);
+}
+#undef SK_NULL
+#undef SK_NEW
+#undef SK_INDEX
+#undef SK_KEY_NULL
+
+// Function seuser_compare
+
+void helper_seuser_compare(level_t level, int seuser_index1,
+                           int seuser_index2) {
+    semanage_seuser_t *seuser;
+    semanage_seuser_key_t *key;
+    int result;
+
+    setup_handle(level);
+
+    seuser = get_seuser_nth(seuser_index1);
+
+    key = get_seuser_key_nth(seuser_index2);
+
+    result = semanage_seuser_compare(seuser, key);
+
+    if (seuser_index1 == seuser_index2) {
+        CU_ASSERT(result == 0);
+    }
+    else {
+        CU_ASSERT(result != 0);
+    }
+
+    semanage_seuser_free(seuser);
+    semanage_seuser_key_free(key);
+    cleanup_handle(level);
+}
+
+void test_seuser_compare(void) {
+    helper_seuser_compare(SH_CONNECT, I_FIRST,  I_FIRST);
+    helper_seuser_compare(SH_CONNECT, I_FIRST,  I_SECOND);
+    helper_seuser_compare(SH_CONNECT, I_SECOND, I_FIRST);
+    helper_seuser_compare(SH_CONNECT, I_SECOND, I_SECOND);
+
+    CU_ASSERT_SIGNAL(helper_seuser_compare(SH_CONNECT, I_NULL,  I_FIRST),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_seuser_compare(SH_CONNECT, I_FIRST, I_NULL),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_seuser_compare(SH_CONNECT, I_NULL,  I_NULL),
+                     SIGSEGV);
+
+    helper_seuser_compare(SH_TRANS, I_FIRST,  I_FIRST);
+    helper_seuser_compare(SH_TRANS, I_FIRST,  I_SECOND);
+    helper_seuser_compare(SH_TRANS, I_SECOND, I_FIRST);
+    helper_seuser_compare(SH_TRANS, I_SECOND, I_SECOND);
+
+    CU_ASSERT_SIGNAL(helper_seuser_compare(SH_TRANS, I_NULL, I_FIRST), SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_seuser_compare(SH_TRANS, I_FIRST, I_NULL), SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_seuser_compare(SH_TRANS, I_NULL, I_NULL), SIGSEGV);
+}
+
+// Function seuser_compare2
+
+void helper_seuser_compare2(level_t level, int seuser_index1,
+                            int seuser_index2) {
+    semanage_seuser_t *seuser1;
+    semanage_seuser_t *seuser2;
+    int result;
+
+    setup_handle(level);
+
+    seuser1 = get_seuser_nth(seuser_index1);
+    seuser2 = get_seuser_nth(seuser_index2);
+
+    result = semanage_seuser_compare2(seuser1, seuser2);
+
+    if (seuser_index1 == seuser_index2) {
+        CU_ASSERT(result == 0);
+    }
+    else {
+        CU_ASSERT(result != 0);
+    }
+
+    semanage_seuser_free(seuser1);
+    semanage_seuser_free(seuser2);
+
+    cleanup_handle(level);
+}
+
+void test_seuser_compare2(void) {
+    helper_seuser_compare2(SH_CONNECT, I_FIRST,  I_FIRST);
+    helper_seuser_compare2(SH_CONNECT, I_FIRST,  I_SECOND);
+    helper_seuser_compare2(SH_CONNECT, I_SECOND, I_FIRST);
+    helper_seuser_compare2(SH_CONNECT, I_SECOND, I_SECOND);
+
+    CU_ASSERT_SIGNAL(helper_seuser_compare2(SH_CONNECT, I_NULL,  I_FIRST),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_seuser_compare2(SH_CONNECT, I_FIRST, I_NULL),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_seuser_compare2(SH_CONNECT, I_NULL,  I_NULL),
+                     SIGSEGV);
+
+    helper_seuser_compare2(SH_TRANS, I_FIRST,  I_FIRST);
+    helper_seuser_compare2(SH_TRANS, I_FIRST,  I_SECOND);
+    helper_seuser_compare2(SH_TRANS, I_SECOND, I_FIRST);
+    helper_seuser_compare2(SH_TRANS, I_SECOND, I_SECOND);
+
+    CU_ASSERT_SIGNAL(helper_seuser_compare2(SH_TRANS, I_NULL, I_FIRST),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_seuser_compare2(SH_TRANS, I_FIRST, I_NULL),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_seuser_compare2(SH_TRANS, I_NULL, I_NULL),
+                     SIGSEGV);
+}
+
+// Function seuser_get_name, seuser_set_name
+
+void helper_seuser_get_set_name(level_t level, int seuser_index,
+                                const char *name) {
+    semanage_seuser_t *user;
+    const char *new_name = NULL;
+    
+    setup_handle(level);
+
+    user = get_seuser_nth(seuser_index);
+
+    CU_ASSERT(semanage_seuser_set_name(sh, user, name) >= 0);
+
+    new_name = semanage_seuser_get_name(user);
+
+    CU_ASSERT_PTR_NOT_NULL(new_name);
+    CU_ASSERT_STRING_EQUAL(new_name, name);
+
+    semanage_seuser_free(user);
+    cleanup_handle(level);
+}
+
+void test_seuser_get_set_name(void) {
+    CU_ASSERT_SIGNAL(helper_seuser_get_set_name(SH_CONNECT, I_FIRST, NULL),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_seuser_get_set_name(SH_CONNECT, I_NULL, "testuser"),
+                     SIGSEGV);
+
+    helper_seuser_get_set_name(SH_CONNECT, I_FIRST, "testseuser");
+    helper_seuser_get_set_name(SH_CONNECT, I_FIRST, "");
+    helper_seuser_get_set_name(SH_CONNECT, I_SECOND, "testseuser");
+    helper_seuser_get_set_name(SH_CONNECT, I_SECOND, "");
+
+    CU_ASSERT_SIGNAL(helper_seuser_get_set_name(SH_TRANS, I_FIRST, NULL),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_seuser_get_set_name(SH_TRANS, I_NULL, "testuser"),
+                     SIGSEGV);
+
+    helper_seuser_get_set_name(SH_TRANS, I_FIRST, "testseuser");
+    helper_seuser_get_set_name(SH_TRANS, I_FIRST, "");
+    helper_seuser_get_set_name(SH_TRANS, I_SECOND, "testseuser");
+    helper_seuser_get_set_name(SH_TRANS, I_SECOND, "");
+}
+
+// Function seuser_get_sename, seuser_set_sename
+
+void helper_seuser_get_set_sename(level_t level, int seuser_index,
+                                  const char *sename) {
+    semanage_seuser_t *user;
+    const char *old_sename = NULL;
+    const char *new_sename = NULL;
+    
+    setup_handle(level);
+
+    user = get_seuser_nth(seuser_index);
+
+    old_sename = semanage_seuser_get_sename(user);
+
+    CU_ASSERT_PTR_NOT_NULL(old_sename);
+
+    CU_ASSERT(semanage_seuser_set_sename(sh, user, sename) >= 0);
+
+    new_sename = semanage_seuser_get_sename(user);
+
+    CU_ASSERT_PTR_NOT_NULL(new_sename);
+    CU_ASSERT_STRING_EQUAL(new_sename, sename);
+
+    semanage_seuser_free(user);
+    cleanup_handle(level);
+}
+
+void test_seuser_get_set_sename(void) {
+    CU_ASSERT_SIGNAL(helper_seuser_get_set_sename(SH_CONNECT, I_FIRST, NULL),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_seuser_get_set_sename(SH_CONNECT, I_NULL,
+                                                  "testseuser"), SIGSEGV);
+
+    helper_seuser_get_set_sename(SH_CONNECT, I_FIRST,  "testseuser");
+    helper_seuser_get_set_sename(SH_CONNECT, I_FIRST,  "");
+    helper_seuser_get_set_sename(SH_CONNECT, I_SECOND, "testseuser");
+    helper_seuser_get_set_sename(SH_CONNECT, I_SECOND, "");
+
+    CU_ASSERT_SIGNAL(helper_seuser_get_set_sename(SH_TRANS, I_FIRST, NULL),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_seuser_get_set_sename(SH_TRANS, I_NULL,
+                                                  "testseuser"), SIGSEGV);
+
+    helper_seuser_get_set_sename(SH_TRANS, I_FIRST,  "testseuser");
+    helper_seuser_get_set_sename(SH_TRANS, I_FIRST,  "");
+    helper_seuser_get_set_sename(SH_TRANS, I_SECOND, "testseuser");
+    helper_seuser_get_set_sename(SH_TRANS, I_SECOND, "");
+}
+
+// Function seuser_get_mlsrange, seuser_set_mlsrange
+
+void helper_seuser_get_set_mlsrange(level_t level, int seuser_index,
+                                    const char *mlsrange) {
+    semanage_seuser_t *user;
+    const char *old_mlsrange = NULL;
+    const char *new_mlsrange = NULL;
+    
+    setup_handle(level);
+
+    user = get_seuser_nth(seuser_index);
+
+    old_mlsrange = semanage_seuser_get_mlsrange(user);
+
+    CU_ASSERT_PTR_NOT_NULL(old_mlsrange);
+
+    CU_ASSERT(semanage_seuser_set_mlsrange(sh, user, mlsrange) >= 0);
+
+    new_mlsrange = semanage_seuser_get_mlsrange(user);
+
+    CU_ASSERT_PTR_NOT_NULL(new_mlsrange);
+    CU_ASSERT_STRING_EQUAL(new_mlsrange, mlsrange);
+
+    semanage_seuser_free(user);
+    cleanup_handle(level);
+}
+
+void test_seuser_get_set_mlsrange(void) {
+    CU_ASSERT_SIGNAL(helper_seuser_get_set_mlsrange(SH_CONNECT, I_FIRST, NULL),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_seuser_get_set_mlsrange(SH_CONNECT, I_NULL,
+                                                    "testmlsrange"), SIGSEGV);
+
+    helper_seuser_get_set_mlsrange(SH_CONNECT, I_FIRST,  "testmlsrange");
+    helper_seuser_get_set_mlsrange(SH_CONNECT, I_FIRST,  "");
+    helper_seuser_get_set_mlsrange(SH_CONNECT, I_SECOND, "testmlsrange");
+    helper_seuser_get_set_mlsrange(SH_CONNECT, I_SECOND, "");
+
+    CU_ASSERT_SIGNAL(helper_seuser_get_set_mlsrange(SH_TRANS, I_FIRST, NULL),
+                     SIGSEGV);
+    CU_ASSERT_SIGNAL(helper_seuser_get_set_mlsrange(SH_TRANS, I_NULL,
+                                                    "testmlsrange"), SIGSEGV);
+
+    helper_seuser_get_set_mlsrange(SH_TRANS, I_FIRST,  "testmlsrange");
+    helper_seuser_get_set_mlsrange(SH_TRANS, I_FIRST,  "");
+    helper_seuser_get_set_mlsrange(SH_TRANS, I_SECOND, "testmlsrange");
+    helper_seuser_get_set_mlsrange(SH_TRANS, I_SECOND, "");
+}
+
+// Function seuser_create
+
+void helper_seuser_create(level_t level) {
+    semanage_seuser_t *seuser;
+    
+    setup_handle(level);
+
+    CU_ASSERT(semanage_seuser_create(sh, &seuser) >= 0);
+
+    CU_ASSERT_PTR_NULL(semanage_seuser_get_name(seuser));
+    CU_ASSERT_PTR_NULL(semanage_seuser_get_sename(seuser));
+    CU_ASSERT_PTR_NULL(semanage_seuser_get_mlsrange(seuser));
+
+    semanage_seuser_free(seuser);
+    cleanup_handle(level);
+}
+
+void test_seuser_create(void) {
+    // FIXME
+    //CU_ASSERT_SIGNAL(helper_seuser_create(SH_NULL), SIGSEGV);
+    helper_seuser_create(SH_NULL);
+
+    // FIXME
+    //CU_ASSERT_SIGNAL(helper_seuser_create(SH_HANDLE), SIGSEGV);
+    helper_seuser_create(SH_HANDLE);
+
+    helper_seuser_create(SH_CONNECT);
+    helper_seuser_create(SH_TRANS);
+}
+
+// Function seuser_clone
+// TODO: error gotos
+
+void helper_seuser_clone(level_t level, int seuser_index) {
+    semanage_seuser_t *seuser;
+    semanage_seuser_t *seuser_clone;
+    const char *str;
+    const char *str_clone;
+    
+    setup_handle(level);
+
+    seuser = get_seuser_nth(seuser_index);
+
+    CU_ASSERT(semanage_seuser_clone(sh, seuser, &seuser_clone) >= 0);
+
+    str = semanage_seuser_get_name(seuser);
+    str_clone = semanage_seuser_get_name(seuser_clone);
+
+    CU_ASSERT_STRING_EQUAL(str, str_clone);
+
+    str = semanage_seuser_get_sename(seuser);
+    str_clone = semanage_seuser_get_sename(seuser_clone);
+
+    CU_ASSERT_STRING_EQUAL(str, str_clone);
+
+    str = semanage_seuser_get_mlsrange(seuser);
+    str_clone = semanage_seuser_get_mlsrange(seuser_clone);
+
+    CU_ASSERT_STRING_EQUAL(str, str_clone);
+
+    semanage_seuser_free(seuser);
+    semanage_seuser_free(seuser_clone);
+    cleanup_handle(level);
+}
+
+void test_seuser_clone(void) {
+    CU_ASSERT_SIGNAL(helper_seuser_clone(SH_CONNECT, I_NULL), SIGSEGV);
+    helper_seuser_clone(SH_CONNECT, I_FIRST);
+    helper_seuser_clone(SH_CONNECT, I_SECOND);
+
+    CU_ASSERT_SIGNAL(helper_seuser_clone(SH_TRANS, I_NULL), SIGSEGV);
+    helper_seuser_clone(SH_TRANS, I_FIRST);
+    helper_seuser_clone(SH_TRANS, I_SECOND);
+}
+
+// Function seuser_query
+
+void helper_seuser_query(level_t level, const char *seuser_str,
+                         int exp_result) {
+    semanage_seuser_key_t *key;
+    semanage_seuser_t *response;
+    const char *name;
+
+    // setup
+    setup_handle(level);
+
+    key = get_seuser_key_from_str(seuser_str);
+
+    // test
+    if (exp_result < 0) {
+        CU_ASSERT(semanage_seuser_query(sh, key, &response) < 0);
+    }
+    else {
+        CU_ASSERT(semanage_seuser_query(sh, key, &response) >= 0);
+
+        name = semanage_seuser_get_name(response);
+
+        CU_ASSERT_STRING_EQUAL(name, seuser_str);
+    }
+
+    // cleanup
+    semanage_seuser_key_free(key);
+    cleanup_handle(level);
+}
+
+void test_seuser_query(void) {
+    CU_ASSERT_SIGNAL(helper_seuser_query(SH_CONNECT, NULL, -1), SIGSEGV);
+
+    helper_seuser_query(SH_CONNECT, SEUSER,  1);
+    helper_seuser_query(SH_CONNECT, SEUSER2, 1);
+    helper_seuser_query(SH_CONNECT, SEUSER_DEFAULT,      1);
+    helper_seuser_query(SH_CONNECT, SEUSER_NONEXISTENT, -1);
+
+    CU_ASSERT_SIGNAL(helper_seuser_query(SH_TRANS, NULL, -1), SIGSEGV);
+
+    helper_seuser_query(SH_TRANS, SEUSER,  1);
+    helper_seuser_query(SH_TRANS, SEUSER2, 1);
+    helper_seuser_query(SH_TRANS, SEUSER_DEFAULT,      1);
+    helper_seuser_query(SH_TRANS, SEUSER_NONEXISTENT, -1);
+}
+
+// Function seuser_exists
+
+void helper_seuser_exists(level_t level, char * seuser_str, int exp_response) {
+    semanage_seuser_key_t *key;
+    int response;
+
+    setup_handle(level);
+
+    key = get_seuser_key_from_str(seuser_str);
+
+    CU_ASSERT(semanage_seuser_exists(sh, key, &response) >= 0);
+    CU_ASSERT(response == exp_response);
+
+    CU_ASSERT_SIGNAL(semanage_seuser_exists(sh, key, NULL), SIGSEGV);
+
+    semanage_seuser_key_free(key);
+
+    cleanup_handle(level);
+}
+
+void test_seuser_exists(void) {
+    CU_ASSERT_SIGNAL(helper_seuser_exists(SH_CONNECT, NULL, 0), SIGSEGV);
+
+    helper_seuser_exists(SH_CONNECT, SEUSER,  1);
+    helper_seuser_exists(SH_CONNECT, SEUSER2, 1);
+    helper_seuser_exists(SH_CONNECT, SEUSER_DEFAULT,     1);
+    helper_seuser_exists(SH_CONNECT, SEUSER_NONEXISTENT, 0);
+
+    CU_ASSERT_SIGNAL(helper_seuser_exists(SH_TRANS, NULL, 0), SIGSEGV);
+
+    helper_seuser_exists(SH_TRANS, SEUSER,  1);
+    helper_seuser_exists(SH_TRANS, SEUSER2, 1);
+    helper_seuser_exists(SH_TRANS, SEUSER_DEFAULT,     1);
+    helper_seuser_exists(SH_TRANS, SEUSER_NONEXISTENT, 0);
+}
+
+// Function seuser_count
+
+void test_seuser_count(void) {
+    unsigned int response;
+
+    // test without handle
+    CU_ASSERT_SIGNAL(semanage_seuser_count(NULL, &response), SIGSEGV);
+
+    // test with handle
+    setup_handle(SH_HANDLE);
+
+    CU_ASSERT(semanage_seuser_count(sh, &response) < 0);
+
+    CU_ASSERT(semanage_seuser_count(sh, NULL) < 0);
+    
+    // test connected
+    helper_connect();
+
+    CU_ASSERT(semanage_seuser_count(sh, &response) >= 0);
+    CU_ASSERT(response == SEUSERS_COUNT);
+
+    CU_ASSERT_SIGNAL(semanage_seuser_count(sh, NULL), SIGSEGV);
+
+    // test in transaction
+    helper_begin_transaction();
+
+    CU_ASSERT(semanage_seuser_count(sh, &response) >= 0);
+    CU_ASSERT(response == SEUSERS_COUNT);
+
+    CU_ASSERT_SIGNAL(semanage_seuser_count(sh, NULL), SIGSEGV);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function seuser_iterate
+// TODO: compare with entries in file
+// TODO: test argument passing
+
+unsigned int counter_seuser_iterate = 0;
+
+int handler_seuser_iterate(const semanage_seuser_t *record, void *varg) {
+    counter_seuser_iterate++;
+    return 0;
+}
+
+void helper_seuser_iterate_invalid(void) {
+    CU_ASSERT_SIGNAL(semanage_seuser_iterate(NULL, &handler_seuser_iterate,
+                                             NULL), SIGSEGV);
+
+    setup_handle(SH_HANDLE);
+
+    CU_ASSERT(semanage_seuser_iterate(sh, &handler_seuser_iterate, NULL) < 0);
+
+    CU_ASSERT(semanage_seuser_iterate(sh, NULL, NULL) < 0);
+
+    cleanup_handle(SH_HANDLE);
+}
+
+void helper_seuser_iterate(level_t level) {
+    setup_handle(level);
+
+    counter_seuser_iterate = 0;
+
+    CU_ASSERT(semanage_seuser_iterate(sh, &handler_seuser_iterate, NULL) >= 0);
+    CU_ASSERT(counter_seuser_iterate == SEUSERS_COUNT);
+
+    CU_ASSERT_SIGNAL(semanage_seuser_iterate(sh, NULL, NULL), SIGSEGV);
+
+    cleanup_handle(level);
+}
+
+void test_seuser_iterate(void) {
+    helper_seuser_iterate_invalid();
+    helper_seuser_iterate(SH_CONNECT);
+    helper_seuser_iterate(SH_TRANS);
+}
+
+// Function seuser_list
+// TODO: compare with entries in file
+
+void helper_seuser_list_invalid(void) {
+    semanage_seuser_t **records;
+    unsigned int count;
+
+    CU_ASSERT_SIGNAL(semanage_seuser_list(NULL, &records, &count), SIGSEGV);
+
+    setup_handle(SH_HANDLE);
+    
+    CU_ASSERT(semanage_seuser_list(sh, &records, &count) < 0);
+
+    CU_ASSERT(semanage_seuser_list(sh, NULL, &count) < 0);
+    CU_ASSERT(semanage_seuser_list(sh, &records, NULL) < 0);
+
+    cleanup_handle(SH_HANDLE);
+}
+
+void helper_seuser_list(level_t level) {
+    semanage_seuser_t **records;
+    unsigned int count;
+
+    setup_handle(level);
+    
+    CU_ASSERT(semanage_seuser_list(sh, &records, &count) >= 0);
+    CU_ASSERT(count == SEUSERS_COUNT);
+
+    for (unsigned int i = 0; i < count; i++) {
+        CU_ASSERT_PTR_NOT_NULL(records[i]);
+    }
+
+    for (unsigned int i = 0; i < count; i++) {
+        semanage_seuser_free(records[i]);
+    }
+
+    free(records);
+
+    CU_ASSERT_SIGNAL(semanage_seuser_list(sh, NULL, &count), SIGSEGV);
+    CU_ASSERT_SIGNAL(semanage_seuser_list(sh, &records, NULL), SIGSEGV);
+
+    cleanup_handle(level);
+}
+
+void test_seuser_list(void) {
+    helper_seuser_list_invalid();
+    helper_seuser_list(SH_CONNECT);
+    helper_seuser_list(SH_TRANS);
+}
+
+// Function seuser_modify_local, seuser_del_local
+// TODO: make semanage_seuser_get_sename return NULL
+// TODO: make semanage_seuser_clone return error
+// TODO: mls enabled
+// TODO: make semanage_seuser_audit return error
+
+void helper_seuser_modify_del_local(level_t level, int seuser_index,
+                                    int exp_result) {
+    semanage_seuser_t *seuser;
+    semanage_seuser_t *seuser_local;
+    semanage_seuser_key_t *key = NULL;
+    int result;
+
+    setup_handle(level);
+
+    seuser = get_seuser_nth(seuser_index);
+
+    CU_ASSERT(semanage_seuser_key_extract(sh, seuser, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    result = semanage_seuser_modify_local(sh, key, seuser);
+
+    if (exp_result < 0) {
+        CU_ASSERT(result < 0);
+    }
+    else {
+        CU_ASSERT(result >= 0);
+
+        // write changes to file
+        if (level == SH_TRANS) {
+            helper_commit();
+            helper_begin_transaction();
+        }
+
+        CU_ASSERT(semanage_seuser_query_local(sh, key, &seuser_local) >= 0);
+        CU_ASSERT(semanage_seuser_compare2(seuser_local, seuser) == 0);
+
+        CU_ASSERT(semanage_seuser_del_local(sh, key) >= 0);
+
+        CU_ASSERT(semanage_seuser_query_local(sh, key, &seuser_local) < 0);
+    }
+
+#if VERS_CHECK(2, 5)
+    CU_ASSERT_SIGNAL(semanage_seuser_modify_local(sh, NULL, seuser), SIGSEGV);
+    CU_ASSERT_SIGNAL(semanage_seuser_modify_local(sh, key, NULL), SIGSEGV);
+    CU_ASSERT_SIGNAL(semanage_seuser_del_local(sh, NULL), SIGSEGV);
+#endif
+
+    semanage_seuser_key_free(key);
+    semanage_seuser_free(seuser);
+
+    cleanup_handle(level);
+}
+
+void test_seuser_modify_del_local(void) {
+    helper_seuser_modify_del_local(SH_CONNECT, I_FIRST,  -1);
+    helper_seuser_modify_del_local(SH_CONNECT, I_SECOND, -1);
+
+    helper_seuser_modify_del_local(SH_TRANS, I_FIRST,  1);
+    helper_seuser_modify_del_local(SH_TRANS, I_SECOND, 1);
+}
+
+// Function seuser_query_local
+
+void test_seuser_query_local(void) {
+    semanage_seuser_key_t *key = NULL;
+    semanage_seuser_t *response = NULL;
+
+    // connect
+    setup_handle(SH_CONNECT);
+
+    key = get_seuser_key_nth(I_FIRST);
+
+    CU_ASSERT(semanage_seuser_query_local(sh, key, &response) < 0);
+    CU_ASSERT_PTR_NULL(response);
+
+    semanage_seuser_key_free(key);
+    cleanup_handle(SH_CONNECT);
+
+    // transaction
+    setup_handle(SH_TRANS);
+
+    key = get_seuser_key_nth(I_FIRST);
+
+    CU_ASSERT(semanage_seuser_query_local(sh, key, &response) < 0);
+    CU_ASSERT_PTR_NULL(response);
+
+    add_local_seuser(I_FIRST);
+
+    CU_ASSERT(semanage_seuser_query_local(sh, key, &response) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(response);
+
+    semanage_seuser_key_free(key);
+    key = get_seuser_key_nth(I_SECOND);
+
+    add_local_seuser(I_SECOND);
+
+    CU_ASSERT(semanage_seuser_query_local(sh, key, &response) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(response);
+
+    semanage_seuser_key_free(key);
+    delete_local_seuser(I_FIRST);
+    delete_local_seuser(I_SECOND);
+    cleanup_handle(SH_TRANS);
+}
+
+// Function seuser_exists_local
+
+void test_seuser_exists_local(void) {
+    int response = -1;
+    semanage_seuser_key_t *key;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    // test
+    key = get_seuser_key_nth(I_FIRST);
+
+    CU_ASSERT(semanage_seuser_exists_local(sh, key, &response) >= 0);
+    CU_ASSERT(response == 0);
+
+    add_local_seuser(I_FIRST);
+    response = -1;
+
+    CU_ASSERT(semanage_seuser_exists_local(sh, key, &response) >= 0);
+    CU_ASSERT(response == 1);
+
+    delete_local_seuser(I_FIRST);
+    response = -1;
+
+    CU_ASSERT(semanage_seuser_exists_local(sh, key, &response) >= 0);
+    CU_ASSERT(response == 0);
+
+    response = -1;
+
+    CU_ASSERT(semanage_seuser_exists_local(sh, NULL, &response) >= 0);
+    CU_ASSERT(response == 0);
+
+    CU_ASSERT_SIGNAL(semanage_seuser_exists_local(sh, key, NULL), SIGSEGV);
+
+    // cleanup
+    semanage_seuser_key_free(key);
+    cleanup_handle(SH_TRANS);
+}
+
+// Function seuser_count_local
+
+void test_seuser_count_local(void) {
+    unsigned int response;
+
+    // test without handle
+    CU_ASSERT_SIGNAL(semanage_seuser_count_local(NULL, &response), SIGSEGV);
+
+    // test with handle
+    setup_handle(SH_HANDLE);
+
+    CU_ASSERT(semanage_seuser_count_local(sh, &response) < 0);
+
+    // test connected
+    helper_connect();
+
+    CU_ASSERT(semanage_seuser_count_local(sh, &response) >= 0);
+    CU_ASSERT(response == 0);
+
+    CU_ASSERT_SIGNAL(semanage_seuser_count_local(sh, NULL), SIGSEGV);
+
+    // test in transaction
+    helper_begin_transaction();
+    
+    CU_ASSERT(semanage_seuser_count_local(sh, &response) >= 0);
+    CU_ASSERT(response == 0);
+
+    add_local_seuser(I_FIRST);
+
+    CU_ASSERT(semanage_seuser_count_local(sh, &response) >= 0);
+    CU_ASSERT(response == 1);
+
+    add_local_seuser(I_SECOND);
+
+    CU_ASSERT(semanage_seuser_count_local(sh, &response) >= 0);
+    CU_ASSERT(response == 2);
+
+    delete_local_seuser(I_SECOND);
+
+    CU_ASSERT(semanage_seuser_count_local(sh, &response) >= 0);
+    CU_ASSERT(response == 1);
+
+    delete_local_seuser(I_FIRST);
+
+    CU_ASSERT_SIGNAL(semanage_seuser_count_local(sh, NULL), SIGSEGV);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function seuser_iterate_local
+
+unsigned int counter_seuser_iterate_local = 0;
+
+int handler_seuser_iterate_local(const semanage_seuser_t *record, void *varg) {
+    counter_seuser_iterate_local++;
+    return 0;
+}
+
+void test_seuser_iterate_local(void) {
+    // test without handle
+    CU_ASSERT_SIGNAL(semanage_seuser_iterate_local(NULL,
+                                 &handler_seuser_iterate_local, NULL), SIGSEGV);
+
+    // test with handle
+    helper_handle_create();
+
+    CU_ASSERT(semanage_seuser_iterate_local(sh, &handler_seuser_iterate_local,
+                                            NULL) < 0);
+
+    CU_ASSERT(semanage_seuser_iterate_local(sh, NULL, NULL) < 0);
+
+    // test connected
+    helper_connect();
+
+    counter_seuser_iterate_local = 0;
+    CU_ASSERT(semanage_seuser_iterate_local(sh, &handler_seuser_iterate_local,
+                                            NULL) >= 0);
+    CU_ASSERT(counter_seuser_iterate_local == 0);
+
+    // FIXME
+    CU_ASSERT(semanage_seuser_iterate_local(sh, NULL, NULL) >= 0);
+
+    // test in transaction
+    helper_begin_transaction();
+
+    counter_seuser_iterate_local = 0;
+    CU_ASSERT(semanage_seuser_iterate_local(sh, &handler_seuser_iterate_local,
+                                            NULL) >= 0);
+    CU_ASSERT(counter_seuser_iterate_local == 0);
+
+    add_local_seuser(I_FIRST);
+
+    counter_seuser_iterate_local = 0;
+    CU_ASSERT(semanage_seuser_iterate_local(sh, &handler_seuser_iterate_local,
+                                            NULL) >= 0);
+    CU_ASSERT(counter_seuser_iterate_local == 1);
+
+    add_local_seuser(I_SECOND);
+
+    counter_seuser_iterate_local = 0;
+    CU_ASSERT(semanage_seuser_iterate_local(sh, &handler_seuser_iterate_local,
+                                            NULL) >= 0);
+    CU_ASSERT(counter_seuser_iterate_local == 2);
+
+    CU_ASSERT_SIGNAL(semanage_seuser_iterate_local(sh, NULL, NULL), SIGSEGV);
+
+    delete_local_seuser(I_FIRST);
+    delete_local_seuser(I_SECOND);
+    cleanup_handle(SH_TRANS);
+}
+
+// Function seuser_list_local
+
+void test_seuser_list_local(void) {
+    semanage_seuser_t **records;
+    unsigned int count;
+
+    // test without handle
+    CU_ASSERT_SIGNAL(semanage_seuser_list_local(NULL, &records, &count),
+                     SIGSEGV);
+    
+    // test with handle
+    helper_handle_create();
+
+    CU_ASSERT(semanage_seuser_list_local(sh, &records, &count) < 0);
+
+    CU_ASSERT(semanage_seuser_list_local(sh, NULL, &count) < 0);
+    CU_ASSERT(semanage_seuser_list_local(sh, &records, NULL) < 0);
+
+    // test connected
+    helper_connect();
+    
+    CU_ASSERT(semanage_seuser_list_local(sh, &records, &count) >= 0);
+    CU_ASSERT(count == 0);
+
+    CU_ASSERT_SIGNAL(semanage_seuser_list_local(sh, NULL, &count), SIGSEGV);
+    CU_ASSERT_SIGNAL(semanage_seuser_list_local(sh, &records, NULL), SIGSEGV);
+
+    // test in transaction
+    helper_begin_transaction();
+
+    CU_ASSERT(semanage_seuser_list_local(sh, &records, &count) >= 0);
+    CU_ASSERT(count == 0);
+
+    add_local_seuser(I_FIRST);
+    
+    CU_ASSERT(semanage_seuser_list_local(sh, &records, &count) >= 0);
+    CU_ASSERT(count == 1);
+    CU_ASSERT_PTR_NOT_NULL(records[0]);
+
+    add_local_seuser(I_SECOND);
+    
+    CU_ASSERT(semanage_seuser_list_local(sh, &records, &count) >= 0);
+    CU_ASSERT(count == 2);
+    CU_ASSERT_PTR_NOT_NULL(records[0]);
+    CU_ASSERT_PTR_NOT_NULL(records[1]);
+
+    CU_ASSERT_SIGNAL(semanage_seuser_list_local(sh, NULL, &count), SIGSEGV);
+    CU_ASSERT_SIGNAL(semanage_seuser_list_local(sh, &records, NULL), SIGSEGV);
+
+    delete_local_seuser(I_FIRST);
+    delete_local_seuser(I_SECOND);
+    cleanup_handle(SH_TRANS);
+}

diff --git a/libsemanage/sanity-tests/tests/test_seuser.h b/libsemanage/sanity-tests/tests/test_seuser.h
new file mode 100644
index 0000000..448c38b
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_seuser.h
@@ -0,0 +1,40 @@
+#ifndef __TEST_SEUSER_H__
+#define __TEST_SEUSER_H__
+
+#include <CUnit/Basic.h>
+
+int seuser_test_init(void);
+int seuser_test_cleanup(void);
+int seuser_add_tests(CU_pSuite suite);
+
+// seuser_record.h
+
+void test_seuser_key_create(void);
+void test_seuser_key_extract(void);
+void test_seuser_compare(void);
+void test_seuser_compare2(void);
+void test_seuser_get_set_name(void);
+void test_seuser_get_set_sename(void);
+void test_seuser_get_set_mlsrange(void);
+void test_seuser_clone(void);
+void test_seuser_create(void);
+
+// seusers_policy.h
+
+void test_seuser_query(void);
+void test_seuser_exists(void);
+void test_seuser_count(void);
+void test_seuser_iterate(void);
+void test_seuser_list(void);
+
+// seusers_local.h
+
+void test_seuser_modify_del_local(void);
+void test_seuser_query_local(void);
+void test_seuser_exists_local(void);
+void test_seuser_count_local(void);
+void test_seuser_iterate_local(void);
+void test_seuser_list_local(void);
+
+#endif
+

diff --git a/libsemanage/sanity-tests/tests/test_user.c b/libsemanage/sanity-tests/tests/test_user.c
new file mode 100644
index 0000000..56de7bf
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_user.c
@@ -0,0 +1,604 @@
+#include <stdio.h>
+#include <semanage/semanage.h>
+#include <semanage/handle.h>
+#include <CUnit/Basic.h>
+
+#include "test_user.h"
+#include "functions.h"
+
+extern semanage_handle_t *sh;
+
+int user_test_init(void) {
+    return 0;
+}
+
+int user_test_cleanup(void) {
+    return 0;
+}
+
+int user_add_tests(CU_pSuite suite) {
+    CU_add_test(suite, "user_compare", test_user_compare);
+    CU_add_test(suite, "user_compare2", test_user_compare2);
+    CU_add_test(suite, "user_key_create", test_user_key_create);
+    CU_add_test(suite, "user_key_extract", test_user_key_extract);
+    CU_add_test(suite, "user_get_set_name", test_user_get_set_name);
+    CU_add_test(suite, "user_get_set_prefix", test_user_get_set_prefix);
+    CU_add_test(suite, "user_get_set_mlslevel", test_user_get_set_mlslevel);
+    CU_add_test(suite, "user_get_set_mlsrange", test_user_get_set_mlsrange);
+    CU_add_test(suite, "user_roles", test_user_roles);
+    CU_add_test(suite, "user_create", test_user_create);
+    CU_add_test(suite, "user_clone", test_user_clone);
+
+    CU_add_test(suite, "user_query", test_user_query);
+    CU_add_test(suite, "user_exists", test_user_exists);
+    CU_add_test(suite, "user_count", test_user_count);
+    CU_add_test(suite, "user_iterate", test_user_iterate);
+    CU_add_test(suite, "user_list", test_user_list);
+
+    CU_add_test(suite, "user_modify_del_query_local",
+                test_user_modify_del_query_local);
+    CU_add_test(suite, "user_exists_local", test_user_exists_local);
+    CU_add_test(suite, "user_count_local", test_user_count_local);
+    CU_add_test(suite, "user_iterate_local", test_user_iterate_local);
+    CU_add_test(suite, "user_list_local", test_user_list_local);
+
+    return 0;
+}
+
+// Function semanage_user_compare
+
+void test_user_compare(void) {
+    semanage_user_t *user = NULL;
+    semanage_user_key_t *key1 = NULL;
+    semanage_user_key_t *key2 = NULL;
+    int result = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    user = get_user_nth(I_FIRST);
+    key1 = get_user_key_nth(I_FIRST);
+    key2 = get_user_key_nth(I_SECOND);
+
+    // test
+    result = semanage_user_compare(user, key1);
+
+    CU_ASSERT(result == 0);
+
+    result = semanage_user_compare(user, key2);
+
+    CU_ASSERT(result != 0);
+
+    // cleanup
+    semanage_user_free(user);
+    semanage_user_key_free(key1);
+    semanage_user_key_free(key2);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_user_compare2
+
+void test_user_compare2(void) {
+    semanage_user_t *user1 = NULL;
+    semanage_user_t *user2 = NULL;
+    semanage_user_t *user3 = NULL;
+    int result = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    user1 = get_user_nth(I_FIRST);
+    user2 = get_user_nth(I_FIRST);
+    user3 = get_user_nth(I_SECOND);
+
+    // test
+    result = semanage_user_compare2(user1, user2);
+
+    CU_ASSERT(result == 0);
+
+    result = semanage_user_compare2(user1, user3);
+
+    CU_ASSERT(result != 0);
+
+    // cleanup
+    semanage_user_free(user1);
+    semanage_user_free(user2);
+    semanage_user_free(user3);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_user_key_create
+
+void test_user_key_create(void) {
+    semanage_user_key_t *key = NULL;
+
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_user_key_create(sh, "asdf", &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    semanage_user_key_free(key);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_user_key_extract
+
+void test_user_key_extract(void) {
+    semanage_user_t *user = NULL;
+    semanage_user_key_t *key = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    user = get_user_nth(I_FIRST);
+
+    // test
+    CU_ASSERT(semanage_user_key_extract(sh, user, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    // cleanup
+    semanage_user_free(user);
+    semanage_user_key_free(key);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_user_get_name, semanage_user_set_name
+
+void test_user_get_set_name(void) {
+    semanage_user_t *user = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_user_create(sh, &user) >= 0);
+
+    // test
+    CU_ASSERT(semanage_user_set_name(sh, user, "user_u") == 0);
+    CU_ASSERT_STRING_EQUAL(semanage_user_get_name(user), "user_u");
+
+    // cleanup
+    semanage_user_free(user);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_user_get_prefix, semanage_user_set_prefix
+
+void test_user_get_set_prefix(void) {
+    semanage_user_t *user = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_user_create(sh, &user) >= 0);
+
+    // test
+    CU_ASSERT(semanage_user_set_prefix(sh, user, "user") == 0);
+    CU_ASSERT_STRING_EQUAL(semanage_user_get_prefix(user), "user");
+
+    // cleanup
+    semanage_user_free(user);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_user_get_mlslevel, semanage_user_set_mlslevel
+
+void test_user_get_set_mlslevel(void) {
+    semanage_user_t *user = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_user_create(sh, &user) >= 0);
+
+    // test
+    CU_ASSERT(semanage_user_set_mlslevel(sh, user, "s0") == 0);
+    CU_ASSERT_STRING_EQUAL(semanage_user_get_mlslevel(user), "s0");
+
+    // cleanup
+    semanage_user_free(user);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_user_get_mlsrange, semanage_user_set_mlsrange
+
+void test_user_get_set_mlsrange(void) {
+    semanage_user_t *user = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_user_create(sh, &user) >= 0);
+
+    // test
+    CU_ASSERT(semanage_user_set_mlsrange(sh, user, "s0-s15") == 0);
+    CU_ASSERT_STRING_EQUAL(semanage_user_get_mlsrange(user), "s0-s15");
+
+    // cleanup
+    semanage_user_free(user);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_user_get_num_roles, semanage_user_add_role,
+// semanage_user_del_role, semanage_user_has_role, semanage_user_get_roles
+// semanage_user_set_roles
+
+void test_user_roles(void) {
+    semanage_user_t *user = NULL;
+    const char **roles_arr = NULL;
+    unsigned int num_roles = 42;
+    const char *new_roles_arr[] = { "new_role_r", "new_my_role_r" };
+    unsigned int new_num_roles = 2;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_user_create(sh, &user) >= 0);
+
+    // test
+    CU_ASSERT(semanage_user_get_num_roles(user) == 0);
+
+    CU_ASSERT(semanage_user_add_role(sh, user, "role_r") == 0);
+    CU_ASSERT(semanage_user_get_num_roles(user) == 1);
+
+    CU_ASSERT(semanage_user_has_role(user, "role_r"));
+    CU_ASSERT(!semanage_user_has_role(user, "my_role_r"));
+
+    CU_ASSERT(semanage_user_add_role(sh, user, "my_role_r") == 0);
+    CU_ASSERT(semanage_user_get_num_roles(user) == 2);
+
+    CU_ASSERT(semanage_user_get_roles(sh, user, &roles_arr, &num_roles) >= 0);
+    CU_ASSERT(num_roles == 2);
+    CU_ASSERT_STRING_EQUAL(roles_arr[0], "role_r");
+    CU_ASSERT_STRING_EQUAL(roles_arr[1], "my_role_r");
+
+    CU_ASSERT(semanage_user_set_roles(sh, user, new_roles_arr,
+                                      new_num_roles) >= 0);
+
+    CU_ASSERT(semanage_user_has_role(user, "new_role_r"));
+    CU_ASSERT(semanage_user_has_role(user, "new_my_role_r"));
+
+    CU_ASSERT(!semanage_user_has_role(user, "role_r"));
+    CU_ASSERT(!semanage_user_has_role(user, "my_role_r"));
+
+    semanage_user_del_role(user, "new_my_role_r");
+    CU_ASSERT(semanage_user_get_num_roles(user) == 1);
+
+    semanage_user_del_role(user, "new_role_r");
+    CU_ASSERT(semanage_user_get_num_roles(user) == 0);
+
+    // cleanup
+    semanage_user_free(user);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_user_create
+
+void test_user_create(void) {
+    semanage_user_t *user = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    // test
+    CU_ASSERT(semanage_user_create(sh, &user) >= 0);
+
+    CU_ASSERT(semanage_user_set_name(sh, user, "user_u") >= 0);
+    CU_ASSERT(semanage_user_set_prefix(sh, user, "user") >= 0);
+    CU_ASSERT(semanage_user_set_mlslevel(sh, user, "s0") >= 0);
+    CU_ASSERT(semanage_user_set_mlsrange(sh, user, "s0-s15") >= 0);
+
+    // cleanup
+    semanage_user_free(user);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_user_clone
+
+void test_user_clone(void) {
+    semanage_user_t *user = NULL;
+    semanage_user_t *user_clone = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    CU_ASSERT(semanage_user_create(sh, &user) >= 0);
+
+    CU_ASSERT(semanage_user_set_name(sh, user, "user_u") >= 0);
+    CU_ASSERT(semanage_user_set_prefix(sh, user, "user") >= 0);
+    CU_ASSERT(semanage_user_set_mlslevel(sh, user, "s0") >= 0);
+    CU_ASSERT(semanage_user_set_mlsrange(sh, user, "s0-s15") >= 0);
+
+    // test
+    CU_ASSERT(semanage_user_clone(sh, user, &user_clone) >= 0);
+
+    CU_ASSERT_STRING_EQUAL(semanage_user_get_name(user), "user_u");
+    CU_ASSERT_STRING_EQUAL(semanage_user_get_prefix(user), "user");
+    CU_ASSERT_STRING_EQUAL(semanage_user_get_mlslevel(user), "s0");
+    CU_ASSERT_STRING_EQUAL(semanage_user_get_mlsrange(user), "s0-s15");
+
+    // cleanup
+    semanage_user_free(user);
+    semanage_user_free(user_clone);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_user_query
+
+void test_user_query(void) {
+    semanage_user_t *user = NULL;
+    semanage_user_key_t *key = NULL;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    key = get_user_key_nth(I_FIRST);
+
+    // test
+    CU_ASSERT(semanage_user_query(sh, key, &user) >= 0);
+
+    // TODO: test values
+    CU_ASSERT_PTR_NOT_NULL(user);
+
+    // cleanup
+    semanage_user_free(user);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_user_exists
+
+void test_user_exists(void) {
+    semanage_user_key_t *key1 = NULL;
+    semanage_user_key_t *key2 = NULL;
+    int response = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    key1 = get_user_key_nth(I_FIRST);
+    
+    CU_ASSERT(semanage_user_key_create(sh, "asdf", &key2) >= 0);
+
+    // test
+    CU_ASSERT(semanage_user_exists(sh, key1, &response) >= 0);
+
+    CU_ASSERT(response);
+
+    CU_ASSERT(semanage_user_exists(sh, key2, &response) >= 0);
+
+    CU_ASSERT(!response);
+
+    // cleanup
+    semanage_user_key_free(key1);
+    semanage_user_key_free(key2);
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_user_count
+
+void test_user_count(void) {
+    unsigned int count = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    // test
+    CU_ASSERT(semanage_user_count(sh, &count) >= 0);
+    
+    // TODO: check real count
+    CU_ASSERT(count > 0);
+
+    // cleanup
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_user_iterate
+
+unsigned int counter_user_iterate = 0;
+
+int handler_user_iterate(const semanage_user_t *record, void *varg) {
+    counter_user_iterate++;
+    return 0;
+}
+
+void test_user_iterate(void) {
+    // setup
+    setup_handle(SH_CONNECT);
+
+    // test
+    semanage_user_iterate(sh, handler_user_iterate, NULL);
+
+    // TODO: check real count
+    CU_ASSERT(counter_user_iterate > 0);
+
+    // cleanup
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_user_list
+
+void test_user_list(void) {
+    semanage_user_t **records = NULL;
+    unsigned int count = 42;
+
+    // setup
+    setup_handle(SH_CONNECT);
+
+    // test
+    CU_ASSERT(semanage_user_list(sh, &records, &count) >= 0);
+
+    // TODO: check real count
+    CU_ASSERT(count > 0);
+
+    // TODO: check real values
+    for (unsigned int i = 0; i < count; i++) {
+        CU_ASSERT_PTR_NOT_NULL(records[i]);
+    }
+
+    for (unsigned int i = 0; i < count; i++) {
+        semanage_user_free(records[i]);
+    }
+
+    // cleanup
+    cleanup_handle(SH_CONNECT);
+}
+
+// Function semanage_user_modify_local, semanage_user_del_local,
+// semanage_user_query_local
+
+void test_user_modify_del_query_local(void) {
+    semanage_user_t *user;
+    semanage_user_t *user_local;
+    semanage_user_key_t *key = NULL;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    user = get_user_nth(I_FIRST);
+
+    CU_ASSERT(semanage_user_key_extract(sh, user, &key) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key);
+
+    // test
+    CU_ASSERT(semanage_user_modify_local(sh, key, user) >= 0);
+
+    // write changes to file
+    helper_commit();
+    helper_begin_transaction();
+
+    CU_ASSERT(semanage_user_query_local(sh, key, &user_local) >= 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(user_local);
+
+    CU_ASSERT(semanage_user_del_local(sh, key) >= 0);
+
+    CU_ASSERT(semanage_user_query_local(sh, key, &user_local) < 0);
+
+    // cleanup
+    semanage_user_free(user);
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_user_exists_local
+
+void test_user_exists_local(void) {
+    semanage_user_t *user = NULL;
+    semanage_user_key_t *key1 = NULL;
+    semanage_user_key_t *key2 = NULL;
+    int response = 42;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    add_local_user(I_FIRST);
+
+    key1 = get_user_key_nth(I_FIRST);
+
+    CU_ASSERT(semanage_user_key_create(sh, "asdf", &key2) >= 0);
+    CU_ASSERT_PTR_NOT_NULL(key2);
+
+    // test existing
+    CU_ASSERT(semanage_user_exists_local(sh, key1, &response) >= 0);
+
+    CU_ASSERT(response);
+
+    // test nonexistent
+    CU_ASSERT(semanage_user_exists_local(sh, key2, &response) >= 0);
+
+    CU_ASSERT(!response);
+
+    // cleanup
+    CU_ASSERT(semanage_user_del_local(sh, key1) >= 0);
+    semanage_user_free(user);
+    semanage_user_key_free(key1);
+    semanage_user_key_free(key2);
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_user_count_local
+
+void test_user_count_local(void) {
+    unsigned int count = 42;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    add_local_user(I_FIRST);
+    add_local_user(I_SECOND);
+    add_local_user(I_THIRD);
+
+    // test
+    CU_ASSERT(semanage_user_count_local(sh, &count) >= 0);
+
+    CU_ASSERT(count == 3);
+
+    // cleanup
+    delete_local_user(I_FIRST);
+    delete_local_user(I_SECOND);
+    delete_local_user(I_THIRD);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_user_iterate_local
+
+unsigned int counter_user_iterate_local = 0;
+
+int handler_user_iterate_local(const semanage_user_t *record, void *varg) {
+    counter_user_iterate_local++;
+    return 0;
+}
+
+void test_user_iterate_local(void) {
+    // setup
+    setup_handle(SH_TRANS);
+
+    add_local_user(I_FIRST);
+    add_local_user(I_SECOND);
+    add_local_user(I_THIRD);
+
+    // test
+    semanage_user_iterate_local(sh, handler_user_iterate_local, NULL);
+
+    CU_ASSERT(counter_user_iterate_local == 3);
+
+    // cleanup
+    delete_local_user(I_FIRST);
+    delete_local_user(I_SECOND);
+    delete_local_user(I_THIRD);
+
+    cleanup_handle(SH_TRANS);
+}
+
+// Function semanage_user_list_local
+
+void test_user_list_local(void) {
+    semanage_user_t **records = NULL;
+    unsigned int count = 42;
+
+    // setup
+    setup_handle(SH_TRANS);
+
+    add_local_user(I_FIRST);
+    add_local_user(I_SECOND);
+    add_local_user(I_THIRD);
+
+    // test
+    CU_ASSERT(semanage_user_list_local(sh, &records, &count) >= 0);
+
+    CU_ASSERT(count == 3);
+
+    for (unsigned int i = 0; i < count; i++) {
+        CU_ASSERT_PTR_NOT_NULL(records[i]);
+    }
+
+    // cleanup
+    for (unsigned int i = 0; i < count; i++) {
+        semanage_user_free(records[i]);
+    }
+
+    delete_local_user(I_FIRST);
+    delete_local_user(I_SECOND);
+    delete_local_user(I_THIRD);
+
+    cleanup_handle(SH_TRANS);
+}
+

diff --git a/libsemanage/sanity-tests/tests/test_user.h b/libsemanage/sanity-tests/tests/test_user.h
new file mode 100644
index 0000000..62c374b
--- /dev/null
+++ b/libsemanage/sanity-tests/tests/test_user.h
@@ -0,0 +1,41 @@
+#ifndef __TEST_USER_H__
+#define __TEST_USER_H__
+
+#include <CUnit/Basic.h>
+
+int user_test_init(void);
+int user_test_cleanup(void);
+int user_add_tests(CU_pSuite suite);
+
+// user_record.h
+
+void test_user_compare(void);
+void test_user_compare2(void);
+void test_user_key_create(void);
+void test_user_key_extract(void);
+void test_user_get_set_name(void);
+void test_user_get_set_prefix(void);
+void test_user_get_set_mlslevel(void);
+void test_user_get_set_mlsrange(void);
+void test_user_roles(void);
+void test_user_create(void);
+void test_user_clone(void);
+
+// users_policy.h
+
+void test_user_query(void);
+void test_user_exists(void);
+void test_user_count(void);
+void test_user_iterate(void);
+void test_user_list(void);
+
+// users_local.h
+
+void test_user_modify_del_query_local(void);
+void test_user_exists_local(void);
+void test_user_count_local(void);
+void test_user_iterate_local(void);
+void test_user_list_local(void);
+
+#endif
+

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-09-11 13:17 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-11 13:17 [tests/selinux] pr775-checkpolicy-revdeps: Add libsemanage sanity test Jan Zarsky

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox