Skip to content

Commit 77dc79c

Browse files
committed
Add unit test
1 parent d284b2d commit 77dc79c

File tree

6 files changed

+421
-135
lines changed

6 files changed

+421
-135
lines changed

src/app/clusters/thread-border-router-management-server/thread-br-delegate.h

+2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ class Delegate
4343
class ActivateDatasetCallback
4444
{
4545
public:
46+
ActivateDatasetCallback() = default;
47+
virtual ~ActivateDatasetCallback() = default;
4648
// If the dataset is set successfully, OnActivateDatasetComplete should be called with CHIP_NO_ERROR when the
4749
// Border Router is attached to the Thread network.
4850
// If an error occurs while setting the active dataset, this callback should be called with the error.

src/app/clusters/thread-border-router-management-server/thread-br-mgmt-server.cpp

+146-121
Original file line numberDiff line numberDiff line change
@@ -45,205 +45,191 @@ namespace ThreadBorderRouterManagement {
4545

4646
using Protocols::InteractionModel::Status;
4747

48-
static bool CheckOverCASESession(CommandHandlerInterface::HandlerContext & ctx)
48+
static bool IsOverCASESession(CommandHandlerInterface::HandlerContext & ctx)
4949
{
5050
Messaging::ExchangeContext * exchangeCtx = ctx.mCommandHandler.GetExchangeContext();
51-
if (!exchangeCtx || !exchangeCtx->HasSessionHandle() || !exchangeCtx->GetSessionHandle()->IsSecureSession() ||
52-
exchangeCtx->GetSessionHandle()->AsSecureSession()->GetSecureSessionType() != Transport::SecureSession::Type::kCASE)
53-
{
54-
ChipLogError(Zcl, "This command MUST be over a valid CASE session");
55-
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::UnsupportedAccess);
56-
return false;
57-
}
58-
return true;
51+
return exchangeCtx && exchangeCtx->HasSessionHandle() && exchangeCtx->GetSessionHandle()->IsSecureSession() &&
52+
exchangeCtx->GetSessionHandle()->AsSecureSession()->GetSecureSessionType() == Transport::SecureSession::Type::kCASE;
5953
}
6054

61-
static bool CheckFailSafeArmed(CommandHandlerInterface::HandlerContext & ctx)
55+
static bool IsFailSafeArmed(CommandHandlerInterface::HandlerContext & ctx)
6256
{
6357
auto & failSafeContext = Server::GetInstance().GetFailSafeContext();
64-
if (failSafeContext.IsFailSafeArmed(ctx.mCommandHandler.GetAccessingFabricIndex()))
65-
{
66-
return true;
67-
}
68-
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::FailsafeRequired);
69-
return false;
58+
return failSafeContext.IsFailSafeArmed(ctx.mCommandHandler.GetAccessingFabricIndex());
7059
}
7160

72-
static bool CheckDelegate(CommandHandlerInterface::HandlerContext & ctx, Delegate * delegate)
61+
Status ServerInstance::HandleGetDatasetRequest(bool isOverCASESession, Delegate::DatasetType type,
62+
Thread::OperationalDataset & dataset)
7363
{
74-
if (!delegate)
64+
if (!isOverCASESession)
7565
{
76-
ChipLogError(Zcl, "Thread Border Router Management server not initialized");
77-
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidInState);
66+
return Status::UnsupportedAccess;
7867
}
79-
return delegate;
80-
}
81-
82-
void ServerInstance::HandleGetDatasetRequest(HandlerContext & ctx, Delegate::DatasetType type)
83-
{
84-
VerifyOrReturn(CheckOverCASESession(ctx));
85-
VerifyOrReturn(CheckDelegate(ctx, mDelegate));
8668

87-
Commands::DatasetResponse::Type response;
88-
Thread::OperationalDataset dataset;
8969
CHIP_ERROR err = mDelegate->GetDataset(dataset, type);
9070
if (err != CHIP_NO_ERROR)
9171
{
92-
ctx.mCommandHandler.AddStatus(ctx.mRequestPath,
93-
err == CHIP_IM_GLOBAL_STATUS(NotFound) ? StatusIB(err).mStatus : Status::Failure);
94-
return;
72+
return err == CHIP_IM_GLOBAL_STATUS(NotFound) ? StatusIB(err).mStatus : Status::Failure;
9573
}
96-
response.dataset = dataset.AsByteSpan();
97-
ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response);
74+
return Status::Success;
9875
}
9976

100-
void ServerInstance::HandleSetActiveDatasetRequest(HandlerContext & ctx,
101-
const Commands::SetActiveDatasetRequest::DecodableType & req)
77+
Status ServerInstance::HandleSetActiveDatasetRequest(bool failSafeArmed,
78+
const Commands::SetActiveDatasetRequest::DecodableType & req)
10279
{
10380
// The SetActiveDatasetRequest command SHALL be FailSafeArmed. Upon receiving this command, the Thread BR will set its
10481
// active dataset. If the dataset is set successfully, OnActivateDatasetComplete will be called with CHIP_NO_ERROR, prompting
10582
// the Thread BR to respond with a success status and disarm the FailSafe timer. If an error occurs while setting the active
10683
// dataset, the Thread BR should respond with a failure status. In this case, when the FailSafe timer expires, the active
10784
// dataset set by this command will be reverted. If the FailSafe timer expires before the Thread BR responds, the Thread BR will
10885
// respond with a timeout status and the active dataset should also be reverted.
109-
VerifyOrReturn(CheckFailSafeArmed(ctx));
110-
VerifyOrReturn(CheckDelegate(ctx, mDelegate));
111-
if (mAsyncCommandHandle.Get() != nullptr)
112-
{
113-
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Busy);
114-
return;
115-
}
86+
ReturnErrorCodeIf(!failSafeArmed, Status::FailsafeRequired);
87+
ReturnErrorCodeIf(!mDelegate, Status::InvalidInState);
11688

11789
Thread::OperationalDataset activeDataset;
11890
Thread::OperationalDataset currentActiveDataset;
11991
uint64_t currentActiveDatasetTimestamp;
120-
if (activeDataset.Init(req.activeDataset) != CHIP_NO_ERROR)
121-
{
122-
// If any of the parameters in the ActiveDataset is invalid, the command SHALL fail with a status code
123-
// of INVALID_COMMAND.
124-
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand);
125-
return;
126-
}
92+
// If any of the parameters in the ActiveDataset is invalid, the command SHALL fail with a status code
93+
// of INVALID_COMMAND.
94+
ReturnErrorCodeIf(activeDataset.Init(req.activeDataset) != CHIP_NO_ERROR, Status::InvalidCommand);
12795

96+
// If this command is invoked when the ActiveDatasetTimestamp attribute is not null, the command SHALL
97+
// fail with a status code of INVALID_IN_STATE.
12898
if (mDelegate->GetDataset(currentActiveDataset, Delegate::DatasetType::kActive) == CHIP_NO_ERROR &&
12999
currentActiveDataset.GetActiveTimestamp(currentActiveDatasetTimestamp) == CHIP_NO_ERROR)
130100
{
131-
// If this command is invoked when the ActiveDatasetTimestamp attribute is not null, the command SHALL
132-
// fail with a status code of INVALID_IN_STATE.
133-
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidInState);
134-
return;
101+
return Status::InvalidInState;
135102
}
136103

137-
mPath = ctx.mRequestPath;
138-
mAsyncCommandHandle = CommandHandler::Handle(&ctx.mCommandHandler);
139-
ctx.mCommandHandler.FlushAcksRightAwayOnSlowCommand();
140104
mBreadcrumb = req.breadcrumb;
141-
CHIP_ERROR err = CHIP_NO_ERROR;
142-
if ((err = mDelegate->SetActiveDataset(activeDataset, this)) != CHIP_NO_ERROR)
143-
{
144-
OnActivateDatasetComplete(err);
145-
}
105+
CHIP_ERROR err = mDelegate->SetActiveDataset(activeDataset, this);
106+
return StatusIB(err).mStatus;
146107
}
147108

148-
void ServerInstance::HandleSetPendingDatasetRequest(HandlerContext & ctx,
149-
const Commands::SetPendingDatasetRequest::DecodableType & req)
109+
Status ServerInstance::HandleSetPendingDatasetRequest(const Commands::SetPendingDatasetRequest::DecodableType & req)
150110
{
151-
VerifyOrReturn(CheckDelegate(ctx, mDelegate));
111+
ReturnErrorCodeIf(!mDelegate, Status::InvalidInState);
152112
bool panChangeSupported;
153113
if (mDelegate->GetPanChangeSupported(panChangeSupported) != CHIP_NO_ERROR || !panChangeSupported)
154114
{
155-
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::UnsupportedCommand);
156-
return;
115+
return Status::UnsupportedCommand;
157116
}
158117
Thread::OperationalDataset pendingDataset;
159-
if (pendingDataset.Init(req.pendingDataset) != CHIP_NO_ERROR)
118+
// If any of the parameters in the PendingDataset is invalid, the command SHALL fail with a status code
119+
// of INVALID_COMMAND.
120+
ReturnErrorCodeIf(pendingDataset.Init(req.pendingDataset) != CHIP_NO_ERROR, Status::InvalidCommand);
121+
CHIP_ERROR err = mDelegate->SetPendingDataset(pendingDataset);
122+
return StatusIB(err).mStatus;
123+
}
124+
125+
void AddDatasetResponse(CommandHandlerInterface::HandlerContext & ctx, Status status, Thread::OperationalDataset & dataset)
126+
{
127+
if (status != Status::Success)
160128
{
161-
// If any of the parameters in the PendingDataset is invalid, the command SHALL fail with a status code
162-
// of INVALID_COMMAND.
163-
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand);
129+
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status);
164130
return;
165131
}
166-
CHIP_ERROR err = mDelegate->SetPendingDataset(pendingDataset);
167-
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, StatusIB(err).mStatus);
132+
Commands::DatasetResponse::Type response;
133+
response.dataset = dataset.AsByteSpan();
134+
ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response);
168135
}
169136

170-
void ServerInstance::InvokeCommand(HandlerContext & ctx)
137+
void ServerInstance::InvokeCommand(HandlerContext & ctxt)
171138
{
172-
switch (ctx.mRequestPath.mCommandId)
139+
switch (ctxt.mRequestPath.mCommandId)
173140
{
174141
case Commands::GetActiveDatasetRequest::Id:
175-
HandleCommand<Commands::GetActiveDatasetRequest::DecodableType>(
176-
ctx, [this](HandlerContext & ctx, const auto & req) { HandleGetActiveDatasetRequest(ctx, req); });
142+
HandleCommand<Commands::GetActiveDatasetRequest::DecodableType>(ctxt, [this](HandlerContext & ctx, const auto & req) {
143+
Thread::OperationalDataset dataset;
144+
Status status = HandleGetActiveDatasetRequest(IsOverCASESession(ctx), dataset);
145+
AddDatasetResponse(ctx, status, dataset);
146+
});
177147
break;
178148
case Commands::GetPendingDatasetRequest::Id:
179-
HandleCommand<Commands::GetPendingDatasetRequest::DecodableType>(
180-
ctx, [this](HandlerContext & ctx, const auto & req) { HandleGetPendingDatasetRequest(ctx, req); });
149+
HandleCommand<Commands::GetPendingDatasetRequest::DecodableType>(ctxt, [this](HandlerContext & ctx, const auto & req) {
150+
Thread::OperationalDataset dataset;
151+
Status status = HandleGetPendingDatasetRequest(IsOverCASESession(ctx), dataset);
152+
AddDatasetResponse(ctx, status, dataset);
153+
});
181154
break;
182155
case Commands::SetActiveDatasetRequest::Id:
183-
HandleCommand<Commands::SetActiveDatasetRequest::DecodableType>(
184-
ctx, [this](HandlerContext & ctx, const auto & req) { HandleSetActiveDatasetRequest(ctx, req); });
156+
HandleCommand<Commands::SetActiveDatasetRequest::DecodableType>(ctxt, [this](HandlerContext & ctx, const auto & req) {
157+
if (!mAsyncCommandHandle.Get())
158+
{
159+
mPath = ctx.mRequestPath;
160+
mAsyncCommandHandle = CommandHandler::Handle(&ctx.mCommandHandler);
161+
ctx.mCommandHandler.FlushAcksRightAwayOnSlowCommand();
162+
Status status = HandleSetActiveDatasetRequest(IsFailSafeArmed(ctx), req);
163+
if (status != Status::Success)
164+
{
165+
OnActivateDatasetComplete(ChipError(ChipError::SdkPart::kIMGlobalStatus, to_underlying(status)));
166+
}
167+
}
168+
else
169+
{
170+
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Busy);
171+
}
172+
});
185173
break;
186174
case Commands::SetPendingDatasetRequest::Id:
187-
HandleCommand<Commands::SetPendingDatasetRequest::DecodableType>(
188-
ctx, [this](HandlerContext & ctx, const auto & req) { HandleSetPendingDatasetRequest(ctx, req); });
175+
HandleCommand<Commands::SetPendingDatasetRequest::DecodableType>(ctxt, [this](HandlerContext & ctx, const auto & req) {
176+
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, HandleSetPendingDatasetRequest(req));
177+
});
189178
break;
190179
default:
191180
break;
192181
}
193182
}
194183

195-
CHIP_ERROR ServerInstance::ReadFeatureMap(AttributeValueEncoder & aEncoder)
184+
CHIP_ERROR ServerInstance::ReadFeatureMap(BitFlags<Feature> & featureMap)
196185
{
197-
BitFlags<Feature> featureMap;
198186
bool panChangeSupported;
199187
ReturnErrorOnFailure(mDelegate->GetPanChangeSupported(panChangeSupported));
200188
if (panChangeSupported)
201189
{
202190
featureMap.Set(Feature::kPANChange);
203191
}
204-
return aEncoder.Encode(featureMap);
192+
return CHIP_NO_ERROR;
205193
}
206194

207-
CHIP_ERROR ServerInstance::ReadBorderRouterName(AttributeValueEncoder & aEncoder)
195+
CHIP_ERROR ServerInstance::ReadBorderRouterName(MutableCharSpan & borderRouterName)
208196
{
209-
char borderRouterName[kBorderRouterNameMaxLength];
210-
MutableCharSpan borderRouterNameSpan(borderRouterName);
211-
ReturnErrorOnFailure(mDelegate->GetBorderRouterName(borderRouterNameSpan));
212-
return aEncoder.Encode(borderRouterNameSpan);
197+
ReturnErrorOnFailure(mDelegate->GetBorderRouterName(borderRouterName));
198+
ReturnErrorCodeIf(borderRouterName.size() > kBorderRouterNameMaxLength, CHIP_IM_GLOBAL_STATUS(ConstraintError));
199+
return CHIP_NO_ERROR;
213200
}
214201

215-
CHIP_ERROR ServerInstance::ReadBorderAgentID(AttributeValueEncoder & aEncoder)
202+
CHIP_ERROR ServerInstance::ReadBorderAgentID(MutableByteSpan & borderAgentId)
216203
{
217-
uint8_t borderAgentId[kBorderAgentIdLength];
218-
MutableByteSpan borderAgentIdSpan(borderAgentId);
219-
ReturnErrorOnFailure(mDelegate->GetBorderAgentId(borderAgentIdSpan));
220-
return aEncoder.Encode(borderAgentIdSpan);
204+
ReturnErrorOnFailure(mDelegate->GetBorderAgentId(borderAgentId));
205+
ReturnErrorCodeIf(borderAgentId.size() != kBorderAgentIdLength, CHIP_IM_GLOBAL_STATUS(ConstraintError));
206+
return CHIP_NO_ERROR;
221207
}
222208

223-
CHIP_ERROR ServerInstance::ReadThreadVersion(AttributeValueEncoder & aEncoder)
209+
CHIP_ERROR ServerInstance::ReadThreadVersion(uint16_t & threadVersion)
224210
{
225-
uint16_t threadVersion;
226-
ReturnErrorOnFailure(mDelegate->GetThreadVersion(threadVersion));
227-
return aEncoder.Encode(threadVersion);
211+
return mDelegate->GetThreadVersion(threadVersion);
228212
}
229213

230-
CHIP_ERROR ServerInstance::ReadInterfaceEnabled(AttributeValueEncoder & aEncoder)
214+
CHIP_ERROR ServerInstance::ReadInterfaceEnabled(bool & interfaceEnabled)
231215
{
232-
bool interfaceEnabled;
233-
ReturnErrorOnFailure(mDelegate->GetInterfaceEnabled(interfaceEnabled));
234-
return aEncoder.Encode(interfaceEnabled);
216+
return mDelegate->GetInterfaceEnabled(interfaceEnabled);
235217
}
236218

237-
CHIP_ERROR ServerInstance::ReadActiveDatasetTimestamp(AttributeValueEncoder & aEncoder)
219+
CHIP_ERROR ServerInstance::ReadActiveDatasetTimestamp(Optional<uint64_t> & activeDatasetTimestamp)
238220
{
221+
uint64_t activeDatasetTimestampValue;
239222
Thread::OperationalDataset activeDataset;
240-
uint64_t activeDatasetTimestamp;
241223
if (mDelegate->GetDataset(activeDataset, Delegate::DatasetType::kActive) == CHIP_NO_ERROR &&
242-
activeDataset.GetActiveTimestamp(activeDatasetTimestamp) == CHIP_NO_ERROR)
224+
activeDataset.GetActiveTimestamp(activeDatasetTimestampValue) == CHIP_NO_ERROR)
243225
{
244-
return aEncoder.Encode(DataModel::MakeNullable(activeDatasetTimestamp));
226+
activeDatasetTimestamp.SetValue(activeDatasetTimestampValue);
245227
}
246-
return aEncoder.EncodeNull();
228+
else
229+
{
230+
activeDatasetTimestamp.ClearValue();
231+
}
232+
return CHIP_NO_ERROR;
247233
}
248234

249235
CHIP_ERROR ServerInstance::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
@@ -260,24 +246,63 @@ CHIP_ERROR ServerInstance::Read(const ConcreteReadAttributePath & aPath, Attribu
260246
CHIP_ERROR status = CHIP_NO_ERROR;
261247
switch (aPath.mAttributeId)
262248
{
263-
case Globals::Attributes::FeatureMap::Id:
264-
status = ReadFeatureMap(aEncoder);
249+
case Globals::Attributes::FeatureMap::Id: {
250+
BitFlags<Feature> featureMap;
251+
status = ReadFeatureMap(featureMap);
252+
if (status == CHIP_NO_ERROR)
253+
{
254+
status = aEncoder.Encode(featureMap);
255+
}
265256
break;
266-
case Attributes::BorderRouterName::Id:
267-
status = ReadBorderRouterName(aEncoder);
257+
}
258+
case Attributes::BorderRouterName::Id: {
259+
char borderRouterNameBuf[kBorderRouterNameMaxLength + 1];
260+
MutableCharSpan borderRouterName(borderRouterNameBuf);
261+
status = ReadBorderRouterName(borderRouterName);
262+
if (status == CHIP_NO_ERROR)
263+
{
264+
status = aEncoder.Encode(borderRouterName);
265+
}
268266
break;
269-
case Attributes::BorderAgentID::Id:
270-
status = ReadBorderAgentID(aEncoder);
267+
}
268+
case Attributes::BorderAgentID::Id: {
269+
uint8_t borderAgentIDBuf[kBorderAgentIdLength];
270+
MutableByteSpan borderAgentID(borderAgentIDBuf);
271+
status = ReadBorderAgentID(borderAgentID);
272+
if (status == CHIP_NO_ERROR)
273+
{
274+
status = aEncoder.Encode(borderAgentID);
275+
}
271276
break;
272-
case Attributes::ThreadVersion::Id:
273-
status = ReadThreadVersion(aEncoder);
277+
}
278+
case Attributes::ThreadVersion::Id: {
279+
uint16_t threadVersion;
280+
status = ReadThreadVersion(threadVersion);
281+
if (status == CHIP_NO_ERROR)
282+
{
283+
status = aEncoder.Encode(threadVersion);
284+
}
274285
break;
275-
case Attributes::InterfaceEnabled::Id:
276-
status = ReadInterfaceEnabled(aEncoder);
286+
}
287+
case Attributes::InterfaceEnabled::Id: {
288+
bool interfaceEnabled;
289+
status = ReadInterfaceEnabled(interfaceEnabled);
290+
if (status == CHIP_NO_ERROR)
291+
{
292+
status = aEncoder.Encode(interfaceEnabled);
293+
}
277294
break;
278-
case Attributes::ActiveDatasetTimestamp::Id:
279-
status = ReadActiveDatasetTimestamp(aEncoder);
295+
}
296+
case Attributes::ActiveDatasetTimestamp::Id: {
297+
Optional<uint64_t> activeDatasetTimestamp;
298+
status = ReadActiveDatasetTimestamp(activeDatasetTimestamp);
299+
if (status == CHIP_NO_ERROR)
300+
{
301+
status = activeDatasetTimestamp.HasValue() ? aEncoder.Encode(DataModel::MakeNullable(activeDatasetTimestamp.Value()))
302+
: aEncoder.EncodeNull();
303+
}
280304
break;
305+
}
281306
default:
282307
break;
283308
}

0 commit comments

Comments
 (0)