Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
FernandoLGuzman authored Jan 13, 2023
2 parents 59fdc65 + b36439e commit 2f18002
Show file tree
Hide file tree
Showing 8 changed files with 265 additions and 59 deletions.
2 changes: 2 additions & 0 deletions examples/java-matter-controller/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ java_binary("java-matter-controller") {
"java/src/com/matter/controller/commands/common/Command.java",
"java/src/com/matter/controller/commands/common/CommandManager.java",
"java/src/com/matter/controller/commands/common/CredentialsIssuer.java",
"java/src/com/matter/controller/commands/common/FutureResult.java",
"java/src/com/matter/controller/commands/common/IPAddress.java",
"java/src/com/matter/controller/commands/common/MatterCommand.java",
"java/src/com/matter/controller/commands/common/RealResult.java",
"java/src/com/matter/controller/commands/discover/DiscoverCommand.java",
"java/src/com/matter/controller/commands/discover/DiscoverCommissionablesCommand.java",
"java/src/com/matter/controller/commands/discover/DiscoverCommissionersCommand.java",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2023 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.
*
*/

package com.matter.controller.commands.common;

import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Implements the future result that encapculates the optional realResult, application would wait
* for realResult set by other thread wben receiving data from the other end. If the expected
* duration elapsed without receiving the expected realResult, the runtime exception would be
* raised.
*/
public class FutureResult {
private Optional<RealResult> realResult;
private long timeoutMs = 0;
private static Logger logger = Logger.getLogger(FutureResult.class.getName());

public void setTimeoutMs(long timeoutMs) {
this.timeoutMs = timeoutMs;
}

public synchronized void setRealResult(RealResult realResult) {
if (this.realResult.isPresent()) {
throw new RuntimeException("error, real result has been set!");
}
this.realResult = Optional.of(realResult);
notifyAll();
}

public synchronized void waitResult() {
long start = System.currentTimeMillis();
while (!realResult.isPresent()) {
try {
if (System.currentTimeMillis() > (start + timeoutMs)) {
throw new RuntimeException("timeout!");
}
wait();
} catch (InterruptedException e) {
}
}

if (!realResult.get().getResult()) {
logger.log(Level.INFO, "error: %s", realResult.get().getError());
throw new RuntimeException("received failure test result");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Logger;

public abstract class MatterCommand extends Command {
private final ChipDeviceController mChipDeviceController;
Expand All @@ -30,9 +31,10 @@ public abstract class MatterCommand extends Command {
private final StringBuffer mPaaTrustStorePath = new StringBuffer();
private final StringBuffer mCDTrustStorePath = new StringBuffer();
private final AtomicLong mCommissionerNodeId = new AtomicLong();
private final AtomicBoolean mUseMaxSizedCerts = new AtomicBoolean();;
private final AtomicBoolean mOnlyAllowTrustedCdKeys = new AtomicBoolean();;
private Optional<String> mTestResult = Optional.empty();
private final AtomicBoolean mUseMaxSizedCerts = new AtomicBoolean();
private final AtomicBoolean mOnlyAllowTrustedCdKeys = new AtomicBoolean();
private FutureResult mFutureResult = new FutureResult();
private static Logger logger = Logger.getLogger(MatterCommand.class.getName());

public MatterCommand(
ChipDeviceController controller, String commandName, CredentialsIssuer credIssuerCmds) {
Expand Down Expand Up @@ -100,39 +102,16 @@ public void run() throws Exception {

protected abstract void runCommand();

public void setTestResult(String result) {
mTestResult = Optional.of(result);
public void setSuccess() {
mFutureResult.setRealResult(RealResult.Success());
}

public void expectSuccess(long timeout) {
expectResult("Success", timeout);
public void setFailure(String error) {
mFutureResult.setRealResult(RealResult.Error(error));
}

private void expectResult(String expectedResult, long timeout) {
long start = System.currentTimeMillis();
while (!mTestResult.isPresent())
try {
if (System.currentTimeMillis() > (start + timeout)) {
throw new RuntimeException("timeout!");
}
Thread.sleep(100);
} catch (InterruptedException ex) {
}

if (!mTestResult.isPresent()) {
throw new RuntimeException("received empty test result");
}

if (!mTestResult.get().equals(expectedResult)) {
if (!expectedResult.equals("Success")) {
System.out.format(
"%s command failed:%n Expected: %s%n Got: %s%n",
getName(), expectedResult, mTestResult);
throw new RuntimeException(getName());
} else {
System.out.format("%s command failed: %s%n", getName(), mTestResult.get());
}
}
mTestResult = Optional.empty();
public void waitCompleteMs(long timeoutMs) {
mFutureResult.setTimeoutMs(timeoutMs);
mFutureResult.waitResult();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2023 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.
*
*/

package com.matter.controller.commands.common;

/**
* Implements a Result where an error string is associated with its failure state.
*
* <p>A `Result` is just a booean of true/false that is exposed via `getResult`. This class will
* contain either a `true` value for `Success` or a `false` value in which case the failure will
* also have an error string explaining the reason of the failure associated with it.
*/
public class RealResult {
private boolean result;
private String error;

public RealResult() {
this.result = true;
}

public RealResult(String error) {
this.result = false;
this.error = error;
}

public static RealResult Success() {
return new RealResult();
}

public static RealResult Error(String error) {
return new RealResult(error);
}

public boolean getResult() {
return result;
}

public String getError() {
return error;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ protected void runCommand() {
getSetupPINCode(),
null);
currentCommissioner().setCompletionListener(this);
expectSuccess(getTimeoutMillis());
waitCompleteMs(getTimeoutMillis());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public void onStatusUpdate(int status) {
public void onPairingComplete(int errorCode) {
logger.log(Level.INFO, "onPairingComplete with error code: " + errorCode);
if (errorCode != 0) {
setTestResult("Failure");
setFailure("onPairingComplete failure");
}
}

Expand All @@ -95,9 +95,9 @@ public void onPairingDeleted(int errorCode) {
public void onCommissioningComplete(long nodeId, int errorCode) {
logger.log(Level.INFO, "onCommissioningComplete with error code: " + errorCode);
if (errorCode == 0) {
setTestResult("Success");
setSuccess();
} else {
setTestResult("Failure");
setFailure("onCommissioningComplete failure");
}
}

Expand All @@ -124,7 +124,7 @@ public void onCloseBleComplete() {

@Override
public void onError(Throwable error) {
setTestResult(error.toString());
setFailure(error.toString());
logger.log(Level.INFO, "onError with error: " + error.toString());
}

Expand Down
34 changes: 26 additions & 8 deletions src/controller/python/chip/yaml/format_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,18 @@

import enum
import typing
from dataclasses import dataclass

from chip.clusters.Types import Nullable, NullValue
from chip.tlv import float32, uint
from chip.yaml.errors import ValidationError
from matter_idl import matter_idl_types


@dataclass
class _TargetTypeInfo:
field: typing.Union[list[matter_idl_types.Field], matter_idl_types.Field]
is_fabric_scoped: bool


def _case_insensitive_getattr(object, attr_name, default):
Expand All @@ -30,15 +38,16 @@ def _case_insensitive_getattr(object, attr_name, default):
return default


def _get_target_type_fields(test_spec_definition, cluster_name, target_name):
def _get_target_type_info(test_spec_definition, cluster_name, target_name) -> _TargetTypeInfo:
element = test_spec_definition.get_type_by_name(cluster_name, target_name)
if hasattr(element, 'fields'):
return element.fields
return None
is_fabric_scoped = test_spec_definition.is_fabric_scoped(element)
return _TargetTypeInfo(element.fields, is_fabric_scoped)
return _TargetTypeInfo(None, False)


def from_data_model_to_test_definition(test_spec_definition, cluster_name, response_definition,
response_value):
response_value, is_fabric_scoped=False):
'''Converts value from data model to definitions provided in test_spec_definition.
Args:
Expand All @@ -56,6 +65,10 @@ def from_data_model_to_test_definition(test_spec_definition, cluster_name, respo
# that need to be worked through recursively to properly convert the value to the right type.
if isinstance(response_definition, list):
rv = {}
# is_fabric_scoped will only be relevant for struct types, hence why it is only checked
# here.
if is_fabric_scoped:
rv['FabricIndex'] = _case_insensitive_getattr(response_value, 'fabricIndex', None)
for item in response_definition:
value = _case_insensitive_getattr(response_value, item.name, None)
if item.is_optional and value is None:
Expand All @@ -82,18 +95,23 @@ def from_data_model_to_test_definition(test_spec_definition, cluster_name, respo
if response_value_type == float32 and response_definition.data_type.name.lower() == 'single':
return float('%g' % response_value)

response_sub_definition = _get_target_type_fields(test_spec_definition, cluster_name,
response_definition.data_type.name)
target_type_info = _get_target_type_info(test_spec_definition, cluster_name,
response_definition.data_type.name)

response_sub_definition = target_type_info.field
is_sub_definition_fabric_scoped = target_type_info.is_fabric_scoped

# Check below is to see if the field itself is an array, for example array of ints.
if response_definition.is_list:
return [
from_data_model_to_test_definition(test_spec_definition, cluster_name,
response_sub_definition, item) for item in response_value
response_sub_definition, item,
is_sub_definition_fabric_scoped) for item in response_value
]

return from_data_model_to_test_definition(test_spec_definition, cluster_name,
response_sub_definition, response_value)
response_sub_definition, response_value,
is_sub_definition_fabric_scoped)


def convert_list_of_name_value_pair_to_dict(arg_values):
Expand Down
Loading

0 comments on commit 2f18002

Please sign in to comment.