/* * * Copyright (c) 2021 Project CHIP Authors * 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. */ #include #include "lib/support/CHIPMem.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace chip { namespace app { class TestPowerSourceCluster : public ::testing::Test { public: static void SetUpTestSuite() { ASSERT_EQ(chip::Platform::MemoryInit(), CHIP_NO_ERROR); } static void TearDownTestSuite() { chip::app::Clusters::PowerSourceServer::Instance().Shutdown(); chip::Platform::MemoryShutdown(); } }; std::vector ReadEndpointsThroughAttributeReader(EndpointId endpoint) { Clusters::PowerSourceAttrAccess & attrAccess = Clusters::TestOnlyGetPowerSourceAttrAccess(); CHIP_ERROR err = CHIP_NO_ERROR; // Write TLV through the attribute access interface into the buffer // Buffer setup constexpr size_t buflen = 128; uint8_t buf[buflen]; memset(buf, 0, buflen); // Create the builders TLV::TLVWriter tlvWriter; tlvWriter.Init(buf); AttributeReportIBs::Builder builder; builder.Init(&tlvWriter); ConcreteAttributePath path(endpoint, Clusters::PowerSource::Id, Clusters::PowerSource::Attributes::EndpointList::Id); ConcreteReadAttributePath readPath(path); chip::DataVersion dataVersion(0); Access::SubjectDescriptor subjectDescriptor; AttributeValueEncoder aEncoder(builder, subjectDescriptor, path, dataVersion); err = attrAccess.Read(readPath, aEncoder); EXPECT_EQ(err, CHIP_NO_ERROR); // Read out from the buffer. This comes back as a nested struct // AttributeReportIBs is a list of // AttributeReportIB structs containing // AttributeDataIB struct, which holds DataVersion (tag 0), AttributePathIB (tag 1) and Data (tag 2) TLV::TLVReader reader; reader.Init(buf); TLV::TLVReader attrReportsReader; TLV::TLVReader attrReportReader; TLV::TLVReader attrDataReader; reader.Next(); reader.OpenContainer(attrReportsReader); attrReportsReader.Next(); attrReportsReader.OpenContainer(attrReportReader); attrReportReader.Next(); attrReportReader.OpenContainer(attrDataReader); // We're now in the attribute data IB, skip to the desired tag, we want TagNum = 2 attrDataReader.Next(); for (int i = 0; i < 3 && !(IsContextTag(attrDataReader.GetTag()) && TagNumFromTag(attrDataReader.GetTag()) == 2); ++i) { attrDataReader.Next(); } EXPECT_TRUE(IsContextTag(attrDataReader.GetTag())); EXPECT_EQ(TagNumFromTag(attrDataReader.GetTag()), 2u); // OK, we should be in the right spot now, let's decode the list. Clusters::PowerSource::Attributes::EndpointList::TypeInfo::DecodableType list; err = list.Decode(attrDataReader); EXPECT_EQ(err, CHIP_NO_ERROR); std::vector ret; auto iter = list.begin(); while (iter.Next()) { ret.push_back(iter.GetValue()); } return ret; } TEST_F(TestPowerSourceCluster, TestEndpointList) { CHIP_ERROR err = CHIP_NO_ERROR; Clusters::PowerSourceServer & powerSourceServer = Clusters::PowerSourceServer::Instance(); // test that when we read everything we get an empty list as nothing has been set up yet for (EndpointId i = 0; i < 11; ++i) { std::vector vec = ReadEndpointsThroughAttributeReader(i); EXPECT_EQ(vec.size(), 0u); } if (powerSourceServer.GetNumSupportedEndpointLists() < 2 || powerSourceServer.GetNumSupportedEndpointLists() > std::numeric_limits::max()) { // Test assumes at least two endpoints. This runs on linux, not worthwhile to run on platforms with fewer endpoints. return; } // ***************** // Test setting, getting and reading through the attribute access interface // ***************** EndpointId list0[5] = { 1, 2, 3, 4, 5 }; EndpointId list1[10] = { 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; EndpointId listRest[1] = { 2 }; // we checked earlier that this fit // This test just uses endpoints in order, so we want to set endpoints from // 0 to chip::Test::numEndpoints - 1, and use this for overflow checking chip::Test::numEndpoints = static_cast(powerSourceServer.GetNumSupportedEndpointLists()); // Endpoint 0 - list of 5 err = powerSourceServer.SetEndpointList(0, Span(list0)); EXPECT_EQ(err, CHIP_NO_ERROR); const Span * readBack = powerSourceServer.GetEndpointList(0); ASSERT_NE(readBack, nullptr); EXPECT_EQ(readBack->size(), 5u); for (size_t i = 0; i < readBack->size(); ++i) { EXPECT_EQ(readBack->data()[i], list0[i]); } // Endpoint 1 - list of 10 err = powerSourceServer.SetEndpointList(1, Span(list1)); EXPECT_EQ(err, CHIP_NO_ERROR); readBack = powerSourceServer.GetEndpointList(1); ASSERT_NE(readBack, nullptr); EXPECT_EQ(readBack->size(), 10u); for (size_t i = 0; i < readBack->size(); ++i) { EXPECT_EQ(readBack->data()[i], list1[i]); } // Remaining endpoints - list of 1 for (EndpointId ep = 2; ep < chip::Test::numEndpoints; ++ep) { err = powerSourceServer.SetEndpointList(ep, Span(listRest)); EXPECT_EQ(err, CHIP_NO_ERROR); readBack = powerSourceServer.GetEndpointList(ep); ASSERT_NE(readBack, nullptr); EXPECT_EQ(readBack->size(), 1u); if (readBack->size() == 1) { EXPECT_EQ(readBack->data()[0], listRest[0]); } } // ***************** // Check for out of memory error when setting too many endpoints // ***************** // pick a random endpoint number for the power cluster - it doesn't matter, we don't have space anyway. err = powerSourceServer.SetEndpointList(55, Span(listRest)); EXPECT_EQ(err, CHIP_ERROR_NO_MEMORY); // ***************** // Recheck getting and reading after OOM // ***************** // EP0 readBack = powerSourceServer.GetEndpointList(0); ASSERT_NE(readBack, nullptr); EXPECT_EQ(readBack->size(), 5u); for (size_t i = 0; i < readBack->size(); ++i) { EXPECT_EQ(readBack->data()[i], list0[i]); } // EP1 readBack = powerSourceServer.GetEndpointList(1); ASSERT_NE(readBack, nullptr); EXPECT_EQ(readBack->size(), 10u); for (size_t i = 0; i < readBack->size(); ++i) { EXPECT_EQ(readBack->data()[i], list1[i]); } // Remaining endpoints for (EndpointId ep = 2; ep < chip::Test::numEndpoints; ++ep) { readBack = powerSourceServer.GetEndpointList(ep); ASSERT_NE(readBack, nullptr); EXPECT_EQ(readBack->size(), 1u); if (readBack->size() == 1) { EXPECT_EQ(readBack->data()[0], listRest[0]); } } // ***************** // Test overwriting // ***************** // Overwrite a list err = powerSourceServer.SetEndpointList(1, Span(listRest)); EXPECT_EQ(err, CHIP_NO_ERROR); readBack = powerSourceServer.GetEndpointList(1); EXPECT_EQ(readBack->size(), 1u); if (readBack->size() == 1) { EXPECT_EQ(readBack->data()[0], listRest[0]); } // Ensure only the overwritten list was changed, using read interface for (EndpointId ep = 0; ep < chip::Test::numEndpoints + 1; ++ep) { std::vector vec = ReadEndpointsThroughAttributeReader(ep); if (ep == 0) { EXPECT_EQ(vec.size(), 5u); for (size_t j = 0; j < vec.size(); ++j) { EXPECT_EQ(vec[j], list0[j]); } } else if (ep == chip::Test::numEndpoints) { EXPECT_EQ(vec.size(), 0u); } else { EXPECT_EQ(vec.size(), 1u); if (vec.size() == 1) { EXPECT_EQ(vec[0], listRest[0]); } } } // ***************** // Test removal // ***************** for (EndpointId ep = 0; ep < chip::Test::numEndpoints; ++ep) { err = powerSourceServer.SetEndpointList(ep, Span()); EXPECT_EQ(err, CHIP_NO_ERROR); readBack = powerSourceServer.GetEndpointList(ep); EXPECT_EQ(readBack, nullptr); } // Check through the read interface for (EndpointId ep = 0; ep < chip::Test::numEndpoints + 1; ++ep) { std::vector vec = ReadEndpointsThroughAttributeReader(ep); EXPECT_EQ(vec.size(), 0u); } } } // namespace app } // namespace chip