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