/*
* PS3 Media Server, for streaming any medias to your PS3.
* Copyright (C) 2008 A.Brochard
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2
* of the License only.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package net.pms.configuration;
import static net.pms.configuration.RendererConfiguration.getRendererConfigurationBySocketAddress;
import static net.pms.configuration.RendererConfiguration.getRendererConfigurationByUA;
import static net.pms.configuration.RendererConfiguration.getRendererConfigurationByUAAHH;
import static net.pms.configuration.RendererConfiguration.loadRendererConfigurations;
import static net.pms.configuration.RendererConfiguration.resetAddressAssociation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.configuration.ConfigurationException;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
/**
* Test the RendererConfiguration class
*/
public class RendererConfigurationTest {
private final Map<String, String> testCases = new HashMap<String, String>();
@Before
public void setUp() {
// Silence all log messages from the PMS code that is being tested
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
context.reset();
// Set locale to EN to ignore translations for renderers
Locale.setDefault(Locale.ENGLISH);
// Cases that are too generic should not match anything
testCases.put("User-Agent: UPnP/1.0 DLNADOC/1.50", null);
testCases.put("User-Agent: Unknown Renderer", null);
testCases.put("X-Unknown-Header: Unknown Content", null);
// From AirPlayer.conf:
testCases.put("User-Agent: AirPlayer/1.0.09 CFNetwork/485.13.9 Darwin/11.0.0", "AirPlayer");
testCases.put("User-Agent: Lavf52.54.0", "AirPlayer");
// From BraviaEX.conf:
testCases.put("X-AV-Client-Info: av=5.0; cn=\"Sony Corporation\"; mn=\"BRAVIA KDL-32CX520\"; mv=\"1.7\";", "Sony Bravia EX");
// From BraviaHX.conf:
testCases.put("X-AV-Client-Info: av=5.0; cn=\"Sony Corporation\"; mn=\"BRAVIA KDL-55HX750\"; mv=\"1.7\";", "Sony Bravia HX");
// From Dlink510.conf:
testCases.put("User-Agent: DLNADOC/1.50 INTEL_NMPR/2.1", "D-Link DSM-510");
// From iPad-iPhone.conf:
testCases.put("User-Agent: 8player lite 2.2.3 (iPad; iPhone OS 5.0.1; nl_NL)", "iPad / iPhone");
testCases.put("User-Agent: yxplayer2%20lite/1.2.7 CFNetwork/485.13.9 Darwin/11.0.0", "iPad / iPhone");
testCases.put("User-Agent: MPlayer 1.0rc4-4.2.1", "iPad / iPhone");
testCases.put("User-Agent: NSPlayer/4.1.0.3856", "iPad / iPhone");
// From Philips.conf:
testCases.put("User-Agent: Allegro-Software-WebClient/4.61 DLNADOC/1.00", "Philips Aurea");
// From PhilipsPFL.conf:
testCases.put("User-Agent: Windows2000/0.0 UPnP/1.0 PhilipsIntelSDK/1.4 DLNADOC/1.50", "Philips TV");
// From PS3.conf:
testCases.put("User-Agent: PLAYSTATION 3", "PlayStation 3");
testCases.put("X-AV-Client-Info: av=5.0; cn=\"Sony Computer Entertainment Inc.\"; mn=\"PLAYSTATION 3\"; mv=\"1.0\"", "PlayStation 3");
// From Realtek.conf:
// FIXME: Actual conflict here! Popcorn Hour is returned...
//testCases.put("User-Agent: POSIX UPnP/1.0 Intel MicroStack/1.0.2718, RealtekMediaCenter, DLNADOC/1.50", "Realtek");
testCases.put("User-Agent: RealtekVOD neon/0.27.2", "Realtek");
// From SamsungAllShare.conf:
testCases.put("User-Agent: SEC_HHP_[HT]D5500/1.0", "Samsung AllShare");
testCases.put("User-Agent: SEC_HHP_[TV]UE32D5000/1.0", "Samsung AllShare");
testCases.put("User-Agent: SEC_HHP_ Family TV/1.0", "Samsung AllShare");
testCases.put("User-Agent: SEC_HHP_[TV]PS51D6900/1.0", "Samsung AllShare");
testCases.put("User-Agent: DLNADOC/1.50 SEC_HHP_[TV]UE32D5000/1.0", "Samsung AllShare");
testCases.put("User-Agent: DLNADOC/1.50 SEC_HHP_[TV]UN55D6050/1.0", "Samsung AllShare");
testCases.put("User-Agent: DLNADOC/1.50 SEC_HHP_ Family TV/1.0", "Samsung AllShare");
// From Samsung-SMT-G7400.conf:
testCases.put("User-Agent: Linux/2.6.35 UPnP/1.0 NDS_MHF DLNADOC/1.50", "Samsung SMT-G7400");
// From WDTVLive.conf:
testCases.put("User-Agent: INTEL_NMPR/2.1 DLNADOC/1.50 Intel MicroStack/1.0.1423", "WD TV Live");
// From XBMC.conf:
testCases.put("User-Agent: XBMC/10.0 r35648 (Mac OS X; 11.2.0 x86_64; http://www.xbmc.org)", "XBMC");
testCases.put("User-Agent: Platinum/0.5.3.0, DLNADOC/1.50", "XBMC");
}
/**
* Test the RendererConfiguration class and the consistency of the renderer
* .conf files it reads. This is done by feeding it known headers and
* checking whether it recognizes the correct renderer.
*/
@Test
public void testKnownHeaders() {
PmsConfiguration pmsConf = null;
try {
pmsConf = new PmsConfiguration(false);
} catch (ConfigurationException e) {
// This should be impossible since no configuration file will be loaded.
}
// Initialize the RendererConfiguration
loadRendererConfigurations(pmsConf);
// Test all header test cases
Set<Entry<String, String>> set = testCases.entrySet();
Iterator<Entry<String, String>> i = set.iterator();
while (i.hasNext()) {
Entry<String, String> entry = (Entry<String, String>) i.next();
testHeader(entry.getKey(), entry.getValue());
}
}
/**
* Test recognition with a forced default renderer configured.
*/
@Test
public void testForcedDefault() {
PmsConfiguration pmsConf = null;
try {
pmsConf = new PmsConfiguration(false);
} catch (ConfigurationException e) {
// This should be impossible since no configuration file will be loaded.
}
// Set default to PlayStation 3
pmsConf.setRendererDefault("PlayStation 3");
pmsConf.setRendererForceDefault(true);
// Initialize the RendererConfiguration
loadRendererConfigurations(pmsConf);
// Known and unknown renderers should always return default
testHeader("User-Agent: AirPlayer/1.0.09 CFNetwork/485.13.9 Darwin/11.0.0", "PlayStation 3");
testHeader("User-Agent: Unknown Renderer", "PlayStation 3");
testHeader("X-Unknown-Header: Unknown Content", "PlayStation 3");
}
/**
* Test recognition with a forced bogus default renderer configured.
*/
@Test
public void testBogusDefault() {
PmsConfiguration pmsConf = null;
try {
pmsConf = new PmsConfiguration(false);
} catch (ConfigurationException e) {
// This should be impossible since no configuration file will be loaded.
}
// Set default to non existent renderer
pmsConf.setRendererDefault("Bogus Renderer");
pmsConf.setRendererForceDefault(true);
// Initialize the RendererConfiguration
loadRendererConfigurations(pmsConf);
// Known and unknown renderers should return "Unknown renderer"
testHeader("User-Agent: AirPlayer/1.0.09 CFNetwork/485.13.9 Darwin/11.0.0", "Unknown renderer");
testHeader("User-Agent: Unknown Renderer", "Unknown renderer");
testHeader("X-Unknown-Header: Unknown Content", "Unknown renderer");
}
/**
* Test one particular header line to see if it returns the correct
* renderer. Set the correct renderer name to <code>null</code> to require
* that nothing matches at all.
*
* @param headerLine
* The header line to recognize.
* @param correctRendererName
* The name of the renderer.
*/
private void testHeader(String headerLine, String correctRendererName) {
if (correctRendererName != null) {
// Header is supposed to match a particular renderer
if (headerLine != null && headerLine.toLowerCase().startsWith("user-agent")) {
// Match by User-Agent
RendererConfiguration rc = getRendererConfigurationByUA(headerLine);
assertNotNull("Recognized renderer for header \"" + headerLine + "\"", rc);
assertEquals("Expected renderer \"" + correctRendererName + "\", "
+ "instead renderer \"" + rc.getRendererName() + "\" was returned for header \""
+ headerLine + "\"", correctRendererName, rc.getRendererName());
} else {
// Match by additional header
RendererConfiguration rc = getRendererConfigurationByUAAHH(headerLine);
assertNotNull("Recognized renderer for header \"" + headerLine + "\"", rc);
assertEquals("Expected renderer \"" + correctRendererName + "\" to be recognized, "
+ "instead renderer \"" + rc.getRendererName() + "\" was returned for header \""
+ headerLine + "\"", correctRendererName, rc.getRendererName());
}
} else {
// Header is supposed to match no renderer at all
if (headerLine != null && headerLine.toLowerCase().startsWith("user-agent")) {
// Match by User-Agent
RendererConfiguration rc = getRendererConfigurationByUA(headerLine);
assertEquals("Expected no matching renderer to be found for header \"" + headerLine
+ "\", instead renderer \"" + (rc != null ? rc.getRendererName() : "")
+ "\" was recognized.", null,
rc);
} else {
// Match by additional header
RendererConfiguration rc = getRendererConfigurationByUAAHH(headerLine);
assertEquals("Expected no matching renderer to be found for header \"" + headerLine
+ "\", instead renderer \"" + (rc != null ? rc.getRendererName() : "")
+ "\" was recognized.", null, rc);
}
}
}
/**
* Test {@link RendererConfiguration#getRendererConfigurationBySocketAddress(InetAddress)}
* @throws UnknownHostException
*/
@Test
public void testGetBySocketAddress() throws UnknownHostException {
RendererConfiguration conf = null;
PmsConfiguration pmsConf = null;
try {
pmsConf = new PmsConfiguration(false);
} catch (ConfigurationException e) {
// This should be impossible since no configuration file will be loaded.
}
// Initialize the RendererConfiguration
loadRendererConfigurations(pmsConf);
// Nothing forced
pmsConf.setRendererForceIp("");
resetAddressAssociation();
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.1.1"));
assertNull(conf);
// Garbled configuration: no renderer name
pmsConf.setRendererForceIp("@192.168.1.1");
resetAddressAssociation();
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.1.1"));
assertNull(conf);
// Garbled configuration: no IP address
pmsConf.setRendererForceIp("PlayStation 3");
resetAddressAssociation();
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.1.1"));
assertNull(conf);
// Garbled configuration: invalid IP address
pmsConf.setRendererForceIp("PlayStation 3@textip");
resetAddressAssociation();
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.1.1"));
assertNull(conf);
// Garbled configuration: unknown renderer name
pmsConf.setRendererForceIp("No Match@192.168.1.1");
resetAddressAssociation();
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.1.1"));
assertNull(conf);
// Garbled configuration: incorrect entries plus correct entry
pmsConf.setRendererForceIp("Sony Bravia EX,No Match@192.168.1.2,Playstation 3@192.168.1.1");
resetAddressAssociation();
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.1.2"));
assertNull(conf);
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.1.1"));
assertNotNull(conf);
assertEquals("PlayStation 3", conf.getRendererName());
// Set single forced IP address
pmsConf.setRendererForceIp("PlayStation 3@192.168.1.1");
resetAddressAssociation();
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.1.2"));
assertNull(conf);
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.1.1"));
assertNotNull(conf);
assertEquals("PlayStation 3", conf.getRendererName());
// Set forced IP address range
pmsConf.setRendererForceIp("PlayStation 3@192.168.1");
resetAddressAssociation();
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.1.1"));
assertNotNull(conf);
assertEquals("PlayStation 3", conf.getRendererName());
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.1.23"));
assertNotNull(conf);
assertEquals("PlayStation 3", conf.getRendererName());
// Set forced IP address range
pmsConf.setRendererForceIp("PlayStation 3@192.168.0-1.*");
resetAddressAssociation();
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.2.1"));
assertNull(conf);
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.0.1"));
assertNotNull(conf);
assertEquals("PlayStation 3", conf.getRendererName());
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.1.23"));
assertNotNull(conf);
assertEquals("PlayStation 3", conf.getRendererName());
// Set multiple forced IP addresses
pmsConf.setRendererForceIp("Sony Bravia EX@192.168.1.1,Sony Bravia HX@192.168.1.2");
resetAddressAssociation();
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.2.1"));
assertNull(conf);
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.1.1"));
assertNotNull(conf);
assertEquals("Sony Bravia EX", conf.getRendererName());
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.1.2"));
assertNotNull(conf);
assertEquals("Sony Bravia HX", conf.getRendererName());
// Multiple addresses with range overlap
pmsConf.setRendererForceIp("Sony Bravia HX@192.168.1.2,Sony Bravia EX@192.168.0-1.*");
resetAddressAssociation();
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.2.1"));
assertNull(conf);
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.1.1"));
assertNotNull(conf);
assertEquals("Sony Bravia EX", conf.getRendererName());
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.1.2"));
assertNotNull(conf);
assertEquals("Sony Bravia HX", conf.getRendererName());
// Renderer name matching is case insensitive
pmsConf.setRendererForceIp("playstation 3@192.168.1.1");
resetAddressAssociation();
conf = getRendererConfigurationBySocketAddress(InetAddress.getByName("192.168.1.1"));
assertNotNull(conf);
assertEquals("PlayStation 3", conf.getRendererName());
}
}