blob: f9756e1d897f325242afcc3cc674814efcc0a109 [file] [log] [blame]
/*
*
* Copyright (c) 2018 Google LLC.
* Copyright (c) 2017-2018 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
* Unit tests for Weave Event Logging
*
*/
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#include <new>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <nlbyteorder.h>
#include <nlunit-test.h>
// Note that the choice of namespace alias must be made up front for each and every compile unit
// This is because many include paths could set the default alias to unintended target.
#include <Weave/Profiles/bulk-data-transfer/Development/BDXManagedNamespace.hpp>
#include <Weave/Profiles/data-management/Current/WdmManagedNamespace.h>
#include "ToolCommon.h"
#include "TestEventLoggingSchemaExamples.h"
#include <InetLayer/Inet.h>
#include <SystemLayer/SystemTimer.h>
#include <Weave/Core/WeaveCore.h>
#include <Weave/Core/WeaveMessageLayer.h>
#include <Weave/Core/WeaveEncoding.h>
#include <Weave/Core/WeaveTLV.h>
#include <Weave/Core/WeaveTLVDebug.hpp>
#include <Weave/Core/WeaveTLVUtilities.hpp>
#include <Weave/Core/WeaveTLVData.hpp>
#include <Weave/Core/WeaveSecurityMgr.h>
#include <Weave/Profiles/security/WeaveSecurity.h>
#include <Weave/Profiles/ProfileCommon.h>
#include <Weave/Profiles/time/WeaveTime.h>
#include <Weave/Support/TraitEventUtils.h>
#include <Weave/Profiles/data-management/DataManagement.h>
#include <Weave/Support/ErrorStr.h>
#include "TestPersistedStorageImplementation.h"
#include <Weave/Support/PersistedCounter.h>
#include "schema/nest/test/trait/TestETrait.h"
#include "schema/nest/test/trait/TestCommon.h"
#include "MockExternalEvents.h"
#include "MockPlatformClocks.h"
using namespace nl::Weave::TLV;
using namespace nl::Weave::Profiles::DataManagement;
namespace Private {
static bool sRealTimeClockValid = true;
System::Error SetClock_RealTime(uint64_t newCurTime)
{
if (newCurTime != 0)
{
sRealTimeClockValid = true;
}
else
{
sRealTimeClockValid = false;
}
return WEAVE_SYSTEM_NO_ERROR;
}
static System::Error GetClock_RealTime(uint64_t & curTime)
{
if (sRealTimeClockValid)
{
curTime = ::nl::Weave::System::Platform::Layer::GetClock_Monotonic();
return WEAVE_SYSTEM_NO_ERROR;
}
else
{
curTime = 0;
return WEAVE_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED;
}
}
} // namespace Private
namespace nl {
namespace Weave {
namespace Profiles {
namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current) {
namespace Platform {
// for unit tests, the dummy critical section is sufficient.
void CriticalSectionEnter()
{
return;
}
void CriticalSectionExit()
{
return;
}
} // namespace Platform
} // namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current)
namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current) {
class TestSubscriptionHandler : public SubscriptionHandler
{
public:
TestSubscriptionHandler(void);
// Make methods from SubscriptionHandler public so we can call them from
// our test cases.
using SubscriptionHandler::CheckEventUpToDate;
using SubscriptionHandler::FindNextImportanceForTransfer;
using SubscriptionHandler::ParsePathVersionEventLists;
using SubscriptionHandler::SetEventLogEndpoint;
bool VerifyTraversingImportance(void);
nl::Weave::Profiles::DataManagement::event_id_t &
GetVendedEvent(nl::Weave::Profiles::DataManagement::ImportanceType inImportance);
void SetActive(void) { mCurrentState = kState_Subscribing_Evaluating; }
void SetTerminated(void) { mCurrentState = kState_Terminated; }
void SetEstablishedIdle(void) { mCurrentState = kState_SubscriptionEstablished_Idle; }
void SetExchangeContext(nl::Weave::ExchangeContext * aEC) { mEC = aEC; }
private:
/* important: this class must not add any members or declare virtual functions */
};
TestSubscriptionHandler::TestSubscriptionHandler(void)
{
InitAsFree();
}
bool TestSubscriptionHandler::VerifyTraversingImportance(void)
{
return FindNextImportanceForTransfer() == nl::Weave::Profiles::DataManagement::kImportanceType_Invalid;
}
nl::Weave::Profiles::DataManagement::event_id_t &
TestSubscriptionHandler::GetVendedEvent(nl::Weave::Profiles::DataManagement::ImportanceType inImportance)
{
return mSelfVendedEvents[inImportance - nl::Weave::Profiles::DataManagement::kImportanceType_First];
}
SubscriptionEngine * SubscriptionEngine::GetInstance()
{
static SubscriptionEngine gWdmSubscriptionEngine;
return &gWdmSubscriptionEngine;
}
} // namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current)
} // namespace Profiles
} // namespace Weave
} // namespace nl
#define TOOL_NAME "TestDataLogging"
// forward declarations for networking functions. They are
// implemented at the end of the file, as they are incidental to the
// test and are irrelevant unless the test is invoked in a mode that
// exercises the upload path (i.e. with a dest node ID, or a dest IP
// address.
struct TestLoggingContext;
static void PrepareBinding(TestLoggingContext * context);
static WEAVE_ERROR InitSubscriptionClient(TestLoggingContext * context);
static void HandleBindingEvent(void * const appState, const Binding::EventType event, const Binding::InEventParam & inParam,
Binding::OutEventParam & outParam);
static void StartClientConnection(System::Layer * systemLayer, void * appState, System::Error err);
static void HandleConnectionComplete(WeaveConnection * con, WEAVE_ERROR conErr);
static void HandleConnectionClosed(WeaveConnection * con, WEAVE_ERROR conErr);
static WEAVE_ERROR FetchEventsHelper(TLVReader & aReader, event_id_t aEventId, uint8_t * aBackingStore, size_t aLen,
ImportanceType aImportance = nl::Weave::Profiles::DataManagement::Production);
static bool HandleOption(const char * progName, OptionSet * optSet, int id, const char * name, const char * arg);
const uint64_t kTestNodeId = 0x18B43000002DCF71ULL;
// Globals used when the test is used in conjunction with BDX
WeaveConnection * Con = NULL;
bool WaitingForBDXResp = false;
bool Listening = false;
bool Upload = true; // download by default
bool Debug = false;
uint32_t ConnectInterval = 200; // ms
uint32_t ConnectTry = 0;
uint32_t ConnectMaxTry = 3;
bool ClientConEstablished = false;
bool DestHostNameResolved = false; // only used for UDP
static OptionDef gToolOptionDefs[] = { { "start-event-id", kArgumentRequired, 's' },
{ "block-size", kArgumentRequired, 'b' },
{ "dest-addr", kArgumentRequired, 'D' },
{ "parent-node-id", kArgumentRequired, 'p' },
{ "debug", kNoArgument, 'd' },
{ "tcp", kNoArgument, 't' },
{ "udp", kNoArgument, 'u' },
{ NULL } };
static const char * const gToolOptionHelp = " -p <num>, --parent-node-id <num> \n"
" Parent node id; the ID of the node that will receive the event\n"
" logs\n"
"\n"
" -D <ip-addr>, --dest-addr <ip-addr>\n"
" The IP address or hostname of the parent (the node that will\n"
" receive thise event log)\n"
" -t, --tcp \n"
" Use TCP for BDX session\n"
"\n"
" -u, --udp \n"
" Use UDP for BDX session\n"
"\n"
" -s <num>, --start-event-id <num>\n"
" Begin the offload of each event sequence at <num> event\n"
"\n"
" -b <num>, --block-size <num>\n"
" Block size to use for BDX upload.\n"
"\n"
" -d, --debug \n"
" Enable debug messages.\n"
"\n";
static OptionSet gToolOptions = { HandleOption, gToolOptionDefs, "GENERAL OPTIONS", gToolOptionHelp };
static HelpOptions gHelpOptions(TOOL_NAME,
"Usage: " TOOL_NAME " [<options...>] <dest-node-id>[@<dest-host>[:<dest-port>][%<interface>]]\n"
" " TOOL_NAME " [<options...>] --listen\n",
WEAVE_VERSION_STRING "\n" WEAVE_TOOL_COPYRIGHT,
"Test event logging. Without any options, the program invokes a\n"
"suite of local log tests. The options enable testing of a log\n"
"upload over the BDX path.\n");
static OptionSet * gToolOptionSets[] = { &gToolOptions, &gNetworkOptions, &gWeaveNodeOptions,
&gFaultInjectionOptions, &gHelpOptions, NULL };
struct BDXContext
{
uint64_t DestNodeId;
IPAddress DestIPAddr;
const char * DestIPAddrStr;
uint32_t mStartingBlock;
bool mUseTCP;
bool mDone;
};
BDXContext gBDXContext;
// Event test harness contex
struct TestLoggingContext
{
bool mVerbose;
bool bdx;
bool bdxDone;
bool mReinitializeBDXUpload;
WeaveExchangeManager * mExchangeMgr;
Binding * mBinding;
SubscriptionClient * mSubClient;
TestLoggingContext();
};
TestLoggingContext gTestLoggingContext;
TestLoggingContext::TestLoggingContext() :
mVerbose(false), bdx(false), bdxDone(false), mReinitializeBDXUpload(false), mExchangeMgr(NULL), mBinding(NULL), mSubClient(NULL)
{ }
LogBDXUpload gLogBDXUpload;
// Example profiles for logging:
#define OpenCloseProfileID 0x235A00AA
#define kOpenCloseStateTag 0x01
#define kBypassStateTag 0x02
enum OpenCloseStateEnum
{
Unknown = 0,
Open = 1,
PartiallyOpen = 2,
Closed = 3,
};
enum BypassStateEnum
{
BypassInactive = 0,
BypassActive = 1,
BypassExpired = 2,
};
struct TestOpenCloseState
{
TestOpenCloseState();
void EvolveState();
uint8_t mState;
uint8_t mBypass;
};
TestOpenCloseState gTestOpenCloseState;
TestOpenCloseState::TestOpenCloseState()
{
mState = Closed;
mBypass = BypassInactive;
}
void TestOpenCloseState::EvolveState(void)
{
if (mState == Closed)
{
mState = Open;
}
else
{
mState = Closed;
}
}
WEAVE_ERROR WriteOpenCloseState(nl::Weave::TLV::TLVWriter & writer, uint8_t inDataTag, void * anAppState)
{
TestOpenCloseState * state = NULL;
WEAVE_ERROR err = WEAVE_NO_ERROR;
nl::Weave::TLV::TLVType openCloseState;
VerifyOrExit(anAppState != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
state = static_cast<TestOpenCloseState *>(anAppState);
err = writer.StartContainer(ContextTag(nl::Weave::Profiles::DataManagement::kTag_EventData), nl::Weave::TLV::kTLVType_Structure,
openCloseState);
SuccessOrExit(err);
err = writer.Put(nl::Weave::TLV::ContextTag(kOpenCloseStateTag), state->mState);
SuccessOrExit(err);
err = writer.Put(nl::Weave::TLV::ContextTag(kBypassStateTag), state->mBypass);
SuccessOrExit(err);
err = writer.EndContainer(openCloseState);
SuccessOrExit(err);
err = writer.Finalize();
state->EvolveState();
exit:
return err;
}
void SimpleDumpWriter(const char * aFormat, ...)
{
va_list args;
va_start(args, aFormat);
vprintf(aFormat, args);
va_end(args);
}
WEAVE_ERROR LogBufferConsole(void * inAppState, PacketBuffer * inBuffer)
{
printf("Log entries:\nTime\tSchema\tEventData\n");
nl::Weave::TLV::TLVReader reader;
uint8_t * p = inBuffer->Start();
uint32_t time = *((uint32_t *) p);
uint16_t schema = *((uint16_t *) (p + 4));
inBuffer->SetStart(p + 6);
reader.Init(inBuffer, inBuffer->TotalLength());
printf("%d\t%d\t", time, schema);
nl::Weave::TLV::Debug::Dump(reader, SimpleDumpWriter);
return WEAVE_NO_ERROR;
}
// Maximally sized event envelope
#define EVENT_ENVELOPE_SIZE 26
// Larger event payload. structured s.t. it fits in within the
// WEAVE_CONFIG_EVENT_SIZE_RESERVE (with the envelope)
#define EVENT_PAYLOAD_SIZE_1 128
// Larger event payload. Structured s.t. it fits in the buffer, but
// it is larger than the WEAVE_CONFIG_SIZE_RESERVE
#define EVENT_PAYLOAD_SIZE_2 256
#define EVENT_SIZE_1 EVENT_PAYLOAD_SIZE_1 + EVENT_ENVELOPE_SIZE
// Larger event payload. Doesn't fit in debug buffer.
#define EVENT_PAYLOAD_SIZE_3 (WEAVE_CONFIG_EVENT_SIZE_RESERVE + EVENT_SIZE_1)
uint64_t gDebugEventBuffer[(sizeof(nl::Weave::Profiles::DataManagement::CircularEventBuffer) + WEAVE_CONFIG_EVENT_SIZE_RESERVE +
EVENT_SIZE_1 + 7) /
8];
uint64_t gInfoEventBuffer[256];
uint64_t gProdEventBuffer[256];
uint64_t gCritEventBuffer[256];
uint8_t gLargeMemoryBackingStore[16384];
static const uint32_t sEventIdCounterEpoch = 0x10000;
static const char * sCritEventIdCounterStorageKey = "CritEIDC";
static nl::Weave::PersistedCounter sCritEventIdCounter;
static const char * sProductionEventIdCounterStorageKey = "ProductionEIDC";
static nl::Weave::PersistedCounter sProductionEventIdCounter;
static const char * sInfoEventIdCounterStorageKey = "InfoEIDC";
static nl::Weave::PersistedCounter sInfoEventIdCounter;
static const char * sDebugEventIdCounterStorageKey = "DebugEIDC";
static nl::Weave::PersistedCounter sDebugEventIdCounter;
void InitializeEventLogging(TestLoggingContext * context)
{
LogStorageResources logStorageResources[] = { { static_cast<void *>(&gCritEventBuffer[0]), sizeof(gCritEventBuffer), NULL, 0,
NULL, nl::Weave::Profiles::DataManagement::ImportanceType::ProductionCritical },
{ static_cast<void *>(&gProdEventBuffer[0]), sizeof(gProdEventBuffer), NULL, 0,
NULL, nl::Weave::Profiles::DataManagement::ImportanceType::Production },
{ static_cast<void *>(&gInfoEventBuffer[0]), sizeof(gInfoEventBuffer), NULL, 0,
NULL, nl::Weave::Profiles::DataManagement::ImportanceType::Info },
{ static_cast<void *>(&gDebugEventBuffer[0]), sizeof(gDebugEventBuffer), NULL, 0,
NULL, nl::Weave::Profiles::DataManagement::ImportanceType::Debug } };
nl::Weave::Profiles::DataManagement::LoggingManagement::CreateLoggingManagement(
context->mExchangeMgr, sizeof(logStorageResources) / sizeof(logStorageResources[0]), logStorageResources);
nl::Weave::Profiles::DataManagement::LoggingManagement & instance =
nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance();
nl::Weave::Profiles::DataManagement::LoggingConfiguration::GetInstance().mGlobalImportance =
nl::Weave::Profiles::DataManagement::Debug;
new (&gLogBDXUpload) nl::Weave::Profiles::DataManagement::LogBDXUpload();
gLogBDXUpload.Init(&instance);
}
void DestroyEventLogging(TestLoggingContext * context)
{
nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance().DestroyLoggingManagement();
}
void InitializeEventLoggingWithPersistedCounters(TestLoggingContext * context, uint32_t startingValue,
nl::Weave::Profiles::DataManagement::ImportanceType globalImportance)
{
LogStorageResources logStorageResources[] = {
{ static_cast<void *>(&gCritEventBuffer[0]), sizeof(gCritEventBuffer), &sCritEventIdCounterStorageKey, sEventIdCounterEpoch,
&sCritEventIdCounter, nl::Weave::Profiles::DataManagement::ImportanceType::ProductionCritical },
{ static_cast<void *>(&gProdEventBuffer[0]), sizeof(gProdEventBuffer), &sProductionEventIdCounterStorageKey,
sEventIdCounterEpoch, &sProductionEventIdCounter, nl::Weave::Profiles::DataManagement::ImportanceType::Production },
{ static_cast<void *>(&gInfoEventBuffer[0]), sizeof(gInfoEventBuffer), &sInfoEventIdCounterStorageKey, sEventIdCounterEpoch,
&sInfoEventIdCounter, nl::Weave::Profiles::DataManagement::ImportanceType::Info },
{ static_cast<void *>(&gDebugEventBuffer[0]), sizeof(gDebugEventBuffer), &sDebugEventIdCounterStorageKey,
sEventIdCounterEpoch, &sDebugEventIdCounter, nl::Weave::Profiles::DataManagement::ImportanceType::Debug }
};
nl::Weave::Platform::PersistedStorage::Write(sCritEventIdCounterStorageKey, startingValue);
nl::Weave::Platform::PersistedStorage::Write(sProductionEventIdCounterStorageKey, startingValue);
nl::Weave::Platform::PersistedStorage::Write(sInfoEventIdCounterStorageKey, startingValue);
nl::Weave::Platform::PersistedStorage::Write(sDebugEventIdCounterStorageKey, startingValue);
nl::Weave::Profiles::DataManagement::LoggingManagement::CreateLoggingManagement(
context->mExchangeMgr, sizeof(logStorageResources) / sizeof(logStorageResources[0]), logStorageResources);
nl::Weave::Profiles::DataManagement::LoggingConfiguration::GetInstance().mGlobalImportance = globalImportance;
}
void DumpEventLog(nlTestSuite * inSuite)
{
uint8_t backingStore[1024];
size_t elementCount;
event_id_t eventId = 1;
TLVWriter writer;
TLVReader reader;
WEAVE_ERROR err;
writer.Init(backingStore, 1024);
err = nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance().FetchEventsSince(
writer, nl::Weave::Profiles::DataManagement::Production, eventId);
if (err == WEAVE_NO_ERROR || err == WEAVE_END_OF_TLV)
{
printf("Successfully wrote %u bytes to the log\n", writer.GetLengthWritten());
}
else
{
printf("Wrote %u bytes to the log, FetchEventsSince returned %s (%d)\n", writer.GetLengthWritten(), ErrorStr(err), err);
}
reader.Init(backingStore, 1024);
nl::Weave::TLV::Utilities::Count(reader, elementCount);
printf("Fetched %zu elements, last eventID: %u \n", elementCount, eventId);
nl::Weave::TLV::Debug::Dump(reader, SimpleDumpWriter);
}
void DoBDXUpload(TestLoggingContext * context)
{
if (!context->bdx)
{
return;
}
gBDXContext.mDone = false;
if (gBDXContext.mUseTCP)
{
SystemLayer.StartTimer(ConnectInterval, StartClientConnection, &gBDXContext);
}
else
{
PrepareBinding(context);
}
while (!gBDXContext.mDone)
{
struct timeval sleepTime;
sleepTime.tv_sec = 0;
sleepTime.tv_usec = 100000;
ServiceNetwork(sleepTime);
if (gLogBDXUpload.mState == nl::Weave::Profiles::DataManagement::LogBDXUpload::UploaderInitialized)
{
gBDXContext.mDone = true;
for (size_t i = 0; i < 1000; i++)
{
sleepTime.tv_sec = 0;
sleepTime.tv_usec = 1000;
ServiceNetwork(sleepTime);
}
}
}
gLogBDXUpload.Shutdown();
}
void PrintEventLog()
{
TLVReader reader;
size_t elementCount;
nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance().GetEventReader(
reader, nl::Weave::Profiles::DataManagement::Production);
nl::Weave::TLV::Utilities::Count(reader, elementCount);
printf("Found %lu elements\n", elementCount);
nl::Weave::TLV::Debug::Dump(reader, SimpleDumpWriter);
}
static int TestSetup(void * inContext)
{
TestLoggingContext * ctx = static_cast<TestLoggingContext *>(inContext);
static WeaveFabricState sFabricState;
static WeaveExchangeManager sExchangeMgr;
InitSystemLayer();
if (ctx->bdx)
{
InitNetwork();
InitWeaveStack(true, true);
ctx->mExchangeMgr = &ExchangeMgr;
}
else
{
// fake Weave exchange layer. We are not running any
// networking tests, and at that point the only functionality
// required by the event logging subsystem is that the
// ExchageManager has a fabric state with a node id.
WEAVE_ERROR err = WEAVE_NO_ERROR;
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
tcpip_init(NULL, NULL);
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
err = sFabricState.Init();
if (err != WEAVE_NO_ERROR)
return FAILURE;
sFabricState.LocalNodeId = kTestNodeId;
sExchangeMgr.FabricState = &sFabricState;
sExchangeMgr.State = WeaveExchangeManager::kState_Initialized;
ctx->mExchangeMgr = &sExchangeMgr;
}
SubscriptionEngine::GetInstance()->Init(&ExchangeMgr, NULL, NULL);
return SUCCESS;
}
static int TestTeardown(void * inContext)
{
TestLoggingContext * ctx = static_cast<TestLoggingContext *>(inContext);
if (ctx->bdx)
{
ShutdownWeaveStack();
ShutdownNetwork();
}
ShutdownSystemLayer();
return SUCCESS;
}
static void CheckLogState(nlTestSuite * inSuite, TestLoggingContext * inContext,
nl::Weave::Profiles::DataManagement::LoggingManagement & logMgmt, size_t expectedNumEvents)
{
WEAVE_ERROR err;
TLVReader reader;
size_t elementCount;
err = logMgmt.GetEventReader(reader, nl::Weave::Profiles::DataManagement::Production);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = nl::Weave::TLV::Utilities::Count(reader, elementCount, false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, elementCount == expectedNumEvents);
if (inContext->mVerbose)
{
printf("Num Events: %lu\n", elementCount);
}
}
static void CheckLogReadOut(nlTestSuite * inSuite, TestLoggingContext * inContext,
nl::Weave::Profiles::DataManagement::LoggingManagement & logMgmt,
nl::Weave::Profiles::DataManagement::ImportanceType importance, event_id_t startingEventId,
size_t expectedNumEvents)
{
WEAVE_ERROR err;
TLVReader reader;
TLVWriter writer;
uint8_t backingStore[1024];
size_t elementCount;
writer.Init(backingStore, 1024);
err = logMgmt.FetchEventsSince(writer, importance, startingEventId);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR || err == WEAVE_END_OF_TLV);
reader.Init(backingStore, writer.GetLengthWritten());
err = nl::Weave::TLV::Utilities::Count(reader, elementCount, false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, elementCount == expectedNumEvents);
if (inContext->mVerbose)
{
reader.Init(backingStore, writer.GetLengthWritten());
printf("Starting Event ID: %u, Expected Events: %lu, Num Events: %lu, Num Bytes: %u\n", startingEventId, expectedNumEvents,
elementCount, writer.GetLengthWritten());
nl::Weave::TLV::Debug::Dump(reader, SimpleDumpWriter);
}
}
static void CheckLogEventBasics(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
event_id_t eid1, eid2, eid3;
EventSchema schema = { OpenCloseProfileID,
1, // Event type 1
nl::Weave::Profiles::DataManagement::Production, 1, 1 };
InitializeEventLogging(context);
nl::Weave::Profiles::DataManagement::LoggingManagement & logMgmt =
nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance();
// Sample production events, spaced 10 milliseconds apart
eid1 = nl::Weave::Profiles::DataManagement::LogEvent(schema, WriteOpenCloseState, static_cast<void *>(&gTestOpenCloseState));
CheckLogState(inSuite, context, logMgmt, 1);
usleep(10000);
eid2 = nl::Weave::Profiles::DataManagement::LogEvent(schema, WriteOpenCloseState, static_cast<void *>(&gTestOpenCloseState));
CheckLogState(inSuite, context, logMgmt, 2);
usleep(10000);
eid3 = nl::Weave::Profiles::DataManagement::LogEvent(schema, WriteOpenCloseState, static_cast<void *>(&gTestOpenCloseState));
CheckLogState(inSuite, context, logMgmt, 3);
if (context->mVerbose)
{
PrintEventLog();
}
NL_TEST_ASSERT(inSuite, (eid1 + 1) == eid2);
NL_TEST_ASSERT(inSuite, (eid2 + 1) == eid3);
// Verify that the readout supports the expected volume of events
CheckLogReadOut(inSuite, context, logMgmt, nl::Weave::Profiles::DataManagement::Production, eid1, 3);
CheckLogReadOut(inSuite, context, logMgmt, nl::Weave::Profiles::DataManagement::Production, eid2, 2);
CheckLogReadOut(inSuite, context, logMgmt, nl::Weave::Profiles::DataManagement::Production, eid3, 1);
if (context->bdx)
{
DoBDXUpload(context);
}
}
static void CheckLogFreeform(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
event_id_t eid1, eid2, eid3;
size_t counter = 0;
InitializeEventLogging(context);
nl::Weave::Profiles::DataManagement::LoggingManagement & logMgmt =
nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance();
// Sample production events, spaced 10 milliseconds apart
eid1 = nl::Weave::Profiles::DataManagement::LogFreeform(nl::Weave::Profiles::DataManagement::Production, "Freeform entry %d",
counter++);
CheckLogState(inSuite, context, logMgmt, 1);
usleep(10000);
eid2 = nl::Weave::Profiles::DataManagement::LogFreeform(nl::Weave::Profiles::DataManagement::Production, "Freeform entry %d",
counter++);
CheckLogState(inSuite, context, logMgmt, 2);
usleep(10000);
eid3 = nl::Weave::Profiles::DataManagement::LogFreeform(nl::Weave::Profiles::DataManagement::Production, "Freeform entry %d",
counter++);
CheckLogState(inSuite, context, logMgmt, 3);
if (context->mVerbose)
{
PrintEventLog();
}
NL_TEST_ASSERT(inSuite, (eid1 + 1) == eid2);
NL_TEST_ASSERT(inSuite, (eid2 + 1) == eid3);
// Verify that the readout supports the expected volume of events
CheckLogReadOut(inSuite, context, logMgmt, nl::Weave::Profiles::DataManagement::Production, eid1, 3);
CheckLogReadOut(inSuite, context, logMgmt, nl::Weave::Profiles::DataManagement::Production, eid2, 2);
CheckLogReadOut(inSuite, context, logMgmt, nl::Weave::Profiles::DataManagement::Production, eid3, 1);
if (context->bdx)
{
DoBDXUpload(context);
}
}
static void CheckLogPreformed(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
WEAVE_ERROR err;
event_id_t eid1, eid2, eid3;
EventSchema schema = { OpenCloseProfileID,
2, // Event type 2
nl::Weave::Profiles::DataManagement::Production, 1, 1 };
uint8_t backingStore[1024];
TLVWriter writer;
TLVType containerType;
TLVReader reader;
InitializeEventLogging(context);
nl::Weave::Profiles::DataManagement::LoggingManagement & logMgmt =
nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance();
writer.Init(backingStore, 1024);
err = writer.StartContainer(AnonymousTag, kTLVType_Structure, containerType);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Put(ContextTag(1), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Put(ContextTag(2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.EndContainer(containerType);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
reader.Init(backingStore, writer.GetLengthWritten());
// Sample production events, spaced 10 milliseconds apart
eid1 = nl::Weave::Profiles::DataManagement::LogEvent(schema, reader);
CheckLogState(inSuite, context, logMgmt, 1);
usleep(10000);
reader.Init(backingStore, writer.GetLengthWritten());
eid2 = nl::Weave::Profiles::DataManagement::LogEvent(schema, reader);
CheckLogState(inSuite, context, logMgmt, 2);
usleep(10000);
reader.Init(backingStore, writer.GetLengthWritten());
eid3 = nl::Weave::Profiles::DataManagement::LogEvent(schema, reader);
CheckLogState(inSuite, context, logMgmt, 3);
if (context->mVerbose)
{
PrintEventLog();
}
NL_TEST_ASSERT(inSuite, (eid1 + 1) == eid2);
NL_TEST_ASSERT(inSuite, (eid2 + 1) == eid3);
// Verify that the readout supports the expected volume of events
CheckLogReadOut(inSuite, context, logMgmt, nl::Weave::Profiles::DataManagement::Production, eid1, 3);
CheckLogReadOut(inSuite, context, logMgmt, nl::Weave::Profiles::DataManagement::Production, eid2, 2);
CheckLogReadOut(inSuite, context, logMgmt, nl::Weave::Profiles::DataManagement::Production, eid3, 1);
if (context->bdx)
{
DoBDXUpload(context);
}
}
#define kSampleEventTag_State 1
#define kSampleEventTag_Timestamp 2
#define kSampleEventTag_Structure 3
#define kSampleEventTag_Samples 4
#define kEventStructTag_a 1
#define kEventStructTag_b 2
#define kEventStatsTag_str 1
#define kDataManagementTag_EventData 50
static const uint8_t SampleEventEncoding[] = { nlWeaveTLV_STRUCTURE(nlWeaveTLV_TAG_FULLY_QUALIFIED_6Bytes(0x0A00, 1)),
nlWeaveTLV_STRUCTURE(nlWeaveTLV_TAG_CONTEXT_SPECIFIC(kDataManagementTag_EventData)),
nlWeaveTLV_UINT8(nlWeaveTLV_TAG_CONTEXT_SPECIFIC(kSampleEventTag_State), 5),
nlWeaveTLV_UINT16(nlWeaveTLV_TAG_CONTEXT_SPECIFIC(kSampleEventTag_Timestamp), 328),
nlWeaveTLV_STRUCTURE(nlWeaveTLV_TAG_CONTEXT_SPECIFIC(kSampleEventTag_Structure)),
nlWeaveTLV_BOOL(nlWeaveTLV_TAG_CONTEXT_SPECIFIC(kEventStructTag_a), true),
nlWeaveTLV_STRUCTURE(nlWeaveTLV_TAG_CONTEXT_SPECIFIC(kEventStructTag_b)),
nlWeaveTLV_UTF8_STRING_1ByteLength(
nlWeaveTLV_TAG_CONTEXT_SPECIFIC(kEventStatsTag_str), 10),
'b',
'l',
'o',
'o',
'p',
'b',
'l',
'o',
'o',
'p',
nlWeaveTLV_END_OF_CONTAINER,
nlWeaveTLV_END_OF_CONTAINER,
nlWeaveTLV_ARRAY(nlWeaveTLV_TAG_CONTEXT_SPECIFIC(kSampleEventTag_Samples)),
nlWeaveTLV_UINT8(nlWeaveTLV_TAG_ANONYMOUS, 0),
nlWeaveTLV_UINT8(nlWeaveTLV_TAG_ANONYMOUS, 1),
nlWeaveTLV_UINT8(nlWeaveTLV_TAG_ANONYMOUS, 2),
nlWeaveTLV_UINT8(nlWeaveTLV_TAG_ANONYMOUS, 3),
nlWeaveTLV_UINT8(nlWeaveTLV_TAG_ANONYMOUS, 4),
nlWeaveTLV_UINT8(nlWeaveTLV_TAG_ANONYMOUS, 5),
nlWeaveTLV_END_OF_CONTAINER,
nlWeaveTLV_END_OF_CONTAINER,
nlWeaveTLV_END_OF_CONTAINER };
static const uint8_t SampleEmptyArrayEventEncoding[] = {
nlWeaveTLV_STRUCTURE(nlWeaveTLV_TAG_FULLY_QUALIFIED_6Bytes(0x0A00, 1)),
nlWeaveTLV_STRUCTURE(nlWeaveTLV_TAG_CONTEXT_SPECIFIC(kDataManagementTag_EventData)),
nlWeaveTLV_UINT8(nlWeaveTLV_TAG_CONTEXT_SPECIFIC(kSampleEventTag_State), 5),
nlWeaveTLV_UINT16(nlWeaveTLV_TAG_CONTEXT_SPECIFIC(kSampleEventTag_Timestamp), 328),
nlWeaveTLV_STRUCTURE(nlWeaveTLV_TAG_CONTEXT_SPECIFIC(kSampleEventTag_Structure)),
nlWeaveTLV_BOOL(nlWeaveTLV_TAG_CONTEXT_SPECIFIC(kEventStructTag_a), true),
nlWeaveTLV_STRUCTURE(nlWeaveTLV_TAG_CONTEXT_SPECIFIC(kEventStructTag_b)),
nlWeaveTLV_UTF8_STRING_1ByteLength(nlWeaveTLV_TAG_CONTEXT_SPECIFIC(kEventStatsTag_str), 10),
'b',
'l',
'o',
'o',
'p',
'b',
'l',
'o',
'o',
'p',
nlWeaveTLV_END_OF_CONTAINER,
nlWeaveTLV_END_OF_CONTAINER,
nlWeaveTLV_ARRAY(nlWeaveTLV_TAG_CONTEXT_SPECIFIC(kSampleEventTag_Samples)),
nlWeaveTLV_END_OF_CONTAINER,
nlWeaveTLV_END_OF_CONTAINER,
nlWeaveTLV_END_OF_CONTAINER
};
static void CheckSchemaGeneratedLogging(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
event_id_t eid1, eid2;
WEAVE_ERROR err;
nl::Weave::Profiles::DataManagement::LoggingManagement & logMgmt =
nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance();
nl::Weave::Profiles::DataManagement::SampleTrait::Event ev;
nl::Weave::Profiles::DataManagement::OpenCloseTrait::Event ev2;
nl::StructureSchemaPointerPair appData;
nl::Weave::TLV::TLVWriter outer, writer;
uint8_t sBuffer[256];
InitializeEventLogging(context);
uint32_t samples[6] = { 0, 1, 2, 3, 4, 5 };
ev.state = 5;
ev.timestamp = 328;
ev.structure.a = true;
ev.structure.b.str = "bloopbloop\0";
ev.samples.num_samples = 6;
ev.samples.samples_buf = samples;
appData.mStructureData = static_cast<void *>(&ev);
appData.mFieldSchema = &sampleEventSchema;
outer.Init(sBuffer, sizeof(sBuffer));
err = outer.OpenContainer(ProfileTag(0x0A00, 1), kTLVType_Structure, writer);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = SerializedDataToTLVWriterHelper(writer, kTag_EventData, &appData);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = outer.CloseContainer(writer);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = outer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Verify the encoding
NL_TEST_ASSERT(inSuite, outer.GetLengthWritten() == sizeof(SampleEventEncoding));
NL_TEST_ASSERT(inSuite, memcmp(sBuffer, SampleEventEncoding, sizeof(SampleEventEncoding)) == 0);
eid1 = LogSampleEvent(&ev, nl::Weave::Profiles::DataManagement::Production);
CheckLogState(inSuite, context, logMgmt, 1);
ev2.state = 1;
eid2 = LogOpenCloseEvent(&ev2, nl::Weave::Profiles::DataManagement::Production);
CheckLogState(inSuite, context, logMgmt, 2);
CheckLogReadOut(inSuite, context, logMgmt, nl::Weave::Profiles::DataManagement::Production, eid1, 2);
CheckLogReadOut(inSuite, context, logMgmt, nl::Weave::Profiles::DataManagement::Production, eid2, 1);
if (context->bdx)
{
DoBDXUpload(context);
}
}
static void CheckByteStringFieldType(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
WEAVE_ERROR err;
event_id_t eventId;
ByteStringTestTrait::Event ev, deserializedEv;
nl::MemoryManagement memMgmt = { malloc, free, realloc };
nl::SerializationContext serializationContext;
serializationContext.memMgmt = memMgmt;
TLVReader testReader;
uint8_t buf[10];
ev.byte_string.mLen = sizeof(buf);
ev.byte_string.mBuf = buf;
memset(buf, 0xaa, 10);
InitializeEventLogging(context);
eventId = LogByteStringTestEvent(&ev);
err = FetchEventsHelper(testReader, eventId, gLargeMemoryBackingStore, sizeof(gLargeMemoryBackingStore));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = DeserializeByteStringTestEvent(testReader, &deserializedEv, &serializationContext);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, deserializedEv.byte_string.mLen == ev.byte_string.mLen);
NL_TEST_ASSERT(inSuite, memcmp(deserializedEv.byte_string.mBuf, ev.byte_string.mBuf, ev.byte_string.mLen) == 0);
}
static void CheckByteStringArray(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
WEAVE_ERROR err;
event_id_t eventId;
ByteStringArrayTestTrait::Event ev, deserializedEv;
nl::MemoryManagement memMgmt = { malloc, free, realloc };
nl::SerializationContext serializationContext;
serializationContext.memMgmt = memMgmt;
TLVReader testReader;
nl::SerializedByteString bytestrings[5];
uint8_t buf[100];
int i;
// some magic numbers to initialize some varied byte strings
for (i = 0; i < 5; i++)
{
memset(&buf[i * 5], (i + 1) * 40, (i + 1) * 5);
bytestrings[i].mLen = (i + 1) * 5;
bytestrings[i].mBuf = &buf[i * 5];
}
ev.testArray.num = 5;
ev.testArray.buf = bytestrings;
InitializeEventLogging(context);
eventId = LogByteStringArrayTestEvent(&ev);
err = FetchEventsHelper(testReader, eventId, gLargeMemoryBackingStore, sizeof(gLargeMemoryBackingStore));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = DeserializeByteStringArrayTestEvent(testReader, &deserializedEv, &serializationContext);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, deserializedEv.testArray.num == ev.testArray.num);
for (i = 0; i < 5; i++)
{
NL_TEST_ASSERT(inSuite, deserializedEv.testArray.buf[i].mLen == ev.testArray.buf[i].mLen);
NL_TEST_ASSERT(inSuite,
memcmp(deserializedEv.testArray.buf[i].mBuf, ev.testArray.buf[i].mBuf, ev.testArray.buf[i].mLen) == 0);
}
}
struct DebugLogContext
{
const char * mRegion;
const char * mFmt;
va_list mArgs;
};
static event_id_t FastLogFreeform(ImportanceType inImportance, timestamp_t inTimestamp, const char * inFormat, ...)
{
DebugLogContext context;
nl::Weave::Profiles::DataManagement::EventOptions options;
event_id_t eid;
EventSchema schema = { kWeaveProfile_NestDebug, kNestDebug_StringLogEntryEvent, inImportance, 1, 1 };
va_start(context.mArgs, inFormat);
context.mRegion = "";
context.mFmt = inFormat;
options = EventOptions(inTimestamp, NULL, 0, nl::Weave::Profiles::DataManagement::kImportanceType_Invalid, false);
eid = LogEvent(schema, PlainTextWriter, &context, &options);
va_end(context.mArgs);
return eid;
}
static void CheckEvict(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
event_id_t eid_prev, eid;
size_t counter = 0;
timestamp_t now;
InitializeEventLogging(context);
now = System::Layer::GetClock_MonotonicMS();
eid_prev = FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now, "Freeform entry %d", counter);
now += 10;
for (counter = 0; counter < 100; counter++)
{
// Sample production events, spaced 10 milliseconds apart
eid = FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now, "Freeform entry %d", counter);
now += 10;
NL_TEST_ASSERT(inSuite, eid > 0);
NL_TEST_ASSERT(inSuite, eid == (eid_prev + 1));
eid_prev = eid;
}
if (context->bdx)
{
DoBDXUpload(context);
}
}
static WEAVE_ERROR ReadFirstEventHeader(TLVReader & aReader, timestamp_t & aTimestamp, utc_timestamp_t & aUtcTimestamp,
event_id_t & aEventId)
{
WEAVE_ERROR err;
TLVType readerType;
uint64_t currentContextTag;
err = aReader.Next();
SuccessOrExit(err);
err = aReader.EnterContainer(readerType);
SuccessOrExit(err);
currentContextTag = aReader.GetTag();
while ((currentContextTag != ContextTag(kTag_EventData)) && !err)
{
if (currentContextTag == ContextTag(nl::Weave::Profiles::DataManagement::kTag_EventSystemTimestamp))
{
err = aReader.Get(aTimestamp);
SuccessOrExit(err);
}
if (currentContextTag == ContextTag(nl::Weave::Profiles::DataManagement::kTag_EventUTCTimestamp))
{
err = aReader.Get(aUtcTimestamp);
SuccessOrExit(err);
}
if (currentContextTag == ContextTag(nl::Weave::Profiles::DataManagement::kTag_EventID))
{
err = aReader.Get(aEventId);
SuccessOrExit(err);
}
err = aReader.Next();
SuccessOrExit(err);
currentContextTag = aReader.GetTag();
}
err = aReader.ExitContainer(readerType);
exit:
return err;
}
static void CheckFetchTimestamps(nlTestSuite * inSuite, void * inContext)
{
WEAVE_ERROR err;
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
event_id_t eid_prev, eid, event_id_read;
size_t counter = 0;
const int k_num_events = 10;
timestamp_t now;
utc_timestamp_t test_start;
InitializeEventLogging(context);
test_start = static_cast<utc_timestamp_t>(System::Layer::GetClock_MonotonicMS());
now = static_cast<timestamp_t>(test_start);
System::Layer::SetClock_RealTime(0);
eid_prev = FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now, "%u", now);
eid_prev = FastLogFreeform(nl::Weave::Profiles::DataManagement::Info, now, "%u", now);
now += 10;
for (counter = 1; counter < k_num_events; counter++)
{
// Sample production events, spaced 10 milliseconds apart
if (counter == k_num_events / 2)
{
System::Layer::SetClock_RealTime((test_start) *1000);
}
eid = FastLogFreeform(nl::Weave::Profiles::DataManagement::Info, now, "%u", now);
NL_TEST_ASSERT(inSuite, eid > 0);
eid = FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now, "%u", now);
NL_TEST_ASSERT(inSuite, eid > 0);
NL_TEST_ASSERT(inSuite, eid == (eid_prev + 1));
now += 10;
eid_prev = eid;
}
NL_TEST_ASSERT(inSuite, eid_prev == k_num_events);
for (counter = 0; counter < k_num_events; counter++)
{
TLVReader testReader;
TLVWriter testWriter;
utc_timestamp_t testUtcTimestamp = 0;
timestamp_t testTimestamp = 0;
event_id_t testEventID = 0;
event_id_read = counter + 1;
testWriter.Init(gLargeMemoryBackingStore, sizeof(gLargeMemoryBackingStore));
err = nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance().FetchEventsSince(
testWriter, nl::Weave::Profiles::DataManagement::Info, event_id_read);
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV);
NL_TEST_ASSERT(inSuite, event_id_read == eid_prev + 1);
if (context->mVerbose)
{
TLVReader reader;
reader.Init(gLargeMemoryBackingStore, testWriter.GetLengthWritten());
nl::Weave::TLV::Debug::Dump(reader, SimpleDumpWriter);
}
testReader.Init(gLargeMemoryBackingStore, testWriter.GetLengthWritten());
err = ReadFirstEventHeader(testReader, testTimestamp, testUtcTimestamp, testEventID);
NL_TEST_ASSERT(inSuite, testEventID == counter + 1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
#if WEAVE_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS
if (counter >= k_num_events / 2)
{
NL_TEST_ASSERT(inSuite, testUtcTimestamp == test_start + (testEventID - 1) * 10);
}
else
#endif // WEAVE_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS
{
NL_TEST_ASSERT(inSuite, testTimestamp == static_cast<timestamp_t>(test_start) + (testEventID - 1) * 10);
}
}
}
WEAVE_ERROR WriteLargeEvent(nl::Weave::TLV::TLVWriter & writer, uint8_t inDataTag, void * anAppState)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
nl::Weave::TLV::TLVType containerType;
uint32_t * payloadEventSize;
uint8_t * dummyPayload = NULL;
VerifyOrExit(anAppState != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
payloadEventSize = static_cast<uint32_t *>(anAppState);
dummyPayload = reinterpret_cast<uint8_t *>(malloc(*payloadEventSize));
VerifyOrExit(dummyPayload != NULL, err = WEAVE_ERROR_NO_MEMORY);
memset(dummyPayload, 0xa5, *payloadEventSize);
err = writer.StartContainer(ContextTag(nl::Weave::Profiles::DataManagement::kTag_EventData), nl::Weave::TLV::kTLVType_Structure,
containerType);
SuccessOrExit(err);
err = writer.PutBytes(nl::Weave::TLV::ContextTag(1), dummyPayload, *payloadEventSize);
SuccessOrExit(err);
err = writer.EndContainer(containerType);
SuccessOrExit(err);
err = writer.Finalize();
exit:
if (dummyPayload != NULL)
{
free(dummyPayload);
}
return err;
}
static void CheckLargeEvents(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
uint32_t payloadSize;
event_id_t eid1, eid2, eid3, eid4;
EventSchema schema = { OpenCloseProfileID,
1, // Event type 1
nl::Weave::Profiles::DataManagement::Production, 1, 1 };
InitializeEventLogging(context);
nl::Weave::Profiles::DataManagement::LoggingManagement & logMgmt =
nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance();
// we expect this payload to succeed
payloadSize = EVENT_PAYLOAD_SIZE_1;
eid1 = nl::Weave::Profiles::DataManagement::LogEvent(schema, WriteLargeEvent, static_cast<void *>(&payloadSize));
NL_TEST_ASSERT(inSuite, eid1 == 1);
eid2 = nl::Weave::Profiles::DataManagement::LogEvent(schema, WriteLargeEvent, static_cast<void *>(&payloadSize));
NL_TEST_ASSERT(inSuite, eid2 == 2);
CheckLogState(inSuite, context, logMgmt, 2);
// new test case - events will get retried if they fail
payloadSize = EVENT_PAYLOAD_SIZE_2;
eid3 = nl::Weave::Profiles::DataManagement::LogEvent(schema, WriteLargeEvent, static_cast<void *>(&payloadSize));
NL_TEST_ASSERT(inSuite, eid3 == 3);
// this event is wider than the debug buffer
payloadSize = EVENT_PAYLOAD_SIZE_3;
eid4 = nl::Weave::Profiles::DataManagement::LogEvent(schema, WriteLargeEvent, static_cast<void *>(&payloadSize));
NL_TEST_ASSERT(inSuite, eid4 == 0);
}
#if WEAVE_CONFIG_EVENT_LOGGING_EXTERNAL_EVENT_SUPPORT
static void CheckDropEvents(nlTestSuite * inSuite, void * inContext)
{
WEAVE_ERROR err;
int counter = 0;
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
EventSchema schema = { OpenCloseProfileID,
1, // Event type 1
nl::Weave::Profiles::DataManagement::Production, 1, 1 };
event_id_t eid_prev, eid;
CircularEventBuffer * prodBuf = reinterpret_cast<CircularEventBuffer *>(&gProdEventBuffer[0]);
uint32_t eventSizes[] = {
EVENT_ENVELOPE_SIZE,
EVENT_PAYLOAD_SIZE_1,
EVENT_PAYLOAD_SIZE_2,
};
const uint32_t numSizes = sizeof(eventSizes) / sizeof(uint32_t);
TLVWriter testWriter;
InitializeEventLogging(context);
nl::Weave::Profiles::DataManagement::LoggingManagement & logMgmt =
nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance();
// register some fake events
err = LogMockExternalEvents(10, 1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
eid_prev = prodBuf->mLastEventID;
while (prodBuf->mFirstEventID <= 10)
{
eid = nl::Weave::Profiles::DataManagement::LogEvent(schema, WriteLargeEvent,
static_cast<void *>(&eventSizes[counter++ % numSizes]));
NL_TEST_ASSERT(inSuite, eid > eid_prev);
if (eid_prev > 10)
{
testWriter.Init(gLargeMemoryBackingStore, sizeof(gLargeMemoryBackingStore));
err = logMgmt.FetchEventsSince(testWriter, nl::Weave::Profiles::DataManagement::Production, eid_prev);
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV);
NL_TEST_ASSERT(inSuite, eid_prev == eid + 1);
}
eid_prev = eid;
}
{
TLVReader testReader;
event_id_t testEventID, eid_in = 0;
timestamp_t testTimestamp;
utc_timestamp_t testUtcTimestamp;
testWriter.Init(gLargeMemoryBackingStore, sizeof(gLargeMemoryBackingStore));
err = logMgmt.FetchEventsSince(testWriter, nl::Weave::Profiles::DataManagement::Production, eid_in);
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV);
NL_TEST_ASSERT(inSuite, eid_in > 10);
testReader.Init(gLargeMemoryBackingStore, testWriter.GetLengthWritten());
err = ReadFirstEventHeader(testReader, testTimestamp, testUtcTimestamp, testEventID);
NL_TEST_ASSERT(inSuite, testEventID >= 10);
}
}
#endif // WEAVE_CONFIG_EVENT_LOGGING_EXTERNAL_EVENT_SUPPORT
static void CheckFetchEvents(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
event_id_t eid_prev, eid, eventId;
size_t counter = 0;
// small buffer, sized s.t. the events generated below will be
// larger than a single buffer, but smaller than two buffers.
uint8_t smallMemoryBackingStore[1280];
PacketBuffer * pbuf = PacketBuffer::New();
TLVWriter testWriter;
WEAVE_ERROR err;
timestamp_t now;
InitializeEventLogging(context);
now = static_cast<timestamp_t>(0);
eid_prev = FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now, "Freeform entry %d", counter);
// The magic number "40" below is selected to be large enough to
// generate more events than can fit in a single PacketBuffer, but
// fewer than can fit in 2 packet buffers. This ensures that we
// test both the cases when we run out of log before ending the
// buffer, and the cases when the writer runs out of space before
// the end of the log.
now += 10;
for (counter = 0; counter < 40; counter++)
{
// Sample production events, spaced 10 milliseconds apart
eid = FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now, "Freeform entry %d", counter);
now += 10;
NL_TEST_ASSERT(inSuite, eid > 0);
NL_TEST_ASSERT(inSuite, eid == (eid_prev + 1));
eid_prev = eid;
}
if (context->mVerbose)
{
PrintEventLog();
}
// Test that offloading events into large buffer completes and
// returns WEAVE_END_OF_TLV
eventId = 0;
testWriter.Init(gLargeMemoryBackingStore, sizeof(gLargeMemoryBackingStore));
err = nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance().FetchEventsSince(
testWriter, nl::Weave::Profiles::DataManagement::Production, eventId);
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV);
// Test that offloading events into a smaller buffer with bounded
// write length results in WEAVE_ERROR_BUFFER_TOO_SMALL and the
// correct number of events as indicated by eventId
eventId = 1;
eid_prev = eventId;
testWriter.Init(smallMemoryBackingStore, sizeof(smallMemoryBackingStore));
err = nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance().FetchEventsSince(
testWriter, nl::Weave::Profiles::DataManagement::Production, eventId);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_BUFFER_TOO_SMALL);
{
TLVReader reader;
size_t eventCount;
reader.Init(smallMemoryBackingStore, testWriter.GetLengthWritten());
err = nl::Weave::TLV::Utilities::Count(reader, eventCount, false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, eventId - eid_prev == eventCount);
}
// resume event offload; this one should reach the end of the
// log (by construction)
testWriter.Init(smallMemoryBackingStore, sizeof(smallMemoryBackingStore));
err = nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance().FetchEventsSince(
testWriter, nl::Weave::Profiles::DataManagement::Production, eventId);
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV);
// Test that offloading events into a PacketBuffer-backed writer with the default (unbounded) max write length results in
// WEAVE_ERROR_NO_MEMORY
eventId = 0;
testWriter.Init(pbuf);
err = nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance().FetchEventsSince(
testWriter, nl::Weave::Profiles::DataManagement::Production, eventId);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_NO_MEMORY);
PacketBuffer::Free(pbuf);
pbuf = PacketBuffer::New();
testWriter.Init(pbuf);
err = nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance().FetchEventsSince(
testWriter, nl::Weave::Profiles::DataManagement::Production, eventId);
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV);
if (context->bdx)
{
DoBDXUpload(context);
}
}
static void CheckBasicEventDeserialization(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
WEAVE_ERROR err;
nl::Weave::Profiles::DataManagement::SampleTrait::Event ev, ev2;
nl::StructureSchemaPointerPair appData;
nl::Weave::TLV::TLVWriter outer, writer;
nl::Weave::TLV::TLVReader reader, outerReader;
uint8_t sBuffer[256];
nl::MemoryManagement memMgmt = { malloc, free, realloc };
nl::SerializationContext serializationContext;
serializationContext.memMgmt = memMgmt;
InitializeEventLogging(context);
uint32_t samples[6] = { 0, 1, 2, 3, 4, 5 };
ev.state = 5;
ev.timestamp = 328;
ev.structure.a = true;
ev.structure.b.str = "bloopbloop\0";
ev.samples.num_samples = 6;
ev.samples.samples_buf = samples;
appData.mStructureData = static_cast<void *>(&ev);
appData.mFieldSchema = &sampleEventSchema;
outer.Init(sBuffer, sizeof(sBuffer));
err = outer.OpenContainer(ProfileTag(0x0A00, 1), kTLVType_Structure, writer);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = SerializedDataToTLVWriterHelper(writer, kTag_EventData, &appData);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = outer.CloseContainer(writer);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = outer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Verify the encoding
NL_TEST_ASSERT(inSuite, outer.GetLengthWritten() == sizeof(SampleEventEncoding));
NL_TEST_ASSERT(inSuite, memcmp(sBuffer, SampleEventEncoding, sizeof(SampleEventEncoding)) == 0);
// Now de-serialize.
outerReader.Init(sBuffer, outer.GetLengthWritten());
err = outerReader.Next(); // Positions us at the beginning of the first element.
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
appData.mStructureData = static_cast<void *>(&ev2);
appData.mFieldSchema = &sampleEventSchema;
err = outerReader.OpenContainer(reader);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = reader.Next(); // Positions us at the beginning of the first element.
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = nl::Weave::Profiles::DataManagement::DeserializeSampleEvent(reader, &ev2, &serializationContext);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = outerReader.CloseContainer(reader);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, ev2.state == ev.state);
NL_TEST_ASSERT(inSuite, ev2.timestamp == ev.timestamp);
NL_TEST_ASSERT(inSuite, ev2.structure.a == ev.structure.a);
NL_TEST_ASSERT(inSuite, strcmp(ev2.structure.b.str, ev.structure.b.str) == 0);
NL_TEST_ASSERT(inSuite, ev2.samples.num_samples == ev.samples.num_samples);
for (uint32_t i = 0; i < ev2.samples.num_samples; i++)
{
NL_TEST_ASSERT(inSuite, ev2.samples.samples_buf[i] == ev.samples.samples_buf[i]);
}
nl::DeallocateDeserializedStructure(&ev2, &sampleEventSchema, &serializationContext);
}
static void CheckComplexEventDeserialization(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
WEAVE_ERROR err;
Schema::Nest::Test::Trait::TestETrait::TestEEvent ev = { 0 };
Schema::Nest::Test::Trait::TestETrait::TestEEvent ev2 = { 0 };
nl::StructureSchemaPointerPair appData;
nl::Weave::TLV::TLVWriter outer, writer;
nl::Weave::TLV::TLVReader reader, outerReader;
uint8_t sBuffer[512];
nl::MemoryManagement memMgmt = { malloc, free, realloc };
nl::SerializationContext serializationContext;
serializationContext.memMgmt = memMgmt;
InitializeEventLogging(context);
memset(&ev, 0, sizeof(ev));
uint32_t numbaz[5];
numbaz[0] = 1;
numbaz[1] = 3;
numbaz[2] = 5;
numbaz[3] = 7;
numbaz[4] = 10;
Schema::Nest::Test::Trait::TestCommon::CommonStructE strukchaz[3];
strukchaz[0].seA = 1111111;
strukchaz[0].seB = true;
strukchaz[1].seA = 2222222;
strukchaz[1].seB = false;
strukchaz[2].seA = 3333333;
strukchaz[2].seB = true;
ev.teA = 444444;
ev.teB = -555555;
ev.teC = true;
ev.teD = -666666;
ev.teE.seA = 777777;
ev.teE.seB = false;
ev.teE.seC = -888888;
ev.teF = 999999;
ev.teG.seA = 101010;
ev.teG.seB = true;
ev.teH.num = sizeof(numbaz) / sizeof(numbaz[0]);
ev.teH.buf = numbaz;
ev.teI.num = sizeof(strukchaz) / sizeof(strukchaz[0]);
ev.teI.buf = strukchaz;
ev.teJ = 12121;
appData.mStructureData = static_cast<void *>(&ev);
appData.mFieldSchema = &Schema::Nest::Test::Trait::TestETrait::TestEEvent::FieldSchema;
outer.Init(sBuffer, sizeof(sBuffer));
err = outer.OpenContainer(ProfileTag(0x0A00, 1), kTLVType_Structure, writer);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = SerializedDataToTLVWriterHelper(writer, kTag_EventData, &appData);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = outer.CloseContainer(writer);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = outer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Now de-serialize.
outerReader.Init(sBuffer, outer.GetLengthWritten());
err = outerReader.Next(); // Positions us at the beginning of the first element.
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
appData.mStructureData = static_cast<void *>(&ev2);
appData.mFieldSchema = &Schema::Nest::Test::Trait::TestETrait::TestEEvent::FieldSchema;
err = outerReader.OpenContainer(reader);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = reader.Next(); // Positions us at the beginning of the first element.
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = nl::DeserializeEvent(reader, &ev2, &serializationContext);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
SuccessOrExit(err);
err = outerReader.CloseContainer(reader);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, ev2.teA == ev.teA);
NL_TEST_ASSERT(inSuite, ev2.teB == ev.teB);
NL_TEST_ASSERT(inSuite, ev2.teC == ev.teC);
NL_TEST_ASSERT(inSuite, ev2.teD == ev.teD);
NL_TEST_ASSERT(inSuite, ev2.teE.seA == ev.teE.seA);
NL_TEST_ASSERT(inSuite, ev2.teE.seB == ev.teE.seB);
NL_TEST_ASSERT(inSuite, ev2.teE.seC == ev.teE.seC);
NL_TEST_ASSERT(inSuite, ev2.teF == ev.teF);
NL_TEST_ASSERT(inSuite, ev2.teG.seA == ev.teG.seA);
NL_TEST_ASSERT(inSuite, ev2.teG.seB == ev.teG.seB);
for (uint32_t i = 0; i < ev2.teH.num; i++)
{
NL_TEST_ASSERT(inSuite, ev2.teH.buf[i] == ev.teH.buf[i]);
}
for (uint32_t i = 0; i < ev2.teI.num; i++)
{
NL_TEST_ASSERT(inSuite, ev2.teI.buf[i].seA == ev.teI.buf[i].seA);
NL_TEST_ASSERT(inSuite, ev2.teI.buf[i].seB == ev.teI.buf[i].seB);
}
NL_TEST_ASSERT(inSuite, ev2.IsTeJPresent());
NL_TEST_ASSERT(inSuite, ev2.teJ == ev.teJ);
nl::DeallocateEvent(&ev2, &serializationContext);
exit:
return;
}
static void CheckEmptyArrayEventDeserialization(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
WEAVE_ERROR err;
nl::Weave::Profiles::DataManagement::SampleTrait::Event ev, ev2;
nl::StructureSchemaPointerPair appData;
nl::Weave::TLV::TLVWriter outer, writer;
nl::Weave::TLV::TLVReader reader, outerReader;
uint8_t sBuffer[256];
nl::MemoryManagement memMgmt = { malloc, free, realloc };
nl::SerializationContext serializationContext;
serializationContext.memMgmt = memMgmt;
InitializeEventLogging(context);
ev.state = 5;
ev.timestamp = 328;
ev.structure.a = true;
ev.structure.b.str = "bloopbloop\0";
ev.samples.num_samples = 0;
ev.samples.samples_buf = NULL;
appData.mStructureData = static_cast<void *>(&ev);
appData.mFieldSchema = &sampleEventSchema;
outer.Init(sBuffer, sizeof(sBuffer));
err = outer.OpenContainer(ProfileTag(0x0A00, 1), kTLVType_Structure, writer);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = SerializedDataToTLVWriterHelper(writer, kTag_EventData, &appData);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = outer.CloseContainer(writer);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = outer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Verify the encoding
NL_TEST_ASSERT(inSuite, outer.GetLengthWritten() == sizeof(SampleEmptyArrayEventEncoding));
NL_TEST_ASSERT(inSuite, memcmp(sBuffer, SampleEmptyArrayEventEncoding, sizeof(SampleEmptyArrayEventEncoding)) == 0);
// Now de-serialize.
outerReader.Init(sBuffer, outer.GetLengthWritten());
err = outerReader.Next(); // Positions us at the beginning of the first element.
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
appData.mStructureData = static_cast<void *>(&ev2);
appData.mFieldSchema = &sampleEventSchema;
err = outerReader.OpenContainer(reader);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = reader.Next(); // Positions us at the beginning of the first element.
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = nl::Weave::Profiles::DataManagement::DeserializeSampleEvent(reader, &ev2, &serializationContext);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = outerReader.CloseContainer(reader);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, ev2.state == ev.state);
NL_TEST_ASSERT(inSuite, ev2.timestamp == ev.timestamp);
NL_TEST_ASSERT(inSuite, ev2.structure.a == ev.structure.a);
NL_TEST_ASSERT(inSuite, strcmp(ev2.structure.b.str, ev.structure.b.str) == 0);
NL_TEST_ASSERT(inSuite, ev2.samples.num_samples == ev.samples.num_samples);
NL_TEST_ASSERT(inSuite, ev2.samples.samples_buf == NULL);
memMgmt.mem_free((void *) ev2.structure.b.str);
}
static WEAVE_ERROR FetchEventsHelper(TLVReader & aReader, event_id_t aEventId, uint8_t * aBackingStore, size_t aLen,
ImportanceType aImportance)
{
WEAVE_ERROR err;
TLVWriter testWriter;
TLVType readerType;
testWriter.Init(aBackingStore, aLen);
err = nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance().FetchEventsSince(testWriter, aImportance, aEventId);
VerifyOrExit(err == WEAVE_END_OF_TLV, err = WEAVE_ERROR_INCORRECT_STATE);
aReader.Init(aBackingStore, testWriter.GetLengthWritten());
err = aReader.Next();
SuccessOrExit(err);
err = aReader.EnterContainer(readerType);
SuccessOrExit(err);
while ((aReader.GetTag() != ContextTag(kTag_EventData)) && (err == WEAVE_NO_ERROR))
{
err = aReader.Next();
}
exit:
return err;
}
class TestEventProcessor : public EventProcessor
{
public:
TestEventProcessor();
WEAVE_ERROR ProcessEvent(TLVReader inReader, SubscriptionClient & inClient, const EventHeader & inEventHeader);
WEAVE_ERROR GapDetected(const EventHeader & inEventHeader);
SchemaVersionRange mSchemaVersionRange;
};
TestEventProcessor::TestEventProcessor() : EventProcessor(0) { }
WEAVE_ERROR TestEventProcessor::ProcessEvent(TLVReader inReader, SubscriptionClient & inClient, const EventHeader & inEventHeader)
{
mSchemaVersionRange = inEventHeader.mDataSchemaVersionRange;
return WEAVE_NO_ERROR;
}
WEAVE_ERROR TestEventProcessor::GapDetected(const EventHeader & inEventHeader)
{
return WEAVE_NO_ERROR;
}
static WEAVE_ERROR VersionCompatibilityHelper(void * inContext, SchemaVersionRange & encodedSchemaVersionRange,
SchemaVersionRange & decodedSchemaVersionRange)
{
WEAVE_ERROR err;
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
InitializeEventLoggingWithPersistedCounters(context, 1, nl::Weave::Profiles::DataManagement::Production);
TLVReader testReader;
uint8_t backingStore[1024];
uint32_t bytesWritten;
Schema::Nest::Test::Trait::TestETrait::TestEEvent evN = { 0 };
EventSchema testSchema = Schema::Nest::Test::Trait::TestETrait::TestEEvent::Schema;
TestEventProcessor eventProcessor;
nl::MemoryManagement memMgmt = { malloc, free, realloc };
nl::SerializationContext serializationContext;
serializationContext.memMgmt = memMgmt;
nl::StructureSchemaPointerPair appData;
PrepareBinding(context);
InitSubscriptionClient(context);
testSchema.mMinCompatibleDataSchemaVersion = encodedSchemaVersionRange.mMinVersion;
testSchema.mDataSchemaVersion = encodedSchemaVersionRange.mMaxVersion;
appData.mStructureData = static_cast<void *>(&evN);
appData.mFieldSchema = &Schema::Nest::Test::Trait::TestETrait::TestEEvent::FieldSchema;
event_id_t eventId =
nl::Weave::Profiles::DataManagement::LogEvent(testSchema, nl::SerializedDataToTLVWriterHelper, (void *) &appData);
err = FetchEventsHelper(testReader, eventId, backingStore, sizeof(backingStore));
SuccessOrExit(err);
bytesWritten = testReader.GetRemainingLength() + testReader.GetLengthRead();
testReader.Init(backingStore, bytesWritten);
err = eventProcessor.ProcessEvents(testReader, *context->mSubClient);
SuccessOrExit(err);
decodedSchemaVersionRange = eventProcessor.mSchemaVersionRange;
if (context->mVerbose)
{
nl::Weave::TLV::Debug::Dump(testReader, SimpleDumpWriter);
}
exit:
return err;
}
static void CheckVersion1DataCompatibility(nlTestSuite * inSuite, void * inContext)
{
WEAVE_ERROR err;
SchemaVersionRange encodedSchemaVersionRange, decodedSchemaVersionRange;
encodedSchemaVersionRange.mMaxVersion = 1;
encodedSchemaVersionRange.mMinVersion = 1;
err = VersionCompatibilityHelper(inContext, encodedSchemaVersionRange, decodedSchemaVersionRange);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, encodedSchemaVersionRange == decodedSchemaVersionRange);
}
static void CheckForwardDataCompatibility(nlTestSuite * inSuite, void * inContext)
{
WEAVE_ERROR err;
SchemaVersionRange encodedSchemaVersionRange, decodedSchemaVersionRange;
encodedSchemaVersionRange.mMaxVersion = 4;
encodedSchemaVersionRange.mMinVersion = 1;
err = VersionCompatibilityHelper(inContext, encodedSchemaVersionRange, decodedSchemaVersionRange);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, encodedSchemaVersionRange == decodedSchemaVersionRange);
}
static void CheckDataIncompatibility(nlTestSuite * inSuite, void * inContext)
{
WEAVE_ERROR err;
SchemaVersionRange encodedSchemaVersionRange, decodedSchemaVersionRange;
encodedSchemaVersionRange.mMaxVersion = 4;
encodedSchemaVersionRange.mMinVersion = 2;
err = VersionCompatibilityHelper(inContext, encodedSchemaVersionRange, decodedSchemaVersionRange);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, encodedSchemaVersionRange == decodedSchemaVersionRange);
}
namespace {
class FakeEventProcessor : public EventProcessor
{
public:
FakeEventProcessor();
void ClearMock();
WEAVE_ERROR ProcessEvent(TLVReader inReader, SubscriptionClient & inClient, const EventHeader & inEventHeader);
WEAVE_ERROR GapDetected(const EventHeader & inEventHeader);
EventHeader mLastEventHeader;
bool mGapDetected;
EventHeader mGapEventHeader;
int mEventsProcessed;
};
FakeEventProcessor::FakeEventProcessor() :
EventProcessor(0), mLastEventHeader(), mGapDetected(false), mGapEventHeader(), mEventsProcessed()
{ }
void FakeEventProcessor::ClearMock()
{
mLastEventHeader = EventHeader();
mGapDetected = false;
mGapEventHeader = EventHeader();
mEventsProcessed = 0;
}
WEAVE_ERROR FakeEventProcessor::ProcessEvent(TLVReader inReader, SubscriptionClient & inClient, const EventHeader & inEventHeader)
{
mLastEventHeader = inEventHeader;
mEventsProcessed++;
return WEAVE_NO_ERROR;
}
WEAVE_ERROR FakeEventProcessor::GapDetected(const EventHeader & inEventHeader)
{
mGapDetected = true;
mGapEventHeader = inEventHeader;
return WEAVE_NO_ERROR;
}
} // namespace
static void CheckGapDetection(nlTestSuite * inSuite, void * inContext)
{
WEAVE_ERROR err;
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
InitializeEventLoggingWithPersistedCounters(context, 1, nl::Weave::Profiles::DataManagement::Production);
TLVReader testReader;
uint8_t backingStore[1024];
uint32_t bytesWritten;
Schema::Nest::Test::Trait::TestETrait::TestEEvent evN = { 0 };
EventSchema testSchema = Schema::Nest::Test::Trait::TestETrait::TestEEvent::Schema;
FakeEventProcessor eventProcessor;
nl::MemoryManagement memMgmt = { malloc, free, realloc };
nl::SerializationContext serializationContext;
serializationContext.memMgmt = memMgmt;
nl::StructureSchemaPointerPair appData;
PrepareBinding(context);
InitSubscriptionClient(context);
appData.mStructureData = static_cast<void *>(&evN);
appData.mFieldSchema = &Schema::Nest::Test::Trait::TestETrait::TestEEvent::FieldSchema;
// Arrange two consecutive events
event_id_t eventId_A =
nl::Weave::Profiles::DataManagement::LogEvent(testSchema, nl::SerializedDataToTLVWriterHelper, (void *) &appData);
event_id_t eventId_B =
nl::Weave::Profiles::DataManagement::LogEvent(testSchema, nl::SerializedDataToTLVWriterHelper, (void *) &appData);
IgnoreUnusedVariable(eventId_B);
// Arrange testReader with all events from the start
err = FetchEventsHelper(testReader, eventId_A, backingStore, sizeof(backingStore));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
bytesWritten = testReader.GetRemainingLength() + testReader.GetLengthRead();
testReader.Init(backingStore, bytesWritten);
err = eventProcessor.ProcessEvents(testReader, *context->mSubClient);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, eventProcessor.mGapDetected == false);
NL_TEST_ASSERT(inSuite, eventProcessor.mEventsProcessed == 2);
eventProcessor.ClearMock();
// Arrange two more consecutive events
event_id_t eventId_C =
nl::Weave::Profiles::DataManagement::LogEvent(testSchema, nl::SerializedDataToTLVWriterHelper, (void *) &appData);
event_id_t eventId_D =
nl::Weave::Profiles::DataManagement::LogEvent(testSchema, nl::SerializedDataToTLVWriterHelper, (void *) &appData);
IgnoreUnusedVariable(eventId_C);
// Arrange testReader skipping eventId_C
err = FetchEventsHelper(testReader, eventId_D, backingStore, sizeof(backingStore));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
bytesWritten = testReader.GetRemainingLength() + testReader.GetLengthRead();
testReader.Init(backingStore, bytesWritten);
err = eventProcessor.ProcessEvents(testReader, *context->mSubClient);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, eventProcessor.mGapDetected == true);
NL_TEST_ASSERT(inSuite, eventProcessor.mEventsProcessed == 1);
eventProcessor.ClearMock();
}
static void CheckDropOverlap(nlTestSuite * inSuite, void * inContext)
{
WEAVE_ERROR err;
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
InitializeEventLoggingWithPersistedCounters(context, 1, nl::Weave::Profiles::DataManagement::Production);
TLVReader testReader;
uint8_t backingStore[1024];
uint32_t bytesWritten;
Schema::Nest::Test::Trait::TestETrait::TestEEvent evN = { 0 };
EventSchema testSchema = Schema::Nest::Test::Trait::TestETrait::TestEEvent::Schema;
FakeEventProcessor eventProcessor;
nl::MemoryManagement memMgmt = { malloc, free, realloc };
nl::SerializationContext serializationContext;
serializationContext.memMgmt = memMgmt;
nl::StructureSchemaPointerPair appData;
PrepareBinding(context);
InitSubscriptionClient(context);
appData.mStructureData = static_cast<void *>(&evN);
appData.mFieldSchema = &Schema::Nest::Test::Trait::TestETrait::TestEEvent::FieldSchema;
// Arrange two consecutive events
event_id_t eventId_A =
nl::Weave::Profiles::DataManagement::LogEvent(testSchema, nl::SerializedDataToTLVWriterHelper, (void *) &appData);
event_id_t eventId_B =
nl::Weave::Profiles::DataManagement::LogEvent(testSchema, nl::SerializedDataToTLVWriterHelper, (void *) &appData);
// Arrange testReader with all events from the start
err = FetchEventsHelper(testReader, eventId_A, backingStore, sizeof(backingStore));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
bytesWritten = testReader.GetRemainingLength() + testReader.GetLengthRead();
testReader.Init(backingStore, bytesWritten);
err = eventProcessor.ProcessEvents(testReader, *context->mSubClient);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, eventProcessor.mGapDetected == false);
NL_TEST_ASSERT(inSuite, eventProcessor.mEventsProcessed == 2);
eventProcessor.ClearMock();
// Arrange two more consecutive events
event_id_t eventId_C =
nl::Weave::Profiles::DataManagement::LogEvent(testSchema, nl::SerializedDataToTLVWriterHelper, (void *) &appData);
event_id_t eventId_D =
nl::Weave::Profiles::DataManagement::LogEvent(testSchema, nl::SerializedDataToTLVWriterHelper, (void *) &appData);
IgnoreUnusedVariable(eventId_C);
IgnoreUnusedVariable(eventId_D);
// Arrange testReader overlapping eventId_B
err = FetchEventsHelper(testReader, eventId_B, backingStore, sizeof(backingStore));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
bytesWritten = testReader.GetRemainingLength() + testReader.GetLengthRead();
testReader.Init(backingStore, bytesWritten);
err = eventProcessor.ProcessEvents(testReader, *context->mSubClient);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, eventProcessor.mGapDetected == false);
NL_TEST_ASSERT(inSuite, eventProcessor.mEventsProcessed == 2);
eventProcessor.ClearMock();
// Arrange testReader overlapping all events
err = FetchEventsHelper(testReader, eventId_A, backingStore, sizeof(backingStore));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
bytesWritten = testReader.GetRemainingLength() + testReader.GetLengthRead();
testReader.Init(backingStore, bytesWritten);
err = eventProcessor.ProcessEvents(testReader, *context->mSubClient);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, eventProcessor.mGapDetected == false);
NL_TEST_ASSERT(inSuite, eventProcessor.mEventsProcessed == 0);
eventProcessor.ClearMock();
}
static void CheckNullableFieldsSimple(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
WEAVE_ERROR err;
TLVReader testReader;
uint8_t backingStore[1024];
Schema::Nest::Test::Trait::TestETrait::TestEEvent evN = { 0 };
Schema::Nest::Test::Trait::TestETrait::TestEEvent deserializedEvN = { 0 };
nl::MemoryManagement memMgmt = { malloc, free, realloc };
nl::SerializationContext serializationContext;
serializationContext.memMgmt = memMgmt;
InitializeEventLogging(context);
evN.teA = 10;
evN.SetTeJNull();
event_id_t eventId = nl::LogEvent(&evN);
err = FetchEventsHelper(testReader, eventId, backingStore, sizeof(backingStore));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
if (context->mVerbose)
{
nl::Weave::TLV::Debug::Dump(testReader, SimpleDumpWriter);
}
err = nl::DeserializeEvent(testReader, &deserializedEvN, &serializationContext);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, deserializedEvN.teA == evN.teA);
NL_TEST_ASSERT(inSuite, GET_FIELD_NULLIFIED_BIT(deserializedEvN.__nullified_fields__, 0));
NL_TEST_ASSERT(inSuite, deserializedEvN.IsTeJPresent() == false);
}
static void CheckNullableFieldsComplex(nlTestSuite * inSuite, void * inContext)
{
// pattern: for each bit in nullified fields, set and check
// for array of nullable structs, set and check
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
WEAVE_ERROR err;
uint8_t backingStore[1024];
Schema::Nest::Test::Trait::TestETrait::TestENullableEvent teN_s = { 0 };
teN_s.neA = 0xAAAAAAAA;
teN_s.neB = -1;
teN_s.neC = true;
teN_s.neD = "bar\0";
teN_s.neE = 5;
teN_s.neF = 0x77777777;
teN_s.neG = -30;
teN_s.neH = false;
teN_s.neI = "foo\0";
teN_s.neJ.neA = 88;
teN_s.neJ.neB = true;
nl::MemoryManagement memMgmt = { malloc, free, realloc };
nl::SerializationContext serializationContext;
serializationContext.memMgmt = memMgmt;
InitializeEventLogging(context);
// hardcoded number nullable fields
for (int i = 0; i < 10; i++)
{
Schema::Nest::Test::Trait::TestETrait::TestENullableEvent teN_d = { 0 };
event_id_t eventId;
TLVReader testReader;
memset(teN_s.__nullified_fields__, 0, sizeof(teN_s.__nullified_fields__));
memset(teN_s.neJ.__nullified_fields__, 0, sizeof(teN_s.neJ.__nullified_fields__));
SET_FIELD_NULLIFIED_BIT(teN_s.__nullified_fields__, i);
eventId = nl::LogEvent(&teN_s);
err = FetchEventsHelper(testReader, eventId, backingStore, sizeof(backingStore));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = nl::DeserializeEvent(testReader, &teN_d, &serializationContext);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, GET_FIELD_NULLIFIED_BIT(teN_d.__nullified_fields__, i));
if (i != 0)
{
NL_TEST_ASSERT(inSuite, teN_d.neA == teN_s.neA);
}
else
{
NL_TEST_ASSERT(inSuite, teN_d.IsNeAPresent() == false);
}
if (i != 1)
{
NL_TEST_ASSERT(inSuite, teN_d.neB == teN_s.neB);
}
else
{
NL_TEST_ASSERT(inSuite, teN_d.IsNeBPresent() == false);
}
if (i != 2)
{
NL_TEST_ASSERT(inSuite, teN_d.neC == teN_s.neC);
}
else
{
NL_TEST_ASSERT(inSuite, teN_d.IsNeCPresent() == false);
}
if (i != 3)
{
NL_TEST_ASSERT(inSuite, strcmp(teN_d.neD, teN_s.neD) == 0);
}
else
{
NL_TEST_ASSERT(inSuite, teN_d.IsNeDPresent() == false);
}
if (i != 4)
{
NL_TEST_ASSERT(inSuite, teN_d.neE == teN_s.neE);
}
else
{
NL_TEST_ASSERT(inSuite, teN_d.IsNeEPresent() == false);
}
if (i != 5)
{
NL_TEST_ASSERT(inSuite, teN_d.neF == teN_s.neF);
}
else
{
NL_TEST_ASSERT(inSuite, teN_d.IsNeFPresent() == false);
}
if (i != 6)
{
NL_TEST_ASSERT(inSuite, teN_d.neG == teN_s.neG);
}
else
{
NL_TEST_ASSERT(inSuite, teN_d.IsNeGPresent() == false);
}
if (i != 7)
{
NL_TEST_ASSERT(inSuite, teN_d.neH == teN_s.neH);
}
else
{
NL_TEST_ASSERT(inSuite, teN_d.IsNeHPresent() == false);
}
if (i != 8)
{
NL_TEST_ASSERT(inSuite, strcmp(teN_d.neI, teN_s.neI) == 0);
}
else
{
NL_TEST_ASSERT(inSuite, teN_d.IsNeIPresent() == false);
}
if (i != 9)
{
NL_TEST_ASSERT(inSuite, teN_d.neJ.neA == teN_s.neJ.neA);
NL_TEST_ASSERT(inSuite, teN_d.neJ.neB == teN_s.neJ.neB);
}
else
{
NL_TEST_ASSERT(inSuite, teN_d.IsNeJPresent() == false);
}
err = nl::DeallocateEvent(&teN_d, &serializationContext);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
for (int i = 0; i < 2; i++)
{
Schema::Nest::Test::Trait::TestETrait::TestENullableEvent teN_d = { 0 };
event_id_t eventId;
TLVReader testReader;
memset(teN_s.__nullified_fields__, 0, sizeof(teN_s.__nullified_fields__));
memset(teN_s.neJ.__nullified_fields__, 0, sizeof(teN_s.neJ.__nullified_fields__));
SET_FIELD_NULLIFIED_BIT(teN_s.neJ.__nullified_fields__, i);
eventId = nl::LogEvent(&teN_s);
err = FetchEventsHelper(testReader, eventId, backingStore, sizeof(backingStore));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = nl::DeserializeEvent(testReader, &teN_d, &serializationContext);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, GET_FIELD_NULLIFIED_BIT(teN_d.neJ.__nullified_fields__, i));
NL_TEST_ASSERT(inSuite, teN_d.neA == teN_s.neA);
NL_TEST_ASSERT(inSuite, teN_d.neB == teN_s.neB);
NL_TEST_ASSERT(inSuite, teN_d.neC == teN_s.neC);
NL_TEST_ASSERT(inSuite, strcmp(teN_d.neD, teN_s.neD) == 0);
NL_TEST_ASSERT(inSuite, teN_d.neE == teN_s.neE);
NL_TEST_ASSERT(inSuite, teN_d.neF == teN_s.neF);
NL_TEST_ASSERT(inSuite, teN_d.neG == teN_s.neG);
NL_TEST_ASSERT(inSuite, teN_d.neH == teN_s.neH);
NL_TEST_ASSERT(inSuite, strcmp(teN_d.neI, teN_s.neI) == 0);
if (i == 1)
{
NL_TEST_ASSERT(inSuite, teN_d.neJ.neA == teN_s.neJ.neA);
NL_TEST_ASSERT(inSuite, teN_d.neJ.IsNeBPresent() == false);
}
else
{
NL_TEST_ASSERT(inSuite, teN_d.neJ.neB == teN_s.neJ.neB);
NL_TEST_ASSERT(inSuite, teN_d.neJ.IsNeAPresent() == false);
}
}
}
static void CheckWDMOffloadTrigger(nlTestSuite * inSuite, void * inContext)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
timestamp_t now;
size_t counter = 0;
uint32_t eventSize;
::nl::Weave::Profiles::DataManagement::TestSubscriptionHandler * testSubHandler;
::nl::Weave::Profiles::DataManagement::SubscriptionHandler * subHandler;
nl::Weave::Profiles::DataManagement::LoggingManagement & logger =
nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance();
event_id_t eid, eid_prev;
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
InitializeEventLogging(context);
// Each event is about 40 bytes; write 40 of those to ensure we
// override the default WDM event byte threshold
now = System::Layer::GetClock_MonotonicMS();
eid_prev = FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now, "Freeform entry %d", counter++);
eventSize = logger.GetBytesWritten();
for (size_t expectedBufferSize = 0; expectedBufferSize < WEAVE_CONFIG_EVENT_LOGGING_BYTE_THRESHOLD;
expectedBufferSize += eventSize)
{
now += 10;
eid = FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now, "Freeform entry %d", counter++);
NL_TEST_ASSERT(inSuite, eid == (eid_prev + 1));
eid_prev = eid;
}
// subscription engine has no subscription handlers, we should not be running the WDM
NL_TEST_ASSERT(inSuite, logger.CheckShouldRunWDM() == false);
// create a fake subscription, and start messing with it to check that WDM trigger will run
err = ::nl::Weave::Profiles::DataManagement::SubscriptionEngine::GetInstance()->NewSubscriptionHandler(&subHandler);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
testSubHandler = static_cast<::nl::Weave::Profiles::DataManagement::TestSubscriptionHandler *>(subHandler);
new (testSubHandler)::nl::Weave::Profiles::DataManagement::TestSubscriptionHandler();
NL_TEST_ASSERT(inSuite, testSubHandler->IsFree());
NL_TEST_ASSERT(inSuite, logger.CheckShouldRunWDM() == false);
testSubHandler->SetActive();
NL_TEST_ASSERT(inSuite, logger.CheckShouldRunWDM() == true);
testSubHandler->SetEventLogEndpoint(logger);
NL_TEST_ASSERT(inSuite, logger.CheckShouldRunWDM() == false);
// A single event at this point should not trigger the engine
eid = FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now, "Freeform entry %d", counter++);
NL_TEST_ASSERT(inSuite, eid == (eid_prev + 1));
NL_TEST_ASSERT(inSuite, logger.CheckShouldRunWDM() == false);
}
// Mock'd Events (would be autogen'd by phoenix)
struct CurrentEvent
{
int32_t enumState;
bool boolState;
static const nl::SchemaFieldDescriptor FieldSchema;
enum
{
kProfileId = 0x1U,
kEventTypeId = 0x1U
};
static const nl::Weave::Profiles::DataManagement::EventSchema Schema;
};
const nl::FieldDescriptor CurrentEventFieldDescriptors[] = {
{ NULL, offsetof(CurrentEvent, enumState), SET_TYPE_AND_FLAGS(nl::SerializedFieldTypeInt32, 0), 1 },
{ NULL, offsetof(CurrentEvent, boolState), SET_TYPE_AND_FLAGS(nl::SerializedFieldTypeBoolean, 0), 32 },
};
const nl::SchemaFieldDescriptor CurrentEvent::FieldSchema = { .mNumFieldDescriptorElements = sizeof(CurrentEventFieldDescriptors) /
sizeof(CurrentEventFieldDescriptors[0]),
.mFields = CurrentEventFieldDescriptors,
.mSize = sizeof(CurrentEvent) };
const nl::Weave::Profiles::DataManagement::EventSchema CurrentEvent::Schema = {
.mProfileId = kProfileId,
.mStructureType = 0x1,
.mImportance = nl::Weave::Profiles::DataManagement::ProductionCritical,
.mDataSchemaVersion = 1,
.mMinCompatibleDataSchemaVersion = 1
};
struct FutureEventNewBaseField
{
int32_t enumState;
int32_t otherEnumState;
bool boolState;
static const nl::SchemaFieldDescriptor FieldSchema;
enum
{
kProfileId = 0x1U,
kEventTypeId = 0x1U
};
static const nl::Weave::Profiles::DataManagement::EventSchema Schema;
};
const nl::FieldDescriptor FutureEventNewBaseFieldFieldDescriptors[] = {
{ NULL, offsetof(FutureEventNewBaseField, enumState), SET_TYPE_AND_FLAGS(nl::SerializedFieldTypeInt32, 0), 1 },
{ NULL, offsetof(FutureEventNewBaseField, otherEnumState), SET_TYPE_AND_FLAGS(nl::SerializedFieldTypeInt32, 0), 2 },
{ NULL, offsetof(FutureEventNewBaseField, boolState), SET_TYPE_AND_FLAGS(nl::SerializedFieldTypeBoolean, 0), 32 },
};
const nl::SchemaFieldDescriptor FutureEventNewBaseField::FieldSchema = { .mNumFieldDescriptorElements =
sizeof(FutureEventNewBaseFieldFieldDescriptors) /
sizeof(FutureEventNewBaseFieldFieldDescriptors[0]),
.mFields = FutureEventNewBaseFieldFieldDescriptors,
.mSize = sizeof(FutureEventNewBaseField) };
const nl::Weave::Profiles::DataManagement::EventSchema FutureEventNewBaseField::Schema = {
.mProfileId = kProfileId,
.mStructureType = 0x1,
.mImportance = nl::Weave::Profiles::DataManagement::ProductionCritical,
.mDataSchemaVersion = 2,
.mMinCompatibleDataSchemaVersion = 1
};
static void CheckDeserializingNewerVersion(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
WEAVE_ERROR err;
nl::MemoryManagement memMgmt = { malloc, free, realloc };
nl::SerializationContext serializationContext;
serializationContext.memMgmt = memMgmt;
uint8_t backingStore[1024];
InitializeEventLogging(context);
FutureEventNewBaseField externalEv = { 0 };
externalEv.enumState = 10;
externalEv.otherEnumState = 20;
externalEv.boolState = true;
event_id_t eventId = nl::LogEvent(&externalEv);
TLVReader testReader;
err = FetchEventsHelper(testReader, eventId, backingStore, sizeof(backingStore),
nl::Weave::Profiles::DataManagement::ProductionCritical);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
if (context->mVerbose)
{
nl::Weave::TLV::Debug::Dump(testReader, SimpleDumpWriter);
}
CurrentEvent deserializedEv = { 0 };
nl::StructureSchemaPointerPair structureSchemaPair;
structureSchemaPair.mStructureData = &deserializedEv;
structureSchemaPair.mFieldSchema = &CurrentEvent::FieldSchema;
err = nl::TLVReaderToDeserializedDataHelper(testReader, nl::Weave::Profiles::DataManagement::kTag_EventData,
(void *) &structureSchemaPair, &serializationContext);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, deserializedEv.enumState == externalEv.enumState);
NL_TEST_ASSERT(inSuite, deserializedEv.boolState == externalEv.boolState);
}
static void CheckDeserializingOlderVersion(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
WEAVE_ERROR err;
nl::MemoryManagement memMgmt = { malloc, free, realloc };
nl::SerializationContext serializationContext;
serializationContext.memMgmt = memMgmt;
uint8_t backingStore[1024];
InitializeEventLogging(context);
CurrentEvent externalEv = { 0 };
externalEv.enumState = 10;
externalEv.boolState = true;
event_id_t eventId = nl::LogEvent(&externalEv);
TLVReader testReader;
err = FetchEventsHelper(testReader, eventId, backingStore, sizeof(backingStore),
nl::Weave::Profiles::DataManagement::ProductionCritical);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
if (context->mVerbose)
{
nl::Weave::TLV::Debug::Dump(testReader, SimpleDumpWriter);
}
FutureEventNewBaseField deserializedEv = { 0 };
nl::StructureSchemaPointerPair structureSchemaPair;
structureSchemaPair.mStructureData = &deserializedEv;
structureSchemaPair.mFieldSchema = &FutureEventNewBaseField::FieldSchema;
err = nl::TLVReaderToDeserializedDataHelper(testReader, nl::Weave::Profiles::DataManagement::kTag_EventData,
(void *) &structureSchemaPair, &serializationContext);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, deserializedEv.enumState == externalEv.enumState);
NL_TEST_ASSERT(inSuite, deserializedEv.otherEnumState == 0);
NL_TEST_ASSERT(inSuite, deserializedEv.boolState == externalEv.boolState);
}
// ---------------
struct CurrentNullableEvent
{
int32_t baseEnum;
void SetBaseEnumNull(void);
void SetBaseEnumPresent(void);
#if WEAVE_CONFIG_SERIALIZATION_ENABLE_DESERIALIZATION
bool IsBaseEnumPresent(void);
#endif
int32_t extendedEnum;
void SetExtendedEnumNull(void);
void SetExtendedEnumPresent(void);
#if WEAVE_CONFIG_SERIALIZATION_ENABLE_DESERIALIZATION
bool IsExtendedEnumPresent(void);
#endif
uint8_t __nullified_fields__[2 / 8 + 1];
static const nl::SchemaFieldDescriptor FieldSchema;
enum
{
kProfileId = 0x1U,
kEventTypeId = 0x1U
};
static const nl::Weave::Profiles::DataManagement::EventSchema Schema;
};
const nl::FieldDescriptor CurrentNullableEventFieldDescriptors[] = {
{ NULL, offsetof(CurrentNullableEvent, baseEnum), SET_TYPE_AND_FLAGS(nl::SerializedFieldTypeInt32, 1), 1 },
{ NULL, offsetof(CurrentNullableEvent, extendedEnum), SET_TYPE_AND_FLAGS(nl::SerializedFieldTypeInt32, 1), 32 },
};
const nl::SchemaFieldDescriptor CurrentNullableEvent::FieldSchema = {
.mNumFieldDescriptorElements = sizeof(CurrentNullableEventFieldDescriptors) / sizeof(CurrentNullableEventFieldDescriptors[0]),
.mFields = CurrentNullableEventFieldDescriptors,
.mSize = sizeof(CurrentNullableEvent)
};
const nl::Weave::Profiles::DataManagement::EventSchema CurrentNullableEvent::Schema = {
.mProfileId = kProfileId,
.mStructureType = 0x1,
.mImportance = nl::Weave::Profiles::DataManagement::ProductionCritical,
.mDataSchemaVersion = 2,
.mMinCompatibleDataSchemaVersion = 1
};
inline void CurrentNullableEvent::SetBaseEnumNull(void)
{
SET_FIELD_NULLIFIED_BIT(__nullified_fields__, 0);
}
inline void CurrentNullableEvent::SetBaseEnumPresent(void)
{
CLEAR_FIELD_NULLIFIED_BIT(__nullified_fields__, 0);
}
#if WEAVE_CONFIG_SERIALIZATION_ENABLE_DESERIALIZATION
inline bool CurrentNullableEvent::IsBaseEnumPresent(void)
{
return (!GET_FIELD_NULLIFIED_BIT(__nullified_fields__, 0));
}
#endif
inline void CurrentNullableEvent::SetExtendedEnumNull(void)
{
SET_FIELD_NULLIFIED_BIT(__nullified_fields__, 1);
}
inline void CurrentNullableEvent::SetExtendedEnumPresent(void)
{
CLEAR_FIELD_NULLIFIED_BIT(__nullified_fields__, 1);
}
#if WEAVE_CONFIG_SERIALIZATION_ENABLE_DESERIALIZATION
inline bool CurrentNullableEvent::IsExtendedEnumPresent(void)
{
return (!GET_FIELD_NULLIFIED_BIT(__nullified_fields__, 1));
}
#endif
struct FutureNullableEvent
{
int32_t baseEnum;
void SetBaseEnumNull(void);
void SetBaseEnumPresent(void);
#if WEAVE_CONFIG_SERIALIZATION_ENABLE_DESERIALIZATION
bool IsBaseEnumPresent(void);
#endif
int32_t futureEnum;
void SetFutureEnumNull(void);
void SetFutureEnumPresent(void);
#if WEAVE_CONFIG_SERIALIZATION_ENABLE_DESERIALIZATION
bool IsFutureEnumPresent(void);
#endif
int32_t extendedEnum;
void SetExtendedEnumNull(void);
void SetExtendedEnumPresent(void);
#if WEAVE_CONFIG_SERIALIZATION_ENABLE_DESERIALIZATION
bool IsExtendedEnumPresent(void);
#endif
int32_t futureExtendedEnum;
void SetFutureExtendedEnumNull(void);
void SetFutureExtendedEnumPresent(void);
#if WEAVE_CONFIG_SERIALIZATION_ENABLE_DESERIALIZATION
bool IsFutureExtendedEnumPresent(void);
#endif
uint8_t __nullified_fields__[4 / 8 + 1];
static const nl::SchemaFieldDescriptor FieldSchema;
enum
{
kProfileId = 0x1U,
kEventTypeId = 0x1U
};
static const nl::Weave::Profiles::DataManagement::EventSchema Schema;
};
const nl::FieldDescriptor FutureNullableEventFieldDescriptors[] = {
{ NULL, offsetof(FutureNullableEvent, baseEnum), SET_TYPE_AND_FLAGS(nl::SerializedFieldTypeInt32, 1), 1 },
{ NULL, offsetof(FutureNullableEvent, futureEnum), SET_TYPE_AND_FLAGS(nl::SerializedFieldTypeInt32, 1), 2 },
{ NULL, offsetof(FutureNullableEvent, extendedEnum), SET_TYPE_AND_FLAGS(nl::SerializedFieldTypeInt32, 1), 32 },
{ NULL, offsetof(FutureNullableEvent, futureExtendedEnum), SET_TYPE_AND_FLAGS(nl::SerializedFieldTypeInt32, 1), 33 },
};
const nl::SchemaFieldDescriptor FutureNullableEvent::FieldSchema = {
.mNumFieldDescriptorElements = sizeof(FutureNullableEventFieldDescriptors) / sizeof(FutureNullableEventFieldDescriptors[0]),
.mFields = FutureNullableEventFieldDescriptors,
.mSize = sizeof(FutureNullableEvent)
};
const nl::Weave::Profiles::DataManagement::EventSchema FutureNullableEvent::Schema = {
.mProfileId = kProfileId,
.mStructureType = 0x1,
.mImportance = nl::Weave::Profiles::DataManagement::ProductionCritical,
.mDataSchemaVersion = 2,
.mMinCompatibleDataSchemaVersion = 1
};
inline void FutureNullableEvent::SetBaseEnumNull(void)
{
SET_FIELD_NULLIFIED_BIT(__nullified_fields__, 0);
}
inline void FutureNullableEvent::SetBaseEnumPresent(void)
{
CLEAR_FIELD_NULLIFIED_BIT(__nullified_fields__, 0);
}
#if WEAVE_CONFIG_SERIALIZATION_ENABLE_DESERIALIZATION
inline bool FutureNullableEvent::IsBaseEnumPresent(void)
{
return (!GET_FIELD_NULLIFIED_BIT(__nullified_fields__, 0));
}
#endif
inline void FutureNullableEvent::SetFutureEnumNull(void)
{
SET_FIELD_NULLIFIED_BIT(__nullified_fields__, 1);
}
inline void FutureNullableEvent::SetFutureEnumPresent(void)
{
CLEAR_FIELD_NULLIFIED_BIT(__nullified_fields__, 1);
}
#if WEAVE_CONFIG_SERIALIZATION_ENABLE_DESERIALIZATION
inline bool FutureNullableEvent::IsFutureEnumPresent(void)
{
return (!GET_FIELD_NULLIFIED_BIT(__nullified_fields__, 1));
}
#endif
inline void FutureNullableEvent::SetExtendedEnumNull(void)
{
SET_FIELD_NULLIFIED_BIT(__nullified_fields__, 2);
}
inline void FutureNullableEvent::SetExtendedEnumPresent(void)
{
CLEAR_FIELD_NULLIFIED_BIT(__nullified_fields__, 2);
}
#if WEAVE_CONFIG_SERIALIZATION_ENABLE_DESERIALIZATION
inline bool FutureNullableEvent::IsExtendedEnumPresent(void)
{
return (!GET_FIELD_NULLIFIED_BIT(__nullified_fields__, 2));
}
#endif
inline void FutureNullableEvent::SetFutureExtendedEnumNull(void)
{
SET_FIELD_NULLIFIED_BIT(__nullified_fields__, 3);
}
inline void FutureNullableEvent::SetFutureExtendedEnumPresent(void)
{
CLEAR_FIELD_NULLIFIED_BIT(__nullified_fields__, 3);
}
#if WEAVE_CONFIG_SERIALIZATION_ENABLE_DESERIALIZATION
inline bool FutureNullableEvent::IsFutureExtendedEnumPresent(void)
{
return (!GET_FIELD_NULLIFIED_BIT(__nullified_fields__, 3));
}
#endif
static void CheckDeserializingNewerVersionNullable(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
WEAVE_ERROR err;
nl::MemoryManagement memMgmt = { malloc, free, realloc };
nl::SerializationContext serializationContext;
serializationContext.memMgmt = memMgmt;
uint8_t backingStore[1024];
InitializeEventLogging(context);
FutureNullableEvent externalEv = { 0 };
externalEv.baseEnum = 50;
externalEv.SetBaseEnumPresent();
externalEv.SetFutureEnumNull();
externalEv.extendedEnum = 70;
externalEv.SetExtendedEnumPresent();
externalEv.SetFutureExtendedEnumNull();
event_id_t eventId = nl::LogEvent(&externalEv);
TLVReader testReader;
err = FetchEventsHelper(testReader, eventId, backingStore, sizeof(backingStore),
nl::Weave::Profiles::DataManagement::ProductionCritical);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
if (context->mVerbose)
{
nl::Weave::TLV::Debug::Dump(testReader, SimpleDumpWriter);
}
CurrentNullableEvent deserializedEv = { 0 };
nl::StructureSchemaPointerPair structureSchemaPair;
structureSchemaPair.mStructureData = &deserializedEv;
structureSchemaPair.mFieldSchema = &CurrentNullableEvent::FieldSchema;
err = nl::TLVReaderToDeserializedDataHelper(testReader, nl::Weave::Profiles::DataManagement::kTag_EventData,
(void *) &structureSchemaPair, &serializationContext);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, deserializedEv.IsBaseEnumPresent());
NL_TEST_ASSERT(inSuite, deserializedEv.IsBaseEnumPresent() == externalEv.IsBaseEnumPresent());
NL_TEST_ASSERT(inSuite, deserializedEv.baseEnum == externalEv.baseEnum);
NL_TEST_ASSERT(inSuite, deserializedEv.IsExtendedEnumPresent());
NL_TEST_ASSERT(inSuite, deserializedEv.IsExtendedEnumPresent() == externalEv.IsExtendedEnumPresent());
NL_TEST_ASSERT(inSuite, deserializedEv.extendedEnum == externalEv.extendedEnum);
}
static void CheckDeserializingOlderVersionNullable(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
WEAVE_ERROR err;
nl::MemoryManagement memMgmt = { malloc, free, realloc };
nl::SerializationContext serializationContext;
serializationContext.memMgmt = memMgmt;
uint8_t backingStore[1024];
InitializeEventLogging(context);
CurrentNullableEvent externalEv = { 0 };
externalEv.baseEnum = 50;
externalEv.SetBaseEnumPresent();
externalEv.SetExtendedEnumNull();
event_id_t eventId = nl::LogEvent(&externalEv);
TLVReader testReader;
err = FetchEventsHelper(testReader, eventId, backingStore, sizeof(backingStore),
nl::Weave::Profiles::DataManagement::ProductionCritical);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
if (context->mVerbose)
{
nl::Weave::TLV::Debug::Dump(testReader, SimpleDumpWriter);
}
FutureNullableEvent deserializedEv = { 0 };
nl::StructureSchemaPointerPair structureSchemaPair;
structureSchemaPair.mStructureData = &deserializedEv;
structureSchemaPair.mFieldSchema = &FutureNullableEvent::FieldSchema;
err = nl::TLVReaderToDeserializedDataHelper(testReader, nl::Weave::Profiles::DataManagement::kTag_EventData,
(void *) &structureSchemaPair, &serializationContext);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, deserializedEv.IsBaseEnumPresent());
NL_TEST_ASSERT(inSuite, deserializedEv.IsBaseEnumPresent() == externalEv.IsBaseEnumPresent());
NL_TEST_ASSERT(inSuite, deserializedEv.baseEnum == externalEv.baseEnum);
NL_TEST_ASSERT(inSuite, deserializedEv.IsFutureEnumPresent() == false);
NL_TEST_ASSERT(inSuite, deserializedEv.IsExtendedEnumPresent() == false);
NL_TEST_ASSERT(inSuite, deserializedEv.IsFutureExtendedEnumPresent() == false);
}
static void CheckSubscriptionHandlerHelper(nlTestSuite * inSuite, TestLoggingContext * context, bool inLogInfoEvents)
{
WEAVE_ERROR err;
timestamp_t now;
size_t counter = 0;
::nl::Weave::Profiles::DataManagement::TestSubscriptionHandler subHandler;
nl::Weave::Profiles::DataManagement::LoggingManagement & logger =
nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance();
nl::Weave::Profiles::DataManagement::ImportanceType importance;
TLVWriter writer;
uint8_t backingStore[1024];
event_id_t eid_init_prod, eid_prev_prod, eid_init_info, eid_prev_info, eid;
now = System::Layer::GetClock_MonotonicMS();
eid_init_prod = FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now, "Freeform entry %d", counter++);
if (inLogInfoEvents)
{
eid_init_info = FastLogFreeform(nl::Weave::Profiles::DataManagement::Info, now + 5, "Freeform entry %d", counter++);
}
eid_prev_prod = FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now + 10, "Freeform entry %d", counter++);
if (inLogInfoEvents)
{
eid_prev_info = FastLogFreeform(nl::Weave::Profiles::DataManagement::Info, now + 15, "Freeform entry %d", counter++);
}
NL_TEST_ASSERT(inSuite, (eid_init_prod + 1) == eid_prev_prod);
if (inLogInfoEvents)
{
if (nl::Weave::Profiles::DataManagement::LoggingConfiguration::GetInstance().mGlobalImportance >=
nl::Weave::Profiles::DataManagement::Info)
{
NL_TEST_ASSERT(inSuite, (eid_init_info + 1) == eid_prev_info);
}
else
{
NL_TEST_ASSERT(inSuite, eid_prev_info == 0 && eid_init_info == 0);
}
}
NL_TEST_ASSERT(inSuite, subHandler.CheckEventUpToDate(logger) == false);
subHandler.SetEventLogEndpoint(logger);
importance = subHandler.FindNextImportanceForTransfer();
NL_TEST_ASSERT(inSuite, importance == nl::Weave::Profiles::DataManagement::Production);
writer.Init(backingStore, 1024);
CheckLogReadOut(inSuite, context, logger, importance, eid_init_prod, 2);
err = logger.FetchEventsSince(writer, importance, subHandler.GetVendedEvent(importance));
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV || err == WEAVE_NO_ERROR);
// If we expect to have logged the Info events above, check the Info logs
if (inLogInfoEvents &&
(nl::Weave::Profiles::DataManagement::LoggingConfiguration::GetInstance().mGlobalImportance >=
nl::Weave::Profiles::DataManagement::Info))
{
importance = subHandler.FindNextImportanceForTransfer();
NL_TEST_ASSERT(inSuite, importance == nl::Weave::Profiles::DataManagement::Info);
writer.Init(backingStore, 1024);
CheckLogReadOut(inSuite, context, logger, importance, eid_init_info, 2);
err = logger.FetchEventsSince(writer, importance, subHandler.GetVendedEvent(importance));
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV || err == WEAVE_NO_ERROR);
}
importance = subHandler.FindNextImportanceForTransfer();
NL_TEST_ASSERT(inSuite, subHandler.VerifyTraversingImportance());
while (importance != nl::Weave::Profiles::DataManagement::kImportanceType_Invalid)
{
err = logger.FetchEventsSince(writer, importance, subHandler.GetVendedEvent(importance));
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV || err == WEAVE_NO_ERROR);
importance = subHandler.FindNextImportanceForTransfer();
}
// Verify that events are retrieved.
NL_TEST_ASSERT(inSuite, subHandler.VerifyTraversingImportance());
NL_TEST_ASSERT(inSuite, subHandler.CheckEventUpToDate(logger));
// Check that a single event will trigger the up to date check
eid = FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now + 10, "Freeform entry %d", counter++);
NL_TEST_ASSERT(inSuite, (eid_prev_prod + 1) == eid);
NL_TEST_ASSERT(inSuite, subHandler.CheckEventUpToDate(logger) == false);
subHandler.SetEventLogEndpoint(logger);
importance = subHandler.FindNextImportanceForTransfer();
NL_TEST_ASSERT(inSuite, importance == nl::Weave::Profiles::DataManagement::Production);
// Verify that the read operation will retrieve a single event
eid_init_prod = subHandler.GetVendedEvent(importance);
CheckLogReadOut(inSuite, context, logger, importance, eid_init_prod, 1);
writer.Init(backingStore, 1024);
while (importance != nl::Weave::Profiles::DataManagement::kImportanceType_Invalid)
{
err = logger.FetchEventsSince(writer, importance, subHandler.GetVendedEvent(importance));
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV || err == WEAVE_NO_ERROR);
importance = subHandler.FindNextImportanceForTransfer();
}
// Verify that the all events are retrieved
NL_TEST_ASSERT(inSuite, subHandler.VerifyTraversingImportance());
NL_TEST_ASSERT(inSuite, subHandler.CheckEventUpToDate(logger));
}
static void CheckSubscriptionHandler(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
const bool aLogInfoEvents = false;
InitializeEventLogging(context);
CheckSubscriptionHandlerHelper(inSuite, context, aLogInfoEvents);
}
static void CheckSubscriptionHandlerCountersStartAtZeroProd(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
const bool aLogInfoEvents = false;
InitializeEventLoggingWithPersistedCounters(context, 0, nl::Weave::Profiles::DataManagement::Production);
CheckSubscriptionHandlerHelper(inSuite, context, aLogInfoEvents);
}
static void CheckSubscriptionHandlerCountersStartAtZeroTwoDifferentImportancesProd(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
const bool aLogInfoEvents = true;
InitializeEventLoggingWithPersistedCounters(context, 0, nl::Weave::Profiles::DataManagement::Production);
CheckSubscriptionHandlerHelper(inSuite, context, aLogInfoEvents);
}
static void CheckSubscriptionHandlerCountersStartAtNonZeroProd(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
const bool aLogInfoEvents = false;
InitializeEventLoggingWithPersistedCounters(context, sEventIdCounterEpoch, nl::Weave::Profiles::DataManagement::Production);
CheckSubscriptionHandlerHelper(inSuite, context, aLogInfoEvents);
}
static void CheckSubscriptionHandlerCountersStartAtNonZeroTwoDifferentImportancesProd(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
const bool aLogInfoEvents = true;
InitializeEventLoggingWithPersistedCounters(context, sEventIdCounterEpoch, nl::Weave::Profiles::DataManagement::Production);
CheckSubscriptionHandlerHelper(inSuite, context, aLogInfoEvents);
}
static void CheckSubscriptionHandlerCountersStartAtZeroInfo(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
const bool aLogInfoEvents = false;
InitializeEventLoggingWithPersistedCounters(context, 0, nl::Weave::Profiles::DataManagement::Info);
CheckSubscriptionHandlerHelper(inSuite, context, aLogInfoEvents);
}
static void CheckSubscriptionHandlerCountersStartAtZeroTwoDifferentImportancesInfo(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
const bool aLogInfoEvents = true;
InitializeEventLoggingWithPersistedCounters(context, 0, nl::Weave::Profiles::DataManagement::Info);
CheckSubscriptionHandlerHelper(inSuite, context, aLogInfoEvents);
}
static void CheckSubscriptionHandlerCountersStartAtNonZeroInfo(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
const bool aLogInfoEvents = false;
InitializeEventLoggingWithPersistedCounters(context, sEventIdCounterEpoch, nl::Weave::Profiles::DataManagement::Info);
CheckSubscriptionHandlerHelper(inSuite, context, aLogInfoEvents);
}
static void CheckSubscriptionHandlerCountersStartAtNonZeroTwoDifferentImportancesInfo(nlTestSuite * inSuite, void * inContext)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
const bool aLogInfoEvents = true;
InitializeEventLoggingWithPersistedCounters(context, sEventIdCounterEpoch, nl::Weave::Profiles::DataManagement::Info);
CheckSubscriptionHandlerHelper(inSuite, context, aLogInfoEvents);
}
#if WEAVE_CONFIG_EVENT_LOGGING_EXTERNAL_EVENT_SUPPORT
static void CheckExternalEvents(nlTestSuite * inSuite, void * inContext)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
TLVWriter testWriter;
TLVReader testReader;
event_id_t eid_in, eid = 0;
int i;
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
InitializeEventLogging(context);
for (i = 1; i < 10; i++)
{
eid_in = nl::Weave::Profiles::DataManagement::LogFreeform(nl::Weave::Profiles::DataManagement::Production,
"Freeform entry %d", i);
}
// register callback
err = LogMockExternalEvents(10, 1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
for (i = 0; i < 10; i++)
{
eid_in = nl::Weave::Profiles::DataManagement::LogFreeform(nl::Weave::Profiles::DataManagement::Production,
"Freeform entry %d", i + 10);
}
// positive case where events lie within event range in importance buffer
// retrieve all events in order
// we make two calls to FetchEventsSince. The first one grabs all
// the initial batch of 10 internally-stored events, and all the
// external events. The second one grabs the remaining 10
// internally stored events.
for (int j = 1; j < 3; j++)
{
testWriter.Init(gLargeMemoryBackingStore, sizeof(gLargeMemoryBackingStore));
err = nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance().FetchEventsSince(
testWriter, nl::Weave::Profiles::DataManagement::Production, eid);
NL_TEST_ASSERT(inSuite, eid == 10 * (static_cast<event_id_t>(j) + 1));
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV || err == WEAVE_NO_ERROR);
if (context->mVerbose)
{
testReader.Init(gLargeMemoryBackingStore, testWriter.GetLengthWritten());
nl::Weave::TLV::Debug::Dump(testReader, SimpleDumpWriter);
}
}
// retrieve events starting in the middle of external events
eid = 14;
for (int x = 0; x < 2; x++)
{
testWriter.Init(gLargeMemoryBackingStore, sizeof(gLargeMemoryBackingStore));
err = nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance().FetchEventsSince(
testWriter, nl::Weave::Profiles::DataManagement::Production, eid);
NL_TEST_ASSERT(inSuite, eid == 10 * (static_cast<event_id_t>(x) + 2));
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV || err == WEAVE_NO_ERROR);
if (context->mVerbose)
{
testReader.Init(gLargeMemoryBackingStore, testWriter.GetLengthWritten());
nl::Weave::TLV::Debug::Dump(testReader, SimpleDumpWriter);
}
}
// log many events so no longer trying to fetch external events
for (i = 0; i < 100; i++)
{
eid_in = nl::Weave::Profiles::DataManagement::LogFreeform(nl::Weave::Profiles::DataManagement::Production,
"Freeform entry %d", i);
}
{
utc_timestamp_t utc_tmp;
timestamp_t time_tmp;
event_id_t eid_tmp;
eid = 0;
testWriter.Init(gLargeMemoryBackingStore, sizeof(gLargeMemoryBackingStore));
err = nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance().FetchEventsSince(
testWriter, nl::Weave::Profiles::DataManagement::Production, eid);
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV);
NL_TEST_ASSERT(inSuite, eid == eid_in + 1);
testReader.Init(gLargeMemoryBackingStore, testWriter.GetLengthWritten());
ReadFirstEventHeader(testReader, time_tmp, utc_tmp, eid_tmp);
NL_TEST_ASSERT(inSuite, eid_tmp >= 20);
}
}
static void CheckExternalEventsMultipleCallbacks(nlTestSuite * inSuite, void * inContext)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
TLVWriter testWriter;
TLVReader testReader;
event_id_t eid = 0;
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
event_id_t endingEIDs[] = { 11, 31, 41 };
InitializeEventLogging(context);
err = LogMockExternalEvents(10, 1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
for (int i = 0; i < 10; i++)
{
(void) nl::Weave::Profiles::DataManagement::LogFreeform(nl::Weave::Profiles::DataManagement::Production,
"Freeform entry %d", i);
}
err = LogMockExternalEvents(10, 2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Note: with the current external event logging scheme, the
// number of externally stored event segments is only limited by
// the available buffering space.
err = LogMockExternalEvents(10, 3);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
ClearMockExternalEvents(1);
// even after clearing the first callback, we should receive 3 separate error codes.
for (int j = 0; j < 3; j++)
{
testWriter.Init(gLargeMemoryBackingStore, sizeof(gLargeMemoryBackingStore));
err = nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance().FetchEventsSince(
testWriter, nl::Weave::Profiles::DataManagement::Production, eid);
NL_TEST_ASSERT(inSuite, eid == endingEIDs[j]);
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV || err == WEAVE_NO_ERROR);
if (context->mVerbose)
{
testReader.Init(gLargeMemoryBackingStore, testWriter.GetLengthWritten());
nl::Weave::TLV::Debug::Dump(testReader, SimpleDumpWriter);
}
}
}
static bool SkipEvenEvents(event_id_t aEventId)
{
return aEventId & 1;
}
static void CheckSkipExternalEvents(nlTestSuite * inSuite, void * inContext)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
TLVWriter testWriter;
TLVReader testReader;
event_id_t eid_before, eid_after, eid = 0;
int i;
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
InitializeEventLogging(context);
SetShouldBlitCallback(SkipEvenEvents);
for (i = 0; i < 10; i++)
{
eid_before = nl::Weave::Profiles::DataManagement::LogFreeform(nl::Weave::Profiles::DataManagement::Production,
"Freeform entry %d", i);
}
// register callback
err = LogMockExternalEvents(10, 0);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
for (i = 0; i < 10; i++)
{
eid_after = nl::Weave::Profiles::DataManagement::LogFreeform(nl::Weave::Profiles::DataManagement::Production,
"Freeform entry %d", i + 10);
}
// Validate event skipping by reading back what was written.
{
utc_timestamp_t utc_tmp;
timestamp_t time_tmp;
event_id_t eid_tmp;
unsigned count;
// Fetch gets initial back of free form events and all external events.
// Fetching stops after an external events block is complete.
eid = 1;
testWriter.Init(gLargeMemoryBackingStore, sizeof(gLargeMemoryBackingStore));
err = nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance().FetchEventsSince(
testWriter, nl::Weave::Profiles::DataManagement::Production, eid);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, eid == eid_before + 11); // Free form events plus external events
testReader.Init(gLargeMemoryBackingStore, testWriter.GetLengthWritten());
count = 0;
while (err == WEAVE_NO_ERROR)
{
err = ReadFirstEventHeader(testReader, time_tmp, utc_tmp, eid_tmp);
count++; // Also incremented on error
}
NL_TEST_ASSERT(inSuite, count == 16); // Initial free form events plus half of external ones
// Fetch second block of free form events.
eid = 21;
testWriter.Init(gLargeMemoryBackingStore, sizeof(gLargeMemoryBackingStore));
err = nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance().FetchEventsSince(
testWriter, nl::Weave::Profiles::DataManagement::Production, eid);
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV);
NL_TEST_ASSERT(inSuite, eid == eid_after + 1);
testReader.Init(gLargeMemoryBackingStore, testWriter.GetLengthWritten());
err = WEAVE_NO_ERROR;
count = 0;
while (err == WEAVE_NO_ERROR)
{
err = ReadFirstEventHeader(testReader, time_tmp, utc_tmp, eid_tmp);
count++; // Also incremented on error
}
NL_TEST_ASSERT(inSuite, count == 11); // Following free form events
}
SetShouldBlitCallback(NULL);
}
static void RegressionWatchdogBug(nlTestSuite * inSuite, void * inContext)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
TLVWriter testWriter;
// TLVReader testReader;
event_id_t eid = 0;
::nl::Weave::Profiles::DataManagement::TestSubscriptionHandler subHandler;
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
nl::Weave::Profiles::DataManagement::LoggingManagement & logger =
nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance();
nl::Weave::Profiles::DataManagement::ImportanceType importance;
InitializeEventLogging(context);
err = LogMockExternalEvents(10, 1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = LogMockExternalEvents(10, 2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
ClearMockExternalEvents(1);
ClearMockExternalEvents(2);
eid = nl::Weave::Profiles::DataManagement::LogFreeform(nl::Weave::Profiles::DataManagement::Production, "Freeform entry");
NL_TEST_ASSERT(inSuite, eid == 21);
testWriter.Init(gLargeMemoryBackingStore, sizeof(gLargeMemoryBackingStore));
subHandler.SetEventLogEndpoint(logger);
importance = subHandler.FindNextImportanceForTransfer();
NL_TEST_ASSERT(inSuite, importance == nl::Weave::Profiles::DataManagement::Production);
while (importance != nl::Weave::Profiles::DataManagement::kImportanceType_Invalid)
{
err = logger.FetchEventsSince(testWriter, importance, subHandler.GetVendedEvent(importance));
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV || err == WEAVE_NO_ERROR);
importance = subHandler.FindNextImportanceForTransfer();
}
// Verify that events are retrieved.
NL_TEST_ASSERT(inSuite, subHandler.VerifyTraversingImportance());
NL_TEST_ASSERT(inSuite, subHandler.CheckEventUpToDate(logger));
}
static void RegressionWatchdogBug_EventRemoval(nlTestSuite * inSuite, void * inContext)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
TLVWriter testWriter;
// TLVReader testReader;
event_id_t eid = 0;
timestamp_t now;
::nl::Weave::Profiles::DataManagement::TestSubscriptionHandler subHandler;
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
nl::Weave::Profiles::DataManagement::LoggingManagement & logger =
nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance();
nl::Weave::Profiles::DataManagement::ImportanceType importance;
InitializeEventLogging(context);
err = LogMockDebugExternalEvents(10, 1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = LogMockDebugExternalEvents(10, 2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
eid = nl::Weave::Profiles::DataManagement::LogFreeform(nl::Weave::Profiles::DataManagement::Debug, "Freeform entry");
NL_TEST_ASSERT(inSuite, eid == 21);
eid = nl::Weave::Profiles::DataManagement::LogFreeform(nl::Weave::Profiles::DataManagement::Debug, "Freeform entry");
NL_TEST_ASSERT(inSuite, eid == 22);
eid = nl::Weave::Profiles::DataManagement::LogFreeform(nl::Weave::Profiles::DataManagement::Debug, "Freeform entry");
NL_TEST_ASSERT(inSuite, eid == 23);
now = System::Layer::GetClock_MonotonicMS();
for (size_t counter = 0; counter < 100; counter++)
{
eid = FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now, "Freeform entry %d", counter);
NL_TEST_ASSERT(inSuite, eid == counter + 1);
now += 10;
}
testWriter.Init(gLargeMemoryBackingStore, sizeof(gLargeMemoryBackingStore));
subHandler.SetEventLogEndpoint(logger);
importance = subHandler.FindNextImportanceForTransfer();
NL_TEST_ASSERT(inSuite, importance == nl::Weave::Profiles::DataManagement::Production);
while (importance != nl::Weave::Profiles::DataManagement::kImportanceType_Invalid)
{
err = logger.FetchEventsSince(testWriter, importance, subHandler.GetVendedEvent(importance));
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV || err == WEAVE_NO_ERROR);
importance = subHandler.FindNextImportanceForTransfer();
}
// Verify that events are retrieved.
NL_TEST_ASSERT(inSuite, subHandler.VerifyTraversingImportance());
NL_TEST_ASSERT(inSuite, subHandler.CheckEventUpToDate(logger));
}
static void RegressionWatchdogBug_ExternalEventState(nlTestSuite * inSuite, void * inContext)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
TLVWriter testWriter;
// TLVReader testReader;
event_id_t eid = 0;
timestamp_t now;
::nl::Weave::Profiles::DataManagement::TestSubscriptionHandler subHandler;
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
nl::Weave::Profiles::DataManagement::LoggingManagement & logger =
nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance();
nl::Weave::Profiles::DataManagement::ImportanceType importance;
InitializeEventLogging(context);
err = LogMockExternalEvents(10, 1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = LogMockExternalEvents(10, 2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
eid = nl::Weave::Profiles::DataManagement::LogFreeform(nl::Weave::Profiles::DataManagement::Production, "F");
NL_TEST_ASSERT(inSuite, eid == 21);
ClearMockExternalEvents(1);
ClearMockExternalEvents(2);
now = System::Layer::GetClock_MonotonicMS();
for (size_t counter = 0; counter < 100; counter++)
{
eid = FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now, "Freeform entry %d", counter);
NL_TEST_ASSERT(inSuite, eid == (counter + 22));
now += 10;
}
testWriter.Init(gLargeMemoryBackingStore, sizeof(gLargeMemoryBackingStore));
subHandler.SetEventLogEndpoint(logger);
importance = subHandler.FindNextImportanceForTransfer();
NL_TEST_ASSERT(inSuite, importance == nl::Weave::Profiles::DataManagement::Production);
while (importance != nl::Weave::Profiles::DataManagement::kImportanceType_Invalid)
{
err = logger.FetchEventsSince(testWriter, importance, subHandler.GetVendedEvent(importance));
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV || err == WEAVE_NO_ERROR);
importance = subHandler.FindNextImportanceForTransfer();
}
// Verify that events are retrieved.
NL_TEST_ASSERT(inSuite, subHandler.VerifyTraversingImportance());
NL_TEST_ASSERT(inSuite, subHandler.CheckEventUpToDate(logger));
}
static void CheckExternalEventsMultipleFetches(nlTestSuite * inSuite, void * inContext)
{
uint8_t smallMemoryBackingStore[256];
WEAVE_ERROR err = WEAVE_NO_ERROR;
TLVWriter testWriter;
TLVReader testReader;
event_id_t fetchId = 0;
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
InitializeEventLogging(context);
err = LogMockExternalEvents(10, 0);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
while ((fetchId <= 10) && (err == WEAVE_NO_ERROR))
{
timestamp_t time_tmp;
utc_timestamp_t utc_tmp = 0;
event_id_t eid_tmp = 0;
testWriter.Init(smallMemoryBackingStore, sizeof(smallMemoryBackingStore));
err = LoggingManagement::GetInstance().FetchEventsSince(testWriter, Production, fetchId);
if (fetchId <= 10)
{
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_BUFFER_TOO_SMALL);
}
else
{
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
if (err == WEAVE_ERROR_BUFFER_TOO_SMALL)
{
err = WEAVE_NO_ERROR;
}
testReader.Init(smallMemoryBackingStore, testWriter.GetLengthWritten());
ReadFirstEventHeader(testReader, time_tmp, utc_tmp, eid_tmp);
// eid_tmp is unsigned and so always positive
NL_TEST_ASSERT(inSuite, eid_tmp < fetchId);
NL_TEST_ASSERT(inSuite, utc_tmp != 0);
}
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
static event_id_t sLastExpectedExternalEventID;
static bool sExternalEventNotificationPassed;
static bool sExternalEventNotificationCalled;
static bool sExternalEventEvictionCalled;
static void ResetExternalEventDeliveryState(void)
{
sLastExpectedExternalEventID = 0;
sExternalEventNotificationCalled = false;
sExternalEventNotificationPassed = false;
sExternalEventEvictionCalled = false;
}
static void MockExternalEventsDelivered(ExternalEvents * inEv, event_id_t inLastDeliveredEventID, uint64_t inRecipientNodeID)
{
sExternalEventNotificationCalled = true;
sExternalEventNotificationPassed = (inEv->mLastEventID == sLastExpectedExternalEventID);
}
static WEAVE_ERROR MockExternalEventsFetch(EventLoadOutContext * aContext)
{
return WEAVE_NO_ERROR;
}
static void MockExternalEventsEvicted(ExternalEvents * inEv)
{
sExternalEventEvictionCalled = true;
}
static void CheckExternalEventNotifyDelivered(nlTestSuite * inSuite, void * inContext)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
event_id_t eid_p, eid_d;
event_id_t external_eid_production, external_eid_debug;
size_t cnt = 1;
timestamp_t now;
::nl::Weave::Profiles::DataManagement::TestSubscriptionHandler subHandler;
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
nl::Weave::Profiles::DataManagement::LoggingManagement & logger =
nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance();
InitializeEventLogging(context);
// Prime the event buffers with some internal events
now = System::Layer::GetClock_MonotonicMS();
eid_p = FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now, "Freeform entry %d", cnt);
eid_d = FastLogFreeform(nl::Weave::Profiles::DataManagement::Debug, now, "Freeform entry %d", cnt);
// Register external events with production and debug importance
err = logger.RegisterEventCallbackForImportance(nl::Weave::Profiles::DataManagement::Production, MockExternalEventsFetch,
MockExternalEventsDelivered, 10, &external_eid_production);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, external_eid_production == (eid_p + 10));
err = logger.RegisterEventCallbackForImportance(nl::Weave::Profiles::DataManagement::Debug, MockExternalEventsFetch,
MockExternalEventsDelivered, 10, &external_eid_debug);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, external_eid_debug == (eid_d + 10));
// Verify that we do not get a notification for an event that
// comes before the external production event
ResetExternalEventDeliveryState();
sLastExpectedExternalEventID = external_eid_production;
logger.NotifyEventsDelivered(nl::Weave::Profiles::DataManagement::Production, eid_p, 0ULL);
NL_TEST_ASSERT(inSuite, sExternalEventNotificationCalled == false);
// Verify we do get called for the first and last event in the external event range
logger.NotifyEventsDelivered(nl::Weave::Profiles::DataManagement::Production, eid_p + 1, 0ULL);
NL_TEST_ASSERT(inSuite, sExternalEventNotificationCalled);
NL_TEST_ASSERT(inSuite, sExternalEventNotificationPassed);
ResetExternalEventDeliveryState();
sLastExpectedExternalEventID = external_eid_production;
logger.NotifyEventsDelivered(nl::Weave::Profiles::DataManagement::Production, external_eid_production, 0ULL);
NL_TEST_ASSERT(inSuite, sExternalEventNotificationCalled);
NL_TEST_ASSERT(inSuite, sExternalEventNotificationPassed);
// Verify that we get called when the event handler is registered and that we do not get called when event handler is
// unregistered. First, reset the checks notification state, and check we get a notification
ResetExternalEventDeliveryState();
sLastExpectedExternalEventID = external_eid_debug;
logger.NotifyEventsDelivered(nl::Weave::Profiles::DataManagement::Debug, external_eid_debug, 0ULL);
NL_TEST_ASSERT(inSuite, sExternalEventNotificationCalled);
NL_TEST_ASSERT(inSuite, sExternalEventNotificationPassed);
// Next, reset the delivery state, unregister the event handler and verify we do not get notified
ResetExternalEventDeliveryState();
logger.UnregisterEventCallbackForImportance(nl::Weave::Profiles::DataManagement::Debug, external_eid_debug);
logger.NotifyEventsDelivered(nl::Weave::Profiles::DataManagement::Debug, external_eid_debug, 0ULL);
NL_TEST_ASSERT(inSuite, sExternalEventNotificationCalled == false);
}
static void CheckExternalEventNotifyEvicted(nlTestSuite * inSuite, void * inContext)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
event_id_t eid, eid_prev;
event_id_t external_eid_production;
size_t counter = 0;
timestamp_t now;
::nl::Weave::Profiles::DataManagement::TestSubscriptionHandler subHandler;
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
nl::Weave::Profiles::DataManagement::LoggingManagement & logger =
nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance();
InitializeEventLogging(context);
// Prime the event buffers with some internal events
now = System::Layer::GetClock_MonotonicMS();
eid = FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now, "Freeform entry %d", counter);
now += 10;
counter++;
// Register external events with production importance
err = logger.RegisterEventCallbackForImportance(nl::Weave::Profiles::DataManagement::Production, MockExternalEventsFetch,
MockExternalEventsDelivered, MockExternalEventsEvicted, 10,
&external_eid_production);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, external_eid_production == (eid + 10));
// Force an eviction
eid_prev = FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now, "Freeform entry %d", counter++);
now += 10;
for (; counter < 103; counter++)
{
// Sample production events, spaced 10 milliseconds apart
eid = FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now, "Freeform entry %d", counter);
now += 10;
NL_TEST_ASSERT(inSuite, eid > 0);
NL_TEST_ASSERT(inSuite, eid == (eid_prev + 1));
eid_prev = eid;
}
NL_TEST_ASSERT(inSuite, sExternalEventEvictionCalled == true);
// Clean up
logger.UnregisterEventCallbackForImportance(nl::Weave::Profiles::DataManagement::Production, external_eid_production);
}
#endif // WEAVE_CONFIG_EVENT_LOGGING_EXTERNAL_EVENT_SUPPORT
static void CheckShutdownLogic(nlTestSuite * inSuite, void * inContext)
{
event_id_t eid = 0;
int counter = 1;
timestamp_t now;
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
InitializeEventLogging(context);
DestroyEventLogging(context);
now = System::Layer::GetClock_MonotonicMS();
eid = FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now, "Freeform entry %d", counter);
NL_TEST_ASSERT(inSuite, eid == 0);
}
static WEAVE_ERROR
BuildSubscribeRequest(nl::Weave::TLV::TLVWriter & writer,
const nl::Weave::Profiles::DataManagement::SubscriptionClient::OutEventParam & outSubscribeParam)
{
WEAVE_ERROR err;
SubscribeRequest::Builder request;
err = request.Init(&writer);
SuccessOrExit(err);
{
PathList::Builder & pathList = request.CreatePathListBuilder();
pathList.EndOfPathList();
SuccessOrExit(err = pathList.GetError());
}
{
VersionList::Builder & versionList = request.CreateVersionListBuilder();
versionList.EndOfVersionList();
SuccessOrExit(err = versionList.GetError());
}
if (outSubscribeParam.mSubscribeRequestPrepareNeeded.mNeedAllEvents)
{
request.SubscribeToAllEvents(true);
if (outSubscribeParam.mSubscribeRequestPrepareNeeded.mLastObservedEventListSize > 0)
{
EventList::Builder & eventList = request.CreateLastObservedEventIdListBuilder();
for (size_t n = 0; n < outSubscribeParam.mSubscribeRequestPrepareNeeded.mLastObservedEventListSize; ++n)
{
Event::Builder & event = eventList.CreateEventBuilder();
event.SourceId(outSubscribeParam.mSubscribeRequestPrepareNeeded.mLastObservedEventList[n].mSourceId)
.Importance(outSubscribeParam.mSubscribeRequestPrepareNeeded.mLastObservedEventList[n].mImportance)
.EventId(outSubscribeParam.mSubscribeRequestPrepareNeeded.mLastObservedEventList[n].mEventId)
.EndOfEvent();
SuccessOrExit(err = event.GetError());
}
eventList.EndOfEventList();
SuccessOrExit(err = eventList.GetError());
}
}
request.EndOfRequest();
SuccessOrExit(err = request.GetError());
err = writer.Finalize();
SuccessOrExit(err);
exit:
return err;
}
static void MockSubscribeRequest(nlTestSuite * inSuite,
::nl::Weave::Profiles::DataManagement::TestSubscriptionHandler & aSubHandler,
const nl::Weave::Profiles::DataManagement::SubscriptionClient::OutEventParam & outSubscribeParam)
{
WEAVE_ERROR err;
uint8_t backingStore[1024];
TLVWriter writer;
TLVReader reader;
SubscribeRequest::Parser request;
uint32_t rejectReasonProfileId = 0;
uint16_t rejectReasonStatusCode = 0;
writer.Init(backingStore, sizeof(backingStore));
err = BuildSubscribeRequest(writer, outSubscribeParam);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
reader.Init(backingStore, writer.GetLengthWritten());
err = reader.Next();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = request.Init(reader);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = aSubHandler.ParsePathVersionEventLists(request, rejectReasonProfileId, rejectReasonStatusCode);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
/*
* This test validates that if a peer specified X as the last observed event
* ID, the subscription handler publishes X+1 for the next event.
*/
static void CheckLastObservedEventId(nlTestSuite * inSuite, void * inContext)
{
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
event_id_t prod_eids[3];
event_id_t info_eids[3];
TestLoggingContext * context = static_cast<TestLoggingContext *>(inContext);
InitializeEventLogging(context);
// Mock 3 production events and 3 info events
timestamp_t now = System::Layer::GetClock_MonotonicMS();
for (int i = 0; i < 3; i++)
{
prod_eids[i] = FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now + i * 10, "Prod entry %d", i);
info_eids[i] = FastLogFreeform(nl::Weave::Profiles::DataManagement::Info, now + i * 10 + 5, "Info entry %d", i);
}
::nl::Weave::Profiles::DataManagement::TestSubscriptionHandler subHandler;
nl::Weave::Profiles::DataManagement::LoggingManagement & logger =
nl::Weave::Profiles::DataManagement::LoggingManagement::GetInstance();
subHandler.SetEventLogEndpoint(logger);
// Make sure we logged all events
CheckLogReadOut(inSuite, context, logger, nl::Weave::Profiles::DataManagement::Production, prod_eids[0], 3);
CheckLogReadOut(inSuite, context, logger, nl::Weave::Profiles::DataManagement::Info, info_eids[0], 3);
// We still have events to upload
NL_TEST_ASSERT(inSuite, subHandler.CheckEventUpToDate(logger) == false);
// No events have been observed so the next importance should be
// Production.
NL_TEST_ASSERT(inSuite, subHandler.FindNextImportanceForTransfer() == nl::Weave::Profiles::DataManagement::Production);
// Create a dummy exchange context so that SubscriptionHandler can verify
// the local node id when parsing the Last Observed Event List in the
// subscribe request.
nl::Weave::ExchangeContext ec;
ec.ExchangeMgr = static_cast<TestLoggingContext *>(inContext)->mExchangeMgr;
subHandler.SetExchangeContext(&ec);
// Mock Last Observed Event List
{
nl::Weave::Profiles::DataManagement::SubscriptionClient::OutEventParam outParam;
nl::Weave::Profiles::DataManagement::SubscriptionClient::LastObservedEvent lastObservedEventList[2];
// Production event
lastObservedEventList[0].mSourceId = kTestNodeId;
lastObservedEventList[0].mImportance = nl::Weave::Profiles::DataManagement::Production;
lastObservedEventList[0].mEventId = prod_eids[2];
// Info event
lastObservedEventList[1].mSourceId = kTestNodeId;
lastObservedEventList[1].mImportance = nl::Weave::Profiles::DataManagement::Info;
lastObservedEventList[1].mEventId = info_eids[1];
outParam.mSubscribeRequestPrepareNeeded.mNeedAllEvents = true;
outParam.mSubscribeRequestPrepareNeeded.mLastObservedEventList = lastObservedEventList;
outParam.mSubscribeRequestPrepareNeeded.mLastObservedEventListSize = ARRAY_SIZE(lastObservedEventList);
MockSubscribeRequest(inSuite, subHandler, outParam);
}
// We still have events to process
NL_TEST_ASSERT(inSuite, subHandler.CheckEventUpToDate(logger) == false);
// Since Production events were all observed, the next importance should be
// Info
NL_TEST_ASSERT(inSuite, subHandler.FindNextImportanceForTransfer() == nl::Weave::Profiles::DataManagement::Info);
// Make sure vended EIDs are what we expect
NL_TEST_ASSERT(inSuite, subHandler.GetVendedEvent(nl::Weave::Profiles::DataManagement::Production) == prod_eids[2] + 1);
NL_TEST_ASSERT(inSuite, subHandler.GetVendedEvent(nl::Weave::Profiles::DataManagement::Info) == info_eids[1] + 1);
// Now mock another subscribe request where all events are observed
{
nl::Weave::Profiles::DataManagement::SubscriptionClient::OutEventParam outParam;
nl::Weave::Profiles::DataManagement::SubscriptionClient::LastObservedEvent lastObservedEventList[2];
// Production event
lastObservedEventList[0].mSourceId = kTestNodeId;
lastObservedEventList[0].mImportance = nl::Weave::Profiles::DataManagement::Production;
lastObservedEventList[0].mEventId = prod_eids[2];
// Info event
lastObservedEventList[1].mSourceId = kTestNodeId;
lastObservedEventList[1].mImportance = nl::Weave::Profiles::DataManagement::Info;
lastObservedEventList[1].mEventId = info_eids[2];
outParam.mSubscribeRequestPrepareNeeded.mNeedAllEvents = true;
outParam.mSubscribeRequestPrepareNeeded.mLastObservedEventList = lastObservedEventList;
outParam.mSubscribeRequestPrepareNeeded.mLastObservedEventListSize = ARRAY_SIZE(lastObservedEventList);
MockSubscribeRequest(inSuite, subHandler, outParam);
}
// No events to process
NL_TEST_ASSERT(inSuite, subHandler.CheckEventUpToDate(logger) == true);
NL_TEST_ASSERT(inSuite,
subHandler.FindNextImportanceForTransfer() == nl::Weave::Profiles::DataManagement::kImportanceType_Invalid);
// Log a new event and confirm that there's more events to process
(void) FastLogFreeform(nl::Weave::Profiles::DataManagement::Production, now + 1000, "Last Prod entry");
subHandler.SetEventLogEndpoint(logger);
NL_TEST_ASSERT(inSuite, subHandler.CheckEventUpToDate(logger) == false);
NL_TEST_ASSERT(inSuite, subHandler.FindNextImportanceForTransfer() == nl::Weave::Profiles::DataManagement::Production);
DestroyEventLogging(context);
}
// Test Suite
/**
* Test Suite that lists all the test functions.
*/
static const nlTest sTests[] = {
NL_TEST_DEF("Simple Event Log Test", CheckLogEventBasics),
NL_TEST_DEF("Simple Freeform Log Test", CheckLogFreeform),
NL_TEST_DEF("Simple Pre-formatted Log Test", CheckLogPreformed),
NL_TEST_DEF("Schema Generated Log Test", CheckSchemaGeneratedLogging),
NL_TEST_DEF("Check Byte String Field Type", CheckByteStringFieldType),
NL_TEST_DEF("Check Byte String Array", CheckByteStringArray),
NL_TEST_DEF("Check Log eviction", CheckEvict),
NL_TEST_DEF("Check Fetch Events", CheckFetchEvents),
NL_TEST_DEF("Check Large Events", CheckLargeEvents),
NL_TEST_DEF("Check Fetch Event Timestamps", CheckFetchTimestamps),
NL_TEST_DEF("Basic Deserialization Test", CheckBasicEventDeserialization),
NL_TEST_DEF("Complex Deserialization Test", CheckComplexEventDeserialization),
NL_TEST_DEF("Empty Array Deserialization Test", CheckEmptyArrayEventDeserialization),
NL_TEST_DEF("Simple Nullable Fields Test", CheckNullableFieldsSimple),
NL_TEST_DEF("Complex Nullable Fields Test", CheckNullableFieldsComplex),
NL_TEST_DEF("Check Deserializing an Event from a Newer Version", CheckDeserializingNewerVersion),
NL_TEST_DEF("Check Deserializing an Event from an Older Version", CheckDeserializingOlderVersion),
NL_TEST_DEF("Check Deserializing an Event from a Newer Version with Nullables", CheckDeserializingNewerVersionNullable),
NL_TEST_DEF("Check Deserializing an Event from an Older Version with Nullables", CheckDeserializingOlderVersionNullable),
NL_TEST_DEF("Subscription Handler accounting", CheckSubscriptionHandler),
NL_TEST_DEF("Subscription Handler accounting, PersistedCounters start at zero, same importances, Production global importance",
CheckSubscriptionHandlerCountersStartAtZeroProd),
NL_TEST_DEF(
"Subscription Handler accounting, PersistedCounters start at zero, two different importances, Production global importance",
CheckSubscriptionHandlerCountersStartAtZeroTwoDifferentImportancesProd),
NL_TEST_DEF(
"Subscription Handler accounting, PersistedCounters start at non-zero, same importances, Production global importance",
CheckSubscriptionHandlerCountersStartAtNonZeroProd),
NL_TEST_DEF("Subscription Handler accounting, PersistedCounters start at non-zero, two different importances, Production "
"global importance",
CheckSubscriptionHandlerCountersStartAtNonZeroTwoDifferentImportancesProd),
NL_TEST_DEF("Subscription Handler accounting, PersistedCounters start at zero, same importances, Info global importance",
CheckSubscriptionHandlerCountersStartAtZeroInfo),
NL_TEST_DEF(
"Subscription Handler accounting, PersistedCounters start at zero, two different importances, Info global importance",
CheckSubscriptionHandlerCountersStartAtZeroTwoDifferentImportancesInfo),
NL_TEST_DEF("Subscription Handler accounting, PersistedCounters start at non-zero, same importances, Info global importance",
CheckSubscriptionHandlerCountersStartAtNonZeroInfo),
NL_TEST_DEF(
"Subscription Handler accounting, PersistedCounters start at non-zero, two different importances, Info global importance",
CheckSubscriptionHandlerCountersStartAtNonZeroTwoDifferentImportancesInfo),
#if WEAVE_CONFIG_EVENT_LOGGING_EXTERNAL_EVENT_SUPPORT
NL_TEST_DEF("Check External Events Basic", CheckExternalEvents),
NL_TEST_DEF("Check External Events Multiple Callbacks", CheckExternalEventsMultipleCallbacks),
NL_TEST_DEF("Check External Events Multiple Fetches", CheckExternalEventsMultipleFetches),
NL_TEST_DEF("Check External Events Skip", CheckSkipExternalEvents),
NL_TEST_DEF("Check Drop Events", CheckDropEvents),
NL_TEST_DEF("Regression: watchdog bug", RegressionWatchdogBug),
NL_TEST_DEF("Regression: external event cleanup", RegressionWatchdogBug_EventRemoval),
NL_TEST_DEF("Regression: external event, external clear call", RegressionWatchdogBug_ExternalEventState),
NL_TEST_DEF("Check External Event delivery notification", CheckExternalEventNotifyDelivered),
#endif
NL_TEST_DEF("Check Shutdown Logic", CheckShutdownLogic),
NL_TEST_DEF("Check WDM offload trigger", CheckWDMOffloadTrigger),
NL_TEST_DEF("Check version 1 data schema compatibility encoding + decoding", CheckVersion1DataCompatibility),
NL_TEST_DEF("Check forward data compatibility encoding + decoding", CheckForwardDataCompatibility),
NL_TEST_DEF("Check data incompatible encoding + decoding", CheckDataIncompatibility),
NL_TEST_DEF("Check Gap detection", CheckGapDetection),
NL_TEST_DEF("Check Drop Overlapping Event Id Ranges", CheckDropOverlap),
NL_TEST_DEF("Check Last Observed Event Id", CheckLastObservedEventId),
NL_TEST_DEF("Check External Event eviction notification", CheckExternalEventNotifyEvicted),
NL_TEST_SENTINEL()
};
int main(int argc, char * argv[])
{
MockPlatform::gMockPlatformClocks.GetClock_RealTime = Private::GetClock_RealTime;
MockPlatform::gMockPlatformClocks.SetClock_RealTime = Private::SetClock_RealTime;
if (!ParseArgsFromEnvVar(TOOL_NAME, TOOL_OPTIONS_ENV_VAR_NAME, gToolOptionSets, NULL, true) ||
!ParseArgs(TOOL_NAME, argc, argv, gToolOptionSets))
{
exit(EXIT_FAILURE);
}
nlTestSuite theSuite = { "weave-event-log", &sTests[0], TestSetup, TestTeardown };
gTestLoggingContext.mReinitializeBDXUpload = true;
// Generate machine-readable, comma-separated value (CSV) output.
nl_test_set_output_style(OUTPUT_CSV);
// Run test suit against one context
nlTestRunner(&theSuite, &gTestLoggingContext);
return nlTestRunnerStats(&theSuite);
}
bool HandleOption(const char * progName, OptionSet * optSet, int id, const char * name, const char * arg)
{
switch (id)
{
case 't':
gBDXContext.mUseTCP = true;
break;
case 'u':
gBDXContext.mUseTCP = false;
break;
case 'D':
gBDXContext.DestIPAddrStr = arg;
gTestLoggingContext.bdx = true;
break;
case 'p':
if (!ParseInt(arg, gBDXContext.DestNodeId))
{
PrintArgError("%s: Invalid value specified for destination node id: %s\n", progName, arg);
return false;
}
gTestLoggingContext.bdx = true;
break;
case 'd':
gTestLoggingContext.mVerbose = true;
break;
case 's':
if (!ParseInt(arg, gBDXContext.mStartingBlock))
{
PrintArgError("%s: Invalid value specified for start block: %s\n", progName, arg);
return false;
}
break;
default:
PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
return false;
}
return true;
}
static void PrepareBinding(TestLoggingContext * context)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
Binding * binding = NULL;
if (!context->mBinding)
{
binding = context->mExchangeMgr->NewBinding(HandleBindingEvent, context);
if (binding == NULL)
{
printf("NewBinding failed\n");
return;
}
Binding::Configuration bindingConfig =
binding->BeginConfiguration().Target_NodeId(gBDXContext.DestNodeId).Transport_UDP().Security_None();
if (gBDXContext.DestIPAddrStr != NULL && nl::Inet::IPAddress::FromString(gBDXContext.DestIPAddrStr, gBDXContext.DestIPAddr))
{
bindingConfig.TargetAddress_IP(gBDXContext.DestIPAddr);
err = bindingConfig.PrepareBinding();
if (err != WEAVE_NO_ERROR)
{
printf("PrepareBinding failed\n");
return;
}
}
context->mBinding = binding;
}
}
static WEAVE_ERROR InitSubscriptionClient(TestLoggingContext * context)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
if (!context->mSubClient)
{
err = SubscriptionEngine::GetInstance()->NewClient(&context->mSubClient, context->mBinding, NULL, NULL, NULL, 0);
}
return err;
}
static void HandleBindingEvent(void * const appState, const Binding::EventType event, const Binding::InEventParam & inParam,
Binding::OutEventParam & outParam)
{
TestLoggingContext * context = static_cast<TestLoggingContext *>(appState);
switch (event)
{
case Binding::kEvent_BindingReady:
gLogBDXUpload.StartUpload(context->mBinding);
break;
case Binding::kEvent_PrepareFailed:
printf("Binding Prepare failed\n");
break;
default:
Binding::DefaultEventHandler(appState, event, inParam, outParam);
break;
}
}
static void StartClientConnection(System::Layer * systemLayer, void * appState, System::Error error)
{
BDXContext * ctx = static_cast<BDXContext *>(appState);
printf("@@@ 0 StartClientConnection entering (Con: %p)\n", Con);
if (Con != NULL && Con->State == WeaveConnection::kState_Closed)
{
printf("@@@ 1 remove previous con (currently closed)\n");
Con->Close();
Con = NULL;
}
// Do nothing if a connect attempt is already in progress.
if (Con != NULL)
{
printf("@@@ 2 (Con: %p) previous Con likely hanging\n", Con);
return;
}
// TODO: move this to BDX logic
Con = MessageLayer.NewConnection();
if (Con == NULL)
{
printf("@@@ 3 WeaveConnection.Connect failed: no memory\n");
return;
}
printf("@@@ 3+ (Con: %p)\n", Con);
Con->OnConnectionComplete = HandleConnectionComplete;
Con->OnConnectionClosed = HandleConnectionClosed;
printf("@@@ 3++ (DestNodeId: %" PRIX64 ", DestIPAddrStr: %s)\n", ctx->DestNodeId, ctx->DestIPAddrStr);
WEAVE_ERROR err;
if (ctx->DestIPAddrStr)
{
IPAddress::FromString(ctx->DestIPAddrStr, ctx->DestIPAddr);
err = Con->Connect(ctx->DestNodeId, kWeaveAuthMode_Unauthenticated, ctx->DestIPAddr);
}
else // not specified, derive from NodeID
{
err = Con->Connect(ctx->DestNodeId);
}
if (err != WEAVE_NO_ERROR)
{
printf("@@@ 4 WeaveConnection.Connect failed: %X (%s)\n", err, ErrorStr(err));
Con->Close();
Con = NULL;
return;
}
ConnectTry++;
printf("@@@ 5 StartClientConnection exiting\n");
}
void HandleConnectionComplete(WeaveConnection * con, WEAVE_ERROR conErr)
{
printf("@@@ 1 HandleConnectionComplete entering\n");
WEAVE_ERROR err = WEAVE_NO_ERROR;
char ipAddrStr[64];
con->PeerAddr.ToString(ipAddrStr, sizeof(ipAddrStr));
if (conErr != WEAVE_NO_ERROR)
{
printf("Connection FAILED to node %" PRIX64 " (%s): %s\n", con->PeerNodeId, ipAddrStr, ErrorStr(conErr));
con->Close();
Con = NULL;
if (ConnectTry < ConnectMaxTry)
{
err = SystemLayer.StartTimer(ConnectInterval, StartClientConnection, &gBDXContext);
if (err != WEAVE_NO_ERROR)
{
printf("Inet.StartTimer failed\n");
exit(-1);
}
}
else
{
printf("Connection FAILED to node %" PRIX64 " (%s) after %d attempts\n", con->PeerNodeId, ipAddrStr, ConnectTry);
exit(-1);
}
ClientConEstablished = false;
return;
}
printf("Connection established to node %" PRIX64 " (%s)\n", con->PeerNodeId, ipAddrStr);
ClientConEstablished = true;
// Send the ReceiveInit or SendInit request
if (Con != NULL)
{
// Kick LogBDXUpload
}
else
{
printf("Non-connection Init Requests not supported!\n");
exit(-1);
}
if (err == WEAVE_NO_ERROR)
{
WaitingForBDXResp = true;
}
printf("@@@ 7 HandleConnectionComplete exiting\n");
}
void HandleConnectionClosed(WeaveConnection * con, WEAVE_ERROR conErr)
{
char ipAddrStr[64];
con->PeerAddr.ToString(ipAddrStr, sizeof(ipAddrStr));
if (conErr == WEAVE_NO_ERROR)
printf("Connection closed to node %" PRIX64 " (%s)\n", con->PeerNodeId, ipAddrStr);
else
printf("Connection ABORTED to node %" PRIX64 " (%s): %s\n", con->PeerNodeId, ipAddrStr, ErrorStr(conErr));
WaitingForBDXResp = false;
if (Listening)
con->Close();
else if (con == Con)
{
con->Close();
Con = NULL;
}
}