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