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&);
~MockZfsEvent()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
MockZfsEvent(Event::Type type,NVPairMap & map,const string & str)113 MockZfsEvent::MockZfsEvent(Event::Type type, NVPairMap& map,
114 const string& str)
115 : ZfsEvent(type, map, str)
116 {
117 }
118
119 Event *
MockZfsEventBuilder(Event::Type type,NVPairMap & nvpairs,const string & eventString)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);
~MockVdev()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
MockVdev(nvlist_t * vdevConfig)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);
~TestableCaseFile()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
RealReEvaluate(const ZfsEvent & event)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 */
getActiveCases()177 static int getActiveCases()
178 {
179 return (s_activeCases.size());
180 }
181 };
182
TestableCaseFile(Vdev & vdev)183 TestableCaseFile::TestableCaseFile(Vdev &vdev)
184 : CaseFile(vdev)
185 {
186 }
187
188 TestableCaseFile &
Create(Vdev & vdev)189 TestableCaseFile::Create(Vdev &vdev)
190 {
191 TestableCaseFile *newCase;
192 newCase = new TestableCaseFile(vdev);
193 return (*newCase);
194 }
195
196 void
SpliceEvents()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:
SetUp()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
TearDown()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
TEST_F(ZfsdExceptionTest,StringConstructorNull)235 TEST_F(ZfsdExceptionTest, StringConstructorNull)
236 {
237 ZfsdException ze("");
238 EXPECT_STREQ("", ze.GetString().c_str());
239 }
240
TEST_F(ZfsdExceptionTest,StringConstructorFormatted)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
TEST_F(ZfsdExceptionTest,LogSimple)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
TEST_F(ZfsdExceptionTest,Pool)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
TEST_F(ZfsdExceptionTest,PoolHandle)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:
SetUp()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
TearDown()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
TEST_F(VdevTest,StateFromConfig)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
TEST_F(VdevTest,StateFaulted)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 */
TEST_F(VdevTest,ConstructAvailSpare)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 */
TEST_F(VdevTest,AvailSpareState)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 */
TEST_F(VdevTest,IsSpare)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:
SetUp()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
TearDown()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
TEST_F(ZfsEventTest,ProcessPoolEventGetsCalled)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:
SetUp()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
TearDown()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 */
TEST_F(CaseFileTest,HealthyVdev)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 */
TEST_F(CaseFileTest,HealthyishVdev)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 */
TEST_F(CaseFileTest,PoolDestroy)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 */
TEST_F(CaseFileTest,VeryManyIOErrors)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 */
TEST_F(CaseFileTest,VeryManyChecksumErrors)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:
SetUp()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
TearDown()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 */
TEST_F(ReEvaluateByGuidTest,ReEvaluateByGuid_empty)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 */
TEST_F(ReEvaluateByGuidTest,ReEvaluateByGuid_oneFalse)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 */
TEST_F(ReEvaluateByGuidTest,ReEvaluateByGuid_oneTrue)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 */
TEST_F(ReEvaluateByGuidTest,ReEvaluateByGuid_five)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