blob: afd46c9dd31d04e3d6f0077284df5cd176117b64 [file] [log] [blame]
/*
*
* Copyright (c) 2017 Nest Labs, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* 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 <nltest.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 "MockExternalEvents.h"
#include "ToolCommon.h"
#include "TestEventLoggingSchemaExamples.h"
#include <InetLayer/Inet.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/TestCommonTrait.h"
#include "TestPlatformTime.h"
using namespace nl::Weave::TLV;
using namespace nl::Weave::Profiles::DataManagement;
namespace Private {
static bool sSystemTimeValid = true;
static WEAVE_ERROR SetSystemTime(const nl::Weave::Profiles::Time::timesync_t timestamp_usec)
{
if (timestamp_usec != 0)
{
sSystemTimeValid = true;
}
else
{
sSystemTimeValid = false;
}
return WEAVE_NO_ERROR;
}
static WEAVE_ERROR GetSystemTimeMs(nl::Weave::Profiles::Time::timesync_t *p_timestamp_msec)
{
if (sSystemTimeValid)
{
*p_timestamp_msec = static_cast<nl::Weave::Profiles::Time::timesync_t>(nl::Weave::System::Timer::GetCurrentEpoch());
}
else
{
*p_timestamp_msec = 0;
}
return WEAVE_NO_ERROR;
}
} // 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;
}
} // Platform
} // WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current)
namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current) {
class TestSubscriptionHandler : public SubscriptionHandler
{
public:
TestSubscriptionHandler(void);
bool CheckEventUpToDate(nl::Weave::Profiles::DataManagement::LoggingManagement &logger);
nl::Weave::Profiles::DataManagement::ImportanceType FindNextImportanceForTransfer(void);
WEAVE_ERROR SetEventLogEndpoint(nl::Weave::Profiles::DataManagement::LoggingManagement &logger);
nl::Weave::Profiles::DataManagement::event_id_t & GetVendedEvent(nl::Weave::Profiles::DataManagement::ImportanceType inImportance);
bool VerifyTraversingImportance(void);
void SetActive(void) { mCurrentState = kState_Subscribing_Evaluating; }
void SetAborted(void) { mCurrentState = kState_Aborted; }
void SetEstablishedIdle(void) { mCurrentState = kState_SubscriptionEstablished_Idle; }
private:
/* important: this class must not add any members or declare virtual functions */
};
TestSubscriptionHandler::TestSubscriptionHandler(void)
{
InitAsFree();
}
bool TestSubscriptionHandler::CheckEventUpToDate(nl::Weave::Profiles::DataManagement::LoggingManagement &logger)
{
return SubscriptionHandler::CheckEventUpToDate(logger);
}
bool TestSubscriptionHandler::VerifyTraversingImportance(void)
{
return FindNextImportanceForTransfer() == nl::Weave::Profiles::DataManagement::kImportanceType_Invalid;
}
nl::Weave::Profiles::DataManagement::ImportanceType TestSubscriptionHandler::FindNextImportanceForTransfer(void)
{
return SubscriptionHandler::FindNextImportanceForTransfer();
}
WEAVE_ERROR TestSubscriptionHandler::SetEventLogEndpoint(nl::Weave::Profiles::DataManagement::LoggingManagement &logger)
{
return SubscriptionHandler::SetEventLogEndpoint(logger);
}
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;
}
} // WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current)
} // Profiles
} // Weave
} // 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;
}
}
const uint32_t gProfileList[] = { OpenCloseProfileID };
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;
const char *sCounterKeys[kImportanceType_Last] = {
sCritEventIdCounterStorageKey,
sProductionEventIdCounterStorageKey,
sInfoEventIdCounterStorageKey,
sDebugEventIdCounterStorageKey,
};
const uint32_t sCounterEpochs[kImportanceType_Last] = {
sEventIdCounterEpoch,
sEventIdCounterEpoch,
sEventIdCounterEpoch,
sEventIdCounterEpoch,
};
PersistedCounter *sCounterStorage[kImportanceType_Last] = {
&sCritEventIdCounter,
&sProductionEventIdCounter,
&sInfoEventIdCounter,
&sDebugEventIdCounter,
};
void InitializeEventLogging(TestLoggingContext *context)
{
size_t arraySizes[] = { sizeof(gDebugEventBuffer), sizeof(gInfoEventBuffer), sizeof(gProdEventBuffer) , sizeof(gCritEventBuffer) };
void *arrays[] = {
static_cast<void *>(&gDebugEventBuffer[0]),
static_cast<void *>(&gInfoEventBuffer[0]),
static_cast<void *>(&gProdEventBuffer[0]),
static_cast<void *>(&gCritEventBuffer[0]) };
nl::Weave::Profiles::DataManagement::LoggingManagement::CreateLoggingManagement(context->mExchangeMgr, sizeof(arrays)/sizeof(arrays[0]), &arraySizes[0], &arrays[0], NULL, NULL, NULL);
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)
{
size_t arraySizes[] = { sizeof(gDebugEventBuffer), sizeof(gInfoEventBuffer), sizeof(gProdEventBuffer), sizeof(gCritEventBuffer[0]) };
void *arrays[] = {
static_cast<void *>(&gDebugEventBuffer[0]),
static_cast<void *>(&gInfoEventBuffer[0]),
static_cast<void *>(&gProdEventBuffer[0]),
static_cast<void *>(&gCritEventBuffer[0]) };
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(arrays)/sizeof(arrays[0]), &arraySizes[0], &arrays[0], sCounterKeys, sCounterEpochs, sCounterStorage);
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
lwip_init();
#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 = static_cast<timestamp_t>(System::Timer::GetCurrentEpoch());
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::Timer::GetCurrentEpoch());
now = static_cast<timestamp_t>(test_start);
nl::Weave::Platform::Time::SetSystemTime(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)
{
nl::Weave::Platform::Time::SetSystemTime((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 - 1);
for (counter = 0; counter <= eid_prev; counter++)
{
TLVReader testReader;
TLVWriter testWriter;
utc_timestamp_t testUtcTimestamp = 0;
timestamp_t testTimestamp = 0;
event_id_t testEventID = 0;
event_id_read = counter;
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);
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) * 10);
}
else
#endif // WEAVE_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS
{
NL_TEST_ASSERT(inSuite, testTimestamp == static_cast<timestamp_t>(test_start) + (testEventID) * 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 == 0);
eid2 = nl::Weave::Profiles::DataManagement::LogEvent(
schema,
WriteLargeEvent,
static_cast<void*> (&payloadSize)
);
NL_TEST_ASSERT(inSuite, eid2 == 1);
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 == 2);
// 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);
}
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);
}
}
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 = 0;
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::TestCommonTrait::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);
InitializeEventLogging(context);
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);
}
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 = static_cast<timestamp_t>(System::Timer::GetCurrentEpoch());
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 = static_cast<timestamp_t>(System::Timer::GetCurrentEpoch());
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);
}
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 = 0; 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
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 == 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);
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);
err = LogMockExternalEvents(10, 3);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_NO_MEMORY);
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 == 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);
}
}
}
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 == 20);
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 == 20);
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);
now = static_cast<timestamp_t>(System::Timer::GetCurrentEpoch());
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);
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 == 20);
ClearMockExternalEvents(1);
ClearMockExternalEvents(2);
now = static_cast<timestamp_t>(System::Timer::GetCurrentEpoch());
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 + 21));
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 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 = static_cast<timestamp_t>(System::Timer::GetCurrentEpoch());
eid = FastLogFreeform(
nl::Weave::Profiles::DataManagement::Production,
now,
"Freeform entry %d", counter);
NL_TEST_ASSERT(inSuite, eid == 0);
}
//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),
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 Drop Events", CheckDropEvents),
NL_TEST_DEF("Check Shutdown Logic", CheckShutdownLogic),
NL_TEST_DEF("Check WDM offload trigger", CheckWDMOffloadTrigger),
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 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_SENTINEL()
};
int main(int argc, char *argv[])
{
nl::Weave::MockPlatform::gTestPlatformTimeFns.GetSystemTimeMs = Private::GetSystemTimeMs;
nl::Weave::MockPlatform::gTestPlatformTimeFns.SetSystemTime = Private::SetSystemTime;
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;
}
}