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