mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[bosesoundtouch] Fix regression and add tests (#14097)
* Fix regression and add tests Signed-off-by: lsiepel <leosiepel@gmail.com>
This commit is contained in:
parent
390c790936
commit
8c175ba4bc
@ -155,7 +155,6 @@ public class CommandExecutor implements AvailableSources {
|
||||
contentItem.setPresetID(presetID);
|
||||
|
||||
currentContentItem = contentItem;
|
||||
|
||||
}
|
||||
updateOperatingValues();
|
||||
}
|
||||
|
@ -97,11 +97,6 @@ public class XMLResponseHandler extends DefaultHandler {
|
||||
// showing a
|
||||
// warning for unhandled states
|
||||
|
||||
XMLHandlerState localState = null;
|
||||
if (stateMap != null) {
|
||||
localState = stateMap.get(localName);
|
||||
}
|
||||
|
||||
switch (curState) {
|
||||
case INIT:
|
||||
if ("updates".equals(localName)) {
|
||||
@ -112,10 +107,13 @@ public class XMLResponseHandler extends DefaultHandler {
|
||||
state = XMLHandlerState.Unprocessed;
|
||||
}
|
||||
} else {
|
||||
XMLHandlerState localState = stateMap.get(localName);
|
||||
if (localState == null) {
|
||||
logger.debug("{}: Unhandled XML entity during {}: '{}", handler.getDeviceName(), curState,
|
||||
logger.warn("{}: Unhandled XML entity during {}: '{}", handler.getDeviceName(), curState,
|
||||
localName);
|
||||
state = XMLHandlerState.Unprocessed;
|
||||
} else {
|
||||
state = localState;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -196,9 +194,11 @@ public class XMLResponseHandler extends DefaultHandler {
|
||||
state = XMLHandlerState.Presets;
|
||||
} else if ("group".equals(localName)) {
|
||||
this.masterDeviceId = new BoseSoundTouchConfiguration();
|
||||
state = stateMap.get(localName);
|
||||
} else {
|
||||
if (localState == null) {
|
||||
logger.debug("{}: Unhandled XML entity during {}: '{}", handler.getDeviceName(), curState,
|
||||
state = stateMap.get(localName);
|
||||
if (state == null) {
|
||||
logger.warn("{}: Unhandled XML entity during {}: '{}", handler.getDeviceName(), curState,
|
||||
localName);
|
||||
|
||||
state = XMLHandlerState.Unprocessed;
|
||||
@ -366,16 +366,12 @@ public class XMLResponseHandler extends DefaultHandler {
|
||||
if (contentItem == null) {
|
||||
contentItem = new ContentItem();
|
||||
}
|
||||
String source = "";
|
||||
String location = "";
|
||||
String sourceAccount = "";
|
||||
Boolean isPresetable = false;
|
||||
|
||||
if (attributes != null) {
|
||||
source = attributes.getValue("source");
|
||||
sourceAccount = attributes.getValue("sourceAccount");
|
||||
location = attributes.getValue("location");
|
||||
isPresetable = Boolean.parseBoolean(attributes.getValue("isPresetable"));
|
||||
String source = attributes.getValue("source");
|
||||
String location = attributes.getValue("location");
|
||||
String sourceAccount = attributes.getValue("sourceAccount");
|
||||
Boolean isPresetable = Boolean.parseBoolean(attributes.getValue("isPresetable"));
|
||||
|
||||
if (source != null) {
|
||||
contentItem.setSource(source);
|
||||
|
@ -47,6 +47,7 @@ public class XMLResponseProcessor {
|
||||
|
||||
public void handleMessage(String msg) throws SAXException, IOException, ParserConfigurationException {
|
||||
SAXParserFactory parserFactory = SAXParserFactory.newInstance();
|
||||
parserFactory.setNamespaceAware(true);
|
||||
SAXParser parser = parserFactory.newSAXParser();
|
||||
XMLReader reader = parser.getXMLReader();
|
||||
reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
|
@ -306,6 +306,14 @@ public class BoseSoundTouchHandler extends BaseThingHandler implements WebSocket
|
||||
return commandExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the CommandExecutor of this handler
|
||||
*
|
||||
*/
|
||||
public void setCommandExecutor(@Nullable CommandExecutor commandExecutor) {
|
||||
this.commandExecutor = commandExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Session this handler has opened
|
||||
*
|
||||
|
@ -0,0 +1,136 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.bosesoundtouch.internal;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.notNull;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.openhab.binding.bosesoundtouch.internal.handler.BoseSoundTouchHandler;
|
||||
import org.openhab.binding.bosesoundtouch.internal.handler.InMemmoryContentStorage;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.library.types.StringListType;
|
||||
import org.openhab.core.storage.Storage;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.ThingHandlerCallback;
|
||||
import org.openhab.core.thing.binding.builder.ChannelBuilder;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Leo Siepel - Initial contribution
|
||||
*
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@NonNullByDefault
|
||||
public class SoundTouch20Tests {
|
||||
|
||||
private @Mock @NonNullByDefault({}) ThingHandlerCallback thingHandlerCallback;
|
||||
private @NonNullByDefault({}) Thing soundTouchThing;
|
||||
private @NonNullByDefault({}) BoseSoundTouchHandler thingHandler;
|
||||
private @NonNullByDefault({}) XMLResponseProcessor processor;
|
||||
private ThingUID thingUID = new ThingUID(BoseSoundTouchBindingConstants.BINDING_ID, "soundtouch20");
|
||||
private ChannelUID volumeChannelUID = new ChannelUID(thingUID, BoseSoundTouchBindingConstants.CHANNEL_VOLUME);
|
||||
private ChannelUID presetChannelUID = new ChannelUID(thingUID, BoseSoundTouchBindingConstants.CHANNEL_PRESET);
|
||||
private Storage<@NonNull ContentItem> storage = new InMemmoryContentStorage();
|
||||
private @Mock @NonNullByDefault({}) BoseStateDescriptionOptionProvider stateDescriptionProvider;
|
||||
|
||||
@BeforeEach
|
||||
public void initialize() {
|
||||
// arrange
|
||||
Configuration config = new Configuration();
|
||||
config.put(BoseSoundTouchConfiguration.MAC_ADDRESS, "B0D5CC1AAAA1");
|
||||
|
||||
soundTouchThing = ThingBuilder.create(BoseSoundTouchBindingConstants.BST_20_THING_TYPE_UID, thingUID)
|
||||
.withConfiguration(config).withChannel(ChannelBuilder.create(volumeChannelUID, "Number").build())
|
||||
.withChannel(ChannelBuilder.create(presetChannelUID, "Number").build()).build();
|
||||
|
||||
PresetContainer container = new PresetContainer(storage);
|
||||
thingHandler = new BoseSoundTouchHandler(soundTouchThing, container, stateDescriptionProvider);
|
||||
processor = new XMLResponseProcessor(thingHandler);
|
||||
}
|
||||
|
||||
private void processIncomingMessage(String mesage) {
|
||||
try {
|
||||
processor.handleMessage(mesage);
|
||||
} catch (Exception e) {
|
||||
assert false : MessageFormat.format("handleMessage throws an exception: {0} Stacktrace: {1}",
|
||||
e.getMessage(), e.getStackTrace());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configurationPropertyUpdated() {
|
||||
// arange
|
||||
CommandExecutor executor = new CommandExecutor(thingHandler);
|
||||
thingHandler.setCommandExecutor(executor);
|
||||
String message = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?><msg><header deviceID=\"B0D5CC1AAAA1\" url=\"info\" method=\"GET\"><request requestID=\"0\" msgType=\"RESPONSE\"><info type=\"new\" /></request></header><body><info deviceID=\"B0D5CC1AAAA1\"><name>livingroom</name><type>SoundTouch 20</type><margeAccountUUID>3504027</margeAccountUUID><components><component><componentCategory>SCM</componentCategory><softwareVersion>27.0.6.46330.5043500 epdbuild.trunk.hepdswbld04.2022-08-04T11:20:29</softwareVersion><serialNumber>U6148010803720048000100</serialNumber></component><component><componentCategory>PackagedProduct</componentCategory><serialNumber>069430P5227013812</serialNumber></component></components><margeURL>https://streaming.bose.com</margeURL><networkInfo type=\"SCM\"><macAddress>B0D5CC1AAAA1</macAddress><ipAddress>192.168.1.1</ipAddress></networkInfo><networkInfo type=\"SMSC\"><macAddress>5CF821E2FD76</macAddress><ipAddress>192.168.1.1</ipAddress></networkInfo><moduleType>sm2</moduleType><variant>spotty</variant><variantMode>normal</variantMode><countryCode>GB</countryCode><regionCode>GB</regionCode></info></body></msg>";
|
||||
|
||||
// act
|
||||
processIncomingMessage(message);
|
||||
|
||||
// assert
|
||||
assertEquals("27.0.6.46330.5043500",
|
||||
soundTouchThing.getProperties().get(org.openhab.core.thing.Thing.PROPERTY_FIRMWARE_VERSION));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void channelVolumeUpdated() {
|
||||
// arrange
|
||||
CommandExecutor executor = new CommandExecutor(thingHandler);
|
||||
|
||||
thingHandler.setCommandExecutor(executor);
|
||||
Mockito.when(thingHandlerCallback.isChannelLinked((ChannelUID) notNull())).thenReturn(true);
|
||||
thingHandler.setCallback(thingHandlerCallback);
|
||||
String message = "<updates deviceID=\"B0D5CC1AAAA1\"><volumeUpdated><volume><actualvolume>27</actualvolume></volume></volumeUpdated></updates>";
|
||||
|
||||
// act
|
||||
processIncomingMessage(message);
|
||||
|
||||
// assert
|
||||
Mockito.verify(thingHandlerCallback).stateUpdated(eq(volumeChannelUID), eq(new PercentType("27")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
public void channelPresetUpdated() {
|
||||
// arrange
|
||||
CommandExecutor executor = new CommandExecutor(thingHandler);
|
||||
|
||||
thingHandler.setCommandExecutor(executor);
|
||||
Mockito.when(thingHandlerCallback.isChannelLinked((ChannelUID) notNull())).thenReturn(true);
|
||||
thingHandler.setCallback(thingHandlerCallback);
|
||||
String message = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?><presets><preset id=\"1\" createdOn=\"1502124154\" updatedOn=\"1644607971\"><ContentItem source=\"TUNEIN\" type=\"stationurl\" location=\"/v1/playback/station/s25077\" sourceAccount=\"\" isPresetable=\"true\"><itemName>Radio FM1</itemName><containerArt>http://cdn-profiles.tunein.com/s25077/images/logoq.jpg</containerArt></ContentItem></preset><preset id=\"2\" createdOn=\"1485893875\" updatedOn=\"1612895566\"><ContentItem source=\"STORED_MUSIC\" location=\"22$2955\" sourceAccount=\"00113254-f4eb-0011-ebf4-ebf454321100/0\" isPresetable=\"true\"><itemName>Medicine At Midnight</itemName><containerArt /></ContentItem></preset><preset id=\"3\" createdOn=\"1506167722\" updatedOn=\"1506167722\"><ContentItem source=\"STORED_MUSIC\" location=\"22$1421\" sourceAccount=\"00113254-f4eb-0011-ebf4-ebf454321100/0\" isPresetable=\"true\"><itemName>Concrete & Gold</itemName><containerArt /></ContentItem></preset><preset id=\"4\" createdOn=\"1444146657\" updatedOn=\"1542740566\"><ContentItem source=\"TUNEIN\" type=\"stationurl\" location=\"/v1/playback/station/s24896\" sourceAccount=\"\" isPresetable=\"true\"><itemName>SWR3</itemName><containerArt>http://radiotime-logos.s3.amazonaws.com/s24896q.png</containerArt></ContentItem></preset><preset id=\"5\" createdOn=\"1468517184\" updatedOn=\"1542740566\"><ContentItem source=\"TUNEIN\" type=\"stationurl\" location=\"/v1/playback/station/s103302\" sourceAccount=\"\" isPresetable=\"true\"><itemName>SRF 3</itemName><containerArt>http://radiotime-logos.s3.amazonaws.com/s24862q.png</containerArt></ContentItem></preset><preset id=\"6\" createdOn=\"1481548081\" updatedOn=\"1524211387\"><ContentItem source=\"STORED_MUSIC\" location=\"22$882\" sourceAccount=\"00113254-f4eb-0011-ebf4-ebf454321100/0\" isPresetable=\"true\"><itemName>Sonic Highways</itemName><containerArt /></ContentItem></preset></presets>";
|
||||
|
||||
// act
|
||||
processIncomingMessage(message);
|
||||
|
||||
// assert
|
||||
// TODO: check if preset channels have changed
|
||||
Mockito.verify(thingHandlerCallback).stateUpdated(eq(presetChannelUID), eq(new StringListType("27")));
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.bosesoundtouch.internal.handler;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.bosesoundtouch.internal.ContentItem;
|
||||
import org.openhab.core.storage.Storage;
|
||||
|
||||
/**
|
||||
* @author Leo Siepel - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class InMemmoryContentStorage implements Storage<ContentItem> {
|
||||
Map<String, @Nullable ContentItem> items = new TreeMap<>();
|
||||
|
||||
public InMemmoryContentStorage() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ContentItem put(String key, @Nullable ContentItem value) {
|
||||
return items.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ContentItem remove(String key) {
|
||||
return items.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(String key) {
|
||||
return items.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ContentItem get(String key) {
|
||||
return items.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<@NonNull String> getKeys() {
|
||||
return items.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<@Nullable ContentItem> getValues() {
|
||||
return items.values();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user