Skip to content

Commit 63c3532

Browse files
authored
Test + updates for unknown client clusters (#2816)
1 parent 4c69395 commit 63c3532

File tree

2 files changed

+50
-16
lines changed

2 files changed

+50
-16
lines changed

packages/node/src/node/client/PeerBehavior.ts

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
ClusterComposer,
2626
ClusterId,
2727
ClusterRegistry,
28+
ClusterType,
2829
Command,
2930
CommandId,
3031
MutableCluster,
@@ -103,12 +104,10 @@ function instrumentDiscoveredShape(shape: PeerBehavior.DiscoveredClusterShape) {
103104
return type;
104105
}
105106

106-
let baseType: Behavior.Type;
107+
let baseType: Behavior.Type | undefined;
107108
const standardCluster = ClusterRegistry.get(shape.id);
108-
if (standardCluster) {
109+
if (standardCluster && !standardCluster.name.startsWith("Unknown cluster 0x")) {
109110
baseType = ClusterBehavior.for(standardCluster);
110-
} else {
111-
baseType = ClusterBehavior;
112111
}
113112

114113
type = discoveredCache[fingerprint] = generateDiscoveredType(analysis, baseType);
@@ -138,22 +137,31 @@ function instrumentKnownShape(shape: PeerBehavior.KnownClusterShape) {
138137
return type;
139138
}
140139

141-
function generateDiscoveredType(analysis: DiscoveredShapeAnalysis, baseType: Behavior.Type): ClusterBehavior.Type {
142-
// Ensure the input type is a ClusterBehavior
143-
if (!ClusterBehavior.is(baseType)) {
144-
throw new InternalError(`Base for cluster ${analysis.schema.name} is not a ClusterBehavior`);
145-
}
146-
140+
function generateDiscoveredType(analysis: DiscoveredShapeAnalysis, baseType?: Behavior.Type): ClusterBehavior.Type {
147141
let { schema } = analysis;
148-
let isExtended = false;
149-
const { attrSupportOverrides, extraAttrs, commandSupportOverrides, extraCommands } = analysis;
150142

151-
// Obtain a ClusterType. This provides TLV for known elements
152-
let { cluster } = baseType;
153-
if (!cluster) {
143+
let isExtended: boolean;
144+
let cluster: ClusterType;
145+
146+
if (baseType) {
147+
isExtended = false;
148+
149+
// Ensure the input type is a ClusterBehavior
150+
if (!ClusterBehavior.is(baseType)) {
151+
throw new InternalError(`Base for cluster ${analysis.schema.name} is not a ClusterBehavior`);
152+
}
153+
154+
cluster = baseType.cluster;
155+
} else {
156+
isExtended = true;
157+
154158
cluster = MutableCluster({ id: schema.id, name: schema.name, revision: schema.revision });
159+
160+
baseType = ClusterBehavior;
155161
}
156162

163+
const { attrSupportOverrides, extraAttrs, commandSupportOverrides, extraCommands } = analysis;
164+
157165
// Identify known features the device supports
158166
let supportedFeatures = analysis.shape.features;
159167
if (typeof supportedFeatures === "number") {

packages/node/test/node/ClientNodeTest.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

7+
import { ClusterBehavior } from "#behavior/cluster/ClusterBehavior.js";
78
import { DiscoveryError } from "#behavior/system/controller/discovery/DiscoveryError.js";
89
import { NetworkClient } from "#behavior/system/network/NetworkClient.js";
910
import { BasicInformationBehavior } from "#behaviors/basic-information";
@@ -15,7 +16,8 @@ import { AggregatorEndpoint } from "#endpoints/aggregator";
1516
import { b$, Crypto, deepCopy, MockCrypto, Seconds, Time, TimeoutError } from "#general";
1617
import { Specification } from "#model";
1718
import { ServerNode } from "#node/ServerNode.js";
18-
import { ClientSubscription, FabricManager, SustainedSubscription } from "#protocol";
19+
import { ClientSubscription, FabricManager, SustainedSubscription, Val } from "#protocol";
20+
import { MyBehavior } from "../behavior/cluster/cluster-behavior-test-util.js";
1921
import { MockSite } from "./mock-site.js";
2022

2123
describe("ClientNode", () => {
@@ -402,6 +404,30 @@ describe("ClientNode", () => {
402404
await ep1.commandsOf(OnOffClient).offWithEffect({ effectIdentifier: 0, effectVariant: 0 });
403405
});
404406

407+
it.only("properly supports unknown clusters", async () => {
408+
// *** SETUP ***
409+
410+
await using site = new MockSite();
411+
const { controller } = await site.addCommissionedPair({
412+
device: {
413+
type: ServerNode.RootEndpoint.with(MyBehavior),
414+
},
415+
});
416+
const peer = controller.peers.get("peer1")!;
417+
418+
// *** VERIFY STRUCTURE ***
419+
420+
const behavior = peer.behaviors.supported.cluster$1;
421+
expect(typeof behavior).equals("function");
422+
expect((behavior as ClusterBehavior.Type).schema.id).equals(1);
423+
expect((behavior as ClusterBehavior.Type).cluster.id).equals(1);
424+
425+
const state = peer.maybeStateOf("cluster$1");
426+
expect(typeof state).equals("object");
427+
expect((state as Val.Struct)[1]).equals("hello");
428+
expect((state as Val.Struct).attr$1).equals("hello");
429+
});
430+
405431
it("handles shutdown event and reestablishes connection", () => {
406432
// TODO
407433
});

0 commit comments

Comments
 (0)