Path: blob/main/cddl/usr.sbin/zfsd/tests/zfsd_unittest.cc
108545 views
/*-1* Copyright (c) 2012, 2013, 2014 Spectra Logic Corporation2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions, and the following disclaimer,9* without modification.10* 2. Redistributions in binary form must reproduce at minimum a disclaimer11* substantially similar to the "NO WARRANTY" disclaimer below12* ("Disclaimer") and any redistribution must be conditioned upon13* including a substantially similar Disclaimer requirement for further14* binary redistribution.15*16* NO WARRANTY17* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS18* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT19* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR20* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT21* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL22* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS23* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)24* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,25* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING26* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE27* POSSIBILITY OF SUCH DAMAGES.28*29* Authors: Alan Somers (Spectra Logic Corporation)30*/31#include <sys/cdefs.h>32#include <sys/byteorder.h>3334#include <stdarg.h>35#include <syslog.h>3637#include <libnvpair.h>38#include <libzfs.h>3940#include <list>41#include <map>42#include <sstream>43#include <string>4445#include <gmock/gmock.h>46#include <gtest/gtest.h>4748#include <devdctl/guid.h>49#include <devdctl/event.h>50#include <devdctl/event_factory.h>51#include <devdctl/exception.h>52#include <devdctl/consumer.h>5354#include <zfsd/callout.h>55#include <zfsd/vdev_iterator.h>56#include <zfsd/zfsd_event.h>57#include <zfsd/case_file.h>58#include <zfsd/vdev.h>59#include <zfsd/zfsd.h>60#include <zfsd/zfsd_exception.h>61#include <zfsd/zpool_list.h>6263#include "libmocks.h"64/*================================== Macros ==================================*/65#define NUM_ELEMENTS(x) (sizeof(x) / sizeof(*x))6667/*============================ Namespace Control =============================*/68using std::string;69using std::stringstream;7071using DevdCtl::Event;72using DevdCtl::EventFactory;73using DevdCtl::EventList;74using DevdCtl::Guid;75using DevdCtl::NVPairMap;7677/* redefine zpool_handle here because libzfs_impl.h is not includable */78struct zpool_handle79{80libzfs_handle_t *zpool_hdl;81zpool_handle_t *zpool_next;82char zpool_name[ZFS_MAX_DATASET_NAME_LEN];83int zpool_state;84unsigned int zpool_n_propnames;85#define ZHP_MAX_PROPNAMES 486const char *zpool_propnames[ZHP_MAX_PROPNAMES];87size_t zpool_config_size;88nvlist_t *zpool_config;89nvlist_t *zpool_old_config;90nvlist_t *zpool_props;91diskaddr_t zpool_start_block;92};9394class MockZfsEvent : public ZfsEvent95{96public:97MockZfsEvent(Event::Type, NVPairMap&, const string&);98virtual ~MockZfsEvent() {}99100static BuildMethod MockZfsEventBuilder;101102MOCK_CONST_METHOD0(ProcessPoolEvent, void());103104static EventFactory::Record s_buildRecords[];105};106107EventFactory::Record MockZfsEvent::s_buildRecords[] =108{109{ Event::NOTIFY, "ZFS", &MockZfsEvent::MockZfsEventBuilder }110};111112MockZfsEvent::MockZfsEvent(Event::Type type, NVPairMap& map,113const string& str)114: ZfsEvent(type, map, str)115{116}117118Event *119MockZfsEvent::MockZfsEventBuilder(Event::Type type,120NVPairMap &nvpairs,121const string &eventString)122{123return (new MockZfsEvent(type, nvpairs, eventString));124}125126/*127* A dummy Vdev class used for testing other classes128*/129class MockVdev : public Vdev130{131public:132MockVdev(nvlist_t *vdevConfig);133virtual ~MockVdev() {}134135MOCK_CONST_METHOD0(GUID, Guid());136MOCK_CONST_METHOD0(PoolGUID, Guid());137MOCK_CONST_METHOD0(State, vdev_state());138MOCK_CONST_METHOD0(PhysicalPath, string());139MOCK_CONST_METHOD2(Name, string(zpool_handle_t * zhp, bool verbose));140};141142MockVdev::MockVdev(nvlist_t *vdevConfig)143: Vdev(vdevConfig)144{145}146147/*148* A CaseFile class with side effects removed, for testing149*/150class TestableCaseFile : public CaseFile151{152public:153static TestableCaseFile &Create(Vdev &vdev);154TestableCaseFile(Vdev &vdev);155virtual ~TestableCaseFile() {}156157MOCK_METHOD0(Close, void());158MOCK_METHOD1(RegisterCallout, void(const Event &event));159MOCK_METHOD0(RefreshVdevState, bool());160MOCK_METHOD1(ReEvaluate, bool(const ZfsEvent &event));161162bool RealReEvaluate(const ZfsEvent &event)163{164return (CaseFile::ReEvaluate(event));165}166167/*168* This splices the event lists, a procedure that would normally be done169* by OnGracePeriodEnded, but we don't necessarily call that in the170* unit tests171*/172void SpliceEvents();173174/*175* Used by some of our expectations. CaseFile does not publicize this176*/177static int getActiveCases()178{179return (s_activeCases.size());180}181};182183TestableCaseFile::TestableCaseFile(Vdev &vdev)184: CaseFile(vdev)185{186}187188TestableCaseFile &189TestableCaseFile::Create(Vdev &vdev)190{191TestableCaseFile *newCase;192newCase = new TestableCaseFile(vdev);193return (*newCase);194}195196void197TestableCaseFile::SpliceEvents()198{199m_events.splice(m_events.begin(), m_tentativeEvents);200}201202203/*204* Test class ZfsdException205*/206class ZfsdExceptionTest : public ::testing::Test207{208protected:209virtual void SetUp()210{211ASSERT_EQ(0, nvlist_alloc(&poolConfig, NV_UNIQUE_NAME, 0));212ASSERT_EQ(0, nvlist_add_string(poolConfig,213ZPOOL_CONFIG_POOL_NAME, "unit_test_pool"));214ASSERT_EQ(0, nvlist_add_uint64(poolConfig,215ZPOOL_CONFIG_POOL_GUID, 0x1234));216217ASSERT_EQ(0, nvlist_alloc(&vdevConfig, NV_UNIQUE_NAME, 0));218ASSERT_EQ(0, nvlist_add_uint64(vdevConfig,219ZPOOL_CONFIG_GUID, 0x5678));220bzero(&poolHandle, sizeof(poolHandle));221poolHandle.zpool_config = poolConfig;222}223224virtual void TearDown()225{226nvlist_free(poolConfig);227nvlist_free(vdevConfig);228}229230nvlist_t *poolConfig;231nvlist_t *vdevConfig;232zpool_handle_t poolHandle;233};234235TEST_F(ZfsdExceptionTest, StringConstructorNull)236{237ZfsdException ze("");238EXPECT_STREQ("", ze.GetString().c_str());239}240241TEST_F(ZfsdExceptionTest, StringConstructorFormatted)242{243ZfsdException ze(" %d %s", 55, "hello world");244EXPECT_STREQ(" 55 hello world", ze.GetString().c_str());245}246247TEST_F(ZfsdExceptionTest, LogSimple)248{249ZfsdException ze("unit test w/o vdev or pool");250ze.Log();251EXPECT_EQ(LOG_ERR, syslog_last_priority);252EXPECT_STREQ("unit test w/o vdev or pool\n", syslog_last_message);253}254255TEST_F(ZfsdExceptionTest, Pool)256{257const char msg[] = "Exception with pool name";258char expected[4096];259sprintf(expected, "Pool unit_test_pool: %s\n", msg);260ZfsdException ze(poolConfig, msg);261ze.Log();262EXPECT_STREQ(expected, syslog_last_message);263}264265TEST_F(ZfsdExceptionTest, PoolHandle)266{267const char msg[] = "Exception with pool handle";268char expected[4096];269sprintf(expected, "Pool unit_test_pool: %s\n", msg);270ZfsdException ze(&poolHandle, msg);271ze.Log();272EXPECT_STREQ(expected, syslog_last_message);273}274275/*276* Test class Vdev277*/278class VdevTest : public ::testing::Test279{280protected:281virtual void SetUp()282{283ASSERT_EQ(0, nvlist_alloc(&m_poolConfig, NV_UNIQUE_NAME, 0));284ASSERT_EQ(0, nvlist_add_uint64(m_poolConfig,285ZPOOL_CONFIG_POOL_GUID,2860x1234));287288ASSERT_EQ(0, nvlist_alloc(&m_vdevConfig, NV_UNIQUE_NAME, 0));289ASSERT_EQ(0, nvlist_add_uint64(m_vdevConfig, ZPOOL_CONFIG_GUID,2900x5678));291}292293virtual void TearDown()294{295nvlist_free(m_poolConfig);296nvlist_free(m_vdevConfig);297}298299nvlist_t *m_poolConfig;300nvlist_t *m_vdevConfig;301};302303304TEST_F(VdevTest, StateFromConfig)305{306vdev_stat_t vs;307308vs.vs_state = VDEV_STATE_OFFLINE;309310ASSERT_EQ(0, nvlist_add_uint64_array(m_vdevConfig,311ZPOOL_CONFIG_VDEV_STATS,312(uint64_t*)&vs,313sizeof(vs) / sizeof(uint64_t)));314315Vdev vdev(m_poolConfig, m_vdevConfig);316317EXPECT_EQ(VDEV_STATE_OFFLINE, vdev.State());318}319320TEST_F(VdevTest, StateFaulted)321{322ASSERT_EQ(0, nvlist_add_uint64(m_vdevConfig, ZPOOL_CONFIG_FAULTED, 1));323324Vdev vdev(m_poolConfig, m_vdevConfig);325326EXPECT_EQ(VDEV_STATE_FAULTED, vdev.State());327}328329/*330* Test that we can construct a Vdev from the label information that is stored331* on an available spare drive332*/333TEST_F(VdevTest, ConstructAvailSpare)334{335nvlist_t *labelConfig;336337ASSERT_EQ(0, nvlist_alloc(&labelConfig, NV_UNIQUE_NAME, 0));338ASSERT_EQ(0, nvlist_add_uint64(labelConfig, ZPOOL_CONFIG_GUID,3391948339428197961030));340ASSERT_EQ(0, nvlist_add_uint64(labelConfig, ZPOOL_CONFIG_POOL_STATE,341POOL_STATE_SPARE));342343EXPECT_NO_THROW(Vdev vdev(labelConfig));344345nvlist_free(labelConfig);346}347348/* Available spares will always show the HEALTHY state */349TEST_F(VdevTest, AvailSpareState) {350nvlist_t *labelConfig;351352ASSERT_EQ(0, nvlist_alloc(&labelConfig, NV_UNIQUE_NAME, 0));353ASSERT_EQ(0, nvlist_add_uint64(labelConfig, ZPOOL_CONFIG_GUID,3541948339428197961030));355ASSERT_EQ(0, nvlist_add_uint64(labelConfig, ZPOOL_CONFIG_POOL_STATE,356POOL_STATE_SPARE));357358Vdev vdev(labelConfig);359EXPECT_EQ(VDEV_STATE_HEALTHY, vdev.State());360361nvlist_free(labelConfig);362}363364/* Test the Vdev::IsSpare method */365TEST_F(VdevTest, IsSpare) {366Vdev notSpare(m_poolConfig, m_vdevConfig);367EXPECT_EQ(false, notSpare.IsSpare());368369ASSERT_EQ(0, nvlist_add_uint64(m_vdevConfig, ZPOOL_CONFIG_IS_SPARE, 1));370Vdev isSpare(m_poolConfig, m_vdevConfig);371EXPECT_EQ(true, isSpare.IsSpare());372}373374/*375* Test class ZFSEvent376*/377class ZfsEventTest : public ::testing::Test378{379protected:380virtual void SetUp()381{382m_eventFactory = new EventFactory();383m_eventFactory->UpdateRegistry(MockZfsEvent::s_buildRecords,384NUM_ELEMENTS(MockZfsEvent::s_buildRecords));385386m_event = NULL;387}388389virtual void TearDown()390{391delete m_eventFactory;392delete m_event;393}394395EventFactory *m_eventFactory;396Event *m_event;397};398399TEST_F(ZfsEventTest, ProcessPoolEventGetsCalled)400{401string evString("!system=ZFS "402"subsystem=ZFS "403"type=sysevent.fs.zfs.vdev_remove "404"pool_name=foo "405"pool_guid=9756779504028057996 "406"vdev_guid=1631193447431603339 "407"vdev_path=/dev/da1 "408"timestamp=1348871594");409m_event = Event::CreateEvent(*m_eventFactory, evString);410MockZfsEvent *mock_event = static_cast<MockZfsEvent*>(m_event);411412EXPECT_CALL(*mock_event, ProcessPoolEvent()).Times(1);413mock_event->Process();414}415416/*417* Test class CaseFile418*/419420class CaseFileTest : public ::testing::Test421{422protected:423virtual void SetUp()424{425m_eventFactory = new EventFactory();426m_eventFactory->UpdateRegistry(MockZfsEvent::s_buildRecords,427NUM_ELEMENTS(MockZfsEvent::s_buildRecords));428429m_event = NULL;430431nvlist_alloc(&m_vdevConfig, NV_UNIQUE_NAME, 0);432ASSERT_EQ(0, nvlist_add_uint64(m_vdevConfig,433ZPOOL_CONFIG_GUID, 0xbeef));434m_vdev = new MockVdev(m_vdevConfig);435ON_CALL(*m_vdev, GUID())436.WillByDefault(::testing::Return(Guid(123)));437ON_CALL(*m_vdev, Name(::testing::_, ::testing::_))438.WillByDefault(::testing::Return(string("/dev/da999")));439ON_CALL(*m_vdev, PoolGUID())440.WillByDefault(::testing::Return(Guid(456)));441ON_CALL(*m_vdev, State())442.WillByDefault(::testing::Return(VDEV_STATE_HEALTHY));443m_caseFile = &TestableCaseFile::Create(*m_vdev);444ON_CALL(*m_caseFile, ReEvaluate(::testing::_))445.WillByDefault(::testing::Invoke(m_caseFile, &TestableCaseFile::RealReEvaluate));446return;447}448449virtual void TearDown()450{451delete m_caseFile;452nvlist_free(m_vdevConfig);453delete m_vdev;454delete m_event;455delete m_eventFactory;456}457458nvlist_t *m_vdevConfig;459MockVdev *m_vdev;460TestableCaseFile *m_caseFile;461Event *m_event;462EventFactory *m_eventFactory;463};464465/*466* A Vdev with no events should not be degraded or faulted467*/468TEST_F(CaseFileTest, HealthyVdev)469{470EXPECT_FALSE(m_caseFile->ShouldDegrade());471EXPECT_FALSE(m_caseFile->ShouldFault());472}473474/*475* A Vdev with only one event should not be degraded or faulted476* For performance reasons, RefreshVdevState should not be called.477*/478TEST_F(CaseFileTest, HealthyishVdev)479{480string evString("!system=ZFS "481"class=ereport.fs.zfs.io "482"ena=12091638756982918145 "483"parent_guid=13237004955564865395 "484"parent_type=raidz "485"pool=testpool.4415 "486"pool_context=0 "487"pool_failmode=wait "488"pool_guid=456 "489"subsystem=ZFS "490"timestamp=1348867914 "491"type=ereport.fs.zfs.io "492"vdev_guid=123 "493"vdev_path=/dev/da400 "494"vdev_type=disk "495"zio_blkid=622 "496"zio_err=1 "497"zio_level=-2 "498"zio_object=0 "499"zio_objset=37 "500"zio_offset=25598976 "501"zio_size=1024");502m_event = Event::CreateEvent(*m_eventFactory, evString);503ZfsEvent *zfs_event = static_cast<ZfsEvent*>(m_event);504505EXPECT_CALL(*m_caseFile, RefreshVdevState())506.Times(::testing::Exactly(0));507EXPECT_TRUE(m_caseFile->ReEvaluate(*zfs_event));508EXPECT_FALSE(m_caseFile->ShouldDegrade());509EXPECT_FALSE(m_caseFile->ShouldFault());510}511512/* The case file should be closed when its pool is destroyed */513TEST_F(CaseFileTest, PoolDestroy)514{515string evString("!system=ZFS "516"pool_name=testpool.4415 "517"pool_guid=456 "518"subsystem=ZFS "519"timestamp=1348867914 "520"type=sysevent.fs.zfs.pool_destroy ");521m_event = Event::CreateEvent(*m_eventFactory, evString);522ZfsEvent *zfs_event = static_cast<ZfsEvent*>(m_event);523EXPECT_CALL(*m_caseFile, Close());524EXPECT_TRUE(m_caseFile->ReEvaluate(*zfs_event));525}526527/*528* A Vdev with a very large number of Delay errors should fault529* For performance reasons, RefreshVdevState should be called at most once530*/531TEST_F(CaseFileTest, VeryManyDelayErrors)532{533EXPECT_CALL(*m_caseFile, RefreshVdevState())534.Times(::testing::AtMost(1))535.WillRepeatedly(::testing::Return(true));536537for(int i=0; i<100; i++) {538stringstream evStringStream;539evStringStream <<540"!system=ZFS "541"class=ereport.fs.zfs.delay "542"ena=12091638756982918145 "543"parent_guid=13237004955564865395 "544"parent_type=raidz "545"pool=testpool.4415 "546"pool_context=0 "547"pool_failmode=wait "548"pool_guid=456 "549"pool_state= 0"550"subsystem=ZFS "551"time=";552evStringStream << i << "0000000000000000 ";553evStringStream << "timestamp=" << i << " ";554evStringStream <<555"type=ereport.fs.zfs.delay "556"vdev_ashift=12 "557"vdev_cksum_errors=0 "558"vdev_complete_ts=948336226469 "559"vdev_delays=77 "560"vdev_delta_ts=123998485899 "561"vdev_guid=123 "562"vdev_path=/dev/da400 "563"vdev_read_errors=0 "564"vdev_spare_guids= "565"vdev_type=disk "566"vdev_write_errors=0 "567"zio_blkid=622 "568"zio_delay=31000041101 "569"zio_delta=123998485899 "570"zio_err=0 "571"zio_flags=1572992 "572"zio_level=-2 "573"zio_object=0 "574"zio_objset=37 "575"zio_offset=25598976 "576"zio_pipeline=48234496 "577"zio_priority=3 "578"zio_size=1024"579"zio_stage=33554432 "580"zio_timestamp=824337740570 ";581Event *event(Event::CreateEvent(*m_eventFactory,582evStringStream.str()));583ZfsEvent *zfs_event = static_cast<ZfsEvent*>(event);584EXPECT_TRUE(m_caseFile->ReEvaluate(*zfs_event));585delete event;586}587588m_caseFile->SpliceEvents();589EXPECT_FALSE(m_caseFile->ShouldDegrade());590EXPECT_TRUE(m_caseFile->ShouldFault());591}592593/*594* A Vdev with a very large number of IO errors should fault595* For performance reasons, RefreshVdevState should be called at most once596*/597TEST_F(CaseFileTest, VeryManyIOErrors)598{599EXPECT_CALL(*m_caseFile, RefreshVdevState())600.Times(::testing::AtMost(1))601.WillRepeatedly(::testing::Return(true));602603for(int i=0; i<100; i++) {604stringstream evStringStream;605evStringStream <<606"!system=ZFS "607"class=ereport.fs.zfs.io "608"ena=12091638756982918145 "609"parent_guid=13237004955564865395 "610"parent_type=raidz "611"pool=testpool.4415 "612"pool_context=0 "613"pool_failmode=wait "614"pool_guid=456 "615"subsystem=ZFS "616"timestamp=";617evStringStream << i << " ";618evStringStream <<619"type=ereport.fs.zfs.io "620"vdev_guid=123 "621"vdev_path=/dev/da400 "622"vdev_type=disk "623"zio_blkid=622 "624"zio_err=1 "625"zio_level=-2 "626"zio_object=0 "627"zio_objset=37 "628"zio_offset=25598976 "629"zio_size=1024";630Event *event(Event::CreateEvent(*m_eventFactory,631evStringStream.str()));632ZfsEvent *zfs_event = static_cast<ZfsEvent*>(event);633EXPECT_TRUE(m_caseFile->ReEvaluate(*zfs_event));634delete event;635}636637m_caseFile->SpliceEvents();638EXPECT_FALSE(m_caseFile->ShouldDegrade());639EXPECT_TRUE(m_caseFile->ShouldFault());640}641642/*643* A Vdev with a very large number of checksum errors should degrade644* For performance reasons, RefreshVdevState should be called at most once645*/646TEST_F(CaseFileTest, VeryManyChecksumErrors)647{648EXPECT_CALL(*m_caseFile, RefreshVdevState())649.Times(::testing::AtMost(1))650.WillRepeatedly(::testing::Return(true));651652for(int i=0; i<100; i++) {653stringstream evStringStream;654evStringStream <<655"!system=ZFS "656"bad_cleared_bits=03000000000000803f50b00000000000 "657"bad_range_clears=0000000e "658"bad_range_sets=00000000 "659"bad_ranges=0000000000000010 "660"bad_ranges_min_gap=8 "661"bad_set_bits=00000000000000000000000000000000 "662"class=ereport.fs.zfs.checksum "663"ena=12272856582652437505 "664"parent_guid=5838204195352909894 "665"parent_type=raidz pool=testpool.7640 "666"pool_context=0 "667"pool_failmode=wait "668"pool_guid=456 "669"subsystem=ZFS timestamp=";670evStringStream << i << " ";671evStringStream <<672"type=ereport.fs.zfs.checksum "673"vdev_guid=123 "674"vdev_path=/mnt/tmp/file1.7702 "675"vdev_type=file "676"zio_blkid=0 "677"zio_err=0 "678"zio_level=0 "679"zio_object=3 "680"zio_objset=0 "681"zio_offset=16896 "682"zio_size=512";683Event *event(Event::CreateEvent(*m_eventFactory,684evStringStream.str()));685ZfsEvent *zfs_event = static_cast<ZfsEvent*>(event);686EXPECT_TRUE(m_caseFile->ReEvaluate(*zfs_event));687delete event;688}689690m_caseFile->SpliceEvents();691EXPECT_TRUE(m_caseFile->ShouldDegrade());692EXPECT_FALSE(m_caseFile->ShouldFault());693}694695/*696* Test CaseFile::ReEvaluateByGuid697*/698class ReEvaluateByGuidTest : public ::testing::Test699{700protected:701virtual void SetUp()702{703m_eventFactory = new EventFactory();704m_eventFactory->UpdateRegistry(MockZfsEvent::s_buildRecords,705NUM_ELEMENTS(MockZfsEvent::s_buildRecords));706m_event = Event::CreateEvent(*m_eventFactory, s_evString);707nvlist_alloc(&m_vdevConfig, NV_UNIQUE_NAME, 0);708ASSERT_EQ(0, nvlist_add_uint64(m_vdevConfig,709ZPOOL_CONFIG_GUID, 0xbeef));710m_vdev456 = new ::testing::NiceMock<MockVdev>(m_vdevConfig);711m_vdev789 = new ::testing::NiceMock<MockVdev>(m_vdevConfig);712ON_CALL(*m_vdev456, GUID())713.WillByDefault(::testing::Return(Guid(123)));714ON_CALL(*m_vdev456, PoolGUID())715.WillByDefault(::testing::Return(Guid(456)));716ON_CALL(*m_vdev456, State())717.WillByDefault(::testing::Return(VDEV_STATE_HEALTHY));718ON_CALL(*m_vdev789, GUID())719.WillByDefault(::testing::Return(Guid(123)));720ON_CALL(*m_vdev789, PoolGUID())721.WillByDefault(::testing::Return(Guid(789)));722ON_CALL(*m_vdev789, State())723.WillByDefault(::testing::Return(VDEV_STATE_HEALTHY));724m_caseFile456 = NULL;725m_caseFile789 = NULL;726return;727}728729virtual void TearDown()730{731delete m_caseFile456;732delete m_caseFile789;733nvlist_free(m_vdevConfig);734delete m_vdev456;735delete m_vdev789;736delete m_event;737delete m_eventFactory;738}739740static string s_evString;741nvlist_t *m_vdevConfig;742::testing::NiceMock<MockVdev> *m_vdev456;743::testing::NiceMock<MockVdev> *m_vdev789;744TestableCaseFile *m_caseFile456;745TestableCaseFile *m_caseFile789;746Event *m_event;747EventFactory *m_eventFactory;748};749750string ReEvaluateByGuidTest::s_evString(751"!system=ZFS "752"pool_guid=16271873792808333580 "753"pool_name=foo "754"subsystem=ZFS "755"timestamp=1360620391 "756"type=sysevent.fs.zfs.config_sync");757758759/*760* Test the ReEvaluateByGuid method on an empty list of casefiles.761* We must create one event, even though it never gets used, because it will762* be passed by reference to ReEvaluateByGuid763*/764TEST_F(ReEvaluateByGuidTest, ReEvaluateByGuid_empty)765{766ZfsEvent *zfs_event = static_cast<ZfsEvent*>(m_event);767768EXPECT_EQ(0, TestableCaseFile::getActiveCases());769CaseFile::ReEvaluateByGuid(Guid(456), *zfs_event);770EXPECT_EQ(0, TestableCaseFile::getActiveCases());771}772773/*774* Test the ReEvaluateByGuid method on a list of CaseFiles that contains only775* one CaseFile, which doesn't match the criteria776*/777TEST_F(ReEvaluateByGuidTest, ReEvaluateByGuid_oneFalse)778{779m_caseFile456 = &TestableCaseFile::Create(*m_vdev456);780ZfsEvent *zfs_event = static_cast<ZfsEvent*>(m_event);781782EXPECT_EQ(1, TestableCaseFile::getActiveCases());783EXPECT_CALL(*m_caseFile456, ReEvaluate(::testing::_))784.Times(::testing::Exactly(0));785CaseFile::ReEvaluateByGuid(Guid(789), *zfs_event);786EXPECT_EQ(1, TestableCaseFile::getActiveCases());787}788789/*790* Test the ReEvaluateByGuid method on a list of CaseFiles that contains only791* one CaseFile, which does match the criteria792*/793TEST_F(ReEvaluateByGuidTest, ReEvaluateByGuid_oneTrue)794{795m_caseFile456 = &TestableCaseFile::Create(*m_vdev456);796ZfsEvent *zfs_event = static_cast<ZfsEvent*>(m_event);797798EXPECT_EQ(1, TestableCaseFile::getActiveCases());799EXPECT_CALL(*m_caseFile456, ReEvaluate(::testing::_))800.Times(::testing::Exactly(1))801.WillRepeatedly(::testing::Return(false));802CaseFile::ReEvaluateByGuid(Guid(456), *zfs_event);803EXPECT_EQ(1, TestableCaseFile::getActiveCases());804}805806/*807* Test the ReEvaluateByGuid method on a long list of CaseFiles that contains a808* few cases which meet the criteria809*/810TEST_F(ReEvaluateByGuidTest, ReEvaluateByGuid_five)811{812TestableCaseFile *CaseFile1 = &TestableCaseFile::Create(*m_vdev456);813TestableCaseFile *CaseFile2 = &TestableCaseFile::Create(*m_vdev789);814TestableCaseFile *CaseFile3 = &TestableCaseFile::Create(*m_vdev456);815TestableCaseFile *CaseFile4 = &TestableCaseFile::Create(*m_vdev789);816TestableCaseFile *CaseFile5 = &TestableCaseFile::Create(*m_vdev789);817ZfsEvent *zfs_event = static_cast<ZfsEvent*>(m_event);818819EXPECT_EQ(5, TestableCaseFile::getActiveCases());820EXPECT_CALL(*CaseFile1, ReEvaluate(::testing::_))821.Times(::testing::Exactly(1))822.WillRepeatedly(::testing::Return(false));823EXPECT_CALL(*CaseFile3, ReEvaluate(::testing::_))824.Times(::testing::Exactly(1))825.WillRepeatedly(::testing::Return(false));826EXPECT_CALL(*CaseFile2, ReEvaluate(::testing::_))827.Times(::testing::Exactly(0));828EXPECT_CALL(*CaseFile4, ReEvaluate(::testing::_))829.Times(::testing::Exactly(0));830EXPECT_CALL(*CaseFile5, ReEvaluate(::testing::_))831.Times(::testing::Exactly(0));832CaseFile::ReEvaluateByGuid(Guid(456), *zfs_event);833EXPECT_EQ(5, TestableCaseFile::getActiveCases());834delete CaseFile1;835delete CaseFile2;836delete CaseFile3;837delete CaseFile4;838delete CaseFile5;839}840841/*842* Test VdevIterator843*/844class VdevIteratorTest : public ::testing::Test845{846};847848bool VdevIteratorTestCB(Vdev &vdev, void *cbArg) {849return (false);850}851852/*853* VdevIterator::Next should not crash when run on a pool that has a previously854* removed vdev. Regression for855* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=273663856*/857TEST_F(VdevIteratorTest, VdevRemoval)858{859nvlist_t* poolConfig, *rootVdev;860861ASSERT_EQ(0, nvlist_alloc(&rootVdev, NV_UNIQUE_NAME, 0));862ASSERT_EQ(0, nvlist_add_uint64(rootVdev, ZPOOL_CONFIG_GUID, 0x5678));863/*864* Note: pools with previously-removed top-level VDEVs will contain a865* TLV in their labels that has 0 children.866*/867ASSERT_EQ(0, nvlist_add_nvlist_array(rootVdev, ZPOOL_CONFIG_CHILDREN,868NULL, 0));869ASSERT_EQ(0, nvlist_alloc(&poolConfig, NV_UNIQUE_NAME, 0));870ASSERT_EQ(0, nvlist_add_uint64(poolConfig,871ZPOOL_CONFIG_POOL_GUID, 0x1234));872ASSERT_EQ(0, nvlist_add_nvlist(poolConfig, ZPOOL_CONFIG_VDEV_TREE,873rootVdev));874875VdevIterator(poolConfig).Each(VdevIteratorTestCB, NULL);876}877878879