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=sysevent.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=sysevent.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=sysevent.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