diff options
Diffstat (limited to 'metis/ccnx/forwarder/metis/config/test')
27 files changed, 5941 insertions, 0 deletions
diff --git a/metis/ccnx/forwarder/metis/config/test/CMakeLists.txt b/metis/ccnx/forwarder/metis/config/test/CMakeLists.txt new file mode 100644 index 00000000..7e14e1d5 --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/CMakeLists.txt @@ -0,0 +1,37 @@ +# Enable gcov output for the tests +add_definitions(--coverage) +set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage") + +set(TestsExpectedToPass + test_metis_ControlState + #test_metis_CommandLineInterface + test_metis_CommandOps + test_metis_CommandParser + test_metis_Configuration + test_metis_ConfigurationFile + test_metis_ConfigurationListeners + test_metis_SymbolicNameTable + test_metisControl_Add + test_metisControl_AddConnection + test_metisControl_AddListener + test_metisControl_AddRoute + test_metisControl_List + test_metisControl_ListConnections + test_metisControl_ListInterfaces + test_metisControl_ListRoutes + test_metisControl_Quit + test_metisControl_Remove + test_metisControl_RemoveConnection + test_metisControl_RemoveRoute + test_metisControl_Root + test_metisControl_Set + test_metisControl_SetDebug + test_metisControl_Unset + test_metisControl_UnsetDebug +) + + +foreach(test ${TestsExpectedToPass}) + AddTest(${test}) +endforeach() + diff --git a/metis/ccnx/forwarder/metis/config/test/test_metisControl_Add.c b/metis/ccnx/forwarder/metis/config/test/test_metisControl_Add.c new file mode 100644 index 00000000..c4001621 --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metisControl_Add.c @@ -0,0 +1,133 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metisControl_Add.c" + +#include <LongBow/unit-test.h> + +#include "testrig_MetisControl.c" + +LONGBOW_TEST_RUNNER(metisControl_Add) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metisControl_Add) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metisControl_Add) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisControlAdd_Create); + LONGBOW_RUN_TEST_CASE(Global, metisControlAdd_CreateHelp); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisControlAdd_Create) +{ + testCommandCreate(testCase, metisControlAdd_Create, __func__); +} + +LONGBOW_TEST_CASE(Global, metisControlAdd_CreateHelp) +{ + testCommandCreate(testCase, metisControlAdd_CreateHelp, __func__); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, _metisControlAdd_Execute); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAdd_Init); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAdd_HelpExecute); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, _metisControlAdd_Execute) +{ + testHelpExecute(testCase, metisControlAdd_Create, __func__, MetisCommandReturn_Success); +} + +/** + * Init should add 4 commands to the command parser + */ +LONGBOW_TEST_CASE(Local, _metisControlAdd_Init) +{ + testInit(testCase, metisControlAdd_Create, __func__, + (const char *[]) { + "add connection", "add route", + "help add connection", "help add route", + NULL + }); +} + +LONGBOW_TEST_CASE(Local, _metisControlAdd_HelpExecute) +{ + testHelpExecute(testCase, metisControlAdd_CreateHelp, __func__, MetisCommandReturn_Success); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metisControl_Add); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metisControl_AddConnection.c b/metis/ccnx/forwarder/metis/config/test/test_metisControl_AddConnection.c new file mode 100644 index 00000000..c98ab268 --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metisControl_AddConnection.c @@ -0,0 +1,473 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metisControl_AddConnection.c" +#include "testrig_MetisControl.c" + +LONGBOW_TEST_RUNNER(metisControl_AddConnection) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metisControl_AddConnection) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metisControl_AddConnection) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisControlAddConnection_Create); + LONGBOW_RUN_TEST_CASE(Global, metisControlAddConnection_HelpCreate); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisControlAddConnection_Create) +{ + testCommandCreate(testCase, &metisControlAddConnection_Create, __func__); +} + +LONGBOW_TEST_CASE(Global, metisControlAddConnection_HelpCreate) +{ + testCommandCreate(testCase, &metisControlAddConnection_HelpCreate, __func__); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_EtherCreate); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_EtherExecute); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_McastCreate); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_McastExecute); + + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_TcpCreate); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_TcpExecute); + + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_UdpCreate); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_UdpExecute); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_Execute); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_Init); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_ConvertStringsToCpiAddress); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_CreateTunnel); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_EtherHelpCreate); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_EtherHelpExecute); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_McastHelpCreate); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_McastHelpExecute); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_TcpHelpCreate); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_TcpHelpExecute); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_UdpHelpCreate); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_UdpHelpExecute); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_HelpExecute); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddConnection_IpHelp); + + LONGBOW_RUN_TEST_CASE(Local, metisControl_ParseIPCommandLine_TooFewArgs); + LONGBOW_RUN_TEST_CASE(Local, metisControl_ParseIPCommandLine_TooManyArgs); + LONGBOW_RUN_TEST_CASE(Local, metisControl_ParseIPCommandLine_BadRemoteIp); + LONGBOW_RUN_TEST_CASE(Local, metisControl_ParseIPCommandLine_GoodRemoteIp); + LONGBOW_RUN_TEST_CASE(Local, metisControl_ParseIPCommandLine_WithLocalIp); + LONGBOW_RUN_TEST_CASE(Local, metisControl_ParseIPCommandLine_WithLocalIpAndPort); + LONGBOW_RUN_TEST_CASE(Local, metisControl_ParseIPCommandLine_BadLocalIp); + LONGBOW_RUN_TEST_CASE(Local, metisControl_ParseIPCommandLine_MismatchLocalAndRemote); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_EtherCreate) +{ + testCommandCreate(testCase, &_metisControlAddConnection_EtherCreate, __func__); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_EtherExecute) +{ + const char *argv[] = { "add", "connection", "ether", "conn3", "e8-06-88-cd-28-de", "em3" }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, 6, (void **) &argv[0]); + + + TestData *data = longBowTestCase_GetClipBoardData(testCase); + MetisCommandOps *ops = _metisControlAddConnection_EtherCreate(data->state); + MetisCommandReturn result = ops->execute(data->state->parser, ops, args); + metisCommandOps_Destroy(&ops); + parcList_Release(&args); + assertTrue(result == MetisCommandReturn_Success, "Valid command line should succeed"); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_McastCreate) +{ + testCommandCreate(testCase, &_metisControlAddConnection_McastCreate, __func__); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_McastExecute) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + MetisCommandOps *ops = _metisControlAddConnection_McastCreate(data->state); + MetisCommandReturn result = ops->execute(data->state->parser, ops, NULL); + metisCommandOps_Destroy(&ops); + assertTrue(result == MetisCommandReturn_Failure, "Unimplemented execute should have failed"); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_TcpCreate) +{ + testCommandCreate(testCase, &_metisControlAddConnection_TcpCreate, __func__); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_TcpExecute) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + const char *argv[] = { "add", "connection", "tcp", "conn3", "1.2.3.4", "123" }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, 6, (void **) &argv[0]); + + MetisCommandOps *ops = _metisControlAddConnection_TcpCreate(data->state); + MetisCommandReturn result = ops->execute(data->state->parser, ops, args); + + metisCommandOps_Destroy(&ops); + parcList_Release(&args); + + assertTrue(result == MetisCommandReturn_Success, "Unimplemented execute should have failed"); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_UdpCreate) +{ + testCommandCreate(testCase, &_metisControlAddConnection_UdpCreate, __func__); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_UdpExecute) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + const char *argv[] = { "add", "connection", "tcp", "conn3", "1.2.3.4", "123" }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, 6, (void **) &argv[0]); + + MetisCommandOps *ops = _metisControlAddConnection_UdpCreate(data->state); + MetisCommandReturn result = ops->execute(data->state->parser, ops, args); + + metisCommandOps_Destroy(&ops); + parcList_Release(&args); + + assertTrue(result == MetisCommandReturn_Success, "Unimplemented execute should have failed"); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_Execute) +{ + // this just prints a Help message + testHelpExecute(testCase, metisControlAddConnection_Create, __func__, MetisCommandReturn_Success); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_Init) +{ + testInit(testCase, metisControlAddConnection_Create, __func__, + (const char *[]) { + _commandAddConnectionTcp, _commandAddConnectionUdp, _commandAddConnectionEther, _commandAddConnectionMcast, + _commandAddConnectionTcpHelp, _commandAddConnectionUdpHelp, _commandAddConnectionEtherHelp, _commandAddConnectionMcastHelp, + NULL + }); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_ConvertStringsToCpiAddress) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_CreateTunnel) +{ + // this is actully testred in the Tcp_Execute and Udp_Execute + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_EtherHelpCreate) +{ + testCommandCreate(testCase, &_metisControlAddConnection_EtherHelpCreate, __func__); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_EtherHelpExecute) +{ + testHelpExecute(testCase, _metisControlAddConnection_EtherHelpCreate, __func__, MetisCommandReturn_Success); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_McastHelpCreate) +{ + testCommandCreate(testCase, &_metisControlAddConnection_McastHelpCreate, __func__); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_McastHelpExecute) +{ + testHelpExecute(testCase, _metisControlAddConnection_McastHelpCreate, __func__, MetisCommandReturn_Success); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_TcpHelpCreate) +{ + testCommandCreate(testCase, &_metisControlAddConnection_TcpHelpCreate, __func__); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_TcpHelpExecute) +{ + testHelpExecute(testCase, _metisControlAddConnection_TcpHelpCreate, __func__, MetisCommandReturn_Success); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_UdpHelpCreate) +{ + testCommandCreate(testCase, &_metisControlAddConnection_UdpHelpCreate, __func__); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_UdpHelpExecute) +{ + testHelpExecute(testCase, _metisControlAddConnection_UdpHelpCreate, __func__, MetisCommandReturn_Success); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_HelpExecute) +{ + testHelpExecute(testCase, metisControlAddConnection_HelpCreate, __func__, MetisCommandReturn_Success); +} + +/** + * Expectes 5 to 7 options + */ +LONGBOW_TEST_CASE(Local, metisControl_ParseIPCommandLine_TooFewArgs) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + const char *argv[] = { "a", "b", "c" }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, 3, (void **) &argv[0]); + + MetisCommandOps *ops = _metisControlAddConnection_TcpCreate(data->state); + + CPIAddress *remote; + CPIAddress *local; + char *symbolic = NULL; + + MetisCommandReturn result = _metisControlAddConnection_ParseIPCommandLine(data->state->parser, ops, args, &remote, &local, &symbolic); + metisCommandOps_Destroy(&ops); + parcList_Release(&args); + + assertTrue(result == MetisCommandReturn_Failure, "ParseIPCommandLine with 3 args should have returned %d, got %d", MetisCommandReturn_Failure, result); +} + +/** + * Expects 5 to 7 options + */ +LONGBOW_TEST_CASE(Local, metisControl_ParseIPCommandLine_TooManyArgs) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + const char *argv[] = { "a", "b", "c", "d", "e", "f", "g", "h", "i" }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, 9, (void **) &argv[0]); + + MetisCommandOps *ops = _metisControlAddConnection_TcpCreate(data->state); + + CPIAddress *remote; + CPIAddress *local; + char *symbolic = NULL; + + MetisCommandReturn result = _metisControlAddConnection_ParseIPCommandLine(data->state->parser, ops, args, &remote, &local, &symbolic); + metisCommandOps_Destroy(&ops); + parcList_Release(&args); + + assertTrue(result == MetisCommandReturn_Failure, "ParseIPCommandLine with 3 args should have returned %d, got %d", MetisCommandReturn_Failure, result); +} + +LONGBOW_TEST_CASE(Local, metisControl_ParseIPCommandLine_BadRemoteIp) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + const char *argv[] = { "a", "b", "c", "tun0", "555.555.555.555", "123", }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, 6, (void **) &argv[0]); + + MetisCommandOps *ops = _metisControlAddConnection_TcpCreate(data->state); + + CPIAddress *remote; + CPIAddress *local; + char *symbolic = NULL; + + MetisCommandReturn result = _metisControlAddConnection_ParseIPCommandLine(data->state->parser, ops, args, &remote, &local, &symbolic); + metisCommandOps_Destroy(&ops); + parcList_Release(&args); + + assertTrue(result == MetisCommandReturn_Failure, "ParseIPCommandLine with invalid IP address should have returned %d, got %d", MetisCommandReturn_Failure, result); +} + +/** + * Pass a set of args to metisControl_ParseIPCommandLine, then verify: + * Successful + * remote_ip is what we gave it + * remote_port is what we gave it + * local_ip is 0.0.0.0 or what we gave it + * local_pot is 0 or what we gave it. + */ +static void +verifyParseIpWithGoodAddress(TestData *data, int argc, const char *remote_ip, const char *remote_port, const char *local_ip, const char *local_port) +{ + const char *argv[] = { "a", "b", "c", "tun0", remote_ip, remote_port, local_ip, local_port }; + + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, argc, (void **) &argv[0]); + + MetisCommandOps *ops = _metisControlAddConnection_TcpCreate(data->state); + + CPIAddress *remote; + CPIAddress *local; + char *symbolic = NULL; + + MetisCommandReturn result = _metisControlAddConnection_ParseIPCommandLine(data->state->parser, ops, args, &remote, &local, &symbolic); + metisCommandOps_Destroy(&ops); + parcList_Release(&args); + + assertTrue(result == MetisCommandReturn_Success, "ParseIPCommandLine with invalid IP address should have returned %d, got %d", MetisCommandReturn_Failure, result); + + struct sockaddr *sockaddr_remote = parcNetwork_SockAddress(remote_ip, atoi(remote_port)); + struct sockaddr *sockaddr_local = parcNetwork_SockAddress(local_ip, atoi(local_port)); + CPIAddress *truth_remote = cpiAddress_CreateFromInet((struct sockaddr_in *) sockaddr_remote); + CPIAddress *truth_local = cpiAddress_CreateFromInet((struct sockaddr_in *) sockaddr_local); + parcMemory_Deallocate((void **) &sockaddr_local); + parcMemory_Deallocate((void **) &sockaddr_remote); + + assertTrue(cpiAddress_Equals(truth_remote, remote), "Got wrong remote address"); + assertTrue(cpiAddress_Equals(truth_local, local), "Got wrong local address"); + cpiAddress_Destroy(&truth_remote); + cpiAddress_Destroy(&truth_local); + cpiAddress_Destroy(&remote); + cpiAddress_Destroy(&local); +} + +LONGBOW_TEST_CASE(Local, metisControl_ParseIPCommandLine_GoodRemoteIp) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + verifyParseIpWithGoodAddress(data, 6, "1.2.3.4", "123", "0.0.0.0", "0"); +} + +LONGBOW_TEST_CASE(Local, metisControl_ParseIPCommandLine_WithLocalIp) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + verifyParseIpWithGoodAddress(data, 7, "1.2.3.4", "123", "10.11.12.13", "0"); +} + +LONGBOW_TEST_CASE(Local, metisControl_ParseIPCommandLine_WithLocalIpAndPort) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + verifyParseIpWithGoodAddress(data, 8, "1.2.3.4", "123", "10.11.12.13", "456"); +} + +LONGBOW_TEST_CASE(Local, metisControl_ParseIPCommandLine_BadLocalIp) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + const char *argv[] = { "a", "b", "c", "tun0", "1.2.3.4", "123", "666.666.666.666", "123", }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, 8, (void **) &argv[0]); + + MetisCommandOps *ops = _metisControlAddConnection_TcpCreate(data->state); + + CPIAddress *remote; + CPIAddress *local; + char *symbolic = NULL; + + MetisCommandReturn result = _metisControlAddConnection_ParseIPCommandLine(data->state->parser, ops, args, &remote, &local, &symbolic); + metisCommandOps_Destroy(&ops); + parcList_Release(&args); + + assertTrue(result == MetisCommandReturn_Failure, "ParseIPCommandLine with invalid local IP address should have returned %d, got %d", MetisCommandReturn_Failure, result); +} + +/** + * One's an IPv4 and one's an IPv6. + */ +LONGBOW_TEST_CASE(Local, metisControl_ParseIPCommandLine_MismatchLocalAndRemote) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + const char *argv[] = { "a", "b", "c", "tun0", "1.2.3.4", "123", "2001:720:1500:1::a100", "123", }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, 8, (void **) &argv[0]); + + MetisCommandOps *ops = _metisControlAddConnection_TcpCreate(data->state); + + CPIAddress *remote; + CPIAddress *local; + char *symbolic = NULL; + + MetisCommandReturn result = _metisControlAddConnection_ParseIPCommandLine(data->state->parser, ops, args, &remote, &local, &symbolic); + metisCommandOps_Destroy(&ops); + parcList_Release(&args); + + assertTrue(result == MetisCommandReturn_Failure, "ParseIPCommandLine with invalid local IP address should have returned %d, got %d", MetisCommandReturn_Failure, result); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddConnection_IpHelp) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + MetisCommandOps *ops = _metisControlAddConnection_McastHelpCreate(data->state); + MetisCommandReturn result = _metisControlAddConnection_IpHelp(NULL, ops, NULL, "WIZARD"); + assertTrue(result == MetisCommandReturn_Success, "Wrong return, got %d expected %d", result, MetisCommandReturn_Success); + metisCommandOps_Destroy(&ops); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metisControl_AddConnection); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metisControl_AddListener.c b/metis/ccnx/forwarder/metis/config/test/test_metisControl_AddListener.c new file mode 100644 index 00000000..b5319aa4 --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metisControl_AddListener.c @@ -0,0 +1,327 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metisControl_AddListener.c" +#include "testrig_MetisControl.c" + +LONGBOW_TEST_RUNNER(metisControl_AddListener) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metisControl_AddListener) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metisControl_AddListener) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisControlAddListener_Create); + LONGBOW_RUN_TEST_CASE(Global, metisControlAddListener_HelpCreate); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisControlAddListener_Create) +{ + testCommandCreate(testCase, &metisControlAddListener_Create, __func__); +} + +LONGBOW_TEST_CASE(Global, metisControlAddListener_HelpCreate) +{ + testCommandCreate(testCase, &metisControlAddListener_HelpCreate, __func__); +} + +// =========================================================== + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddListener_Execute_WrongArgCount); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddListener_Execute_Tcp); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddListener_Execute_Udp); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddListener_Execute_Udp6); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddListener_Execute_Ether); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddListener_Execute_UnknownProtocol); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddListener_Execute_BadSymbolic); + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddListener_Execute_BadSymbolic_NotAlphaNum); + + LONGBOW_RUN_TEST_CASE(Local, _metisControlAddListener_HelpExecute); + LONGBOW_RUN_TEST_CASE(Local, _createTcpListener); + LONGBOW_RUN_TEST_CASE(Local, _createUdpListener); + LONGBOW_RUN_TEST_CASE(Local, _createEtherListener); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, _createTcpListener) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + MetisCommandOps *ops = metisControlAddListener_Create(data->state); + + const char *argv[] = { "add", "listener", "tcp", "public0", "13.14.15.16", "9596", }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, 6, (void **) &argv[0]); + + MetisCommandReturn test = _createTcpListener(data->state->parser, ops, args); + + assertTrue(test == MetisCommandReturn_Success, "Command did not return success: %d", test); + assertTrue(data->writeread_count == 1, "Wrong write/read count, expected %d got %u", 1, data->writeread_count); + + parcList_Release(&args); + ops->destroyer(&ops); +} + +LONGBOW_TEST_CASE(Local, _createUdpListener) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + MetisCommandOps *ops = metisControlAddListener_Create(data->state); + + const char *argv[] = { "add", "listener", "udp", "public0", "13.14.15.16", "9596", }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, 6, (void **) &argv[0]); + + MetisCommandReturn test = _createUdpListener(data->state->parser, ops, args); + + assertTrue(test == MetisCommandReturn_Success, "Command did not return success: %d", test); + assertTrue(data->writeread_count == 1, "Wrong write/read count, expected %d got %u", 1, data->writeread_count); + + parcList_Release(&args); + ops->destroyer(&ops); +} + +LONGBOW_TEST_CASE(Local, _createEtherListener) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + MetisCommandOps *ops = metisControlAddListener_Create(data->state); + + const char *argv[] = { "add", "listener", "ether", "nic3", "eth3", "0x0801", }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, 6, (void **) &argv[0]); + + MetisCommandReturn test = _createEtherListener(data->state->parser, ops, args); + + assertTrue(test == MetisCommandReturn_Success, "Command did not return success: %d", test); + assertTrue(data->writeread_count == 1, "Wrong write/read count, expected %d got %u", 1, data->writeread_count); + + parcList_Release(&args); + ops->destroyer(&ops); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddListener_Execute_WrongArgCount) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + MetisCommandOps *ops = metisControlAddListener_Create(data->state); + + const char *argv[] = { "add", "listener", "ether" "nic3", "eth3", "0x0801", "foobar" }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, 7, (void **) &argv[0]); + + MetisCommandReturn test = _metisControlAddListener_Execute(data->state->parser, ops, args); + + assertTrue(test == MetisCommandReturn_Failure, "Command did not return failure: %d", test); + assertTrue(data->writeread_count == 0, "Wrong write/read count, expected %d got %u", 0, data->writeread_count); + + parcList_Release(&args); + ops->destroyer(&ops); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddListener_Execute_Tcp) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + MetisCommandOps *ops = metisControlAddListener_Create(data->state); + metisControlState_SetDebug(data->state, true); + + const char *argv[] = { "add", "listener", "tcp", "public0", "13.14.15.16", "9596", }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, 6, (void **) &argv[0]); + + MetisCommandReturn test = _metisControlAddListener_Execute(data->state->parser, ops, args); + + assertTrue(test == MetisCommandReturn_Success, "Command did not return success: %d", test); + assertTrue(data->writeread_count == 1, "Wrong write/read count, expected %d got %u", 1, data->writeread_count); + + parcList_Release(&args); + ops->destroyer(&ops); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddListener_Execute_Udp) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + MetisCommandOps *ops = metisControlAddListener_Create(data->state); + metisControlState_SetDebug(data->state, true); + + const char *argv[] = { "add", "listener", "udp", "public0", "13.14.15.16", "9596", }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, 6, (void **) &argv[0]); + + MetisCommandReturn test = _metisControlAddListener_Execute(data->state->parser, ops, args); + + assertTrue(test == MetisCommandReturn_Success, "Command did not return success: %d", test); + assertTrue(data->writeread_count == 1, "Wrong write/read count, expected %d got %u", 1, data->writeread_count); + + parcList_Release(&args); + ops->destroyer(&ops); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddListener_Execute_Udp6) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + MetisCommandOps *ops = metisControlAddListener_Create(data->state); + metisControlState_SetDebug(data->state, true); + + // INET6 address + const char *argv[] = { "add", "listener", "udp", "public0", "::1", "9596", }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, 6, (void **) &argv[0]); + + MetisCommandReturn test = _metisControlAddListener_Execute(data->state->parser, ops, args); + + assertTrue(test == MetisCommandReturn_Success, "Command did not return success: %d", test); + assertTrue(data->writeread_count == 1, "Wrong write/read count, expected %d got %u", 1, data->writeread_count); + + parcList_Release(&args); + ops->destroyer(&ops); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddListener_Execute_Ether) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + MetisCommandOps *ops = metisControlAddListener_Create(data->state); + + const char *argv[] = { "add", "listener", "ether", "nic3", "eth3", "0x0801", }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, 6, (void **) &argv[0]); + + MetisCommandReturn test = _metisControlAddListener_Execute(data->state->parser, ops, args); + + assertTrue(test == MetisCommandReturn_Success, "Command did not return success: %d", test); + assertTrue(data->writeread_count == 1, "Wrong write/read count, expected %d got %u", 1, data->writeread_count); + + parcList_Release(&args); + ops->destroyer(&ops); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddListener_Execute_UnknownProtocol) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + MetisCommandOps *ops = metisControlAddListener_Create(data->state); + + const char *argv[] = { "add", "listener", "pup", "nic3", "eth3", "0x0801" }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, 6, (void **) &argv[0]); + + MetisCommandReturn test = _metisControlAddListener_Execute(data->state->parser, ops, args); + + assertTrue(test == MetisCommandReturn_Failure, "Command did not return failure: %d", test); + assertTrue(data->writeread_count == 0, "Wrong write/read count, expected %d got %u", 0, data->writeread_count); + + parcList_Release(&args); + ops->destroyer(&ops); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddListener_Execute_BadSymbolic) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + MetisCommandOps *ops = metisControlAddListener_Create(data->state); + + const char *argv[] = { "add", "listener", "ether" "111", "eth3", "0x0801" }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, 6, (void **) &argv[0]); + + MetisCommandReturn test = _metisControlAddListener_Execute(data->state->parser, ops, args); + + assertTrue(test == MetisCommandReturn_Failure, "Command did not return failure: %d", test); + assertTrue(data->writeread_count == 0, "Wrong write/read count, expected %d got %u", 0, data->writeread_count); + + parcList_Release(&args); + ops->destroyer(&ops); +} + + +LONGBOW_TEST_CASE(Local, _metisControlAddListener_Execute_BadSymbolic_NotAlphaNum) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + MetisCommandOps *ops = metisControlAddListener_Create(data->state); + + const char *argv[] = { "add", "listener", "ether", "n()t", "eth3", "0x0801" }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, 6, (void **) &argv[0]); + + MetisCommandReturn test = _metisControlAddListener_Execute(data->state->parser, ops, args); + + assertTrue(test == MetisCommandReturn_Failure, "Command did not return failure: %d", test); + assertTrue(data->writeread_count == 0, "Wrong write/read count, expected %d got %u", 0, data->writeread_count); + + parcList_Release(&args); + ops->destroyer(&ops); +} + +LONGBOW_TEST_CASE(Local, _metisControlAddListener_HelpExecute) +{ + _metisControlAddListener_HelpExecute(NULL, NULL, NULL); +} + +// =========================================================== + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metisControl_AddListener); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metisControl_AddRoute.c b/metis/ccnx/forwarder/metis/config/test/test_metisControl_AddRoute.c new file mode 100644 index 00000000..4a57dd64 --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metisControl_AddRoute.c @@ -0,0 +1,170 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metisControl_AddRoute.c" +#include "testrig_MetisControl.c" + +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(metisControl_AddRoute) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metisControl_AddRoute) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metisControl_AddRoute) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisControlAddRoute_Create); + LONGBOW_RUN_TEST_CASE(Global, metisControlAddRoute_HelpCreate); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisControlAddRoute_Create) +{ + testCommandCreate(testCase, &metisControlAddRoute_Create, __func__); +} + +LONGBOW_TEST_CASE(Global, metisControlAddRoute_HelpCreate) +{ + testCommandCreate(testCase, &metisControlAddRoute_HelpCreate, __func__); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisControl_AddRoute_Execute_WrongArgCount); + LONGBOW_RUN_TEST_CASE(Local, metisControl_AddRoute_Execute_ZeroCost); + LONGBOW_RUN_TEST_CASE(Local, metisControl_AddRoute_Execute_BadPrefix); + LONGBOW_RUN_TEST_CASE(Local, metisControl_AddRoute_Execute_Good); + + LONGBOW_RUN_TEST_CASE(Local, metisControl_Help_AddRoute_Execute); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +static MetisCommandReturn +testAddRoute(const LongBowTestCase *testCase, int argc, const char *prefix, const char *nexthop, const char *cost) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + metisControlState_SetDebug(data->state, true); + + const char *argv[] = { "add", "route", nexthop, prefix, cost }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, argc, (void **) &argv[0]); + + MetisCommandOps *ops = metisControlAddRoute_Create(data->state); + + MetisCommandReturn result = ops->execute(data->state->parser, ops, args); + metisCommandOps_Destroy(&ops); + parcList_Release(&args); + return result; +} + +LONGBOW_TEST_CASE(Local, metisControl_AddRoute_Execute_WrongArgCount) +{ + // argc is wrong, needs to be 5. + MetisCommandReturn result = testAddRoute(testCase, 2, "lci:/foo", "703", "1"); + + assertTrue(result == MetisCommandReturn_Failure, + "metisControl_AddRoute with wrong argc should return %d, got %d", MetisCommandReturn_Failure, result); +} + +LONGBOW_TEST_CASE(Local, metisControl_AddRoute_Execute_ZeroCost) +{ + MetisCommandReturn result = testAddRoute(testCase, 5, "lci:/foo", "702", "0"); + + assertTrue(result == MetisCommandReturn_Failure, + "metisControl_AddRoute with zero cost should return %d, got %d", MetisCommandReturn_Failure, result); +} + +LONGBOW_TEST_CASE(Local, metisControl_AddRoute_Execute_BadPrefix) +{ + MetisCommandReturn result = testAddRoute(testCase, 5, "blah", "701", "1"); + + assertTrue(result == MetisCommandReturn_Failure, + "metisControl_AddRoute with zero cost should return %d, got %d", MetisCommandReturn_Failure, result); +} + +LONGBOW_TEST_CASE(Local, metisControl_AddRoute_Execute_Good) +{ + MetisCommandReturn result = testAddRoute(testCase, 5, "lci:/foo", "700", "1"); + + assertTrue(result == MetisCommandReturn_Success, + "metisControl_AddRoute should return %d, got %d", MetisCommandReturn_Success, result); +} + +LONGBOW_TEST_CASE(Local, metisControl_Help_AddRoute_Execute) +{ + testHelpExecute(testCase, metisControlAddRoute_HelpCreate, __func__, MetisCommandReturn_Success); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metisControl_AddRoute); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metisControl_List.c b/metis/ccnx/forwarder/metis/config/test/test_metisControl_List.c new file mode 100644 index 00000000..1d8f347f --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metisControl_List.c @@ -0,0 +1,130 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metisControl_List.c" +#include "testrig_MetisControl.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(metisControl_List) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metisControl_List) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metisControl_List) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisControlList_HelpCreate); + LONGBOW_RUN_TEST_CASE(Global, metisControlList_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisControlList_HelpCreate) +{ + testCommandCreate(testCase, &metisControlList_HelpCreate, __func__); +} + +LONGBOW_TEST_CASE(Global, metisControlList_Create) +{ + testCommandCreate(testCase, &metisControlList_Create, __func__); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisControl_Help_List_Execute); + LONGBOW_RUN_TEST_CASE(Local, metisControl_List_Execute); + LONGBOW_RUN_TEST_CASE(Local, metisControl_List_Init); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, metisControl_Help_List_Execute) +{ + testHelpExecute(testCase, metisControlList_HelpCreate, __func__, MetisCommandReturn_Success); +} + +LONGBOW_TEST_CASE(Local, metisControl_List_Execute) +{ + // this just prints the Help function + testHelpExecute(testCase, metisControlList_Create, __func__, MetisCommandReturn_Success); +} + +LONGBOW_TEST_CASE(Local, metisControl_List_Init) +{ + testInit(testCase, metisControlList_Create, __func__, + (const char *[]) { + "list connections", "list interfaces", "list routes", + "help list connections", "help list interfaces", "help list routes", + NULL + }); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metisControl_List); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metisControl_ListConnections.c b/metis/ccnx/forwarder/metis/config/test/test_metisControl_ListConnections.c new file mode 100644 index 00000000..56d691e1 --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metisControl_ListConnections.c @@ -0,0 +1,172 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metisControl_ListConnections.c" +#include "testrig_MetisControl.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(metisControl_ListConnections) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metisControl_ListConnections) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metisControl_ListConnections) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisControlListConnections_HelpCreate); + LONGBOW_RUN_TEST_CASE(Global, metisControlListConnections_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisControlListConnections_HelpCreate) +{ + testCommandCreate(testCase, &metisControlListConnections_HelpCreate, __func__); +} + +LONGBOW_TEST_CASE(Global, metisControlListConnections_Create) +{ + testCommandCreate(testCase, &metisControlListConnections_Create, __func__); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisControl_Help_ListConnections_Execute); + LONGBOW_RUN_TEST_CASE(Local, metisControl_ListConnections_Execute_WrongArgCount); + LONGBOW_RUN_TEST_CASE(Local, metisControl_ListConnections_Execute_Good); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, metisControl_Help_ListConnections_Execute) +{ + testHelpExecute(testCase, &metisControlListConnections_HelpCreate, __func__, MetisCommandReturn_Success); +} + +static CCNxControl * +customWriteReadResponse(void *userdata, CCNxMetaMessage *messageToWrite) +{ + CPIConnectionList *connlist = cpiConnectionList_Create(); + CPIConnection *conn = cpiConnection_Create(1, cpiAddress_CreateFromInterface(1), cpiAddress_CreateFromInterface(2), cpiConnection_L2); + cpiConnectionList_Append(connlist, conn); + + PARCJSON *connectionListAsJson = cpiConnectionList_ToJson(connlist); + + CCNxControl *inboundControlMessage = ccnxMetaMessage_GetControl(messageToWrite); + + // Create a response to the inbound Control message. + CCNxControl *outboundControlMessage = cpi_CreateResponse(inboundControlMessage, connectionListAsJson); + parcJSON_Release(&connectionListAsJson); + + ccnxControl_Release(&inboundControlMessage); + + cpiConnectionList_Destroy(&connlist); + + return outboundControlMessage; +} + +static MetisCommandReturn +testListConnections(const LongBowTestCase *testCase, int argc) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + metisControlState_SetDebug(data->state, true); + data->customWriteReadReply = &customWriteReadResponse; + + const char *argv[] = { "list", "interfaces" }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, argc, (void **) &argv[0]); + + MetisCommandOps *ops = metisControlListConnections_Create(data->state); + + MetisCommandReturn result = ops->execute(data->state->parser, ops, args); + metisCommandOps_Destroy(&ops); + parcList_Release(&args); + return result; +} + +LONGBOW_TEST_CASE(Local, metisControl_ListConnections_Execute_WrongArgCount) +{ + // argc is wrong, needs to be 2. + MetisCommandReturn result = testListConnections(testCase, 3); + + assertTrue(result == MetisCommandReturn_Failure, + "metisControl_ListConnections with wrong argc should return %d, got %d", MetisCommandReturn_Failure, result); +} + +LONGBOW_TEST_CASE(Local, metisControl_ListConnections_Execute_Good) +{ + MetisCommandReturn result = testListConnections(testCase, 2); + + assertTrue(result == MetisCommandReturn_Success, + "metisControl_ListConnections should return %d, got %d", MetisCommandReturn_Success, result); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metisControl_ListConnections); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metisControl_ListInterfaces.c b/metis/ccnx/forwarder/metis/config/test/test_metisControl_ListInterfaces.c new file mode 100644 index 00000000..0e1e13d2 --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metisControl_ListInterfaces.c @@ -0,0 +1,177 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metisControl_ListInterfaces.c" +#include "testrig_MetisControl.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(metisControl_ListInterfaces) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metisControl_ListInterfaces) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metisControl_ListInterfaces) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisControlListInterfaces_HelpCreate); + LONGBOW_RUN_TEST_CASE(Global, metisControlListInterfaces_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisControlListInterfaces_HelpCreate) +{ + testCommandCreate(testCase, &metisControlListInterfaces_HelpCreate, __func__); +} + +LONGBOW_TEST_CASE(Global, metisControlListInterfaces_Create) +{ + testCommandCreate(testCase, &metisControlListInterfaces_Create, __func__); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisControl_Help_ListInterfaces_Execute); + LONGBOW_RUN_TEST_CASE(Local, metisControl_ListInterfaces_Execute_WrongArgCount); + LONGBOW_RUN_TEST_CASE(Local, metisControl_ListInterfaces_Execute_Good); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, metisControl_Help_ListInterfaces_Execute) +{ + testHelpExecute(testCase, &metisControlListInterfaces_HelpCreate, __func__, MetisCommandReturn_Success); +} + +LONGBOW_TEST_CASE(Local, metisControl_ListInterfaces_Execute) +{ + testUnimplemented(""); +} + +static CCNxControl * +customWriteReadResponse(void *userdata, CCNxMetaMessage *messageToWrite) +{ + CPIInterfaceSet *set = cpiInterfaceSet_Create(); + cpiInterfaceSet_Add(set, cpiInterface_Create("abc0", 1, false, true, 1500)); + cpiInterfaceSet_Add(set, cpiInterface_Create("abc1", 2, false, true, 1500)); + PARCJSON *setJson = cpiInterfaceSet_ToJson(set); + + CCNxControl *inboundControlMessage = ccnxMetaMessage_GetControl(messageToWrite); + + // Create a response to the inbound Control message. + CCNxControl *outboundControlMessage = cpi_CreateResponse(inboundControlMessage, setJson); + parcJSON_Release(&setJson); + + ccnxControl_Release(&inboundControlMessage); + cpiInterfaceSet_Destroy(&set); + + return outboundControlMessage; +} + +static MetisCommandReturn +testListInterfaces(const LongBowTestCase *testCase, int argc) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + metisControlState_SetDebug(data->state, true); + data->customWriteReadReply = &customWriteReadResponse; + + const char *argv[] = { "list", "connections" }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, argc, (void **) &argv[0]); + + MetisCommandOps *ops = metisControlListInterfaces_Create(data->state); + + MetisCommandReturn result = ops->execute(data->state->parser, ops, args); + metisCommandOps_Destroy(&ops); + parcList_Release(&args); + return result; +} + +LONGBOW_TEST_CASE(Local, metisControl_ListInterfaces_Execute_WrongArgCount) +{ + // argc is wrong, needs to be 2. + MetisCommandReturn result = testListInterfaces(testCase, 3); + + assertTrue(result == MetisCommandReturn_Failure, + "metisControl_ListInterfaces with wrong argc should return %d, got %d", MetisCommandReturn_Failure, result); +} + +LONGBOW_TEST_CASE(Local, metisControl_ListInterfaces_Execute_Good) +{ + MetisCommandReturn result = testListInterfaces(testCase, 2); + + assertTrue(result == MetisCommandReturn_Success, + "metisControl_ListInterfaces should return %d, got %d", MetisCommandReturn_Success, result); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metisControl_ListInterfaces); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metisControl_ListRoutes.c b/metis/ccnx/forwarder/metis/config/test/test_metisControl_ListRoutes.c new file mode 100644 index 00000000..ca71f93f --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metisControl_ListRoutes.c @@ -0,0 +1,187 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metisControl_ListRoutes.c" +#include "testrig_MetisControl.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(metisControl_ListRoutes) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metisControl_ListRoutes) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metisControl_ListRoutes) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisControlListRoutes_HelpCreate); + LONGBOW_RUN_TEST_CASE(Global, metisControlListRoutes_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisControlListRoutes_HelpCreate) +{ + testCommandCreate(testCase, &metisControlListRoutes_HelpCreate, __func__); +} + +LONGBOW_TEST_CASE(Global, metisControlListRoutes_Create) +{ + testCommandCreate(testCase, &metisControlListRoutes_Create, __func__); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisControl_Help_ListRoutes_Execute); + LONGBOW_RUN_TEST_CASE(Local, metisControl_ListRoutes_Execute_WrongArgCount); + LONGBOW_RUN_TEST_CASE(Local, metisControl_ListRoutes_Execute_Good); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, metisControl_Help_ListRoutes_Execute) +{ + testHelpExecute(testCase, &metisControlListRoutes_HelpCreate, __func__, MetisCommandReturn_Success); +} + +LONGBOW_TEST_CASE(Local, metisControl_ListRoutes_Execute) +{ + testUnimplemented(""); +} + +static CCNxControl * +customWriteReadResponse(void *userdata, CCNxMetaMessage *messageToWrite) +{ + CPIRouteEntryList *routeEntryList = cpiRouteEntryList_Create(); + CPIAddress *nexthop = cpiAddress_CreateFromInterface(10); + CPIRouteEntry *route = cpiRouteEntry_Create(ccnxName_CreateFromCString("lci:/foo"), + 1, + nexthop, + cpiNameRouteProtocolType_STATIC, + cpiNameRouteType_LONGEST_MATCH, + &((struct timeval) { 100, 0 }), // lifetime + 1); // cost + + cpiRouteEntryList_Append(routeEntryList, route); + PARCJSON *setJson = cpiRouteEntryList_ToJson(routeEntryList); + + CCNxControl *inboundControlMessage = ccnxMetaMessage_GetControl(messageToWrite); + + // Create a response to the inbound Control message. + CCNxControl *outboundControlMessage = cpi_CreateResponse(inboundControlMessage, setJson); + parcJSON_Release(&setJson); + + ccnxControl_Release(&inboundControlMessage); + + cpiAddress_Destroy(&nexthop); + cpiRouteEntryList_Destroy(&routeEntryList); + + return outboundControlMessage; +} + +static MetisCommandReturn +testListRoutes(const LongBowTestCase *testCase, int argc) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + metisControlState_SetDebug(data->state, true); + data->customWriteReadReply = &customWriteReadResponse; + + const char *argv[] = { "list", "connections" }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, argc, (void **) &argv[0]); + + MetisCommandOps *ops = metisControlListRoutes_Create(data->state); + + MetisCommandReturn result = ops->execute(data->state->parser, ops, args); + metisCommandOps_Destroy(&ops); + parcList_Release(&args); + return result; +} + +LONGBOW_TEST_CASE(Local, metisControl_ListRoutes_Execute_WrongArgCount) +{ + // argc is wrong, needs to be 2. + MetisCommandReturn result = testListRoutes(testCase, 3); + + assertTrue(result == MetisCommandReturn_Failure, + "metisControl_ListRoutes with wrong argc should return %d, got %d", MetisCommandReturn_Failure, result); +} + +LONGBOW_TEST_CASE(Local, metisControl_ListRoutes_Execute_Good) +{ + MetisCommandReturn result = testListRoutes(testCase, 2); + + assertTrue(result == MetisCommandReturn_Success, + "metisControl_ListRoutes should return %d, got %d", MetisCommandReturn_Success, result); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metisControl_ListRoutes); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metisControl_Quit.c b/metis/ccnx/forwarder/metis/config/test/test_metisControl_Quit.c new file mode 100644 index 00000000..192bdf86 --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metisControl_Quit.c @@ -0,0 +1,119 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metisControl_Quit.c" +#include "testrig_MetisControl.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(metisControl_Quit) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metisControl_Quit) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metisControl_Quit) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisControlQuit_HelpCreate); + LONGBOW_RUN_TEST_CASE(Global, metisControlQuit_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisControlQuit_HelpCreate) +{ + testCommandCreate(testCase, metisControlQuit_HelpCreate, __func__); +} + +LONGBOW_TEST_CASE(Global, metisControlQuit_Create) +{ + testCommandCreate(testCase, metisControlQuit_Create, __func__); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisControl_Help_Quit_Execute); + LONGBOW_RUN_TEST_CASE(Local, metisControl_Quit_Execute); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, metisControl_Help_Quit_Execute) +{ + testHelpExecute(testCase, metisControlQuit_HelpCreate, __func__, MetisCommandReturn_Success); +} + +LONGBOW_TEST_CASE(Local, metisControl_Quit_Execute) +{ + // This only displays the Help message + testHelpExecute(testCase, metisControlQuit_Create, __func__, MetisCommandReturn_Exit); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metisControl_Quit); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metisControl_Remove.c b/metis/ccnx/forwarder/metis/config/test/test_metisControl_Remove.c new file mode 100644 index 00000000..b5878797 --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metisControl_Remove.c @@ -0,0 +1,130 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metisControl_Remove.c" +#include "testrig_MetisControl.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(metisControl_Remove) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metisControl_Remove) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metisControl_Remove) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisControlRemove_HelpCreate); + LONGBOW_RUN_TEST_CASE(Global, metisControlRemove_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisControlRemove_HelpCreate) +{ + testCommandCreate(testCase, metisControlRemove_HelpCreate, __func__); +} + +LONGBOW_TEST_CASE(Global, metisControlRemove_Create) +{ + testCommandCreate(testCase, metisControlRemove_Create, __func__); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisControl_Help_Remove_Execute); + LONGBOW_RUN_TEST_CASE(Local, metisControl_Remove_Execute); + LONGBOW_RUN_TEST_CASE(Local, metisControl_Remove_Init); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, metisControl_Help_Remove_Execute) +{ + testHelpExecute(testCase, metisControlRemove_HelpCreate, __func__, MetisCommandReturn_Success); +} + +LONGBOW_TEST_CASE(Local, metisControl_Remove_Execute) +{ + // this only displays the help menu + testHelpExecute(testCase, metisControlRemove_Create, __func__, MetisCommandReturn_Success); +} + +LONGBOW_TEST_CASE(Local, metisControl_Remove_Init) +{ + testInit(testCase, metisControlRemove_Create, __func__, + (const char *[]) { + "remove connection", "remove route", + "help remove connection", "help remove route", + NULL + }); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metisControl_Remove); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metisControl_RemoveConnection.c b/metis/ccnx/forwarder/metis/config/test/test_metisControl_RemoveConnection.c new file mode 100644 index 00000000..76340b77 --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metisControl_RemoveConnection.c @@ -0,0 +1,118 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metisControl_RemoveConnection.c" +#include "testrig_MetisControl.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(metisControl_RemoveConnection) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metisControl_RemoveConnection) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metisControl_RemoveConnection) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisControlRemoveConnection_HelpCreate); + LONGBOW_RUN_TEST_CASE(Global, metisControlRemoveConnection_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisControlRemoveConnection_HelpCreate) +{ + testCommandCreate(testCase, &metisControlRemoveConnection_HelpCreate, __func__); +} + +LONGBOW_TEST_CASE(Global, metisControlRemoveConnection_Create) +{ + testCommandCreate(testCase, &metisControlRemoveConnection_Create, __func__); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisControl_Help_RemoveConnection_Execute); + LONGBOW_RUN_TEST_CASE(Local, metisControl_RemoveConnection_Execute); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, metisControl_Help_RemoveConnection_Execute) +{ + testHelpExecute(testCase, &metisControlRemoveConnection_HelpCreate, __func__, MetisCommandReturn_Success); +} + +LONGBOW_TEST_CASE(Local, metisControl_RemoveConnection_Execute) +{ + testHelpExecute(testCase, &metisControlRemoveConnection_Create, __func__, MetisCommandReturn_Success); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metisControl_RemoveConnection); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metisControl_RemoveRoute.c b/metis/ccnx/forwarder/metis/config/test/test_metisControl_RemoveRoute.c new file mode 100644 index 00000000..636d04b5 --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metisControl_RemoveRoute.c @@ -0,0 +1,118 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metisControl_RemoveRoute.c" +#include "testrig_MetisControl.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(metisControl_RemoveRoute) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metisControl_RemoveRoute) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metisControl_RemoveRoute) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisControlRemoveRoute_HelpCreate); + LONGBOW_RUN_TEST_CASE(Global, metisControlRemoveRoute_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisControlRemoveRoute_HelpCreate) +{ + testCommandCreate(testCase, &metisControlRemoveRoute_HelpCreate, __func__); +} + +LONGBOW_TEST_CASE(Global, metisControlRemoveRoute_Create) +{ + testCommandCreate(testCase, &metisControlRemoveRoute_Create, __func__); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisControl_Help_RemoveRoute_Execute); + LONGBOW_RUN_TEST_CASE(Local, metisControl_RemoveRoute_Execute); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, metisControl_Help_RemoveRoute_Execute) +{ + testHelpExecute(testCase, &metisControlRemoveRoute_HelpCreate, __func__, MetisCommandReturn_Success); +} + +LONGBOW_TEST_CASE(Local, metisControl_RemoveRoute_Execute) +{ + testUnimplemented(""); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metisControl_RemoveRoute); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metisControl_Root.c b/metis/ccnx/forwarder/metis/config/test/test_metisControl_Root.c new file mode 100644 index 00000000..3adf736c --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metisControl_Root.c @@ -0,0 +1,130 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metisControl_Root.c" +#include "testrig_MetisControl.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(metisControl_Root) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metisControl_Root) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metisControl_Root) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisControlRoot_HelpCreate); + LONGBOW_RUN_TEST_CASE(Global, metisControlRoot_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisControlRoot_HelpCreate) +{ + testCommandCreate(testCase, &metisControlRoot_HelpCreate, __func__); +} + +LONGBOW_TEST_CASE(Global, metisControlRoot_Create) +{ + testCommandCreate(testCase, &metisControlRoot_Create, __func__); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisControl_Help_Root_Execute); + LONGBOW_RUN_TEST_CASE(Local, metisControl_Root_Execute); + LONGBOW_RUN_TEST_CASE(Local, metisControl_Root_Init); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, metisControl_Help_Root_Execute) +{ + testHelpExecute(testCase, &metisControlRoot_HelpCreate, __func__, MetisCommandReturn_Success); +} + +LONGBOW_TEST_CASE(Local, metisControl_Root_Execute) +{ + // this command only displays Help + testHelpExecute(testCase, &metisControlRoot_Create, __func__, MetisCommandReturn_Success); +} + +LONGBOW_TEST_CASE(Local, metisControl_Root_Init) +{ + testInit(testCase, &metisControlRoot_Create, __func__, + (const char *[]) { + "add", "list", "quit", "remove", "set", "unset", + "help add", "help list", "help quit", "help remove", "help set", "help unset", + NULL + }); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metisControl_Root); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metisControl_Set.c b/metis/ccnx/forwarder/metis/config/test/test_metisControl_Set.c new file mode 100644 index 00000000..b224e49f --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metisControl_Set.c @@ -0,0 +1,130 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metisControl_Set.c" +#include "testrig_MetisControl.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(metisControl_Set) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metisControl_Set) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metisControl_Set) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisControlSet_HelpCreate); + LONGBOW_RUN_TEST_CASE(Global, metisControlSet_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisControlSet_HelpCreate) +{ + testCommandCreate(testCase, &metisControlSet_HelpCreate, __func__); +} + +LONGBOW_TEST_CASE(Global, metisControlSet_Create) +{ + testCommandCreate(testCase, &metisControlSet_Create, __func__); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisControl_Help_Set_Execute); + LONGBOW_RUN_TEST_CASE(Local, metisControl_Set_Execute); + LONGBOW_RUN_TEST_CASE(Local, metisControl_Set_Init); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, metisControl_Help_Set_Execute) +{ + testHelpExecute(testCase, &metisControlSet_HelpCreate, __func__, MetisCommandReturn_Success); +} + +LONGBOW_TEST_CASE(Local, metisControl_Set_Execute) +{ + // Only prints a help menu + testHelpExecute(testCase, &metisControlSet_Create, __func__, MetisCommandReturn_Success); +} + +LONGBOW_TEST_CASE(Local, metisControl_Set_Init) +{ + testInit(testCase, &metisControlSet_Create, __func__, + (const char *[]) { + "set debug", + "help set debug", + NULL + }); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metisControl_Set); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metisControl_SetDebug.c b/metis/ccnx/forwarder/metis/config/test/test_metisControl_SetDebug.c new file mode 100644 index 00000000..5f7f4805 --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metisControl_SetDebug.c @@ -0,0 +1,153 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metisControl_SetDebug.c" +#include "testrig_MetisControl.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(metisControl_SetDebug) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metisControl_SetDebug) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metisControl_SetDebug) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisControlSetDebug_HelpCreate); + LONGBOW_RUN_TEST_CASE(Global, metisControlSetDebug_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisControlSetDebug_HelpCreate) +{ + testCommandCreate(testCase, &metisControlSetDebug_HelpCreate, __func__); +} + +LONGBOW_TEST_CASE(Global, metisControlSetDebug_Create) +{ + testCommandCreate(testCase, &metisControlSetDebug_Create, __func__); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisControl_Help_SetDebug_Execute); + LONGBOW_RUN_TEST_CASE(Local, metisControl_SetDebug_Execute_WrongArgCount); + LONGBOW_RUN_TEST_CASE(Local, metisControl_SetDebug_Execute_Good); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, metisControl_Help_SetDebug_Execute) +{ + testHelpExecute(testCase, &metisControlSetDebug_HelpCreate, __func__, MetisCommandReturn_Success); +} + +static MetisCommandReturn +testDebug(const LongBowTestCase *testCase, MetisCommandOps * (*create)(MetisControlState * state), int argc, bool initialDebugSetting, bool expectedDebugSetting) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + const char *argv[] = { "blah", "blah" }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, argc, (void **) &argv[0]); + + metisControlState_SetDebug(data->state, initialDebugSetting); + MetisCommandOps *ops = create(data->state); + MetisCommandReturn result = ops->execute(data->state->parser, ops, args); + if (result == MetisCommandReturn_Success) { + assertTrue(data->state->debugFlag == expectedDebugSetting, + "Debug flag wrong, expected %d got %d", + expectedDebugSetting, + data->state->debugFlag); + } + + metisCommandOps_Destroy(&ops); + parcList_Release(&args); + return result; +} + +LONGBOW_TEST_CASE(Local, metisControl_SetDebug_Execute_WrongArgCount) +{ + MetisCommandReturn result = testDebug(testCase, metisControlSetDebug_Create, 3, false, true); + assertTrue(result == MetisCommandReturn_Failure, + "metisControl_SetDebug_Execute should return %d, got %d", MetisCommandReturn_Failure, result); +} + + +LONGBOW_TEST_CASE(Local, metisControl_SetDebug_Execute_Good) +{ + MetisCommandReturn result = testDebug(testCase, metisControlSetDebug_Create, 2, false, true); + assertTrue(result == MetisCommandReturn_Success, + "metisControl_SetDebug_Execute should return %d, got %d", MetisCommandReturn_Success, result); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metisControl_SetDebug); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metisControl_Unset.c b/metis/ccnx/forwarder/metis/config/test/test_metisControl_Unset.c new file mode 100644 index 00000000..f7e27daf --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metisControl_Unset.c @@ -0,0 +1,130 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metisControl_Unset.c" +#include "testrig_MetisControl.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(metisControl_Unset) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metisControl_Unset) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metisControl_Unset) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisControlUnset_HelpCreate); + LONGBOW_RUN_TEST_CASE(Global, metisControlUnset_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisControlUnset_HelpCreate) +{ + testCommandCreate(testCase, &metisControlUnset_HelpCreate, __func__); +} + +LONGBOW_TEST_CASE(Global, metisControlUnset_Create) +{ + testCommandCreate(testCase, &metisControlUnset_Create, __func__); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisControl_Help_Unset_Execute); + LONGBOW_RUN_TEST_CASE(Local, metisControl_Unset_Init); + LONGBOW_RUN_TEST_CASE(Local, metisControl_Unset_Execute); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, metisControl_Help_Unset_Execute) +{ + testHelpExecute(testCase, &metisControlUnset_HelpCreate, __func__, MetisCommandReturn_Success); +} + +LONGBOW_TEST_CASE(Local, metisControl_Unset_Init) +{ + testInit(testCase, &metisControlUnset_Create, __func__, + (const char *[]) { + "unset debug", + "help unset debug", + NULL + }); +} + +LONGBOW_TEST_CASE(Local, metisControl_Unset_Execute) +{ + // Only prints a help menu + testHelpExecute(testCase, &metisControlUnset_Create, __func__, MetisCommandReturn_Success); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metisControl_Unset); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metisControl_UnsetDebug.c b/metis/ccnx/forwarder/metis/config/test/test_metisControl_UnsetDebug.c new file mode 100644 index 00000000..bb31b917 --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metisControl_UnsetDebug.c @@ -0,0 +1,153 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metisControl_UnsetDebug.c" +#include "testrig_MetisControl.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(metisControl_UnsetDebug) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metisControl_UnsetDebug) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metisControl_UnsetDebug) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisControlUnsetDebug_HelpCreate); + LONGBOW_RUN_TEST_CASE(Global, metisControlUnsetDebug_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisControlUnsetDebug_HelpCreate) +{ + testCommandCreate(testCase, &metisControlUnsetDebug_HelpCreate, __func__); +} + +LONGBOW_TEST_CASE(Global, metisControlUnsetDebug_Create) +{ + testCommandCreate(testCase, &metisControlUnsetDebug_Create, __func__); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisControl_Help_UnsetDebug_Execute); + LONGBOW_RUN_TEST_CASE(Local, metisControl_UnsetDebug_Execute_WrongArgCount); + LONGBOW_RUN_TEST_CASE(Local, metisControl_UnsetDebug_Execute_Good); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + testrigMetisControl_commonSetup(testCase); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + testrigMetisControl_CommonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, metisControl_Help_UnsetDebug_Execute) +{ + testHelpExecute(testCase, &metisControlUnsetDebug_HelpCreate, __func__, MetisCommandReturn_Success); +} + +static MetisCommandReturn +testDebug(const LongBowTestCase *testCase, MetisCommandOps * (*create)(MetisControlState * state), int argc, bool initialDebugSetting, bool expectedDebugSetting) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + const char *argv[] = { "blah", "blah" }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, argc, (void **) &argv[0]); + + metisControlState_SetDebug(data->state, initialDebugSetting); + MetisCommandOps *ops = create(data->state); + MetisCommandReturn result = ops->execute(data->state->parser, ops, args); + if (result == MetisCommandReturn_Success) { + assertTrue(data->state->debugFlag == expectedDebugSetting, + "Debug flag wrong, expected %d got %d", + expectedDebugSetting, + data->state->debugFlag); + } + + metisCommandOps_Destroy(&ops); + parcList_Release(&args); + return result; +} + +LONGBOW_TEST_CASE(Local, metisControl_UnsetDebug_Execute_WrongArgCount) +{ + MetisCommandReturn result = testDebug(testCase, metisControlUnsetDebug_Create, 3, true, false); + assertTrue(result == MetisCommandReturn_Failure, + "metisControl_UnsetDebug_Execute should return %d, got %d", MetisCommandReturn_Failure, result); +} + + +LONGBOW_TEST_CASE(Local, metisControl_UnsetDebug_Execute_Good) +{ + MetisCommandReturn result = testDebug(testCase, metisControlUnsetDebug_Create, 2, true, false); + assertTrue(result == MetisCommandReturn_Success, + "metisControl_UnsetDebug_Execute should return %d, got %d", MetisCommandReturn_Success, result); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metisControl_UnsetDebug); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metis_CommandLineInterface.c b/metis/ccnx/forwarder/metis/config/test/test_metis_CommandLineInterface.c new file mode 100644 index 00000000..fe8e911c --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metis_CommandLineInterface.c @@ -0,0 +1,181 @@ +/* + * 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. + */ + +#include "../metis_CommandLineInterface.c" + +#include <errno.h> +#include <string.h> + +#include <LongBow/unit-test.h> +#include <LongBow/debugging.h> + +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(test_metis_CommandLineInterface) +{ +// The following Test Fixtures will run their corresponding Test Cases. +// Test Fixtures are run in the order specified, but all tests should be idempotent. +// Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(test_metis_CommandLineInterface) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(test_metis_CommandLineInterface) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + //LONGBOW_RUN_TEST_CASE(Global, myTest); + LONGBOW_RUN_TEST_CASE(Global, Version); +} + +typedef struct test_state { + MetisForwarder *metis; + MetisDispatcher *dispatcher; + MetisCommandLineInterface *cli; + + int clientFd; +} TestState; + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + TestState *state = malloc(sizeof(TestState)); + + state->metis = metisForwarder_Create(NULL); + state->dispatcher = metisForwarder_GetDispatcher(state->metis); + +// we create our own CLI, because the one built in to metisForwarder is not started +// until the forwarder is running. + + state->cli = metisCommandLineInterface_Create(state->metis, 2001); + metisCommandLineInterface_Start(state->cli); + + metisDispatcher_RunCount(state->dispatcher, 1); + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = PF_INET; + addr.sin_port = htons(2001); + inet_pton(AF_INET, "127.0.0.1", &(addr.sin_addr)); + + state->clientFd = socket(PF_INET, SOCK_STREAM, 0); + assertFalse(state->clientFd < 0, "Error on socket: (%d) %s", errno, strerror(errno)); + + int failure = connect(state->clientFd, (struct sockaddr *) &addr, sizeof(addr)); + assertFalse(failure, "Error on connect: (%d) %s", errno, strerror(errno)); + +// crank the handle once + metisDispatcher_RunDuration(metisForwarder_GetDispatcher(state->metis), &((struct timeval) { 0, 1000 })); + + longBowTestCase_SetClipBoardData(testCase, state); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + TestState *state = longBowTestCase_GetClipBoardData(testCase); + + close(state->clientFd); + metisCommandLineInterface_Destroy(&state->cli); + metisForwarder_Destroy(&state->metis); + free(state); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +/** + * The CLI has a secret command "~~" (two of them) that will echo back whatever the next + * words are. The string "~~ hello world" would echo back "success: hello world" followed by + * the next command prompt. This lets us test that the 1st level of parsing is working. It + * differentiates "~~" as the command and the rest of the string as parameters. + */ +LONGBOW_TEST_CASE(Global, myTest) +{ + TestState *state = longBowTestCase_GetClipBoardData(testCase); + + + char readbuffer[1024]; + +// Skipover the MOTD + ssize_t nread = read(state->clientFd, readbuffer, 1024); + assertTrue(nread > -1, "Error read"); + printf("read:\n%s\n", readbuffer); + + // send special command "~~" followed by a string. It should be repeated back + // as "success: see no hands\nmetis> ", where the stuff after the \n is the next command prompt + char magic[] = "~~ see no hands\r\n"; + ssize_t nwritten = write(state->clientFd, magic, sizeof(magic)); + assertTrue(nwritten == sizeof(magic), "Error write, expected %zu got %zd", sizeof(magic), nwritten); + + metisDispatcher_RunDuration(state->dispatcher, &((struct timeval) { 0, 1000 })); + + memset(readbuffer, 0, 1024); + nread = read(state->clientFd, readbuffer, 1024); + assertTrue(nread > -1, "Error read"); + + // we look for the answer without the "\nmetis> " part. + char answer[] = "success: see no hands"; + assertTrue(strncasecmp(readbuffer, answer, sizeof(answer) - 1) == 0, "Got wrong string: %s", readbuffer); +} + +LONGBOW_TEST_CASE(Global, Version) +{ + TestState *state = longBowTestCase_GetClipBoardData(testCase); + + char readbuffer[1024]; + + // Skipover the MOTD + ssize_t nread = read(state->clientFd, readbuffer, 1024); + assertTrue(nread > -1, "Error read"); + + printf("read:\n%s\n", readbuffer); + + // send special command "~~" followed by a string. It should be repeated back + // as "success: see no hands\nmetis> ", where the stuff after the \n is the next command prompt + char magic[] = "ver\r\n"; + ssize_t nwritten = write(state->clientFd, magic, sizeof(magic)); + assertTrue(nwritten == sizeof(magic), "Error write, expected %zu got %zd", sizeof(magic), nwritten); + + metisDispatcher_RunDuration(state->dispatcher, &((struct timeval) { 0, 1000 })); + + memset(readbuffer, 0, 1024); + nread = read(state->clientFd, readbuffer, 1024); + assertTrue(nread > -1, "Error read"); + + printf("%s", readbuffer); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_metis_CommandLineInterface); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metis_CommandOps.c b/metis/ccnx/forwarder/metis/config/test/test_metis_CommandOps.c new file mode 100644 index 00000000..4d6a5c13 --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metis_CommandOps.c @@ -0,0 +1,104 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metis_CommandOps.c" + +#include <inttypes.h> +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(metis_CommandOps) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metis_CommandOps) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metis_CommandOps) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisCommandOps_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +static void +_init(struct metis_command_parser *parser, MetisCommandOps *ops) +{ +} + +static MetisCommandReturn +_execute(struct metis_command_parser *parser, MetisCommandOps *ops, PARCList *args) +{ + return MetisCommandReturn_Success; +} + +static void +_destroyer(MetisCommandOps **opsPtr) +{ +} + +LONGBOW_TEST_CASE(Global, metisCommandOps_Create) +{ + char hello[] = "hello"; + char command[] = "test"; + + MetisCommandOps *ops = metisCommandOps_Create(hello, command, _init, _execute, _destroyer); + + assertTrue(ops->closure == hello, "closure wrong expected %p got %p", (void *) hello, (void *) ops->closure); + assertTrue(strcmp(ops->command, command) == 0, "command wrong expected '%s' got '%s'", command, ops->command); + assertTrue(ops->init == _init, "Wrong init, expected %" PRIXPTR " got %" PRIXPTR, (uintptr_t) _init, (uintptr_t) ops->init); + assertTrue(ops->execute == _execute, "Wrong execute, expected %" PRIXPTR " got %" PRIXPTR, (uintptr_t) _execute, (uintptr_t) ops->execute); + assertTrue(ops->destroyer == _destroyer, "Wrong destroyer, expected %" PRIXPTR " got %" PRIXPTR, (uintptr_t) _destroyer, (uintptr_t) ops->destroyer); + + metisCommandOps_Destroy(&ops); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_CommandOps); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metis_CommandParser.c b/metis/ccnx/forwarder/metis/config/test/test_metis_CommandParser.c new file mode 100644 index 00000000..b7e6edae --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metis_CommandParser.c @@ -0,0 +1,259 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metis_CommandParser.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(metis_CommandParser) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metis_CommandParser) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metis_CommandParser) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisCommandParser_Create_Destroy); + + LONGBOW_RUN_TEST_CASE(Global, metisCommandParser_DispatchCommand_Exact); + LONGBOW_RUN_TEST_CASE(Global, metisCommandParser_DispatchCommand_Longer); + LONGBOW_RUN_TEST_CASE(Global, metisCommandParser_DispatchCommand_Shorter); + LONGBOW_RUN_TEST_CASE(Global, metisCommandParser_DispatchCommand_Sibling); + LONGBOW_RUN_TEST_CASE(Global, metisCommandParser_GetDebug); + LONGBOW_RUN_TEST_CASE(Global, metisCommandParser_Interactive); + LONGBOW_RUN_TEST_CASE(Global, metisCommandParser_RegisterCommand_NullInit); + LONGBOW_RUN_TEST_CASE(Global, metisCommandParser_RegisterCommand_WithInit); + LONGBOW_RUN_TEST_CASE(Global, metisCommandParser_SetDebug); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisCommandParser_Create_Destroy) +{ + MetisCommandParser *parser = metisCommandParser_Create(); + assertNotNull(parser, "Got null parser from metisCommandParser_Create"); + metisCommandParser_Destroy(&parser); + assertTrue(parcSafeMemory_ReportAllocation(STDOUT_FILENO) == 0, "Memory imbalance!"); + assertNull(parser, "metisCommandParser_Destroy did not null pointer"); +} + +static MetisCommandReturn +test_execute(MetisCommandParser *parser, MetisCommandOps *ops, PARCList *args) +{ + bool *execute_called_ptr = (bool *) ops->closure; + *execute_called_ptr = true; + return MetisCommandReturn_Success; +} + +/** + * argc = the exact number of args, don't include the command name + * example: argc = 2, argv = {"Hello", "World"} + * + * expectedResult true means the execute function is called + */ +static void +dispatchCommand(const char *command_string, int argc, char **argv, bool expectedResult) +{ + MetisCommandParser *parser = metisCommandParser_Create(); + + bool execute_called = false; + + MetisCommandOps *ops = metisCommandOps_Create(&execute_called, command_string, NULL, test_execute, metisCommandOps_Destroy); + + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, argc, (void **) &argv[0]); + + execute_called = false; + metisCommandParser_RegisterCommand(parser, ops); + metisCommandParser_DispatchCommand(parser, args); + if (expectedResult) { + assertTrue(execute_called, "Did not call the execute function"); + } else { + assertFalse(execute_called, "The execute function should not have been called but was"); + } + + metisCommandParser_Destroy(&parser); + parcList_Release(&args); +} + +LONGBOW_TEST_CASE(Global, metisCommandParser_DispatchCommand_Exact) +{ + // note that it is not case sensitive + dispatchCommand("hello world", 2, (char *[]) { "Hello", "World" }, true); +} + +LONGBOW_TEST_CASE(Global, metisCommandParser_DispatchCommand_Sibling) +{ + // note that it is not case sensitive + dispatchCommand("hello world", 2, (char *[]) { "Hello", "Universe" }, false); +} + + +LONGBOW_TEST_CASE(Global, metisCommandParser_DispatchCommand_Longer) +{ + // note that it is not case sensitive + dispatchCommand("hello world", 3, (char *[]) { "Hello", "World", "Again" }, true); +} + +LONGBOW_TEST_CASE(Global, metisCommandParser_DispatchCommand_Shorter) +{ + // note that it is not case sensitive + dispatchCommand("hello world", 1, (char *[]) { "Hello" }, false); +} + +LONGBOW_TEST_CASE(Global, metisCommandParser_GetDebug) +{ + MetisCommandParser *parser = metisCommandParser_Create(); + bool test = metisCommandParser_GetDebug(parser); + assertTrue(test == parser->debugFlag, "Got %d expected %d", test, parser->debugFlag); + metisCommandParser_Destroy(&parser); +} + +LONGBOW_TEST_CASE(Global, metisCommandParser_Interactive) +{ + testUnimplemented(""); +} + +static bool called_init = false; +static void +test_init_command(MetisCommandParser *parser, MetisCommandOps *ops) +{ + called_init = true; +} + +LONGBOW_TEST_CASE(Global, metisCommandParser_RegisterCommand_WithInit) +{ + MetisCommandParser *parser = metisCommandParser_Create(); + + MetisCommandOps *ops = metisCommandOps_Create(NULL, "hello world", test_init_command, test_execute, metisCommandOps_Destroy); + + called_init = false; + metisCommandParser_RegisterCommand(parser, ops); + + MetisCommandOps *test = parcTreeRedBlack_Get(parser->commandTree, ops->command); + assertNotNull(test, "Got null looking up command in tree"); + assertTrue(test == ops, "Wrong pointer, got %p expected %p", (void *) test, (void *) ops); + assertTrue(called_init, "Did not call the init function"); + + metisCommandParser_Destroy(&parser); +} + +LONGBOW_TEST_CASE(Global, metisCommandParser_RegisterCommand_NullInit) +{ + MetisCommandParser *parser = metisCommandParser_Create(); + + MetisCommandOps command = { + .command = "hello world", + .init = NULL, + .execute = NULL + }; + + called_init = false; + metisCommandParser_RegisterCommand(parser, &command); + + MetisCommandOps *test = parcTreeRedBlack_Get(parser->commandTree, command.command); + assertNotNull(test, "Got null looking up command in tree"); + assertTrue(test == &command, "Wrong pointer, got %p expected %p", (void *) test, (void *) &command); + assertFalse(called_init, "Somehow called the init function"); + + metisCommandParser_Destroy(&parser); +} + +LONGBOW_TEST_CASE(Global, metisCommandParser_SetDebug) +{ + MetisCommandParser *parser = metisCommandParser_Create(); + // flip the setting + bool truth = ~parser->debugFlag; + metisCommandParser_SetDebug(parser, truth); + assertTrue(truth == parser->debugFlag, "Got %d expected %d", parser->debugFlag, truth); + metisCommandParser_Destroy(&parser); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisCommandParser_MatchCommand); + LONGBOW_RUN_TEST_CASE(Local, parseStringIntoTokens); + LONGBOW_RUN_TEST_CASE(Local, stringCompare); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, metisCommandParser_MatchCommand) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Local, parseStringIntoTokens) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Local, stringCompare) +{ + testUnimplemented(""); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_CommandParser); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metis_Configuration.c b/metis/ccnx/forwarder/metis/config/test/test_metis_Configuration.c new file mode 100644 index 00000000..09b9a576 --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metis_Configuration.c @@ -0,0 +1,779 @@ +/* + * 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. + */ + +/* + * Some of these tests might not execute on certain systems, as they + * depend on having INET and INET6 addresses available. If you system + * does not have one or both of those, the corresponding tests will not + * execute. + */ + +// We need to specifically include the Ethernet mockup and set the proper define so +// we do not need an actual Ethernet listener + +#define METIS_MOCK_ETHERNET 1 +#include "../../io/test/testrig_GenericEther.c" + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metis_Configuration.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + +#include <signal.h> + +// so we can mock up an interface +#include "../../core/test/testrig_MetisIoOperations.h" + +// so we can test content store size +#include "../../core/metis_Forwarder.c" +#include "../../processor/metis_MessageProcessor.c" +#include "../../content_store/metis_ContentStoreInterface.h" + +struct sigaction save_sigchld; +struct sigaction save_sigpipe; + +/** + * Add a connection to the connection table to mock the "ingress" port of a control message + * + * You must release the return value + * + * @param [<#in out in,out#>] <#name#> <#description#> + * + * @retval non-null A mockup of a connection + * @retval null An error + * + * Example: + * @code + * { + * unsigned mockConnectionId = 7; + * MetisIoOperations *ops = _addIngressMockConnection(metis, mockConnectionId); + * MockIoOperationsData *data = ops->context; + * mockIoOperationsData_Destroy(&ops); + * } + * @endcode + */ +static MetisIoOperations * +_addIngressMockConnection(MetisForwarder *metis, unsigned mockup_id) +{ + MetisIoOperations *ops = mockIoOperationsData_CreateSimple(1, 2, mockup_id, true, true, true); + + MetisConnection *conn = metisConnection_Create(ops); + MetisConnectionTable *connTable = metisForwarder_GetConnectionTable(metis); + metisConnectionTable_Add(connTable, conn); + return ops; +} + +// returns a strdup() of the interface name, use free(3) +static char * +_pickInterfaceName(MetisForwarder *metis) +{ + char *ifname = NULL; + + CPIInterfaceSet *set = metisSystem_Interfaces(metis); + size_t length = cpiInterfaceSet_Length(set); + assertTrue(length > 0, "metisSystem_Interfaces returned no interfaces"); + + for (size_t i = 0; i < length; i++) { + CPIInterface *iface = cpiInterfaceSet_GetByOrdinalIndex(set, i); + const CPIAddressList *addressList = cpiInterface_GetAddresses(iface); + + size_t length = cpiAddressList_Length(addressList); + for (size_t i = 0; i < length && !ifname; i++) { + const CPIAddress *a = cpiAddressList_GetItem(addressList, i); + if (cpiAddress_GetType(a) == cpiAddressType_LINK) { + ifname = strdup(cpiInterface_GetName(iface)); + } + } + } + + cpiInterfaceSet_Destroy(&set); + return ifname; +} + +/** + * Adds a mock ethernet connection to the given peer address with a symbolic name. + * You must have previously added an Ethernet listener. + * + * @return true Added + * @return false An error + */ +static bool +_addEthernetConnection(MetisForwarder *metis, unsigned connid, const char *symbolicName, MetisListenerOps *listener, uint8_t peerEther[6]) +{ + // Create a CPIConnectionEthernet Add control message + char *ifname = _pickInterfaceName(metis); + + uint16_t etherType = 0x0801; + + CPIAddress *peerAddress = cpiAddress_CreateFromLink(peerEther, 6); + CPIConnectionEthernet *etherConn = cpiConnectionEthernet_Create(ifname, peerAddress, etherType, symbolicName); + bool success = _metisConfiguration_AddConnectionEthernet(metisForwarder_GetConfiguration(metis), etherConn, peerAddress, listener); + + + cpiAddress_Destroy(&peerAddress); + free(ifname); + cpiConnectionEthernet_Release(ðerConn); + + return success; +} + +// ========================================================================= + +LONGBOW_TEST_RUNNER(metis_Configuration) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + printf("line 140\n"); + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metis_Configuration) +{ + printf("line 148\n"); + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metis_Configuration) +{ + printf("line 156\n"); + return LONGBOW_STATUS_SUCCEEDED; +} + +// ============================================================================== + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisConfiguration_SetupAllListeners); + LONGBOW_RUN_TEST_CASE(Global, metisConfiguration_Receive); + LONGBOW_RUN_TEST_CASE(Global, metisConfiguration_SetObjectStoreSize); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisConfiguration_SetupAllListeners) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, metisConfiguration_Receive) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + + // Add a connection to apply the route to + unsigned mockConnectionId = 7000; + MetisIoOperations *ops = _addIngressMockConnection(metis, mockConnectionId); + MockIoOperationsData *data = metisIoOperations_GetClosure(ops); + + CCNxName *prefix = ccnxName_CreateFromCString("lci:/foo"); + CPIRouteEntry *routeEntry = cpiRouteEntry_Create(prefix, mockConnectionId, NULL, + cpiNameRouteProtocolType_STATIC, + cpiNameRouteType_LONGEST_MATCH, NULL, 4); + CCNxControl *request = ccnxControl_CreateAddRouteRequest(routeEntry); + cpiRouteEntry_Destroy(&routeEntry); + + PARCBuffer *buffer = metisTlv_EncodeControlPlaneInformation(request); + + MetisMessage *message = metisMessage_CreateFromArray(parcBuffer_Overlay(buffer, 0), parcBuffer_Limit(buffer), mockConnectionId, 2, metisForwarder_GetLogger(metis)); + parcBuffer_Release(&buffer); + + // this takes ownership of message and disposes of it + metisConfiguration_Receive(metisForwarder_GetConfiguration(metis), message); + + // crank the handle to lets the ACKs or NACKs move + metisDispatcher_RunDuration(metisForwarder_GetDispatcher(metis), &((struct timeval) { 0, 10000 })); + + assertTrue(data->sendCount == 1, "Did not send a response message, expected 1 got %u", data->sendCount); + CCNxControl *response = metisMessage_CreateControlMessage(data->lastMessage); + + assertTrue(cpi_GetMessageType(response) == CPI_ACK, + "CPI message not a response: %s", + parcJSON_ToString(ccnxControl_GetJson(response))); + + ccnxControl_Release(&response); + ccnxControl_Release(&request); + metisForwarder_Destroy(&metis); + + mockIoOperationsData_Destroy(&ops); +} + +LONGBOW_TEST_CASE(Global, metisConfiguration_SetObjectStoreSize) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + + MetisContentStoreInterface *store = metis->processor->contentStore; + MetisConfiguration *config = metisForwarder_GetConfiguration(metis); + size_t current_capacity = metisContentStoreInterface_GetObjectCapacity(store); + size_t new_capacity = current_capacity + 5; + + metisConfiguration_SetObjectStoreSize(config, new_capacity); + + // Get the store pointer again, as it may have changed. + store = metis->processor->contentStore; + assertTrue(new_capacity == metisContentStoreInterface_GetObjectCapacity(store), + "Object Store is wrong capacity, got %zu expected %zu", + metisContentStoreInterface_GetObjectCapacity(store), new_capacity); + + metisForwarder_Destroy(&metis); +} + +// ============================================================================== + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisConfiguration_Receive_AddConnectionEthernet); + LONGBOW_RUN_TEST_CASE(Local, metisConfiguration_Receive_AddConnectionEthernet_Dup); + + LONGBOW_RUN_TEST_CASE(Local, metisConfiguration_ProcessUnregisterPrefix); + LONGBOW_RUN_TEST_CASE(Local, metisConfiguration_ProcessRegisterPrefix); + LONGBOW_RUN_TEST_CASE(Local, metisConfiguration_ProcessRegisterPrefix_Symbolic); + + LONGBOW_RUN_TEST_CASE(Local, metisConfiguration_ProcessInterfaceList); + LONGBOW_RUN_TEST_CASE(Local, metisConfiguration_ProcessRegistrationList); + LONGBOW_RUN_TEST_CASE(Local, metisConfiguration_ProcessCreateTunnel_Dup); + LONGBOW_RUN_TEST_CASE(Local, metisConfiguration_ProcessCreateTunnel_TCP); + LONGBOW_RUN_TEST_CASE(Local, metisConfiguration_ProcessCreateTunnel_UDP); + LONGBOW_RUN_TEST_CASE(Local, metisConfiguration_ProcessConnectionList); + + LONGBOW_RUN_TEST_CASE(Local, metisConfiguration_ProcessAddConnectionEthernet); + LONGBOW_RUN_TEST_CASE(Local, metisConfiguration_ProcessRemoveConnectionEthernet); + + LONGBOW_RUN_TEST_CASE(Local, metisConfiguration_Receive_AddConnectionEthernet); + LONGBOW_RUN_TEST_CASE(Local, metisConfiguration_Receive_RemoveConnectionEthernet); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, metisConfiguration_ProcessInterfaceList) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + + CCNxControl *request = ccnxControl_CreateInterfaceListRequest(); + + unsigned mockConnectionId = 7; + + CCNxControl *response = metisConfiguration_ProcessInterfaceList(metisForwarder_GetConfiguration(metis), request, mockConnectionId); + + assertNotNull(response, "Got null response"); + + assertTrue(cpi_GetMessageType(response) == CPI_RESPONSE, + "CPI message not a response: %s", + parcJSON_ToString(ccnxControl_GetJson(response))); + + assertTrue(cpi_GetMessageOperation(response) == CPI_INTERFACE_LIST, + "CPI message not an interface list: %s", + parcJSON_ToString(ccnxControl_GetJson(response))); + + ccnxControl_Release(&response); + ccnxControl_Release(&request); + metisForwarder_Destroy(&metis); +} + +LONGBOW_TEST_CASE(Local, metisConfiguration_ProcessUnregisterPrefix) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Local, metisConfiguration_ProcessRegisterPrefix) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + + // Add a connection to apply the route to + unsigned mockConnectionId = 7000; + + CCNxName *prefix = ccnxName_CreateFromCString("lci:/foo"); + CPIRouteEntry *routeEntry = cpiRouteEntry_Create(prefix, mockConnectionId, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 4); + CCNxControl *request = ccnxControl_CreateAddRouteRequest(routeEntry); + cpiRouteEntry_Destroy(&routeEntry); + + CCNxControl *response = metisConfiguration_ProcessRegisterPrefix(metisForwarder_GetConfiguration(metis), request, mockConnectionId); + + // crank the handle to lets the ACKs or NACKs move + metisDispatcher_RunDuration(metisForwarder_GetDispatcher(metis), &((struct timeval) { 0, 10000 })); + + assertNotNull(response, "LastMessage is not set in the test rig"); + + assertTrue(cpi_GetMessageType(response) == CPI_ACK, + "CPI message not a response: %s", + parcJSON_ToString(ccnxControl_GetJson(response))); + + ccnxControl_Release(&response); + ccnxControl_Release(&request); + metisForwarder_Destroy(&metis); +} + +LONGBOW_TEST_CASE(Local, metisConfiguration_ProcessRegisterPrefix_Symbolic) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + + // Add a connection to apply the route to + unsigned mockConnectionId = 7000; + + // hack in the symbolic name because _addIngressMockConnection does not do that + metisSymbolicNameTable_Add(metisForwarder_GetConfiguration(metis)->symbolicNameTable, "foo0", mockConnectionId); + + CCNxName *prefix = ccnxName_CreateFromCString("lci:/foo"); + CPIRouteEntry *routeEntry = cpiRouteEntry_CreateSymbolic(prefix, "foo0", cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 4); + CCNxControl *request = ccnxControl_CreateAddRouteRequest(routeEntry); + cpiRouteEntry_Destroy(&routeEntry); + + CCNxControl *response = metisConfiguration_ProcessRegisterPrefix(metisForwarder_GetConfiguration(metis), request, mockConnectionId); + + // crank the handle to lets the ACKs or NACKs move + metisDispatcher_RunDuration(metisForwarder_GetDispatcher(metis), &((struct timeval) { 0, 10000 })); + + assertNotNull(response, "Response is NULL"); + + assertTrue(cpi_GetMessageType(response) == CPI_ACK, + "CPI message not a response: %s", + parcJSON_ToString(ccnxControl_GetJson(response))); + + ccnxControl_Release(&response); + ccnxControl_Release(&request); + metisForwarder_Destroy(&metis); +} + +/** + * Add a route, then verify the route shows up in a list + */ +LONGBOW_TEST_CASE(Local, metisConfiguration_ProcessRegistrationList) +{ + printf("\n%s starting\n", __func__); + + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + + // Create a mock up of an interface so we can see the response + unsigned mockup_id = 7; + + // Add a route to the forwarding table + CCNxName *prefix = ccnxName_CreateFromCString("lci:/pancakes/for/all"); + CPIRouteEntry *route = cpiRouteEntry_Create(prefix, 3, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 2); + metisForwarder_AddOrUpdateRoute(metis, route); + cpiRouteEntry_Destroy(&route); + + // Create a request and send it in to MetisConfiguration. The response will be + // sent out the "mockup_id" interface + + CCNxControl *request = ccnxControl_CreateRouteListRequest(); + MetisConfiguration *config = metisForwarder_GetConfiguration(metis); + CCNxControl *response = metisConfiguration_ProcessRegistrationList(config, request, mockup_id); + + assertNotNull(response, "Got null response"); + + assertTrue(cpi_GetMessageType(response) == CPI_RESPONSE, + "CPI message not a response: %s", + parcJSON_ToString(ccnxControl_GetJson(response))); + + assertTrue(cpi_GetMessageOperation(response) == CPI_PREFIX_REGISTRATION_LIST, + "CPI message not an interface list: %s", + parcJSON_ToString(ccnxControl_GetJson(response))); + + ccnxControl_Release(&response); + ccnxControl_Release(&request); + metisForwarder_Destroy(&metis); +} + +LONGBOW_TEST_CASE(Local, metisConfiguration_ProcessCreateTunnel_TCP) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + + // Create a mock up of an interface so we can see the response + unsigned mockup_id = 7; + + // ----- + // Issue a command to create a TCP tunnel. We should be able to verify that it's in + // the connection table and we'll see the ACK come back to our mock interface. + + // --------------------------- + // Tunnel addresses + struct sockaddr_in sockaddr_any; + memset(&sockaddr_any, 0, sizeof(sockaddr_any)); + sockaddr_any.sin_family = PF_INET; + sockaddr_any.sin_addr.s_addr = INADDR_ANY; + + CPIAddress *source = cpiAddress_CreateFromInet(&sockaddr_any); + + struct sockaddr_in sockaddr_dst; + memset(&sockaddr_dst, 0, sizeof(sockaddr_dst)); + sockaddr_dst.sin_family = PF_INET; + sockaddr_dst.sin_port = htons(PORT_NUMBER); + inet_pton(AF_INET, "127.0.0.1", &(sockaddr_dst.sin_addr)); + + CPIAddress *destination = cpiAddress_CreateFromInet(&sockaddr_dst); + + // --------------------------- + + CPIInterfaceIPTunnel *iptun = cpiInterfaceIPTunnel_Create(0, source, destination, IPTUN_TCP, "tun0"); + CCNxControl *request = ccnxControl_CreateIPTunnelRequest(iptun); + + MetisConfiguration *config = metisForwarder_GetConfiguration(metis); + + CCNxControl *response = metisConfiguration_ProcessCreateTunnel(config, request, mockup_id); + + // crank the handle to lets the ACKs or NACKs move + metisDispatcher_RunDuration(metisForwarder_GetDispatcher(metis), &((struct timeval) { 0, 10000 })); + + // Validate the ACK + assertNotNull(response, "Got null response"); + + assertTrue(cpi_GetMessageType(response) == CPI_ACK, + "CPI message not an ACK: %s", + parcJSON_ToString(ccnxControl_GetJson(response))); + + ccnxControl_Release(&response); + ccnxControl_Release(&request); + cpiInterfaceIPTunnel_Release(&iptun); + metisForwarder_Destroy(&metis); +} + +LONGBOW_TEST_CASE(Local, metisConfiguration_ProcessCreateTunnel_Dup) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + + // Create a mock up of an interface so we can see the response + unsigned mockup_id = 7000; + MetisIoOperations *ops = _addIngressMockConnection(metis, mockup_id); + + // --------------------------- + // Tunnel addresses + struct sockaddr_in sockaddr_any; + memset(&sockaddr_any, 0, sizeof(sockaddr_any)); + sockaddr_any.sin_family = PF_INET; + sockaddr_any.sin_addr.s_addr = INADDR_ANY; + + CPIAddress *source = cpiAddress_CreateFromInet(&sockaddr_any); + + struct sockaddr_in sockaddr_dst; + memset(&sockaddr_dst, 0, sizeof(sockaddr_dst)); + sockaddr_dst.sin_family = PF_INET; + sockaddr_dst.sin_port = htons(PORT_NUMBER); + inet_pton(AF_INET, "127.0.0.1", &(sockaddr_dst.sin_addr)); + + CPIAddress *destination = cpiAddress_CreateFromInet(&sockaddr_dst); + + // --------------------------- + + CPIInterfaceIPTunnel *iptun = cpiInterfaceIPTunnel_Create(0, source, destination, IPTUN_TCP, "tun0"); + CCNxControl *request = ccnxControl_CreateIPTunnelRequest(iptun); + + MetisConfiguration *config = metisForwarder_GetConfiguration(metis); + + CCNxControl *response_1 = metisConfiguration_ProcessCreateTunnel(config, request, mockup_id); + assertNotNull(response_1, "got null response"); + assertTrue(ccnxControl_IsACK(response_1), "Did not get ACK response for first tunnel"); + ccnxControl_Release(&response_1); + + CCNxControl *response_2 = metisConfiguration_ProcessCreateTunnel(config, request, mockup_id); + assertNotNull(response_2, "got null response"); + assertTrue(ccnxControl_IsNACK(response_2), "Did not get NACK response for second tunnel"); + + ccnxControl_Release(&response_2); + + ccnxControl_Release(&request); + cpiInterfaceIPTunnel_Release(&iptun); + metisForwarder_Destroy(&metis); + mockIoOperationsData_Destroy(&ops); +} + +LONGBOW_TEST_CASE(Local, metisConfiguration_ProcessCreateTunnel_UDP) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + + // Create a mock up of an interface so we can see the response + unsigned mockup_id = 7; + + // ----- + // Issue a command to create a UDP tunnel. We should be able to verify that it's in + // the connection table and we'll see the ACK come back to our mock interface. + + // --------------------------- + // Tunnel addresses + struct sockaddr_in sockaddr_any; + memset(&sockaddr_any, 0, sizeof(sockaddr_any)); + sockaddr_any.sin_family = PF_INET; + sockaddr_any.sin_addr.s_addr = INADDR_ANY; + + CPIAddress *source = cpiAddress_CreateFromInet(&sockaddr_any); + + struct sockaddr_in sockaddr_dst; + memset(&sockaddr_dst, 0, sizeof(sockaddr_dst)); + sockaddr_dst.sin_family = PF_INET; + sockaddr_dst.sin_port = htons(PORT_NUMBER); + inet_pton(AF_INET, "127.0.0.1", &(sockaddr_dst.sin_addr)); + + CPIAddress *destination = cpiAddress_CreateFromInet(&sockaddr_dst); + + // --------------------------- + + CPIInterfaceIPTunnel *iptun = cpiInterfaceIPTunnel_Create(0, source, destination, IPTUN_UDP, "conn0"); + CCNxControl *request = ccnxControl_CreateIPTunnelRequest(iptun); + + MetisConfiguration *config = metisForwarder_GetConfiguration(metis); + + CCNxControl *response = metisConfiguration_ProcessCreateTunnel(config, request, mockup_id); + + // Validate the ACK + assertNotNull(response, "Got null response"); + + assertTrue(cpi_GetMessageType(response) == CPI_ACK, + "CPI message not an ACK: %s", + parcJSON_ToString(ccnxControl_GetJson(response))); + + ccnxControl_Release(&response); + ccnxControl_Release(&request); + cpiInterfaceIPTunnel_Release(&iptun); + metisForwarder_Destroy(&metis); +} + + +LONGBOW_TEST_CASE(Local, metisConfiguration_ProcessConnectionList) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + + // Create a mock up of an interface so we can see the response + unsigned mockup_id = 7; + MetisIoOperations *ops = _addIngressMockConnection(metis, mockup_id); + + CCNxControl *request = ccnxControl_CreateConnectionListRequest(); + + MetisConfiguration *config = metisForwarder_GetConfiguration(metis); + CCNxControl *response = metisConfiguration_ProcessConnectionList(config, request, mockup_id); + + // Validate the response + assertNotNull(response, "Got null response"); + + // Get the CPI response out of the test mock up + CPIConnectionList *list = cpiLinks_ConnectionListFromControlMessage(response); + assertTrue(cpiConnectionList_Length(list) == 1, "Wrong list size, expected %u got %zu", 1, cpiConnectionList_Length(list)); + + ccnxControl_Release(&response); + ccnxControl_Release(&request); + cpiConnectionList_Destroy(&list); + metisForwarder_Destroy(&metis); + mockIoOperationsData_Destroy(&ops); +} + + +LONGBOW_TEST_CASE(Local, metisConfiguration_ProcessAddConnectionEthernet) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Debug); + + // Create a mock up of an interface so we can see the response + unsigned mockup_id = 77; + + // create the listener + char *ifname = _pickInterfaceName(metis); + CPIListener *cpiListener = cpiListener_CreateEther(ifname, 0x0801, "fake0"); + CCNxControl *control = cpiListener_CreateAddMessage(cpiListener); + bool listenerOk = metisConfigurationListeners_Add(metisForwarder_GetConfiguration(metis), control, mockup_id); + assertTrue(listenerOk, "Failed to setup ether listener."); + + ccnxControl_Release(&control); + cpiListener_Release(&cpiListener); + + // ======== + uint8_t peerEther[6] = { 0x02, 0x33, 0x44, 0x55, 0x66, 0x77 }; + CPIAddress *peerAddress = cpiAddress_CreateFromLink(peerEther, sizeof(peerEther)); + CPIConnectionEthernet *etherconn = cpiConnectionEthernet_Create(ifname, peerAddress, 0x0801, "conn3"); + CCNxControl *addRequest = cpiConnectionEthernet_CreateAddMessage(etherconn); + + MetisConfiguration *config = metisForwarder_GetConfiguration(metis); + + CCNxControl *response = metisConfiguration_ProcessAddConnectionEthernet(config, addRequest, mockup_id); + + // crank the handle to lets the ACKs or NACKs move + metisDispatcher_RunDuration(metisForwarder_GetDispatcher(metis), &((struct timeval) { 0, 10000 })); + + // Get the CPI response out of the test mock up + assertNotNull(response, "Got null response"); + + assertTrue(ccnxControl_IsACK(response), "Response is not an ACK") + { + ccnxControl_Display(response, 3); + } + + // we must manually destroy a Mock connection + ccnxControl_Release(&response); + free(ifname); + cpiConnectionEthernet_Release(ðerconn); + cpiAddress_Destroy(&peerAddress); + ccnxControl_Release(&addRequest); + metisForwarder_Destroy(&metis); +} + +LONGBOW_TEST_CASE(Local, metisConfiguration_ProcessRemoveConnectionEthernet) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Local, metisConfiguration_Receive_AddConnectionEthernet) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Debug); + + // Create a mock up of an interface so we can see the response + unsigned mockup_id = 7; + MetisIoOperations *ops = _addIngressMockConnection(metis, mockup_id); + + // create the listener + char *ifname = _pickInterfaceName(metis); + CPIListener *cpiListener = cpiListener_CreateEther(ifname, 0x0801, "fake0"); + CCNxControl *control = cpiListener_CreateAddMessage(cpiListener); + bool listenerOk = metisConfigurationListeners_Add(metisForwarder_GetConfiguration(metis), control, mockup_id); + assertTrue(listenerOk, "Failed to setup ether listener."); + + ccnxControl_Release(&control); + cpiListener_Release(&cpiListener); + + // create the connection + uint8_t linkAddrArray[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; + uint16_t etherType = 0x0801; + + CPIAddress *peerAddress = cpiAddress_CreateFromLink(linkAddrArray, sizeof(linkAddrArray)); + CPIConnectionEthernet *etherconn = cpiConnectionEthernet_Create(ifname, peerAddress, etherType, "conn3"); + CCNxControl *addRequest = cpiConnectionEthernet_CreateAddMessage(etherconn); + + // Translate the control message to a MetisMessage + PARCBuffer *buffer = metisTlv_EncodeControlPlaneInformation(addRequest); + + MetisMessage *message = metisMessage_CreateFromArray(parcBuffer_Overlay(buffer, 0), parcBuffer_Limit(buffer), mockup_id, 2, metisForwarder_GetLogger(metis)); + + MetisConfiguration *config = metisForwarder_GetConfiguration(metis); + + // this will release the message + metisConfiguration_Receive(config, message); + + // ==== Verify it's in the connection table + + MetisConnectionList *connList = metisConnectionTable_GetEntries(metisForwarder_GetConnectionTable(metis)); + assertNotNull(connList, "Got null connection list"); + + bool found = false; + for (size_t i = 0; i < metisConnectionList_Length(connList) && !found; i++) { + MetisConnection *conn = metisConnectionList_Get(connList, i); + const MetisAddressPair *pair = metisConnection_GetAddressPair(conn); + const CPIAddress *remote = metisAddressPair_GetRemote(pair); + if (cpiAddress_Equals(remote, peerAddress)) { + found = true; + } + } + + assertTrue(found, "Could not find peer address in the connection table as a remote"); + + // ==== Cleanup + + parcBuffer_Release(&buffer); + ccnxControl_Release(&addRequest); + cpiConnectionEthernet_Release(ðerconn); + cpiAddress_Destroy(&peerAddress); + free(ifname); + metisConnectionList_Destroy(&connList); + metisForwarder_Destroy(&metis); + mockIoOperationsData_Destroy(&ops); +} + +/* + * Try to add a second connection with same symbolic name + */ +LONGBOW_TEST_CASE(Local, metisConfiguration_Receive_AddConnectionEthernet_Dup) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + + uint8_t peerEther[6] = { 7, 8, 9, 10, 11, 12 }; + + // Create a mock up of an interface so we can see the response + unsigned mockup_id = 7000; + MetisIoOperations *ops = _addIngressMockConnection(metis, mockup_id); + + char *ifname = _pickInterfaceName(metis); + CPIListener *cpiListener = cpiListener_CreateEther(ifname, 0x0801, "fake0"); + CCNxControl *control = cpiListener_CreateAddMessage(cpiListener); + metisConfigurationListeners_Add(metisForwarder_GetConfiguration(metis), control, mockup_id); + ccnxControl_Release(&control); + cpiListener_Release(&cpiListener); + free(ifname); + + MetisListenerOps *listener = metisListenerSet_Get(metisForwarder_GetListenerSet(metis), 0); + + // Create a mock up of an interface so we can see the response + bool success = _addEthernetConnection(metis, 1000, "conn3", listener, peerEther); + assertTrue(success, "Failed to add first instance of connection"); + + // now add again, should fail + bool failure = _addEthernetConnection(metis, 1001, "conn3", listener, peerEther); + assertFalse(failure, "Should have failed to add it a second time"); + + metisForwarder_Destroy(&metis); + mockIoOperationsData_Destroy(&ops); +} + +LONGBOW_TEST_CASE(Local, metisConfiguration_Receive_RemoveConnectionEthernet) +{ +} + +// ====================================================== + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_Configuration); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metis_ConfigurationFile.c b/metis/ccnx/forwarder/metis/config/test/test_metis_ConfigurationFile.c new file mode 100644 index 00000000..6c7e19df --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metis_ConfigurationFile.c @@ -0,0 +1,403 @@ +/* + * 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. + */ + + +#include "../metis_ConfigurationFile.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> +#include <errno.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/stat.h> + +// ========================================================================= + +LONGBOW_TEST_RUNNER(metis_ConfigurationFile) +{ + LONGBOW_RUN_TEST_FIXTURE(Create); + LONGBOW_RUN_TEST_FIXTURE(Process); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metis_ConfigurationFile) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metis_ConfigurationFile) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ============================================================================== + +LONGBOW_TEST_FIXTURE(Create) +{ + LONGBOW_RUN_TEST_CASE(Create, metisConfigurationFile_Create); + LONGBOW_RUN_TEST_CASE(Create, metisConfigurationFile_Create_CantRead); + LONGBOW_RUN_TEST_CASE(Create, metisConfigurationFile_Create_Missing); +} + +LONGBOW_TEST_FIXTURE_SETUP(Create) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Create) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +static void +_writeConfigFile(FILE *fh) +{ + ssize_t nwritten = fprintf(fh, "add listener udp conn0 127.0.0.1 9696\n"); + assertTrue(nwritten > 0, "Bad fprintf"); + fflush(fh); +} + +LONGBOW_TEST_CASE(Create, metisConfigurationFile_Create) +{ + char template[] = "/tmp/test_metis_ConfigurationFile.XXXXXX"; + int fd = mkstemp(template); + assertTrue(fd > -1, "Error creating temp file: (%d) %s", errno, strerror(errno)); + + FILE *fh = fdopen(fd, "w"); + _writeConfigFile(fh); + + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + + MetisConfigurationFile *cf = metisConfigurationFile_Create(metis, template); + + assertNotNull(cf, "Should have returned non-null for good configuration file"); + + metisConfigurationFile_Release(&cf); + metisForwarder_Destroy(&metis); + fclose(fh); + unlink(template); +} + +LONGBOW_TEST_CASE(Create, metisConfigurationFile_Create_CantRead) +{ + char template[] = "/tmp/test_metis_ConfigurationFile.XXXXXX"; + int fd = mkstemp(template); + assertTrue(fd > -1, "Error creating temp file: (%d) %s", errno, strerror(errno)); + + chmod(template, 0); + + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + + MetisConfigurationFile *cf = metisConfigurationFile_Create(metis, template); + + chmod(template, 0600); + unlink(template); + + uid_t uid = getuid(), euid = geteuid(); + if (uid <= 0 || uid != euid) { + metisConfigurationFile_Release(&cf); + } else { + assertNull(cf, "Should have returned null configuration file for non-readable file"); + } + + metisForwarder_Destroy(&metis); + close(fd); +} + +LONGBOW_TEST_CASE(Create, metisConfigurationFile_Create_Missing) +{ + char template[] = "/tmp/test_metis_ConfigurationFile.ZZZZZZZZZ"; + + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + + MetisConfigurationFile *cf = metisConfigurationFile_Create(metis, template); + + assertNull(cf, "Should have returned null configuration file for missing file"); + + metisForwarder_Destroy(&metis); +} + +// ====================================================== + +typedef struct test_data { + MetisForwarder *metis; + char template[1024]; + int fd; + FILE *fh; +} TestData; + +LONGBOW_TEST_FIXTURE(Process) +{ + LONGBOW_RUN_TEST_CASE(Process, metisConfigurationFile_Process_NoErrors); + LONGBOW_RUN_TEST_CASE(Process, metisConfigurationFile_Process_WithErrors); + LONGBOW_RUN_TEST_CASE(Process, metisConfigurationFile_Process_WithComments); + LONGBOW_RUN_TEST_CASE(Process, metisConfigurationFile_Process_Whitespace); +} + +LONGBOW_TEST_FIXTURE_SETUP(Process) +{ + TestData *data = parcMemory_Allocate(sizeof(TestData)); + data->metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(data->metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + metisLogger_SetLogLevel(metisForwarder_GetLogger(data->metis), MetisLoggerFacility_IO, PARCLogLevel_Debug); + + sprintf(data->template, "/tmp/test_metis_ConfigurationFile.XXXXXX"); + + data->fd = mkstemp(data->template); + assertTrue(data->fd > -1, "Error creating temp file: (%d) %s", errno, strerror(errno)); + + data->fh = fdopen(data->fd, "w"); + + longBowTestCase_SetClipBoardData(testCase, data); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Process) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + fclose(data->fh); + unlink(data->template); + metisForwarder_Destroy(&data->metis); + parcMemory_Deallocate((void **) &data); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Process, metisConfigurationFile_Process_NoErrors) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + _writeConfigFile(data->fh); + + MetisConfigurationFile *cf = metisConfigurationFile_Create(data->metis, data->template); + + bool success = metisConfigurationFile_Process(cf); + assertTrue(success, "Failed to execute configuration file."); + assertTrue(cf->linesRead == 1, "Should have read 1 line, got %zu", cf->linesRead); + + metisConfigurationFile_Release(&cf); +} + +LONGBOW_TEST_CASE(Process, metisConfigurationFile_Process_WithErrors) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + _writeConfigFile(data->fh); + + ssize_t nwritten = fprintf(data->fh, "blah blah\n"); + assertTrue(nwritten > 0, "Bad write"); + + // this should not be executed + nwritten = fprintf(data->fh, "add listener conn3 tcp 127.0.0.1 9696\n"); + assertTrue(nwritten > 0, "Bad write"); + + fflush(data->fh); + + MetisConfigurationFile *cf = metisConfigurationFile_Create(data->metis, data->template); + + bool success = metisConfigurationFile_Process(cf); + assertFalse(success, "Should have failed to execute configuration file.") { + int res; + res = system("netstat -an -p tcp"); + assertTrue(res != -1, "Error on system call"); + res = system("ps -el"); + assertTrue(res != -1, "Error on system call"); + } + assertTrue(cf->linesRead == 2, "Should have read 2 lines, got %zu", cf->linesRead); + + metisConfigurationFile_Release(&cf); +} + +LONGBOW_TEST_CASE(Process, metisConfigurationFile_Process_WithComments) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + _writeConfigFile(data->fh); + + ssize_t nwritten = fprintf(data->fh, "# ignore this\n"); + assertTrue(nwritten > 0, "Bad write"); + + nwritten = fprintf(data->fh, "add listener tcp conn3 127.0.0.1 9696\n"); + assertTrue(nwritten > 0, "Bad write"); + + fflush(data->fh); + + MetisConfigurationFile *cf = metisConfigurationFile_Create(data->metis, data->template); + + bool success = metisConfigurationFile_Process(cf); + assertTrue(success, "Should have failed to execute configuration file.") { + int res; + res = system("netstat -an -p tcp"); + assertTrue(res != -1, "Error on system call"); + res = system("ps -el"); + assertTrue(res != -1, "Error on system call"); + } + assertTrue(cf->linesRead == 3, "Should have read 3 lines, got %zu", cf->linesRead); + + metisConfigurationFile_Release(&cf); +} + +LONGBOW_TEST_CASE(Process, metisConfigurationFile_Process_Whitespace) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + _writeConfigFile(data->fh); + + ssize_t nwritten = fprintf(data->fh, "add listener tcp conn3 127.0.0.1 9696\n"); + assertTrue(nwritten > 0, "Bad write"); + + fflush(data->fh); + + MetisConfigurationFile *cf = metisConfigurationFile_Create(data->metis, data->template); + + bool success = metisConfigurationFile_Process(cf); + assertTrue(success, "Should have failed to execute configuration file.") { + int res; + res = system("netstat -an -p tcp"); + assertTrue(res != -1, "Error on system call"); + res = system("ps -el"); + assertTrue(res != -1, "Error on system call"); + } + assertTrue(cf->linesRead == 2, "Should have read 2 lines, got %zu", cf->linesRead); + + metisConfigurationFile_Release(&cf); +} + + +// ============================================================================== + + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, _stripLeadingWhitespace); + LONGBOW_RUN_TEST_CASE(Local, _stripTrailingWhitespace); + LONGBOW_RUN_TEST_CASE(Local, _trim); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +typedef struct test_vector { + const char *input; + const char *output; + bool sentinel; +} TestVector; + +LONGBOW_TEST_CASE(Local, _stripLeadingWhitespace) +{ + TestVector vectors[] = { + { .input = "", .output = "" }, + { .input = " ", .output = "" }, + { .input = "\t", .output = "" }, + { .input = "a", .output = "a" }, + { .input = "abc", .output = "abc" }, + { .input = " a c ", .output = "a c " }, + { .input = " bc", .output = "bc" }, + { .input = "\tbc", .output = "bc" }, + { .input = " \tbc", .output = "bc" }, + { .input = "\t\tbc ", .output = "bc " }, + { .input = NULL, .output = NULL }, + }; + + for (int i = 0; vectors[i].input != NULL; i++) { + char *copy = parcMemory_StringDuplicate(vectors[i].input, strlen(vectors[i].input)); + char *test = _stripLeadingWhitespace(copy); + assertTrue(strcmp(test, vectors[i].output) == 0, "Bad output index %d. input = '%s' expected = '%s' actual = '%s'", i, vectors[i].input, vectors[i].output, test); + parcMemory_Deallocate((void **) ©); + } +} + +LONGBOW_TEST_CASE(Local, _stripTrailingWhitespace) +{ + TestVector vectors[] = { + { .input = "", .output = "" }, + { .input = " ", .output = "" }, + { .input = "\t", .output = "" }, + { .input = "a", .output = "a" }, + { .input = "abc", .output = "abc" }, + { .input = " a c ", .output = " a c" }, + { .input = "bc ", .output = "bc" }, + { .input = "bc\t", .output = "bc" }, + { .input = "bc \t", .output = "bc" }, + { .input = " bc\t\t", .output = " bc" }, + { .input = NULL, .output = NULL }, + }; + + for (int i = 0; vectors[i].input != NULL; i++) { + char *copy = parcMemory_StringDuplicate(vectors[i].input, strlen(vectors[i].input)); + char *test = _stripTrailingWhitespace(copy); + assertTrue(strcmp(test, vectors[i].output) == 0, "Bad output index %d. input = '%s' expected = '%s' actual = '%s'", i, vectors[i].input, vectors[i].output, test); + parcMemory_Deallocate((void **) ©); + } +} + +LONGBOW_TEST_CASE(Local, _trim) +{ + TestVector vectors[] = { + { .input = "", .output = "" }, + { .input = " ", .output = "" }, + { .input = "\t", .output = "" }, + { .input = "a", .output = "a" }, + { .input = "abc", .output = "abc" }, + { .input = " a c ", .output = "a c" }, + { .input = "bc ", .output = "bc" }, + { .input = "bc\t", .output = "bc" }, + { .input = "bc \t", .output = "bc" }, + { .input = " bc\t\t", .output = "bc" }, + { .input = NULL, .output = NULL }, + }; + + for (int i = 0; vectors[i].input != NULL; i++) { + char *copy = parcMemory_StringDuplicate(vectors[i].input, strlen(vectors[i].input)); + char *test = _trim(copy); + assertTrue(strcmp(test, vectors[i].output) == 0, "Bad output index %d. input = '%s' expected = '%s' actual = '%s'", i, vectors[i].input, vectors[i].output, test); + parcMemory_Deallocate((void **) ©); + } +} + +// ====================================================== + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_ConfigurationFile); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metis_ConfigurationListeners.c b/metis/ccnx/forwarder/metis/config/test/test_metis_ConfigurationListeners.c new file mode 100644 index 00000000..8ac2c82d --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metis_ConfigurationListeners.c @@ -0,0 +1,644 @@ +/* + * 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. + */ + +/* + * Some of these tests might not execute on certain systems, as they + * depend on having INET and INET6 addresses available. If you system + * does not have one or both of those, the corresponding tests will not + * execute. + */ + +// We need to specifically include the Ethernet mockup and set the proper define so +// we do not need an actual Ethernet listener + +#define METIS_MOCK_ETHERNET 1 +#include "../../io/test/testrig_GenericEther.c" + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metis_ConfigurationListeners.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + +#include <signal.h> +#include <net/ethernet.h> + +#define TEST_PORT 9697 +static const CPIAddress * +getFirstAddressOfType(CPIInterfaceSet *set, CPIAddressType type) +{ + for (int i = 0; i < cpiInterfaceSet_Length(set); i++) { + CPIInterface *iface = cpiInterfaceSet_GetByOrdinalIndex(set, i); + const CPIAddressList *list = cpiInterface_GetAddresses(iface); + for (int j = 0; j < cpiAddressList_Length(list); j++) { + const CPIAddress *address = cpiAddressList_GetItem(list, j); + if (cpiAddress_GetType(address) == type) { + return address; + } + } + } + return NULL; +} + +struct sigaction save_sigchld; +struct sigaction save_sigpipe; + +static void +blockSigChild() +{ + struct sigaction ignore_action; + ignore_action.sa_handler = SIG_IGN; + sigemptyset(&ignore_action.sa_mask); + ignore_action.sa_flags = 0; + + sigaction(SIGCHLD, NULL, &save_sigchld); + sigaction(SIGPIPE, NULL, &save_sigpipe); + + sigaction(SIGCHLD, &ignore_action, NULL); + sigaction(SIGPIPE, &ignore_action, NULL); +} + +static void +unblockSigChild() +{ + sigaction(SIGCHLD, &save_sigchld, NULL); + sigaction(SIGPIPE, &save_sigpipe, NULL); +} + +static bool +verifyInNetstat(const char *addressString, int port) +{ + // now verify that we are listening + // tcp4 0 0 127.0.0.1.49009 *.* LISTEN + + FILE *fp = popen("netstat -an", "r"); + assertNotNull(fp, "Got null opening netstat for reading"); + + char buffer[4][1024]; + + sprintf(buffer[0], "%s.%d", addressString, port); + sprintf(buffer[1], "%s:%d", addressString, port); + sprintf(buffer[2], "%s%%lo0.%d", addressString, port); + sprintf(buffer[3], "%s%%lo0:%d", addressString, port); + + char str[1035]; + bool found = false; + while (!found && (fgets(str, sizeof(str) - 1, fp) != NULL)) { + for (int i = 0; i < 4; i++) { + if (strstr(str, buffer[i]) != NULL) { + found = true; + } + } + } + + blockSigChild(); + pclose(fp); + unblockSigChild(); + + return found; +} + +// returns a strdup() of the interface name, use free(3) +static char * +_pickInterfaceName(MetisForwarder *metis) +{ + char *ifname = NULL; + + CPIInterfaceSet *set = metisSystem_Interfaces(metis); + size_t length = cpiInterfaceSet_Length(set); + assertTrue(length > 0, "metisSystem_Interfaces returned no interfaces"); + + for (size_t i = 0; i < length; i++) { + CPIInterface *iface = cpiInterfaceSet_GetByOrdinalIndex(set, i); + const CPIAddressList *addressList = cpiInterface_GetAddresses(iface); + + size_t length = cpiAddressList_Length(addressList); + for (size_t i = 0; i < length && !ifname; i++) { + const CPIAddress *a = cpiAddressList_GetItem(addressList, i); + if (cpiAddress_GetType(a) == cpiAddressType_LINK) { + ifname = strdup(cpiInterface_GetName(iface)); + } + } + } + + cpiInterfaceSet_Destroy(&set); + return ifname; +} + +// ========================================================================= + +LONGBOW_TEST_RUNNER(metis_Configuration) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metis_Configuration) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metis_Configuration) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ============================================================================== + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisConfigurationListeners_SetupAll); + LONGBOW_RUN_TEST_CASE(Global, metisConfigurationListeners_Add_Ether); + LONGBOW_RUN_TEST_CASE(Global, metisConfigurationListeners_Add_IP_UDP4); + LONGBOW_RUN_TEST_CASE(Global, metisConfigurationListeners_Add_IP_UDP6); + LONGBOW_RUN_TEST_CASE(Global, metisConfigurationListeners_Add_IP_TCP4); + LONGBOW_RUN_TEST_CASE(Global, metisConfigurationListeners_Add_IP_TCP6); + LONGBOW_RUN_TEST_CASE(Global, metisConfigurationListeners_Remove); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisConfigurationListeners_SetupAll) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Debug); + + metisConfigurationListeners_SetupAll(metisForwarder_GetConfiguration(metis), TEST_PORT, NULL); + + MetisListenerSet *set = metisForwarder_GetListenerSet(metis); + size_t len = metisListenerSet_Length(set); + assertTrue(len > 0, "Bad listener set size, expected positive, got %zu", len); + + metisForwarder_Destroy(&metis); +} + +LONGBOW_TEST_CASE(Global, metisConfigurationListeners_Add_Ether) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Debug); + + // Create a mock up of an interface so we can see the response + unsigned mockup_id = 77; + + // create the listener + char *ifname = _pickInterfaceName(metis); + CPIListener *cpiListener = cpiListener_CreateEther(ifname, 0x0801, "fake0"); + CCNxControl *control = cpiListener_CreateAddMessage(cpiListener); + bool listenerOk = metisConfigurationListeners_Add(metisForwarder_GetConfiguration(metis), control, mockup_id); + assertTrue(listenerOk, "Failed to setup ether listener."); + free(ifname); + + ccnxControl_Release(&control); + cpiListener_Release(&cpiListener); + + MetisListenerSet *set = metisForwarder_GetListenerSet(metis); + size_t len = metisListenerSet_Length(set); + assertTrue(len == 1, "Bad listener set size, expected 1, got %zu", len); + + metisForwarder_Destroy(&metis); +} + +LONGBOW_TEST_CASE(Global, metisConfigurationListeners_Add_IP_UDP4) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Debug); + + // Create a mock up of an interface so we can see the response + unsigned mockup_id = 77; + + // create the listener + struct sockaddr_in sin; + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(TEST_PORT); + int result = inet_aton("127.0.0.1", &sin.sin_addr); + assertTrue(result == 1, "failed inet_aton: (%d) %s", errno, strerror(errno)); + + CPIAddress *address = cpiAddress_CreateFromInet(&sin); + CPIListener *listener = cpiListener_CreateIP(IPTUN_UDP, address, "conn1"); + cpiAddress_Destroy(&address); + + + CCNxControl *control = cpiListener_CreateAddMessage(listener); + bool listenerOk = metisConfigurationListeners_Add(metisForwarder_GetConfiguration(metis), control, mockup_id); + assertTrue(listenerOk, "Failed to setup ether listener.") { + int res; + res = system("netstat -an -p udp"); + assertTrue(res != -1, "Error on system call"); + res = system("ps -el"); + assertTrue(res != -1, "Error on system call"); + } + + ccnxControl_Release(&control); + cpiListener_Release(&listener); + + MetisListenerSet *set = metisForwarder_GetListenerSet(metis); + size_t len = metisListenerSet_Length(set); + assertTrue(len == 1, "Bad listener set size, expected 1, got %zu", len); + + metisForwarder_Destroy(&metis); +} + +LONGBOW_TEST_CASE(Global, metisConfigurationListeners_Add_IP_UDP6) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Debug); + + // Create a mock up of an interface so we can see the response + unsigned mockup_id = 77; + + // create the listener + struct sockaddr_in6 sin6; + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons(TEST_PORT); + int result = inet_pton(AF_INET6, "::1", &(sin6.sin6_addr)); + if (result == 1) { + CPIAddress *address = cpiAddress_CreateFromInet6(&sin6); + CPIListener *listener = cpiListener_CreateIP(IPTUN_UDP, address, "conn1"); + cpiAddress_Destroy(&address); + + + CCNxControl *control = cpiListener_CreateAddMessage(listener); + bool listenerOk = metisConfigurationListeners_Add(metisForwarder_GetConfiguration(metis), control, mockup_id); + assertTrue(listenerOk, "Failed to setup ether listener.") { + int res; + res = system("netstat -an -p udp"); + assertTrue(res != -1, "Error on system call"); + res = system("ps -el"); + assertTrue(res != -1, "Error on system call"); + } + + ccnxControl_Release(&control); + cpiListener_Release(&listener); + + MetisListenerSet *set = metisForwarder_GetListenerSet(metis); + size_t len = metisListenerSet_Length(set); + assertTrue(len == 1, "Bad listener set size, expected 1, got %zu", len); + metisForwarder_Destroy(&metis); + } else { + metisForwarder_Destroy(&metis); + testSkip("IPv6 not supported"); + } +} + +LONGBOW_TEST_CASE(Global, metisConfigurationListeners_Add_IP_TCP4) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Debug); + + // Create a mock up of an interface so we can see the response + unsigned mockup_id = 77; + + // create the listener + struct sockaddr_in sin; + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(TEST_PORT); + int result = inet_aton("127.0.0.1", &sin.sin_addr); + assertTrue(result == 1, "failed inet_aton: (%d) %s", errno, strerror(errno)); + + CPIAddress *address = cpiAddress_CreateFromInet(&sin); + CPIListener *listener = cpiListener_CreateIP(IPTUN_TCP, address, "conn1"); + cpiAddress_Destroy(&address); + + + CCNxControl *control = cpiListener_CreateAddMessage(listener); + bool listenerOk = metisConfigurationListeners_Add(metisForwarder_GetConfiguration(metis), control, mockup_id); + assertTrue(listenerOk, "Failed to setup ether listener.") { + int res; + res = system("netstat -an -p tcp"); + assertTrue(res != -1, "Error on system call"); + res = system("ps -el"); + assertTrue(res != -1, "Error on system call"); + } + + ccnxControl_Release(&control); + cpiListener_Release(&listener); + + MetisListenerSet *set = metisForwarder_GetListenerSet(metis); + size_t len = metisListenerSet_Length(set); + assertTrue(len == 1, "Bad listener set size, expected 1, got %zu", len); + + metisForwarder_Destroy(&metis); +} + +LONGBOW_TEST_CASE(Global, metisConfigurationListeners_Add_IP_TCP6) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Debug); + + // Create a mock up of an interface so we can see the response + unsigned mockup_id = 77; + + // create the listener + struct sockaddr_in6 sin6; + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons(TEST_PORT); + int result = inet_pton(AF_INET6, "::1", &(sin6.sin6_addr)); + if (result == 1) { + CPIAddress *address = cpiAddress_CreateFromInet6(&sin6); + CPIListener *listener = cpiListener_CreateIP(IPTUN_TCP, address, "conn1"); + cpiAddress_Destroy(&address); + + + CCNxControl *control = cpiListener_CreateAddMessage(listener); + bool listenerOk = metisConfigurationListeners_Add(metisForwarder_GetConfiguration(metis), control, mockup_id); + assertTrue(listenerOk, "Failed to setup ether listener.") { + int res; + res = system("netstat -an -p tcp"); + assertTrue(res != -1, "Error on system call"); + res = system("ps -el"); + assertTrue(res != -1, "Error on system call"); + } + + ccnxControl_Release(&control); + cpiListener_Release(&listener); + + MetisListenerSet *set = metisForwarder_GetListenerSet(metis); + size_t len = metisListenerSet_Length(set); + assertTrue(len == 1, "Bad listener set size, expected 1, got %zu", len); + metisForwarder_Destroy(&metis); + } else { + metisForwarder_Destroy(&metis); + testSkip("IPv6 not supported"); + } +} + +LONGBOW_TEST_CASE(Global, metisConfigurationListeners_Remove) +{ + testUnimplemented("This test is unimplemented"); +} + +// ============================================================================== + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, setupEthernetListenerOnLink); + LONGBOW_RUN_TEST_CASE(Local, setupEthernetListenerOnLink_SecondEthertype); + LONGBOW_RUN_TEST_CASE(Local, setupIPMulticastListenerOnInet); + LONGBOW_RUN_TEST_CASE(Local, setupListenersOnAddress); + LONGBOW_RUN_TEST_CASE(Local, setupListenersOnInet); + LONGBOW_RUN_TEST_CASE(Local, setupListenersOnInet6); + LONGBOW_RUN_TEST_CASE(Local, setupListenersOnLink); + LONGBOW_RUN_TEST_CASE(Local, setupLocalListener); + LONGBOW_RUN_TEST_CASE(Local, setupTcpListenerOnInet); + LONGBOW_RUN_TEST_CASE(Local, setupTcpListenerOnInet6); + LONGBOW_RUN_TEST_CASE(Local, setupUdpListenerOnInet); + LONGBOW_RUN_TEST_CASE(Local, setupUdpListenerOnInet6); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, setupEthernetListenerOnLink) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + + uint8_t addr[ETHER_ADDR_LEN] = { 1, 2, 3, 4, 5, 6 }; + CPIAddress *localAddress = cpiAddress_CreateFromLink(addr, ETHER_ADDR_LEN); + + char *ifname = _pickInterfaceName(metis); + MetisListenerOps *listenerops = _setupEthernetListenerOnLink(metis, localAddress, ifname, 0x0801); + assertNotNull(listenerops, "Got null result from _setupEthernetListenerOnLink"); + + free(ifname); + cpiAddress_Destroy(&localAddress); + metisForwarder_Destroy(&metis); +} + +/* + * The current system does not allow multiple ether listeners on a single interface. + * even if they are different ethertypes + */ +LONGBOW_TEST_CASE(Local, setupEthernetListenerOnLink_SecondEthertype) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + + uint8_t addr[ETHER_ADDR_LEN] = { 1, 2, 3, 4, 5, 6 }; + CPIAddress *localAddress = cpiAddress_CreateFromLink(addr, ETHER_ADDR_LEN); + + char *ifname = _pickInterfaceName(metis); + MetisListenerOps *listenerops = _setupEthernetListenerOnLink(metis, localAddress, ifname, 0x0801); + assertNotNull(listenerops, "Got null result from _setupEthernetListenerOnLink"); + + // now try to add again with different ethertype + MetisListenerOps *second = _setupEthernetListenerOnLink(metis, localAddress, ifname, 0x0802); + assertNull(second, "Should have gotten null for second listener"); + + free(ifname); + cpiAddress_Destroy(&localAddress); + metisForwarder_Destroy(&metis); +} + + +LONGBOW_TEST_CASE(Local, setupIPMulticastListenerOnInet) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Local, setupListenersOnAddress) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Local, setupListenersOnInet) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Local, setupListenersOnInet6) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Local, setupListenersOnLink) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Local, setupLocalListener) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Local, setupTcpListenerOnInet) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + + CPIInterfaceSet *set = metisSystem_Interfaces(metis); + const CPIAddress *address = getFirstAddressOfType(set, cpiAddressType_INET); + if (address != NULL) { + char valueToFind[1024]; + struct sockaddr_in sin; + cpiAddress_GetInet(address, &sin); + _setupTcpListenerOnInet(metis, address, PORT_NUMBER); + bool found = verifyInNetstat(inet_ntoa(sin.sin_addr), PORT_NUMBER); + if (!found) { + // extra diagnostics + int ret = system("netstat -an -p tcp"); + assertTrue(ret > -1, "Error on system call"); + } + assertTrue(found, "Did not find value %s in netstat", valueToFind); + } + + cpiInterfaceSet_Destroy(&set); + metisForwarder_Destroy(&metis); + + if (address == NULL) { + testSkip("No network interfaces of type INET found"); + } +} + +LONGBOW_TEST_CASE(Local, setupTcpListenerOnInet6) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + + CPIInterfaceSet *set = metisSystem_Interfaces(metis); + const CPIAddress *address = getFirstAddressOfType(set, cpiAddressType_INET6); + if (address != NULL) { + char valueToFind[1024]; + char inet6str[INET6_ADDRSTRLEN]; + struct sockaddr_in6 sin6; + cpiAddress_GetInet6(address, &sin6); + inet_ntop(AF_INET6, &sin6.sin6_addr, inet6str, INET6_ADDRSTRLEN); + _setupTcpListenerOnInet6(metis, address, PORT_NUMBER); + bool found = verifyInNetstat(inet6str, PORT_NUMBER); + if (!found) { + // extra diagnostics + int ret = system("netstat -an -p tcp"); + assertTrue(ret > -1, "Error on system call"); + } + assertTrue(found, "Did not find value %s in netstat", valueToFind); + } + + cpiInterfaceSet_Destroy(&set); + metisForwarder_Destroy(&metis); + + if (address == NULL) { + testSkip("No network interfaces of type INET found"); + } +} + +LONGBOW_TEST_CASE(Local, setupUdpListenerOnInet) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + + CPIInterfaceSet *set = metisSystem_Interfaces(metis); + const CPIAddress *address = getFirstAddressOfType(set, cpiAddressType_INET); + if (address != NULL) { + char valueToFind[1024]; + struct sockaddr_in sin; + cpiAddress_GetInet(address, &sin); + _setupUdpListenerOnInet(metis, address, PORT_NUMBER); + bool found = verifyInNetstat(inet_ntoa(sin.sin_addr), PORT_NUMBER); + if (!found) { + // extra diagnostics + int ret = system("netstat -an -p udp"); + assertTrue(ret > -1, "Error on system call"); + } + assertTrue(found, "Did not find value %s in netstat", valueToFind); + } + + cpiInterfaceSet_Destroy(&set); + metisForwarder_Destroy(&metis); + + if (address == NULL) { + testSkip("No network interfaces of type INET found"); + } +} + +LONGBOW_TEST_CASE(Local, setupUdpListenerOnInet6) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug); + + CPIInterfaceSet *set = metisSystem_Interfaces(metis); + const CPIAddress *address = getFirstAddressOfType(set, cpiAddressType_INET6); + if (address != NULL) { + char valueToFind[1024]; + char inet6str[INET6_ADDRSTRLEN]; + struct sockaddr_in6 sin6; + cpiAddress_GetInet6(address, &sin6); + inet_ntop(AF_INET6, &sin6.sin6_addr, inet6str, INET6_ADDRSTRLEN); + _setupUdpListenerOnInet6(metis, address, PORT_NUMBER); + bool found = verifyInNetstat(inet6str, PORT_NUMBER); + if (!found) { + // extra diagnostics + int ret = system("netstat -an -p udp"); + assertTrue(ret > -1, "Error on system call"); + } + assertTrue(found, "Did not find value %s in netstat", valueToFind); + } + + cpiInterfaceSet_Destroy(&set); + metisForwarder_Destroy(&metis); + + if (address == NULL) { + testSkip("No network interfaces of type INET found"); + } +} + + +// ====================================================== + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_Configuration); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metis_ControlState.c b/metis/ccnx/forwarder/metis/config/test/test_metis_ControlState.c new file mode 100644 index 00000000..088118d4 --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metis_ControlState.c @@ -0,0 +1,253 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metis_ControlState.c" + +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(metis_Control) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metis_Control) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metis_Control) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ================================================== + +static CCNxMetaMessage *_testWriteMessage = NULL; +static CCNxMetaMessage *_testReadMessage = NULL; + +/** + * For testing purposes writes a message to a local buffer and reads response from local buffer + * + * _testWriteMessage will be an allocated reference to what is written + * _testReadMessage will be sent back (returend). You must put an allocated message there + * before calling this test function. + */ +static CCNxMetaMessage * +_testWriteRead(void *userdata, CCNxMetaMessage *msg) +{ + _testWriteMessage = ccnxMetaMessage_Acquire(msg); + return ccnxMetaMessage_Acquire(_testReadMessage); +} + +static unsigned _testCommandExecuteCount = 0; + +static MetisCommandReturn +_testCommand(MetisCommandParser *parser, MetisCommandOps *ops, PARCList *args) +{ + _testCommandExecuteCount++; + return MetisCommandReturn_Success; +} + +static MetisCommandOps _testCommandOps = { + .command = "test", // empty string for root + .init = NULL, + .execute = _testCommand +}; + +// ================================================== + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisControlState_Create); + LONGBOW_RUN_TEST_CASE(Global, metisControlState_DispatchCommand); + LONGBOW_RUN_TEST_CASE(Global, metisControlState_GetDebug); + LONGBOW_RUN_TEST_CASE(Global, metisControlState_Interactive); + LONGBOW_RUN_TEST_CASE(Global, metisControlState_RegisterCommand); + LONGBOW_RUN_TEST_CASE(Global, metisControlState_SetDebug); + LONGBOW_RUN_TEST_CASE(Global, metisControlState_WriteRead); + LONGBOW_RUN_TEST_CASE(Global, _metisControlState_ParseStringIntoTokens); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisControlState_Create) +{ + char hello[] = "hello"; + MetisControlState *state = metisControlState_Create(hello, _testWriteRead); + metisControlState_Destroy(&state); +} + +LONGBOW_TEST_CASE(Global, metisControlState_DispatchCommand) +{ + char hello[] = "hello"; + MetisControlState *state = metisControlState_Create(hello, _testWriteRead); + + metisControlState_RegisterCommand(state, &_testCommandOps); + + const char *argv[] = { "test", "foobar" }; + PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(args, 2, (void **) &argv[0]); + + _testCommandExecuteCount = 0; + + metisControlState_DispatchCommand(state, args); + + assertTrue(_testCommandExecuteCount == 1, "Incorrect execution count, expected 1 got %u", _testCommandExecuteCount); + parcList_Release(&args); + metisControlState_Destroy(&state); +} + +LONGBOW_TEST_CASE(Global, metisControlState_GetDebug) +{ + char hello[] = "hello"; + MetisControlState *state = metisControlState_Create(hello, _testWriteRead); + + bool test = metisControlState_GetDebug(state); + assertTrue(test == state->debugFlag, "debug flag in unexpected state"); + + metisControlState_Destroy(&state); +} + +LONGBOW_TEST_CASE(Global, metisControlState_Interactive) +{ + // this reads commands from stdin. not sure how to test this. + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Global, metisControlState_RegisterCommand) +{ + char hello[] = "hello"; + MetisControlState *state = metisControlState_Create(hello, _testWriteRead); + + metisControlState_RegisterCommand(state, &_testCommandOps); + + bool match = metisCommandParser_ContainsCommand(state->parser, "test"); + assertTrue(match, "Command not found in parser"); + + metisControlState_Destroy(&state); +} + +LONGBOW_TEST_CASE(Global, metisControlState_SetDebug) +{ + char hello[] = "hello"; + MetisControlState *state = metisControlState_Create(hello, _testWriteRead); + + assertFalse(state->debugFlag, "debug flag in unexpected true state"); + metisControlState_SetDebug(state, true); + assertTrue(state->debugFlag, "debug flag in unexpected false state"); + + metisControlState_Destroy(&state); +} + +LONGBOW_TEST_CASE(Global, metisControlState_WriteRead) +{ + char hello[] = "hello"; + MetisControlState *state = metisControlState_Create(hello, _testWriteRead); + + CCNxName *appleName = ccnxName_CreateFromCString("lci:/apple"); + CCNxInterest *appleInterest = ccnxInterest_CreateSimple(appleName); + _testReadMessage = ccnxMetaMessage_CreateFromInterest(appleInterest); + ccnxInterest_Release(&appleInterest); + ccnxName_Release(&appleName); + + CCNxName *pieName = ccnxName_CreateFromCString("lci:/pie"); + CCNxInterest *pieInterest = ccnxInterest_CreateSimple(pieName); + CCNxMetaMessage *writeMessage = ccnxMetaMessage_CreateFromInterest(pieInterest);; + ccnxInterest_Release(&pieInterest); + ccnxName_Release(&pieName); + + CCNxMetaMessage *test = metisControlState_WriteRead(state, writeMessage); + + assertTrue(_testWriteMessage == writeMessage, "write message incorrect, expected %p got %p", (void *) writeMessage, (void *) _testWriteMessage); + assertTrue(_testReadMessage == test, "read message incorrect, expected %p got %p", (void *) _testReadMessage, (void *) test); + + ccnxMetaMessage_Release(&test); + ccnxMetaMessage_Release(&writeMessage); + + ccnxMetaMessage_Release(&_testReadMessage); + ccnxMetaMessage_Release(&_testWriteMessage); + + metisControlState_Destroy(&state); +} + +LONGBOW_TEST_CASE(Global, _metisControlState_ParseStringIntoTokens) +{ + const char *string = "the quick brown fox"; + + const char *argv[] = { "the", "quick", "brown", "fox" }; + PARCList *truth = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + parcList_AddAll(truth, 4, (void **) &argv[0]); + + PARCList *test = _metisControlState_ParseStringIntoTokens(string); + + assertTrue(parcList_Size(test) == parcList_Size(truth), "list wrong size, expected %zu got %zu", parcList_Size(truth), parcList_Size(test)); + + for (int i = 0; i < parcList_Size(truth); i++) { + const char *testString = parcList_GetAtIndex(test, i); + const char *truthString = parcList_GetAtIndex(truth, i); + assertTrue(strcmp(testString, truthString) == 0, "index %d not equal, expected '%s' got '%s'", i, truthString, testString); + } + + parcList_Release(&test); + parcList_Release(&truth); +} + +// ======================================================================== + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_Control); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/test_metis_SymbolicNameTable.c b/metis/ccnx/forwarder/metis/config/test/test_metis_SymbolicNameTable.c new file mode 100644 index 00000000..811f5b0f --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/test_metis_SymbolicNameTable.c @@ -0,0 +1,140 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metis_SymbolicNameTable.c" + +#include <stdio.h> +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(metis_SymbolicNameTable) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metis_SymbolicNameTable) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metis_SymbolicNameTable) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ============================================================== + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisSymbolicNameTable_Create); + LONGBOW_RUN_TEST_CASE(Global, metisSymbolicNameTable_Exists_True); + LONGBOW_RUN_TEST_CASE(Global, metisSymbolicNameTable_Exists_False); + LONGBOW_RUN_TEST_CASE(Global, metisSymbolicNameTable_Add_Unique); + LONGBOW_RUN_TEST_CASE(Global, metisSymbolicNameTable_Add_Duplicate); + LONGBOW_RUN_TEST_CASE(Global, metisSymbolicNameTable_Get_Exists); + LONGBOW_RUN_TEST_CASE(Global, metisSymbolicNameTable_Get_Missing); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisSymbolicNameTable_Create) +{ + MetisSymbolicNameTable *table = metisSymbolicNameTable_Create(); + assertNotNull(table, "Got null table"); + assertNotNull(table->symbolicNameTable, "Table did not have an inner hash table allocated"); + metisSymbolicNameTable_Destroy(&table); +} + +LONGBOW_TEST_CASE(Global, metisSymbolicNameTable_Exists_True) +{ + MetisSymbolicNameTable *table = metisSymbolicNameTable_Create(); + metisSymbolicNameTable_Add(table, "foo", 3); + bool exists = metisSymbolicNameTable_Exists(table, "foo"); + assertTrue(exists, "Failed to find existing key"); + metisSymbolicNameTable_Destroy(&table); +} + +LONGBOW_TEST_CASE(Global, metisSymbolicNameTable_Exists_False) +{ + MetisSymbolicNameTable *table = metisSymbolicNameTable_Create(); + bool exists = metisSymbolicNameTable_Exists(table, "foo"); + assertFalse(exists, "Found non-existent key!"); + metisSymbolicNameTable_Destroy(&table); +} + +LONGBOW_TEST_CASE(Global, metisSymbolicNameTable_Add_Unique) +{ + MetisSymbolicNameTable *table = metisSymbolicNameTable_Create(); + bool success = metisSymbolicNameTable_Add(table, "foo", 3); + assertTrue(success, "Failed to add a unique key"); + metisSymbolicNameTable_Destroy(&table); +} + +LONGBOW_TEST_CASE(Global, metisSymbolicNameTable_Add_Duplicate) +{ + MetisSymbolicNameTable *table = metisSymbolicNameTable_Create(); + metisSymbolicNameTable_Add(table, "foo", 3); + bool failure = metisSymbolicNameTable_Add(table, "foo", 4); + assertFalse(failure, "Should have failed to add a duplicate key"); + metisSymbolicNameTable_Destroy(&table); +} + +LONGBOW_TEST_CASE(Global, metisSymbolicNameTable_Get_Exists) +{ + MetisSymbolicNameTable *table = metisSymbolicNameTable_Create(); + metisSymbolicNameTable_Add(table, "foo", 3); + unsigned value = metisSymbolicNameTable_Get(table, "foo"); + assertTrue(value == 3, "Wrong value, expected %u got %u", 3, value); + metisSymbolicNameTable_Destroy(&table); +} + +LONGBOW_TEST_CASE(Global, metisSymbolicNameTable_Get_Missing) +{ + MetisSymbolicNameTable *table = metisSymbolicNameTable_Create(); + unsigned value = metisSymbolicNameTable_Get(table, "foo"); + assertTrue(value == UINT32_MAX, "Wrong value, expected %u got %u", UINT32_MAX, value); + metisSymbolicNameTable_Destroy(&table); +} + + +// ============================================================== + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_SymbolicNameTable); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/config/test/testrig_MetisControl.c b/metis/ccnx/forwarder/metis/config/test/testrig_MetisControl.c new file mode 100644 index 00000000..f3f18000 --- /dev/null +++ b/metis/ccnx/forwarder/metis/config/test/testrig_MetisControl.c @@ -0,0 +1,191 @@ +/* + * 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. + */ + +/** + * Common operations for the metisControl tests. This C module + * is intended to be #include'd in to each test. + * + */ + +#include <LongBow/unit-test.h> + +#include "../metis_ControlState.c" +#include <parc/algol/parc_SafeMemory.h> +#include <ccnx/forwarder/metis/config/metis_CommandParser.h> +#include <ccnx/api/control/controlPlaneInterface.h> + +typedef struct test_data { + MetisControlState *state; + unsigned writeread_count; + + // If the user specifies this, it will be used as the reply to all test_WriteRead calls + CCNxControl * (*customWriteReadReply)(void *userdata, CCNxMetaMessage * messageToWrite); +} TestData; + +/** + * As part of the testrig, we simply create a CPIAck of the request message. + * We also increment the call count in TestData. + * + * If the user specified a customWriteReadReply function, we will call that to get + * the specific response to send. + */ +static CCNxMetaMessage * +test_WriteRead(void *userdata, CCNxMetaMessage *messageToWrite) +{ + TestData *data = (TestData *) userdata; + data->writeread_count++; + + assertTrue(ccnxMetaMessage_IsControl(messageToWrite), "messageToWrite is not a control message"); + + CCNxControl *response; + CCNxMetaMessage *result; + + if (data->customWriteReadReply == NULL) { + CCNxControl *request = ccnxMetaMessage_GetControl(messageToWrite); + PARCJSON *json = ccnxControl_GetJson(request); + PARCJSON *jsonAck = cpiAcks_CreateAck(json); + + response = ccnxControl_CreateCPIRequest(jsonAck); + result = ccnxMetaMessage_CreateFromControl(response); + + parcJSON_Release(&jsonAck); + ccnxControl_Release(&response); + } else { + response = data->customWriteReadReply(userdata, messageToWrite); + assertTrue(ccnxMetaMessage_IsControl(response), "response is not a control message"); + result = ccnxMetaMessage_CreateFromControl(response); + ccnxControl_Release(&response); + } + + return result; +} + +static void +testrigMetisControl_commonSetup(const LongBowTestCase *testCase) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + memset(data, 0, sizeof(TestData)); + + data->state = metisControlState_Create(data, test_WriteRead); + longBowTestCase_SetClipBoardData(testCase, data); +} + +static void +testrigMetisControl_CommonTeardown(const LongBowTestCase *testCase) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + metisControlState_Destroy(&data->state); + parcMemory_Deallocate((void **) &data); +} + +/** + * Verify that a Command Create operated correctly + * + * We verify the basic properties of what a Create returns. Will assert if a failure. + * + * @param [in] testCase The LongBow test case (used for the clipboard) + * @param [in] create The command create function pointer to test + * @param [in] title The descriptive title to display in case of error + * + * Example: + * @code + * <#example#> + * @endcode + */ +void +testCommandCreate(const LongBowTestCase *testCase, MetisCommandOps * (*create)(MetisControlState * state), const char *title) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + MetisCommandOps *ops = create(data->state); + assertNotNull(ops, "%s: Got null ops", title); + assertNotNull(ops->execute, "%s: Ops execute must not be null", title); + assertNotNull(ops->command, "%s: Ops command must not be null", title); + assertTrue(ops->closure == data->state, "%s: ops closure should be data->state, got wrong pointer", title); + + metisCommandOps_Destroy(&ops); + assertNull(ops, "Ops not nulled by Destroy"); +} + +/** + * Test a Help command's execution. + * + * A Help execution will display text (which we don't test). We make sure there + * is no memory leak and that it returns successfully. We will call the passed create method + * to create the Help command then execute its execute. + * + * @param [in] testCase The LongBow test case (used for the clipboard) + * @param [in] create The command create function pointer to test + * @param [in] title The descriptive title to display in case of error + * @param [in] expected A MetisCommandReturn to use as the expected result + * + * Example: + * @code + * { + * // expectes MetisCommandReturn_Success + * testHelpExecute(testCase, metisControl_Add_Create, __func__, MetisCommandReturn_Success); + * + * // expectes MetisCommandReturn_Exit + * testHelpExecute(testCase, metisControl_Quit_Create, __func__, MetisCommandReturn_Exit); + * } + * @endcode + */ +void +testHelpExecute(const LongBowTestCase *testCase, MetisCommandOps * (*create)(MetisControlState * state), const char *title, MetisCommandReturn expected) +{ + uint32_t beforeMemory = parcMemory_Outstanding(); + TestData *data = longBowTestCase_GetClipBoardData(testCase); + MetisCommandOps *ops = create(data->state); + MetisCommandReturn result = ops->execute(NULL, ops, NULL); + assertTrue(result == expected, "Wrong return, got %d expected %d", result, expected); + metisCommandOps_Destroy(&ops); + uint32_t afterMemory = parcMemory_Outstanding(); + + assertTrue(beforeMemory == afterMemory, "Memory leak by %d\n", (int) (afterMemory - beforeMemory)); +} + +/** + * Verify that a list of commands is added by the Init function + * + * <#Paragraphs Of Explanation#> + * + * @param [in] testCase The LongBow test case (used for the clipboard) + * @param [in] create We will create one of these and call it's init() function + * @param [in] title The descriptive title to display in case of error + * @param [in] commandList Null terminated list of commands + * + * Example: + * @code + * <#example#> + * @endcode + */ +void +testInit(const LongBowTestCase *testCase, MetisCommandOps * (*create)(MetisControlState * state), const char *title, const char **commandList) +{ + // this will register 8 commands, so check they exist + TestData *data = longBowTestCase_GetClipBoardData(testCase); + MetisCommandOps *ops = create(data->state); + assertNotNull(ops, "%s got null ops from the create function", title); + assertNotNull(ops->init, "%s got null ops->init from the create function", title); + + ops->init(data->state->parser, ops); + + for (int i = 0; commandList[i] != NULL; i++) { + bool success = metisCommandParser_ContainsCommand(data->state->parser, commandList[i]); + assertTrue(success, "%s: Missing: %s", title, commandList[i]); + } + + metisCommandOps_Destroy(&ops); +} |