/*
* Copyright (c) 2017 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef Metis_testrig_MetisIoOperations_h
#define Metis_testrig_MetisIoOperations_h
/**
* Setup a test rig around a MetisIoOperation so we have visibility in to
* what the connection table is doing
*
* Usage: Use mockIoOperationsData_Create()
or mockIoOperationsData_CreateSimple()
* to create the MetisIoOperations. You can then inspect the TestData inside the context
* by mapping TestData *data = (TestData *) metisIoOperations_GetClosure(ops)
.
*
* IMPORTANT: ops->destroy(&ops) will not destroy the test rig. It will increment a counter.
* you must call testdata_Destroy(&ops)
yourself. You should call this
* as the very last thing, even after metisForwarder_Destroy()
, if you put
* the MetisIoOpereations in the connection table.
*/
static bool mockIoOperations_Send(MetisIoOperations *ops, const CPIAddress *nexthop, MetisMessage *message);
static const CPIAddress *mockIoOperations_GetRemoteAddress(const MetisIoOperations *ops);
static const MetisAddressPair *mockIoOperations_GetAddressPair(const MetisIoOperations *ops);
static bool mockIoOperations_IsUp(const MetisIoOperations *ops);
static bool mockIoOperations_IsLocal(const MetisIoOperations *ops);
static unsigned mockIoOperations_GetConnectionId(const MetisIoOperations *ops);
static void mockIoOperations_Destroy(MetisIoOperations **opsPtr);
static CPIConnectionType mockIoOperations_GetConnectionType(const MetisIoOperations *ops);
static const void *mockIoOperations_Class(const MetisIoOperations *ops);
static MetisIoOperations mockIoOperationsTemplate = {
.closure = NULL,
.send = &mockIoOperations_Send,
.getRemoteAddress = &mockIoOperations_GetRemoteAddress,
.getAddressPair = &mockIoOperations_GetAddressPair,
.isUp = &mockIoOperations_IsUp,
.isLocal = &mockIoOperations_IsLocal,
.getConnectionId = &mockIoOperations_GetConnectionId,
.destroy = &mockIoOperations_Destroy,
.getConnectionType = &mockIoOperations_GetConnectionType,
.class = &mockIoOperations_Class
};
typedef struct mock_io_operations_data {
// counters for each call
unsigned sendCount;
unsigned getRemoteAddressCount;
unsigned getAddressPairCount;
unsigned isUpCount;
unsigned isLocalCount;
unsigned getConnectionIdCount;
unsigned destroyCount;
unsigned getConnectionTypeCount;
unsigned classCount;
MetisMessage *lastMessage;
MetisAddressPair *addressPair;
unsigned id;
bool isUp;
bool isLocal;
bool sendResult; // what to return when send() called
CPIConnectionType connType;
} MockIoOperationsData;
/**
* @function testdata_Create
* @abstract Creates a data set for testing MetisIoOperations
* @discussion
* Caller must explicitly use testdata_Destroy()
when done. Calling the destroyer through
* the io operations only increments counters, it does not destroy the object.
*
* @param <#param1#>
* @return <#return#>
*/
static MetisIoOperations *
mockIoOperationsData_Create(MetisAddressPair *pair, unsigned id, bool isUp, bool sendResult, bool isLocal, CPIConnectionType connType)
{
MockIoOperationsData *data = parcMemory_AllocateAndClear(sizeof(MockIoOperationsData));
data->addressPair = pair;
data->id = id;
data->isUp = isUp;
data->sendResult = sendResult;
data->lastMessage = NULL;
data->isLocal = isLocal;
data->connType = connType;
MetisIoOperations *ops = parcMemory_AllocateAndClear(sizeof(MetisIoOperations));
memcpy(ops, &mockIoOperationsTemplate, sizeof(MetisIoOperations));
ops->closure = data;
return ops;
}
/**
* @function testdata_CreateSimple
* @abstract Creates a data set for testing MetisIoOperations
* @discussion
* Caller must explicitly use testdata_Destroy()
when done. Calling the destroyer through
* the io operations only increments counters, it does not destroy the object.
*
* @param <#param1#>
* @return <#return#>
*/
static MetisIoOperations *
mockIoOperationsData_CreateSimple(unsigned addressLocal, unsigned addressRemote, unsigned id, bool isUp, bool sendResult, bool isLocal)
{
CPIAddress *local = cpiAddress_CreateFromInterface(addressLocal);
CPIAddress *remote = cpiAddress_CreateFromInterface(addressRemote);
MetisAddressPair *pair = metisAddressPair_Create(local, remote);
MetisIoOperations *ops = mockIoOperationsData_Create(pair, id, isUp, sendResult, isLocal, cpiConnection_UDP);
cpiAddress_Destroy(&local);
cpiAddress_Destroy(&remote);
return ops;
}
static void
mockIoOperationsData_Destroy(MetisIoOperations **opsPtr)
{
MetisIoOperations *ops = *opsPtr;
MockIoOperationsData *data = (MockIoOperationsData *) metisIoOperations_GetClosure(ops);
metisAddressPair_Release(&data->addressPair);
if (data->lastMessage) {
metisMessage_Release(&data->lastMessage);
}
parcMemory_Deallocate((void **) &data);
ops->closure = NULL;
parcMemory_Deallocate((void **) &ops);
*opsPtr = NULL;
}
static bool
mockIoOperations_Send(MetisIoOperations *ops, const CPIAddress *nexthop, MetisMessage *message)
{
MockIoOperationsData *data = (MockIoOperationsData *) metisIoOperations_GetClosure(ops);
data->sendCount++;
if (message) {
if (data->lastMessage) {
metisMessage_Release(&data->lastMessage);
}
data->lastMessage = metisMessage_Acquire(message);
}
return data->sendResult;
}
static const CPIAddress *
mockIoOperations_GetRemoteAddress(const MetisIoOperations *ops)
{
MockIoOperationsData *data = (MockIoOperationsData *) metisIoOperations_GetClosure(ops);
data->getRemoteAddressCount++;
return metisAddressPair_GetRemote(data->addressPair);
}
static const MetisAddressPair *
mockIoOperations_GetAddressPair(const MetisIoOperations *ops)
{
MockIoOperationsData *data = (MockIoOperationsData *) metisIoOperations_GetClosure(ops);
data->getAddressPairCount++;
return data->addressPair;
}
static bool
mockIoOperations_IsUp(const MetisIoOperations *ops)
{
MockIoOperationsData *data = (MockIoOperationsData *) metisIoOperations_GetClosure(ops);
data->isUpCount++;
return data->isUp;
}
static bool
mockIoOperations_IsLocal(const MetisIoOperations *ops)
{
MockIoOperationsData *data = (MockIoOperationsData *) metisIoOperations_GetClosure(ops);
data->isLocalCount++;
return data->isLocal;
}
static unsigned
mockIoOperations_GetConnectionId(const MetisIoOperations *ops)
{
MockIoOperationsData *data = (MockIoOperationsData *) metisIoOperations_GetClosure(ops);
data->getConnectionIdCount++;
return data->id;
}
static void
mockIoOperations_Destroy(MetisIoOperations **opsPtr)
{
MockIoOperationsData *data = (MockIoOperationsData *) (*opsPtr)->closure;
data->destroyCount++;
*opsPtr = NULL;
}
static CPIConnectionType
mockIoOperations_GetConnectionType(const MetisIoOperations *ops)
{
MockIoOperationsData *data = (MockIoOperationsData *) metisIoOperations_GetClosure(ops);
data->getConnectionTypeCount++;
return data->connType;
}
static const void *
mockIoOperations_Class(const MetisIoOperations *ops)
{
MockIoOperationsData *data = (MockIoOperationsData *) metisIoOperations_GetClosure(ops);
data->classCount++;
return __FILE__;
}
#endif // Metis_testrig_MetisIoOperations_h