add update server test
diff --git a/src/lib/profiles/data-management/Current/SubscriptionClient.h b/src/lib/profiles/data-management/Current/SubscriptionClient.h
index 5e3b492..5e3fb05 100644
--- a/src/lib/profiles/data-management/Current/SubscriptionClient.h
+++ b/src/lib/profiles/data-management/Current/SubscriptionClient.h
@@ -403,6 +403,7 @@
     friend class TestTdm;
     friend class TestWdm;
     friend class WdmUpdateEncoderTest;
+    friend class WdmUpdateServerTest;
     friend class MockWdmSubscriptionInitiatorImpl;
     friend class TraitDataSink;
     friend class TraitSchemaEngine;
diff --git a/src/lib/profiles/data-management/Current/SubscriptionEngine.h b/src/lib/profiles/data-management/Current/SubscriptionEngine.h
index 1bc7e39..7ae183d 100644
--- a/src/lib/profiles/data-management/Current/SubscriptionEngine.h
+++ b/src/lib/profiles/data-management/Current/SubscriptionEngine.h
@@ -356,6 +356,7 @@
     friend class NotificationEngine;
     friend class TestTdm;
     friend class TestWdm;
+    friend class WdmUpdateServerTest;
 
     nl::Weave::WeaveExchangeManager * mExchangeMgr;
     void * mAppState;
diff --git a/src/lib/profiles/data-management/Current/TraitData.h b/src/lib/profiles/data-management/Current/TraitData.h
index 980740c..e99eefb 100644
--- a/src/lib/profiles/data-management/Current/TraitData.h
+++ b/src/lib/profiles/data-management/Current/TraitData.h
@@ -831,6 +831,7 @@
 private:
     friend class SubscriptionClient;
     friend class UpdateEncoder;
+    friend class WdmUpdateServerTest;
 
     /**
      * Checks if a DataVersion is more recent than the one currently stored in the Sink.
@@ -965,6 +966,7 @@
     const TraitSchemaEngine * mSchemaEngine;
 
 private:
+    friend class WdmUpdateServerTest;
     // Current version of the data in this source.
     uint64_t mVersion;
     // Tracks whether SetDirty was called within a Lock/Unlock 'session'
diff --git a/src/test-apps/Makefile.am b/src/test-apps/Makefile.am
index b613399..f636b31 100644
--- a/src/test-apps/Makefile.am
+++ b/src/test-apps/Makefile.am
@@ -364,6 +364,7 @@
     TestPathStore                                \
     TestWdmUpdateEncoder                         \
     TestWdmUpdateResponse                        \
+    TestWdmUpdateServer                          \
     $(NULL)
 
 if WEAVE_BUILD_WARM
@@ -479,6 +480,7 @@
     TestPathStore                                \
     TestWdmUpdateEncoder                         \
     TestWdmUpdateResponse                        \
+    TestWdmUpdateServer                          \
     $(NULL)
 endif
 
@@ -1263,6 +1265,22 @@
 TestWdmUpdateResponse_LDFLAGS                  = $(AM_CPPFLAGS)
 TestWdmUpdateResponse_LDADD                    = libWeaveTestCommon.a $(COMMON_LDADD)
 
+TestWdmUpdateServer_SOURCES                    = TestWdmUpdateServer.cpp \
+                                                 MockSinkTraits.cpp						\
+                                                 MockSourceTraits.cpp						\
+                                                 schema/nest/test/trait/TestATrait.cpp			\
+                                                 schema/nest/test/trait/TestBTrait.cpp			\
+                                                 schema/nest/test/trait/TestETrait.cpp			\
+                                                 schema/nest/test/trait/TestCommon.cpp \
+                                                 schema/weave/trait/security/BoltLockSettingsTrait.cpp	\
+                                                 schema/weave/trait/telemetry/NetworkWiFiTelemetryTrait.cpp	\
+                                                 MockWdmNodeOptions.cpp                   \
+                                                 TestPersistedStorageImplementation.cpp
+
+TestWdmUpdateServer_CPPFLAGS                         = $(AM_CPPFLAGS) -I$(top_srcdir)/src/test-apps/schema
+TestWdmUpdateServer_LDFLAGS                          = $(AM_CPPFLAGS)
+TestWdmUpdateServer_LDADD                            = libWeaveTestCommon.a $(COMMON_LDADD)
+
 TestFabricStateDelegate_SOURCES          = TestFabricStateDelegate.cpp TestPersistedStorageImplementation.cpp
 TestFabricStateDelegate_LDFLAGS          = $(AM_CPPFLAGS)
 TestFabricStateDelegate_LDADD            = libWeaveTestCommon.a $(COMMON_LDADD)
diff --git a/src/test-apps/MockSinkTraits.h b/src/test-apps/MockSinkTraits.h
index 1b1d506..9474eef 100644
--- a/src/test-apps/MockSinkTraits.h
+++ b/src/test-apps/MockSinkTraits.h
@@ -86,6 +86,7 @@
 namespace Profiles {
 namespace DataManagement_Current {
 class    WdmUpdateEncoderTest;
+class    WdmUpdateServerTest;
 } // namespace DataManagement_Current
 } // namespace Profiles
 } // namespace Weave
@@ -107,7 +108,7 @@
 
 private:
     friend class nl::Weave::Profiles::DataManagement_Current::WdmUpdateEncoderTest;
-
+    friend class nl::Weave::Profiles::DataManagement_Current::WdmUpdateServerTest;
     void SetNullifiedPath(nl::Weave::Profiles::DataManagement::PropertyPathHandle aHandle, bool isNull);
     WEAVE_ERROR SetData(nl::Weave::Profiles::DataManagement::PropertyPathHandle aHandle, nl::Weave::TLV::TLVReader &aReader, bool aIsNull) __OVERRIDE;
     WEAVE_ERROR SetLeafData(nl::Weave::Profiles::DataManagement::PropertyPathHandle aLeafHandle, nl::Weave::TLV::TLVReader &aReader) __OVERRIDE;
diff --git a/src/test-apps/MockSourceTraits.cpp b/src/test-apps/MockSourceTraits.cpp
index 2994a42..d0b5ea3 100644
--- a/src/test-apps/MockSourceTraits.cpp
+++ b/src/test-apps/MockSourceTraits.cpp
@@ -1626,8 +1626,12 @@
     }
 }
 
-TestBTraitDataSource::TestBTraitDataSource()
-    : TraitDataSource(&TestBTrait::TraitSchema)
+TestBTraitDataSource::TestBTraitDataSource():
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+    TraitUpdatableDataSource(&TestBTrait::TraitSchema)
+#else
+    TraitDataSource(&TestBTrait::TraitSchema)
+#endif
 {
     SetVersion(200);
     taa = TestATrait::ENUM_A_VALUE_1;
@@ -1651,6 +1655,207 @@
     MOCK_strlcpy(tbc_seac, "hallo", sizeof(tbc_seac));
 }
 
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+WEAVE_ERROR
+TestBTraitDataSource::SetLeafData(PropertyPathHandle aLeafHandle, TLVReader &aReader)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+
+    switch (aLeafHandle) {
+        //
+        // TestATrait
+        //
+
+        case TestBTrait::kPropertyHandle_TaA:
+            int32_t next_taa;
+            err = aReader.Get(next_taa);
+            SuccessOrExit(err);
+            if (next_taa != taa)
+            {
+                WeaveLogDetail(DataManagement, "<<  ta_a is changed from %u to %u", taa, next_taa);
+                taa = next_taa;
+            }
+
+            WeaveLogDetail(DataManagement, "<<  ta_a = %u", taa);
+            break;
+
+        case TestBTrait::kPropertyHandle_TaB:
+            int32_t next_tab;
+            err = aReader.Get(next_tab);
+            SuccessOrExit(err);
+            if (next_tab != tab)
+            {
+                WeaveLogDetail(DataManagement, "<<  ta_b is changed from %u to %u", tab, next_tab);
+                tab = next_tab;
+            }
+
+            WeaveLogDetail(DataManagement, "<<  ta_b = %u", tab);
+            break;
+
+        case TestBTrait::kPropertyHandle_TaC:
+            uint32_t next_tac;
+            err = aReader.Get(next_tac);
+            SuccessOrExit(err);
+            if (next_tac != tac)
+            {
+                WeaveLogDetail(DataManagement, "<<  ta_c is changed from %u to %u", tac, next_tac);
+                tac = next_tac;
+            }
+
+            WeaveLogDetail(DataManagement, "<<  ta_c = %u", tac);
+            break;
+
+        case TestBTrait::kPropertyHandle_TaD_SaA:
+            uint32_t next_tad_saa;
+            err = aReader.Get(next_tad_saa);
+            SuccessOrExit(err);
+            if (next_tad_saa != tad_saa)
+            {
+                WeaveLogDetail(DataManagement, "<<  ta_d.sa_a is changed from %u to %u", tad_saa, next_tad_saa);
+                tad_saa = next_tad_saa;
+            }
+
+            WeaveLogDetail(DataManagement, "<<  ta_d.sa_a = %u", tad_saa);
+            break;
+
+        case TestBTrait::kPropertyHandle_TaD_SaB:
+            bool next_tad_sab;
+            err = aReader.Get(next_tad_sab);
+            SuccessOrExit(err);
+            if (next_tad_sab != tad_sab)
+            {
+                WeaveLogDetail(DataManagement, "<<  ta_d.sa_b is changed from %u to %u", tad_sab, next_tad_sab);
+                tad_sab = next_tad_sab;
+            }
+
+            WeaveLogDetail(DataManagement, "<<  ta_d.sa_b = %u", tad_sab);
+            break;
+
+        case TestBTrait::kPropertyHandle_TaE:
+        {
+            TLVType outerType;
+            uint32_t i = 0;
+
+            err = aReader.EnterContainer(outerType);
+            SuccessOrExit(err);
+
+            while (((err = aReader.Next()) == WEAVE_NO_ERROR) && (i < (sizeof(tae) / sizeof(tae[0])))) {
+                uint32_t next_tae;
+                err = aReader.Get(next_tae);
+                SuccessOrExit(err);
+                if (tae[i] != next_tae)
+                {
+                    WeaveLogDetail(DataManagement, "<<  ta_e[%u] is changed from %u to %u", i, tae[i], next_tae);
+                    tae[i] = next_tae;
+                }
+
+                WeaveLogDetail(DataManagement, "<<  ta_e[%u] = %u", i, tae[i]);
+                i++;
+            }
+
+            err = aReader.ExitContainer(outerType);
+            break;
+        }
+
+        case TestBTrait::kPropertyHandle_TaP:
+            err = aReader.Get(tap);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  ta_p = %" PRId64, tap);
+            break;
+
+        //
+        // TestBTrait
+        //
+
+        case TestBTrait::kPropertyHandle_TbA:
+            uint32_t next_tba;
+            err = aReader.Get(next_tba);
+            SuccessOrExit(err);
+            if (tba != next_tba)
+            {
+                WeaveLogDetail(DataManagement, "<<  tb_a is changed from %u to %u", tba, next_tba);
+                tba = next_tba;
+            }
+
+            WeaveLogDetail(DataManagement, "<<  tb_a = %u", tba);
+            break;
+
+        case TestBTrait::kPropertyHandle_TbB_SbA:
+            char next_tbb_sba[10];
+            err = aReader.GetString(next_tbb_sba, 10);
+            SuccessOrExit(err);
+            if (strncmp(tbb_sba, next_tbb_sba, 10))
+            {
+                WeaveLogDetail(DataManagement, "<<  tb_b.sb_a is changed from %s to %s", tbb_sba, next_tbb_sba);
+                memcpy(tbb_sba, next_tbb_sba, 10);
+            }
+
+            WeaveLogDetail(DataManagement, "<<  tb_b.sb_a = %s", tbb_sba);
+            break;
+
+        case TestBTrait::kPropertyHandle_TbB_SbB:
+            uint32_t next_tbb_sbb;
+            err = aReader.Get(next_tbb_sbb);
+            SuccessOrExit(err);
+            if (tbb_sbb != next_tbb_sbb)
+            {
+                WeaveLogDetail(DataManagement, "<<  tb_b.sb_b is changed from %u to %u", tbb_sbb, next_tbb_sbb);
+                tbb_sbb = next_tbb_sbb;
+            }
+
+            WeaveLogDetail(DataManagement, "<<  tb_b.sb_b = %u", tbb_sbb);
+            break;
+
+        case TestBTrait::kPropertyHandle_TbC_SaA:
+            uint32_t next_tbc_saa;
+            err = aReader.Get(next_tbc_saa);
+            SuccessOrExit(err);
+            if (tbc_saa != next_tbc_saa)
+            {
+                WeaveLogDetail(DataManagement, "<<  tb_c.sa_a is changed from %u to %u", tbc_saa, next_tbc_saa);
+                tbc_saa = next_tbc_saa;
+            }
+
+            WeaveLogDetail(DataManagement, "<<  tb_c.sa_a = %u", tbc_saa);
+            break;
+
+        case TestBTrait::kPropertyHandle_TbC_SaB:
+            bool next_tbc_sab;
+            err = aReader.Get(next_tbc_sab);
+            SuccessOrExit(err);
+            if (tbc_sab != next_tbc_sab)
+            {
+                WeaveLogDetail(DataManagement, "<<  tb_c.sa_b is changed from %u to %u", tbc_sab, next_tbc_sab);
+                tbc_sab = next_tbc_sab;
+            }
+
+            WeaveLogDetail(DataManagement, "<<  tb_c.sa_b = %u", tbc_sab);
+            break;
+
+        case TestBTrait::kPropertyHandle_TbC_SeaC:
+            char next_tbc_seac[10];
+            err = aReader.GetString(next_tbc_seac, 10);
+            SuccessOrExit(err);
+            if (strncmp(tbc_seac, next_tbc_seac, 10))
+            {
+                WeaveLogDetail(DataManagement, "<<  tb_c.sea_c is changed from \"%s\" to \"%s\"", tbc_seac, next_tbc_seac);
+                memcpy(tbc_seac, next_tbc_seac, 10);
+            }
+
+            WeaveLogDetail(DataManagement, "<<  tb_c.sea_c = \"%s\"", tbc_seac);
+            break;
+
+        default:
+            WeaveLogDetail(DataManagement, "<<  TestBTrait UNKNOWN! %08x", aLeafHandle);
+    }
+
+exit:
+    return err;
+}
+
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+
 void TestBTraitDataSource::Mutate()
 {
     Lock();
diff --git a/src/test-apps/MockSourceTraits.h b/src/test-apps/MockSourceTraits.h
index 9e802a1..6b401f3 100644
--- a/src/test-apps/MockSourceTraits.h
+++ b/src/test-apps/MockSourceTraits.h
@@ -195,18 +195,26 @@
     uint32_t mTestCounter;
 };
 
-class TestBTraitDataSource : public nl::Weave::Profiles::DataManagement::TraitDataSource
+class TestBTraitDataSource:
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+    public nl::Weave::Profiles::DataManagement::TraitUpdatableDataSource
+#else
+    public nl::Weave::Profiles::DataManagement::TraitDataSource
+#endif
 {
 public:
     TestBTraitDataSource();
     void Mutate();
 
 private:
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+    WEAVE_ERROR SetLeafData(nl::Weave::Profiles::DataManagement::PropertyPathHandle aLeafHandle, nl::Weave::TLV::TLVReader &aReader) __OVERRIDE;
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
     WEAVE_ERROR GetLeafData(nl::Weave::Profiles::DataManagement::PropertyPathHandle aLeafHandle, uint64_t aTagToWrite, nl::Weave::TLV::TLVWriter &aWriter) __OVERRIDE;
     WEAVE_ERROR GetNextDictionaryItemKey(nl::Weave::Profiles::DataManagement::PropertyPathHandle aDictionaryHandle, uintptr_t &aContext, nl::Weave::Profiles::DataManagement::PropertyDictionaryKey &aKey) __OVERRIDE;
 
-    Schema::Nest::Test::Trait::TestATrait::EnumA taa;
-    Schema::Nest::Test::Trait::TestCommon::CommonEnumA tab;
+    int32_t taa;
+    int32_t tab;
     uint32_t tac;
     uint32_t tad_saa;
     bool tad_sab;
diff --git a/src/test-apps/TestWdmUpdateServer.cpp b/src/test-apps/TestWdmUpdateServer.cpp
new file mode 100644
index 0000000..eddb2de
--- /dev/null
+++ b/src/test-apps/TestWdmUpdateServer.cpp
@@ -0,0 +1,634 @@
+/*
+ *
+ *    Copyright (c) 2020 Google LLC.
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+/**
+ *    @file
+ *      This file implements unit tests for the Wdm Update Server.
+ *
+ */
+
+#include "ToolCommon.h"
+
+#include <nlbyteorder.h>
+#include <nlunit-test.h>
+
+#include <Weave/Core/WeaveCore.h>
+
+#include <Weave/Profiles/data-management/Current/WdmManagedNamespace.h>
+#include <Weave/Profiles/data-management/DataManagement.h>
+
+#include <nest/test/trait/TestATrait.h>
+#include "MockSinkTraits.h"
+#include "MockSourceTraits.h"
+#include <new>
+#include <map>
+#include <set>
+#include <algorithm>
+#include <set>
+#include <string>
+#include <iterator>
+
+#if WEAVE_SYSTEM_CONFIG_USE_LWIP
+#include <lwip/init.h>
+#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
+
+#define PRINT_TEST_NAME() printf("\n%s\n", __func__);
+
+using namespace nl;
+using namespace nl::Weave::TLV;
+using namespace nl::Weave::Profiles::DataManagement;
+using namespace Schema::Nest::Test::Trait;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// System/Platform definitions
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+namespace nl {
+namespace Weave {
+namespace Profiles {
+namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current) {
+
+SubscriptionEngine * SubscriptionEngine::GetInstance()
+{
+    static nl::Weave::Profiles::DataManagement::SubscriptionEngine gWdmSubscriptionEngine;
+    return &gWdmSubscriptionEngine;
+}
+
+namespace Platform {
+// For unit tests, a dummy critical section is sufficient.
+void CriticalSectionEnter()
+{
+    return;
+}
+
+void CriticalSectionExit()
+{
+    return;
+}
+
+} // namespace Platform
+
+} // namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current)
+} // namespace Profiles
+} // namespace Weave
+} // namespace nl
+
+#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING && WEAVE_CONFIG_ENABLE_WDM_UPDATE
+namespace nl {
+namespace Weave {
+namespace Profiles {
+namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current) {
+
+class WdmUpdateServerTest
+{
+public:
+    WdmUpdateServerTest();
+    ~WdmUpdateServerTest() { }
+
+    // Tests
+    void SetupTest();
+    void TearDownTest();
+
+    void TestInitCleanup(nlTestSuite * inSuite, void * inContext);
+    void TestUpdateServerConditionalOneLeaf(nlTestSuite * inSuite, void * inContext);
+    void TestUpdateServerUnconditionalOneLeaf(nlTestSuite * inSuite, void * inContext);
+    void TestUpdateServerMixedConditionalOneLeaf(nlTestSuite * inSuite, void * inContext);
+    void TestUpdateServerConditionalTwoProperties(nlTestSuite * inSuite, void * inContext);
+    void TestUpdateServerUnconditionalTwoProperties(nlTestSuite * inSuite, void * inContext);
+    void TestUpdateServerMixedConditionalTwoProperties(nlTestSuite * inSuite, void * inContext);
+
+private:
+    // The encoder
+    UpdateEncoder mEncoder;
+    UpdateEncoder::Context mContext;
+
+    // These are here for convenience
+    PacketBuffer * mBuf;
+    TraitPath mTP;
+
+    //
+    // The state usually held by the SubscriptionClient
+    //
+
+    // The list of path to encode
+    TraitPathStore mPathList;
+    TraitPathStore::Record mStorage[10];
+
+    // The Trait instances
+    TestATraitUpdatableDataSink mTestATraitUpdatableDataSink0;
+    TestATraitDataSource mTestATraitDataSource0;
+    TestBTraitUpdatableDataSink mTestBTraitUpdatableDataSink;
+    TestBTraitDataSource mTestBTraitDataSource;
+    // The catalog
+    SingleResourceSinkTraitCatalog mSinkCatalog;
+    SingleResourceSinkTraitCatalog::CatalogItem mSinkCatalogStore[9];
+    SingleResourceSourceTraitCatalog mSourceCatalog;
+    SingleResourceSourceTraitCatalog::CatalogItem mSourceCatalogStore[9];
+    // The set of TraitDataHandles assigned by the catalog
+    // to the Trait instances
+    enum
+    {
+        kTestATraitSink0Index = 0,
+        kTestATraitSink1Index,
+        kTestBTraitSinkIndex,
+
+        kTestATraitSource0Index,
+        kTestATraitSource1Index,
+        kTestBTraitSourceIndex,
+        kMaxNumTraitHandles,
+    };
+    TraitDataHandle mTraitHandleSet[kMaxNumTraitHandles];
+
+    // Test support functions
+    void UpdateServerBasicTestBody(nlTestSuite * inSuite);
+    void InitEncoderContext(nlTestSuite * inSuite);
+    static void TLVPrettyPrinter(const char * aFormat, ...);
+    WEAVE_ERROR DebugPrettyPrint(PacketBuffer * apMsgBuf);
+
+    WEAVE_ERROR VerifyUpdateRequest(nlTestSuite * inSuite, PacketBuffer * aPayload, size_t aItemToStartFrom = 0);
+};
+
+WdmUpdateServerTest::WdmUpdateServerTest() :
+    mBuf(NULL), mSinkCatalog(ResourceIdentifier(ResourceIdentifier::SELF_NODE_ID), mSinkCatalogStore,
+                             sizeof(mSinkCatalogStore) / sizeof(mSinkCatalogStore[0])),
+    mSourceCatalog(ResourceIdentifier(ResourceIdentifier::SELF_NODE_ID), mSourceCatalogStore,
+                   sizeof(mSourceCatalogStore) / sizeof(mSourceCatalogStore[0]))
+{
+    mPathList.Init(mStorage, ArraySize(mStorage));
+
+    mSinkCatalog.Add(0, &mTestATraitUpdatableDataSink0, mTraitHandleSet[kTestATraitSink0Index]);
+    mSourceCatalog.Add(0, &mTestATraitDataSource0, mTraitHandleSet[kTestBTraitSourceIndex]);
+
+    mSinkCatalog.Add(0, &mTestBTraitUpdatableDataSink, mTraitHandleSet[kTestBTraitSinkIndex]);
+    mSourceCatalog.Add(0, &mTestBTraitDataSource, mTraitHandleSet[kTestBTraitSourceIndex]);
+
+    mTestATraitUpdatableDataSink0.SetUpdateEncoder(&mEncoder);
+}
+
+void WdmUpdateServerTest::SetupTest()
+{
+    mPathList.Clear();
+
+    mTestATraitUpdatableDataSink0.tai_map.clear();
+
+    for (int32_t i = 0; i < 10; i++)
+    {
+        mTestATraitUpdatableDataSink0.tai_map[i] = i + 100;
+    }
+}
+
+void WdmUpdateServerTest::TearDownTest()
+{
+    if (mBuf != NULL)
+    {
+        PacketBuffer::Free(mBuf);
+        mBuf = 0;
+    }
+}
+
+void WdmUpdateServerTest::InitEncoderContext(nlTestSuite * inSuite)
+{
+    if (NULL == mBuf)
+    {
+        mBuf = PacketBuffer::New(0);
+        NL_TEST_ASSERT(inSuite, mBuf != NULL);
+    }
+
+    mBuf->SetDataLength(0);
+
+    mContext.mBuf                             = mBuf;
+    mContext.mMaxPayloadSize                  = mBuf->AvailableDataLength();
+    mContext.mUpdateRequestIndex              = 7;
+    mContext.mExpiryTimeMicroSecond           = 0;
+    mContext.mItemInProgress                  = 0;
+    mContext.mNextDictionaryElementPathHandle = kNullPropertyPathHandle;
+    mContext.mInProgressUpdateList            = &mPathList;
+    mContext.mDataSinkCatalog                 = &mSinkCatalog;
+}
+
+void WdmUpdateServerTest::TestInitCleanup(nlTestSuite * inSuite, void * inContext)
+{
+    PRINT_TEST_NAME();
+
+    NL_TEST_ASSERT(inSuite, 0 == mPathList.GetNumItems());
+}
+
+void WdmUpdateServerTest::TLVPrettyPrinter(const char * aFormat, ...)
+{
+    va_list args;
+
+    va_start(args, aFormat);
+
+    vprintf(aFormat, args);
+
+    va_end(args);
+}
+
+WEAVE_ERROR WdmUpdateServerTest::DebugPrettyPrint(PacketBuffer * apMsgBuf)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    nl::Weave::TLV::TLVReader reader;
+    reader.Init(apMsgBuf);
+    err = reader.Next();
+    SuccessOrExit(err);
+    nl::Weave::TLV::Debug::Dump(reader, TLVPrettyPrinter);
+
+exit:
+    if (WEAVE_NO_ERROR != err)
+    {
+        WeaveLogProgress(DataManagement, "DebugPrettyPrint fails with err %d", err);
+    }
+
+    return err;
+}
+
+WEAVE_ERROR WdmUpdateServerTest::VerifyUpdateRequest(nlTestSuite * inSuite, PacketBuffer * aPayload, size_t aItemToStartFrom)
+{
+    WEAVE_ERROR err     = WEAVE_NO_ERROR;
+    PacketBuffer * pBuf = NULL;
+    UpdateRequest::Parser update;
+    Weave::TLV::TLVReader reader;
+    bool isDataListPresent                                             = false;
+    bool existFailure                                                  = false;
+    uint32_t numDataElements                                           = 0;
+    uint32_t maxPayloadSize                                            = 0;
+    SubscriptionEngine::StatusDataHandleElement * statusDataHandleList = NULL;
+    uint8_t * pBufEndAddr                                              = NULL;
+    SubscriptionEngine::UpdateRequestDataElementAccessControlDelegate acDelegate(NULL);
+
+    err = SubscriptionEngine::GetInstance()->Init(&ExchangeMgr, this, NULL);
+    SuccessOrExit(err);
+
+    err = SubscriptionEngine::GetInstance()->EnablePublisher(NULL, &mSourceCatalog);
+    SuccessOrExit(err);
+
+    DebugPrettyPrint(aPayload);
+
+    reader.Init(aPayload);
+
+    err = reader.Next();
+    SuccessOrExit(err);
+
+    err = update.Init(reader);
+    SuccessOrExit(err);
+
+#if WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
+    err = update.CheckSchemaValidity();
+    SuccessOrExit(err);
+#endif // WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
+
+    {
+        DataList::Parser dataList;
+        err = update.GetDataList(&dataList);
+        if (WEAVE_NO_ERROR == err)
+        {
+            isDataListPresent = true;
+        }
+        else if (WEAVE_END_OF_TLV == err)
+        {
+            isDataListPresent = false;
+            err               = WEAVE_NO_ERROR;
+        }
+        SuccessOrExit(err);
+
+        // re-initialize the reader to point to individual date element (reuse to save stack depth).
+        dataList.GetReader(&reader);
+    }
+
+    err = SubscriptionEngine::AllocateRightSizedBuffer(pBuf, WDM_MAX_UPDATE_RESPONSE_SIZE, WDM_MIN_UPDATE_RESPONSE_SIZE,
+                                                       maxPayloadSize);
+    SuccessOrExit(err);
+
+    statusDataHandleList =
+        reinterpret_cast<SubscriptionEngine::StatusDataHandleElement *> WEAVE_SYSTEM_ALIGN_SIZE((size_t)(pBuf->Start()), 4);
+    pBufEndAddr = pBuf->Start() + maxPayloadSize;
+    err         = SubscriptionEngine::InitializeStatusDataHandleList(reader, statusDataHandleList, numDataElements, pBufEndAddr);
+    SuccessOrExit(err);
+
+    err = SubscriptionEngine::ProcessUpdateRequestDataList(reader, statusDataHandleList, &mSourceCatalog, acDelegate, existFailure,
+                                                           numDataElements);
+    SuccessOrExit(err);
+exit:
+    if (pBuf != NULL)
+    {
+        PacketBuffer::Free(pBuf);
+        pBuf = NULL;
+    }
+
+    return err;
+}
+
+void WdmUpdateServerTest::UpdateServerBasicTestBody(nlTestSuite * inSuite)
+{
+    WEAVE_ERROR err;
+
+    InitEncoderContext(inSuite);
+
+    err = mEncoder.EncodeRequest(mContext);
+    NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
+    NL_TEST_ASSERT(inSuite, mPathList.GetPathStoreSize() == mContext.mItemInProgress);
+    NL_TEST_ASSERT(inSuite, kNullPropertyPathHandle == mContext.mNextDictionaryElementPathHandle);
+
+    err = VerifyUpdateRequest(inSuite, mBuf);
+    NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
+}
+
+void WdmUpdateServerTest::TestUpdateServerConditionalOneLeaf(nlTestSuite * inSuite, void * inContext)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+
+    mTestATraitDataSource0.SetVersion(100);
+    mTestATraitUpdatableDataSink0.SetUpdateRequiredVersion(100);
+    mTestATraitUpdatableDataSink0.SetConditionalUpdate(true);
+
+    PRINT_TEST_NAME();
+
+    mTP = { mTraitHandleSet[kTestATraitSink0Index], CreatePropertyPathHandle(TestATrait::kPropertyHandle_TaC) };
+
+    err = mPathList.AddItem(mTP);
+    NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
+
+    UpdateServerBasicTestBody(inSuite);
+
+    NL_TEST_ASSERT(inSuite, mTestATraitDataSource0.GetVersion() == 101);
+    mTestATraitUpdatableDataSink0.ClearUpdateRequiredVersion();
+    mTestATraitUpdatableDataSink0.SetConditionalUpdate(false);
+    NL_TEST_ASSERT(inSuite, 1 == mPathList.GetNumItems());
+}
+
+void WdmUpdateServerTest::TestUpdateServerUnconditionalOneLeaf(nlTestSuite * inSuite, void * inContext)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    mTestATraitDataSource0.SetVersion(100);
+
+    PRINT_TEST_NAME();
+
+    mTP = { mTraitHandleSet[kTestATraitSink0Index], CreatePropertyPathHandle(TestATrait::kPropertyHandle_TaC) };
+
+    err = mPathList.AddItem(mTP);
+    NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
+
+    UpdateServerBasicTestBody(inSuite);
+    NL_TEST_ASSERT(inSuite, mTestATraitDataSource0.GetVersion() == 101);
+
+    NL_TEST_ASSERT(inSuite, 1 == mPathList.GetNumItems());
+}
+
+void WdmUpdateServerTest::TestUpdateServerMixedConditionalOneLeaf(nlTestSuite * inSuite, void * inContext)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    mTestATraitDataSource0.SetVersion(100);
+    mTestATraitUpdatableDataSink0.SetUpdateRequiredVersion(100);
+    mTestATraitUpdatableDataSink0.SetConditionalUpdate(true);
+
+    mTestBTraitDataSource.SetVersion(200);
+
+    PRINT_TEST_NAME();
+
+    mTP = { mTraitHandleSet[kTestATraitSink0Index], CreatePropertyPathHandle(TestATrait::kPropertyHandle_TaC) };
+
+    err = mPathList.AddItem(mTP);
+    NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
+
+    mTP = { mTraitHandleSet[kTestBTraitSinkIndex], CreatePropertyPathHandle(TestBTrait::kPropertyHandle_TaC) };
+
+    err = mPathList.AddItem(mTP);
+    NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
+
+    UpdateServerBasicTestBody(inSuite);
+
+    NL_TEST_ASSERT(inSuite, mTestATraitDataSource0.GetVersion() == 101);
+    NL_TEST_ASSERT(inSuite, mTestBTraitDataSource.GetVersion() == 201);
+
+    mTestATraitUpdatableDataSink0.ClearUpdateRequiredVersion();
+    mTestATraitUpdatableDataSink0.SetConditionalUpdate(false);
+    NL_TEST_ASSERT(inSuite, 2 == mPathList.GetNumItems());
+}
+
+void WdmUpdateServerTest::TestUpdateServerConditionalTwoProperties(nlTestSuite * inSuite, void * inContext)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    mTestATraitDataSource0.SetVersion(100);
+    mTestATraitUpdatableDataSink0.SetUpdateRequiredVersion(100);
+    mTestATraitUpdatableDataSink0.SetConditionalUpdate(true);
+
+    PRINT_TEST_NAME();
+
+    mTP = { mTraitHandleSet[kTestATraitSink0Index], CreatePropertyPathHandle(TestATrait::kPropertyHandle_TaA) };
+
+    err = mPathList.AddItem(mTP);
+    NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
+
+    mTP.mPropertyPathHandle = CreatePropertyPathHandle(TestATrait::kPropertyHandle_TaB);
+    err                     = mPathList.AddItem(mTP);
+    NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
+
+    UpdateServerBasicTestBody(inSuite);
+
+    NL_TEST_ASSERT(inSuite, mTestATraitDataSource0.GetVersion() == 101);
+
+    mTestATraitUpdatableDataSink0.ClearUpdateRequiredVersion();
+    mTestATraitUpdatableDataSink0.SetConditionalUpdate(false);
+
+    NL_TEST_ASSERT(inSuite, 2 == mPathList.GetNumItems());
+}
+
+void WdmUpdateServerTest::TestUpdateServerUnconditionalTwoProperties(nlTestSuite * inSuite, void * inContext)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    mTestATraitDataSource0.SetVersion(100);
+
+    PRINT_TEST_NAME();
+
+    mTP = { mTraitHandleSet[kTestATraitSink0Index], CreatePropertyPathHandle(TestATrait::kPropertyHandle_TaA) };
+
+    err = mPathList.AddItem(mTP);
+    NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
+
+    mTP.mPropertyPathHandle = CreatePropertyPathHandle(TestATrait::kPropertyHandle_TaB);
+    err                     = mPathList.AddItem(mTP);
+    NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
+
+    UpdateServerBasicTestBody(inSuite);
+
+    NL_TEST_ASSERT(inSuite, mTestATraitDataSource0.GetVersion() == 101);
+
+    NL_TEST_ASSERT(inSuite, 2 == mPathList.GetNumItems());
+}
+
+void WdmUpdateServerTest::TestUpdateServerMixedConditionalTwoProperties(nlTestSuite * inSuite, void * inContext)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    mTestATraitDataSource0.SetVersion(100);
+    mTestATraitUpdatableDataSink0.SetUpdateRequiredVersion(100);
+    mTestATraitUpdatableDataSink0.SetConditionalUpdate(true);
+
+    PRINT_TEST_NAME();
+
+    mTP = { mTraitHandleSet[kTestATraitSink0Index], CreatePropertyPathHandle(TestATrait::kPropertyHandle_TaA) };
+
+    err = mPathList.AddItem(mTP);
+    NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
+
+    mTP.mPropertyPathHandle = CreatePropertyPathHandle(TestATrait::kPropertyHandle_TaB);
+    err                     = mPathList.AddItem(mTP);
+    NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
+
+    mTP = { mTraitHandleSet[kTestBTraitSinkIndex], CreatePropertyPathHandle(TestBTrait::kPropertyHandle_TaC) };
+
+    err = mPathList.AddItem(mTP);
+    NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
+
+    mTP.mPropertyPathHandle = CreatePropertyPathHandle(TestATrait::kPropertyHandle_TaD_SaA);
+    err                     = mPathList.AddItem(mTP);
+    NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
+
+    UpdateServerBasicTestBody(inSuite);
+
+    NL_TEST_ASSERT(inSuite, mTestATraitDataSource0.GetVersion() == 101);
+    NL_TEST_ASSERT(inSuite, mTestBTraitDataSource.GetVersion() == 202);
+
+    mTestATraitUpdatableDataSink0.ClearUpdateRequiredVersion();
+    mTestATraitUpdatableDataSink0.SetConditionalUpdate(false);
+
+    NL_TEST_ASSERT(inSuite, 4 == mPathList.GetNumItems());
+}
+
+} // namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current)
+} // namespace Profiles
+} // namespace Weave
+} // namespace nl
+
+WdmUpdateServerTest gWdmUpdateServerTest;
+
+void WdmUpdateEncoderTest_InitCleanup(nlTestSuite * inSuite, void * inContext)
+{
+    gWdmUpdateServerTest.TestInitCleanup(inSuite, inContext);
+}
+
+void WdmUpdateServerTest_ConditionalOneLeaf(nlTestSuite * inSuite, void * inContext)
+{
+    gWdmUpdateServerTest.TestUpdateServerConditionalOneLeaf(inSuite, inContext);
+}
+
+void WdmUpdateServerTest_UnconditionalOneLeaf(nlTestSuite * inSuite, void * inContext)
+{
+    gWdmUpdateServerTest.TestUpdateServerUnconditionalOneLeaf(inSuite, inContext);
+}
+
+void WdmUpdateServerTest_MiexedConditionalOneLeaf(nlTestSuite * inSuite, void * inContext)
+{
+    gWdmUpdateServerTest.TestUpdateServerMixedConditionalOneLeaf(inSuite, inContext);
+}
+
+void WdmUpdateServerTest_ConditionalTwoProperties(nlTestSuite * inSuite, void * inContext)
+{
+    gWdmUpdateServerTest.TestUpdateServerConditionalTwoProperties(inSuite, inContext);
+}
+
+void WdmUpdateServerTest_UnconditionalTwoProperties(nlTestSuite * inSuite, void * inContext)
+{
+    gWdmUpdateServerTest.TestUpdateServerUnconditionalTwoProperties(inSuite, inContext);
+}
+
+void WdmUpdateServerTest_MixedConditionalTwoProperties(nlTestSuite * inSuite, void * inContext)
+{
+    gWdmUpdateServerTest.TestUpdateServerMixedConditionalTwoProperties(inSuite, inContext);
+}
+
+// Test Suite
+
+/**
+ *  Test Suite that lists all the test functions.
+ */
+static const nlTest sTests[] = { NL_TEST_DEF("Init and cleanup", WdmUpdateEncoderTest_InitCleanup),
+                                 NL_TEST_DEF("Decode conditional one leaf", WdmUpdateServerTest_ConditionalOneLeaf),
+                                 NL_TEST_DEF("Decode unconditional one leaf", WdmUpdateServerTest_UnconditionalOneLeaf),
+                                 NL_TEST_DEF("Decode mixedconditional one leaf", WdmUpdateServerTest_MiexedConditionalOneLeaf),
+                                 NL_TEST_DEF("Decode conditional two properties", WdmUpdateServerTest_ConditionalTwoProperties),
+                                 NL_TEST_DEF("Decode unconditional two properties", WdmUpdateServerTest_UnconditionalTwoProperties),
+                                 NL_TEST_DEF("Decode mixedconditional two properties",
+                                             WdmUpdateServerTest_MixedConditionalTwoProperties),
+                                 NL_TEST_SENTINEL() };
+
+/**
+ *  Set up the test suite.
+ */
+static int SuiteSetup(void * inContext)
+{
+    return 0;
+}
+
+/**
+ *  Tear down the test suite.
+ */
+static int SuiteTeardown(void * inContext)
+{
+    return 0;
+}
+
+/**
+ *  Set up each test.
+ */
+static int TestSetup(void * inContext)
+{
+    gWdmUpdateServerTest.SetupTest();
+
+    return 0;
+}
+
+/**
+ *  Tear down each test.
+ */
+static int TestTeardown(void * inContext)
+{
+    gWdmUpdateServerTest.TearDownTest();
+
+    return 0;
+}
+
+/**
+ *  Main
+ */
+int main(int argc, char * argv[])
+{
+#if WEAVE_SYSTEM_CONFIG_USE_LWIP
+    tcpip_init(NULL, NULL);
+#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
+
+    nlTestSuite theSuite = { "weave-WdmUpdateServer", &sTests[0], SuiteSetup, SuiteTeardown, TestSetup, TestTeardown };
+
+    // Generate machine-readable, comma-separated value (CSV) output.
+    nl_test_set_output_style(OUTPUT_CSV);
+
+    // Run test suit against one context
+    nlTestRunner(&theSuite, NULL);
+
+    return nlTestRunnerStats(&theSuite);
+}
+
+#else // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING && WEAVE_CONFIG_ENABLE_WDM_UPDATE
+
+int main(int argc, char * argv[])
+{
+    return 0;
+}
+
+#endif // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING && WEAVE_CONFIG_ENABLE_WDM_UPDATE