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 #include <sys/byteorder.h>
34 
35 #include <stdarg.h>
36 #include <syslog.h>
37 
38 #include <libnvpair.h>
39 #include <libzfs.h>
40 
41 #include <list>
42 #include <map>
43 #include <sstream>
44 #include <string>
45 
46 #include <gmock/gmock.h>
47 #include <gtest/gtest.h>
48 
49 #include <devdctl/guid.h>
50 #include <devdctl/event.h>
51 #include <devdctl/event_factory.h>
52 #include <devdctl/exception.h>
53 #include <devdctl/consumer.h>
54 
55 #include <zfsd/callout.h>
56 #include <zfsd/vdev_iterator.h>
57 #include <zfsd/zfsd_event.h>
58 #include <zfsd/case_file.h>
59 #include <zfsd/vdev.h>
60 #include <zfsd/zfsd.h>
61 #include <zfsd/zfsd_exception.h>
62 #include <zfsd/zpool_list.h>
63 
64 #include "libmocks.h"
65 
66 __FBSDID("$FreeBSD$");
67 
68 /*================================== Macros ==================================*/
69 #define	NUM_ELEMENTS(x) (sizeof(x) / sizeof(*x))
70 
71 /*============================ Namespace Control =============================*/
72 using std::string;
73 using std::stringstream;
74 
75 using DevdCtl::Event;
76 using DevdCtl::EventFactory;
77 using DevdCtl::EventList;
78 using DevdCtl::Guid;
79 using DevdCtl::NVPairMap;
80 
81 /* redefine zpool_handle here because libzfs_impl.h is not includable */
82 struct zpool_handle
83 {
84         libzfs_handle_t *zpool_hdl;
85         zpool_handle_t *zpool_next;
86         char zpool_name[ZFS_MAX_DATASET_NAME_LEN];
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 
95 class MockZfsEvent : public ZfsEvent
96 {
97 public:
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 
108 EventFactory::Record MockZfsEvent::s_buildRecords[] =
109 {
110         { Event::NOTIFY, "ZFS", &MockZfsEvent::MockZfsEventBuilder }
111 };
112 
113 MockZfsEvent::MockZfsEvent(Event::Type type, NVPairMap& map,
114 			   const string& str)
115  : ZfsEvent(type, map, str)
116 {
117 }
118 
119 Event *
120 MockZfsEvent::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  */
130 class MockVdev : public Vdev
131 {
132 public:
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 
142 MockVdev::MockVdev(nvlist_t *vdevConfig)
143  : Vdev(vdevConfig)
144 {
145 }
146 
147 /*
148  * A CaseFile class with side effects removed, for testing
149  */
150 class TestableCaseFile : public CaseFile
151 {
152 public:
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 
183 TestableCaseFile::TestableCaseFile(Vdev &vdev)
184  : CaseFile(vdev)
185 {
186 }
187 
188 TestableCaseFile &
189 TestableCaseFile::Create(Vdev &vdev)
190 {
191 	TestableCaseFile *newCase;
192 	newCase = new TestableCaseFile(vdev);
193 	return (*newCase);
194 }
195 
196 void
197 TestableCaseFile::SpliceEvents()
198 {
199 	m_events.splice(m_events.begin(), m_tentativeEvents);
200 }
201 
202 
203 /*
204  * Test class ZfsdException
205  */
206 class ZfsdExceptionTest : public ::testing::Test
207 {
208 protected:
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 
235 TEST_F(ZfsdExceptionTest, StringConstructorNull)
236 {
237 	ZfsdException ze("");
238 	EXPECT_STREQ("", ze.GetString().c_str());
239 }
240 
241 TEST_F(ZfsdExceptionTest, StringConstructorFormatted)
242 {
243 	ZfsdException ze(" %d %s", 55, "hello world");
244 	EXPECT_STREQ(" 55 hello world", ze.GetString().c_str());
245 }
246 
247 TEST_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 
255 TEST_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 
265 TEST_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  */
278 class VdevTest : public ::testing::Test
279 {
280 protected:
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 
304 TEST_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 
320 TEST_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  */
333 TEST_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 */
349 TEST_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 */
365 TEST_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  */
377 class ZfsEventTest : public ::testing::Test
378 {
379 protected:
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 
399 TEST_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 
420 class CaseFileTest : public ::testing::Test
421 {
422 protected:
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  */
466 TEST_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  */
476 TEST_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 */
511 TEST_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  */
529 TEST_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  */
578 TEST_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  */
630 class ReEvaluateByGuidTest : public ::testing::Test
631 {
632 protected:
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 
682 string 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  */
696 TEST_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  */
709 TEST_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  */
725 TEST_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  */
742 TEST_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