Skip to content

Commit b0a5688

Browse files
authored
Updates to start/stop discovery and add more tests (#489)
Signed-off-by: Chris Jackson <chris@cd-jackson.com>
1 parent c252c33 commit b0a5688

6 files changed

Lines changed: 376 additions & 86 deletions

File tree

com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/app/discovery/ZigBeeDiscoveryExtension.java

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.zsmartsystems.zigbee.ZigBeeNetworkManager;
2222
import com.zsmartsystems.zigbee.ZigBeeNetworkNodeListener;
2323
import com.zsmartsystems.zigbee.ZigBeeNode;
24+
import com.zsmartsystems.zigbee.ZigBeeNode.ZigBeeNodeState;
2425
import com.zsmartsystems.zigbee.ZigBeeStatus;
2526
import com.zsmartsystems.zigbee.app.ZigBeeNetworkExtension;
2627
import com.zsmartsystems.zigbee.zdo.command.DeviceAnnounce;
@@ -97,6 +98,10 @@ public void extensionShutdown() {
9798
networkDiscoverer.shutdown();
9899
}
99100

101+
for (ZigBeeNodeServiceDiscoverer nodeDiscoverer : nodeDiscovery.values()) {
102+
nodeDiscoverer.stopDiscovery();
103+
}
104+
100105
extensionStarted = false;
101106

102107
if (futureTask != null) {
@@ -159,20 +164,25 @@ public void nodeAdded(ZigBeeNode node) {
159164

160165
logger.debug("DISCOVERY Extension: Adding discoverer for {}", node.getIeeeAddress());
161166

162-
ZigBeeNodeServiceDiscoverer nodeDiscoverer = new ZigBeeNodeServiceDiscoverer(networkManager, node);
163-
nodeDiscovery.put(node.getIeeeAddress(), nodeDiscoverer);
164-
nodeDiscoverer.startDiscovery();
167+
startDiscovery(node);
165168
}
166169

167170
@Override
168171
public void nodeUpdated(ZigBeeNode node) {
169-
// Not used
172+
// We need to handle the cases where the node changes to ONLINE, or to OFFLINE
173+
if (node.getNodeState() == ZigBeeNodeState.ONLINE && !nodeDiscovery.containsKey(node.getIeeeAddress())) {
174+
// If the state is ONLINE, then ensure discovery is running
175+
startDiscovery(node);
176+
} else if (node.getNodeState() != ZigBeeNodeState.ONLINE && nodeDiscovery.containsKey(node.getIeeeAddress())) {
177+
// If state is not ONLINE, then stop discovery
178+
stopDiscovery(node);
179+
}
170180
}
171181

172182
@Override
173183
public void nodeRemoved(ZigBeeNode node) {
174184
logger.debug("DISCOVERY Extension: Removing discoverer for {}", node.getIeeeAddress());
175-
nodeDiscovery.remove(node.getIeeeAddress());
185+
stopDiscovery(node);
176186
}
177187

178188
@Override
@@ -203,14 +213,27 @@ public void rediscoverNode(final IeeeAddress ieeeAddress) {
203213
networkDiscoverer.rediscoverNode(ieeeAddress);
204214
}
205215

206-
private void stopScheduler() {
216+
protected void startDiscovery(ZigBeeNode node) {
217+
ZigBeeNodeServiceDiscoverer nodeDiscoverer = new ZigBeeNodeServiceDiscoverer(networkManager, node);
218+
nodeDiscovery.put(node.getIeeeAddress(), nodeDiscoverer);
219+
nodeDiscoverer.startDiscovery();
220+
}
221+
222+
protected void stopDiscovery(ZigBeeNode node) {
223+
ZigBeeNodeServiceDiscoverer discoverer = nodeDiscovery.remove(node.getIeeeAddress());
224+
if (discoverer != null) {
225+
discoverer.stopDiscovery();
226+
}
227+
}
228+
229+
protected void stopScheduler() {
207230
if (futureTask != null) {
208231
futureTask.cancel(true);
209232
futureTask = null;
210233
}
211234
}
212235

213-
private void startScheduler(int initialPeriod) {
236+
protected void startScheduler(int initialPeriod) {
214237
stopScheduler();
215238

216239
Runnable meshUpdateThread = new Runnable() {
@@ -228,8 +251,8 @@ public void run() {
228251
}
229252

230253
/**
231-
* Gets the Collection of {@link ZigBeeNodeServiceDiscoverer} for all nodes
232-
*
254+
* Gets the Collection of {@link ZigBeeNodeServiceDiscoverer}s for all nodes
255+
*
233256
* @return Collection of {@link ZigBeeNodeServiceDiscoverer}
234257
*/
235258
public Collection<ZigBeeNodeServiceDiscoverer> getNodeDiscoverers() {

com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/app/discovery/ZigBeeNodeServiceDiscoverer.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -232,13 +232,17 @@ public void stopDiscovery() {
232232
}
233233

234234
/**
235+
* Gets the maximum backoff counter. If this number of retries are sent, the request will fail.
236+
*
235237
* @return the maxBackoff
236238
*/
237239
public int getMaxBackoff() {
238240
return maxBackoff;
239241
}
240242

241243
/**
244+
* Sets the maximum backoff counter. If this number of retries are sent, the request will fail.
245+
*
242246
* @param maxBackoff the maxBackoff to set
243247
*/
244248
public void setMaxBackoff(int maxBackoff) {
@@ -560,9 +564,7 @@ private class NodeServiceDiscoveryTask implements Runnable {
560564
@Override
561565
public void run() {
562566
try {
563-
logger.debug("{}: Node SVC Discovery: running", node.getIeeeAddress());
564567
NodeDiscoveryTask discoveryTask;
565-
566568
synchronized (discoveryTasks) {
567569
discoveryTask = discoveryTasks.peek();
568570
}
@@ -572,6 +574,7 @@ public void run() {
572574
networkManager.updateNode(node);
573575
return;
574576
}
577+
logger.debug("{}: Node SVC Discovery: running {}", node.getIeeeAddress(), discoveryTask);
575578

576579
boolean success = false;
577580
switch (discoveryTask) {
@@ -607,9 +610,8 @@ public void run() {
607610
synchronized (discoveryTasks) {
608611
discoveryTasks.remove(discoveryTask);
609612
}
610-
logger.debug("{}: Node SVC Discovery: request {} successful. Advanced to {}.",
613+
logger.debug("{}: Node SVC Discovery: request {} successful. Advancing to {}.",
611614
node.getIeeeAddress(), discoveryTask, discoveryTasks.peek());
612-
613615
retryCnt = 0;
614616
} else if (retryCnt > maxBackoff) {
615617
logger.debug("{}: Node SVC Discovery: request {} failed after {} attempts.", node.getIeeeAddress(),
@@ -667,8 +669,9 @@ public void startDiscovery() {
667669

668670
/**
669671
* Starts service discovery for the node in order to update the mesh. This adds the
670-
* {@link NodeDiscoveryTask#NEIGHBORS} and {@link NodeDiscoveryTask#ROUTES} tasks to the task list. Note that
671-
* {@link NodeDiscoveryTask#ROUTES} is not added for end devices.
672+
* {@link NodeDiscoveryTask#NEIGHBORS} and {@link NodeDiscoveryTask#ROUTES} tasks to the task list.
673+
* <p>
674+
* Note that {@link NodeDiscoveryTask#ROUTES} is not added for end devices.
672675
*/
673676
public void updateMesh() {
674677
logger.debug("{}: Node SVC Discovery: Update mesh", node.getIeeeAddress());
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* Copyright (c) 2016-2018 by the respective copyright holders.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*/
8+
package com.zsmartsystems.zigbee;
9+
10+
import java.lang.reflect.Field;
11+
import java.lang.reflect.Modifier;
12+
13+
/**
14+
*
15+
* @author Chris Jackson
16+
*
17+
*/
18+
public class TestUtilities {
19+
20+
static public void setField(Class clazz, Object object, String fieldName, Object newValue) throws Exception {
21+
Field field = clazz.getDeclaredField(fieldName);
22+
field.setAccessible(true);
23+
Field modifiersField = Field.class.getDeclaredField("modifiers");
24+
modifiersField.setAccessible(true);
25+
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
26+
field.set(object, newValue);
27+
}
28+
29+
}

com.zsmartsystems.zigbee/src/test/java/com/zsmartsystems/zigbee/app/discovery/ZigBeeDiscoveryExtensionTest.java

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,23 @@
99

1010
import static org.junit.Assert.assertEquals;
1111

12+
import java.util.Map;
13+
import java.util.concurrent.ConcurrentHashMap;
14+
1215
import org.junit.Test;
1316
import org.mockito.ArgumentMatchers;
1417
import org.mockito.Mockito;
1518

19+
import com.zsmartsystems.zigbee.IeeeAddress;
20+
import com.zsmartsystems.zigbee.TestUtilities;
1621
import com.zsmartsystems.zigbee.ZigBeeCommandListener;
1722
import com.zsmartsystems.zigbee.ZigBeeNetworkManager;
1823
import com.zsmartsystems.zigbee.ZigBeeNetworkNodeListener;
24+
import com.zsmartsystems.zigbee.ZigBeeNode;
25+
import com.zsmartsystems.zigbee.ZigBeeNode.ZigBeeNodeState;
1926
import com.zsmartsystems.zigbee.ZigBeeStatus;
27+
import com.zsmartsystems.zigbee.zdo.command.DeviceAnnounce;
28+
import com.zsmartsystems.zigbee.zdo.command.ManagementLeaveResponse;
2029

2130
/**
2231
*
@@ -25,27 +34,86 @@
2534
*/
2635
public class ZigBeeDiscoveryExtensionTest {
2736
@Test
28-
public void test() {
37+
public void test() throws Exception {
2938
ZigBeeNetworkManager networkManager = Mockito.mock(ZigBeeNetworkManager.class);
3039

31-
ZigBeeDiscoveryExtension extension = new ZigBeeDiscoveryExtension();
40+
ZigBeeNode node = Mockito.mock(ZigBeeNode.class);
41+
Mockito.when(node.getIeeeAddress()).thenReturn(new IeeeAddress("1234567890ABCDEF"));
42+
Mockito.when(node.getNodeState()).thenReturn(ZigBeeNodeState.ONLINE);
43+
44+
ZigBeeDiscoveryExtension extension = Mockito.spy(ZigBeeDiscoveryExtension.class);
45+
Mockito.doNothing().when(extension).startDiscovery(node);
46+
Mockito.doNothing().when(extension).stopDiscovery(node);
47+
Mockito.doNothing().when(extension).startScheduler(ArgumentMatchers.any(int.class));
48+
3249
extension.setUpdatePeriod(0);
3350

3451
assertEquals(ZigBeeStatus.SUCCESS, extension.extensionInitialize(networkManager));
3552
extension.extensionStartup();
3653

54+
extension.setUpdatePeriod(0);
55+
Mockito.verify(extension, Mockito.times(1)).stopScheduler();
56+
assertEquals(0, extension.getUpdatePeriod());
57+
58+
extension.setUpdatePeriod(1);
59+
Mockito.verify(extension, Mockito.times(1)).startScheduler(1);
60+
assertEquals(1, extension.getUpdatePeriod());
61+
3762
Mockito.verify(networkManager, Mockito.timeout(1000).atLeast(1))
3863
.addNetworkNodeListener(ArgumentMatchers.any(ZigBeeNetworkNodeListener.class));
3964
Mockito.verify(networkManager, Mockito.timeout(1000).atLeast(1))
4065
.addCommandListener(ArgumentMatchers.any(ZigBeeCommandListener.class));
4166

67+
extension.nodeAdded(node);
68+
Mockito.verify(extension, Mockito.times(1)).startDiscovery(node);
69+
70+
Map<IeeeAddress, ZigBeeNodeServiceDiscoverer> nodeDiscovery = new ConcurrentHashMap<>();
71+
nodeDiscovery.put(node.getIeeeAddress(), Mockito.mock(ZigBeeNodeServiceDiscoverer.class));
72+
TestUtilities.setField(ZigBeeDiscoveryExtension.class, extension, "nodeDiscovery", nodeDiscovery);
73+
74+
assertEquals(1, extension.getNodeDiscoverers().size());
75+
76+
// Add again and make sure we don't call startDiscovery again
77+
extension.nodeAdded(node);
78+
Mockito.verify(extension, Mockito.times(1)).startDiscovery(node);
79+
80+
// Updated node when ONLINE should not do anything
81+
extension.nodeUpdated(node);
82+
Mockito.verify(extension, Mockito.times(1)).startDiscovery(node);
83+
Mockito.verify(extension, Mockito.times(0)).stopDiscovery(node);
84+
85+
// Updated node when OFFLINE should stop discovery
86+
Mockito.when(node.getNodeState()).thenReturn(ZigBeeNodeState.OFFLINE);
87+
extension.nodeUpdated(node);
88+
Mockito.verify(extension, Mockito.times(1)).startDiscovery(node);
89+
Mockito.verify(extension, Mockito.times(1)).stopDiscovery(node);
90+
91+
// Remove node should also stopDiscovery
92+
extension.nodeRemoved(node);
93+
Mockito.verify(extension, Mockito.times(1)).startDiscovery(node);
94+
Mockito.verify(extension, Mockito.times(2)).stopDiscovery(node);
95+
96+
nodeDiscovery.clear();
97+
98+
// Updated node when ONLINE and node not known should start discovery
99+
Mockito.when(node.getNodeState()).thenReturn(ZigBeeNodeState.ONLINE);
100+
extension.nodeUpdated(node);
101+
Mockito.verify(extension, Mockito.times(2)).startDiscovery(node);
102+
Mockito.verify(extension, Mockito.times(2)).stopDiscovery(node);
103+
104+
ManagementLeaveResponse leave = Mockito.mock(ManagementLeaveResponse.class);
105+
extension.commandReceived(leave);
106+
Mockito.verify(extension, Mockito.times(1)).refresh();
107+
108+
DeviceAnnounce announce = Mockito.mock(DeviceAnnounce.class);
109+
extension.commandReceived(announce);
110+
Mockito.verify(extension, Mockito.times(2)).refresh();
111+
42112
extension.extensionShutdown();
43113

44114
Mockito.verify(networkManager, Mockito.timeout(1000).atLeast(1))
45115
.removeNetworkNodeListener(ArgumentMatchers.any(ZigBeeNetworkNodeListener.class));
46116
Mockito.verify(networkManager, Mockito.timeout(1000).atLeast(1))
47117
.removeCommandListener(ArgumentMatchers.any(ZigBeeCommandListener.class));
48-
49-
assertEquals(0, extension.getUpdatePeriod());
50118
}
51119
}

0 commit comments

Comments
 (0)