blob: f1f3686881a857f1dc64b00746ddbe2e419d76af [file] [log] [blame]
/*
*
* Copyright (c) 2016-2017 Nest Labs, Inc.
* All rights reserved.
*
* 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.
*/
/**
* @file
* This file aims to test the service directory profile.
*
*/
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <limits.h>
#include "ToolCommon.h"
#include <Weave/WeaveVersion.h>
#include <Weave/Profiles/service-directory/ServiceDirectory.h>
#include "MockSDServer.h"
#define TOOL_NAME "weave-service-dir"
static void HandleConnectionComplete(WeaveConnection *con, WEAVE_ERROR conErr);
static void HandleServiceMgrStatus(void *appState, WEAVE_ERROR anError, StatusReport *aReport);
static void HandleTestTimeout(System::Layer* aSystemLayer, void* aAppState, System::Error aError);
enum
{
kRole_ServiceDirServer = 0,
kRole_ServiceDirClient,
};
uint8_t Role = kRole_ServiceDirServer;
ServiceDirectory::WeaveServiceManager ServiceMgr;
uint8_t ServiceDirCache[300];
const char *DirectoryServer = NULL;
WeaveAuthMode AuthMode = kWeaveAuthMode_Unauthenticated;
MockServiceDirServer MockSDServer;
static bool sLastIterationFailed = false;
static bool sTimerRunning = false;
static HelpOptions gHelpOptions(
TOOL_NAME,
"Usage: " TOOL_NAME " [<options...>]\n"
" " TOOL_NAME " [<options...>] --service-dir-server <host>[:<port>]\n",
WEAVE_VERSION_STRING "\n" WEAVE_TOOL_COPYRIGHT
);
static OptionSet *gToolOptionSets[] =
{
&gNetworkOptions,
&gWeaveNodeOptions,
&gServiceDirClientOptions,
&gFaultInjectionOptions,
&gHelpOptions,
NULL
};
static void HandleTestTimeout(System::Layer* aSystemLayer, void* aAppState, System::Error aError)
{
printf("test timeout\n");
sTimerRunning = false;
Done = true;
ServiceMgr.cancel(kServiceEndpoint_SoftwareUpdate, static_cast<void *>(&ServiceMgr));
}
static void ExpireTimer(int32_t argument)
{
SystemLayer.StartTimer(0, HandleTestTimeout, NULL);
}
static int32_t GetNumEventsAvailable(void)
{
int32_t retval = 0;
if (Role == kRole_ServiceDirClient && sTimerRunning)
{
retval = 1;
}
return retval;
}
int main(int argc, char *argv[])
{
WEAVE_ERROR err;
nl::Weave::System::Stats::Snapshot before;
nl::Weave::System::Stats::Snapshot after;
const bool printStats = true;
InitToolCommon();
SetupFaultInjectionContext(argc, argv, GetNumEventsAvailable, ExpireTimer);
SetSignalHandler(DoneOnHandleSIGUSR1);
gServiceDirClientOptions.ServerHost = NULL;
if (!ParseArgsFromEnvVar(TOOL_NAME, TOOL_OPTIONS_ENV_VAR_NAME, gToolOptionSets, NULL, true) ||
!ParseArgs(TOOL_NAME, argc, argv, gToolOptionSets) ||
!ResolveWeaveNetworkOptions(TOOL_NAME, gWeaveNodeOptions, gNetworkOptions))
{
exit(EXIT_FAILURE);
}
Role = (gServiceDirClientOptions.ServerHost != NULL) ? kRole_ServiceDirClient : kRole_ServiceDirServer;
InitSystemLayer();
InitNetwork();
InitWeaveStack(true, true);
PrintNodeConfig();
nl::Weave::Stats::UpdateSnapshot(before);
if (Role == kRole_ServiceDirServer)
{
// Initialize the mock service directory server.
err = MockSDServer.Init(&ExchangeMgr);
FAIL_ERROR(err, "MockSDServer.Init failed");
}
else
{
err = ServiceMgr.init(&ExchangeMgr, ServiceDirCache, sizeof(ServiceDirCache),
GetRootServiceDirectoryEntry, AuthMode, NULL, NULL, OverrideServiceConnectArguments);
if (err != WEAVE_NO_ERROR)
{
printf("ServiceMgr.init() failed with error: %s\n", ErrorStr(err));
exit(EXIT_FAILURE);
}
}
for (uint32_t iteration = 1; iteration <= gFaultInjectionOptions.TestIterations; iteration++)
{
if (Role == kRole_ServiceDirClient)
{
sLastIterationFailed = false;
printf("Iteration %u\n", iteration);
// Ask for a connection to SoftwareUpdate; the MockSDServer responds to both
SystemLayer.StartTimer(30000, HandleTestTimeout, NULL);
sTimerRunning = true;
err = ServiceMgr.connect(kServiceEndpoint_SoftwareUpdate,
AuthMode,
static_cast<void *>(&ServiceMgr), // you have to put something here, or the status callback is not invoked
HandleServiceMgrStatus,
HandleConnectionComplete);
if (err != WEAVE_NO_ERROR)
{
printf("WeaveServiceManager.Connect(): failed: %s\n", ErrorStr(err));
Done = true;
sLastIterationFailed = true;
}
}
ServiceNetworkUntil(&Done);
SystemLayer.CancelTimer(HandleTestTimeout, NULL);
sTimerRunning = false;
if (sLastIterationFailed)
{
// Sleep a couple of seconds; if a new attempt is made too soon, the service process can
// reject the connection (e.g. if it is restarting after a crash)
uint32_t waitTimeMs = 2000;
ServiceNetworkUntil(NULL, &waitTimeMs);
}
Done = false;
}
ServiceMgr.relocate(WEAVE_NO_ERROR);
ServiceMgr.reset(WEAVE_NO_ERROR);
ServiceMgr.unresolve(WEAVE_NO_ERROR);
ServiceMgr.cancel(kServiceEndpoint_SoftwareUpdate, NULL);
if (Role == kRole_ServiceDirServer)
{
err = MockSDServer.TearDown();
FAIL_ERROR(err, "MockSDServer.TearDown failed");
}
ProcessStats(before, after, printStats, NULL);
PrintFaultInjectionCounters();
ShutdownWeaveStack();
ShutdownNetwork();
ShutdownSystemLayer();
return EXIT_SUCCESS;
}
void HandleConnectionComplete(WeaveConnection *con, WEAVE_ERROR conErr)
{
char ipAddrStr[64];
con->PeerAddr.ToString(ipAddrStr, sizeof(ipAddrStr));
if (conErr != WEAVE_NO_ERROR)
{
printf("Connection failed to node %" PRIX64 " (%s)\n", con->PeerNodeId, ipAddrStr);
sLastIterationFailed = true;
}
else
printf("Connection established to node %" PRIX64 " (%s)\n", con->PeerNodeId, ipAddrStr);
// stop the test
con->Close();
Done = true;
}
void HandleServiceMgrStatus(void* anAppState, WEAVE_ERROR anError, StatusReport *aReport)
{
if (aReport)
printf("service directory status report [%" PRIx32 ", %" PRIx32 "] %s\n", aReport->mProfileId, aReport->mStatusCode,
nl::StatusReportStr(aReport->mProfileId, aReport->mStatusCode));
else
{
printf("service directory error %" PRIx32 " %s\n", static_cast<uint32_t>(anError), nl::ErrorStr(anError));
if (anError == WEAVE_ERROR_INVALID_SERVICE_EP)
{
ServiceMgr.clearCache();
}
sLastIterationFailed = true;
}
Done = true;
}