/**
* Copyright (C) 2015 MongoDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#include "mongo/platform/basic.h"
#include "mongo/s/catalog/dist_lock_catalog_mock.h"
#include "mongo/base/status.h"
#include "mongo/base/status_with.h"
#include "mongo/s/catalog/type_lockpings.h"
#include "mongo/s/catalog/type_locks.h"
#include "mongo/unittest/unittest.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
namespace {
Status kBadRetValue(ErrorCodes::InternalError, "no return value");
StatusWith kLocksTypeBadRetValue(kBadRetValue);
StatusWith kLockpingsTypeBadRetValue(kBadRetValue);
StatusWith kServerInfoBadRetValue(kBadRetValue);
void noGrabLockFuncSet(StringData lockID,
const OID& lockSessionID,
StringData who,
StringData processId,
Date_t time,
StringData why) {
FAIL(str::stream() << "grabLock not expected to be called. "
<< "lockID: "
<< lockID
<< ", who: "
<< who
<< ", processId: "
<< processId
<< ", why: "
<< why);
}
void noOvertakeLockFuncSet(StringData lockID,
const OID& lockSessionID,
const OID& currentHolderTS,
StringData who,
StringData processId,
Date_t time,
StringData why) {
FAIL(str::stream() << "overtakeLock not expected to be called. "
<< "lockID: "
<< lockID
<< ", currentHolderTS: "
<< currentHolderTS
<< ", who: "
<< who
<< ", processId: "
<< processId
<< ", why: "
<< why);
}
void noUnLockFuncSet(const OID& lockSessionID) {
FAIL(str::stream() << "unlock not expected to be called. "
<< "lockSessionID: "
<< lockSessionID);
}
void noPingFuncSet(StringData processID, Date_t ping) {
// Ping is expected to be called all the time, so default behavior is do nothing.
}
void noStopPingFuncSet(StringData processID) {
FAIL(str::stream() << "stopPing not expected to be called. "
<< "processID: "
<< processID);
}
void noGetLockByTSSet(const OID& lockSessionID) {
FAIL(str::stream() << "getLockByTS not expected to be called. "
<< "lockSessionID: "
<< lockSessionID);
}
void noGetLockByNameSet(StringData name) {
FAIL(str::stream() << "getLockByName not expected to be called. "
<< "lockName: "
<< name);
}
void noGetPingSet(StringData processId) {
FAIL(str::stream() << "getPing not expected to be called. "
<< "lockName: "
<< processId);
}
void noGetServerInfoSet() {
FAIL("getServerInfo not expected to be called");
}
} // namespace
DistLockCatalogMock::DistLockCatalogMock()
: _grabLockChecker(noGrabLockFuncSet),
_grabLockReturnValue(kLocksTypeBadRetValue),
_unlockChecker(noUnLockFuncSet),
_unlockReturnValue(kBadRetValue),
_pingChecker(noPingFuncSet),
_pingReturnValue(kBadRetValue),
_stopPingChecker(noStopPingFuncSet),
_stopPingReturnValue(kBadRetValue),
_getLockByTSChecker(noGetLockByTSSet),
_getLockByTSReturnValue(kLocksTypeBadRetValue),
_getLockByNameChecker(noGetLockByNameSet),
_getLockByNameReturnValue(kLocksTypeBadRetValue),
_overtakeLockChecker(noOvertakeLockFuncSet),
_overtakeLockReturnValue(kLocksTypeBadRetValue),
_getPingChecker(noGetPingSet),
_getPingReturnValue(kLockpingsTypeBadRetValue),
_getServerInfoChecker(noGetServerInfoSet),
_getServerInfoReturnValue(kServerInfoBadRetValue) {}
DistLockCatalogMock::~DistLockCatalogMock() {}
StatusWith DistLockCatalogMock::getPing(OperationContext* opCtx,
StringData processID) {
auto ret = kLockpingsTypeBadRetValue;
GetPingFunc checkerFunc = noGetPingSet;
{
stdx::lock_guard lk(_mutex);
ret = _getPingReturnValue;
checkerFunc = _getPingChecker;
}
checkerFunc(processID);
return ret;
}
Status DistLockCatalogMock::ping(OperationContext* opCtx, StringData processID, Date_t ping) {
auto ret = kBadRetValue;
PingFunc checkerFunc = noPingFuncSet;
{
stdx::lock_guard lk(_mutex);
ret = _pingReturnValue;
checkerFunc = _pingChecker;
}
checkerFunc(processID, ping);
return ret;
}
StatusWith DistLockCatalogMock::grabLock(OperationContext* opCtx,
StringData lockID,
const OID& lockSessionID,
StringData who,
StringData processId,
Date_t time,
StringData why,
const WriteConcernOptions& writeConcern) {
auto ret = kLocksTypeBadRetValue;
GrabLockFunc checkerFunc = noGrabLockFuncSet;
{
stdx::lock_guard lk(_mutex);
ret = _grabLockReturnValue;
checkerFunc = _grabLockChecker;
}
checkerFunc(lockID, lockSessionID, who, processId, time, why);
return ret;
}
StatusWith DistLockCatalogMock::overtakeLock(OperationContext* opCtx,
StringData lockID,
const OID& lockSessionID,
const OID& currentHolderTS,
StringData who,
StringData processId,
Date_t time,
StringData why) {
auto ret = kLocksTypeBadRetValue;
OvertakeLockFunc checkerFunc = noOvertakeLockFuncSet;
{
stdx::lock_guard lk(_mutex);
ret = _overtakeLockReturnValue;
checkerFunc = _overtakeLockChecker;
}
checkerFunc(lockID, lockSessionID, currentHolderTS, who, processId, time, why);
return ret;
}
Status DistLockCatalogMock::unlock(OperationContext* opCtx, const OID& lockSessionID) {
auto ret = kBadRetValue;
UnlockFunc checkerFunc = noUnLockFuncSet;
{
stdx::lock_guard lk(_mutex);
ret = _unlockReturnValue;
checkerFunc = _unlockChecker;
}
checkerFunc(lockSessionID);
return ret;
}
Status DistLockCatalogMock::unlock(OperationContext* opCtx,
const OID& lockSessionID,
StringData name) {
auto ret = kBadRetValue;
UnlockFunc checkerFunc = noUnLockFuncSet;
{
stdx::lock_guard lk(_mutex);
ret = _unlockReturnValue;
checkerFunc = _unlockChecker;
}
checkerFunc(lockSessionID);
return ret;
}
StatusWith DistLockCatalogMock::getServerInfo(
OperationContext* opCtx) {
auto ret = kServerInfoBadRetValue;
GetServerInfoFunc checkerFunc = noGetServerInfoSet;
{
stdx::lock_guard lk(_mutex);
ret = _getServerInfoReturnValue;
checkerFunc = _getServerInfoChecker;
}
checkerFunc();
return ret;
}
StatusWith DistLockCatalogMock::getLockByTS(OperationContext* opCtx,
const OID& lockSessionID) {
auto ret = kLocksTypeBadRetValue;
GetLockByTSFunc checkerFunc = noGetLockByTSSet;
{
stdx::lock_guard lk(_mutex);
ret = _getLockByTSReturnValue;
checkerFunc = _getLockByTSChecker;
}
checkerFunc(lockSessionID);
return ret;
}
StatusWith DistLockCatalogMock::getLockByName(OperationContext* opCtx, StringData name) {
auto ret = kLocksTypeBadRetValue;
GetLockByNameFunc checkerFunc = noGetLockByNameSet;
{
stdx::lock_guard lk(_mutex);
ret = _getLockByNameReturnValue;
checkerFunc = _getLockByNameChecker;
}
checkerFunc(name);
return ret;
}
Status DistLockCatalogMock::stopPing(OperationContext* opCtx, StringData processId) {
auto ret = kBadRetValue;
StopPingFunc checkerFunc = noStopPingFuncSet;
{
stdx::lock_guard lk(_mutex);
ret = _stopPingReturnValue;
checkerFunc = _stopPingChecker;
}
checkerFunc(processId);
return ret;
}
void DistLockCatalogMock::expectGrabLock(DistLockCatalogMock::GrabLockFunc checkerFunc,
StatusWith returnThis) {
stdx::lock_guard lk(_mutex);
_grabLockChecker = checkerFunc;
_grabLockReturnValue = returnThis;
}
void DistLockCatalogMock::expectNoGrabLock() {
stdx::lock_guard lk(_mutex);
_grabLockChecker = noGrabLockFuncSet;
_grabLockReturnValue = kLocksTypeBadRetValue;
}
void DistLockCatalogMock::expectUnLock(DistLockCatalogMock::UnlockFunc checkerFunc,
Status returnThis) {
stdx::lock_guard lk(_mutex);
_unlockChecker = checkerFunc;
_unlockReturnValue = returnThis;
}
void DistLockCatalogMock::expectPing(DistLockCatalogMock::PingFunc checkerFunc, Status returnThis) {
stdx::lock_guard lk(_mutex);
_pingChecker = checkerFunc;
_pingReturnValue = returnThis;
}
void DistLockCatalogMock::expectStopPing(StopPingFunc checkerFunc, Status returnThis) {
stdx::lock_guard lk(_mutex);
_stopPingChecker = checkerFunc;
_stopPingReturnValue = returnThis;
}
void DistLockCatalogMock::expectGetLockByTS(GetLockByTSFunc checkerFunc,
StatusWith returnThis) {
stdx::lock_guard lk(_mutex);
_getLockByTSChecker = checkerFunc;
_getLockByTSReturnValue = returnThis;
}
void DistLockCatalogMock::expectGetLockByName(GetLockByNameFunc checkerFunc,
StatusWith returnThis) {
stdx::lock_guard lk(_mutex);
_getLockByNameChecker = checkerFunc;
_getLockByNameReturnValue = returnThis;
}
void DistLockCatalogMock::expectOvertakeLock(OvertakeLockFunc checkerFunc,
StatusWith returnThis) {
stdx::lock_guard lk(_mutex);
_overtakeLockChecker = checkerFunc;
_overtakeLockReturnValue = returnThis;
}
void DistLockCatalogMock::expectGetPing(GetPingFunc checkerFunc,
StatusWith returnThis) {
stdx::lock_guard lk(_mutex);
_getPingChecker = checkerFunc;
_getPingReturnValue = returnThis;
}
void DistLockCatalogMock::expectGetServerInfo(GetServerInfoFunc checkerFunc,
StatusWith returnThis) {
stdx::lock_guard lk(_mutex);
_getServerInfoChecker = checkerFunc;
_getServerInfoReturnValue = returnThis;
}
Status DistLockCatalogMock::unlockAll(OperationContext* opCtx, const std::string& processID) {
return Status(ErrorCodes::IllegalOperation,
str::stream() << "unlockAll not expected to be called; processID: " << processID);
}
} // namespace mongo