svn commit: r256751 - in projects/zfsd/head/cddl/sbin/zfsd: . tests
Alan Somers
asomers at FreeBSD.org
Fri Oct 18 17:43:50 UTC 2013
Author: asomers
Date: Fri Oct 18 17:43:48 2013
New Revision: 256751
URL: http://svnweb.freebsd.org/changeset/base/256751
Log:
Add the zfsd unit tests. They require googletest and googlemock from ports.
cddl/sbin/zfsd/tests
cddl/sbin/zfsd/tests/libmocks.c
cddl/sbin/zfsd/tests/zfsd_unittest.cc
cddl/sbin/zfsd/tests/libmocks.h
cddl/sbin/zfsd/tests/Makefile
Add the zfsd unit tests.
cddl/sbin/zfsd/tests/zfsd_unittest.supp
Add a valgrind suppression file.
cddl/sbin/zfsd/tests/zfsd_test.sh
An ATF test program that runs the unit tests
cddl/sbin/zfsd/Makefile.common
Modify Makefile.common so that it can be used either to build zfsd
or zfsd's unit tests.
cddl/sbin/zfsd/Makefile
Don't descend into the tests directory if googletest and googlemock
are not installed, even if MK_TESTS=yes
Submitted by: asomers
Approved by: ken (mentor)
Sponsored by: Spectra Logic Corporation
Added:
projects/zfsd/head/cddl/sbin/zfsd/tests/
projects/zfsd/head/cddl/sbin/zfsd/tests/Makefile
projects/zfsd/head/cddl/sbin/zfsd/tests/libmocks.c
projects/zfsd/head/cddl/sbin/zfsd/tests/libmocks.h
projects/zfsd/head/cddl/sbin/zfsd/tests/zfsd_test.sh
projects/zfsd/head/cddl/sbin/zfsd/tests/zfsd_unittest.cc
projects/zfsd/head/cddl/sbin/zfsd/tests/zfsd_unittest.supp
Modified:
projects/zfsd/head/cddl/sbin/zfsd/Makefile
projects/zfsd/head/cddl/sbin/zfsd/Makefile.common
Modified: projects/zfsd/head/cddl/sbin/zfsd/Makefile
==============================================================================
--- projects/zfsd/head/cddl/sbin/zfsd/Makefile Fri Oct 18 17:38:57 2013 (r256750)
+++ projects/zfsd/head/cddl/sbin/zfsd/Makefile Fri Oct 18 17:43:48 2013 (r256751)
@@ -1,7 +1,15 @@
# $FreeBSD$
+SRCDIR=${.CURDIR}/../../..
.include "Makefile.common"
PROG_CXX= zfsd
.include <bsd.prog.mk>
+
+# Check for the existence of the googletest and googlemock header files, which
+# come from ports. Don't compile the tests without them.
+.if exists(${LOCALBASE}/include/gtest/gtest.h) && exists(${LOCALBASE}/include/gmock/gmock.h)
+.else
+SUBDIR=
+.endif
Modified: projects/zfsd/head/cddl/sbin/zfsd/Makefile.common
==============================================================================
--- projects/zfsd/head/cddl/sbin/zfsd/Makefile.common Fri Oct 18 17:38:57 2013 (r256750)
+++ projects/zfsd/head/cddl/sbin/zfsd/Makefile.common Fri Oct 18 17:43:48 2013 (r256751)
@@ -17,19 +17,19 @@ WARNS?= 3
# Ignore warnings about Solaris specific pragmas.
IGNORE_PRAGMA= YES
-INCFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzpool/common
-INCFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/include
-INCFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/lib/libumem
-INCFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris
-INCFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/head
-INCFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libuutil/common
-INCFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libumem/common
-INCFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs/common
-INCFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libnvpair
-INCFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/zfs
-INCFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common
-INCFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/fs/zfs
-INCFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/sys
+INCFLAGS+= -I${SRCDIR}/cddl/contrib/opensolaris/lib/libzpool/common
+INCFLAGS+= -I${SRCDIR}/cddl/compat/opensolaris/include
+INCFLAGS+= -I${SRCDIR}/cddl/compat/opensolaris/lib/libumem
+INCFLAGS+= -I${SRCDIR}/sys/cddl/compat/opensolaris
+INCFLAGS+= -I${SRCDIR}/cddl/contrib/opensolaris/head
+INCFLAGS+= -I${SRCDIR}/cddl/contrib/opensolaris/lib/libuutil/common
+INCFLAGS+= -I${SRCDIR}/cddl/contrib/opensolaris/lib/libumem/common
+INCFLAGS+= -I${SRCDIR}/cddl/contrib/opensolaris/lib/libzfs/common
+INCFLAGS+= -I${SRCDIR}/cddl/contrib/opensolaris/lib/libnvpair
+INCFLAGS+= -I${SRCDIR}/sys/cddl/contrib/opensolaris/common/zfs
+INCFLAGS+= -I${SRCDIR}/sys/cddl/contrib/opensolaris/uts/common
+INCFLAGS+= -I${SRCDIR}/sys/cddl/contrib/opensolaris/uts/common/fs/zfs
+INCFLAGS+= -I${SRCDIR}/sys/cddl/contrib/opensolaris/uts/common/sys
CFLAGS= -g -DNEED_SOLARIS_BOOLEAN ${INCFLAGS}
Added: projects/zfsd/head/cddl/sbin/zfsd/tests/Makefile
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/zfsd/head/cddl/sbin/zfsd/tests/Makefile Fri Oct 18 17:43:48 2013 (r256751)
@@ -0,0 +1,83 @@
+# $FreeBSD$
+
+SRCDIR=${.CURDIR}/../../../..
+.include "${.CURDIR}/../Makefile.common"
+.PATH: ${.CURDIR}/..
+
+PROG_CXX= zfsd_unittest
+SRCS:= ${SRCS:Nzfsd_main.cc}
+SRCS+= libmocks.c zfsd_unittest.cc
+CLEANFILES+= *.gcno *.gcda *.info
+CLEANDIRS+= lcov-report
+
+# Use #include <zfsd/xxx.h> in test programs.
+INCFLAGS+= -I ${.CURDIR}/../..
+
+.if defined(DESTDIR)
+INCFLAGS+= -I ${DESTDIR}/usr/include
+LIBRARY_PATH= ${DESTDIR}/lib:${DESTDIR}/usr/lib
+LDFLAGS+= -L ${DESTDIR}/lib -L ${DESTDIR}/usr/lib
+.elif defined(WORLDTMP)
+INCFLAGS+= -I ${WORLDTMP}/usr/include
+LIBRARY_PATH= ${WORLDTMP}/lib:${WORLDTMP}/usr/lib
+LDFLAGS+= -L ${WORLDTMP}/lib -L ${WORLDTMP}/usr/lib
+.else
+LIBRARY_PATH=
+.endif
+ZFSD_UNITTEST= env LD_LIBRARY_PATH=${LIBRARY_PATH} ./zfsd_unittest
+
+# Extra tools
+LCOV= lcov
+
+# Googletest options
+LOCALBASE?= /usr/local
+INCFLAGS+= -I ${LOCALBASE}/include -D_THREAD_SAFE -pthread
+LDFLAGS+= -L ${LOCALBASE}/lib -D_THREAD_SAFE -pthread
+LDADD+= ${LOCALBASE}/lib/libgtest.a
+
+# GoogleMock options
+LDADD+= ${LOCALBASE}/lib/libgmock.a ${LOCALBASE}/lib/libgmock_main.a
+
+# Googlemock fails if we don't have this line
+# https://groups.google.com/forum/#!msg/googletestframework/h8ixEPCFm0o/amwfu4xGJb0J
+CFLAGS+= -DGTEST_HAS_PTHREAD
+
+# GCOV options
+CFLAGS+= -fprofile-arcs -ftest-coverage
+LDADD+= -lgcov
+
+all: tests
+
+# Install the tests
+TESTSBASE?= /usr/tests
+TESTSDIR= ${TESTSBASE}/zfsd
+# TODO: Convert from an ATF SH test to a Kyua plain test
+# Long term TODO: Convert to a Kyua googletest test
+TESTS_SH+= zfsd_test
+BINDIR= ${TESTSDIR}
+
+# Install the gcov annotation files too
+FILESDIR= ${TESTSDIR}
+GCNOS= ${SRCS:C/.c+$/.gcno/}
+${GCNOS}: ${SRCS:C/.c+$/.o/}
+FILES= ${GCNOS}
+
+
+# Run the tests and produce the coverage report
+EXCLUDE_PATTERNS='/usr/include/*' '${LOCALBASE}/include/*'
+EXCLUDE_PATTERNS+= '*/cddl/compat/opensolaris/include/*'
+EXCLUDE_PATTERNS+= '*/tools/regression/zfsd/*'
+.PHONY: tests
+tests: zfsd_unittest
+ ${ZFSD_UNITTEST} --gmock_verbose=error
+
+.PHONY: lcov
+lcov: zfsd_unittest
+ ${LCOV} -z -d . -f && \
+ ${ZFSD_UNITTEST} --gmock_verbose=error
+ ${LCOV} -f -d . -c -o default.info && \
+ ${LCOV} -r default.info $(EXCLUDE_PATTERNS) -o trimmed.info && \
+ mkdir -p lcov-report && \
+ genhtml -o lcov-report trimmed.info
+
+.include <atf.test.mk>
Added: projects/zfsd/head/cddl/sbin/zfsd/tests/libmocks.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/zfsd/head/cddl/sbin/zfsd/tests/libmocks.c Fri Oct 18 17:43:48 2013 (r256751)
@@ -0,0 +1,24 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include "libmocks.h"
+
+/*
+ * This file mocks shared library functions that are used by zfsd. Every
+ * function present will be used for all tests in all test suites instead of the
+ * normal function.
+ */
+
+int syslog_last_priority;
+char syslog_last_message[4096];
+void syslog(int priority, const char* message, ...) {
+ va_list ap;
+
+ syslog_last_priority = priority;
+ va_start(ap, message);
+ vsnprintf(syslog_last_message, 4096, message, ap);
+ va_end(ap);
+}
+
+int zpool_iter(libzfs_handle_t* handle, zpool_iter_f iter, void* arg) {
+ return (0);
+}
Added: projects/zfsd/head/cddl/sbin/zfsd/tests/libmocks.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/zfsd/head/cddl/sbin/zfsd/tests/libmocks.h Fri Oct 18 17:43:48 2013 (r256751)
@@ -0,0 +1,24 @@
+#ifndef _LIBMOCKS_H_
+#define _LIBMOCKS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct libzfs_handle;
+typedef struct libzfs_handle libzfs_handle_t;
+struct zpool_handle;
+typedef struct zpool_handle zpool_handle_t;
+typedef int (*zpool_iter_f)(zpool_handle_t *, void *);
+
+void syslog(int priority, const char* message, ...);
+int zpool_iter(libzfs_handle_t*, zpool_iter_f, void*);
+
+extern int syslog_last_priority;
+extern char syslog_last_message[4096];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Added: projects/zfsd/head/cddl/sbin/zfsd/tests/zfsd_test.sh
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/zfsd/head/cddl/sbin/zfsd/tests/zfsd_test.sh Fri Oct 18 17:43:48 2013 (r256751)
@@ -0,0 +1,52 @@
+# Copyright (c) 2013 Spectra Logic Corporation
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions, and the following disclaimer,
+# without modification.
+# 2. Redistributions in binary form must reproduce at minimum a disclaimer
+# substantially similar to the "NO WARRANTY" disclaimer below
+# ("Disclaimer") and any redistribution must be conditioned upon
+# including a substantially similar Disclaimer requirement for further
+# binary redistribution.
+#
+# NO WARRANTY
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGES.
+#
+# Authors: Alan Somers (Spectra Logic Corporation)
+#
+# $FreeBSD$
+
+#
+# Test Case: zfsd_unittest
+# TODO: get coverage in cleanup
+#
+atf_test_case zfsd_unittest
+zfsd_unittest_head()
+{
+ atf_set "descr" "Run zfsd unit tests"
+}
+
+
+zfsd_unittest_body()
+{
+ atf_check -s exit:0 -o ignore -e ignore $(atf_get_srcdir)/zfsd_unittest
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case zfsd_unittest
+}
Added: projects/zfsd/head/cddl/sbin/zfsd/tests/zfsd_unittest.cc
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/zfsd/head/cddl/sbin/zfsd/tests/zfsd_unittest.cc Fri Oct 18 17:43:48 2013 (r256751)
@@ -0,0 +1,778 @@
+/*-
+ * Copyright (c) 2012, 2013 Spectra Logic Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * Authors: Alan Somers (Spectra Logic Corporation)
+ */
+#include <sys/cdefs.h>
+
+#include <stdarg.h>
+#include <syslog.h>
+
+#include <libnvpair.h>
+#include <libzfs.h>
+
+#include <list>
+#include <map>
+#include <sstream>
+#include <string>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <devctl/guid.h>
+#include <devctl/event.h>
+#include <devctl/event_buffer.h>
+#include <devctl/event_factory.h>
+#include <devctl/exception.h>
+#include <devctl/consumer.h>
+#include <devctl/reader.h>
+
+#include <zfsd/callout.h>
+#include <zfsd/vdev_iterator.h>
+#include <zfsd/zfsd_event.h>
+#include <zfsd/case_file.h>
+#include <zfsd/vdev.h>
+#include <zfsd/zfsd.h>
+#include <zfsd/zfsd_exception.h>
+#include <zfsd/zpool_list.h>
+
+#include "libmocks.h"
+
+__FBSDID("$FreeBSD$");
+
+/*================================== Macros ==================================*/
+#define NUM_ELEMENTS(x) (sizeof(x) / sizeof(*x))
+
+/*============================ Namespace Control =============================*/
+using std::string;
+using std::stringstream;
+
+using DevCtl::Event;
+using DevCtl::EventBuffer;
+using DevCtl::EventFactory;
+using DevCtl::EventList;
+using DevCtl::Guid;
+using DevCtl::NVPairMap;
+
+/* redefine zpool_handle here because libzfs_impl.h is not includable */
+struct zpool_handle
+{
+ libzfs_handle_t *zpool_hdl;
+ zpool_handle_t *zpool_next;
+ char zpool_name[ZPOOL_MAXNAMELEN];
+ int zpool_state;
+ size_t zpool_config_size;
+ nvlist_t *zpool_config;
+ nvlist_t *zpool_old_config;
+ nvlist_t *zpool_props;
+ diskaddr_t zpool_start_block;
+};
+
+class MockZfsEvent : public ZfsEvent
+{
+public:
+ MockZfsEvent(Event::Type, NVPairMap&, const string&);
+ virtual ~MockZfsEvent() {}
+
+ static BuildMethod MockZfsEventBuilder;
+
+ MOCK_CONST_METHOD0(ProcessPoolEvent, void());
+
+ static EventFactory::Record s_buildRecords[];
+};
+
+EventFactory::Record MockZfsEvent::s_buildRecords[] =
+{
+ { Event::NOTIFY, "ZFS", &MockZfsEvent::MockZfsEventBuilder }
+};
+
+MockZfsEvent::MockZfsEvent(Event::Type type, NVPairMap& map,
+ const string& str)
+ : ZfsEvent(type, map, str)
+{
+}
+
+Event *
+MockZfsEvent::MockZfsEventBuilder(Event::Type type,
+ NVPairMap &nvpairs,
+ const string &eventString)
+{
+ return (new MockZfsEvent(type, nvpairs, eventString));
+}
+
+/*
+ * A dummy Vdev class used for testing other classes
+ */
+class MockVdev : public Vdev
+{
+public:
+ MockVdev(nvlist_t *vdevConfig);
+ virtual ~MockVdev() {}
+
+ MOCK_CONST_METHOD0(GUID, Guid());
+ MOCK_CONST_METHOD0(PoolGUID, Guid());
+ MOCK_CONST_METHOD0(State, vdev_state());
+ MOCK_CONST_METHOD0(PhysicalPath, string());
+};
+
+MockVdev::MockVdev(nvlist_t *vdevConfig)
+ : Vdev(vdevConfig)
+{
+}
+
+/*
+ * A CaseFile class with side effects removed, for testing
+ */
+class TestableCaseFile : public CaseFile
+{
+public:
+ static TestableCaseFile &Create(Vdev &vdev);
+ TestableCaseFile(Vdev &vdev);
+ virtual ~TestableCaseFile() {}
+
+ MOCK_METHOD0(Close, void());
+ MOCK_METHOD1(RegisterCallout, void(const Event &event));
+ MOCK_METHOD0(RefreshVdevState, bool());
+ MOCK_METHOD1(ReEvaluate, bool(const ZfsEvent &event));
+
+ bool RealReEvaluate(const ZfsEvent &event)
+ {
+ return (CaseFile::ReEvaluate(event));
+ }
+
+ /*
+ * This splices the event lists, a procedure that would normally be done
+ * by OnGracePeriodEnded, but we don't necessarily call that in the
+ * unit tests
+ */
+ void SpliceEvents();
+
+ /*
+ * Used by some of our expectations. CaseFile does not publicize this
+ */
+ static int getActiveCases()
+ {
+ return (s_activeCases.size());
+ }
+};
+
+TestableCaseFile::TestableCaseFile(Vdev &vdev)
+ : CaseFile(vdev)
+{
+}
+
+TestableCaseFile &
+TestableCaseFile::Create(Vdev &vdev)
+{
+ TestableCaseFile *newCase;
+ newCase = new TestableCaseFile(vdev);
+ return (*newCase);
+}
+
+void
+TestableCaseFile::SpliceEvents()
+{
+ m_events.splice(m_events.begin(), m_tentativeEvents);
+}
+
+
+/*
+ * Test class ZfsdException
+ */
+class ZfsdExceptionTest : public ::testing::Test
+{
+protected:
+ virtual void SetUp()
+ {
+ ASSERT_EQ(0, nvlist_alloc(&poolConfig, NV_UNIQUE_NAME, 0));
+ ASSERT_EQ(0, nvlist_add_string(poolConfig,
+ ZPOOL_CONFIG_POOL_NAME, "unit_test_pool"));
+ ASSERT_EQ(0, nvlist_add_uint64(poolConfig,
+ ZPOOL_CONFIG_POOL_GUID, 0x1234));
+
+ ASSERT_EQ(0, nvlist_alloc(&vdevConfig, NV_UNIQUE_NAME, 0));
+ ASSERT_EQ(0, nvlist_add_uint64(vdevConfig,
+ ZPOOL_CONFIG_GUID, 0x5678));
+ bzero(&poolHandle, sizeof(poolHandle));
+ poolHandle.zpool_config = poolConfig;
+ }
+
+ virtual void TearDown()
+ {
+ nvlist_free(poolConfig);
+ nvlist_free(vdevConfig);
+ }
+
+ nvlist_t *poolConfig;
+ nvlist_t *vdevConfig;
+ zpool_handle_t poolHandle;
+};
+
+TEST_F(ZfsdExceptionTest, StringConstructorNull)
+{
+ ZfsdException ze("");
+ EXPECT_STREQ("", ze.GetString().c_str());
+}
+
+TEST_F(ZfsdExceptionTest, StringConstructorFormatted)
+{
+ ZfsdException ze(" %d %s", 55, "hello world");
+ EXPECT_STREQ(" 55 hello world", ze.GetString().c_str());
+}
+
+TEST_F(ZfsdExceptionTest, LogSimple)
+{
+ ZfsdException ze("unit test w/o vdev or pool");
+ ze.Log();
+ EXPECT_EQ(LOG_ERR, syslog_last_priority);
+ EXPECT_STREQ("unit test w/o vdev or pool\n", syslog_last_message);
+}
+
+TEST_F(ZfsdExceptionTest, Pool)
+{
+ const char msg[] = "Exception with pool name";
+ char expected[4096];
+ sprintf(expected, "Pool unit_test_pool: %s\n", msg);
+ ZfsdException ze(poolConfig, msg);
+ ze.Log();
+ EXPECT_STREQ(expected, syslog_last_message);
+}
+
+TEST_F(ZfsdExceptionTest, PoolHandle)
+{
+ const char msg[] = "Exception with pool handle";
+ char expected[4096];
+ sprintf(expected, "Pool unit_test_pool: %s\n", msg);
+ ZfsdException ze(&poolHandle, msg);
+ ze.Log();
+ EXPECT_STREQ(expected, syslog_last_message);
+}
+
+/*
+ * Test class Vdev
+ */
+class VdevTest : public ::testing::Test
+{
+protected:
+ virtual void SetUp()
+ {
+ ASSERT_EQ(0, nvlist_alloc(&m_poolConfig, NV_UNIQUE_NAME, 0));
+ ASSERT_EQ(0, nvlist_add_uint64(m_poolConfig,
+ ZPOOL_CONFIG_POOL_GUID,
+ 0x1234));
+
+ ASSERT_EQ(0, nvlist_alloc(&m_vdevConfig, NV_UNIQUE_NAME, 0));
+ ASSERT_EQ(0, nvlist_add_uint64(m_vdevConfig, ZPOOL_CONFIG_GUID,
+ 0x5678));
+ }
+
+ virtual void TearDown()
+ {
+ nvlist_free(m_poolConfig);
+ nvlist_free(m_vdevConfig);
+ }
+
+ nvlist_t *m_poolConfig;
+ nvlist_t *m_vdevConfig;
+};
+
+
+TEST_F(VdevTest, StateFromConfig)
+{
+ vdev_stat_t vs;
+
+ vs.vs_state = VDEV_STATE_OFFLINE;
+
+ ASSERT_EQ(0, nvlist_add_uint64_array(m_vdevConfig,
+ ZPOOL_CONFIG_VDEV_STATS,
+ (uint64_t*)&vs,
+ sizeof(vs) / sizeof(uint64_t)));
+
+ Vdev vdev(m_poolConfig, m_vdevConfig);
+
+ EXPECT_EQ(VDEV_STATE_OFFLINE, vdev.State());
+}
+
+TEST_F(VdevTest, StateFaulted)
+{
+ ASSERT_EQ(0, nvlist_add_uint64(m_vdevConfig, ZPOOL_CONFIG_FAULTED, 1));
+
+ Vdev vdev(m_poolConfig, m_vdevConfig);
+
+ EXPECT_EQ(VDEV_STATE_FAULTED, vdev.State());
+}
+
+/*
+ * Test that we can construct a Vdev from the label information that is stored
+ * on an available spare drive
+ */
+TEST_F(VdevTest, ConstructAvailSpare)
+{
+ nvlist_t *labelConfig;
+
+ ASSERT_EQ(0, nvlist_alloc(&labelConfig, NV_UNIQUE_NAME, 0));
+ ASSERT_EQ(0, nvlist_add_uint64(labelConfig, ZPOOL_CONFIG_GUID,
+ 1948339428197961030));
+ ASSERT_EQ(0, nvlist_add_uint64(labelConfig, ZPOOL_CONFIG_POOL_STATE,
+ POOL_STATE_SPARE));
+
+ EXPECT_NO_THROW(Vdev vdev(labelConfig));
+
+ nvlist_free(labelConfig);
+}
+
+/* Available spares will always show the HEALTHY state */
+TEST_F(VdevTest, AvailSpareState) {
+ nvlist_t *labelConfig;
+
+ ASSERT_EQ(0, nvlist_alloc(&labelConfig, NV_UNIQUE_NAME, 0));
+ ASSERT_EQ(0, nvlist_add_uint64(labelConfig, ZPOOL_CONFIG_GUID,
+ 1948339428197961030));
+ ASSERT_EQ(0, nvlist_add_uint64(labelConfig, ZPOOL_CONFIG_POOL_STATE,
+ POOL_STATE_SPARE));
+
+ Vdev vdev(labelConfig);
+ EXPECT_EQ(VDEV_STATE_HEALTHY, vdev.State());
+
+ nvlist_free(labelConfig);
+}
+
+/* Test the Vdev::IsSpare method */
+TEST_F(VdevTest, IsSpare) {
+ Vdev* vdev;
+
+ vdev = new Vdev(m_poolConfig, m_vdevConfig);
+ EXPECT_EQ(false, vdev->IsSpare());
+ delete vdev;
+
+
+ ASSERT_EQ(0, nvlist_add_uint64(m_vdevConfig, ZPOOL_CONFIG_IS_SPARE, 1));
+ vdev = new Vdev(m_poolConfig, m_vdevConfig);
+ EXPECT_EQ(true, vdev->IsSpare());
+ delete vdev;
+}
+
+/*
+ * Test class ZFSEvent
+ */
+class ZfsEventTest : public ::testing::Test
+{
+protected:
+ virtual void SetUp()
+ {
+ m_eventFactory = new EventFactory();
+ m_eventFactory->UpdateRegistry(MockZfsEvent::s_buildRecords,
+ NUM_ELEMENTS(MockZfsEvent::s_buildRecords));
+
+ m_event = NULL;
+ }
+
+ virtual void TearDown()
+ {
+ delete m_eventFactory;
+ delete m_event;
+ }
+
+ EventFactory *m_eventFactory;
+ Event *m_event;
+};
+
+TEST_F(ZfsEventTest, ProcessPoolEventGetsCalled)
+{
+ string evString("!system=ZFS "
+ "subsystem=ZFS "
+ "type=misc.fs.zfs.vdev_remove "
+ "pool_name=foo "
+ "pool_guid=9756779504028057996 "
+ "vdev_guid=1631193447431603339 "
+ "vdev_path=/dev/da1 "
+ "timestamp=1348871594");
+ m_event = Event::CreateEvent(*m_eventFactory, evString);
+ MockZfsEvent *mock_event = static_cast<MockZfsEvent*>(m_event);
+
+ EXPECT_CALL(*mock_event, ProcessPoolEvent()).Times(1);
+ mock_event->Process();
+}
+
+/*
+ * Test class CaseFile
+ */
+
+class CaseFileTest : public ::testing::Test
+{
+protected:
+ virtual void SetUp()
+ {
+ m_eventFactory = new EventFactory();
+ m_eventFactory->UpdateRegistry(MockZfsEvent::s_buildRecords,
+ NUM_ELEMENTS(MockZfsEvent::s_buildRecords));
+
+ m_event = NULL;
+
+ nvlist_alloc(&m_vdevConfig, NV_UNIQUE_NAME, 0);
+ ASSERT_EQ(0, nvlist_add_uint64(m_vdevConfig,
+ ZPOOL_CONFIG_GUID, 0xbeef));
+ m_vdev = new MockVdev(m_vdevConfig);
+ ON_CALL(*m_vdev, GUID())
+ .WillByDefault(::testing::Return(Guid(123)));
+ ON_CALL(*m_vdev, PoolGUID())
+ .WillByDefault(::testing::Return(Guid(456)));
+ ON_CALL(*m_vdev, State())
+ .WillByDefault(::testing::Return(VDEV_STATE_HEALTHY));
+ m_caseFile = &TestableCaseFile::Create(*m_vdev);
+ ON_CALL(*m_caseFile, ReEvaluate(::testing::_))
+ .WillByDefault(::testing::Invoke(m_caseFile, &TestableCaseFile::RealReEvaluate));
+ return;
+ }
+
+ virtual void TearDown()
+ {
+ delete m_caseFile;
+ nvlist_free(m_vdevConfig);
+ delete m_vdev;
+ delete m_event;
+ delete m_eventFactory;
+ }
+
+ nvlist_t *m_vdevConfig;
+ MockVdev *m_vdev;
+ TestableCaseFile *m_caseFile;
+ Event *m_event;
+ EventFactory *m_eventFactory;
+};
+
+/*
+ * A Vdev with no events should not be degraded or faulted
+ */
+TEST_F(CaseFileTest, HealthyVdev)
+{
+ EXPECT_FALSE(m_caseFile->ShouldDegrade());
+ EXPECT_FALSE(m_caseFile->ShouldFault());
+}
+
+/*
+ * A Vdev with only one event should not be degraded or faulted
+ * For performance reasons, RefreshVdevState should not be called.
+ */
+TEST_F(CaseFileTest, HealthyishVdev)
+{
+ string evString("!system=ZFS "
+ "class=ereport.fs.zfs.io "
+ "ena=12091638756982918145 "
+ "parent_guid=13237004955564865395 "
+ "parent_type=raidz "
+ "pool=testpool.4415 "
+ "pool_context=0 "
+ "pool_failmode=wait "
+ "pool_guid=456 "
+ "subsystem=ZFS "
+ "timestamp=1348867914 "
+ "type=ereport.fs.zfs.io "
+ "vdev_guid=123 "
+ "vdev_path=/dev/da400 "
+ "vdev_type=disk "
+ "zio_blkid=622 "
+ "zio_err=1 "
+ "zio_level=-2 "
+ "zio_object=0 "
+ "zio_objset=37 "
+ "zio_offset=25598976 "
+ "zio_size=1024");
+ m_event = Event::CreateEvent(*m_eventFactory, evString);
+ ZfsEvent *zfs_event = static_cast<ZfsEvent*>(m_event);
+
+ EXPECT_CALL(*m_caseFile, RefreshVdevState())
+ .Times(::testing::Exactly(0));
+ EXPECT_TRUE(m_caseFile->ReEvaluate(*zfs_event));
+ EXPECT_FALSE(m_caseFile->ShouldDegrade());
+ EXPECT_FALSE(m_caseFile->ShouldFault());
+}
+
+/* The case file should be closed when its pool is destroyed */
+TEST_F(CaseFileTest, PoolDestroy)
+{
+ string evString("!system=ZFS "
+ "pool_name=testpool.4415 "
+ "pool_guid=456 "
+ "subsystem=ZFS "
+ "timestamp=1348867914 "
+ "type=misc.fs.zfs.pool_destroy ");
+ m_event = Event::CreateEvent(*m_eventFactory, evString);
+ ZfsEvent *zfs_event = static_cast<ZfsEvent*>(m_event);
+ EXPECT_CALL(*m_caseFile, Close());
+ EXPECT_TRUE(m_caseFile->ReEvaluate(*zfs_event));
+}
+
+/*
+ * A Vdev with a very large number of IO errors should fault
+ * For performance reasons, RefreshVdevState should be called at most once
+ */
+TEST_F(CaseFileTest, VeryManyIOErrors)
+{
+ EXPECT_CALL(*m_caseFile, RefreshVdevState())
+ .Times(::testing::AtMost(1))
+ .WillRepeatedly(::testing::Return(true));
+
+ for(int i=0; i<100; i++) {
+ stringstream evStringStream;
+ evStringStream <<
+ "!system=ZFS "
+ "class=ereport.fs.zfs.io "
+ "ena=12091638756982918145 "
+ "parent_guid=13237004955564865395 "
+ "parent_type=raidz "
+ "pool=testpool.4415 "
+ "pool_context=0 "
+ "pool_failmode=wait "
+ "pool_guid=456 "
+ "subsystem=ZFS "
+ "timestamp=";
+ evStringStream << i << " ";
+ evStringStream <<
+ "type=ereport.fs.zfs.io "
+ "vdev_guid=123 "
+ "vdev_path=/dev/da400 "
+ "vdev_type=disk "
+ "zio_blkid=622 "
+ "zio_err=1 "
+ "zio_level=-2 "
+ "zio_object=0 "
+ "zio_objset=37 "
+ "zio_offset=25598976 "
+ "zio_size=1024";
+ Event *event(Event::CreateEvent(*m_eventFactory,
+ evStringStream.str()));
+ ZfsEvent *zfs_event = static_cast<ZfsEvent*>(event);
+ EXPECT_TRUE(m_caseFile->ReEvaluate(*zfs_event));
+ delete event;
+ }
+
+ m_caseFile->SpliceEvents();
+ EXPECT_FALSE(m_caseFile->ShouldDegrade());
+ EXPECT_TRUE(m_caseFile->ShouldFault());
+}
+
+/*
+ * A Vdev with a very large number of checksum errors should degrade
+ * For performance reasons, RefreshVdevState should be called at most once
+ */
+TEST_F(CaseFileTest, VeryManyChecksumErrors)
+{
+ EXPECT_CALL(*m_caseFile, RefreshVdevState())
+ .Times(::testing::AtMost(1))
+ .WillRepeatedly(::testing::Return(true));
+
+ for(int i=0; i<100; i++) {
+ stringstream evStringStream;
+ evStringStream <<
+ "!system=ZFS "
+ "bad_cleared_bits=03000000000000803f50b00000000000 "
+ "bad_range_clears=0000000e "
+ "bad_range_sets=00000000 "
+ "bad_ranges=0000000000000010 "
+ "bad_ranges_min_gap=8 "
+ "bad_set_bits=00000000000000000000000000000000 "
+ "class=ereport.fs.zfs.checksum "
+ "ena=12272856582652437505 "
+ "parent_guid=5838204195352909894 "
+ "parent_type=raidz pool=testpool.7640 "
+ "pool_context=0 "
+ "pool_failmode=wait "
+ "pool_guid=456 "
+ "subsystem=ZFS timestamp=";
+ evStringStream << i << " ";
+ evStringStream <<
+ "type=ereport.fs.zfs.checksum "
+ "vdev_guid=123 "
+ "vdev_path=/mnt/tmp/file1.7702 "
+ "vdev_type=file "
+ "zio_blkid=0 "
+ "zio_err=0 "
+ "zio_level=0 "
+ "zio_object=3 "
+ "zio_objset=0 "
+ "zio_offset=16896 "
+ "zio_size=512";
+ Event *event(Event::CreateEvent(*m_eventFactory,
+ evStringStream.str()));
+ ZfsEvent *zfs_event = static_cast<ZfsEvent*>(event);
+ EXPECT_TRUE(m_caseFile->ReEvaluate(*zfs_event));
+ delete event;
+ }
+
+ m_caseFile->SpliceEvents();
+ EXPECT_TRUE(m_caseFile->ShouldDegrade());
+ EXPECT_FALSE(m_caseFile->ShouldFault());
+}
+
+/*
+ * Test CaseFile::ReEvaluateByGuid
+ */
+class ReEvaluateByGuidTest : public ::testing::Test
+{
+protected:
+ virtual void SetUp()
+ {
+ m_eventFactory = new EventFactory();
+ m_eventFactory->UpdateRegistry(MockZfsEvent::s_buildRecords,
+ NUM_ELEMENTS(MockZfsEvent::s_buildRecords));
+ m_event = Event::CreateEvent(*m_eventFactory, s_evString);
+ nvlist_alloc(&m_vdevConfig, NV_UNIQUE_NAME, 0);
+ ASSERT_EQ(0, nvlist_add_uint64(m_vdevConfig,
+ ZPOOL_CONFIG_GUID, 0xbeef));
+ m_vdev456 = new ::testing::NiceMock<MockVdev>(m_vdevConfig);
+ m_vdev789 = new ::testing::NiceMock<MockVdev>(m_vdevConfig);
+ ON_CALL(*m_vdev456, GUID())
+ .WillByDefault(::testing::Return(Guid(123)));
+ ON_CALL(*m_vdev456, PoolGUID())
+ .WillByDefault(::testing::Return(Guid(456)));
+ ON_CALL(*m_vdev456, State())
+ .WillByDefault(::testing::Return(VDEV_STATE_HEALTHY));
+ ON_CALL(*m_vdev789, GUID())
+ .WillByDefault(::testing::Return(Guid(123)));
+ ON_CALL(*m_vdev789, PoolGUID())
+ .WillByDefault(::testing::Return(Guid(789)));
+ ON_CALL(*m_vdev789, State())
+ .WillByDefault(::testing::Return(VDEV_STATE_HEALTHY));
+ m_caseFile456 = NULL;
+ m_caseFile789 = NULL;
+ return;
+ }
+
+ virtual void TearDown()
+ {
+ delete m_caseFile456;
+ delete m_caseFile789;
+ nvlist_free(m_vdevConfig);
+ delete m_vdev456;
+ delete m_vdev789;
+ delete m_event;
+ delete m_eventFactory;
+ }
+
+ static string s_evString;
+ nvlist_t *m_vdevConfig;
+ ::testing::NiceMock<MockVdev> *m_vdev456;
+ ::testing::NiceMock<MockVdev> *m_vdev789;
+ TestableCaseFile *m_caseFile456;
+ TestableCaseFile *m_caseFile789;
+ Event *m_event;
+ EventFactory *m_eventFactory;
+};
+
+string ReEvaluateByGuidTest::s_evString(
+ "!system=ZFS "
+ "pool_guid=16271873792808333580 "
+ "pool_name=foo "
+ "subsystem=ZFS "
+ "timestamp=1360620391 "
+ "type=misc.fs.zfs.config_sync");
+
+
+/*
+ * Test the ReEvaluateByGuid method on an empty list of casefiles.
+ * We must create one event, even though it never gets used, because it will
+ * be passed by reference to ReEvaluateByGuid
+ */
+TEST_F(ReEvaluateByGuidTest, ReEvaluateByGuid_empty)
+{
+ ZfsEvent *zfs_event = static_cast<ZfsEvent*>(m_event);
+
+ EXPECT_EQ(0, TestableCaseFile::getActiveCases());
+ CaseFile::ReEvaluateByGuid(Guid(456), *zfs_event);
+ EXPECT_EQ(0, TestableCaseFile::getActiveCases());
+}
+
+/*
+ * Test the ReEvaluateByGuid method on a list of CaseFiles that contains only
+ * one CaseFile, which doesn't match the criteria
+ */
+TEST_F(ReEvaluateByGuidTest, ReEvaluateByGuid_oneFalse)
+{
+ m_caseFile456 = &TestableCaseFile::Create(*m_vdev456);
+ ZfsEvent *zfs_event = static_cast<ZfsEvent*>(m_event);
+
+ EXPECT_EQ(1, TestableCaseFile::getActiveCases());
+ EXPECT_CALL(*m_caseFile456, ReEvaluate(::testing::_))
+ .Times(::testing::Exactly(0));
+ CaseFile::ReEvaluateByGuid(Guid(789), *zfs_event);
+ EXPECT_EQ(1, TestableCaseFile::getActiveCases());
+}
+
+/*
+ * Test the ReEvaluateByGuid method on a list of CaseFiles that contains only
+ * one CaseFile, which does match the criteria
+ */
+TEST_F(ReEvaluateByGuidTest, ReEvaluateByGuid_oneTrue)
+{
+ m_caseFile456 = &TestableCaseFile::Create(*m_vdev456);
+ ZfsEvent *zfs_event = static_cast<ZfsEvent*>(m_event);
+
+ EXPECT_EQ(1, TestableCaseFile::getActiveCases());
+ EXPECT_CALL(*m_caseFile456, ReEvaluate(::testing::_))
+ .Times(::testing::Exactly(1))
+ .WillRepeatedly(::testing::Return(false));
+ CaseFile::ReEvaluateByGuid(Guid(456), *zfs_event);
+ EXPECT_EQ(1, TestableCaseFile::getActiveCases());
+}
+
+/*
+ * Test the ReEvaluateByGuid method on a long list of CaseFiles that contains a
+ * few cases which meet the criteria
+ */
+TEST_F(ReEvaluateByGuidTest, ReEvaluateByGuid_five)
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-projects
mailing list