Skip to content

Commit 1080707

Browse files
vivien-appleVivien Nicolas
authored andcommitted
[MatterYamlTests] Add basic support for darwin-framework-tool (#28969)
* Add darwin-framework-tool python yaml parser connection support. For the moment darwin-framework-tool does not send back anything nor supports special test commands that have been added to chip-tool to fully support yaml * Add sleep command to darwin-framework-tool * Add wait-for-commissionee command to darwin-framework-tool * Add darwin-framework-tool python yaml parser output connection support * Hack examples/chip-tool/py_matter_chip_tool_adapter/matter_chip_tool_adapter/encoder.py so it does use the right argument names for darwin-framework-tool --------- Co-authored-by: Vivien Nicolas <vn@MacBook-Air-de-Vivien.local>
1 parent 0990908 commit 1080707

File tree

22 files changed

+17961
-2737
lines changed

22 files changed

+17961
-2737
lines changed

examples/chip-tool/py_matter_chip_tool_adapter/matter_chip_tool_adapter/decoder.py

+16
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,22 @@ def run(self, specs, value, cluster_name: str, typename: str, array: bool):
303303
)
304304
del value[str(field_code)]
305305

306+
# darwin-framework-tool returns the field name but with a different casing than what
307+
# the test suite expects.
308+
# To not confuse the test suite, the field name is replaced by its field name
309+
# equivalent from the spec and then removed.
310+
wrong_casing_field_name = field_name[0].lower(
311+
) + field_name[1:]
312+
if field_name not in value and field_name[0].upper() == field_name[0] and wrong_casing_field_name in value:
313+
value[field_name] = self.run(
314+
specs,
315+
value[wrong_casing_field_name],
316+
cluster_name,
317+
field_type,
318+
field_array
319+
)
320+
del value[wrong_casing_field_name]
321+
306322
if specs.is_fabric_scoped(struct):
307323
value[_FABRIC_INDEX_FIELD_NAME] = self.run(
308324
specs,

examples/chip-tool/py_matter_chip_tool_adapter/matter_chip_tool_adapter/encoder.py

+19-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414

1515
import base64
1616
import json
17+
import os
1718
import re
19+
import sys
1820

1921
_ANY_COMMANDS_LIST = [
2022
'ReadById',
@@ -208,6 +210,12 @@ class Encoder:
208210
def __init__(self, specifications):
209211
self.__specs = specifications
210212

213+
# This is not the best way to toggle this flag. But for now it prevents having
214+
# to build a new adapter for the very small differences that exists...
215+
is_darwin_framework_tool = os.path.basename(
216+
sys.argv[0]) == 'darwinframeworktool.py'
217+
self.__is_darwin_framework_tool = is_darwin_framework_tool
218+
211219
def encode(self, request):
212220
cluster = self.__get_cluster_name(request)
213221
command, command_specifier = self.__get_command_name(request)
@@ -305,7 +313,10 @@ def __maybe_add_destination(self, rv, request):
305313
if not self._supports_destination(request):
306314
return rv
307315

308-
destination_argument_name = 'destination-id'
316+
if self.__is_darwin_framework_tool:
317+
destination_argument_name = 'node-id'
318+
else:
319+
destination_argument_name = 'destination-id'
309320
destination_argument_value = None
310321

311322
if request.group_id:
@@ -333,6 +344,9 @@ def __maybe_add_endpoint(self, rv, request):
333344
if (request.is_attribute and not request.command == "writeAttribute") or request.is_event or (request.command in _ANY_COMMANDS_LIST and not request.command == "WriteById"):
334345
endpoint_argument_name = 'endpoint-ids'
335346

347+
if self.__is_darwin_framework_tool:
348+
endpoint_argument_name = 'endpoint-id'
349+
336350
if rv:
337351
rv += ', '
338352
rv += f'"{endpoint_argument_name}": "{endpoint_argument_value}"'
@@ -378,7 +392,10 @@ def __get_argument_name(self, request, entry):
378392

379393
if request.is_attribute:
380394
if command_name == 'writeAttribute':
381-
argument_name = 'attribute-values'
395+
if self.__is_darwin_framework_tool:
396+
argument_name = 'attr-value'
397+
else:
398+
argument_name = 'attribute-values'
382399
else:
383400
argument_name = 'value'
384401

examples/darwin-framework-tool/BUILD.gn

+18-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import("//build_overrides/build.gni")
1616
import("//build_overrides/chip.gni")
17+
import("//build_overrides/jsoncpp.gni")
1718

1819
import("${chip_root}/build/chip/tools.gni")
1920
import("${chip_root}/build/config/compiler/compiler.gni")
@@ -132,6 +133,7 @@ action("build-darwin-framework") {
132133
config("config") {
133134
include_dirs = [
134135
".",
136+
"${chip_root}/examples/common",
135137
"${chip_root}/examples/darwin-framework-tool/commands/common",
136138
"${chip_root}/zzz_generated/darwin-framework-tool",
137139
"${chip_root}/zzz_generated/controller-clusters",
@@ -178,6 +180,13 @@ executable("darwin-framework-tool") {
178180
"commands/common/MTRError.mm",
179181
"commands/common/MTRError_Utils.h",
180182
"commands/common/MTRLogging.h",
183+
"commands/common/RemoteDataModelLogger.h",
184+
"commands/common/RemoteDataModelLogger.mm",
185+
"commands/delay/Commands.h",
186+
"commands/delay/SleepCommand.h",
187+
"commands/delay/SleepCommand.mm",
188+
"commands/delay/WaitForCommissioneeCommand.h",
189+
"commands/delay/WaitForCommissioneeCommand.mm",
181190
"commands/discover/Commands.h",
182191
"commands/discover/DiscoverCommissionablesCommand.h",
183192
"commands/discover/DiscoverCommissionablesCommand.mm",
@@ -200,12 +209,16 @@ executable("darwin-framework-tool") {
200209

201210
deps = [
202211
":build-darwin-framework",
203-
"${chip_root}/third_party/jsoncpp",
212+
jsoncpp_root,
204213
]
205214

206215
if (config_use_interactive_mode) {
207216
sources += [ "commands/interactive/InteractiveCommands.mm" ]
208-
deps += [ "${editline_root}:editline" ]
217+
218+
deps += [
219+
"${chip_root}/examples/common/websocket-server",
220+
"${editline_root}:editline",
221+
]
209222
}
210223

211224
ldflags = [
@@ -240,6 +253,7 @@ executable("darwin-framework-tool") {
240253

241254
# pics is needed by tests
242255
"${chip_root}/src/app/tests/suites/pics",
256+
"${chip_root}/src/protocols:im_status",
243257
]
244258

245259
defines = []
@@ -248,6 +262,8 @@ executable("darwin-framework-tool") {
248262
"${chip_root}/config/standalone/",
249263
"${chip_root}/src/",
250264
"${chip_root}/src/include/",
265+
"${chip_root}/src/protocols/",
266+
"${chip_root}/src/protocols/interaction_model",
251267
"${chip_root}/third_party/nlassert/repo/include/",
252268
"${chip_root}/third_party/nlio/repo/include/",
253269
"${chip_root}/zzz_generated/app-common/",

examples/darwin-framework-tool/commands/common/CHIPCommandBridge.mm

+6
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@
4040
ChipLogProgress(chipTool, "Running Command");
4141
ReturnErrorOnFailure(MaybeSetUpStack());
4242
SetIdentity(mCommissionerName.HasValue() ? mCommissionerName.Value() : kIdentityAlpha);
43+
44+
{
45+
std::lock_guard<std::mutex> lk(cvWaitingForResponseMutex);
46+
mWaitingForResponse = YES;
47+
}
48+
4349
ReturnLogErrorOnFailure(RunCommand());
4450

4551
auto err = StartWaiting(GetWaitDuration());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (c) 2023 Project CHIP Authors
3+
* All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
#import <Matter/Matter.h>
20+
21+
#include <lib/core/CHIPError.h>
22+
23+
class RemoteDataModelLoggerDelegate {
24+
public:
25+
CHIP_ERROR virtual LogJSON(const char *) = 0;
26+
virtual ~RemoteDataModelLoggerDelegate() {};
27+
};
28+
29+
namespace RemoteDataModelLogger {
30+
CHIP_ERROR LogAttributeAsJSON(NSNumber * endpointId, NSNumber * clusterId, NSNumber * attributeId, id result);
31+
CHIP_ERROR LogCommandAsJSON(NSNumber * endpointId, NSNumber * clusterId, NSNumber * commandId, id result);
32+
CHIP_ERROR LogAttributeErrorAsJSON(NSNumber * endpointId, NSNumber * clusterId, NSNumber * attributeId, NSError * error);
33+
CHIP_ERROR LogCommandErrorAsJSON(NSNumber * endpointId, NSNumber * clusterId, NSNumber * commandId, NSError * error);
34+
void SetDelegate(RemoteDataModelLoggerDelegate * delegate);
35+
}; // namespace RemoteDataModelLogger
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
/*
2+
* Copyright (c) 2023 Project CHIP Authors
3+
* All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
#include "RemoteDataModelLogger.h"
20+
21+
#import "MTRError_Utils.h"
22+
#import <objc/runtime.h>
23+
24+
#include <json/json.h>
25+
#include <lib/support/SafeInt.h>
26+
#include <protocols/interaction_model/StatusCode.h>
27+
28+
#include <string>
29+
30+
constexpr const char * kClusterIdKey = "clusterId";
31+
constexpr const char * kEndpointIdKey = "endpointId";
32+
constexpr const char * kAttributeIdKey = "attributeId";
33+
constexpr const char * kCommandIdKey = "commandId";
34+
constexpr const char * kErrorIdKey = "error";
35+
constexpr const char * kClusterErrorIdKey = "clusterError";
36+
constexpr const char * kValueKey = "value";
37+
38+
constexpr const char kBase64Header[] = "base64:";
39+
40+
namespace {
41+
RemoteDataModelLoggerDelegate * gDelegate;
42+
43+
std::string JsonToString(Json::Value & json)
44+
{
45+
Json::FastWriter writer;
46+
writer.omitEndingLineFeed();
47+
return writer.write(json);
48+
}
49+
50+
CHIP_ERROR LogError(Json::Value & value, const chip::app::StatusIB & status)
51+
{
52+
if (status.mClusterStatus.HasValue()) {
53+
auto statusValue = status.mClusterStatus.Value();
54+
value[kClusterErrorIdKey] = statusValue;
55+
}
56+
57+
#if CHIP_CONFIG_IM_STATUS_CODE_VERBOSE_FORMAT
58+
auto statusName = chip::Protocols::InteractionModel::StatusName(status.mStatus);
59+
value[kErrorIdKey] = statusName;
60+
#else
61+
auto statusName = status.mStatus;
62+
value[kErrorIdKey] = chip::to_underlying(statusName);
63+
#endif // CHIP_CONFIG_IM_STATUS_CODE_VERBOSE_FORMAT
64+
65+
auto valueStr = JsonToString(value);
66+
return gDelegate->LogJSON(valueStr.c_str());
67+
}
68+
69+
CHIP_ERROR AsJsonValue(id value, Json::Value & jsonValue)
70+
{
71+
if (value == nil) {
72+
jsonValue = Json::nullValue;
73+
} else if ([value isKindOfClass:[NSNumber class]]) {
74+
if (CFNumberIsFloatType((CFNumberRef) value)) {
75+
jsonValue = [value doubleValue];
76+
} else if ([[value stringValue] hasPrefix:@"-"]) {
77+
jsonValue = [value longLongValue];
78+
} else {
79+
jsonValue = [value unsignedLongLongValue];
80+
}
81+
} else if ([value isKindOfClass:[NSArray class]]) {
82+
jsonValue = Json::arrayValue;
83+
84+
NSArray * array = value;
85+
for (id element in array) {
86+
Json::Value jsonElement;
87+
VerifyOrDie(CHIP_NO_ERROR == AsJsonValue(element, jsonElement));
88+
jsonValue.append(jsonElement);
89+
}
90+
} else if ([value isKindOfClass:[NSDictionary class]]) {
91+
jsonValue = Json::ValueType::objectValue;
92+
93+
NSDictionary * dict = value;
94+
for (id key in dict) {
95+
Json::Value jsonElement;
96+
VerifyOrDie(CHIP_NO_ERROR == AsJsonValue([dict objectForKey:key], jsonElement));
97+
jsonValue[[key UTF8String]] = jsonElement;
98+
}
99+
} else if ([value isKindOfClass:[NSData class]]) {
100+
NSData * data = value;
101+
data = [data base64EncodedDataWithOptions:0];
102+
auto base64Str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
103+
auto prefix = [NSString stringWithUTF8String:kBase64Header];
104+
auto base64PrefixedStr = [prefix stringByAppendingString:base64Str];
105+
jsonValue = [base64PrefixedStr UTF8String];
106+
} else if ([value isKindOfClass:[NSString class]]) {
107+
jsonValue = [value UTF8String];
108+
} else if ([value isKindOfClass:[NSObject class]]) {
109+
jsonValue = Json::ValueType::objectValue;
110+
111+
unsigned int numberOfProperties;
112+
objc_property_t * properties = class_copyPropertyList([value class], &numberOfProperties);
113+
for (NSUInteger i = 0; i < numberOfProperties; i++) {
114+
objc_property_t property = properties[i];
115+
NSString * key = [[NSString alloc] initWithUTF8String:property_getName(property)];
116+
117+
Json::Value jsonElement;
118+
VerifyOrDie(CHIP_NO_ERROR == AsJsonValue([value valueForKey:key], jsonElement));
119+
jsonValue[[key UTF8String]] = jsonElement;
120+
}
121+
free(properties);
122+
} else {
123+
return CHIP_ERROR_NOT_IMPLEMENTED;
124+
}
125+
126+
return CHIP_NO_ERROR;
127+
}
128+
129+
} // namespace
130+
131+
namespace RemoteDataModelLogger {
132+
CHIP_ERROR LogAttributeAsJSON(NSNumber * endpointId, NSNumber * clusterId, NSNumber * attributeId, id result)
133+
{
134+
VerifyOrReturnError(gDelegate != nullptr, CHIP_NO_ERROR);
135+
136+
Json::Value value;
137+
value[kEndpointIdKey] = [endpointId unsignedLongLongValue];
138+
value[kClusterIdKey] = [clusterId unsignedLongLongValue];
139+
value[kAttributeIdKey] = [attributeId unsignedLongLongValue];
140+
141+
Json::Value jsonValue;
142+
VerifyOrDie(CHIP_NO_ERROR == AsJsonValue(result, jsonValue));
143+
value[kValueKey] = jsonValue;
144+
145+
auto valueStr = JsonToString(value);
146+
return gDelegate->LogJSON(valueStr.c_str());
147+
}
148+
149+
CHIP_ERROR LogCommandAsJSON(NSNumber * endpointId, NSNumber * clusterId, NSNumber * commandId, id result)
150+
{
151+
VerifyOrReturnError(gDelegate != nullptr, CHIP_NO_ERROR);
152+
153+
Json::Value value;
154+
value[kEndpointIdKey] = [endpointId unsignedLongLongValue];
155+
value[kClusterIdKey] = [clusterId unsignedLongLongValue];
156+
value[kCommandIdKey] = [commandId unsignedLongLongValue];
157+
158+
Json::Value jsonValue;
159+
VerifyOrDie(CHIP_NO_ERROR == AsJsonValue(result, jsonValue));
160+
value[kValueKey] = jsonValue;
161+
162+
auto valueStr = JsonToString(value);
163+
return gDelegate->LogJSON(valueStr.c_str());
164+
}
165+
166+
CHIP_ERROR LogAttributeErrorAsJSON(NSNumber * endpointId, NSNumber * clusterId, NSNumber * attributeId, NSError * error)
167+
{
168+
VerifyOrReturnError(gDelegate != nullptr, CHIP_NO_ERROR);
169+
170+
Json::Value value;
171+
value[kEndpointIdKey] = [endpointId unsignedLongLongValue];
172+
value[kClusterIdKey] = [clusterId unsignedLongLongValue];
173+
value[kAttributeIdKey] = [attributeId unsignedLongLongValue];
174+
175+
auto err = MTRErrorToCHIPErrorCode(error);
176+
auto status = chip::app::StatusIB(err);
177+
return LogError(value, status);
178+
}
179+
180+
CHIP_ERROR LogCommandErrorAsJSON(NSNumber * endpointId, NSNumber * clusterId, NSNumber * commandId, NSError * error)
181+
{
182+
VerifyOrReturnError(gDelegate != nullptr, CHIP_NO_ERROR);
183+
184+
Json::Value value;
185+
value[kEndpointIdKey] = [endpointId unsignedLongLongValue];
186+
value[kClusterIdKey] = [clusterId unsignedLongLongValue];
187+
value[kCommandIdKey] = [commandId unsignedLongLongValue];
188+
189+
auto err = MTRErrorToCHIPErrorCode(error);
190+
auto status = chip::app::StatusIB(err);
191+
return LogError(value, status);
192+
}
193+
194+
void SetDelegate(RemoteDataModelLoggerDelegate * delegate) { gDelegate = delegate; }
195+
}; // namespace RemoteDataModelLogger

0 commit comments

Comments
 (0)