diff --git a/.gitignore b/.gitignore index 1c2d1430263594..be50dcbd1dd1dd 100644 --- a/.gitignore +++ b/.gitignore @@ -85,3 +85,5 @@ examples/*/esp32/dependencies.lock # jupyter temporary files .ipynb_checkpoints +separate/ +src/python_testing/matter_testing_infrastructure/build/ diff --git a/src/app/clusters/general-commissioning-server/general-commissioning-server.cpp b/src/app/clusters/general-commissioning-server/general-commissioning-server.cpp index 6c1465873de433..46b7a03ea3d8f4 100644 --- a/src/app/clusters/general-commissioning-server/general-commissioning-server.cpp +++ b/src/app/clusters/general-commissioning-server/general-commissioning-server.cpp @@ -72,9 +72,6 @@ class GeneralCommissioningAttrAccess : public AttributeAccessInterface CHIP_ERROR ReadIfSupported(CHIP_ERROR (ConfigurationManager::*getter)(uint8_t &), AttributeValueEncoder & aEncoder); CHIP_ERROR ReadBasicCommissioningInfo(AttributeValueEncoder & aEncoder); CHIP_ERROR ReadSupportsConcurrentConnection(AttributeValueEncoder & aEncoder); - template - CHIP_ERROR ReadFromProvider(Provider * const aProvider, CHIP_ERROR (Provider::*const aConstGetter)(T &) const, - AttributeValueEncoder & aEncoder); }; GeneralCommissioningAttrAccess gAttrAccess; @@ -103,24 +100,24 @@ CHIP_ERROR GeneralCommissioningAttrAccess::Read(const ConcreteReadAttributePath } #if CHIP_CONFIG_TC_REQUIRED case TCAcceptedVersion::Id: { - auto provider = Server::GetInstance().GetEnhancedSetupFlowProvider(); - auto getter = &EnhancedSetupFlowProvider::GetTermsAndConditionsAcceptedAcknowledgementsVersion; - return ReadFromProvider(provider, getter, aEncoder); + Optional outTermsAndConditions; + Server::GetInstance().GetEnhancedSetupFlowProvider()->GetTermsAndConditionsAcknowledgements(outTermsAndConditions); + return !outTermsAndConditions.HasValue() ? aEncoder.Encode(0) : aEncoder.Encode(outTermsAndConditions.Value().version); } case TCMinRequiredVersion::Id: { - auto provider = Server::GetInstance().GetEnhancedSetupFlowProvider(); - auto getter = &EnhancedSetupFlowProvider::GetTermsAndConditionsRequiredAcknowledgementsVersion; - return ReadFromProvider(provider, getter, aEncoder); + Optional outTermsAndConditions; + Server::GetInstance().GetEnhancedSetupFlowProvider()->GetTermsAndConditionsRequirements(outTermsAndConditions); + return !outTermsAndConditions.HasValue() ? aEncoder.Encode(0) : aEncoder.Encode(outTermsAndConditions.Value().version); } case TCAcknowledgements::Id: { - auto provider = Server::GetInstance().GetEnhancedSetupFlowProvider(); - auto getter = &EnhancedSetupFlowProvider::GetTermsAndConditionsAcceptedAcknowledgements; - return ReadFromProvider(provider, getter, aEncoder); + Optional outTermsAndConditions; + Server::GetInstance().GetEnhancedSetupFlowProvider()->GetTermsAndConditionsAcknowledgements(outTermsAndConditions); + return !outTermsAndConditions.HasValue() ? aEncoder.Encode(0) : aEncoder.Encode(outTermsAndConditions.Value().value); } case TCAcknowledgementsRequired::Id: { - auto provider = Server::GetInstance().GetEnhancedSetupFlowProvider(); - auto getter = &EnhancedSetupFlowProvider::IsTermsAndConditionsAcceptanceRequired; - return ReadFromProvider(provider, getter, aEncoder); + Optional outTermsAndConditions; + Server::GetInstance().GetEnhancedSetupFlowProvider()->GetTermsAndConditionsRequirements(outTermsAndConditions); + return aEncoder.Encode(outTermsAndConditions.HasValue()); } #endif default: { @@ -172,93 +169,61 @@ CHIP_ERROR GeneralCommissioningAttrAccess::ReadSupportsConcurrentConnection(Attr return aEncoder.Encode(supportsConcurrentConnection); } -template -CHIP_ERROR GeneralCommissioningAttrAccess::ReadFromProvider(Provider * const aProvider, - CHIP_ERROR (Provider::*const aConstGetter)(T &) const, - AttributeValueEncoder & aEncoder) +#if CHIP_CONFIG_TC_REQUIRED +CommissioningErrorEnum CheckTermsAndConditionsAcknowledgementsState(const Optional & requiredTermsAndConditions, + const Optional & acceptedTermsAndConditions) { - if (nullptr == aProvider) + // No validation checks required if no required terms and conditions + if (!requiredTermsAndConditions.HasValue()) { - return CHIP_ERROR_PERSISTED_STORAGE_FAILED; + return CommissioningErrorEnum::kOk; } - T value; - CHIP_ERROR err = (aProvider->*aConstGetter)(value); - if (err != CHIP_NO_ERROR) + // Validate if we have received any terms and conditions acceptance + if (!acceptedTermsAndConditions.HasValue()) { - return err; + ChipLogError(AppServer, "Failed to HasReceivedTermsAndConditionsAcknowledgements"); + return CommissioningErrorEnum::kTCAcknowledgementsNotReceived; } - return aEncoder.Encode(value); -} - -#if CHIP_CONFIG_TC_REQUIRED -CHIP_ERROR checkTermsAndConditionsAcknowledgementsState(CommissioningErrorEnum & errorCode) -{ - EnhancedSetupFlowProvider * enhancedSetupFlowProvider = Server::GetInstance().GetEnhancedSetupFlowProvider(); - - CHIP_ERROR err; - - uint16_t termsAndConditionsAcceptedAcknowledgements; - bool hasAnyAcknowledgements; - bool hasRequiredTermAccepted; - bool hasRequiredTermVersionAccepted; - - err = enhancedSetupFlowProvider->HasReceivedTermsAndConditionscknowledgements(hasAnyAcknowledgements); - if (!::chip::ChipError::IsSuccess(err)) + // Validate the accepted version first... + if (requiredTermsAndConditions.Value().version > acceptedTermsAndConditions.Value().version) { - ChipLogError(AppServer, "Failed to HasReceivedTermsAndConditionscknowledgements"); - errorCode = CommissioningErrorEnum::kTCAcknowledgementsNotReceived; - return err; + ChipLogProgress(AppServer, "Minimum terms and conditions version, 0x%04x, has not been accepted", + requiredTermsAndConditions.Value().version); + return CommissioningErrorEnum::kTCMinVersionNotMet; } - err = enhancedSetupFlowProvider->GetTermsAndConditionsAcceptedAcknowledgements(termsAndConditionsAcceptedAcknowledgements); - if (!::chip::ChipError::IsSuccess(err)) + // Validate the accepted bits second... + if (requiredTermsAndConditions.Value().value != + (requiredTermsAndConditions.Value().value & acceptedTermsAndConditions.Value().value)) { - ChipLogError(AppServer, "Failed to GetTermsAndConditionsAcceptedAcknowledgements"); - return err; + ChipLogProgress(AppServer, "Required terms and conditions, 0x%04x,have not been accepted", + requiredTermsAndConditions.Value().value); + return CommissioningErrorEnum::kRequiredTCNotAccepted; } - err = enhancedSetupFlowProvider->HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted(hasRequiredTermAccepted); - if (!::chip::ChipError::IsSuccess(err)) - { - ChipLogError(AppServer, "Failed to HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted"); - return err; - } + // All validation check succeeded... + return CommissioningErrorEnum::kOk; +} - err = - enhancedSetupFlowProvider->HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted(hasRequiredTermVersionAccepted); - if (!::chip::ChipError::IsSuccess(err)) - { - ChipLogError(AppServer, "Failed to HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted"); - return err; - } +#if 0 +CHIP_ERROR CheckTermsAndConditionsAcknowledgementsStateOnCommissioningComplete(CommissioningErrorEnum & errorCode) +{ + EnhancedSetupFlowProvider * const enhancedSetupFlowProvider = Server::GetInstance().GetEnhancedSetupFlowProvider(); - if (!hasRequiredTermVersionAccepted) - { - uint16_t requiredAcknowledgementsVersion = 0; - (void) enhancedSetupFlowProvider->GetTermsAndConditionsRequiredAcknowledgementsVersion(requiredAcknowledgementsVersion); - ChipLogProgress(AppServer, "Minimum terms and conditions version, 0x%04x, has not been accepted", - requiredAcknowledgementsVersion); - errorCode = CommissioningErrorEnum::kTCMinVersionNotMet; - return CHIP_NO_ERROR; - } + Optional acceptedTermsAndConditions; + Optional requiredTermsAndConditions; - if (!hasRequiredTermAccepted) - { - uint16_t requiredAcknowledgements = 0; - (void) enhancedSetupFlowProvider->GetTermsAndConditionsRequiredAcknowledgements(requiredAcknowledgements); + enhancedSetupFlowProvider->GetTermsAndConditionsAcknowledgements(acceptedTermsAndConditions); + enhancedSetupFlowProvider->GetTermsAndConditionsRequirements(requiredTermsAndConditions); - ChipLogProgress(AppServer, "Required terms and conditions, 0x%04x,have not been accepted", requiredAcknowledgements); - errorCode = (0 == termsAndConditionsAcceptedAcknowledgements) ? CommissioningErrorEnum::kTCAcknowledgementsNotReceived - : CommissioningErrorEnum::kRequiredTCNotAccepted; - return CHIP_NO_ERROR; - } + errorCode = CheckTermsAndConditionsAcknowledgementsState(requiredTermsAndConditions, acceptedTermsAndConditions); + return (CommissioningErrorEnum::kOk == errorCode) ? CHIP_NO_ERROR : CHIP_ERROR_INCORRECT_STATE; - errorCode = CommissioningErrorEnum::kOk; - return CHIP_NO_ERROR; } #endif +#endif } // anonymous namespace @@ -356,7 +321,30 @@ bool emberAfGeneralCommissioningClusterCommissioningCompleteCallback( else { #if CHIP_CONFIG_TC_REQUIRED - CheckSuccess(checkTermsAndConditionsAcknowledgementsState(response.errorCode), Failure); + // CheckSuccess(CheckTermsAndConditionsAcknowledgementsStateOnCommissioningComplete(response.errorCode), Failure); + + EnhancedSetupFlowProvider * const enhancedSetupFlowProvider = Server::GetInstance().GetEnhancedSetupFlowProvider(); + + Optional acceptedTermsAndConditions; + Optional requiredTermsAndConditions; + + enhancedSetupFlowProvider->GetTermsAndConditionsAcknowledgements(acceptedTermsAndConditions); + enhancedSetupFlowProvider->GetTermsAndConditionsRequirements(requiredTermsAndConditions); + + ChipLogError(AppServer, "acceptedTermsAndConditions HasValue= %d", acceptedTermsAndConditions.HasValue()); + if (acceptedTermsAndConditions.HasValue()) + { + ChipLogError(AppServer, "acceptedTermsAndConditions Value= %d", acceptedTermsAndConditions.Value().value); + ChipLogError(AppServer, "acceptedTermsAndConditions Version= %d", acceptedTermsAndConditions.Value().version); + } + + response.errorCode = + CheckTermsAndConditionsAcknowledgementsState(requiredTermsAndConditions, acceptedTermsAndConditions); + if (CommissioningErrorEnum::kOk != response.errorCode) + { + commandObj->AddResponse(commandPath, response); + return true; + } #endif if (failSafe.NocCommandHasBeenInvoked()) @@ -375,6 +363,14 @@ bool emberAfGeneralCommissioningClusterCommissioningCompleteCallback( CheckSuccess(err, Failure); } +#if CHIP_CONFIG_TC_REQUIRED + if (failSafe.UpdateTermsAndConditionsHasBeenInvoked()) + { + // Commit terms and conditions acceptance on commissioning complete + Server::GetInstance().GetEnhancedSetupFlowProvider()->CommitTermsAndConditionsAcceptance(); + } +#endif + /* * Pass fabric of commissioner to DeviceControlSvr. * This allows device to send messages back to commissioner. @@ -456,16 +452,38 @@ bool emberAfGeneralCommissioningClusterSetTCAcknowledgementsCallback( return false; #else + MATTER_TRACE_SCOPE("SetTCAcknowledgements", "GeneralCommissioning"); + auto & failSafeContext = Server::GetInstance().GetFailSafeContext(); - MATTER_TRACE_SCOPE("SetTCAcknowledgements", "GeneralCommissioning"); Commands::SetTCAcknowledgementsResponse::Type response; EnhancedSetupFlowProvider * const enhancedSetupFlowProvider = Server::GetInstance().GetEnhancedSetupFlowProvider(); - uint16_t acknowledgements = commandData.TCUserResponse; - uint16_t acknowledgementsVersion = commandData.TCVersion; - CheckSuccess(enhancedSetupFlowProvider->SetTermsAndConditionsAcceptance(acknowledgements, acknowledgementsVersion), Failure); - CheckSuccess(checkTermsAndConditionsAcknowledgementsState(response.errorCode), Failure); - failSafeContext.SetUpdateTermsAndConditionsHasBeenInvoked(); + + Optional requiredTermsAndConditions; + + enhancedSetupFlowProvider->GetTermsAndConditionsRequirements(requiredTermsAndConditions); + + Optional acceptedTermsAndConditions = Optional({ + .value = commandData.TCUserResponse, + .version = commandData.TCVersion, + }); + + response.errorCode = CheckTermsAndConditionsAcknowledgementsState(requiredTermsAndConditions, acceptedTermsAndConditions); + + if (CommissioningErrorEnum::kOk == response.errorCode) + { + CheckSuccess(enhancedSetupFlowProvider->SetTermsAndConditionsAcceptance(acceptedTermsAndConditions), Failure); + + if (failSafeContext.IsFailSafeArmed()) + { + failSafeContext.SetUpdateTermsAndConditionsHasBeenInvoked(); + } + else + { + enhancedSetupFlowProvider->CommitTermsAndConditionsAcceptance(); + } + } + commandObj->AddResponse(commandPath, response); return true; @@ -486,18 +504,6 @@ void OnPlatformEventHandler(const DeviceLayer::ChipDeviceEvent * event, intptr_t // Clear terms and conditions acceptance on failsafe timer expiration Server::GetInstance().GetEnhancedSetupFlowProvider()->RevertTermsAndConditionsAcceptance(); } -#endif - } - - if (event->Type == DeviceLayer::DeviceEventType::kCommissioningComplete) - { -#if CHIP_CONFIG_TC_REQUIRED - auto & failSafeContext = Server::GetInstance().GetFailSafeContext(); - if (failSafeContext.UpdateTermsAndConditionsHasBeenInvoked()) - { - // Commit terms and conditions acceptance on commissioning complete - Server::GetInstance().GetEnhancedSetupFlowProvider()->CommitTermsAndConditionsAcceptance(); - } #endif } } diff --git a/src/app/server/DefaultEnhancedSetupFlowProvider.cpp b/src/app/server/DefaultEnhancedSetupFlowProvider.cpp index 9bcd0e4dc1acbc..f90ca2cb609140 100644 --- a/src/app/server/DefaultEnhancedSetupFlowProvider.cpp +++ b/src/app/server/DefaultEnhancedSetupFlowProvider.cpp @@ -30,129 +30,28 @@ CHIP_ERROR chip::app::DefaultEnhancedSetupFlowProvider::Init(TermsAndConditionsP return CHIP_NO_ERROR; } -CHIP_ERROR chip::app::DefaultEnhancedSetupFlowProvider::HasReceivedTermsAndConditionscknowledgements(bool & outReceived) const +CHIP_ERROR chip::app::DefaultEnhancedSetupFlowProvider::GetTermsAndConditionsAcknowledgements( + Optional & outTermsAndConditions) const { VerifyOrReturnError(nullptr != mTermsAndConditionsProvider, CHIP_ERROR_UNINITIALIZED); - ReturnErrorOnFailure(mTermsAndConditionsProvider->HasAcceptance(outReceived)); + ReturnErrorOnFailure(mTermsAndConditionsProvider->GetAcceptance(outTermsAndConditions)); return CHIP_NO_ERROR; } CHIP_ERROR -chip::app::DefaultEnhancedSetupFlowProvider::HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted(bool & outAccepted) const +chip::app::DefaultEnhancedSetupFlowProvider::GetTermsAndConditionsRequirements( + Optional & outTermsAndConditions) const { - uint16_t requiredAcknowledgements; - uint16_t requiredAcknowledgementsVersion; - uint16_t acceptedAcknowledgements; - uint16_t acceptedAcknowledgementsVersion; - VerifyOrReturnError(nullptr != mTermsAndConditionsProvider, CHIP_ERROR_UNINITIALIZED); - ReturnErrorOnFailure(mTermsAndConditionsProvider->GetRequirements(requiredAcknowledgements, requiredAcknowledgementsVersion)); - - if (0 == requiredAcknowledgements) - { - outAccepted = true; - return CHIP_NO_ERROR; - } - - ReturnErrorOnFailure(mTermsAndConditionsProvider->GetAcceptance(acceptedAcknowledgements, acceptedAcknowledgementsVersion)); - - outAccepted = ((requiredAcknowledgements & acceptedAcknowledgements) == requiredAcknowledgements); - + ReturnErrorOnFailure(mTermsAndConditionsProvider->GetRequirements(outTermsAndConditions)); return CHIP_NO_ERROR; } -CHIP_ERROR chip::app::DefaultEnhancedSetupFlowProvider::HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted( - bool & outAccepted) const +CHIP_ERROR chip::app::DefaultEnhancedSetupFlowProvider::SetTermsAndConditionsAcceptance( + const Optional & inTermsAndConditions) { - uint16_t requiredAcknowledgements; - uint16_t requiredAcknowledgementsVersion; - uint16_t acceptedAcknowledgements; - uint16_t acceptedAcknowledgementsVersion; - VerifyOrReturnError(nullptr != mTermsAndConditionsProvider, CHIP_ERROR_UNINITIALIZED); - ReturnErrorOnFailure(mTermsAndConditionsProvider->GetRequirements(requiredAcknowledgements, requiredAcknowledgementsVersion)); - - if (0 == requiredAcknowledgementsVersion) - { - outAccepted = true; - return CHIP_NO_ERROR; - } - - ReturnErrorOnFailure(mTermsAndConditionsProvider->GetAcceptance(acceptedAcknowledgements, acceptedAcknowledgementsVersion)); - - outAccepted = (acceptedAcknowledgementsVersion >= requiredAcknowledgementsVersion); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR chip::app::DefaultEnhancedSetupFlowProvider::IsTermsAndConditionsAcceptanceRequired(bool & outValue) const -{ - // Default implementation requires terms and conditions check only if not previously accepted. Other implementations may skip - // requiring a terms and conditions check on secondary commissioning, in the case that the required terms and conditions may - // have changed. - return HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted(outValue); -} - -CHIP_ERROR chip::app::DefaultEnhancedSetupFlowProvider::GetTermsAndConditionsRequiredAcknowledgements(uint16_t & outValue) const -{ - uint16_t requiredAcknowledgements; - uint16_t requiredAcknowledgementsVersion; - - VerifyOrReturnError(nullptr != mTermsAndConditionsProvider, CHIP_ERROR_UNINITIALIZED); - ReturnErrorOnFailure(mTermsAndConditionsProvider->GetRequirements(requiredAcknowledgements, requiredAcknowledgementsVersion)); - - outValue = requiredAcknowledgements; - - return CHIP_NO_ERROR; -} - -CHIP_ERROR -chip::app::DefaultEnhancedSetupFlowProvider::GetTermsAndConditionsRequiredAcknowledgementsVersion(uint16_t & outValue) const -{ - uint16_t requiredAcknowledgements; - uint16_t requiredAcknowledgementsVersion; - - VerifyOrReturnError(nullptr != mTermsAndConditionsProvider, CHIP_ERROR_UNINITIALIZED); - ReturnErrorOnFailure(mTermsAndConditionsProvider->GetRequirements(requiredAcknowledgements, requiredAcknowledgementsVersion)); - - outValue = requiredAcknowledgementsVersion; - - return CHIP_NO_ERROR; -} - -CHIP_ERROR chip::app::DefaultEnhancedSetupFlowProvider::GetTermsAndConditionsAcceptedAcknowledgements(uint16_t & outValue) const -{ - uint16_t acceptedAcknowledgements; - uint16_t acceptedAcknowledgementsVersion; - - VerifyOrReturnError(nullptr != mTermsAndConditionsProvider, CHIP_ERROR_UNINITIALIZED); - ReturnErrorOnFailure(mTermsAndConditionsProvider->GetAcceptance(acceptedAcknowledgements, acceptedAcknowledgementsVersion)); - - outValue = acceptedAcknowledgements; - - return CHIP_NO_ERROR; -} - -CHIP_ERROR -chip::app::DefaultEnhancedSetupFlowProvider::GetTermsAndConditionsAcceptedAcknowledgementsVersion(uint16_t & outValue) const -{ - uint16_t acceptedAcknowledgements; - uint16_t acceptedAcknowledgementsVersion; - - VerifyOrReturnError(nullptr != mTermsAndConditionsProvider, CHIP_ERROR_UNINITIALIZED); - ReturnErrorOnFailure(mTermsAndConditionsProvider->GetAcceptance(acceptedAcknowledgements, acceptedAcknowledgementsVersion)); - - outValue = acceptedAcknowledgementsVersion; - - return CHIP_NO_ERROR; -} - -CHIP_ERROR chip::app::DefaultEnhancedSetupFlowProvider::SetTermsAndConditionsAcceptance(uint16_t inTCAcknowledgementsValue, - uint16_t inTCAcknowledgementsVersionValue) -{ - VerifyOrReturnError(nullptr != mTermsAndConditionsProvider, CHIP_ERROR_UNINITIALIZED); - ReturnErrorOnFailure(mTermsAndConditionsProvider->SetAcceptance(inTCAcknowledgementsValue, inTCAcknowledgementsVersionValue)); - + ReturnErrorOnFailure(mTermsAndConditionsProvider->SetAcceptance(inTermsAndConditions)); return CHIP_NO_ERROR; } diff --git a/src/app/server/DefaultEnhancedSetupFlowProvider.h b/src/app/server/DefaultEnhancedSetupFlowProvider.h index 01a04269723b79..0dba132d306ec4 100644 --- a/src/app/server/DefaultEnhancedSetupFlowProvider.h +++ b/src/app/server/DefaultEnhancedSetupFlowProvider.h @@ -39,27 +39,15 @@ class DefaultEnhancedSetupFlowProvider : public EnhancedSetupFlowProvider */ CHIP_ERROR Init(TermsAndConditionsProvider * const inTermsAndConditionsProvider); - CHIP_ERROR HasReceivedTermsAndConditionscknowledgements(bool & outReceived) const override; + virtual CHIP_ERROR GetTermsAndConditionsAcknowledgements(Optional & outTermsAndConditions) const override; - CHIP_ERROR HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted(bool & outAccepted) const override; + virtual CHIP_ERROR GetTermsAndConditionsRequirements(Optional & outTermsAndConditions) const override; - CHIP_ERROR HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted(bool & outAccepted) const override; + virtual CHIP_ERROR SetTermsAndConditionsAcceptance(const Optional & inTermsAndConditions) override; - CHIP_ERROR IsTermsAndConditionsAcceptanceRequired(bool & outValue) const override; + virtual CHIP_ERROR RevertTermsAndConditionsAcceptance() override; - CHIP_ERROR GetTermsAndConditionsRequiredAcknowledgements(uint16_t & outValue) const override; - - CHIP_ERROR GetTermsAndConditionsRequiredAcknowledgementsVersion(uint16_t & outValue) const override; - - CHIP_ERROR GetTermsAndConditionsAcceptedAcknowledgements(uint16_t & outValue) const override; - - CHIP_ERROR GetTermsAndConditionsAcceptedAcknowledgementsVersion(uint16_t & outValue) const override; - - CHIP_ERROR SetTermsAndConditionsAcceptance(uint16_t aTCAcknowledgements, uint16_t inTCAcknowledgementsVersionValue) override; - - CHIP_ERROR CommitTermsAndConditionsAcceptance() override; - - CHIP_ERROR RevertTermsAndConditionsAcceptance() override; + virtual CHIP_ERROR CommitTermsAndConditionsAcceptance() override; private: TermsAndConditionsProvider * mTermsAndConditionsProvider; diff --git a/src/app/server/DefaultTermsAndConditionsProvider.cpp b/src/app/server/DefaultTermsAndConditionsProvider.cpp index b32a507b3c52fa..ba47a2391b3b7e 100644 --- a/src/app/server/DefaultTermsAndConditionsProvider.cpp +++ b/src/app/server/DefaultTermsAndConditionsProvider.cpp @@ -17,6 +17,7 @@ */ #include "DefaultTermsAndConditionsProvider.h" +#include "TermsAndConditionsProvider.h" #include #include @@ -38,25 +39,20 @@ constexpr size_t kEstimatedTlvBufferSize = chip::TLV::EstimateStructOverhead(siz 2; // Extra space for rollback compatibility } // namespace -CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::Init(chip::PersistentStorageDelegate * const inPersistentStorageDelegate, - uint16_t inRequiredAcknowledgementsValue, - uint16_t inRequiredAcknowledgementsVersionValue) +CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::Init(chip::PersistentStorageDelegate * const inPersistentStorageDelegate) { VerifyOrReturnError(nullptr != inPersistentStorageDelegate, CHIP_ERROR_INVALID_ARGUMENT); - mPersistentStorageDelegate = inPersistentStorageDelegate; - mRequiredAcknowledgementsValue = inRequiredAcknowledgementsValue; - mRequiredAcknowledgementsVersionValue = inRequiredAcknowledgementsVersionValue; + mPersistentStorageDelegate = inPersistentStorageDelegate; - uint16_t acknowledgementsAcceptanceValue = 0; - uint16_t acknowledgementsAcceptanceVersionValue = 0; + mRequiredAcknowledgements = Optional({ + .value = CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS, + .version = CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION, + }); - if (CHIP_NO_ERROR == LoadAcceptance(acknowledgementsAcceptanceValue, acknowledgementsAcceptanceVersionValue)) + if (CHIP_NO_ERROR == LoadAcceptance(mLatchedAcceptance)) { - mLatchedAcknowledgementsAcceptanceValue.SetValue(acknowledgementsAcceptanceValue); - mLatchedAcknowledgementsAcceptanceVersionValue.SetValue(acknowledgementsAcceptanceVersionValue); - mTemporaryAcknowledgementsAcceptanceValue = mLatchedAcknowledgementsAcceptanceValue; - mTemporaryAcknowledgementsAcceptanceVersionValue = mLatchedAcknowledgementsAcceptanceVersionValue; + mTemporalAcceptance.SetValue(mLatchedAcceptance.Value()); } return CHIP_NO_ERROR; @@ -64,89 +60,70 @@ CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::Init(chip::PersistentSt CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::RevertAcceptance() { - mTemporaryAcknowledgementsAcceptanceValue = mLatchedAcknowledgementsAcceptanceValue; - mTemporaryAcknowledgementsAcceptanceVersionValue = mLatchedAcknowledgementsAcceptanceVersionValue; - + ChipLogProgress(AppServer, "DefaultTermsAndConditionsProvider: RevertAcceptance"); + mTemporalAcceptance.SetValue(mLatchedAcceptance.Value()); return CHIP_NO_ERROR; } CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::CommitAcceptance() { - VerifyOrReturnError(mLatchedAcknowledgementsAcceptanceValue.HasValue() || mTemporaryAcknowledgementsAcceptanceValue.HasValue(), - CHIP_ERROR_INCORRECT_STATE); - VerifyOrReturnError(mLatchedAcknowledgementsAcceptanceVersionValue.HasValue() || - mTemporaryAcknowledgementsAcceptanceVersionValue.HasValue(), - CHIP_ERROR_INCORRECT_STATE); - - uint16_t acknowledgementsAcceptanceValue = - mTemporaryAcknowledgementsAcceptanceValue.ValueOr(mLatchedAcknowledgementsAcceptanceValue.HasValue()); - uint16_t acknowledgementsAcceptanceVersionValue = - mTemporaryAcknowledgementsAcceptanceVersionValue.ValueOr(mLatchedAcknowledgementsAcceptanceVersionValue.HasValue()); - - CHIP_ERROR err = StoreAcceptance(acknowledgementsAcceptanceValue, acknowledgementsAcceptanceVersionValue); - - if (CHIP_NO_ERROR == err) + if (!mTemporalAcceptance.HasValue()) { - mLatchedAcknowledgementsAcceptanceValue.SetValue(acknowledgementsAcceptanceValue); - mLatchedAcknowledgementsAcceptanceVersionValue.SetValue(acknowledgementsAcceptanceVersionValue); + return CHIP_NO_ERROR; } - return err; + mLatchedAcceptance.SetValue(mTemporalAcceptance.Value()); + return StoreAcceptance(mLatchedAcceptance); } -CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::GetAcceptance(uint16_t & outAcknowledgementsValue, - uint16_t & outAcknowledgementsVersionValue) const +CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::GetAcceptance(Optional & outTermsAndConditions) const { - VerifyOrReturnError(mTemporaryAcknowledgementsAcceptanceValue.HasValue(), CHIP_ERROR_INCORRECT_STATE); - VerifyOrReturnError(mTemporaryAcknowledgementsAcceptanceVersionValue.HasValue(), CHIP_ERROR_INCORRECT_STATE); + ChipLogProgress(AppServer, "DefaultTermsAndConditionsProvider: GetAcceptance"); - outAcknowledgementsValue = mTemporaryAcknowledgementsAcceptanceValue.Value(); - outAcknowledgementsVersionValue = mTemporaryAcknowledgementsAcceptanceVersionValue.Value(); + if (!mTemporalAcceptance.HasValue()) + { + return CHIP_ERROR_INCORRECT_STATE; + } + outTermsAndConditions.SetValue(mTemporalAcceptance.Value()); return CHIP_NO_ERROR; } -CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::GetRequirements(uint16_t & outAcknowledgementsValue, - uint16_t & outAcknowledgementsVersionValue) const +CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::GetRequirements(Optional & outTermsAndConditions) const { - outAcknowledgementsValue = mRequiredAcknowledgementsValue; - outAcknowledgementsVersionValue = mRequiredAcknowledgementsVersionValue; + ChipLogProgress(AppServer, "DefaultTermsAndConditionsProvider: GetRequirements"); - return CHIP_NO_ERROR; -} - -CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::HasAcceptance(bool & outHasAcceptance) const -{ - outHasAcceptance = - mTemporaryAcknowledgementsAcceptanceValue.HasValue() && mTemporaryAcknowledgementsAcceptanceVersionValue.HasValue(); + if (!mRequiredAcknowledgements.HasValue()) + { + return CHIP_ERROR_INCORRECT_STATE; + } + outTermsAndConditions.SetValue(mRequiredAcknowledgements.Value()); return CHIP_NO_ERROR; } CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::ResetAcceptance() { + ChipLogProgress(AppServer, "DefaultTermsAndConditionsProvider: ResetAcceptance"); VerifyOrReturnError(nullptr != mPersistentStorageDelegate, CHIP_ERROR_UNINITIALIZED); const chip::StorageKeyName storageKey = DefaultStorageKeyAllocator::TermsAndConditionsAcceptance(); ReturnErrorOnFailure(mPersistentStorageDelegate->SyncDeleteKeyValue(storageKey.KeyName())); - mLatchedAcknowledgementsAcceptanceValue.ClearValue(); - mLatchedAcknowledgementsAcceptanceVersionValue.ClearValue(); - ReturnErrorOnFailure(RevertAcceptance()); + mLatchedAcceptance.ClearValue(); + mTemporalAcceptance.ClearValue(); return CHIP_NO_ERROR; } -CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::SetAcceptance(uint16_t inAcceptedAcknowledgementsValue, - uint16_t inAcceptedAcknowledgementsVersionValue) +CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::SetAcceptance(const Optional & inTermsAndConditions) { - mTemporaryAcknowledgementsAcceptanceValue.SetValue(inAcceptedAcknowledgementsValue); - mTemporaryAcknowledgementsAcceptanceVersionValue.SetValue(inAcceptedAcknowledgementsVersionValue); + ChipLogProgress(AppServer, "DefaultTermsAndConditionsProvider: SetAcceptance"); + mTemporalAcceptance.SetValue(inTermsAndConditions.Value()); return CHIP_NO_ERROR; } -CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::LoadAcceptance(uint16_t & outAcknowledgementsValue, - uint16_t & outAcknowledgementsVersionValue) +CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::LoadAcceptance(Optional & outTermsAndConditions) { uint8_t serializationVersion = 0; uint16_t acknowledgements = 0; @@ -158,16 +135,19 @@ CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::LoadAcceptance(uint16_t uint8_t buffer[kEstimatedTlvBufferSize] = { 0 }; uint16_t bufferSize = sizeof(buffer); + ChipLogProgress(AppServer, "DefaultTermsAndConditionsProvider: LoadAcceptance"); + VerifyOrReturnError(nullptr != mPersistentStorageDelegate, CHIP_ERROR_UNINITIALIZED); const chip::StorageKeyName storageKey = DefaultStorageKeyAllocator::TermsAndConditionsAcceptance(); CHIP_ERROR err = mPersistentStorageDelegate->SyncGetKeyValue(storageKey.KeyName(), &buffer, bufferSize); if (CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND == err) { - outAcknowledgementsValue = acknowledgements; - outAcknowledgementsVersionValue = acknowledgementsVersion; - - return CHIP_NO_ERROR; + // outTermsAndConditions.SetValue({ + // .value = acknowledgements, + // .version = acknowledgementsVersion, + // }); + return CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; } VerifyOrReturnError(CHIP_NO_ERROR == err, err); @@ -188,28 +168,30 @@ CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::LoadAcceptance(uint16_t return CHIP_ERROR_VERSION_MISMATCH; } - outAcknowledgementsValue = acknowledgements; - outAcknowledgementsVersionValue = acknowledgementsVersion; + outTermsAndConditions.SetValue({ + .value = acknowledgements, + .version = acknowledgementsVersion, + }); return CHIP_NO_ERROR; } -CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::StoreAcceptance(uint16_t inAcknowledgementsValue, - uint16_t inAcknowledgementsVersionValue) +CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::StoreAcceptance(const Optional & inTermsAndConditions) { uint8_t buffer[kEstimatedTlvBufferSize] = { 0 }; chip::TLV::TLVWriter tlvWriter; chip::TLV::TLVType tlvContainer; + ChipLogProgress(AppServer, "DefaultTermsAndConditionsProvider: StoreAcceptance"); + VerifyOrReturnError(nullptr != mPersistentStorageDelegate, CHIP_ERROR_UNINITIALIZED); - VerifyOrReturnError(mTemporaryAcknowledgementsAcceptanceValue.HasValue(), CHIP_ERROR_INCORRECT_STATE); - VerifyOrReturnError(mTemporaryAcknowledgementsAcceptanceVersionValue.HasValue(), CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(inTermsAndConditions.HasValue(), CHIP_ERROR_INCORRECT_STATE); tlvWriter.Init(buffer, sizeof(buffer)); ReturnErrorOnFailure(tlvWriter.StartContainer(chip::TLV::AnonymousTag(), chip::TLV::kTLVType_Structure, tlvContainer)); ReturnErrorOnFailure(tlvWriter.Put(kSerializationVersionTag, kSerializationVersion)); - ReturnErrorOnFailure(tlvWriter.Put(kAcceptedAcknowledgementsTag, inAcknowledgementsValue)); - ReturnErrorOnFailure(tlvWriter.Put(kAcceptedAcknowledgementsVersionTag, inAcknowledgementsVersionValue)); + ReturnErrorOnFailure(tlvWriter.Put(kAcceptedAcknowledgementsTag, inTermsAndConditions.Value().value)); + ReturnErrorOnFailure(tlvWriter.Put(kAcceptedAcknowledgementsVersionTag, inTermsAndConditions.Value().version)); ReturnErrorOnFailure(tlvWriter.EndContainer(tlvContainer)); ReturnErrorOnFailure(tlvWriter.Finalize()); uint32_t lengthWritten = tlvWriter.GetLengthWritten(); diff --git a/src/app/server/DefaultTermsAndConditionsProvider.h b/src/app/server/DefaultTermsAndConditionsProvider.h index c68293d5143642..4593dcbfd32661 100644 --- a/src/app/server/DefaultTermsAndConditionsProvider.h +++ b/src/app/server/DefaultTermsAndConditionsProvider.h @@ -38,37 +38,30 @@ class DefaultTermsAndConditionsProvider : public TermsAndConditionsProvider * @param[in] inRequiredAcknowledgementsValue The bitmask of required acknowledgements. * @param[in] inRequiredAcknowledgementsVersionValue The version of the required acknowledgements. */ - CHIP_ERROR Init(PersistentStorageDelegate * const inPersistentStorageDelegate, uint16_t inRequiredAcknowledgementsValue, - uint16_t inRequiredAcknowledgementsVersionValue); + CHIP_ERROR Init(PersistentStorageDelegate * const inPersistentStorageDelegate); - CHIP_ERROR CommitAcceptance() override; - - CHIP_ERROR GetAcceptance(uint16_t & outAcknowledgementsValue, uint16_t & outAcknowledgementsVersionValue) const override; + CHIP_ERROR SetAcceptance(const Optional & inTermsAndConditions) override; - CHIP_ERROR GetRequirements(uint16_t & outAcknowledgementsValue, uint16_t & outAcknowledgementsVersionValue) const override; + CHIP_ERROR CommitAcceptance() override; - CHIP_ERROR HasAcceptance(bool & outHasAcceptance) const override; + CHIP_ERROR RevertAcceptance() override; CHIP_ERROR ResetAcceptance() override; - CHIP_ERROR RevertAcceptance() override; + CHIP_ERROR GetAcceptance(Optional & outTermsAndConditions) const override; - CHIP_ERROR SetAcceptance(uint16_t inAcknowledgementsValue, uint16_t inAcknowledgementsVersionValue) override; + CHIP_ERROR GetRequirements(Optional & outTermsAndConditions) const override; private: - CHIP_ERROR LoadAcceptance(uint16_t & outAcknowledgementsValue, uint16_t & outAcknowledgementsVersionValue); + CHIP_ERROR LoadAcceptance(Optional & outTermsAndConditions); - CHIP_ERROR StoreAcceptance(uint16_t inAcknowledgementsValue, uint16_t inAcknowledgementsVersionValue); + CHIP_ERROR StoreAcceptance(const Optional & inTermsAndConditions); PersistentStorageDelegate * mPersistentStorageDelegate; - uint16_t mRequiredAcknowledgementsValue; - uint16_t mRequiredAcknowledgementsVersionValue; - - Optional mLatchedAcknowledgementsAcceptanceValue; - Optional mLatchedAcknowledgementsAcceptanceVersionValue; - Optional mTemporaryAcknowledgementsAcceptanceValue; - Optional mTemporaryAcknowledgementsAcceptanceVersionValue; + Optional mLatchedAcceptance; + Optional mTemporalAcceptance; + Optional mRequiredAcknowledgements; }; } // namespace app diff --git a/src/app/server/EnhancedSetupFlowProvider.h b/src/app/server/EnhancedSetupFlowProvider.h index fd9862fd69ef2c..e4b5ce7ce89864 100644 --- a/src/app/server/EnhancedSetupFlowProvider.h +++ b/src/app/server/EnhancedSetupFlowProvider.h @@ -22,6 +22,8 @@ #include +#include "TermsAndConditionsProvider.h" + namespace chip { namespace app { @@ -33,55 +35,12 @@ class EnhancedSetupFlowProvider public: virtual ~EnhancedSetupFlowProvider() = default; - virtual CHIP_ERROR HasReceivedTermsAndConditionscknowledgements(bool & outReceived) const = 0; - - /** - * @param[out] outAccepted true if the required acknowledgements have been accepted, false otherwise. - */ - virtual CHIP_ERROR HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted(bool & outAccepted) const = 0; - - /** - * @param[out] outAccepted true if the required acknowledgements version has been accepted, false otherwise. - */ - virtual CHIP_ERROR HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted(bool & outAccepted) const = 0; - - /** - * @param[out] outValue true if terms and conditions acceptance is required before commissioning complete may succeed, false - * otherwise. - */ - virtual CHIP_ERROR IsTermsAndConditionsAcceptanceRequired(bool & outValue) const = 0; - - /** - * @param[out] outValue The version of the required acknowledgements. - */ - virtual CHIP_ERROR GetTermsAndConditionsRequiredAcknowledgements(uint16_t & outValue) const = 0; - - /** - * @param[out] outValue The outValue of the required acknowledgements version. - */ - virtual CHIP_ERROR GetTermsAndConditionsRequiredAcknowledgementsVersion(uint16_t & outValue) const = 0; - - /** - * @param[out] outValue The outValue of the accepted acknowledgements. - */ - virtual CHIP_ERROR GetTermsAndConditionsAcceptedAcknowledgements(uint16_t & outValue) const = 0; + virtual CHIP_ERROR GetTermsAndConditionsAcknowledgements(Optional & outTermsAndConditions) const = 0; - /** - * @param[out] outValue The outValue of the accepted acknowledgements version. - */ - virtual CHIP_ERROR GetTermsAndConditionsAcceptedAcknowledgementsVersion(uint16_t & outValue) const = 0; + virtual CHIP_ERROR GetTermsAndConditionsRequirements(Optional & outTermsAndConditions) const = 0; - /** - * @param[in] inTCAcknowledgements The acknowledgements to accept. - * @param[in] inTCAcknowledgementsVersionValue The version of the acknowledgements to accept. - */ - virtual CHIP_ERROR SetTermsAndConditionsAcceptance(uint16_t inTCAcknowledgementsValue, - uint16_t inTCAcknowledgementsVersionValue) = 0; + virtual CHIP_ERROR SetTermsAndConditionsAcceptance(const Optional & inTermsAndConditions) = 0; - /** - * Reset the terms and conditions acceptance. The terms and conditions should be cleared on factory reset or if failure occurs - * during a failsafe context. - */ virtual CHIP_ERROR RevertTermsAndConditionsAcceptance() = 0; virtual CHIP_ERROR CommitTermsAndConditionsAcceptance() = 0; diff --git a/src/app/server/Server.h b/src/app/server/Server.h index cb8ab12f40f547..d6e19cb6b6f767 100644 --- a/src/app/server/Server.h +++ b/src/app/server/Server.h @@ -317,9 +317,7 @@ struct CommonCaseDeviceServerInitParams : public ServerInitParams static app::DefaultTermsAndConditionsProvider sDefaultTermsAndConditionsProviderInstance; if (this->termsAndConditionsProvider == nullptr) { - ReturnErrorOnFailure(sDefaultTermsAndConditionsProviderInstance.Init(this->persistentStorageDelegate, - CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS, - CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION)); + ReturnErrorOnFailure(sDefaultTermsAndConditionsProviderInstance.Init(this->persistentStorageDelegate)); this->termsAndConditionsProvider = &sDefaultTermsAndConditionsProviderInstance; } diff --git a/src/app/server/TermsAndConditionsProvider.h b/src/app/server/TermsAndConditionsProvider.h index 45268d78baf23f..1875a48417e058 100644 --- a/src/app/server/TermsAndConditionsProvider.h +++ b/src/app/server/TermsAndConditionsProvider.h @@ -22,10 +22,17 @@ #include #include +#include namespace chip { namespace app { +typedef struct sTermsAndConditions +{ + uint16_t value; + uint16_t version; +} TermsAndConditions; + /** * @brief Data access layer for the required terms and conditions and the store for the user acceptance. */ @@ -35,9 +42,12 @@ class TermsAndConditionsProvider virtual ~TermsAndConditionsProvider() = default; /** - * @brief Clear the temporary acceptance status of the required terms and conditions. + * @brief Sets the acceptance status of the required terms and conditions. + * + * @param[in] inAcknowledgementsValue The bitmask of acknowledgements that was accepted. + * @param[in] inAcknowledgementsVersionValue The version of the acknowledgements that was accepted. */ - virtual CHIP_ERROR RevertAcceptance() = 0; + virtual CHIP_ERROR SetAcceptance(const Optional & inTermsAndConditions) = 0; /** * @brief Commit the persistent acceptance status of the required terms and conditions. @@ -45,40 +55,30 @@ class TermsAndConditionsProvider virtual CHIP_ERROR CommitAcceptance() = 0; /** - * @brief Retrieves the latest acceptance status of the required terms and conditions. - * - * @param[out] outAcknowledgementsValue The bitmask of acknowledgements accepted. - * @param[out] outAcknowledgementsVersionValue The version of the accepted acknowledgements. + * @brief Clear the temporary acceptance status of the required terms and conditions. */ - virtual CHIP_ERROR GetAcceptance(uint16_t & outAcknowledgementsValue, uint16_t & outAcknowledgementsVersionValue) const = 0; + virtual CHIP_ERROR RevertAcceptance() = 0; /** - * @brief Retrieves the requirements of the terms and conditions. - * - * @param[out] outAcknowledgementsValue The bitmask of required acknowledgements. - * @param[out] outAcknowledgementsVersionValue The version of the required acknowledgements. + * @brief Reset the persisted acceptance status of the required terms and conditions. */ - virtual CHIP_ERROR GetRequirements(uint16_t & outAcknowledgementsValue, uint16_t & outAcknowledgementsVersionValue) const = 0; + virtual CHIP_ERROR ResetAcceptance() = 0; /** - * @brief Retrieve if any terms and conditions has been set. + * @brief Retrieves the latest acceptance status of the required terms and conditions. * - * @param[out] outHasAcceptance True if any acceptance has been set. - */ - virtual CHIP_ERROR HasAcceptance(bool & outHasAcceptance) const = 0; - - /** - * @brief Reset the persisted acceptance status of the required terms and conditions. + * @param[out] outAcknowledgementsValue The bitmask of acknowledgements accepted. + * @param[out] outAcknowledgementsVersionValue The version of the accepted acknowledgements. */ - virtual CHIP_ERROR ResetAcceptance() = 0; + virtual CHIP_ERROR GetAcceptance(Optional & outTermsAndConditions) const = 0; /** - * @brief Sets the acceptance status of the required terms and conditions. + * @brief Retrieves the requirements of the terms and conditions. * - * @param[in] inAcknowledgementsValue The bitmask of acknowledgements that was accepted. - * @param[in] inAcknowledgementsVersionValue The version of the acknowledgements that was accepted. + * @param[out] outAcknowledgementsValue The bitmask of required acknowledgements. + * @param[out] outAcknowledgementsVersionValue The version of the required acknowledgements. */ - virtual CHIP_ERROR SetAcceptance(uint16_t inAcknowledgementsValue, uint16_t inAcknowledgementsVersionValue) = 0; + virtual CHIP_ERROR GetRequirements(Optional & outTermsAndConditions) const = 0; }; } // namespace app diff --git a/src/app/tests/TestDefaultEnhancedSetupFlowProvider.cpp b/src/app/tests/TestDefaultEnhancedSetupFlowProvider.cpp index 8ef94119ef54ee..24213068e6b1a2 100644 --- a/src/app/tests/TestDefaultEnhancedSetupFlowProvider.cpp +++ b/src/app/tests/TestDefaultEnhancedSetupFlowProvider.cpp @@ -54,6 +54,8 @@ class FakeTermsAndConditionsProvider : public chip::app::TermsAndConditionsProvi return CHIP_NO_ERROR; } + CHIP_ERROR HasAcceptance(bool & outHasAcceptance) const override { return CHIP_NO_ERROR; } + CHIP_ERROR SetAcceptance(uint16_t inAcknowledgements, uint16_t inAcknowledgementsVersion) override { mAcceptedAcknowledgements = inAcknowledgements; diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index c1b788aca643bd..8f2448a720977c 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -3207,6 +3207,7 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio if (!params.GetRequireTermsAndConditionsAcknowledgement()) { + ChipLogProgress(Controller, "Setting Terms and Conditions: Skipped"); CommissioningStageComplete(CHIP_NO_ERROR); return; } @@ -3222,6 +3223,8 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio TermsAndConditionsAcknowledgement termsAndConditionsAcknowledgement = params.GetTermsAndConditionsAcknowledgement().Value(); request.TCUserResponse = termsAndConditionsAcknowledgement.acceptedTermsAndConditions; request.TCVersion = termsAndConditionsAcknowledgement.acceptedTermsAndConditionsVersion; + + ChipLogProgress(Controller, "Setting Terms and Conditions: %hu, %hu", request.TCUserResponse, request.TCVersion); CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnSetTCAcknowledgementsResponse, OnBasicFailure, endpoint, timeout); if (err != CHIP_NO_ERROR) diff --git a/src/controller/python/ChipDeviceController-ScriptBinding.cpp b/src/controller/python/ChipDeviceController-ScriptBinding.cpp index b31cb5b7b8a4e6..460f707cdb3a73 100644 --- a/src/controller/python/ChipDeviceController-ScriptBinding.cpp +++ b/src/controller/python/ChipDeviceController-ScriptBinding.cpp @@ -181,6 +181,9 @@ PyChipError pychip_DeviceController_OpenCommissioningWindow(chip::Controller::De bool pychip_DeviceController_GetIPForDiscoveredDevice(chip::Controller::DeviceCommissioner * devCtrl, int idx, char * addrStr, uint32_t len); +PyChipError pychip_DeviceController_SetRequireTermsAndConditionsAcknowledgement(bool tcRequired); +PyChipError pychip_DeviceController_SetTermsAcknowledgements(uint16_t tcVersion, uint16_t tcUserResponse); +PyChipError pychip_DeviceController_SetSkipCommissioningComplete(bool skipCommissioningComplete); // Pairing Delegate PyChipError @@ -570,6 +573,25 @@ PyChipError pychip_DeviceController_SetDefaultNtp(const char * defaultNTP) return ToPyChipError(CHIP_NO_ERROR); } +PyChipError pychip_DeviceController_SetRequireTermsAndConditionsAcknowledgement(bool tcRequired) +{ + sCommissioningParameters.SetRequireTermsAndConditionsAcknowledgement(tcRequired); + return ToPyChipError(CHIP_NO_ERROR); +} + +PyChipError pychip_DeviceController_SetTermsAcknowledgements(uint16_t tcVersion, uint16_t tcUserResponse) +{ + sCommissioningParameters.SetTermsAndConditionsAcknowledgement( + { .acceptedTermsAndConditions = tcUserResponse, .acceptedTermsAndConditionsVersion = tcVersion }); + return ToPyChipError(CHIP_NO_ERROR); +} + +PyChipError pychip_DeviceController_SetSkipCommissioningComplete(bool skipCommissioningComplete) +{ + sCommissioningParameters.SetSkipCommissioningComplete(skipCommissioningComplete); + return ToPyChipError(CHIP_NO_ERROR); +} + PyChipError pychip_DeviceController_SetTrustedTimeSource(chip::NodeId nodeId, chip::EndpointId endpoint) { chip::app::Clusters::TimeSynchronization::Structs::FabricScopedTrustedTimeSourceStruct::Type timeSource = { .nodeID = nodeId, @@ -839,11 +861,7 @@ PyChipError pychip_IsSessionOverTCPConnection(chip::OperationalDeviceProxy * dev VerifyOrReturnError(deviceProxy->GetSecureSession().HasValue(), ToPyChipError(CHIP_ERROR_MISSING_SECURE_SESSION)); VerifyOrReturnError(isSessionOverTCP != nullptr, ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT)); -#if INET_CONFIG_ENABLE_TCP_ENDPOINT *isSessionOverTCP = deviceProxy->GetSecureSession().Value()->AsSecureSession()->GetTCPConnection() != nullptr; -#else - *isSessionOverTCP = false; -#endif return ToPyChipError(CHIP_NO_ERROR); } @@ -863,7 +881,6 @@ PyChipError pychip_IsActiveSession(chip::OperationalDeviceProxy * deviceProxy, b PyChipError pychip_CloseTCPConnectionWithPeer(chip::OperationalDeviceProxy * deviceProxy) { -#if INET_CONFIG_ENABLE_TCP_ENDPOINT VerifyOrReturnError(deviceProxy->GetSecureSession().HasValue(), ToPyChipError(CHIP_ERROR_MISSING_SECURE_SESSION)); VerifyOrReturnError(deviceProxy->GetSecureSession().Value()->AsSecureSession()->AllowsLargePayload(), ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT)); @@ -872,9 +889,6 @@ PyChipError pychip_CloseTCPConnectionWithPeer(chip::OperationalDeviceProxy * dev deviceProxy->GetSecureSession().Value()->AsSecureSession()->GetTCPConnection(), /* shouldAbort = */ false); return ToPyChipError(CHIP_NO_ERROR); -#else - return ToPyChipError(CHIP_ERROR_NOT_IMPLEMENTED); -#endif } PyChipError pychip_FreeOperationalDeviceProxy(chip::OperationalDeviceProxy * deviceProxy) diff --git a/src/controller/python/chip/ChipDeviceCtrl.py b/src/controller/python/chip/ChipDeviceCtrl.py index 24fe59486f78d5..e5a604a0771214 100644 --- a/src/controller/python/chip/ChipDeviceCtrl.py +++ b/src/controller/python/chip/ChipDeviceCtrl.py @@ -1351,12 +1351,8 @@ def _parseAttributePathTuple(self, pathTuple: typing.Union[ # Wildcard attribute id typing.Tuple[int, typing.Type[ClusterObjects.Cluster]], # Concrete path - typing.Tuple[int, typing.Type[ClusterObjects.ClusterAttributeDescriptor]], - # Directly specified attribute path - ClusterAttribute.AttributePath + typing.Tuple[int, typing.Type[ClusterObjects.ClusterAttributeDescriptor]] ]): - if isinstance(pathTuple, ClusterAttribute.AttributePath): - return pathTuple if pathTuple == ('*') or pathTuple == (): # Wildcard return ClusterAttribute.AttributePath() @@ -1441,9 +1437,7 @@ async def Read(self, nodeid: int, attributes: typing.Optional[typing.List[typing # Wildcard attribute id typing.Tuple[int, typing.Type[ClusterObjects.Cluster]], # Concrete path - typing.Tuple[int, typing.Type[ClusterObjects.ClusterAttributeDescriptor]], - # Directly specified attribute path - ClusterAttribute.AttributePath + typing.Tuple[int, typing.Type[ClusterObjects.ClusterAttributeDescriptor]] ]]] = None, dataVersionFilters: typing.Optional[typing.List[typing.Tuple[int, typing.Type[ClusterObjects.Cluster], int]]] = None, events: typing.Optional[typing.List[ typing.Union[ @@ -1482,8 +1476,6 @@ async def Read(self, nodeid: int, attributes: typing.Optional[typing.List[typing ReadAttribute(1, [ Clusters.BasicInformation ] ) -- case 5 above. ReadAttribute(1, [ (1, Clusters.BasicInformation.Attributes.Location ] ) -- case 1 above. - An AttributePath can also be specified directly by [chip.cluster.Attribute.AttributePath(...)] - dataVersionFilters: A list of tuples of (endpoint, cluster, data version). events: A list of tuples of varying types depending on the type of read being requested: @@ -1551,9 +1543,7 @@ async def ReadAttribute(self, nodeid: int, attributes: typing.Optional[typing.Li # Wildcard attribute id typing.Tuple[int, typing.Type[ClusterObjects.Cluster]], # Concrete path - typing.Tuple[int, typing.Type[ClusterObjects.ClusterAttributeDescriptor]], - # Directly specified attribute path - ClusterAttribute.AttributePath + typing.Tuple[int, typing.Type[ClusterObjects.ClusterAttributeDescriptor]] ]]], dataVersionFilters: typing.Optional[typing.List[typing.Tuple[int, typing.Type[ClusterObjects.Cluster], int]]] = None, returnClusterObject: bool = False, reportInterval: typing.Optional[typing.Tuple[int, int]] = None, @@ -1578,8 +1568,6 @@ async def ReadAttribute(self, nodeid: int, attributes: typing.Optional[typing.Li ReadAttribute(1, [ Clusters.BasicInformation ] ) -- case 5 above. ReadAttribute(1, [ (1, Clusters.BasicInformation.Attributes.Location ] ) -- case 1 above. - An AttributePath can also be specified directly by [chip.cluster.Attribute.AttributePath(...)] - returnClusterObject: This returns the data as consolidated cluster objects, with all attributes for a cluster inside a single cluster-wide cluster object. @@ -1938,6 +1926,15 @@ def _InitLib(self): self._dmLib.pychip_DeviceProxy_GetRemoteSessionParameters.restype = PyChipError self._dmLib.pychip_DeviceProxy_GetRemoteSessionParameters.argtypes = [c_void_p, c_char_p] + self._dmLib.pychip_DeviceController_SetSkipCommissioningComplete.restype = PyChipError + self._dmLib.pychip_DeviceController_SetSkipCommissioningComplete.argtypes = [c_bool] + + self._dmLib.pychip_DeviceController_SetRequireTermsAndConditionsAcknowledgement.restype = PyChipError + self._dmLib.pychip_DeviceController_SetRequireTermsAndConditionsAcknowledgement.argtypes = [c_bool] + + self._dmLib.pychip_DeviceController_SetTermsAcknowledgements.restype = PyChipError + self._dmLib.pychip_DeviceController_SetTermsAcknowledgements.argtypes = [c_uint16, c_uint16] + class ChipDeviceController(ChipDeviceControllerBase): ''' The ChipDeviceCommissioner binding, named as ChipDeviceController @@ -2066,6 +2063,27 @@ def SetDSTOffset(self, offset: int, validStarting: int, validUntil: int): lambda: self._dmLib.pychip_DeviceController_SetDSTOffset(offset, validStarting, validUntil) ).raise_on_error() + def SetTCRequired(self, tcRequired: bool): + ''' Set whether TC Acknowledgements should be set during commissioning''' + self.CheckIsActive() + self._ChipStack.Call( + lambda: self._dmLib.pychip_DeviceController_SetRequireTermsAndConditionsAcknowledgement(tcRequired) + ).raise_on_error() + + def SetTCAcknowledgements(self, tcAcceptedVersion: int, tcUserResponse: int): + ''' Set the TC acknowledgements to set during commissioning''' + self.CheckIsActive() + self._ChipStack.Call( + lambda: self._dmLib.pychip_DeviceController_SetTermsAcknowledgements(tcAcceptedVersion, tcUserResponse) + ).raise_on_error() + + def SetSkipCommissioningComplete(self, skipCommissioningComplete: bool): + ''' Set whether to skip the commissioning complete callback''' + self.CheckIsActive() + self._ChipStack.Call( + lambda: self._dmLib.pychip_DeviceController_SetSkipCommissioningComplete(skipCommissioningComplete) + ).raise_on_error() + def SetDefaultNTP(self, defaultNTP: str): ''' Set the DefaultNTP to set during commissioning''' self.CheckIsActive() diff --git a/src/python_testing/TC_CGEN_2_5.py b/src/python_testing/TC_CGEN_2_5.py new file mode 100644 index 00000000000000..d75ebccb776526 --- /dev/null +++ b/src/python_testing/TC_CGEN_2_5.py @@ -0,0 +1,179 @@ +# +# Copyright (c) 2022 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. +# + +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto + +import logging +import random + +import chip.clusters as Clusters +from chip.exceptions import ChipStackError +from matter_testing_support import DiscoveryFilterType, MatterBaseTest, async_test_body, default_matter_test_main +from mobly import asserts + + +class TC_CGEN_2_5(MatterBaseTest): + + async def commission_device(self) -> bool: + dev_ctrl = self.default_controller + conf = self.matter_test_config + info = self.get_setup_payload_info()[0] + + if conf.commissioning_method == "on-network": + try: + await dev_ctrl.CommissionOnNetwork( + nodeId=self.dut_node_id, + setupPinCode=info.passcode, + filterType=info.filter_type, + filter=info.filter_value + ) + return True + except ChipStackError as e: + logging.error("Commissioning failed: %s" % e) + return False + elif conf.commissioning_method == "ble-wifi": + try: + await dev_ctrl.CommissionWiFi( + info.filter_value, + info.passcode, + conf.self.dut_node_id, + conf.wifi_ssid, + conf.wifi_passphrase, + isShortDiscriminator=(info.filter_type == DiscoveryFilterType.SHORT_DISCRIMINATOR) + ) + return True + except ChipStackError as e: + logging.error("Commissioning failed: %s" % e) + return False + elif conf.commissioning_method == "ble-thread": + try: + await dev_ctrl.CommissionThread( + info.filter_value, + info.passcode, + conf.self.dut_node_id, + conf.thread_operational_dataset, + isShortDiscriminator=(info.filter_type == DiscoveryFilterType.SHORT_DISCRIMINATOR) + ) + return True + except ChipStackError as e: + logging.error("Commissioning failed: %s" % e) + return False + else: + raise ValueError("Invalid commissioning method %s!" % conf.commissioning_method) + + async def verify_tc_attributes(self, expected_tc_version: int, expected_tc_acknowledgements: int): + attr = Clusters.GeneralCommissioning.Attributes.TCAcceptedVersion + tc_accepted_version = await self.read_single_attribute(dev_ctrl=self.th1, node_id=self.dut_node_id, endpoint=0, attribute=attr) + asserts.assert_equal(tc_accepted_version, expected_tc_version, + f"Expected TCAcceptedVersion to be {expected_tc_version}, but got {tc_accepted_version}") + + attr = Clusters.GeneralCommissioning.Attributes.TCAcknowledgements + tc_acknowedgements = await self.read_single_attribute(dev_ctrl=self.th1, node_id=self.dut_node_id, endpoint=0, attribute=attr) + asserts.assert_equal(tc_acknowedgements, expected_tc_acknowledgements, + f"Expected TCAcknowledgements to be {expected_tc_acknowledgements}, but got {tc_acknowedgements}") + + @async_test_body + async def test_TC_CGEN_2_5(self): + self.th1 = self.default_controller + self.discriminator = random.randint(0, 4095) + + logging.info('Step 1 - TH reads the TCAcceptedVersion attribute') + attr = Clusters.GeneralCommissioning.Attributes.TCAcceptedVersion + tc_accepted_version = await self.read_single_attribute(dev_ctrl=self.th1, node_id=self.dut_node_id, endpoint=0, attribute=attr) + + print(f"tc_accepted_version: {tc_accepted_version}") + + logging.info('Step 2 - TH reads the TCAcknowledgements attribute') + attr = Clusters.GeneralCommissioning.Attributes.TCAcknowledgements + tc_acknowedgements = await self.read_single_attribute(dev_ctrl=self.th1, node_id=self.dut_node_id, endpoint=0, attribute=attr) + print(f"tc_acknowedgements: {tc_acknowedgements}") + + logging.info('Step 3 - TH reads the TCMinRequiredVersion attribute') + attr = Clusters.GeneralCommissioning.Attributes.TCMinRequiredVersion + tc_min_requried_version = await self.read_single_attribute(dev_ctrl=self.th1, node_id=self.dut_node_id, endpoint=0, attribute=attr) + + logging.info('Step 4 - TH reads the TCAcknowledgementsRequired attribute') + attr = Clusters.GeneralCommissioning.Attributes.TCAcknowledgementsRequired + tc_required = await self.read_single_attribute(dev_ctrl=self.th1, node_id=self.dut_node_id, endpoint=0, attribute=attr) + + logging.info('Step 5 - TH sends SetTCAcknowledgements with greater values than current and verify set') + new_accepted_version = tc_accepted_version + 1 + new_acknowledgements = 65535 + + cmd = Clusters.GeneralCommissioning.Commands.SetTCAcknowledgements(new_accepted_version, new_acknowledgements) + resp = await self.th1.SendCommand(nodeid=self.dut_node_id, endpoint=0, payload=cmd, timedRequestTimeoutMs=6000) + asserts.assert_equal(resp.errorCode, Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, 'Incorrect error code') + await self.verify_tc_attributes(new_accepted_version, new_acknowledgements) + + logging.info('Step 6 - TH sends SetTCAcknowledgements with no accepted terms at version 0') + cmd = Clusters.GeneralCommissioning.Commands.SetTCAcknowledgements(0, 0) + resp = await self.th1.SendCommand(nodeid=self.dut_node_id, endpoint=0, payload=cmd, timedRequestTimeoutMs=6000) + asserts.assert_equal( + resp.errorCode, Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kTCMinVersionNotMet, 'Incorrect error code' + ) + await self.verify_tc_attributes(new_accepted_version, new_acknowledgements) + + logging.info('Step 7 - TH sends SetTCAcknowledgements with no accepted terms at version 1') + cmd = Clusters.GeneralCommissioning.Commands.SetTCAcknowledgements(1, 0) + resp = await self.th1.SendCommand(nodeid=self.dut_node_id, endpoint=0, payload=cmd, timedRequestTimeoutMs=6000) + asserts.assert_equal( + resp.errorCode, Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kRequiredTCNotAccepted, 'Incorrect error code' + ) + await self.verify_tc_attributes(new_accepted_version, new_acknowledgements) + + logging.info('Step 8 - TH sends ArmFailSafe with ExpiryLengthSeconds set to 60') + cmd = Clusters.GeneralCommissioning.Commands.ArmFailSafe(60) + resp = await self.th1.SendCommand(nodeid=self.dut_node_id, endpoint=0, payload=cmd, timedRequestTimeoutMs=6000) + asserts.assert_equal(resp.errorCode, Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, + 'Incorrect error code') + + logging.info('Step 9 - TH sends SetTCAcknowledgements with incremented TCVersion') + cmd = Clusters.GeneralCommissioning.Commands.SetTCAcknowledgements(new_accepted_version + 1, new_acknowledgements) + resp = await self.th1.SendCommand(nodeid=self.dut_node_id, endpoint=0, payload=cmd, timedRequestTimeoutMs=6000) + asserts.assert_equal(resp.errorCode, Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, + 'Incorrect error code') + + logging.info('Step 10 - TH sends ArmFailSafe with ExpiryLengthSeconds set to 0') + cmd = Clusters.GeneralCommissioning.Commands.ArmFailSafe(0) + resp = await self.th1.SendCommand(nodeid=self.dut_node_id, endpoint=0, payload=cmd, timedRequestTimeoutMs=6000) + asserts.assert_equal(resp.errorCode, Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, + 'Incorrect error code') + + # Verify that the TC attributes have been reset to the pre-failsafe state + await self.verify_tc_attributes(new_accepted_version, new_acknowledgements) + + logging.info('Step 11 - TH removes all fabrics from the device') + fabrics = await self.read_single_attribute(dev_ctrl=self.th1, node_id=self.dut_node_id, endpoint=0, attribute=Clusters.OperationalCredentials.Attributes.Fabrics) + for fabric in fabrics: + if fabric.fabricIndex == self.th1.fabricId: + continue + cmd = Clusters.OperationalCredentials.Commands.RemoveFabric(fabric.fabricIndex) + resp = await self.th1.SendCommand(nodeid=self.dut_node_id, endpoint=0, payload=cmd, timedRequestTimeoutMs=6000) + asserts.assert_equal(resp.statusCode, Clusters.OperationalCredentials.Enums.NodeOperationalCertStatusEnum.kOk) + + # Remove TH1 fabric last + cmd = Clusters.OperationalCredentials.Commands.RemoveFabric(self.th1.fabricId) + resp = await self.th1.SendCommand(nodeid=self.dut_node_id, endpoint=0, payload=cmd, timedRequestTimeoutMs=6000) + + +if __name__ == "__main__": + default_matter_test_main() diff --git a/src/python_testing/TC_CGEN_2_6.py b/src/python_testing/TC_CGEN_2_6.py new file mode 100644 index 00000000000000..9ad75357458342 --- /dev/null +++ b/src/python_testing/TC_CGEN_2_6.py @@ -0,0 +1,68 @@ +# +# Copyright (c) 2024 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. +# + +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto + +import logging +import random + +import chip.clusters as Clusters +from chip.exceptions import ChipStackError +from matter_testing_support import (InternalTestRunnerHooks, MatterBaseTest, MatterTestConfig, async_test_body, + parse_matter_test_args, run_tests) +from mobly import asserts + + +class TC_CGEN_2_6(MatterBaseTest): + + async def test_TC_CGEN_2_6(self): + info = self.get_setup_payload_info()[0] + + self.th1 = self.default_controller + self.discriminator = random.randint(0, 4095) + + logging.info('Step 1 - TH commissions the DUT without setting TCs') + + # Don't set TCs for the next commissioning and skip CommissioningComplete so we can manually call CommissioningComplete in order to check the response error code + self.th1.SetTCRequired(False) + self.th1.SetSkipCommissioningComplete(True) + + await self.default_controller.CommissionOnNetwork( + nodeId=self.dut_node_id, + setupPinCode=info.passcode, + filterType=info.filter_type, + filter=info.filter_value + ) + + cmd = Clusters.GeneralCommissioning.Commands.CommissioningComplete() + resp = await self.th1.SendCommand(nodeid=self.dut_node_id, endpoint=0, payload=cmd, timedRequestTimeoutMs=6000) + asserts.assert_equal( + resp.errorCode, Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kTCAcknowledgementsNotReceived, 'Incorrect error code') + + +if __name__ == "__main__": + config: MatterTestConfig = parse_matter_test_args() + + # When commissioning_method is set, the MatterBaseTest inherently depends on CommissionDeviceTest, which we want to avoid to test commissioning failure cases + config.commissioning_method = None + + run_tests(TC_CGEN_2_6, config, InternalTestRunnerHooks()) diff --git a/src/python_testing/matter_testing_support.py b/src/python_testing/matter_testing_support.py index 4127ead64c3083..97b51e97eeafd6 100644 --- a/src/python_testing/matter_testing_support.py +++ b/src/python_testing/matter_testing_support.py @@ -27,7 +27,6 @@ import random import re import sys -import textwrap import time import typing import uuid @@ -54,7 +53,6 @@ import chip.native from chip import discovery from chip.ChipStack import ChipStack -from chip.clusters import Attribute from chip.clusters import ClusterObjects as ClusterObjects from chip.clusters.Attribute import EventReadResult, SubscriptionTransaction, TypedAttributePath from chip.exceptions import ChipStackError @@ -331,7 +329,7 @@ def wait_for_report(self): logging.info( f"[AttributeChangeCallback] Got attribute subscription report. Attribute {path.AttributeType}. Updated value: {attribute_value}. SubscriptionId: {transaction.subscriptionId}") except KeyError: - asserts.fail(f"[AttributeChangeCallback] Attribute {self._expected_attribute} not found in returned report") + asserts.fail("[AttributeChangeCallback] Attribute {expected_attribute} not found in returned report") def clear_queue(report_queue: queue.Queue): @@ -573,6 +571,10 @@ class MatterTestConfig: trace_to: List[str] = field(default_factory=list) + # Accepted Terms and Conditions if used + tc_version: int = None + tc_user_response: int = None + class ClusterMapper: """Describe clusters/attributes using schema names.""" @@ -1150,60 +1152,12 @@ def on_fail(self, record): self.failed = True if self.runner_hook and not self.is_commissioning: exception = record.termination_signal.exception - - try: - step_duration = (datetime.now(timezone.utc) - self.step_start_time) / timedelta(microseconds=1) - except AttributeError: - # If we failed during setup, these may not be populated - step_duration = 0 - try: - test_duration = (datetime.now(timezone.utc) - self.test_start_time) / timedelta(microseconds=1) - except AttributeError: - test_duration = 0 + step_duration = (datetime.now(timezone.utc) - self.step_start_time) / timedelta(microseconds=1) + test_duration = (datetime.now(timezone.utc) - self.test_start_time) / timedelta(microseconds=1) # TODO: I have no idea what logger, logs, request or received are. Hope None works because I have nothing to give self.runner_hook.step_failure(logger=None, logs=None, duration=step_duration, request=None, received=None) self.runner_hook.test_stop(exception=exception, duration=test_duration) - def extract_error_text() -> tuple[str, str]: - no_stack_trace = ("Stack Trace Unavailable", "") - if not record.termination_signal.stacktrace: - return no_stack_trace - trace = record.termination_signal.stacktrace.splitlines() - if not trace: - return no_stack_trace - - if isinstance(exception, signals.TestError): - # Exception gets raised by the mobly framework, so the proximal error is one line back in the stack trace - assert_candidates = [idx for idx, line in enumerate(trace) if "asserts" in line and "asserts.py" not in line] - if not assert_candidates: - return "Unknown error, please see stack trace above", "" - assert_candidate_idx = assert_candidates[-1] - else: - # Normal assert is on the Last line - assert_candidate_idx = -1 - probable_error = trace[assert_candidate_idx] - - # Find the file marker immediately above the probable error - file_candidates = [idx for idx, line in enumerate(trace[:assert_candidate_idx]) if "File" in line] - if not file_candidates: - return probable_error, "Unknown file" - return probable_error.strip(), trace[file_candidates[-1]].strip() - - probable_error, probable_file = extract_error_text() - logging.error(textwrap.dedent(f""" - - ****************************************************************** - * - * Test {self.current_test_info.name} failed for the following reason: - * {exception} - * - * {probable_file} - * {probable_error} - * - ******************************************************************* - - """)) - def on_pass(self, record): ''' Called by Mobly on test pass @@ -1666,6 +1620,9 @@ def convert_args_to_matter_config(args: argparse.Namespace) -> MatterTestConfig: config.controller_node_id = args.controller_node_id config.trace_to = args.trace_to + config.tc_version = args.tc_version + config.tc_user_response = args.tc_user_response + # Accumulate all command-line-passed named args all_global_args = [] argsets = [item for item in (args.int_arg, args.float_arg, args.string_arg, args.json_arg, @@ -1759,6 +1716,10 @@ def parse_matter_test_args(argv: Optional[List[str]] = None) -> MatterTestConfig commission_group.add_argument('--commission-only', action="store_true", default=False, help="If true, test exits after commissioning without running subsequent tests") + commission_group.add_argument('--tc-version', type=int, help="Terms and conditions version") + + commission_group.add_argument('--tc-user-response', type=int, help="Terms and conditions acknowledgements") + code_group = parser.add_mutually_exclusive_group(required=False) code_group.add_argument('-q', '--qr-code', type=str, @@ -1947,7 +1908,7 @@ async def get_accepted_endpoints_for_test(self: MatterBaseTest, accept_function: Returns a list of endpoints on which the test should be run given the accept_function for the test. """ - wildcard = await self.default_controller.Read(self.dut_node_id, [(Clusters.Descriptor), Attribute.AttributePath(None, None, GlobalAttributeIds.ATTRIBUTE_LIST_ID), Attribute.AttributePath(None, None, GlobalAttributeIds.FEATURE_MAP_ID), Attribute.AttributePath(None, None, GlobalAttributeIds.ACCEPTED_COMMAND_LIST_ID)]) + wildcard = await self.default_controller.Read(self.dut_node_id, [()]) return [e for e in wildcard.attributes.keys() if accept_function(wildcard, e)] @@ -2037,6 +1998,13 @@ async def _commission_device(self, i) -> bool: info = self.get_setup_payload_info()[i] + if conf.tc_version is not None and conf.tc_user_response is not None: + logging.debug(f"Setting TC Acknowledgements to version {conf.tc_version} with user response {conf.tc_user_response}.") + dev_ctrl.SetTCAcknowledgements(conf.tc_version, conf.tc_user_response) + dev_ctrl.SetTCRequired(True) + else: + dev_ctrl.SetTCRequired(False) + if conf.commissioning_method == "on-network": try: await dev_ctrl.CommissionOnNetwork(