+
+TEST_F(SynchronizedLockTest, UpgradableLocking) {
+ folly::Synchronized<int, FakeAllPowerfulAssertingMutex> sync;
+
+ // sanity assert
+ static_assert(
+ std::is_same<std::decay<decltype(*sync.ulock())>::type, int>::value,
+ "The ulock function was not well configured, blame aary@instagram.com");
+
+ {
+ auto ulock = sync.ulock();
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::UPGRADE);
+ }
+
+ // should be unlocked here
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::UNLOCKED);
+
+ // test going from upgrade to exclusive
+ {
+ auto ulock = sync.ulock();
+ auto wlock = ulock.moveFromUpgradeToWrite();
+ EXPECT_EQ(static_cast<bool>(ulock), false);
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::UNIQUE);
+ }
+
+ // should be unlocked here
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::UNLOCKED);
+
+ // test going from upgrade to shared
+ {
+ auto ulock = sync.ulock();
+ auto slock = ulock.moveFromUpgradeToShared();
+ EXPECT_EQ(static_cast<bool>(ulock), false);
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::SHARED);
+ }
+
+ // should be unlocked here
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::UNLOCKED);
+
+ // test going from exclusive to upgrade
+ {
+ auto wlock = sync.wlock();
+ auto ulock = wlock.moveFromWriteToUpgrade();
+ EXPECT_EQ(static_cast<bool>(wlock), false);
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::UPGRADE);
+ }
+
+ // should be unlocked here
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::UNLOCKED);
+
+ // test going from exclusive to shared
+ {
+ auto wlock = sync.wlock();
+ auto slock = wlock.moveFromWriteToShared();
+ EXPECT_EQ(static_cast<bool>(wlock), false);
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::SHARED);
+ }
+
+ // should be unlocked here
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::UNLOCKED);
+}
+
+TEST_F(SynchronizedLockTest, UpgradableLockingWithULock) {
+ folly::Synchronized<int, FakeAllPowerfulAssertingMutex> sync;
+
+ // sanity assert
+ static_assert(
+ std::is_same<std::decay<decltype(*sync.ulock())>::type, int>::value,
+ "The ulock function was not well configured, blame aary@instagram.com");
+
+ // test from upgrade to write
+ sync.withULockPtr([](auto ulock) {
+ EXPECT_EQ(static_cast<bool>(ulock), true);
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::UPGRADE);
+
+ auto wlock = ulock.moveFromUpgradeToWrite();
+ EXPECT_EQ(static_cast<bool>(ulock), false);
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::UNIQUE);
+ });
+
+ // should be unlocked here
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::UNLOCKED);
+
+ // test from write to upgrade
+ sync.withWLockPtr([](auto wlock) {
+ EXPECT_EQ(static_cast<bool>(wlock), true);
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::UNIQUE);
+
+ auto ulock = wlock.moveFromWriteToUpgrade();
+ EXPECT_EQ(static_cast<bool>(wlock), false);
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::UPGRADE);
+ });
+
+ // should be unlocked here
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::UNLOCKED);
+
+ // test from upgrade to shared
+ sync.withULockPtr([](auto ulock) {
+ EXPECT_EQ(static_cast<bool>(ulock), true);
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::UPGRADE);
+
+ auto slock = ulock.moveFromUpgradeToShared();
+ EXPECT_EQ(static_cast<bool>(ulock), false);
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::SHARED);
+ });
+
+ // should be unlocked here
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::UNLOCKED);
+
+ // test from write to shared
+ sync.withWLockPtr([](auto wlock) {
+ EXPECT_EQ(static_cast<bool>(wlock), true);
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::UNIQUE);
+
+ auto slock = wlock.moveFromWriteToShared();
+ EXPECT_EQ(static_cast<bool>(wlock), false);
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::SHARED);
+ });
+
+ // should be unlocked here
+ EXPECT_EQ(
+ globalAllPowerfulAssertingMutex.lock_state,
+ FakeAllPowerfulAssertingMutexInternal::CurrentLockState::UNLOCKED);
+}