zfsd_unittest.cc revision 302408
1/*-
2 * Copyright (c) 2012, 2013, 2014 Spectra Logic Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions, and the following disclaimer,
10 *    without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 *    substantially similar to the "NO WARRANTY" disclaimer below
13 *    ("Disclaimer") and any redistribution must be conditioned upon
14 *    including a substantially similar Disclaimer requirement for further
15 *    binary redistribution.
16 *
17 * NO WARRANTY
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGES.
29 *
30 * Authors: Alan Somers         (Spectra Logic Corporation)
31 */
32#include <sys/cdefs.h>
33
34#include <stdarg.h>
35#include <syslog.h>
36
37#include <libnvpair.h>
38#include <libzfs.h>
39
40#include <list>
41#include <map>
42#include <sstream>
43#include <string>
44
45#include <gmock/gmock.h>
46#include <gtest/gtest.h>
47
48#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>
53
54#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>
62
63#include "libmocks.h"
64
65__FBSDID("$FreeBSD: stable/11/cddl/usr.sbin/zfsd/tests/zfsd_unittest.cc 300906 2016-05-28 17:43:40Z asomers $");
66
67/*================================== Macros ==================================*/
68#define	NUM_ELEMENTS(x) (sizeof(x) / sizeof(*x))
69
70/*============================ Namespace Control =============================*/
71using std::string;
72using std::stringstream;
73
74using DevdCtl::Event;
75using DevdCtl::EventBuffer;
76using DevdCtl::EventFactory;
77using DevdCtl::EventList;
78using DevdCtl::Guid;
79using DevdCtl::NVPairMap;
80
81/* redefine zpool_handle here because libzfs_impl.h is not includable */
82struct zpool_handle
83{
84        libzfs_handle_t *zpool_hdl;
85        zpool_handle_t *zpool_next;
86        char zpool_name[ZPOOL_MAXNAMELEN];
87        int zpool_state;
88        size_t zpool_config_size;
89        nvlist_t *zpool_config;
90        nvlist_t *zpool_old_config;
91        nvlist_t *zpool_props;
92        diskaddr_t zpool_start_block;
93};
94
95class MockZfsEvent : public ZfsEvent
96{
97public:
98	MockZfsEvent(Event::Type, NVPairMap&, const string&);
99	virtual ~MockZfsEvent() {}
100
101	static BuildMethod MockZfsEventBuilder;
102
103	MOCK_CONST_METHOD0(ProcessPoolEvent, void());
104
105	static EventFactory::Record s_buildRecords[];
106};
107
108EventFactory::Record MockZfsEvent::s_buildRecords[] =
109{
110        { Event::NOTIFY, "ZFS", &MockZfsEvent::MockZfsEventBuilder }
111};
112
113MockZfsEvent::MockZfsEvent(Event::Type type, NVPairMap& map,
114			   const string& str)
115 : ZfsEvent(type, map, str)
116{
117}
118
119Event *
120MockZfsEvent::MockZfsEventBuilder(Event::Type type,
121				  NVPairMap &nvpairs,
122			  	  const string &eventString)
123{
124	return (new MockZfsEvent(type, nvpairs, eventString));
125}
126
127/*
128 * A dummy Vdev class used for testing other classes
129 */
130class MockVdev : public Vdev
131{
132public:
133	MockVdev(nvlist_t *vdevConfig);
134	virtual ~MockVdev() {}
135
136	MOCK_CONST_METHOD0(GUID, Guid());
137	MOCK_CONST_METHOD0(PoolGUID, Guid());
138	MOCK_CONST_METHOD0(State, vdev_state());
139	MOCK_CONST_METHOD0(PhysicalPath, string());
140};
141
142MockVdev::MockVdev(nvlist_t *vdevConfig)
143 : Vdev(vdevConfig)
144{
145}
146
147/*
148 * A CaseFile class with side effects removed, for testing
149 */
150class TestableCaseFile : public CaseFile
151{
152public:
153	static TestableCaseFile &Create(Vdev &vdev);
154	TestableCaseFile(Vdev &vdev);
155	virtual ~TestableCaseFile() {}
156
157	MOCK_METHOD0(Close, void());
158	MOCK_METHOD1(RegisterCallout, void(const Event &event));
159	MOCK_METHOD0(RefreshVdevState, bool());
160	MOCK_METHOD1(ReEvaluate, bool(const ZfsEvent &event));
161
162	bool RealReEvaluate(const ZfsEvent &event)
163	{
164		return (CaseFile::ReEvaluate(event));
165	}
166
167	/*
168	 * This splices the event lists, a procedure that would normally be done
169	 * by OnGracePeriodEnded, but we don't necessarily call that in the
170	 * unit tests
171	 */
172	void SpliceEvents();
173
174	/*
175	 * Used by some of our expectations.  CaseFile does not publicize this
176	 */
177	static int getActiveCases()
178	{
179		return (s_activeCases.size());
180	}
181};
182
183TestableCaseFile::TestableCaseFile(Vdev &vdev)
184 : CaseFile(vdev)
185{
186}
187
188TestableCaseFile &
189TestableCaseFile::Create(Vdev &vdev)
190{
191	TestableCaseFile *newCase;
192	newCase = new TestableCaseFile(vdev);
193	return (*newCase);
194}
195
196void
197TestableCaseFile::SpliceEvents()
198{
199	m_events.splice(m_events.begin(), m_tentativeEvents);
200}
201
202
203/*
204 * Test class ZfsdException
205 */
206class ZfsdExceptionTest : public ::testing::Test
207{
208protected:
209	virtual void SetUp()
210	{
211		ASSERT_EQ(0, nvlist_alloc(&poolConfig, NV_UNIQUE_NAME, 0));
212		ASSERT_EQ(0, nvlist_add_string(poolConfig,
213				ZPOOL_CONFIG_POOL_NAME, "unit_test_pool"));
214		ASSERT_EQ(0, nvlist_add_uint64(poolConfig,
215				ZPOOL_CONFIG_POOL_GUID, 0x1234));
216
217		ASSERT_EQ(0, nvlist_alloc(&vdevConfig, NV_UNIQUE_NAME, 0));
218		ASSERT_EQ(0, nvlist_add_uint64(vdevConfig,
219				ZPOOL_CONFIG_GUID, 0x5678));
220		bzero(&poolHandle, sizeof(poolHandle));
221		poolHandle.zpool_config = poolConfig;
222	}
223
224	virtual void TearDown()
225	{
226		nvlist_free(poolConfig);
227		nvlist_free(vdevConfig);
228	}
229
230	nvlist_t	*poolConfig;
231	nvlist_t	*vdevConfig;
232	zpool_handle_t   poolHandle;
233};
234
235TEST_F(ZfsdExceptionTest, StringConstructorNull)
236{
237	ZfsdException ze("");
238	EXPECT_STREQ("", ze.GetString().c_str());
239}
240
241TEST_F(ZfsdExceptionTest, StringConstructorFormatted)
242{
243	ZfsdException ze(" %d %s", 55, "hello world");
244	EXPECT_STREQ(" 55 hello world", ze.GetString().c_str());
245}
246
247TEST_F(ZfsdExceptionTest, LogSimple)
248{
249	ZfsdException ze("unit test w/o vdev or pool");
250	ze.Log();
251	EXPECT_EQ(LOG_ERR, syslog_last_priority);
252	EXPECT_STREQ("unit test w/o vdev or pool\n", syslog_last_message);
253}
254
255TEST_F(ZfsdExceptionTest, Pool)
256{
257	const char msg[] = "Exception with pool name";
258	char expected[4096];
259	sprintf(expected, "Pool unit_test_pool: %s\n", msg);
260	ZfsdException ze(poolConfig, msg);
261	ze.Log();
262	EXPECT_STREQ(expected, syslog_last_message);
263}
264
265TEST_F(ZfsdExceptionTest, PoolHandle)
266{
267	const char msg[] = "Exception with pool handle";
268	char expected[4096];
269	sprintf(expected, "Pool unit_test_pool: %s\n", msg);
270	ZfsdException ze(&poolHandle, msg);
271	ze.Log();
272	EXPECT_STREQ(expected, syslog_last_message);
273}
274
275/*
276 * Test class Vdev
277 */
278class VdevTest : public ::testing::Test
279{
280protected:
281	virtual void SetUp()
282	{
283		ASSERT_EQ(0, nvlist_alloc(&m_poolConfig, NV_UNIQUE_NAME, 0));
284		ASSERT_EQ(0, nvlist_add_uint64(m_poolConfig,
285					       ZPOOL_CONFIG_POOL_GUID,
286					       0x1234));
287
288		ASSERT_EQ(0, nvlist_alloc(&m_vdevConfig, NV_UNIQUE_NAME, 0));
289		ASSERT_EQ(0, nvlist_add_uint64(m_vdevConfig, ZPOOL_CONFIG_GUID,
290					       0x5678));
291	}
292
293	virtual void TearDown()
294	{
295		nvlist_free(m_poolConfig);
296		nvlist_free(m_vdevConfig);
297	}
298
299	nvlist_t	*m_poolConfig;
300	nvlist_t	*m_vdevConfig;
301};
302
303
304TEST_F(VdevTest, StateFromConfig)
305{
306	vdev_stat_t vs;
307
308	vs.vs_state = VDEV_STATE_OFFLINE;
309
310	ASSERT_EQ(0, nvlist_add_uint64_array(m_vdevConfig,
311					     ZPOOL_CONFIG_VDEV_STATS,
312					     (uint64_t*)&vs,
313					     sizeof(vs) / sizeof(uint64_t)));
314
315	Vdev vdev(m_poolConfig, m_vdevConfig);
316
317	EXPECT_EQ(VDEV_STATE_OFFLINE, vdev.State());
318}
319
320TEST_F(VdevTest, StateFaulted)
321{
322	ASSERT_EQ(0, nvlist_add_uint64(m_vdevConfig, ZPOOL_CONFIG_FAULTED, 1));
323
324	Vdev vdev(m_poolConfig, m_vdevConfig);
325
326	EXPECT_EQ(VDEV_STATE_FAULTED, vdev.State());
327}
328
329/*
330 * Test that we can construct a Vdev from the label information that is stored
331 * on an available spare drive
332 */
333TEST_F(VdevTest, ConstructAvailSpare)
334{
335	nvlist_t	*labelConfig;
336
337	ASSERT_EQ(0, nvlist_alloc(&labelConfig, NV_UNIQUE_NAME, 0));
338	ASSERT_EQ(0, nvlist_add_uint64(labelConfig, ZPOOL_CONFIG_GUID,
339				       1948339428197961030));
340	ASSERT_EQ(0, nvlist_add_uint64(labelConfig, ZPOOL_CONFIG_POOL_STATE,
341				       POOL_STATE_SPARE));
342
343	EXPECT_NO_THROW(Vdev vdev(labelConfig));
344
345	nvlist_free(labelConfig);
346}
347
348/* Available spares will always show the HEALTHY state */
349TEST_F(VdevTest, AvailSpareState) {
350	nvlist_t	*labelConfig;
351
352	ASSERT_EQ(0, nvlist_alloc(&labelConfig, NV_UNIQUE_NAME, 0));
353	ASSERT_EQ(0, nvlist_add_uint64(labelConfig, ZPOOL_CONFIG_GUID,
354				       1948339428197961030));
355	ASSERT_EQ(0, nvlist_add_uint64(labelConfig, ZPOOL_CONFIG_POOL_STATE,
356				       POOL_STATE_SPARE));
357
358	Vdev vdev(labelConfig);
359	EXPECT_EQ(VDEV_STATE_HEALTHY, vdev.State());
360
361	nvlist_free(labelConfig);
362}
363
364/* Test the Vdev::IsSpare method */
365TEST_F(VdevTest, IsSpare) {
366	Vdev notSpare(m_poolConfig, m_vdevConfig);
367	EXPECT_EQ(false, notSpare.IsSpare());
368
369	ASSERT_EQ(0, nvlist_add_uint64(m_vdevConfig, ZPOOL_CONFIG_IS_SPARE, 1));
370	Vdev isSpare(m_poolConfig, m_vdevConfig);
371	EXPECT_EQ(true, isSpare.IsSpare());
372}
373
374/*
375 * Test class ZFSEvent
376 */
377class ZfsEventTest : public ::testing::Test
378{
379protected:
380	virtual void SetUp()
381	{
382		m_eventFactory = new EventFactory();
383		m_eventFactory->UpdateRegistry(MockZfsEvent::s_buildRecords,
384		    NUM_ELEMENTS(MockZfsEvent::s_buildRecords));
385
386		m_event = NULL;
387	}
388
389	virtual void TearDown()
390	{
391		delete m_eventFactory;
392		delete m_event;
393	}
394
395	EventFactory	*m_eventFactory;
396	Event		*m_event;
397};
398
399TEST_F(ZfsEventTest, ProcessPoolEventGetsCalled)
400{
401	string evString("!system=ZFS "
402			"subsystem=ZFS "
403			"type=misc.fs.zfs.vdev_remove "
404			"pool_name=foo "
405			"pool_guid=9756779504028057996 "
406			"vdev_guid=1631193447431603339 "
407			"vdev_path=/dev/da1 "
408			"timestamp=1348871594");
409	m_event = Event::CreateEvent(*m_eventFactory, evString);
410	MockZfsEvent *mock_event = static_cast<MockZfsEvent*>(m_event);
411
412	EXPECT_CALL(*mock_event, ProcessPoolEvent()).Times(1);
413	mock_event->Process();
414}
415
416/*
417 * Test class CaseFile
418 */
419
420class CaseFileTest : public ::testing::Test
421{
422protected:
423	virtual void SetUp()
424	{
425		m_eventFactory = new EventFactory();
426		m_eventFactory->UpdateRegistry(MockZfsEvent::s_buildRecords,
427		    NUM_ELEMENTS(MockZfsEvent::s_buildRecords));
428
429		m_event = NULL;
430
431		nvlist_alloc(&m_vdevConfig, NV_UNIQUE_NAME, 0);
432		ASSERT_EQ(0, nvlist_add_uint64(m_vdevConfig,
433					       ZPOOL_CONFIG_GUID, 0xbeef));
434		m_vdev = new MockVdev(m_vdevConfig);
435		ON_CALL(*m_vdev, GUID())
436		    .WillByDefault(::testing::Return(Guid(123)));
437		ON_CALL(*m_vdev, PoolGUID())
438		    .WillByDefault(::testing::Return(Guid(456)));
439		ON_CALL(*m_vdev, State())
440		    .WillByDefault(::testing::Return(VDEV_STATE_HEALTHY));
441		m_caseFile = &TestableCaseFile::Create(*m_vdev);
442		ON_CALL(*m_caseFile, ReEvaluate(::testing::_))
443		    .WillByDefault(::testing::Invoke(m_caseFile, &TestableCaseFile::RealReEvaluate));
444		return;
445	}
446
447	virtual void TearDown()
448	{
449		delete m_caseFile;
450		nvlist_free(m_vdevConfig);
451		delete m_vdev;
452		delete m_event;
453		delete m_eventFactory;
454	}
455
456	nvlist_t		*m_vdevConfig;
457	MockVdev		*m_vdev;
458	TestableCaseFile 	*m_caseFile;
459	Event			*m_event;
460	EventFactory		*m_eventFactory;
461};
462
463/*
464 * A Vdev with no events should not be degraded or faulted
465 */
466TEST_F(CaseFileTest, HealthyVdev)
467{
468	EXPECT_FALSE(m_caseFile->ShouldDegrade());
469	EXPECT_FALSE(m_caseFile->ShouldFault());
470}
471
472/*
473 * A Vdev with only one event should not be degraded or faulted
474 * For performance reasons, RefreshVdevState should not be called.
475 */
476TEST_F(CaseFileTest, HealthyishVdev)
477{
478	string evString("!system=ZFS "
479			"class=ereport.fs.zfs.io "
480			"ena=12091638756982918145 "
481			"parent_guid=13237004955564865395 "
482			"parent_type=raidz "
483			"pool=testpool.4415 "
484			"pool_context=0 "
485			"pool_failmode=wait "
486			"pool_guid=456 "
487			"subsystem=ZFS "
488			"timestamp=1348867914 "
489			"type=ereport.fs.zfs.io "
490			"vdev_guid=123 "
491			"vdev_path=/dev/da400 "
492			"vdev_type=disk "
493			"zio_blkid=622 "
494			"zio_err=1 "
495			"zio_level=-2 "
496			"zio_object=0 "
497			"zio_objset=37 "
498			"zio_offset=25598976 "
499			"zio_size=1024");
500	m_event = Event::CreateEvent(*m_eventFactory, evString);
501	ZfsEvent *zfs_event = static_cast<ZfsEvent*>(m_event);
502
503	EXPECT_CALL(*m_caseFile, RefreshVdevState())
504	    .Times(::testing::Exactly(0));
505	EXPECT_TRUE(m_caseFile->ReEvaluate(*zfs_event));
506	EXPECT_FALSE(m_caseFile->ShouldDegrade());
507	EXPECT_FALSE(m_caseFile->ShouldFault());
508}
509
510/* The case file should be closed when its pool is destroyed */
511TEST_F(CaseFileTest, PoolDestroy)
512{
513	string evString("!system=ZFS "
514			"pool_name=testpool.4415 "
515			"pool_guid=456 "
516			"subsystem=ZFS "
517			"timestamp=1348867914 "
518			"type=misc.fs.zfs.pool_destroy ");
519	m_event = Event::CreateEvent(*m_eventFactory, evString);
520	ZfsEvent *zfs_event = static_cast<ZfsEvent*>(m_event);
521	EXPECT_CALL(*m_caseFile, Close());
522	EXPECT_TRUE(m_caseFile->ReEvaluate(*zfs_event));
523}
524
525/*
526 * A Vdev with a very large number of IO errors should fault
527 * For performance reasons, RefreshVdevState should be called at most once
528 */
529TEST_F(CaseFileTest, VeryManyIOErrors)
530{
531	EXPECT_CALL(*m_caseFile, RefreshVdevState())
532	    .Times(::testing::AtMost(1))
533	    .WillRepeatedly(::testing::Return(true));
534
535	for(int i=0; i<100; i++) {
536		stringstream evStringStream;
537		evStringStream <<
538			"!system=ZFS "
539			"class=ereport.fs.zfs.io "
540			"ena=12091638756982918145 "
541			"parent_guid=13237004955564865395 "
542			"parent_type=raidz "
543			"pool=testpool.4415 "
544			"pool_context=0 "
545			"pool_failmode=wait "
546			"pool_guid=456 "
547			"subsystem=ZFS "
548			"timestamp=";
549		evStringStream << i << " ";
550		evStringStream <<
551			"type=ereport.fs.zfs.io "
552			"vdev_guid=123 "
553			"vdev_path=/dev/da400 "
554			"vdev_type=disk "
555			"zio_blkid=622 "
556			"zio_err=1 "
557			"zio_level=-2 "
558			"zio_object=0 "
559			"zio_objset=37 "
560			"zio_offset=25598976 "
561			"zio_size=1024";
562		Event *event(Event::CreateEvent(*m_eventFactory,
563						evStringStream.str()));
564		ZfsEvent *zfs_event = static_cast<ZfsEvent*>(event);
565		EXPECT_TRUE(m_caseFile->ReEvaluate(*zfs_event));
566		delete event;
567	}
568
569	m_caseFile->SpliceEvents();
570	EXPECT_FALSE(m_caseFile->ShouldDegrade());
571	EXPECT_TRUE(m_caseFile->ShouldFault());
572}
573
574/*
575 * A Vdev with a very large number of checksum errors should degrade
576 * For performance reasons, RefreshVdevState should be called at most once
577 */
578TEST_F(CaseFileTest, VeryManyChecksumErrors)
579{
580	EXPECT_CALL(*m_caseFile, RefreshVdevState())
581	    .Times(::testing::AtMost(1))
582	    .WillRepeatedly(::testing::Return(true));
583
584	for(int i=0; i<100; i++) {
585		stringstream evStringStream;
586		evStringStream <<
587			"!system=ZFS "
588			"bad_cleared_bits=03000000000000803f50b00000000000 "
589			"bad_range_clears=0000000e "
590			"bad_range_sets=00000000 "
591			"bad_ranges=0000000000000010 "
592			"bad_ranges_min_gap=8 "
593			"bad_set_bits=00000000000000000000000000000000 "
594			"class=ereport.fs.zfs.checksum "
595			"ena=12272856582652437505 "
596			"parent_guid=5838204195352909894 "
597			"parent_type=raidz pool=testpool.7640 "
598			"pool_context=0 "
599			"pool_failmode=wait "
600			"pool_guid=456 "
601			"subsystem=ZFS timestamp=";
602		evStringStream << i << " ";
603		evStringStream <<
604			"type=ereport.fs.zfs.checksum "
605			"vdev_guid=123 "
606			"vdev_path=/mnt/tmp/file1.7702 "
607			"vdev_type=file "
608			"zio_blkid=0 "
609			"zio_err=0 "
610			"zio_level=0 "
611			"zio_object=3 "
612			"zio_objset=0 "
613			"zio_offset=16896 "
614			"zio_size=512";
615		Event *event(Event::CreateEvent(*m_eventFactory,
616						evStringStream.str()));
617		ZfsEvent *zfs_event = static_cast<ZfsEvent*>(event);
618		EXPECT_TRUE(m_caseFile->ReEvaluate(*zfs_event));
619		delete event;
620	}
621
622	m_caseFile->SpliceEvents();
623	EXPECT_TRUE(m_caseFile->ShouldDegrade());
624	EXPECT_FALSE(m_caseFile->ShouldFault());
625}
626
627/*
628 * Test CaseFile::ReEvaluateByGuid
629 */
630class ReEvaluateByGuidTest : public ::testing::Test
631{
632protected:
633	virtual void SetUp()
634	{
635		m_eventFactory = new EventFactory();
636		m_eventFactory->UpdateRegistry(MockZfsEvent::s_buildRecords,
637		    NUM_ELEMENTS(MockZfsEvent::s_buildRecords));
638		m_event = Event::CreateEvent(*m_eventFactory, s_evString);
639		nvlist_alloc(&m_vdevConfig, NV_UNIQUE_NAME, 0);
640		ASSERT_EQ(0, nvlist_add_uint64(m_vdevConfig,
641					       ZPOOL_CONFIG_GUID, 0xbeef));
642		m_vdev456 = new ::testing::NiceMock<MockVdev>(m_vdevConfig);
643		m_vdev789 = new ::testing::NiceMock<MockVdev>(m_vdevConfig);
644		ON_CALL(*m_vdev456, GUID())
645		    .WillByDefault(::testing::Return(Guid(123)));
646		ON_CALL(*m_vdev456, PoolGUID())
647		    .WillByDefault(::testing::Return(Guid(456)));
648		ON_CALL(*m_vdev456, State())
649		    .WillByDefault(::testing::Return(VDEV_STATE_HEALTHY));
650		ON_CALL(*m_vdev789, GUID())
651		    .WillByDefault(::testing::Return(Guid(123)));
652		ON_CALL(*m_vdev789, PoolGUID())
653		    .WillByDefault(::testing::Return(Guid(789)));
654		ON_CALL(*m_vdev789, State())
655		    .WillByDefault(::testing::Return(VDEV_STATE_HEALTHY));
656		m_caseFile456 = NULL;
657		m_caseFile789 = NULL;
658		return;
659	}
660
661	virtual void TearDown()
662	{
663		delete m_caseFile456;
664		delete m_caseFile789;
665		nvlist_free(m_vdevConfig);
666		delete m_vdev456;
667		delete m_vdev789;
668		delete m_event;
669		delete m_eventFactory;
670	}
671
672	static string			 s_evString;
673	nvlist_t			*m_vdevConfig;
674	::testing::NiceMock<MockVdev>	*m_vdev456;
675	::testing::NiceMock<MockVdev>	*m_vdev789;
676	TestableCaseFile 		*m_caseFile456;
677	TestableCaseFile 		*m_caseFile789;
678	Event				*m_event;
679	EventFactory			*m_eventFactory;
680};
681
682string ReEvaluateByGuidTest::s_evString(
683	"!system=ZFS "
684	"pool_guid=16271873792808333580 "
685	"pool_name=foo "
686	"subsystem=ZFS "
687	"timestamp=1360620391 "
688	"type=misc.fs.zfs.config_sync");
689
690
691/*
692 * Test the ReEvaluateByGuid method on an empty list of casefiles.
693 * We must create one event, even though it never gets used, because it will
694 * be passed by reference to ReEvaluateByGuid
695 */
696TEST_F(ReEvaluateByGuidTest, ReEvaluateByGuid_empty)
697{
698	ZfsEvent *zfs_event = static_cast<ZfsEvent*>(m_event);
699
700	EXPECT_EQ(0, TestableCaseFile::getActiveCases());
701	CaseFile::ReEvaluateByGuid(Guid(456), *zfs_event);
702	EXPECT_EQ(0, TestableCaseFile::getActiveCases());
703}
704
705/*
706 * Test the ReEvaluateByGuid method on a list of CaseFiles that contains only
707 * one CaseFile, which doesn't match the criteria
708 */
709TEST_F(ReEvaluateByGuidTest, ReEvaluateByGuid_oneFalse)
710{
711	m_caseFile456 = &TestableCaseFile::Create(*m_vdev456);
712	ZfsEvent *zfs_event = static_cast<ZfsEvent*>(m_event);
713
714	EXPECT_EQ(1, TestableCaseFile::getActiveCases());
715	EXPECT_CALL(*m_caseFile456, ReEvaluate(::testing::_))
716	    .Times(::testing::Exactly(0));
717	CaseFile::ReEvaluateByGuid(Guid(789), *zfs_event);
718	EXPECT_EQ(1, TestableCaseFile::getActiveCases());
719}
720
721/*
722 * Test the ReEvaluateByGuid method on a list of CaseFiles that contains only
723 * one CaseFile, which does match the criteria
724 */
725TEST_F(ReEvaluateByGuidTest, ReEvaluateByGuid_oneTrue)
726{
727	m_caseFile456 = &TestableCaseFile::Create(*m_vdev456);
728	ZfsEvent *zfs_event = static_cast<ZfsEvent*>(m_event);
729
730	EXPECT_EQ(1, TestableCaseFile::getActiveCases());
731	EXPECT_CALL(*m_caseFile456, ReEvaluate(::testing::_))
732	    .Times(::testing::Exactly(1))
733	    .WillRepeatedly(::testing::Return(false));
734	CaseFile::ReEvaluateByGuid(Guid(456), *zfs_event);
735	EXPECT_EQ(1, TestableCaseFile::getActiveCases());
736}
737
738/*
739 * Test the ReEvaluateByGuid method on a long list of CaseFiles that contains a
740 * few cases which meet the criteria
741 */
742TEST_F(ReEvaluateByGuidTest, ReEvaluateByGuid_five)
743{
744	TestableCaseFile *CaseFile1 = &TestableCaseFile::Create(*m_vdev456);
745	TestableCaseFile *CaseFile2 = &TestableCaseFile::Create(*m_vdev789);
746	TestableCaseFile *CaseFile3 = &TestableCaseFile::Create(*m_vdev456);
747	TestableCaseFile *CaseFile4 = &TestableCaseFile::Create(*m_vdev789);
748	TestableCaseFile *CaseFile5 = &TestableCaseFile::Create(*m_vdev789);
749	ZfsEvent *zfs_event = static_cast<ZfsEvent*>(m_event);
750
751	EXPECT_EQ(5, TestableCaseFile::getActiveCases());
752	EXPECT_CALL(*CaseFile1, ReEvaluate(::testing::_))
753	    .Times(::testing::Exactly(1))
754	    .WillRepeatedly(::testing::Return(false));
755	EXPECT_CALL(*CaseFile3, ReEvaluate(::testing::_))
756	    .Times(::testing::Exactly(1))
757	    .WillRepeatedly(::testing::Return(false));
758	EXPECT_CALL(*CaseFile2, ReEvaluate(::testing::_))
759	    .Times(::testing::Exactly(0));
760	EXPECT_CALL(*CaseFile4, ReEvaluate(::testing::_))
761	    .Times(::testing::Exactly(0));
762	EXPECT_CALL(*CaseFile5, ReEvaluate(::testing::_))
763	    .Times(::testing::Exactly(0));
764	CaseFile::ReEvaluateByGuid(Guid(456), *zfs_event);
765	EXPECT_EQ(5, TestableCaseFile::getActiveCases());
766	delete CaseFile1;
767	delete CaseFile2;
768	delete CaseFile3;
769	delete CaseFile4;
770	delete CaseFile5;
771}
772