make a first step to split between pure JUnit and integration tests (#488)

* make a first step to split between pure JUnit and integration tests

Related to: https://github.com/openhab/openhab-core/issues/482

Signed-off-by: Markus Rathgeb <maggu2810@gmail.com>
This commit is contained in:
Markus Rathgeb
2019-01-30 08:57:06 +01:00
committed by Kai Kreuzer
parent c4f1fc3cfa
commit 76dd62623f
585 changed files with 214 additions and 323 deletions
@@ -0,0 +1,19 @@
This content is produced and maintained by the Eclipse SmartHome project.
* Project home: https://eclipse.org/smarthome/
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/eclipse/smarthome
== Copyright Holders
See the NOTICE file distributed with the source code at
https://github.com/eclipse/smarthome/blob/master/NOTICE
for detailed information regarding copyright ownership.
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.pde.ui.JunitLaunchConfig">
<booleanAttribute key="append.args" value="true"/>
<stringAttribute key="application" value="org.eclipse.pde.junit.runtime.coretestapplication"/>
<booleanAttribute key="askclear" value="false"/>
<booleanAttribute key="automaticAdd" value="false"/>
<booleanAttribute key="automaticValidate" value="true"/>
<stringAttribute key="bootstrap" value=""/>
<stringAttribute key="checked" value="[NONE]"/>
<booleanAttribute key="clearConfig" value="true"/>
<booleanAttribute key="clearws" value="true"/>
<booleanAttribute key="clearwslog" value="false"/>
<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/pde-junit"/>
<booleanAttribute key="default" value="false"/>
<booleanAttribute key="default_auto_start" value="true"/>
<booleanAttribute key="includeOptional" value="false"/>
<stringAttribute key="location" value="${workspace_loc}/../junit-workspace"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/org.eclipse.smarthome.core.audio.test"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.smarthome.core.audio.test"/>
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.smarthome.core.audio.test"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Djetty.port=9090 -Djetty.home.bundle=org.eclipse.jetty.osgi.boot"/>
<stringAttribute key="pde.version" value="3.3"/>
<stringAttribute key="product" value=""/>
<booleanAttribute key="run_in_ui_thread" value="false"/>
<stringAttribute key="selected_target_plugins" value="ch.qos.logback.classic@default:default,ch.qos.logback.core@default:default,ch.qos.logback.slf4j@default:false,com.eclipsesource.jaxrs.jersey-min@default:default,com.google.gson@default:default,com.google.guava@default:default,javax.activation@default:default,javax.inject@default:default,javax.measure.unit-api@default:default,javax.servlet@default:default,javax.transaction@default:false,javax.xml@default:default,net.bytebuddy.byte-buddy-agent@default:default,net.bytebuddy.byte-buddy@default:default,org.apache.ant@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.felix.scr@1:true,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.codehaus.groovy@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.runtime@default:true,org.eclipse.emf.common@default:default,org.eclipse.emf.ecore.xmi@default:default,org.eclipse.emf.ecore@default:default,org.eclipse.equinox.app@default:default,org.eclipse.equinox.cm@default:default,org.eclipse.equinox.common@default:true,org.eclipse.equinox.ds@1:true,org.eclipse.equinox.event@2:default,org.eclipse.equinox.http.servlet@default:default,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.region@default:false,org.eclipse.equinox.registry@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.equinox.util@default:default,org.eclipse.equinox.weaving.hook@default:false,org.eclipse.jetty.client@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.osgi.alpn.fragment@default:false,org.eclipse.jetty.osgi.boot@default:default,org.eclipse.jetty.osgi.httpservice@default:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi.util@default:default,org.eclipse.osgi@-1:true,org.hamcrest.core@default:default,org.junit@default:default,org.mockito.mockito-core@default:default,org.objectweb.asm@default:default,org.objenesis@default:default,org.slf4j.api@default:default,tec.uom.lib.uom-lib-common@default:default,tec.uom.se@default:default"/>
<stringAttribute key="selected_workspace_plugins" value="org.eclipse.smarthome.config.core@default:default,org.eclipse.smarthome.config.xml@default:default,org.eclipse.smarthome.core.audio.test@default:false,org.eclipse.smarthome.core.audio@default:default,org.eclipse.smarthome.core.binding.xml@default:default,org.eclipse.smarthome.core.thing.xml@default:default,org.eclipse.smarthome.core.thing@default:default,org.eclipse.smarthome.core@default:default,org.eclipse.smarthome.io.console@default:default,org.eclipse.smarthome.io.http@default:default,org.eclipse.smarthome.test@default:default"/>
<booleanAttribute key="show_selected_only" value="false"/>
<stringAttribute key="templateConfig" value="${target_home}\configuration\config.ini"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfig" value="true"/>
<booleanAttribute key="useDefaultConfigArea" value="false"/>
<booleanAttribute key="useProduct" value="false"/>
</launchConfiguration>
+165
View File
@@ -0,0 +1,165 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.core.itests</groupId>
<artifactId>org.openhab.core.reactor.itests</artifactId>
<version>2.5.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.core.audio.tests</artifactId>
<packaging>eclipse-test-plugin</packaging>
<name>openHAB Core :: Integration Tests :: Audio Test</name>
<build>
<plugins>
<plugin>
<groupId>${tycho-groupid}</groupId>
<artifactId>target-platform-configuration</artifactId>
<configuration>
<dependency-resolution>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>0.0.0</version>
</dependency>
<extraRequirements>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.jetty.osgi.boot</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.equinox.cm</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.equinox.ds</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.equinox.event</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.config.xml</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.core.binding.xml</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.core.thing.xml</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.jetty.server</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.jetty.servlet</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.equinox.http.servlet</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.jetty.osgi.httpservice</id>
<versionRange>0.0.0</versionRange>
</requirement>
</extraRequirements>
</dependency-resolution>
</configuration>
</plugin>
<plugin>
<groupId>${tycho-groupid}</groupId>
<artifactId>tycho-surefire-plugin</artifactId>
<configuration>
<bundleStartLevel>
<bundle>
<id>org.eclipse.jetty.osgi.boot</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.ds</id>
<level>1</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.event</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.core.thing</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.config.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.config.xml</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.core.thing.xml</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.core.binding.xml</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.jetty.server</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.jetty.servlet</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.http.servlet</id>
<level>3</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.jetty.osgi.httpservice</id>
<level>3</level>
<autoStart>true</autoStart>
</bundle>
</bundleStartLevel>
<argLine>-Djetty.port=9090 -Djetty.home.bundle=org.eclipse.jetty.osgi.boot</argLine>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,124 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.core.audio.internal;
import static org.junit.Assert.fail;
import java.util.concurrent.CompletableFuture;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.smarthome.core.audio.AudioFormat;
import org.eclipse.smarthome.core.audio.AudioStream;
import org.eclipse.smarthome.core.audio.ByteArrayAudioStream;
import org.eclipse.smarthome.core.audio.FixedLengthAudioStream;
import org.eclipse.smarthome.test.TestPortUtil;
import org.eclipse.smarthome.test.TestServer;
import org.eclipse.smarthome.test.java.JavaTest;
import org.junit.After;
import org.junit.Before;
/**
* Base class for tests using the {@link AudioServlet}.
*
* @author Henning Treu - initial contribution
*
*/
public abstract class AbstractAudioServeltTest extends JavaTest {
protected AudioServlet audioServlet;
private int port;
private TestServer server;
private final static String AUDIO_SERVLET_PROTOCOL = "http";
private final static String AUDIO_SERVLET_HOSTNAME = "localhost";
private CompletableFuture<Boolean> serverStarted;
private HttpClient httpClient;
@Before
public void setupServerAndClient() {
audioServlet = new AudioServlet();
ServletHolder servletHolder = new ServletHolder(audioServlet);
port = TestPortUtil.findFreePort();
server = new TestServer(AUDIO_SERVLET_HOSTNAME, port, 10000, servletHolder);
serverStarted = server.startServer();
httpClient = new HttpClient();
}
@After
public void tearDownServerAndClient() throws Exception {
server.stopServer();
httpClient.stop();
}
protected ByteArrayAudioStream getByteArrayAudioStream(byte[] byteArray, String container, String codec) {
int bitDepth = 16;
int bitRate = 1000;
long frequency = 16384;
AudioFormat audioFormat = new AudioFormat(container, codec, true, bitDepth, bitRate, frequency);
return new ByteArrayAudioStream(byteArray, audioFormat);
}
protected ContentResponse getHttpResponse(AudioStream audioStream) throws Exception {
String url = serveStream(audioStream);
return getHttpRequest(url).send();
}
protected String serveStream(AudioStream stream) throws Exception {
return serveStream(stream, null);
}
protected void startHttpClient(HttpClient client) {
if (!client.isStarted()) {
try {
client.start();
} catch (Exception e) {
fail("An exception " + e + " was thrown, while starting the HTTP client");
}
}
}
protected Request getHttpRequest(String url) {
startHttpClient(httpClient);
return httpClient.newRequest(url).method(HttpMethod.GET);
}
protected String serveStream(AudioStream stream, Integer timeInterval) throws Exception {
serverStarted.get(); // wait for the server thread to be started
String path;
if (timeInterval != null) {
path = audioServlet.serve((FixedLengthAudioStream) stream, timeInterval);
} else {
path = audioServlet.serve(stream);
}
return generateURL(AUDIO_SERVLET_PROTOCOL, AUDIO_SERVLET_HOSTNAME, port, path);
}
private String generateURL(String protocol, String hostname, int port, String path) {
return String.format("%s://%s:%s%s", protocol, hostname, port, path);
}
}
@@ -0,0 +1,200 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.core.audio.internal;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.*;
import java.io.File;
import java.io.IOException;
import java.util.Locale;
import org.eclipse.smarthome.config.core.ConfigConstants;
import org.eclipse.smarthome.core.audio.AudioException;
import org.eclipse.smarthome.core.audio.AudioFormat;
import org.eclipse.smarthome.core.audio.AudioSource;
import org.eclipse.smarthome.core.audio.AudioStream;
import org.eclipse.smarthome.core.audio.FileAudioStream;
import org.eclipse.smarthome.core.audio.URLAudioStream;
import org.eclipse.smarthome.core.audio.internal.fake.AudioSinkFake;
import org.eclipse.smarthome.core.i18n.LocaleProvider;
import org.eclipse.smarthome.io.console.Console;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* OSGi test for {@link AudioConsoleCommandExtension}
*
* @author Petar Valchev - Initial contribution and API
* @author Christoph Weitkamp - Added parameter to adjust the volume
* @author Wouter Born - Migrate tests from Groovy to Java
*/
public class AudioConsoleTest extends AbstractAudioServeltTest {
private AudioConsoleCommandExtension audioConsoleCommandExtension;
private AudioManagerImpl audioManager;
private AudioSinkFake audioSink;
private final byte[] testByteArray = new byte[] { 0, 1, 2 };
private static final String CONFIGURATION_DIRECTORY_NAME = "configuration";
protected static final String MP3_FILE_NAME = "mp3AudioFile.mp3";
protected static final String MP3_FILE_PATH = CONFIGURATION_DIRECTORY_NAME + "/sounds/" + MP3_FILE_NAME;
protected static final String WAV_FILE_NAME = "wavAudioFile.wav";
protected static final String WAV_FILE_PATH = CONFIGURATION_DIRECTORY_NAME + "/sounds/" + WAV_FILE_NAME;
private String consoleOutput;
private final Console consoleMock = new Console() {
@Override
public void println(String s) {
consoleOutput = s;
}
@Override
public void printUsage(String s) {
}
@Override
public void print(String s) {
consoleOutput = s;
}
};
private final int testTimeout = 1;
@Before
public void setUp() {
audioManager = new AudioManagerImpl();
audioSink = new AudioSinkFake();
audioManager.addAudioSink(audioSink);
audioConsoleCommandExtension = new AudioConsoleCommandExtension();
audioConsoleCommandExtension.setAudioManager(audioManager);
LocaleProvider localeProvider = mock(LocaleProvider.class);
when(localeProvider.getLocale()).thenReturn(Locale.getDefault());
audioConsoleCommandExtension.setLocaleProvider(localeProvider);
System.setProperty(ConfigConstants.CONFIG_DIR_PROG_ARGUMENT, CONFIGURATION_DIRECTORY_NAME);
}
@After
public void tearDown() {
System.setProperty(ConfigConstants.CONFIG_DIR_PROG_ARGUMENT, ConfigConstants.DEFAULT_CONFIG_FOLDER);
}
@Test
public void testUsages() {
assertThat("Could not get AudioConsoleCommandExtension's usages", audioConsoleCommandExtension.getUsages(),
is(notNullValue()));
}
@Test
public void audioConsolePlaysFile() throws AudioException, IOException {
AudioStream audioStream = new FileAudioStream(new File(WAV_FILE_PATH));
String[] args = new String[] { AudioConsoleCommandExtension.SUBCMD_PLAY, WAV_FILE_NAME };
audioConsoleCommandExtension.execute(args, consoleMock);
assertThat(audioSink.audioFormat.isCompatible(audioStream.getFormat()), is(true));
audioStream.close();
}
@Test
public void audioConsolePlaysFileForASpecifiedSink() throws AudioException, IOException {
AudioStream audioStream = new FileAudioStream(new File(WAV_FILE_PATH));
String[] args = new String[] { AudioConsoleCommandExtension.SUBCMD_PLAY, audioSink.getId(), WAV_FILE_NAME };
audioConsoleCommandExtension.execute(args, consoleMock);
assertThat(audioSink.audioFormat.isCompatible(audioStream.getFormat()), is(true));
audioStream.close();
}
@Test
public void audioConsolePlaysFileForASpecifiedSinkWithASpecifiedVolume() throws AudioException, IOException {
AudioStream audioStream = new FileAudioStream(new File(WAV_FILE_PATH));
String[] args = new String[] { AudioConsoleCommandExtension.SUBCMD_PLAY, audioSink.getId(), WAV_FILE_NAME,
"25" };
audioConsoleCommandExtension.execute(args, consoleMock);
assertThat(audioSink.audioFormat.isCompatible(audioStream.getFormat()), is(true));
audioStream.close();
}
@Test
public void audioConsolePlaysFileForASpecifiedSinkWithAnInvalidVolume() {
String[] args = new String[] { AudioConsoleCommandExtension.SUBCMD_PLAY, audioSink.getId(), WAV_FILE_NAME,
"invalid" };
audioConsoleCommandExtension.execute(args, consoleMock);
waitForAssert(() -> assertThat("The given volume was invalid", consoleOutput, nullValue()));
}
@Test
public void audioConsolePlaysStream() throws Exception {
AudioStream audioStream = getByteArrayAudioStream(testByteArray, AudioFormat.CONTAINER_WAVE,
AudioFormat.CODEC_PCM_SIGNED);
String url = serveStream(audioStream, testTimeout);
String[] args = new String[] { AudioConsoleCommandExtension.SUBCMD_STREAM, url };
audioConsoleCommandExtension.execute(args, consoleMock);
assertThat("The streamed URL was not as expected", ((URLAudioStream) audioSink.audioStream).getURL(), is(url));
}
@Test
public void audioConsolePlaysStreamForASpecifiedSink() throws Exception {
AudioStream audioStream = getByteArrayAudioStream(testByteArray, AudioFormat.CONTAINER_WAVE,
AudioFormat.CODEC_PCM_SIGNED);
String url = serveStream(audioStream, testTimeout);
String[] args = new String[] { AudioConsoleCommandExtension.SUBCMD_STREAM, audioSink.getId(), url };
audioConsoleCommandExtension.execute(args, consoleMock);
assertThat("The streamed URL was not as expected", ((URLAudioStream) audioSink.audioStream).getURL(), is(url));
}
@Test
public void audioConsoleListsSinks() {
String[] args = new String[] { AudioConsoleCommandExtension.SUBCMD_SINKS };
audioConsoleCommandExtension.execute(args, consoleMock);
waitForAssert(() -> assertThat("The listed sink was not as expected", consoleOutput,
is(String.format("* %s (%s)", audioSink.getLabel(Locale.getDefault()), audioSink.getId()))));
}
@Test
public void audioConsoleListsSources() {
AudioSource audioSource = mock(AudioSource.class);
when(audioSource.getId()).thenReturn("sourceId");
audioManager.addAudioSource(audioSource);
String[] args = new String[] { AudioConsoleCommandExtension.SUBCMD_SOURCES };
audioConsoleCommandExtension.execute(args, consoleMock);
waitForAssert(() -> assertThat("The listed source was not as expected", consoleOutput,
is(String.format("* %s (%s)", audioSource.getLabel(Locale.getDefault()), audioSource.getId()))));
}
}
@@ -0,0 +1,123 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.core.audio.internal;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.smarthome.core.audio.AudioFormat;
import org.junit.Test;
/**
* OSGi test for {@link AudioFormat}
*
* @author Petar Valchev - Initial contribution
* @author Wouter Born - Migrate tests from Groovy to Java
*/
public class AudioFormatTest {
private final String testContainer = AudioFormat.CONTAINER_WAVE;
private final String testCodec = AudioFormat.CODEC_PCM_SIGNED;
private final boolean testBigEndian = true;
private final Integer testBitDepth = new Integer(16);
private final Integer testBitRate = new Integer(1000);
private final Long testFrequency = new Long(1024);
@Test
public void thereIsNoBestMatchForAnAudioFormatIfOneOfTheFieldsIsNull() {
Set<AudioFormat> inputs = new HashSet<>();
Set<AudioFormat> outputs = new HashSet<>();
AudioFormat nullContainerAudioFormat = new AudioFormat(null, testCodec, testBigEndian, testBitDepth,
testBitRate, testFrequency);
AudioFormat nullCodecAudioFormat = new AudioFormat(testContainer, null, testBigEndian, testBitDepth,
testBitRate, testFrequency);
AudioFormat nullBitDepthAudioFormat = new AudioFormat(testContainer, testCodec, testBigEndian, null,
testBitRate, testFrequency);
AudioFormat nullBitRateAudioFormat = new AudioFormat(testContainer, testCodec, testBigEndian, testBitDepth,
null, testFrequency);
AudioFormat nullFrequencyAudioFormat = new AudioFormat(testContainer, testCodec, testBigEndian, testBitDepth,
testBitRate, null);
AudioFormat outputAudioFormat = new AudioFormat(testContainer, testCodec, testBigEndian, testBitDepth,
testBitRate, testFrequency);
inputs.add(nullContainerAudioFormat);
inputs.add(nullCodecAudioFormat);
inputs.add(nullBitDepthAudioFormat);
inputs.add(nullBitRateAudioFormat);
inputs.add(nullFrequencyAudioFormat);
outputs.add(outputAudioFormat);
AudioFormat bestMatch = AudioFormat.getBestMatch(inputs, outputs);
assertThat("The best match for the audio format was not as expected", bestMatch, is(nullValue()));
}
@Test
public void waveContainerIsPreferredWhenDeterminingABestMatch() {
Set<AudioFormat> audioFormats = new HashSet<>();
AudioFormat waveContainerAudioFormat = new AudioFormat(testContainer, testCodec, true, testBitDepth,
testBitRate, testFrequency);
AudioFormat oggContainerAudioFormat = new AudioFormat(AudioFormat.CONTAINER_OGG, testCodec, true, testBitDepth,
testBitRate, testFrequency);
audioFormats.add(waveContainerAudioFormat);
audioFormats.add(oggContainerAudioFormat);
AudioFormat preferredFormat = AudioFormat.getPreferredFormat(audioFormats);
assertThat("The best match for the audio format was not as expected", preferredFormat,
is(waveContainerAudioFormat));
}
@Test
public void theCompatibleWaveContainerIsTheBestMatch() {
Set<AudioFormat> inputs = new HashSet<>();
Set<AudioFormat> outputs = new HashSet<>();
AudioFormat alawAudioFormat = new AudioFormat(testContainer, AudioFormat.CODEC_PCM_ALAW, true, testBitDepth,
testBitRate, testFrequency);
AudioFormat ulawAudioFormat = new AudioFormat(testContainer, AudioFormat.CODEC_PCM_ULAW, true, testBitDepth,
testBitRate, testFrequency);
inputs.add(alawAudioFormat);
inputs.add(ulawAudioFormat);
outputs.add(alawAudioFormat);
AudioFormat bestMatch = AudioFormat.getBestMatch(inputs, outputs);
assertThat("The best match for the audio format was not as expected", bestMatch, is(alawAudioFormat));
}
@Test
public void thereIsNoBestMatchIfNoWaveContainer() {
Set<AudioFormat> inputs = new HashSet<>();
Set<AudioFormat> outputs = new HashSet<>();
AudioFormat oggContainerAudioFormat = new AudioFormat(AudioFormat.CONTAINER_OGG, testCodec, true, testBitDepth,
testBitRate, testFrequency);
AudioFormat nonContainerAudioFormat = new AudioFormat(AudioFormat.CONTAINER_NONE, AudioFormat.CODEC_MP3, true,
testBitDepth, testBitRate, testFrequency);
inputs.add(oggContainerAudioFormat);
inputs.add(nonContainerAudioFormat);
outputs.add(oggContainerAudioFormat);
outputs.add(nonContainerAudioFormat);
AudioFormat bestMatch = AudioFormat.getBestMatch(inputs, outputs);
assertThat("The best match for the audio format was not as expected", bestMatch, is(nullValue()));
}
}
@@ -0,0 +1,91 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.core.audio.internal;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
import org.eclipse.smarthome.core.audio.AudioFormat;
import org.eclipse.smarthome.core.audio.AudioStream;
import org.eclipse.smarthome.core.audio.ByteArrayAudioStream;
import org.eclipse.smarthome.core.audio.URLAudioStream;
import org.eclipse.smarthome.core.audio.internal.fake.AudioSinkFake;
import org.junit.Before;
import org.junit.Test;
/**
* OSGi test for {@link AudioManagerImpl}
*
* @author Petar Valchev - Initial contribution and API
* @author Christoph Weitkamp - Added parameter to adjust the volume
* @author Wouter Born - Migrate tests from Groovy to Java
* @author Henning Treu - extract servlet tests
*/
public class AudioManagerServletTest extends AbstractAudioServeltTest {
private AudioManagerImpl audioManager;
private AudioSinkFake audioSink;
@Before
public void setup() {
audioManager = new AudioManagerImpl();
audioSink = new AudioSinkFake();
}
@Test
public void audioManagerProcessesMultitimeStreams() throws Exception {
audioManager.addAudioSink(audioSink);
int streamTimeout = 10;
assertServedStream(streamTimeout);
}
@Test
public void audioManagerProcessesOneTimeStream() throws Exception {
audioManager.addAudioSink(audioSink);
assertServedStream(null);
}
@Test
public void audioManagerDoesNotProcessStreamsIfThereIsNoRegisteredSink() throws Exception {
int streamTimeout = 10;
assertServedStream(streamTimeout);
}
private void assertServedStream(Integer timeInterval) throws Exception {
AudioStream audioStream = getByteArrayAudioStream(AudioFormat.CONTAINER_WAVE, AudioFormat.CODEC_PCM_SIGNED);
String url = serveStream(audioStream, timeInterval);
audioManager.stream(url, audioSink.getId());
if (audioManager.getSink() == audioSink) {
assertThat("The streamed url was not as expected", ((URLAudioStream) audioSink.audioStream).getURL(),
is(url));
} else {
assertThat(String.format("The sink %s received an unexpected stream", audioSink.getId()),
audioSink.audioStream, is(nullValue()));
}
}
private ByteArrayAudioStream getByteArrayAudioStream(String container, String codec) {
int bitDepth = 16;
int bitRate = 1000;
long frequency = 16384;
byte[] testByteArray = new byte[] { 0, 1, 2 };
AudioFormat audioFormat = new AudioFormat(container, codec, true, bitDepth, bitRate, frequency);
return new ByteArrayAudioStream(testByteArray, audioFormat);
}
}
@@ -0,0 +1,325 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.core.audio.internal;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
import java.util.function.BiFunction;
import org.eclipse.smarthome.config.core.ConfigConstants;
import org.eclipse.smarthome.config.core.ParameterOption;
import org.eclipse.smarthome.core.audio.AudioException;
import org.eclipse.smarthome.core.audio.AudioFormat;
import org.eclipse.smarthome.core.audio.AudioSource;
import org.eclipse.smarthome.core.audio.AudioStream;
import org.eclipse.smarthome.core.audio.ByteArrayAudioStream;
import org.eclipse.smarthome.core.audio.FileAudioStream;
import org.eclipse.smarthome.core.audio.UnsupportedAudioStreamException;
import org.eclipse.smarthome.core.audio.internal.fake.AudioSinkFake;
import org.eclipse.smarthome.core.library.types.PercentType;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* OSGi test for {@link AudioManagerImpl}
*
* @author Petar Valchev - Initial contribution and API
* @author Christoph Weitkamp - Added parameter to adjust the volume
* @author Wouter Born - Migrate tests from Groovy to Java
* @author Henning Treu - Convert to plain java tests
*/
public class AudioManagerTest {
private AudioManagerImpl audioManager;
private AudioSinkFake audioSink;
private AudioSource audioSource;
private static final String CONFIGURATION_DIRECTORY_NAME = "configuration";
private static final String MP3_FILE_NAME = "mp3AudioFile.mp3";
private static final String MP3_FILE_PATH = CONFIGURATION_DIRECTORY_NAME + "/sounds/" + MP3_FILE_NAME;
private static final String WAV_FILE_NAME = "wavAudioFile.wav";
private static final String WAV_FILE_PATH = CONFIGURATION_DIRECTORY_NAME + "/sounds/" + WAV_FILE_NAME;
@Before
public void setup() {
audioManager = new AudioManagerImpl();
audioSink = new AudioSinkFake();
audioSource = mock(AudioSource.class);
when(audioSource.getId()).thenReturn("audioSourceId");
when(audioSource.getLabel(any(Locale.class))).thenReturn("audioSourceLabel");
System.setProperty(ConfigConstants.CONFIG_DIR_PROG_ARGUMENT, CONFIGURATION_DIRECTORY_NAME);
}
@After
public void tearDown() {
System.setProperty(ConfigConstants.CONFIG_DIR_PROG_ARGUMENT, ConfigConstants.DEFAULT_CONFIG_FOLDER);
}
@Test
public void audioManagerPlaysByteArrayAudioStream() throws AudioException {
audioManager.addAudioSink(audioSink);
ByteArrayAudioStream audioStream = getByteArrayAudioStream(AudioFormat.CONTAINER_WAVE, AudioFormat.CODEC_MP3);
audioManager.play(audioStream, audioSink.getId());
AudioFormat expectedAudioFormat = audioStream.getFormat();
assertThat(audioSink.audioFormat.isCompatible(expectedAudioFormat), is(true));
}
@Test
public void nullStreamsAreProcessed() {
audioManager.addAudioSink(audioSink);
audioManager.play(null, audioSink.getId());
assertThat(audioSink.isStreamProcessed, is(true));
assertThat(audioSink.isStreamStopped, is(true));
}
@Test
public void audioManagerPlaysStreamFromWavAudioFiles() throws AudioException {
audioManager.addAudioSink(audioSink);
AudioStream audioStream = new FileAudioStream(new File(WAV_FILE_PATH));
audioManager.play(audioStream, audioSink.getId());
assertThat(audioSink.audioFormat.isCompatible(audioStream.getFormat()), is(true));
}
@Test
public void audioManagerPlaysStreamFromMp3AudioFiles() throws AudioException {
audioManager.addAudioSink(audioSink);
AudioStream audioStream = new FileAudioStream(new File(MP3_FILE_PATH));
audioManager.play(audioStream, audioSink.getId());
assertThat(audioSink.audioFormat.isCompatible(audioStream.getFormat()), is(true));
}
@Test
public void audioManagerPlaysWavAudioFiles() throws AudioException, IOException {
audioManager.addAudioSink(audioSink);
AudioStream audioStream = new FileAudioStream(new File(WAV_FILE_PATH));
audioManager.playFile(WAV_FILE_NAME, audioSink.getId());
assertThat(audioSink.audioFormat.isCompatible(audioStream.getFormat()), is(true));
audioStream.close();
}
@Test
public void audioManagerPlaysMp3AudioFiles() throws AudioException, IOException {
audioManager.addAudioSink(audioSink);
AudioStream audioStream = new FileAudioStream(new File(MP3_FILE_PATH));
audioManager.playFile(MP3_FILE_NAME, audioSink.getId());
assertThat(audioSink.audioFormat.isCompatible(audioStream.getFormat()), is(true));
audioStream.close();
}
@Test
public void fileIsNotProcessedIfThereIsNoRegisteredSink() throws AudioException {
File file = new File(MP3_FILE_PATH);
audioManager.playFile(file.getName(), audioSink.getId());
assertThat(audioSink.isStreamProcessed, is(false));
}
@Test
public void audioManagerHandlesUnsupportedAudioFormatException() throws AudioException {
audioManager.addAudioSink(audioSink);
audioSink.isUnsupportedAudioFormatExceptionExpected = true;
try {
audioManager.playFile(MP3_FILE_NAME, audioSink.getId());
} catch (UnsupportedAudioStreamException e) {
fail("An exception " + e + " was thrown, while trying to process a stream");
}
}
@Test
public void audioManagerHandlesUnsupportedAudioStreamException() throws AudioException {
audioManager.addAudioSink(audioSink);
audioSink.isUnsupportedAudioStreamExceptionExpected = true;
try {
audioManager.playFile(MP3_FILE_NAME, audioSink.getId());
} catch (UnsupportedAudioStreamException e) {
fail("An exception " + e + " was thrown, while trying to process a stream");
}
}
@Test
public void audioManagerSetsTheVolumeOfASink() throws IOException {
audioManager.addAudioSink(audioSink);
PercentType initialVolume = new PercentType(67);
PercentType sinkMockVolume = getSinkMockVolume(initialVolume);
assertThat(sinkMockVolume, is(initialVolume));
}
@Test
public void theVolumeOfANullSinkIsZero() throws IOException {
assertThat(audioManager.getVolume(null), is(PercentType.ZERO));
}
@Test
public void audioManagerSetsTheVolumeOfNotRegisteredSinkToZero() throws IOException {
PercentType initialVolume = new PercentType(67);
PercentType sinkMockVolume = getSinkMockVolume(initialVolume);
assertThat(sinkMockVolume, is(PercentType.ZERO));
}
@Test
public void sourceIsRegistered() {
assertRegisteredSource(false);
}
@Test
public void defaultSourceIsRegistered() {
assertRegisteredSource(true);
}
@Test
public void sinkIsRegistered() {
assertRegisteredSink(false);
}
@Test
public void defaultSinkIsRegistered() {
assertRegisteredSink(true);
}
@Test
public void sinkIsAddedInParameterOptions() {
assertAddedParameterOption(AudioManagerImpl.CONFIG_DEFAULT_SINK, Locale.getDefault());
}
@Test
public void sourceIsAddedInParameterOptions() {
assertAddedParameterOption(AudioManagerImpl.CONFIG_DEFAULT_SOURCE, Locale.getDefault());
}
@Test
public void inCaseOfWrongUriNoParameterOptionsAreAdded() {
audioManager.addAudioSink(audioSink);
Collection<ParameterOption> parameterOptions = audioManager.getParameterOptions(URI.create("wrong.uri"),
AudioManagerImpl.CONFIG_DEFAULT_SINK, Locale.US);
assertThat("The parameter options were not as expected", parameterOptions, is(nullValue()));
}
private void assertRegisteredSource(boolean isSourceDefault) {
audioManager.addAudioSource(audioSource);
if (isSourceDefault) {
audioManager
.modified(Collections.singletonMap(AudioManagerImpl.CONFIG_DEFAULT_SOURCE, audioSource.getId()));
} else {
// just to make sure there is no default source
audioManager.modified(Collections.emptyMap());
}
assertThat(String.format("The source %s was not registered", audioSource.getId()), audioManager.getSource(),
is(audioSource));
assertThat(String.format("The source %s was not added to the set of sources", audioSource.getId()),
audioManager.getAllSources().contains(audioSource), is(true));
assertThat(String.format("The source %s was not added to the set of sources", audioSource.getId()),
audioManager.getSourceIds(audioSource.getId()).contains(audioSource.getId()), is(true));
}
private void assertRegisteredSink(boolean isSinkDefault) {
audioManager.addAudioSink(audioSink);
if (isSinkDefault) {
audioManager.modified(Collections.singletonMap(AudioManagerImpl.CONFIG_DEFAULT_SINK, audioSink.getId()));
} else {
// just to make sure there is no default sink
audioManager.modified(Collections.emptyMap());
}
assertThat(String.format("The sink %s was not registered", audioSink.getId()), audioManager.getSink(),
is(audioSink));
assertThat(String.format("The sink %s was not added to the set of sinks", audioSink.getId()),
audioManager.getAllSinks().contains(audioSink), is(true));
assertThat(String.format("The sink %s was not added to the set of sinks", audioSink.getId()),
audioManager.getSinkIds(audioSink.getId()).contains(audioSink.getId()), is(true));
}
private PercentType getSinkMockVolume(PercentType initialVolume) throws IOException {
audioManager.setVolume(initialVolume, audioSink.getId());
String sinkMockId = audioSink.getId();
return audioManager.getVolume(sinkMockId);
}
/**
*
* @param param - either default source or default sink
*/
private void assertAddedParameterOption(String param, Locale locale) {
String id = "";
String label = "";
switch (param) {
case AudioManagerImpl.CONFIG_DEFAULT_SINK:
audioManager.addAudioSink(audioSink);
id = audioSink.getId();
label = audioSink.getLabel(locale);
break;
case AudioManagerImpl.CONFIG_DEFAULT_SOURCE:
audioManager.addAudioSource(audioSource);
id = audioSource.getId();
label = audioSource.getLabel(locale);
break;
default:
fail("The parameter must be either default sink or default source");
}
Collection<ParameterOption> parameterOptions = audioManager
.getParameterOptions(URI.create(AudioManagerImpl.CONFIG_URI), param, locale);
@SuppressWarnings("null")
BiFunction<String, String, Boolean> isParameterOptionAdded = (v, l) -> parameterOptions.stream()
.anyMatch(po -> po.getValue().equals(v) && po.getLabel().equals(l));
assertThat(param + " was not added to the parameter options", isParameterOptionAdded.apply(id, label),
is(true));
}
private ByteArrayAudioStream getByteArrayAudioStream(String container, String codec) {
int bitDepth = 16;
int bitRate = 1000;
long frequency = 16384;
byte[] testByteArray = new byte[] { 0, 1, 2 };
AudioFormat audioFormat = new AudioFormat(container, codec, true, bitDepth, bitRate, frequency);
return new ByteArrayAudioStream(testByteArray, audioFormat);
}
}
@@ -0,0 +1,159 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.core.audio.internal;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
import java.io.File;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.smarthome.config.core.ConfigConstants;
import org.eclipse.smarthome.core.audio.AudioFormat;
import org.eclipse.smarthome.core.audio.AudioStream;
import org.eclipse.smarthome.core.audio.FileAudioStream;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Test cases for {@link AudioServlet}
*
* @author Petar Valchev - Initial contribution
* @author Wouter Born - Migrate tests from Groovy to Java
*/
public class AudioServletTest extends AbstractAudioServeltTest {
private final String MEDIA_TYPE_AUDIO_WAV = "audio/wav";
private final String MEDIA_TYPE_AUDIO_OGG = "audio/ogg";
private final String MEDIA_TYPE_AUDIO_MPEG = "audio/mpeg";
private static final String CONFIGURATION_DIRECTORY_NAME = "configuration";
private static final String WAV_FILE_NAME = "wavAudioFile.wav";
private static final String WAV_FILE_PATH = CONFIGURATION_DIRECTORY_NAME + "/sounds/" + WAV_FILE_NAME;
private final byte[] testByteArray = new byte[] { 0, 1, 2 };
@Before
public void setup() {
System.setProperty(ConfigConstants.CONFIG_DIR_PROG_ARGUMENT, CONFIGURATION_DIRECTORY_NAME);
}
@After
public void tearDown() {
System.setProperty(ConfigConstants.CONFIG_DIR_PROG_ARGUMENT, ConfigConstants.DEFAULT_CONFIG_FOLDER);
}
@Test
public void audioServletProcessesByteArrayStream() throws Exception {
AudioStream audioStream = getByteArrayAudioStream(testByteArray, AudioFormat.CONTAINER_NONE,
AudioFormat.CODEC_MP3);
ContentResponse response = getHttpResponse(audioStream);
assertThat("The response status was not as expected", response.getStatus(), is(HttpStatus.OK_200));
assertThat("The response content was not as expected", response.getContent(), is(testByteArray));
assertThat("The response media type was not as expected", response.getMediaType(),
is(equalTo(MEDIA_TYPE_AUDIO_MPEG)));
}
@Test
public void audioServletProcessesStreamFromWavFile() throws Exception {
AudioStream audioStream = new FileAudioStream(new File(WAV_FILE_PATH));
ContentResponse response = getHttpResponse(audioStream);
assertThat("The response status was not as expected", response.getStatus(), is(HttpStatus.OK_200));
assertThat("The response media type was not as expected", response.getMediaType(), is(MEDIA_TYPE_AUDIO_WAV));
}
@Test
public void audioServletProcessesStreamFromOggContainer() throws Exception {
AudioStream audioStream = getByteArrayAudioStream(testByteArray, AudioFormat.CONTAINER_OGG,
AudioFormat.CODEC_PCM_SIGNED);
ContentResponse response = getHttpResponse(audioStream);
assertThat("The response status was not as expected", response.getStatus(), is(HttpStatus.OK_200));
assertThat("The response content was not as expected", response.getContent(), is(testByteArray));
assertThat("The response media type was not as expected", response.getMediaType(), is(MEDIA_TYPE_AUDIO_OGG));
}
@Test
public void mimeTypeIsNullWhenNoContainerAndTheAudioFormatIsNotMp3() throws Exception {
AudioStream audioStream = getByteArrayAudioStream(testByteArray, AudioFormat.CONTAINER_NONE,
AudioFormat.CODEC_PCM_SIGNED);
ContentResponse response = getHttpResponse(audioStream);
assertThat("The response status was not as expected", response.getStatus(), is(HttpStatus.OK_200));
assertThat("The response media type was not as expected", response.getMediaType(), is(nullValue()));
}
@Test
public void onlyOneRequestToOneTimeStreamsCanBeMade() throws Exception {
AudioStream audioStream = getByteArrayAudioStream(testByteArray, AudioFormat.CONTAINER_NONE,
AudioFormat.CODEC_MP3);
String url = serveStream(audioStream);
Request request = getHttpRequest(url);
ContentResponse response = request.send();
assertThat("The response status was not as expected", response.getStatus(), is(HttpStatus.OK_200));
assertThat("The response content was not as expected", response.getContent(), is(testByteArray));
assertThat("The response media type was not as expected", response.getMediaType(), is(MEDIA_TYPE_AUDIO_MPEG));
response = request.send();
assertThat("The response status was not as expected", response.getStatus(), is(HttpStatus.NOT_FOUND_404));
}
@Test
public void requestToMultitimeStreamCannotBeDoneAfterTheTimeoutOfTheStreamHasExipred() throws Exception {
AudioStream audioStream = getByteArrayAudioStream(testByteArray, AudioFormat.CONTAINER_NONE,
AudioFormat.CODEC_MP3);
int streamTimeout = 1;
String url = serveStream(audioStream, streamTimeout);
Request request = getHttpRequest(url);
ContentResponse response = request.send();
assertThat("The response status was not as expected", response.getStatus(), is(HttpStatus.OK_200));
assertThat("The response content was not as expected", response.getContent(), is(testByteArray));
assertThat("The response media type was not as expected", response.getMediaType(), is(MEDIA_TYPE_AUDIO_MPEG));
assertThat("The audio stream was not added to the multitime streams",
audioServlet.getMultiTimeStreams().containsValue(audioStream), is(true));
waitForAssert(() -> {
try {
request.send();
} catch (Exception e) {
throw new IllegalStateException(e);
}
assertThat("The audio stream was not removed from multitime streams",
audioServlet.getMultiTimeStreams().containsValue(audioStream), is(false));
});
response = request.send();
assertThat("The response status was not as expected", response.getStatus(), is(HttpStatus.NOT_FOUND_404));
}
}
@@ -0,0 +1,112 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.core.audio.internal.fake;
import java.io.IOException;
import java.util.Collections;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.smarthome.core.audio.AudioFormat;
import org.eclipse.smarthome.core.audio.AudioSink;
import org.eclipse.smarthome.core.audio.AudioStream;
import org.eclipse.smarthome.core.audio.FixedLengthAudioStream;
import org.eclipse.smarthome.core.audio.URLAudioStream;
import org.eclipse.smarthome.core.audio.UnsupportedAudioFormatException;
import org.eclipse.smarthome.core.audio.UnsupportedAudioStreamException;
import org.eclipse.smarthome.core.library.types.PercentType;
/**
* An {@link AudioSink} fake used for the tests.
*
* @author Christoph Weitkamp - Added examples for getSupportedFormats() and getSupportedStreams()
* @author Christoph Weitkamp - Added parameter to adjust the volume
* @author Wouter Born - Migrate tests from Groovy to Java
*/
public class AudioSinkFake implements AudioSink {
public AudioStream audioStream;
public AudioFormat audioFormat;
public boolean isStreamProcessed;
public boolean isStreamStopped;
public PercentType volume;
public boolean isIOExceptionExpected;
public boolean isUnsupportedAudioFormatExceptionExpected;
public boolean isUnsupportedAudioStreamExceptionExpected;
private static final Set<AudioFormat> SUPPORTED_AUDIO_FORMATS = Collections
.unmodifiableSet(Stream.of(AudioFormat.MP3, AudioFormat.WAV).collect(Collectors.toSet()));
private static final Set<Class<? extends AudioStream>> SUPPORTED_AUDIO_STREAMS = Collections
.unmodifiableSet(Stream.of(FixedLengthAudioStream.class, URLAudioStream.class).collect(Collectors.toSet()));
@Override
public String getId() {
return "testSinkId";
}
@Override
public String getLabel(Locale locale) {
return "testSinkLabel";
}
@Override
public void process(AudioStream audioStream)
throws UnsupportedAudioFormatException, UnsupportedAudioStreamException {
if (isUnsupportedAudioFormatExceptionExpected) {
throw new UnsupportedAudioFormatException("Expected audio format exception", null);
}
if (isUnsupportedAudioStreamExceptionExpected) {
throw new UnsupportedAudioStreamException("Expected audio stream exception", null);
}
this.audioStream = audioStream;
if (audioStream != null) {
audioFormat = audioStream.getFormat();
} else {
isStreamStopped = true;
}
isStreamProcessed = true;
}
public AudioFormat getAudioFormat() {
return audioFormat;
}
@Override
public Set<AudioFormat> getSupportedFormats() {
return SUPPORTED_AUDIO_FORMATS;
}
@Override
public Set<Class<? extends AudioStream>> getSupportedStreams() {
return SUPPORTED_AUDIO_STREAMS;
}
@Override
public PercentType getVolume() throws IOException {
if (isIOExceptionExpected) {
throw new IOException();
}
return volume;
}
@Override
public void setVolume(PercentType volume) throws IOException {
if (isIOExceptionExpected) {
throw new IOException();
}
this.volume = volume;
}
}
@@ -0,0 +1,19 @@
This content is produced and maintained by the Eclipse SmartHome project.
* Project home: https://eclipse.org/smarthome/
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/eclipse/smarthome
== Copyright Holders
See the NOTICE file distributed with the source code at
https://github.com/eclipse/smarthome/blob/master/NOTICE
for detailed information regarding copyright ownership.
@@ -0,0 +1,69 @@
This is a working bundle for demonstrating/ testing the Oauth2 client.
Passwords, secrets, etc have to be configured through config admin in order for it to work
Simply deploy it to the runtime; then smarthome oauth commands will be registered and ready to test.
# Example 1: (Using authorization code)
## Try these on the OSGI console:
```
smarthome oauth Code cleanupEverything
smarthome oauth Code create
smarthome oauth Code getClient <fill in handle from create step>
smarthome oauth Code getAuthorizationUrl
```
```
now open browser with the URL from above step, authenticate yourself
to a real oauth provider
if everything works properly, it should redirect you to your redirectURL
Read the code http parameter from the redirectURL
```
```
smarthome oauth Code getAccessTokenByCode <code from redirectURL parameter>
smarthome oauth Code getCachedAccessToken
smarthome oauth Code refresh
smarthome oauth Code close
```
# Example 2: (Using ResourceOwner credentials i.e. you have the user's username and password directly)
## Try these on the OSGI console:
```
smarthome oauth ResourceOwner create
smarthome oauth ResourceOwner getClient <fill in handle from create step>
smarthome oauth ResourceOwner getAccessTokenByResourceOwnerPassword
smarthome oauth ResourceOwner getCachedAccessToken
smarthome oauth ResourceOwner refresh
smarthome oauth ResourceOwner close
```
### load again, similar to reboot/restart
```
smarthome oauth ResourceOwner getClient <fill in handle from create step>
smarthome oauth ResourceOwner getCachedAccessToken
smarthome oauth ResourceOwner refresh
```
### Done playing, delete this service permanently
```
smarthome oauth ResourceOwner delete <fill in handle from create step>
```
### Verify this is deleted (will throw exception)
```
smarthome oauth ResourceOwner getCachedAccessToken
```
### Cannot get the client after delete
```
smarthome oauth ResourceOwner getClient <fill in handle from create step>
```
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.core.itests</groupId>
<artifactId>org.openhab.core.reactor.itests</artifactId>
<version>2.5.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.core.auth.oauth2client.tests</artifactId>
<name>openHAB Core :: Integration Tests :: OAuth2Client Tests</name>
<packaging>eclipse-test-plugin</packaging>
</project>
@@ -0,0 +1,175 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.auth.oauth2client.test.internal;
import java.io.IOException;
import java.util.Map;
import java.util.UUID;
import org.eclipse.smarthome.core.auth.client.oauth2.AccessTokenResponse;
import org.eclipse.smarthome.core.auth.client.oauth2.OAuthClientService;
import org.eclipse.smarthome.core.auth.client.oauth2.OAuthException;
import org.eclipse.smarthome.core.auth.client.oauth2.OAuthFactory;
import org.eclipse.smarthome.core.auth.client.oauth2.OAuthResponseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* For testing
*
* @author Gary Tse - initial contribution
*
*/
public abstract class AbstractTestAgent implements TestAgent {
private final Logger logger = LoggerFactory.getLogger(AbstractTestAgent.class);
public String handle;
protected String tokenUrl;
protected String clientId;
protected String authUrl;
protected String redirectUri;
protected String clientSecret;
protected String username;
protected String password;
protected String scope;
protected OAuthFactory oauthFactory;
protected OAuthClientService oauthClientService;
public void activate(Map<String, Object> properties) {
tokenUrl = getProperty(properties, "TOKEN_URL");
clientId = getProperty(properties, "CLIENT_ID");
authUrl = getProperty(properties, "AUTH_URL");
redirectUri = getProperty(properties, "REDIRECT_URI");
clientSecret = getProperty(properties, "CLIENT_SECRET");
username = getProperty(properties, "USERNAME");
password = getProperty(properties, "PASSWORD");
scope = getProperty(properties, "SCOPE");
}
private static String getProperty(Map<String, Object> properties, String propKey) {
Object obj = properties.get(propKey);
if (obj == null) {
return "";
}
if (obj instanceof String) {
return (String) obj;
}
if (obj instanceof String[]) {
String[] strArr = (String[]) obj;
if (strArr.length >= 1) {
return strArr[0];
} else {
return "";
}
}
return obj.toString();
}
public void deactivate() {
logger.debug("{} deactivated", this.getClass().getSimpleName());
if (handle != null) {
oauthFactory.ungetOAuthService(handle);
}
}
@Override
public OAuthClientService testCreateClient() {
logger.debug("test createClient");
handle = UUID.randomUUID().toString();
OAuthClientService service = oauthFactory.createOAuthClientService(handle, tokenUrl, authUrl, clientId,
clientSecret, scope, false);
logger.info("new client handle: {}", handle);
return service;
}
@Override
public OAuthClientService testGetClient(String handle) throws OAuthException {
logger.debug("test GetClient handle: {}", handle);
if (handle == null) {
if (this.handle == null) {
logger.error("Cannot get client with handle: {}", handle);
return null;
} else {
logger.info("Using existing handle: {}", this.handle);
oauthClientService = oauthFactory.getOAuthClientService(this.handle);
}
} else {
this.handle = handle;
oauthClientService = oauthFactory.getOAuthClientService(this.handle);
}
return oauthClientService;
}
@Override
public AccessTokenResponse testGetAccessTokenByResourceOwnerPasswordCredentials()
throws OAuthException, IOException, OAuthResponseException {
logger.debug("test getOAuthTokenByResourceOwnerPasswordCredentials");
if (handle == null) {
logger.debug("Creating new oauth service");
oauthClientService = testCreateClient();
} else {
logger.debug("getting oauth client by handle: {}", handle);
oauthClientService = oauthFactory.getOAuthClientService(handle);
}
AccessTokenResponse accessTokenResponse = oauthClientService
.getAccessTokenByResourceOwnerPasswordCredentials(username, password, scope);
logger.debug("Token: {}", accessTokenResponse);
return accessTokenResponse;
}
@Override
public AccessTokenResponse testGetAccessTokenByAuthorizationCode(String code)
throws OAuthException, IOException, OAuthResponseException {
return oauthClientService.getAccessTokenResponseByAuthorizationCode(code, redirectUri);
}
@Override
public AccessTokenResponse testGetCachedAccessToken() throws OAuthException, IOException, OAuthResponseException {
logger.debug("test getCachedAccessToken");
AccessTokenResponse oldRefreshedToken = oauthClientService.getAccessTokenResponse();
return oldRefreshedToken;
}
@Override
public AccessTokenResponse testRefreshToken() throws OAuthException, IOException, OAuthResponseException {
logger.debug("test RefreshToken");
AccessTokenResponse newRefreshedToken = oauthClientService.refreshToken();
return newRefreshedToken;
}
@Override
public String testGetAuthorizationUrl(String state) throws OAuthException {
logger.debug("test getAuthorizationUrl {}", state);
String authorizationURL = oauthClientService.getAuthorizationUrl(redirectUri, scope, state);
return authorizationURL;
}
@Override
public void close() {
oauthClientService.close();
// delibrately not set to null to test on oauthClientService
// oauthClientService = null;
}
@Override
public void delete(String handle) {
logger.debug("Delete handle: {}", handle);
oauthFactory.deleteServiceAndAccessToken(handle);
}
}
@@ -0,0 +1,65 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.auth.oauth2client.test.internal;
import java.util.Map;
import org.eclipse.smarthome.core.auth.client.oauth2.OAuthFactory;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* For testing of AuthorizationCode against a real provider
*
* @author Gary Tse - initial contribution
*
*/
@Component(immediate = true, configurationPolicy = ConfigurationPolicy.REQUIRE, name = "AuthorizationCodeTestAgent", configurationPid = "AuthorizationCodeTestAgent")
public class AuthorizationCodeTestAgent extends AbstractTestAgent implements TestAgent {
public static final String CONFIGURATION_PID = "AuthorizationCodeTestAgent";
private final Logger logger = LoggerFactory.getLogger(AuthorizationCodeTestAgent.class);
@Override
@Activate
public void activate(Map<String, Object> properties) {
super.activate(properties);
logger.debug("{} activated", this.getClass().getSimpleName());
}
@Override
@Deactivate
public void deactivate() {
super.deactivate();
logger.debug("{} deactivated", this.getClass().getSimpleName());
}
@Reference
public void setOauthFactory(OAuthFactory oauthFactory) {
super.oauthFactory = oauthFactory;
}
public void unsetOauthFactory(OAuthFactory oauthFactory) {
if (super.oauthFactory == oauthFactory) {
if (handle != null) {
oauthFactory.ungetOAuthService(handle);
}
super.oauthFactory = null;
}
}
}
@@ -0,0 +1,65 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.auth.oauth2client.test.internal;
import java.util.Map;
import org.eclipse.smarthome.core.auth.client.oauth2.OAuthFactory;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* For testing of ResourceOwner credentials against a real provider
*
* @author Gary Tse - initial contribution
*
*/
@Component(immediate = true, configurationPolicy = ConfigurationPolicy.REQUIRE, name = "ResourceOwnerTestAgent", configurationPid = "ResourceOwnerTestAgent")
public class ResourceOwnerTestAgent extends AbstractTestAgent implements TestAgent {
public static final String CONFIGURATION_PID = "ResourceOwnerTestAgent";
private final Logger logger = LoggerFactory.getLogger(ResourceOwnerTestAgent.class);
@Override
@Activate
public void activate(Map<String, Object> properties) {
super.activate(properties);
logger.debug("{} activated", this.getClass().getSimpleName());
}
@Override
@Deactivate
public void deactivate() {
super.deactivate();
logger.debug("{} deactivated", this.getClass().getSimpleName());
}
@Reference
public void setOauthFactory(OAuthFactory oauthFactory) {
this.oauthFactory = oauthFactory;
}
public void unsetOauthFactory(OAuthFactory oauthFactory) {
if (super.oauthFactory == oauthFactory) {
if (handle != null) {
oauthFactory.ungetOAuthService(handle);
}
super.oauthFactory = null;
}
}
}
@@ -0,0 +1,50 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.auth.oauth2client.test.internal;
import java.io.IOException;
import org.eclipse.smarthome.core.auth.client.oauth2.AccessTokenResponse;
import org.eclipse.smarthome.core.auth.client.oauth2.OAuthClientService;
import org.eclipse.smarthome.core.auth.client.oauth2.OAuthException;
import org.eclipse.smarthome.core.auth.client.oauth2.OAuthResponseException;
/**
* For testing
*
* @author Gary Tse - initial contribution
*
*/
public interface TestAgent {
OAuthClientService testCreateClient();
AccessTokenResponse testGetAccessTokenByResourceOwnerPasswordCredentials()
throws OAuthException, IOException, OAuthResponseException;
OAuthClientService testGetClient(String handle) throws OAuthException;
AccessTokenResponse testGetAccessTokenByAuthorizationCode(String code)
throws OAuthException, IOException, OAuthResponseException;
AccessTokenResponse testRefreshToken() throws OAuthException, IOException, OAuthResponseException;
AccessTokenResponse testGetCachedAccessToken() throws OAuthException, IOException, OAuthResponseException;
String testGetAuthorizationUrl(String state) throws OAuthException;
void close();
void delete(String handle);
}
@@ -0,0 +1,170 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.auth.oauth2client.test.internal.console;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.eclipse.smarthome.auth.oauth2client.test.internal.AbstractTestAgent;
import org.eclipse.smarthome.auth.oauth2client.test.internal.AuthorizationCodeTestAgent;
import org.eclipse.smarthome.auth.oauth2client.test.internal.ResourceOwnerTestAgent;
import org.eclipse.smarthome.auth.oauth2client.test.internal.TestAgent;
import org.eclipse.smarthome.core.auth.client.oauth2.AccessTokenResponse;
import org.eclipse.smarthome.core.auth.client.oauth2.OAuthClientService;
import org.eclipse.smarthome.core.auth.client.oauth2.OAuthException;
import org.eclipse.smarthome.core.auth.client.oauth2.OAuthResponseException;
import org.eclipse.smarthome.io.console.Console;
import org.eclipse.smarthome.io.console.extensions.AbstractConsoleCommandExtension;
import org.eclipse.smarthome.io.console.extensions.ConsoleCommandExtension;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* Command for testing in the OSGI console
*
* @author Gary Tse - Initial contribution
*
*/
@Component(immediate = true, name = "ConsoleOAuthCommandExtension")
public class ConsoleOAuthCommandExtension extends AbstractConsoleCommandExtension implements ConsoleCommandExtension {
public ConsoleOAuthCommandExtension() {
super("oauth", "Test of oauth client with console. Available test agent: {Code, ResourceOwner}.\n"
+ "The commands in oauth requires oauth provider data to be inputted in configuration admin.");
}
private AuthorizationCodeTestAgent authorizationCodeTestAgent;
private ResourceOwnerTestAgent resourceOwnerTestAgent;
private Console console;
@Override
public void execute(String[] args, Console console) {
this.console = console;
if (args.length < 2) {
console.println("Argument expected. Please check usage.");
return;
}
AbstractTestAgent agent = getTestAgent(args[0]);
if (agent == null) {
console.println("Unexpected test agent:" + args[0]);
return;
}
AccessTokenResponse response;
try {
switch (args[1]) {
case "create":
OAuthClientService newService = agent.testCreateClient();
console.println("handle: " + agent.handle + ", service: " + newService);
break;
case "getAccessTokenByResourceOwnerPassword":
response = agent.testGetAccessTokenByResourceOwnerPasswordCredentials();
consolePrintAccessToken(response);
break;
case "getClient":
OAuthClientService service = agent.testGetClient(args[2]);
console.println("OAuthClientService: " + service);
break;
case "refresh":
response = agent.testRefreshToken();
consolePrintAccessToken(response);
break;
case "getAccessTokenByCode":
console.println("using authorization code: " + args[2]);
response = agent.testGetAccessTokenByAuthorizationCode(args[2]);
consolePrintAccessToken(response);
break;
case "getAuthorizationUrl":
String authURL;
if (args.length >= 3) {
authURL = agent.testGetAuthorizationUrl(args[2]);
console.println("Authorization URL: " + authURL + " state: " + args[2]);
} else {
authURL = agent.testGetAuthorizationUrl(null);
console.println("Authorization URL: " + authURL + " state: null");
}
break;
case "getCachedAccessToken":
response = agent.testGetCachedAccessToken();
consolePrintAccessToken(response);
break;
case "close":
console.println("Closing test agent client service...");
agent.close();
break;
case "delete":
console.println("Delete by handle: " + args[2]);
agent.delete(args[2]);
break;
default:
console.println("Commands are case-sensitive. Unknown command: " + args[1]);
break;
}
} catch (OAuthException | IOException | OAuthResponseException e) {
console.print(String.format("%s %s, cause %s", e.getClass(), e.getMessage(), e.getCause()));
}
}
private AbstractTestAgent getTestAgent(String name) {
if ("Code".equals(name)) {
return authorizationCodeTestAgent;
} else if ("ResourceOwner".equals(name)) {
return resourceOwnerTestAgent;
} else {
return null;
}
}
private void consolePrintAccessToken(AccessTokenResponse response) {
console.println("AccessTokenResponse: " + (response == null ? "null" : response.toString()));
}
/**
* @formatter:off
*/
@Override
public List<String> getUsages() {
return Arrays.asList(
buildCommandUsage("<agent> create","create an oauth client. Agent:={Code | ResourceOwner}"),
buildCommandUsage("<agent> getClient <handle>", "get the client by handle"),
buildCommandUsage("<agent> getAccessTokenByResourceOwnerPassword","get access token by resource owner username and password"),
buildCommandUsage("<agent> getAuthorizationUrl", "get authorization url"),
buildCommandUsage("<agent> getAccessTokenByCode <code>","get the access token by authorization code"),
buildCommandUsage("<agent> getCachedAccessToken", "get the access token from cache"),
buildCommandUsage("<agent> refresh", "refresh access token"),
buildCommandUsage("<agent> delete <handle>", "delete service, access token, configurations by the handle"),
buildCommandUsage("<agent> close", "close the test agent and release resources, tokens are persisted"));
}
@Reference(target = "(service.pid=ResourceOwnerTestAgent)")
protected void setResourceOwnerTestAgent(TestAgent resourceOwnerTestAgent) {
this.resourceOwnerTestAgent = (ResourceOwnerTestAgent)resourceOwnerTestAgent;
}
protected void unsetResourceOwnerTestAgent(TestAgent resourceOwnerTestAgent) {
this.resourceOwnerTestAgent = null;
}
@Reference(target = "(service.pid=AuthorizationCodeTestAgent)")
protected void setAuthorizationCodeTestAgent(TestAgent authorizationCodeTestAgent) {
this.authorizationCodeTestAgent = (AuthorizationCodeTestAgent)authorizationCodeTestAgent;
}
protected void unsetAuthorizationCodeTestAgent(TestAgent authorizationCodeTestAgent) {
this.authorizationCodeTestAgent = null;
}
}
@@ -0,0 +1,83 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.auth.oauth2client.test.internal.cipher;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.util.Dictionary;
import java.util.Hashtable;
import org.eclipse.smarthome.auth.oauth2client.internal.cipher.SymmetricKeyCipher;
import org.junit.Before;
import org.junit.Test;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
/**
* Verify that the SymmetricKeyCipher is working properly.
*
* @author Gary Tse - Initial Contribution
*/
public class CipherTest {
private static final String PLAIN_TEXT = "hello world";
private SymmetricKeyCipher spySymmetricKeyCipher;
@Before
public void setUp() throws IOException, InvalidSyntaxException, NoSuchAlgorithmException {
spySymmetricKeyCipher = spySymmetricKeyCipher();
}
@Test
public void testEncDec() throws GeneralSecurityException {
String cipherText = spySymmetricKeyCipher.encrypt(PLAIN_TEXT);
assertNotNull("Cipher text should not be null", cipherText);
assertNotEquals("Cipher text should not be the same as plaintext", PLAIN_TEXT, cipherText);
String decryptedText = spySymmetricKeyCipher.decrypt(cipherText);
assertNotNull("Decrypted text should not be null", decryptedText);
assertEquals("Decrypted text should be same as before", PLAIN_TEXT, decryptedText);
}
private SymmetricKeyCipher spySymmetricKeyCipher()
throws IOException, InvalidSyntaxException, NoSuchAlgorithmException {
spySymmetricKeyCipher = spy(SymmetricKeyCipher.class);
spySymmetricKeyCipher.setConfigurationAdmin(mockConfigurationAdmin());
spySymmetricKeyCipher.activate(); // generate encryption key
return spySymmetricKeyCipher;
}
private ConfigurationAdmin mockConfigurationAdmin() throws IOException {
ConfigurationAdmin configurationAdmin = mock(ConfigurationAdmin.class);
Configuration configuration = mockConfiguration();
when(configurationAdmin.getConfiguration(anyString())).thenReturn(configuration);
return configurationAdmin;
}
private Configuration mockConfiguration() {
Dictionary<String, Object> properties = new Hashtable<String, Object>();
Configuration configurationMock = mock(Configuration.class);
when(configurationMock.getPid()).thenReturn("PID");
when(configurationMock.getProperties()).thenReturn(properties);
return configurationMock;
}
}
@@ -0,0 +1,19 @@
This content is produced and maintained by the Eclipse SmartHome project.
* Project home: https://eclipse.org/smarthome/
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/eclipse/smarthome
== Copyright Holders
See the NOTICE file distributed with the source code at
https://github.com/eclipse/smarthome/blob/master/NOTICE
for detailed information regarding copyright ownership.
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.pde.ui.JunitLaunchConfig">
<booleanAttribute key="append.args" value="true"/>
<stringAttribute key="application" value="org.eclipse.pde.junit.runtime.coretestapplication"/>
<booleanAttribute key="askclear" value="false"/>
<booleanAttribute key="automaticAdd" value="false"/>
<booleanAttribute key="automaticValidate" value="true"/>
<stringAttribute key="bootstrap" value=""/>
<stringAttribute key="checked" value="[NONE]"/>
<booleanAttribute key="clearConfig" value="true"/>
<booleanAttribute key="clearws" value="true"/>
<booleanAttribute key="clearwslog" value="false"/>
<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/pde-junit"/>
<booleanAttribute key="default" value="false"/>
<booleanAttribute key="default_auto_start" value="true"/>
<booleanAttribute key="includeOptional" value="false"/>
<stringAttribute key="location" value="${workspace_loc}/../junit-workspace"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/org.eclipse.smarthome.automation.core.test"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.smarthome.automation.core.test"/>
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.smarthome.automation.core.test"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="pde.version" value="3.3"/>
<stringAttribute key="product" value="org.eclipse.equinox.p2.director.app.product"/>
<booleanAttribute key="run_in_ui_thread" value="true"/>
<stringAttribute key="selected_target_plugins" value="ch.qos.logback.classic@default:default,ch.qos.logback.core@default:default,ch.qos.logback.slf4j@default:false,com.eclipsesource.jaxrs.jersey-min@default:default,com.google.gson@default:default,com.google.guava@default:default,javax.measure.unit-api@default:default,javax.servlet@default:default,javax.transaction@default:false,javax.xml@default:default,net.bytebuddy.byte-buddy-agent@default:default,net.bytebuddy.byte-buddy@default:default,org.apache.ant@default:default,org.apache.commons.collections@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.felix.scr@1:true,org.codehaus.groovy@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.runtime@default:true,org.eclipse.emf.common@default:default,org.eclipse.emf.ecore.xmi@default:default,org.eclipse.emf.ecore@default:default,org.eclipse.equinox.app@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.ds@1:true,org.eclipse.equinox.event@default:default,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.region@default:false,org.eclipse.equinox.registry@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.equinox.util@default:default,org.eclipse.equinox.weaving.hook@default:false,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi.util@default:default,org.eclipse.osgi@-1:true,org.hamcrest.core@default:default,org.junit@default:default,org.mockito.mockito-core@default:default,org.objenesis@default:default,org.slf4j.api@default:default,tec.uom.lib.uom-lib-common@default:default,tec.uom.se@default:default"/>
<stringAttribute key="selected_workspace_plugins" value="org.eclipse.smarthome.automation.api@default:default,org.eclipse.smarthome.automation.core.test@default:false,org.eclipse.smarthome.automation.core@default:default,org.eclipse.smarthome.automation.module.core@default:default,org.eclipse.smarthome.automation.parser.gson@default:default,org.eclipse.smarthome.automation.providers@default:default,org.eclipse.smarthome.config.core@default:default,org.eclipse.smarthome.config.xml@default:default,org.eclipse.smarthome.core.scheduler@default:default,org.eclipse.smarthome.core.thing@default:true,org.eclipse.smarthome.core@default:default,org.eclipse.smarthome.io.console@default:true,org.eclipse.smarthome.test@default:default"/>
<booleanAttribute key="show_selected_only" value="false"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfig" value="true"/>
<booleanAttribute key="useDefaultConfigArea" value="false"/>
<booleanAttribute key="useProduct" value="false"/>
</launchConfiguration>
@@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.core.itests</groupId>
<artifactId>org.openhab.core.reactor.itests</artifactId>
<version>2.5.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.core.automation.core.tests</artifactId>
<packaging>eclipse-test-plugin</packaging>
<name>openHAB Core :: Integration Tests :: Automation Core Tests</name>
<build>
<plugins>
<plugin>
<groupId>${tycho-groupid}</groupId>
<artifactId>tycho-surefire-plugin</artifactId>
<configuration>
<dependencies>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.openhab.core.automation.api</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.openhab.core.config.core</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.openhab.core.config.xml</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.openhab.core</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.eclipse.core.runtime</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.eclipse.equinox.common</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.eclipse.equinox.ds</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.eclipse.equinox.event</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.eclipse.osgi</artifactId>
<version>0.0.0</version>
</dependency>
<!-- LOGGING -->
<dependency>
<type>eclipse-plugin</type>
<artifactId>ch.qos.logback.classic</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>ch.qos.logback.core</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>ch.qos.logback.slf4j</artifactId>
<version>0.0.0</version>
</dependency>
</dependencies>
<bundleStartLevel>
<bundle>
<id>org.eclipse.smarthome.automation.api</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.core</id>
<level>3</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.config.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.config.xml</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.core</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.core.runtime</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.common</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.ds</id>
<level>1</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.event</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
</bundleStartLevel>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,111 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.automation.core.internal;
import java.util.regex.Pattern;
import org.junit.Assert;
import org.junit.Test;
public class ConnectionValidatorTest {
@Test
public void testValidConnections() {
Assert.assertTrue(Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "$name"));
Assert.assertTrue(Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "${name}"));
Assert.assertTrue(Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "moduleId.outputName"));
Assert.assertTrue(Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "module.list[1].name.values"));
Assert.assertTrue(
Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "module1.map[\"na[m}.\"e\"][1].values_1-2"));
}
@Test
public void testInvalidConnections() {
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "name"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "$name}"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "{name"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "name}"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "$name}"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "$name}"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "${name"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "$name}"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "${name.values}"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "$name.values"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "moduleId.outputName."));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "[1].name.values"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "list.[1]name.values"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, ".module.array[1].name.values"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "module1.map\"na[m}.\"e\"]"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "module.map[\"na[m}.\"e\""));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "module.list[1.name"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "module.list1].name"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "module.list[1].name."));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "module[\"name\"]"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "module.[name]"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "module[\"name]"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONNECTION_PATTERN, "module.[name\"]"));
}
@Test
public void testInvalidConfigReference() {
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONFIG_REFERENCE_PATTERN, ""));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONFIG_REFERENCE_PATTERN, "name"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONFIG_REFERENCE_PATTERN, "$name}"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONFIG_REFERENCE_PATTERN, "{name"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONFIG_REFERENCE_PATTERN, "name}"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONFIG_REFERENCE_PATTERN, "$name}"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONFIG_REFERENCE_PATTERN, "$name}"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONFIG_REFERENCE_PATTERN, "${name"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONFIG_REFERENCE_PATTERN, "$name}"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONFIG_REFERENCE_PATTERN, "${name.values}"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONFIG_REFERENCE_PATTERN, "$name.values"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONFIG_REFERENCE_PATTERN, "[1].name.values"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONFIG_REFERENCE_PATTERN, "${name.values"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.CONFIG_REFERENCE_PATTERN, "$name.values}"));
}
@Test
public void testValidOutputReference() {
Assert.assertTrue(Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, "[1]"));
Assert.assertTrue(Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, ".phones[1]"));
Assert.assertTrue(Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, ".phones[1].number"));
Assert.assertTrue(Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, "[\"test\"]"));
Assert.assertTrue(Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, "[\"test\"].name"));
Assert.assertTrue(Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, ".map[\"test\"]"));
Assert.assertTrue(Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, ".map[\"test\"].name"));
Assert.assertTrue(Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, ".bean.values"));
Assert.assertTrue(Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, ".bean.array[1]"));
Assert.assertTrue(Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, ".bean.map[\"na[m}.\"e\"]"));
Assert.assertTrue(
Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, ".bean.map[\"na[m}.\"e\"].values"));
}
@Test
public void testInvalidOutputReference() {
Assert.assertTrue(!Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, "phones."));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, "phones["));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, "]phones"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, "phones[].name"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, "phones[\"\"].name"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, "list.[1]name.values"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, ".map\"na[m}.\"e\"]"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, "module.map[\"na[m}.\"e\""));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, "module.list[1.name"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, "module.list1].name"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, "module.list[1].name."));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, "module[\"name\"]"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, "module.[name]"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, "module[\"name]"));
Assert.assertTrue(!Pattern.matches(ConnectionValidator.OUTPUT_REFERENCE_PATTERN, "module.[name\"]"));
}
}
@@ -0,0 +1,273 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.automation.core.internal;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.smarthome.automation.Module;
import org.eclipse.smarthome.automation.core.util.ModuleBuilder;
import org.eclipse.smarthome.automation.core.util.ReferenceResolver;
import org.eclipse.smarthome.config.core.Configuration;
import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ReferenceResolverUtilTest {
private static final String CONTEXT_PROPERTY1 = "contextProperty1";
private static final String CONTEXT_PROPERTY2 = "contextProperty2";
private static final String CONTEXT_PROPERTY3 = "contextProperty3";
private static final String CONTEXT_PROPERTY4 = "contextProperty4";
private static final Map<String, Object> context = new HashMap<>();
private static final Map<String, Object> moduleConfiguration = new HashMap<>();
private static final Map<String, Object> expectedModuleConfiguration = new HashMap<>();
private static final Map<String, String> compositeChildModuleInputsReferences = new HashMap<>();
private static final Map<String, Object> expectedCompositeChildModuleContext = new HashMap<>();
private final Logger logger = LoggerFactory.getLogger(getClass());
static {
// context from where references will be taken
context.put(CONTEXT_PROPERTY1, "value1");
context.put(CONTEXT_PROPERTY2, "value2");
context.put(CONTEXT_PROPERTY3, "value3");
context.put(CONTEXT_PROPERTY4, new BigDecimal(12345));
// module configuration with references
moduleConfiguration.put("simpleReference", String.format("${%s}", CONTEXT_PROPERTY4));
moduleConfiguration.put("complexReference",
String.format("Hello ${%s} ${%s}", CONTEXT_PROPERTY1, CONTEXT_PROPERTY4));
moduleConfiguration.put("complexReferenceWithMissing",
String.format("Testing ${UNKNOWN}, ${%s}", CONTEXT_PROPERTY4));
moduleConfiguration.put("complexReferenceArray",
String.format("[${%s}, ${%s}, staticText]", CONTEXT_PROPERTY2, CONTEXT_PROPERTY3));
moduleConfiguration.put("complexReferenceArrayWithMissing",
String.format("[${UNKNOWN}, ${%s}, staticText]", CONTEXT_PROPERTY3));
moduleConfiguration.put("complexReferenceObj",
String.format("{key1: ${%s}, key2: staticText, key3: ${%s}}", CONTEXT_PROPERTY1, CONTEXT_PROPERTY4));
moduleConfiguration.put("complexReferenceObjWithMissing",
String.format("{key1: ${UNKNOWN}, key2: ${%s}, key3: ${UNKNOWN2}}", CONTEXT_PROPERTY2));
// expected resolved module configuration
expectedModuleConfiguration.put("simpleReference", context.get(CONTEXT_PROPERTY4));
expectedModuleConfiguration.put("complexReference",
String.format("Hello %s %s", context.get(CONTEXT_PROPERTY1), context.get(CONTEXT_PROPERTY4)));
expectedModuleConfiguration.put("complexReferenceWithMissing",
String.format("Testing ${UNKNOWN}, %s", context.get(CONTEXT_PROPERTY4)));
expectedModuleConfiguration.put("complexReferenceArray",
String.format("[%s, %s, staticText]", context.get(CONTEXT_PROPERTY2), context.get(CONTEXT_PROPERTY3)));
expectedModuleConfiguration.put("complexReferenceArrayWithMissing",
String.format("[${UNKNOWN}, %s, staticText]", context.get(CONTEXT_PROPERTY3)));
expectedModuleConfiguration.put("complexReferenceObj", String.format("{key1: %s, key2: staticText, key3: %s}",
context.get(CONTEXT_PROPERTY1), context.get(CONTEXT_PROPERTY4)));
expectedModuleConfiguration.put("complexReferenceObjWithMissing",
String.format("{key1: ${UNKNOWN}, key2: %s, key3: ${UNKNOWN2}}", context.get(CONTEXT_PROPERTY2)));
// composite child module input with references
compositeChildModuleInputsReferences.put("moduleInput", String.format("${%s}", CONTEXT_PROPERTY1));
compositeChildModuleInputsReferences.put("moduleInputMissing", "${UNKNOWN}");
compositeChildModuleInputsReferences.put("moduleInput2", String.format("${%s}", CONTEXT_PROPERTY2));
// expected resolved child module context
expectedCompositeChildModuleContext.put("moduleInput", context.get(CONTEXT_PROPERTY1));
expectedCompositeChildModuleContext.put("moduleInputMissing", context.get("UNKNOWN"));
expectedCompositeChildModuleContext.put("moduleInput2", context.get(CONTEXT_PROPERTY2));
}
Logger log = LoggerFactory.getLogger(ReferenceResolverUtilTest.class);
@Test
public void testModuleConfigurationResolving() {
// test trigger configuration.
Module trigger = ModuleBuilder.createTrigger().withId("id1").withTypeUID("typeUID1")
.withConfiguration(new Configuration(moduleConfiguration)).build();
ReferenceResolver.updateConfiguration(trigger.getConfiguration(), context, logger);
Assert.assertEquals(trigger.getConfiguration(), new Configuration(expectedModuleConfiguration));
// test condition configuration.
Module condition = ModuleBuilder.createCondition().withId("id2").withTypeUID("typeUID2")
.withConfiguration(new Configuration(moduleConfiguration)).build();
ReferenceResolver.updateConfiguration(condition.getConfiguration(), context, logger);
Assert.assertEquals(condition.getConfiguration(), new Configuration(expectedModuleConfiguration));
// test action configuration.
Module action = ModuleBuilder.createAction().withId("id3").withTypeUID("typeUID3")
.withConfiguration(new Configuration(moduleConfiguration)).build();
ReferenceResolver.updateConfiguration(action.getConfiguration(), context, logger);
Assert.assertEquals(action.getConfiguration(), new Configuration(expectedModuleConfiguration));
}
@Test
public void testModuleInputResolving() {
// test Composite child ModuleImpl(condition) context
Module condition = ModuleBuilder.createCondition().withId("id1").withTypeUID("typeUID1")
.withInputs(compositeChildModuleInputsReferences).build();
Map<String, Object> conditionContext = ReferenceResolver.getCompositeChildContext(condition, context);
Assert.assertEquals(conditionContext, expectedCompositeChildModuleContext);
// test Composite child ModuleImpl(action) context
Module action = ModuleBuilder.createAction().withId("id2").withTypeUID("typeUID2")
.withInputs(compositeChildModuleInputsReferences).build();
Assert.assertEquals(expectedCompositeChildModuleContext, conditionContext);
Map<String, Object> actionContext = ReferenceResolver.getCompositeChildContext(action, context);
Assert.assertEquals(actionContext, expectedCompositeChildModuleContext);
}
@Test
public void testSplitReferenceToTokens() {
Assert.assertNull(ReferenceResolver.splitReferenceToTokens(null));
Assert.assertTrue(ReferenceResolver.splitReferenceToTokens("").length == 0);
final String[] referenceTokens = ReferenceResolver
.splitReferenceToTokens(".module.array[\".na[m}.\"e\"][1].values1");
Assert.assertTrue(referenceTokens[0].equals("module"));
Assert.assertTrue(referenceTokens[1].equals("array"));
Assert.assertTrue(referenceTokens[2].equals(".na[m}.\"e"));
Assert.assertTrue(referenceTokens[3].equals("1"));
Assert.assertTrue(referenceTokens[4].equals("values1"));
}
@Test
public void testResolvingFromNull() {
String ken = "Ken";
Assert.assertEquals(ken,
ReferenceResolver.resolveComplexDataReference(ken, ReferenceResolver.splitReferenceToTokens(null)));
}
@Test
public void testResolvingFromEmptyString() {
String ken = "Ken";
Assert.assertEquals(ken,
ReferenceResolver.resolveComplexDataReference(ken, ReferenceResolver.splitReferenceToTokens("")));
}
@Test
public void testGetFromList() {
String ken = "Ken";
List<String> names = Arrays.asList("John", ken, "Sue");
Assert.assertEquals(ken,
ReferenceResolver.resolveComplexDataReference(names, ReferenceResolver.splitReferenceToTokens("[1]")));
}
@Test(expected = NumberFormatException.class)
public void testGetFromListInvalidIndexFormat() {
List<String> names = Arrays.asList("John", "Ken", "Sue");
ReferenceResolver.resolveComplexDataReference(names, ReferenceResolver.splitReferenceToTokens("[Ten]"));
}
@Test
public void getFromMap() {
String phone = "0331 1387 121";
Map<String, String> phones = new HashMap<>();
phones.put("John", phone);
phones.put("Sue", "0222 2184 121");
phones.put("Mark", "0222 5641 121");
Assert.assertEquals(phone, ReferenceResolver.resolveComplexDataReference(phones,
ReferenceResolver.splitReferenceToTokens("[\"John\"]")));
}
@Test
public void getFromMapWithKeyThatContainsSpecialCharacters() {
String phone = "0331 1387 121";
Map<String, String> phones = new HashMap<>();
phones.put("John[].Smi\"th].", phone);
phones.put("Sue", "0222 2184 121");
phones.put("Mark", "0222 5641 121");
Assert.assertEquals(phone, ReferenceResolver.resolveComplexDataReference(phones,
ReferenceResolver.splitReferenceToTokens("[\"John[].Smi\"th].\"]")));
}
@Test
public void getFromMapUnExistingKey() {
Map<String, String> phones = new HashMap<>();
phones.put("Sue", "0222 2184 121");
phones.put("Mark", "0222 5641 121");
Assert.assertNull(ReferenceResolver.resolveComplexDataReference(phones,
ReferenceResolver.splitReferenceToTokens("[\"John\"]")));
}
@Test
public void getFromList() {
String ken = "Ken";
List<String> names = Arrays.asList(new String[] { "John", ken, "Sue" });
Assert.assertEquals(ken,
ReferenceResolver.resolveComplexDataReference(names, ReferenceResolver.splitReferenceToTokens("[1]")));
}
@Test(expected = ArrayIndexOutOfBoundsException.class)
public void testGetFromListInvalidIndex() {
List<String> names = Arrays.asList(new String[] { "John", "Ken", "Sue" });
ReferenceResolver.resolveComplexDataReference(names, ReferenceResolver.splitReferenceToTokens("[10]"));
}
@Test(expected = NumberFormatException.class)
public void testGetFromInvalidIndexFormat() {
List<String> names = Arrays.asList(new String[] { "John", "Ken", "Sue" });
ReferenceResolver.resolveComplexDataReference(names, ReferenceResolver.splitReferenceToTokens("[Ten]"));
}
@Test
public void testGetFromBean() {
String name = "John";
B1<String> b3 = new B1<>(name);
Assert.assertEquals(name,
ReferenceResolver.resolveComplexDataReference(b3, ReferenceResolver.splitReferenceToTokens("value")));
}
@Test
public void testGetFromBeanWithPrivateField() {
String name = "John";
B2<String> b4 = new B2<>(name);
Assert.assertEquals(name,
ReferenceResolver.resolveComplexDataReference(b4, ReferenceResolver.splitReferenceToTokens("value")));
}
@Test
public void testBeanFromBean() {
String phone = "0331 1387 121";
Map<String, String> phones = new HashMap<>();
phones.put("John", phone);
B1<Map<String, String>> b3 = new B1<>(phones);
B2<B1<Map<String, String>>> b4 = new B2<>(b3);
Assert.assertEquals(phone, ReferenceResolver.resolveComplexDataReference(b4,
ReferenceResolver.splitReferenceToTokens("value.value[\"John\"]")));
}
@Test()
public void testGetBeanFieldFromList() {
String name = "John";
B1<String> b31 = new B1<>("Ken");
B1<String> b32 = new B1<>("Sue");
B1<String> b33 = new B1<>(name);
List<B1<String>> b = Arrays.asList(b31, b32, b33);
Assert.assertEquals(name, ReferenceResolver.resolveComplexDataReference(b,
ReferenceResolver.splitReferenceToTokens("[2].value")));
}
public class B1<T> {
@SuppressWarnings("unused")
private final T value;
public B1(T value) {
this.value = value;
}
}
public class B2<T> {
public T value;
public B2(T value) {
this.value = value;
}
}
}
@@ -0,0 +1,372 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.automation.core.internal;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.smarthome.automation.Action;
import org.eclipse.smarthome.automation.Condition;
import org.eclipse.smarthome.automation.Rule;
import org.eclipse.smarthome.automation.RuleManager;
import org.eclipse.smarthome.automation.RuleRegistry;
import org.eclipse.smarthome.automation.Trigger;
import org.eclipse.smarthome.automation.core.util.ModuleBuilder;
import org.eclipse.smarthome.automation.core.util.RuleBuilder;
import org.eclipse.smarthome.automation.type.ModuleTypeProvider;
import org.eclipse.smarthome.config.core.ConfigDescriptionParameter;
import org.eclipse.smarthome.config.core.ConfigDescriptionParameter.Type;
import org.eclipse.smarthome.config.core.ConfigDescriptionParameterBuilder;
import org.eclipse.smarthome.config.core.Configuration;
import org.eclipse.smarthome.config.core.FilterCriteria;
import org.eclipse.smarthome.config.core.ParameterOption;
import org.eclipse.smarthome.test.java.JavaOSGiTest;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
/**
* Test adding, retrieving and updating rules from the RuleEngineImpl
*
* @author Marin Mitev - initial version
* @author Thomas Höfer - Added config description parameter unit
*/
public class RuleEngineTest extends JavaOSGiTest {
RuleEngineImpl ruleEngine;
RuleRegistry ruleRegistry;
@Before
public void setup() {
registerVolatileStorageService();
ruleEngine = (RuleEngineImpl) getService(RuleManager.class);
ruleRegistry = getService(RuleRegistry.class);
registerService(new TestModuleTypeProvider(), ModuleTypeProvider.class.getName());
}
/**
* test auto map connections of the rule
*
*/
@Test
@Ignore
public void testAutoMapRuleConnections() {
RuleImpl rule = createAutoMapRule();
// check condition connections
Map<String, String> conditionInputs = rule.getConditions().get(0).getInputs();
Assert.assertEquals("Number of user define condition inputs", 1, conditionInputs.size());
Assert.assertTrue("Check user define condition connection",
"triggerId.triggerOutput".equals(conditionInputs.get("conditionInput")));
// check action connections
Map<String, String> actionInputs = rule.getActions().get(0).getInputs();
Assert.assertEquals("Number of user define action inputs", 2, actionInputs.size());
Assert.assertTrue("Check user define action connections for input actionInput",
"triggerId.triggerOutput".equals(actionInputs.get("actionInput")));
Assert.assertTrue("Check user define action connections for input in6",
"triggerId.triggerOutput".equals(actionInputs.get("in6")));
// do connections auto mapping
ruleRegistry.add(rule);
Rule ruleGet = ruleEngine.getRule("AutoMapRule");
Assert.assertEquals("Returned rule with wrong UID", "AutoMapRule", ruleGet.getUID());
// check condition connections
conditionInputs = ruleGet.getConditions().get(0).getInputs();
Assert.assertEquals("Number of user define condition inputs", 2, conditionInputs.size());
Assert.assertEquals("Check user define condition connection", "triggerId.triggerOutput",
conditionInputs.get("conditionInput"));
Assert.assertEquals("Auto map condition input in2[tagA, tagB] to trigger output out3[tagA, tagB, tagC]",
"triggerId.out3", conditionInputs.get("in2"));
// check action connections
actionInputs = ruleGet.getActions().get(0).getInputs();
Assert.assertEquals("Number of user define action inputs", 4, actionInputs.size());
Assert.assertTrue("Check user define action connections for input actionInput",
"triggerId.triggerOutput".equals(actionInputs.get("actionInput")));
Assert.assertEquals("Check user define action connections for input in6 is not changed by the auto mapping",
"triggerId.triggerOutput", actionInputs.get("in6"));
Assert.assertEquals("Auto map action input in5[tagA, tagB, tagC] to trigger output out3[tagA, tagB, tagC]",
"triggerId.out3", actionInputs.get("in5"));
Assert.assertEquals("Auto map action input in5[tagD, tagE] to action output out5[tagD, tagE]", "actionId.out5",
actionInputs.get("in4"));
}
/**
* test editing rule tags
*
*/
@Test
public void testRuleTags() {
RuleImpl rule1 = new RuleImpl("ruleWithTag1");
Set<String> ruleTags = new LinkedHashSet<String>();
ruleTags.add("tag1");
rule1.setTags(ruleTags);
ruleRegistry.add(rule1);
RuleImpl rule2 = new RuleImpl("ruleWithTags12");
ruleTags = new LinkedHashSet<String>();
ruleTags.add("tag1");
ruleTags.add("tag2");
rule2.setTags(ruleTags);
ruleRegistry.add(rule2);
Rule rule1Get = ruleEngine.getRule("ruleWithTag1");
Assert.assertNotNull("Cannot find rule by UID", rule1Get);
Assert.assertNotNull("rule.getTags is null", rule1Get.getTags());
Assert.assertEquals("rule.getTags is empty", 1, rule1Get.getTags().size());
Rule rule2Get = ruleEngine.getRule("ruleWithTags12");
Assert.assertNotNull("Cannot find rule by UID", rule2Get);
Assert.assertNotNull("rule.getTags is null", rule2Get.getTags());
Assert.assertEquals("rule.getTags is empty", 2, rule2Get.getTags().size());
}
/**
* test rule configurations with null
*
*/
@Test
public void testRuleConfigNull() {
Rule rule3 = RuleBuilder.create("rule3").withTriggers(createTriggers("typeUID"))
.withConditions(createConditions("typeUID")).withActions(createActions("typeUID")).build();
ruleRegistry.add(rule3);
Rule rule3Get = ruleEngine.getRule("rule3");
Assert.assertNotNull("RuleImpl configuration is null", rule3Get.getConfiguration());
}
/**
* test rule configurations with real values
*
*/
@Test
public void testRuleConfigValue() {
List<ConfigDescriptionParameter> configDescriptions = createConfigDescriptions();
Configuration configurations = new Configuration();
configurations.put("config1", 5);
Rule rule4 = RuleBuilder.create("rule4").withTriggers(createTriggers("typeUID"))
.withConditions(createConditions("typeUID")).withActions(createActions("typeUID"))
.withConfigurationDescriptions(configDescriptions).withConfiguration(configurations).build();
ruleRegistry.add(rule4);
Rule rule4Get = ruleEngine.getRule("rule4");
Configuration rule4cfg = rule4Get.getConfiguration();
List<ConfigDescriptionParameter> rule4cfgD = rule4Get.getConfigurationDescriptions();
Assert.assertNotNull("RuleImpl configuration is null", rule4cfg);
Assert.assertTrue("Missing config property in rule copy", rule4cfg.containsKey("config1"));
Assert.assertEquals("Wrong config value", new BigDecimal(5), rule4cfg.get("config1"));
Assert.assertNotNull("RuleImpl configuration description is null", rule4cfgD);
Assert.assertEquals("Missing config description in rule copy", 1, rule4cfgD.size());
ConfigDescriptionParameter rule4cfgDP = rule4cfgD.iterator().next();
Assert.assertEquals("Wrong default value in config description", "3", rule4cfgDP.getDefault());
Assert.assertEquals("Wrong context value in config description", "context1", rule4cfgDP.getContext());
Assert.assertNotNull("Null options in config description", rule4cfgDP.getOptions());
Assert.assertEquals("Wrong option value in config description", "1", rule4cfgDP.getOptions().get(0).getValue());
Assert.assertEquals("Wrong option label in config description", "one",
rule4cfgDP.getOptions().get(0).getLabel());
}
/**
* test rule actions
*
*/
@Test
public void testRuleActions() {
RuleImpl rule1 = createRule();
List<Action> actions = new ArrayList<Action>(rule1.getActions());
ruleRegistry.add(rule1);
Rule rule1Get = ruleEngine.getRule("rule1");
List<Action> actionsGet = rule1Get.getActions();
Assert.assertNotNull("Null actions list", actionsGet);
Assert.assertEquals("Empty actions list", 1, actionsGet.size());
Assert.assertEquals("Returned actions list should not be a copy", actionsGet, rule1Get.getActions());
actions.add(ModuleBuilder.createAction().withId("actionId2").withTypeUID("typeUID2").build());
rule1.setActions(actions);
ruleEngine.addRule(rule1);
rule1Get = ruleEngine.getRule("rule1");
List<Action> actionsGet2 = rule1Get.getActions();
Assert.assertNotNull("Null actions list", actionsGet2);
Assert.assertEquals("Action was not added to the rule's list of actions", 2, actionsGet2.size());
Assert.assertNotNull("RuleImpl action with wrong id is returned", rule1Get.getModule("actionId2"));
actions.add(ModuleBuilder.createAction().withId("actionId3").withTypeUID("typeUID3").build());
ruleEngine.addRule(rule1); // ruleEngine.update will update the RuleImpl2.moduleMap with the new module
rule1Get = ruleEngine.getRule("rule1");
List<Action> actionsGet3 = rule1Get.getActions();
Assert.assertNotNull("Null actions list", actionsGet3);
Assert.assertEquals("Action was not added to the rule's list of actions", 3, actionsGet3.size());
Assert.assertNotNull("RuleImpl modules map was not updated",
ruleEngine.getRule("rule1").getModule("actionId3"));
}
/**
* test rule triggers
*
*/
@Test
public void testRuleTriggers() {
RuleImpl rule1 = createRule();
List<Trigger> triggers = new ArrayList<Trigger>(rule1.getTriggers());
ruleRegistry.add(rule1);
Rule rule1Get = ruleEngine.getRule("rule1");
List<Trigger> triggersGet = rule1Get.getTriggers();
Assert.assertNotNull("Null triggers list", triggersGet);
Assert.assertEquals("Empty triggers list", 1, triggersGet.size());
Assert.assertEquals("Returned triggers list should not be a copy", triggersGet, rule1Get.getTriggers());
triggers.add(ModuleBuilder.createTrigger().withId("triggerId2").withTypeUID("typeUID2").build());
rule1.setTriggers(triggers);
ruleEngine.addRule(rule1); // ruleEngine.update will update the
// RuleImpl2.moduleMap with the new
// module
Rule rule2Get = ruleEngine.getRule("rule1");
List<Trigger> triggersGet2 = rule2Get.getTriggers();
Assert.assertNotNull("Null triggers list", triggersGet2);
Assert.assertEquals("Trigger was not added to the rule's list of triggers", 2, triggersGet2.size());
Assert.assertEquals("Returned triggers list should not be a copy", triggersGet2, rule2Get.getTriggers());
Assert.assertNotNull("RuleImpl trigger with wrong id is returned: " + triggersGet2,
rule2Get.getModule("triggerId2"));
}
/**
* test rule condition
*/
@Test
public void testRuleConditions() {
RuleImpl rule1 = createRule();
List<Condition> conditions = new ArrayList<>(rule1.getConditions());
ruleRegistry.add(rule1);
Rule rule1Get = ruleEngine.getRule("rule1");
List<Condition> conditionsGet = rule1Get.getConditions();
Assert.assertNotNull("Null conditions list", conditionsGet);
Assert.assertEquals("Empty conditions list", 1, conditionsGet.size());
Assert.assertEquals("Returned conditions list should not be a copy", conditionsGet, rule1Get.getConditions());
conditions.add(ModuleBuilder.createCondition().withId("conditionId2").withTypeUID("typeUID2").build());
rule1.setConditions(conditions);
ruleEngine.addRule(rule1); // ruleEngine.update will update the RuleImpl2.moduleMap with the new module
Rule rule2Get = ruleEngine.getRule("rule1");
List<Condition> conditionsGet2 = rule2Get.getConditions();
Assert.assertNotNull("Null conditions list", conditionsGet2);
Assert.assertEquals("Condition was not added to the rule's list of conditions", 2, conditionsGet2.size());
Assert.assertEquals("Returned conditions list should not be a copy", conditionsGet2, rule2Get.getConditions());
Assert.assertNotNull("RuleImpl condition with wrong id is returned: " + conditionsGet2,
rule2Get.getModule("conditionId2"));
}
private RuleImpl createRule() {
return (RuleImpl) RuleBuilder.create("rule1").withTriggers(createTriggers("typeUID"))
.withConditions(createConditions("typeUID")).withActions(createActions("typeUID")).build();
}
private RuleImpl createAutoMapRule() {
return (RuleImpl) RuleBuilder.create("AutoMapRule")
.withTriggers(createTriggers(TestModuleTypeProvider.TRIGGER_TYPE))
.withConditions(createConditions(TestModuleTypeProvider.CONDITION_TYPE))
.withActions(createActions(TestModuleTypeProvider.ACTION_TYPE)).build();
}
private List<Trigger> createTriggers(String type) {
List<Trigger> triggers = new ArrayList<Trigger>();
Configuration configurations = new Configuration();
configurations.put("a", "x");
configurations.put("b", "y");
configurations.put("c", "z");
triggers.add(ModuleBuilder.createTrigger().withId("triggerId").withTypeUID(type)
.withConfiguration(configurations).build());
return triggers;
}
private List<Condition> createConditions(String type) {
List<Condition> conditions = new ArrayList<Condition>();
Configuration configurations = new Configuration();
configurations.put("a", "x");
configurations.put("b", "y");
configurations.put("c", "z");
Map<String, String> inputs = new HashMap<String, String>(11);
String ouputModuleId = "triggerId";
String outputName = "triggerOutput";
String inputName = "conditionInput";
inputs.put(inputName, ouputModuleId + "." + outputName);
conditions.add(ModuleBuilder.createCondition().withId("conditionId").withTypeUID(type)
.withConfiguration(configurations).withInputs(inputs).build());
return conditions;
}
private List<Action> createActions(String type) {
List<Action> actions = new ArrayList<Action>();
Configuration configurations = new Configuration();
configurations.put("a", "x");
configurations.put("b", "y");
configurations.put("c", "z");
Map<String, String> inputs = new HashMap<String, String>(11);
String ouputModuleId = "triggerId";
String outputName = "triggerOutput";
String inputName = "actionInput";
inputs.put(inputName, ouputModuleId + "." + outputName);
inputs.put("in6", ouputModuleId + "." + outputName);
actions.add(ModuleBuilder.createAction().withId("actionId").withTypeUID(type).withConfiguration(configurations)
.withInputs(inputs).build());
return actions;
}
private List<ConfigDescriptionParameter> createConfigDescriptions() {
List<ConfigDescriptionParameter> configDescriptions = new ArrayList<ConfigDescriptionParameter>();
List<ParameterOption> options = new ArrayList<ParameterOption>();
options.add(new ParameterOption("1", "one"));
options.add(new ParameterOption("2", "two"));
String groupName = null;
Boolean advanced = false;
Boolean limitToOptions = true;
Integer multipleLimit = 0;
String label = "label1";
String pattern = null;
String context = "context1";
String description = "description1";
BigDecimal min = null;
BigDecimal max = null;
BigDecimal step = null;
Boolean required = true;
Boolean multiple = false;
Boolean readOnly = false;
String typeStr = ConfigDescriptionParameter.Type.INTEGER.name();
String defValue = "3";
List<FilterCriteria> filter = new ArrayList<FilterCriteria>();
String configPropertyName = "config1";
ConfigDescriptionParameter cfgDP = ConfigDescriptionParameterBuilder
.create(configPropertyName, Type.valueOf(typeStr)).withMaximum(max).withMinimum(min).withStepSize(step)
.withPattern(pattern).withRequired(required).withReadOnly(readOnly).withMultiple(multiple)
.withContext(context).withDefault(defValue).withLabel(label).withDescription(description)
.withOptions(options).withFilterCriteria(filter).withGroupName(groupName).withAdvanced(advanced)
.withLimitToOptions(limitToOptions).withMultipleLimit(multipleLimit).build();
configDescriptions.add(cfgDP);
return configDescriptions;
}
}
@@ -0,0 +1,77 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.automation.core.internal;
import org.eclipse.smarthome.automation.RulePredicates;
import org.junit.Assert;
import org.junit.Test;
/**
* Testing the prefix functionality.
*
* @author Victor Toni - Initial contribution
*/
public class RulePrefixTest {
private static final String TESTING_PREFIX = "Testing";
/**
* Testing Rules without UID / without prefix / empty prefix.
*
* @see RulePredicates#PREFIX_SEPARATOR
*
*/
@Test
public void testEmptyPrefix() {
final RuleImpl rule0 = new RuleImpl(null);
Assert.assertNotNull("Returned UID is null instead of generated one", rule0.getUID());
Assert.assertNull("Returned a prefix instead of null", RulePredicates.getPrefix(rule0));
final String somethingWithoutSeparator = "something_without_separator";
final RuleImpl rule1 = new RuleImpl(somethingWithoutSeparator);
Assert.assertEquals("Returned wrong UID", somethingWithoutSeparator, rule1.getUID());
Assert.assertNull("Returned a prefix instead of null", RulePredicates.getPrefix(rule1));
final String withSeparatorButEmpty = RulePredicates.PREFIX_SEPARATOR + "with_separator_but_empty";
final RuleImpl rule2 = new RuleImpl(withSeparatorButEmpty);
Assert.assertEquals("Returned wrong UID", withSeparatorButEmpty, rule2.getUID());
Assert.assertNull("Returned a prefix instead of null", RulePredicates.getPrefix(rule2));
}
/**
* Testing Rules with manually created prefix / empty parts after the separator / multiple separators.
*
* @see RulePredicates#PREFIX_SEPARATOR
*
*/
@Test
public void testManualPrefix() {
final String testingPrefixPrefix = TESTING_PREFIX + RulePredicates.PREFIX_SEPARATOR;
final String someName = "someName";
final RuleImpl rule0 = new RuleImpl(testingPrefixPrefix + someName);
Assert.assertEquals("Returned wrong prefix", TESTING_PREFIX, RulePredicates.getPrefix(rule0));
Assert.assertEquals("Returned wrong UID", testingPrefixPrefix + someName, rule0.getUID());
final String multipleSeparatorName = RulePredicates.PREFIX_SEPARATOR + "nameBetweenSeparator"
+ RulePredicates.PREFIX_SEPARATOR;
final RuleImpl rule1 = new RuleImpl(testingPrefixPrefix + multipleSeparatorName);
Assert.assertEquals("Returned wrong prefix", TESTING_PREFIX, RulePredicates.getPrefix(rule1));
Assert.assertEquals("Returned wrong UID", testingPrefixPrefix + someName, rule0.getUID());
final String emptyName = "";
final RuleImpl rule2 = new RuleImpl(testingPrefixPrefix + emptyName);
Assert.assertEquals("Returned wrong prefix", TESTING_PREFIX, RulePredicates.getPrefix(rule2));
Assert.assertEquals("Returned wrong UID", testingPrefixPrefix + emptyName, rule2.getUID());
}
}
@@ -0,0 +1,290 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.automation.core.internal;
import static org.eclipse.smarthome.automation.RulePredicates.*;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.eclipse.smarthome.automation.Rule;
import org.eclipse.smarthome.automation.RuleRegistry;
import org.eclipse.smarthome.test.java.JavaOSGiTest;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* Testing the {@link Predicate}s for {@link RuleImpl}s.
*
* @author Victor Toni - Initial contribution
*/
public class RuleRegistryTest extends JavaOSGiTest {
RuleRegistry ruleRegistry;
@Before
public void setup() {
registerVolatileStorageService();
ruleRegistry = getService(RuleRegistry.class);
}
/**
* test adding and retrieving rules
*
*/
@Test
public void testAddRetrieveRules() {
final String tag1 = "tag1";
final String tag2 = "tag2";
final String tag3 = "tag3";
Set<String> tags;
String name;
Rule addedRule;
Rule getRule;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// checking RuleRegistry
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Assert.assertEquals("RuleImpl list size", 0, ruleRegistry.getAll().size());
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// checking rule without tag
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
name = "rule_without_tag";
final RuleImpl rule_without_tag = new RuleImpl(name);
addedRule = ruleRegistry.add(rule_without_tag);
Assert.assertNotNull("RuleImpl for:" + name, addedRule);
getRule = ruleRegistry.get(name);
Assert.assertNotNull("RuleImpl for:" + name, getRule);
Assert.assertEquals("RuleImpl list size", 1, ruleRegistry.getAll().size());
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// checking that results from stream() have the same size as getAll() above
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Assert.assertEquals("RuleImpl list size", 1, ruleRegistry.stream().collect(Collectors.toList()).size());
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// checking predicates
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Assert.assertEquals("RuleImpl list size", 1,
ruleRegistry.stream().filter(hasNoTags()).collect(Collectors.toList()).size());
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// checking rule with 1 tag
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
name = "rule_with_tag1";
tags = new HashSet<>();
tags.add(tag1);
final RuleImpl rule_with_tag1 = new RuleImpl(name);
rule_with_tag1.setTags(tags);
addedRule = ruleRegistry.add(rule_with_tag1);
Assert.assertNotNull("RuleImpl for:" + name, addedRule);
getRule = ruleRegistry.get(name);
Assert.assertNotNull("RuleImpl for:" + name, getRule);
Assert.assertEquals("RuleImpl list size", 2, ruleRegistry.getAll().size());
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// checking that results from stream() have the same size as getAll() above
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Assert.assertEquals("RuleImpl list size", 2, ruleRegistry.stream().collect(Collectors.toList()).size());
Collection<Rule> rules_with_tag1 = ruleRegistry.getByTags(tag1);
Assert.assertEquals("RuleImpl list size", 1, rules_with_tag1.size());
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// checking predicates
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Assert.assertEquals("RuleImpl list size", 1,
ruleRegistry.stream().filter(hasNoTags()).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 1,
ruleRegistry.stream().filter(hasAnyOfTags(tags)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 1,
ruleRegistry.stream().filter(hasAnyOfTags(tag1)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 1,
ruleRegistry.stream().filter(hasAllTags(tags)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 1,
ruleRegistry.stream().filter(hasAllTags(tag1)).collect(Collectors.toList()).size());
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// checking rule with 2 tags
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
name = "rule_with_tag1_tag2";
tags = new HashSet<>();
tags.add(tag1);
tags.add(tag2);
final RuleImpl rule_with_tag1_tag2 = new RuleImpl(name);
rule_with_tag1_tag2.setTags(tags);
addedRule = ruleRegistry.add(rule_with_tag1_tag2);
Assert.assertNotNull("RuleImpl for:" + name, addedRule);
getRule = ruleRegistry.get(name);
Assert.assertNotNull("RuleImpl for:" + name, getRule);
Assert.assertEquals("RuleImpl list size", 3, ruleRegistry.getAll().size());
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// checking that results from stream() have the same size as getAll() above
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Assert.assertEquals("RuleImpl list size", 3, ruleRegistry.stream().collect(Collectors.toList()).size());
rules_with_tag1 = ruleRegistry.getByTags(tag1);
Assert.assertEquals("RuleImpl list size", 2, rules_with_tag1.size());
Collection<Rule> rules_with_tag2 = ruleRegistry.getByTags(tag2);
Assert.assertEquals("RuleImpl list size", 1, rules_with_tag2.size());
Collection<Rule> rules_with_all_of_tag1_tag2 = ruleRegistry.getByTags(tag1, tag2);
Assert.assertEquals("RuleImpl list size", 1, rules_with_all_of_tag1_tag2.size());
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// checking predicates
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Assert.assertEquals("RuleImpl list size", 1,
ruleRegistry.stream().filter(hasNoTags()).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 2,
ruleRegistry.stream().filter(hasAnyOfTags(tags)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 2,
ruleRegistry.stream().filter(hasAnyOfTags(tag1)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 2,
ruleRegistry.stream().filter(hasAnyOfTags(tag1, tag2)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 1,
ruleRegistry.stream().filter(hasAnyOfTags(tag2)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 1, ruleRegistry.stream()
.filter(hasAnyOfTags(tag1).and(hasAnyOfTags(tag2))).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 2,
ruleRegistry.stream().filter(hasAllTags(tag1)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 1,
ruleRegistry.stream().filter(hasAllTags(tags)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 1,
ruleRegistry.stream().filter(hasAllTags(tag1, tag2)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 1,
ruleRegistry.stream().filter(hasAllTags(tag2)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 1, ruleRegistry.stream()
.filter(hasAllTags(tag1).and(hasAllTags(tag2))).collect(Collectors.toList()).size());
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// checking rule with 3 tags
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
name = "rule_with_tag1_tag2_tag3";
tags = new HashSet<>();
tags.add(tag1);
tags.add(tag2);
tags.add(tag3);
final RuleImpl rule_with_tag1_tag2_tag3 = new RuleImpl("rule_with_tag1_tag2_tag3");
rule_with_tag1_tag2_tag3.setTags(tags);
addedRule = ruleRegistry.add(rule_with_tag1_tag2_tag3);
Assert.assertNotNull("RuleImpl for:" + name, addedRule);
getRule = ruleRegistry.get(name);
Assert.assertNotNull("RuleImpl for:" + name, getRule);
Assert.assertEquals("RuleImpl list size", 4, ruleRegistry.getAll().size());
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// checking that results from stream() have the same size as getAll() above
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Assert.assertEquals("RuleImpl list size", 4, ruleRegistry.stream().collect(Collectors.toList()).size());
rules_with_tag1 = ruleRegistry.getByTags(tag1);
Assert.assertEquals("RuleImpl list size", 3, rules_with_tag1.size());
rules_with_tag2 = ruleRegistry.getByTags(tag2);
Assert.assertEquals("RuleImpl list size", 2, rules_with_tag2.size());
Collection<Rule> rules_with_tag3 = ruleRegistry.getByTags(tag3);
Assert.assertEquals("RuleImpl list size", 1, rules_with_tag3.size());
rules_with_all_of_tag1_tag2 = ruleRegistry.getByTags(tag1, tag2);
Assert.assertEquals("RuleImpl list size", 2, rules_with_all_of_tag1_tag2.size());
Collection<Rule> rules_with_all_tag1_tag3 = ruleRegistry.getByTags(tag1, tag3);
Assert.assertEquals("RuleImpl list size", 1, rules_with_all_tag1_tag3.size());
Collection<Rule> rules_with_all_of_tag1_tag2_tag3 = ruleRegistry.getByTags(tag1, tag2, tag3);
Assert.assertEquals("RuleImpl list size", 1, rules_with_all_of_tag1_tag2_tag3.size());
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// checking predicates
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Assert.assertEquals("RuleImpl list size", 1,
ruleRegistry.stream().filter(hasNoTags()).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 3,
ruleRegistry.stream().filter(hasAnyOfTags(tags)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 3,
ruleRegistry.stream().filter(hasAnyOfTags(tag1)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 3,
ruleRegistry.stream().filter(hasAnyOfTags(tag1, tag2)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 3,
ruleRegistry.stream().filter(hasAnyOfTags(tag1, tag2, tag3)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 2,
ruleRegistry.stream().filter(hasAnyOfTags(tag2)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 2,
ruleRegistry.stream().filter(hasAnyOfTags(tag2, tag3)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 2, ruleRegistry.stream()
.filter(hasAnyOfTags(tag1).and(hasAnyOfTags(tag2))).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 1, ruleRegistry.stream()
.filter(hasAnyOfTags(tag1).and(hasAnyOfTags(tag3))).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 1, ruleRegistry.stream()
.filter(hasAnyOfTags(tag2).and(hasAnyOfTags(tag3))).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 1,
ruleRegistry.stream().filter(hasAnyOfTags(tag3)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 3,
ruleRegistry.stream().filter(hasAllTags(tag1)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 2,
ruleRegistry.stream().filter(hasAllTags(tag2)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 2,
ruleRegistry.stream().filter(hasAllTags(tag1, tag2)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 1,
ruleRegistry.stream().filter(hasAllTags(tags)).collect(Collectors.toList()).size());
Assert.assertEquals("RuleImpl list size", 1,
ruleRegistry.stream().filter(hasAllTags(tag1, tag2, tag3)).collect(Collectors.toList()).size());
}
}
@@ -0,0 +1,117 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.automation.core.internal;
import static java.util.stream.Collectors.toSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.smarthome.automation.type.ActionType;
import org.eclipse.smarthome.automation.type.ConditionType;
import org.eclipse.smarthome.automation.type.Input;
import org.eclipse.smarthome.automation.type.ModuleType;
import org.eclipse.smarthome.automation.type.ModuleTypeProvider;
import org.eclipse.smarthome.automation.type.Output;
import org.eclipse.smarthome.automation.type.TriggerType;
import org.eclipse.smarthome.core.common.registry.ProviderChangeListener;
/**
* ModuleTypeManagerMockup is a ModuleTypeManager which returns mockup module types for the following predefined module
* types: triggerTypeUID, conditionTypeUID and actionTypeUID. The types have preset tags of their input and outputs.
*
* @author Yordan Mihaylov - initial version
*/
public class TestModuleTypeProvider implements ModuleTypeProvider {
public static final String TRIGGER_TYPE = "triggerTypeUID";
public static final String ACTION_TYPE = "actionTypeUID";
public static final String CONDITION_TYPE = "conditionTypeUID";
public TestModuleTypeProvider() {
super();
}
private TriggerType createTriggerType() {
List<Output> outputs = new ArrayList<Output>(3);
outputs.add(createOutput("out1", new String[] { "tagA" }));
outputs.add(createOutput("out2", new String[] { "tagB", "tagC" }));
outputs.add(createOutput("out3", new String[] { "tagA", "tagB", "tagC" }));
TriggerType t = new TriggerType(TRIGGER_TYPE, null, outputs);
return t;
}
private ConditionType createConditionType() {
List<Input> inputs = new ArrayList<Input>(3);
inputs.add(createInput("in0", new String[] { "tagE" })); // no connection, missing condition tag
inputs.add(createInput("in1", new String[] { "tagA" })); // conflict in2 -> out1 or in2 -> out3
inputs.add(createInput("in2", new String[] { "tagA", "tagB" })); // in2 -> out3
ConditionType t = new ConditionType(CONDITION_TYPE, null, inputs);
return t;
}
private ActionType createActionType() {
List<Input> inputs = new ArrayList<Input>(3);
inputs.add(createInput("in3", new String[] { "tagD" })); // conflict in3 -> out4 or in3 -> out5
inputs.add(createInput("in4", new String[] { "tagD", "tagE" })); // in4 -> out5
inputs.add(createInput("in5", new String[] { "tagA", "tagB", "tagC" })); // in5 -> out3
inputs.add(createInput("in6", new String[] { "tagA", "tagB" })); // conflict in6 has user defined connection
List<Output> outputs = new ArrayList<Output>(3);
outputs.add(createOutput("out4", new String[] { "tagD" }));
outputs.add(createOutput("out5", new String[] { "tagD", "tagE" }));
ActionType t = new ActionType(ACTION_TYPE, null, inputs, outputs);
return t;
}
private Output createOutput(String name, String[] tags) {
Set<String> tagSet = new HashSet<String>(Arrays.asList(tags));
return new Output(name, String.class.getName(), null, null, tagSet, null, null);
}
private Input createInput(String name, String[] tags) {
Set<String> tagSet = new HashSet<String>(Arrays.asList(tags));
return new Input(name, String.class.getName(), null, null, tagSet, false, null, null);
}
@Override
public void addProviderChangeListener(@NonNull ProviderChangeListener<ModuleType> listener) {
}
@Override
public @NonNull Collection<ModuleType> getAll() {
return Stream.of(createTriggerType(), createConditionType(), createActionType()).collect(toSet());
}
@Override
public void removeProviderChangeListener(@NonNull ProviderChangeListener<ModuleType> listener) {
}
@Override
public <T extends ModuleType> T getModuleType(String UID, Locale locale) {
return null;
}
@Override
public <T extends ModuleType> Collection<T> getModuleTypes(Locale locale) {
return null;
}
}
@@ -0,0 +1 @@
/test-classes/
@@ -0,0 +1,19 @@
This content is produced and maintained by the Eclipse SmartHome project.
* Project home: https://eclipse.org/smarthome/
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/eclipse/smarthome
== Copyright Holders
See the NOTICE file distributed with the source code at
https://github.com/eclipse/smarthome/blob/master/NOTICE
for detailed information regarding copyright ownership.
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.pde.ui.JunitLaunchConfig">
<booleanAttribute key="append.args" value="true"/>
<booleanAttribute key="askclear" value="false"/>
<booleanAttribute key="automaticAdd" value="false"/>
<booleanAttribute key="automaticValidate" value="true"/>
<stringAttribute key="bootstrap" value=""/>
<stringAttribute key="checked" value="[NONE]"/>
<booleanAttribute key="clearConfig" value="true"/>
<booleanAttribute key="clearws" value="true"/>
<booleanAttribute key="clearwslog" value="false"/>
<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/pde-junit"/>
<booleanAttribute key="default" value="false"/>
<booleanAttribute key="includeOptional" value="false"/>
<stringAttribute key="location" value="${workspace_loc}/../junit-workspace"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/org.eclipse.smarthome.automation.event.test"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.smarthome.automation.event.test"/>
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.smarthome.automation.event.test"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="pde.version" value="3.3"/>
<stringAttribute key="product" value="org.eclipse.equinox.p2.director.app.product"/>
<booleanAttribute key="run_in_ui_thread" value="false"/>
<stringAttribute key="selected_target_plugins" value="ch.qos.logback.classic@default:default,ch.qos.logback.core@default:default,ch.qos.logback.slf4j@default:false,com.google.gson@default:true,com.google.guava@default:default,javax.activation@default:default,javax.inject@default:default,javax.measure.unit-api@default:default,javax.servlet@default:default,javax.transaction@default:false,javax.xml@default:default,net.bytebuddy.byte-buddy-agent@default:default,net.bytebuddy.byte-buddy@default:default,org.apache.ant@default:default,org.apache.commons.collections@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.felix.scr@1:true,org.codehaus.groovy@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.runtime@default:true,org.eclipse.emf.common@default:default,org.eclipse.emf.ecore.xmi@default:default,org.eclipse.emf.ecore@default:default,org.eclipse.equinox.app@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.ds@1:true,org.eclipse.equinox.event@default:true,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.region@default:false,org.eclipse.equinox.registry@default:default,org.eclipse.equinox.util@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi.util@default:default,org.eclipse.osgi@-1:true,org.hamcrest.core@default:default,org.junit@default:true,org.mockito.mockito-core@default:default,org.objenesis@default:default,org.slf4j.api@default:default,org.slf4j.log4j@default:default,tec.uom.lib.uom-lib-common@default:default,tec.uom.se@default:default"/>
<stringAttribute key="selected_workspace_plugins" value="org.eclipse.smarthome.automation.api@2:true,org.eclipse.smarthome.automation.core@3:true,org.eclipse.smarthome.automation.event.test@default:true,org.eclipse.smarthome.automation.module.core@3:true,org.eclipse.smarthome.automation.module.script.defaultscope@default:default,org.eclipse.smarthome.automation.module.script.rulesupport@default:default,org.eclipse.smarthome.automation.module.script@default:default,org.eclipse.smarthome.automation.module.timer.test@default:default,org.eclipse.smarthome.automation.module.timer@default:default,org.eclipse.smarthome.automation.parser.gson@2:true,org.eclipse.smarthome.automation.provider.file@default:default,org.eclipse.smarthome.automation.providers@2:true,org.eclipse.smarthome.config.core@default:true,org.eclipse.smarthome.config.xml@default:true,org.eclipse.smarthome.core.thing@default:true,org.eclipse.smarthome.core@2:true,org.eclipse.smarthome.io.console@default:default,org.eclipse.smarthome.test@default:default"/>
<booleanAttribute key="show_selected_only" value="false"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfig" value="true"/>
<booleanAttribute key="useDefaultConfigArea" value="false"/>
<booleanAttribute key="useProduct" value="false"/>
</launchConfiguration>
@@ -0,0 +1,146 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.core.itests</groupId>
<artifactId>org.openhab.core.reactor.itests</artifactId>
<version>2.5.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.core.automation.event.tests</artifactId>
<packaging>eclipse-test-plugin</packaging>
<name>openHAB Core :: Integration Tests :: Automation Event Tests</name>
<build>
<plugins>
<plugin>
<groupId>${tycho-groupid}</groupId>
<artifactId>tycho-surefire-plugin</artifactId>
<configuration>
<dependencies>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.openhab.core.config.core</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.openhab.core.config.xml</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.openhab.core</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.eclipse.core.runtime</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.eclipse.equinox.common</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.eclipse.equinox.ds</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.eclipse.equinox.event</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.eclipse.osgi</artifactId>
<version>0.0.0</version>
</dependency>
<!-- LOGGING -->
<dependency>
<type>eclipse-plugin</type>
<artifactId>ch.qos.logback.classic</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>ch.qos.logback.core</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>ch.qos.logback.slf4j</artifactId>
<version>0.0.0</version>
</dependency>
</dependencies>
<bundleStartLevel>
<bundle>
<id>org.eclipse.smarthome.automation.api</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.core</id>
<level>3</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.module.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.parser.gson</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.providers</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.config.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.config.xml</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.core</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.core.runtime</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.common</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.ds</id>
<level>1</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.event</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
</bundleStartLevel>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,238 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.automation.event;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.smarthome.automation.Action;
import org.eclipse.smarthome.automation.Rule;
import org.eclipse.smarthome.automation.RuleManager;
import org.eclipse.smarthome.automation.RuleRegistry;
import org.eclipse.smarthome.automation.RuleStatus;
import org.eclipse.smarthome.automation.Trigger;
import org.eclipse.smarthome.automation.core.util.ModuleBuilder;
import org.eclipse.smarthome.automation.core.util.RuleBuilder;
import org.eclipse.smarthome.automation.events.RuleAddedEvent;
import org.eclipse.smarthome.automation.events.RuleRemovedEvent;
import org.eclipse.smarthome.automation.events.RuleStatusInfoEvent;
import org.eclipse.smarthome.automation.events.RuleUpdatedEvent;
import org.eclipse.smarthome.config.core.Configuration;
import org.eclipse.smarthome.core.common.registry.ProviderChangeListener;
import org.eclipse.smarthome.core.events.Event;
import org.eclipse.smarthome.core.events.EventFilter;
import org.eclipse.smarthome.core.events.EventPublisher;
import org.eclipse.smarthome.core.events.EventSubscriber;
import org.eclipse.smarthome.core.items.Item;
import org.eclipse.smarthome.core.items.ItemNotFoundException;
import org.eclipse.smarthome.core.items.ItemProvider;
import org.eclipse.smarthome.core.items.ItemRegistry;
import org.eclipse.smarthome.core.items.events.ItemCommandEvent;
import org.eclipse.smarthome.core.items.events.ItemEventFactory;
import org.eclipse.smarthome.core.library.items.SwitchItem;
import org.eclipse.smarthome.core.library.types.OnOffType;
import org.eclipse.smarthome.test.java.JavaOSGiTest;
import org.eclipse.smarthome.test.storage.VolatileStorageService;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This tests events of rules
*
* @author Benedikt Niehues - initial contribution
* @author Kai Kreuzer - ported test to Java
*
*/
public class RuleEventTest extends JavaOSGiTest {
final Logger logger = LoggerFactory.getLogger(RuleEventTest.class);
VolatileStorageService volatileStorageService = new VolatileStorageService();
Event itemEvent = null;
Event ruleRemovedEvent = null;
public RuleEventTest() {
}
@Before
public void before() {
ItemProvider itemProvider = new ItemProvider() {
@Override
public void addProviderChangeListener(@NonNull ProviderChangeListener<@NonNull Item> listener) {
}
@Override
public @NonNull Collection<@NonNull Item> getAll() {
return Arrays.asList(new Item[] { new SwitchItem("myMotionItem"), new SwitchItem("myPresenceItem"),
new SwitchItem("myLampItem"), new SwitchItem("myMotionItem2"),
new SwitchItem("myPresenceItem2"), new SwitchItem("myLampItem2") });
}
@Override
public void removeProviderChangeListener(@NonNull ProviderChangeListener<@NonNull Item> listener) {
}
};
registerService(itemProvider);
registerVolatileStorageService();
}
@Test
public void testRuleEvents() throws ItemNotFoundException {
// Registering eventSubscriber
List<Event> ruleEvents = new ArrayList<>();
EventSubscriber ruleEventHandler = new EventSubscriber() {
@Override
public Set<String> getSubscribedEventTypes() {
Set<String> types = new HashSet<>();
types.add(RuleAddedEvent.TYPE);
types.add(RuleRemovedEvent.TYPE);
types.add(RuleStatusInfoEvent.TYPE);
types.add(RuleUpdatedEvent.TYPE);
return types;
}
@Override
public EventFilter getEventFilter() {
return null;
}
@Override
public void receive(Event event) {
logger.info("RuleEvent: {}", event.getTopic());
ruleEvents.add(event);
}
};
registerService(ruleEventHandler);
// Creation of RULE
Map<String, Object> triggerCfgEntries = new HashMap<>();
triggerCfgEntries.put("eventSource", "myMotionItem2");
triggerCfgEntries.put("eventTopic", "smarthome/*");
triggerCfgEntries.put("eventTypes", "ItemStateEvent");
Configuration triggerConfig = new Configuration(triggerCfgEntries);
Map<String, Object> actionCfgEntries = new HashMap<>();
actionCfgEntries.put("itemName", "myLampItem2");
actionCfgEntries.put("command", "ON");
Configuration actionConfig = new Configuration(actionCfgEntries);
List<Trigger> triggers = Collections
.singletonList(ModuleBuilder.createTrigger().withId("ItemStateChangeTrigger2")
.withTypeUID("core.GenericEventTrigger").withConfiguration(triggerConfig).build());
List<Action> actions = Collections.singletonList(ModuleBuilder.createAction().withId("ItemPostCommandAction2")
.withTypeUID("core.ItemCommandAction").withConfiguration(actionConfig).build());
Rule rule = RuleBuilder.create("myRule21").withTriggers(triggers).withActions(actions)
.withName("RuleEventTestingRule").build();
logger.info("Rule created: {}", rule.getUID());
RuleRegistry ruleRegistry = getService(RuleRegistry.class);
RuleManager ruleEngine = getService(RuleManager.class);
ruleRegistry.add(rule);
ruleEngine.setEnabled(rule.getUID(), true);
waitForAssert(() -> {
assertThat(ruleEngine.getStatusInfo(rule.getUID()).getStatus(), is(RuleStatus.IDLE));
});
// TEST RULE
EventPublisher eventPublisher = getService(EventPublisher.class);
ItemRegistry itemRegistry = getService(ItemRegistry.class);
SwitchItem myMotionItem = (SwitchItem) itemRegistry.getItem("myMotionItem2");
assertNotNull(myMotionItem);
eventPublisher.post(ItemEventFactory.createStateEvent("myPresenceItem2", OnOffType.ON));
EventSubscriber itemEventHandler = new EventSubscriber() {
@Override
public void receive(Event event) {
logger.info("Event: {}", event.getTopic());
if (event instanceof ItemCommandEvent && event.getTopic().contains("myLampItem2")) {
itemEvent = event;
}
}
@Override
public Set<String> getSubscribedEventTypes() {
return Collections.singleton(ItemCommandEvent.TYPE);
}
@Override
public EventFilter getEventFilter() {
return null;
}
};
registerService(itemEventHandler);
eventPublisher.post(ItemEventFactory.createStateEvent("myMotionItem2", OnOffType.ON));
waitForAssert(() -> assertThat(itemEvent, is(notNullValue())));
assertThat(itemEvent.getTopic(), is(equalTo("smarthome/items/myLampItem2/command")));
assertThat(((ItemCommandEvent) itemEvent).getItemCommand(), is(OnOffType.ON));
assertThat(ruleEvents.size(), is(not(0)));
assertThat(ruleEvents.stream().filter(e -> e.getTopic().equals("smarthome/rules/myRule21/added")).findFirst()
.isPresent(), is(true));
assertThat(ruleEvents.stream().filter(e -> e.getTopic().equals("smarthome/rules/myRule21/state")).findFirst()
.isPresent(), is(true));
List<Event> stateEvents = ruleEvents.stream().filter(e -> e.getTopic().equals("smarthome/rules/myRule21/state"))
.collect(Collectors.toList());
assertThat(stateEvents, is(notNullValue()));
Optional<Event> runningEvent = stateEvents.stream()
.filter(e -> ((RuleStatusInfoEvent) e).getStatusInfo().getStatus() == RuleStatus.RUNNING).findFirst();
assertThat(runningEvent.isPresent(), is(true));
EventSubscriber ruleRemovedEventHandler = new EventSubscriber() {
@Override
public Set<String> getSubscribedEventTypes() {
return Collections.singleton(RuleRemovedEvent.TYPE);
}
@Override
public EventFilter getEventFilter() {
return null;
}
@Override
public void receive(Event event) {
logger.info("RuleRemovedEvent: {}", event.getTopic());
ruleRemovedEvent = event;
}
};
registerService(ruleRemovedEventHandler);
ruleRegistry.remove("myRule21");
waitForAssert(() -> {
assertThat(ruleRemovedEvent, is(notNullValue()));
assertThat(ruleRemovedEvent.getTopic(), is(equalTo("smarthome/rules/myRule21/removed")));
});
}
}
@@ -0,0 +1 @@
/test-classes/
@@ -0,0 +1,19 @@
This content is produced and maintained by the Eclipse SmartHome project.
* Project home: https://eclipse.org/smarthome/
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/eclipse/smarthome
== Copyright Holders
See the NOTICE file distributed with the source code at
https://github.com/eclipse/smarthome/blob/master/NOTICE
for detailed information regarding copyright ownership.
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.pde.ui.JunitLaunchConfig">
<booleanAttribute key="append.args" value="true"/>
<stringAttribute key="application" value="org.eclipse.pde.junit.runtime.coretestapplication"/>
<booleanAttribute key="askclear" value="false"/>
<booleanAttribute key="automaticAdd" value="false"/>
<booleanAttribute key="automaticValidate" value="true"/>
<stringAttribute key="bootstrap" value=""/>
<stringAttribute key="checked" value="[NONE]"/>
<booleanAttribute key="clearConfig" value="true"/>
<booleanAttribute key="clearws" value="true"/>
<booleanAttribute key="clearwslog" value="false"/>
<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/pde-junit"/>
<booleanAttribute key="default" value="false"/>
<booleanAttribute key="default_auto_start" value="true"/>
<booleanAttribute key="includeOptional" value="false"/>
<stringAttribute key="location" value="${workspace_loc}/../junit-workspace"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/org.eclipse.smarthome.automation.integration.test"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.smarthome.automation.integration.test"/>
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.smarthome.automation.integration.test"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="pde.version" value="3.3"/>
<stringAttribute key="product" value="org.eclipse.equinox.p2.director.app.product"/>
<booleanAttribute key="run_in_ui_thread" value="true"/>
<stringAttribute key="selected_target_plugins" value="ch.qos.logback.classic@default:default,ch.qos.logback.core@default:default,ch.qos.logback.slf4j@default:false,com.google.gson@default:default,com.google.guava@default:default,javax.measure.unit-api@default:default,javax.servlet@default:default,javax.transaction@default:false,javax.xml@default:default,net.bytebuddy.byte-buddy-agent@default:default,net.bytebuddy.byte-buddy@default:default,org.apache.ant@default:default,org.apache.commons.collections@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.felix.scr@1:true,org.codehaus.groovy@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.runtime@default:true,org.eclipse.equinox.app@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.ds@1:true,org.eclipse.equinox.event@default:default,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.region@default:false,org.eclipse.equinox.registry@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.equinox.util@default:default,org.eclipse.equinox.weaving.hook@default:false,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi.util@default:default,org.eclipse.osgi@-1:true,org.hamcrest.core@default:default,org.hamcrest.integration@default:default,org.hamcrest.library@default:default,org.hamcrest.text@default:default,org.hamcrest@default:default,org.junit@default:default,org.mockito.mockito-core@default:default,org.objenesis@default:default,org.slf4j.api@default:default,tec.uom.lib.uom-lib-common@default:default,tec.uom.se@default:default"/>
<stringAttribute key="selected_workspace_plugins" value="org.eclipse.smarthome.automation.api@2:true,org.eclipse.smarthome.automation.core@3:true,org.eclipse.smarthome.automation.integration.test@default:default,org.eclipse.smarthome.automation.module.core@default:true,org.eclipse.smarthome.automation.parser.gson@default:default,org.eclipse.smarthome.automation.providers@2:true,org.eclipse.smarthome.automation.sample.extension.json@default:default,org.eclipse.smarthome.config.core@default:true,org.eclipse.smarthome.config.xml@default:true,org.eclipse.smarthome.core.thing@default:true,org.eclipse.smarthome.core@2:true,org.eclipse.smarthome.io.console@default:default,org.eclipse.smarthome.test@default:default"/>
<booleanAttribute key="show_selected_only" value="false"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfig" value="true"/>
<booleanAttribute key="useDefaultConfigArea" value="false"/>
<booleanAttribute key="useProduct" value="false"/>
</launchConfiguration>
@@ -0,0 +1,152 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.core.itests</groupId>
<artifactId>org.openhab.core.reactor.itests</artifactId>
<version>2.5.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.core.automation.integration.tests</artifactId>
<packaging>eclipse-test-plugin</packaging>
<name>openHAB Core :: Integration Tests :: Automation Integration Tests</name>
<build>
<plugins>
<plugin>
<groupId>${tycho-groupid}</groupId>
<artifactId>tycho-surefire-plugin</artifactId>
<configuration>
<dependencies>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.openhab.core.config.core</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.openhab.core.config.xml</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.openhab.core</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.eclipse.core.runtime</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.eclipse.equinox.common</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.eclipse.equinox.ds</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.eclipse.equinox.event</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.eclipse.osgi</artifactId>
<version>0.0.0</version>
</dependency>
<!-- LOGGING -->
<dependency>
<type>eclipse-plugin</type>
<artifactId>ch.qos.logback.classic</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>ch.qos.logback.core</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>ch.qos.logback.slf4j</artifactId>
<version>0.0.0</version>
</dependency>
</dependencies>
<bundleStartLevel>
<bundle>
<id>org.eclipse.smarthome.automation.api</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.core</id>
<level>3</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.module.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.parser.gson</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.providers</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.sample.extension.json</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.config.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.config.xml</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.core</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.core.runtime</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.common</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.ds</id>
<level>1</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.event</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
</bundleStartLevel>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,32 @@
{
"actions":[
{
"uid":"CustomAction1",
"label":"CustomAction1",
"outputs":[
{
"name":"customActionOutput3",
"type":"outputType3",
"label":"CustomActionOutput1 label",
"description":"Custom action output.",
"defaultValue":"{\"command\":\"OFF\"}",
"required":false
}
]
},
{
"uid":"CustomAction2",
"label":"CustomAction2",
"inputs":[
{
"name":"customActionInput",
"type":"outputType4",
"label":"CustomActionOutput2 label",
"description":"Custom action output.",
"defaultValue":5,
"required":false
}
]
}
]
}
@@ -0,0 +1,32 @@
{
"triggers":[
{
"uid":"CustomTrigger1",
"label":"Custom Event Trigger",
"outputs":[
{
"name":"customTriggerOutput1",
"type":"outputType1",
"label":"CustomTriggerOutput1 label",
"description":"Custom trigger output.",
"defaultValue":true,
"reference":"${event}"
}
]
},
{
"uid":"CustomTrigger2",
"label":"Custom Event Trigger",
"outputs":[
{
"name":"customTriggerOutput2",
"type":"outputType2",
"label":"CustomTriggerOutput2 label",
"description":"Custom trigger output.",
"defaultValue":"event",
"reference":"${event}"
}
]
}
]
}
@@ -0,0 +1,51 @@
[
{
"name": "ItemSampleRule",
"uid": "ItemSampleRule",
"tags": [
"sample",
"item",
"jsonTest",
"rule"
],
"configuration": {},
"description": "Sample Rule for items definition.",
"triggers": [
{
"id": "ItemStateChangeTriggerID",
"type": "core.GenericEventTrigger",
"configuration":{
"eventSource":"myMotionItem",
"eventTopic":"smarthome/items/*",
"eventTypes":"ItemStateEvent"
}
}
],
"actions": [
{
"id": "ItemPostCommandActionID",
"type": "core.ItemCommandAction",
"configuration": {
"itemName": "myLampItem",
"command": "ON"
}
}
]
},
{
"uid": "ItemSampleRuleWithReferences",
"name": "ItemSampleRuleWithReferences",
"templateUID": "TemplateSampleRuleWithReferences",
"tags": [
"sample",
"item",
"jsonTest",
"rule",
"references"
],
"configuration": {
"triggerItem": "myMotionItem",
"actionItem": "myLampItem"
}
}
]
@@ -0,0 +1,59 @@
[
{
"uid":"SimpleTestTemplate",
"description":"Sample Rule Template.",
"tags":[
"sample",
"rule",
"template",
"simple"
],
"configDescriptions":[
{
"name":"onItem",
"type":"TEXT",
"description":"ItemName which state change triggers the rule",
"required":true
},
{
"name":"ifState",
"type":"TEXT",
"description":"Right operand which is compared with the input.",
"required":true
},
{
"name":"updateItem",
"type":"TEXT",
"description":"Item which should be updated",
"required":true
},
{
"name":"updateCommand",
"type":"TEXT",
"description":"Command which should be sent to updateItem",
"required":true
}
],
"triggers":[
{
"id":"ItemUpdateTrigger_1",
"type":"core.GenericEventTrigger",
"configuration":{
"eventSource":"${onItem}",
"eventTopic":"smarthome/items/*",
"eventTypes":"ItemStateEvent"
}
}
],
"actions":[
{
"id":"ItemPostCommandActionID_1",
"type":"core.ItemCommandAction",
"configuration":{
"itemName":"${updateItem}",
"command":"${updateCommand}"
}
}
]
}
]
@@ -0,0 +1,62 @@
[
{
"name": "TemplateSampleRuleWithReferences",
"uid": "TemplateSampleRuleWithReferences",
"tags": [
"sample",
"item",
"jsonTest",
"rule",
"references"
],
"configDescriptions": [
{
"name":"triggerItem",
"type":"TEXT",
"description":"ItemName which state change triggers the rule",
"required":true
},
{
"name":"actionItem",
"type":"TEXT",
"description":"ItemName on which action will be performed.",
"required":true
}
],
"description": "Sample Rule for items definition.",
"triggers": [
{
"id": "ItemStateChangeTriggerID",
"type": "core.GenericEventTrigger",
"configuration":{
"eventSource":"${triggerItem}",
"eventTopic":"smarthome/items/*",
"eventTypes":"ItemStateEvent"
}
}
],
"conditions": [
{
"id": "ItemStateConditionID",
"type": "core.GenericEventCondition",
"configuration": {
"topic": "smarthome/items/${triggerItem}/state",
"payload":".*ON.*"
},
"inputs":{
"event":"ItemStateChangeTriggerID.event"
}
}
],
"actions": [
{
"id": "ItemPostCommandActionID",
"type": "core.ItemCommandAction",
"configuration": {
"itemName": "${actionItem}",
"command": "ON"
}
}
]
}
]
@@ -0,0 +1,57 @@
[
{
"uid":"TestTemplateWithCompositeModules",
"description":"Sample Rule Template.",
"tags":[
"sample",
"rule",
"template",
"composite"
],
"configDescriptions":[
{
"name":"onItem",
"type":"TEXT",
"description":"ItemName which state change triggers the rule",
"required":true
},
{
"name":"ifState",
"type":"TEXT",
"description":"Right operand which is compared with the input.",
"required":true
},
{
"name":"updateItem",
"type":"TEXT",
"description":"Item which should be updated",
"required":true
},
{
"name":"updateCommand",
"type":"TEXT",
"description":"Command which should be sent to updateItem",
"required":true
}
],
"triggers":[
{
"id":"ItemUpdateTrigger_2",
"type":"core.ItemStateChangeTrigger",
"configuration":{
"itemName":"${onItem}"
}
}
],
"actions":[
{
"id":"ItemPostCommandActionID_1",
"type":"core.ItemCommandAction",
"configuration":{
"itemName":"${updateItem}",
"command":"${updateCommand}"
}
}
]
}
]
@@ -0,0 +1,389 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.automation.integration.test;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.automation.Action;
import org.eclipse.smarthome.automation.Rule;
import org.eclipse.smarthome.automation.RuleManager;
import org.eclipse.smarthome.automation.RulePredicates;
import org.eclipse.smarthome.automation.RuleRegistry;
import org.eclipse.smarthome.automation.RuleStatus;
import org.eclipse.smarthome.automation.RuleStatusInfo;
import org.eclipse.smarthome.automation.Trigger;
import org.eclipse.smarthome.automation.core.ManagedRuleProvider;
import org.eclipse.smarthome.automation.events.RuleStatusInfoEvent;
import org.eclipse.smarthome.automation.type.ActionType;
import org.eclipse.smarthome.automation.type.Input;
import org.eclipse.smarthome.automation.type.ModuleTypeRegistry;
import org.eclipse.smarthome.automation.type.Output;
import org.eclipse.smarthome.automation.type.TriggerType;
import org.eclipse.smarthome.core.common.registry.ProviderChangeListener;
import org.eclipse.smarthome.core.events.Event;
import org.eclipse.smarthome.core.events.EventFilter;
import org.eclipse.smarthome.core.events.EventPublisher;
import org.eclipse.smarthome.core.events.EventSubscriber;
import org.eclipse.smarthome.core.items.Item;
import org.eclipse.smarthome.core.items.ItemNotFoundException;
import org.eclipse.smarthome.core.items.ItemProvider;
import org.eclipse.smarthome.core.items.ItemRegistry;
import org.eclipse.smarthome.core.items.events.ItemCommandEvent;
import org.eclipse.smarthome.core.items.events.ItemEventFactory;
import org.eclipse.smarthome.core.library.items.SwitchItem;
import org.eclipse.smarthome.core.library.types.OnOffType;
import org.eclipse.smarthome.core.storage.StorageService;
import org.eclipse.smarthome.core.types.UnDefType;
import org.eclipse.smarthome.test.java.JavaOSGiTest;
import org.eclipse.smarthome.test.storage.VolatileStorageService;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This tests the RuleEngineImpl and the import from JSON resources contained in the ESH-INF folder.
* This test must be run first otherwise imported rules will be cleared.
*
* @author Benedikt Niehues - initial contribution
* @author Marin Mitev - make the test to pass on each run
* @author Kai Kreuzer - refactored to Java
*
*/
public class AutomationIntegrationJsonTest extends JavaOSGiTest {
final Logger logger = LoggerFactory.getLogger(AutomationIntegrationJsonTest.class);
private EventPublisher eventPublisher;
private ItemRegistry itemRegistry;
private RuleRegistry ruleRegistry;
private RuleManager ruleManager;
private ManagedRuleProvider managedRuleProvider;
private ModuleTypeRegistry moduleTypeRegistry;
private Event ruleEvent;
public Event itemEvent;
public static VolatileStorageService VOLATILE_STORAGE_SERVICE = new VolatileStorageService(); // keep storage with
// rules imported from
// json files
@Before
public void before() {
logger.info("@Before.begin");
getService(ItemRegistry.class);
ItemProvider itemProvider = new ItemProvider() {
@Override
public void addProviderChangeListener(@NonNull ProviderChangeListener<@NonNull Item> listener) {
}
@Override
public @NonNull Collection<@NonNull Item> getAll() {
HashSet<Item> items = new HashSet<>();
items.add(new SwitchItem("myMotionItem"));
items.add(new SwitchItem("myPresenceItem"));
items.add(new SwitchItem("myLampItem"));
items.add(new SwitchItem("myMotionItem2"));
items.add(new SwitchItem("myPresenceItem2"));
items.add(new SwitchItem("myLampItem2"));
items.add(new SwitchItem("myMotionItem11"));
items.add(new SwitchItem("myLampItem11"));
items.add(new SwitchItem("myMotionItem3"));
items.add(new SwitchItem("templ_MotionItem"));
items.add(new SwitchItem("templ_LampItem"));
return items;
}
@Override
public void removeProviderChangeListener(@NonNull ProviderChangeListener<@NonNull Item> listener) {
}
};
registerService(itemProvider);
registerVolatileStorageService();
EventSubscriber ruleEventHandler = new EventSubscriber() {
@Override
public @NonNull Set<@NonNull String> getSubscribedEventTypes() {
return Collections.singleton(RuleStatusInfoEvent.TYPE);
}
@Override
public @Nullable EventFilter getEventFilter() {
return null;
}
@Override
public void receive(@NonNull Event e) {
logger.info("RuleEvent: " + e.getTopic() + " --> " + e.getPayload());
System.out.println("RuleEvent: " + e.getTopic() + " --> " + e.getPayload());
if (e.getPayload().contains("RUNNING")) {
ruleEvent = e;
}
}
};
registerService(ruleEventHandler);
StorageService storageService = getService(StorageService.class);
managedRuleProvider = getService(ManagedRuleProvider.class);
eventPublisher = getService(EventPublisher.class);
itemRegistry = getService(ItemRegistry.class);
ruleRegistry = getService(RuleRegistry.class);
ruleManager = getService(RuleManager.class);
moduleTypeRegistry = getService(ModuleTypeRegistry.class);
waitForAssert(() -> {
assertThat(storageService, is(notNullValue()));
// sometimes assert fails because EventPublisher service is null
assertThat(eventPublisher, is(notNullValue()));
assertThat(itemRegistry, is(notNullValue()));
assertThat(ruleRegistry, is(notNullValue()));
assertThat(ruleManager, is(notNullValue()));
assertThat(managedRuleProvider, is(notNullValue()));
assertThat(moduleTypeRegistry, is(notNullValue()));
}, 9000, 1000);
logger.info("@Before.finish");
}
@After
public void after() {
logger.info("@After");
}
@Override
protected void registerVolatileStorageService() {
registerService(VOLATILE_STORAGE_SERVICE);
}
@Test
public void assertThatModuleTypeInputsAndOutputsFromJsonFileAreParsedCorrectly() {
logger.info("assert that module type inputs and outputs from json file are parsed correctly");
// WAIT until module type resources are parsed
waitForAssert(() -> {
assertThat(moduleTypeRegistry.getTriggers().isEmpty(), is(false));
assertThat(moduleTypeRegistry.getActions().isEmpty(), is(false));
TriggerType moduleType1 = (TriggerType) moduleTypeRegistry.get("CustomTrigger1");
TriggerType moduleType2 = (TriggerType) moduleTypeRegistry.get("CustomTrigger2");
ActionType moduleType3 = (ActionType) moduleTypeRegistry.get("CustomAction1");
ActionType moduleType4 = (ActionType) moduleTypeRegistry.get("CustomAction2");
assertThat(moduleType1.getOutputs(), is(notNullValue()));
Optional<Output> output1 = moduleType1.getOutputs().stream()
.filter(o -> o.getName().equals("customTriggerOutput1")).findFirst();
assertThat(output1.isPresent(), is(true));
assertThat(output1.get().getDefaultValue(), is("true"));
assertThat(moduleType2.getOutputs(), is(notNullValue()));
Optional<Output> output2 = moduleType2.getOutputs().stream()
.filter(o -> o.getName().equals("customTriggerOutput2")).findFirst();
assertThat(output2.isPresent(), is(true));
assertThat(output2.get().getDefaultValue(), is("event"));
assertThat(moduleType4.getInputs(), is(notNullValue()));
Optional<Input> input = moduleType4.getInputs().stream()
.filter(o -> o.getName().equals("customActionInput")).findFirst();
assertThat(input.isPresent(), is(true));
assertThat(input.get().getDefaultValue(), is("5"));
assertThat(moduleType3.getOutputs(), is(notNullValue()));
Optional<Output> output3 = moduleType3.getOutputs().stream()
.filter(o -> o.getName().equals("customActionOutput3")).findFirst();
assertThat(output3.isPresent(), is(true));
assertThat(output3.get().getDefaultValue(), is("{\"command\":\"OFF\"}"));
}, 10000, 200);
}
@Test
public void assertThatARuleFromJsonFileIsAddedAutomatically() {
logger.info("assert that a rule from json file is added automatically");
// WAIT until Rule modules types are parsed and the rule becomes IDLE
waitForAssert(() -> {
assertThat(ruleRegistry.getAll().isEmpty(), is(false));
Rule rule2 = ruleRegistry.stream().filter(
RulePredicates.hasAnyOfTags("jsonTest").and(RulePredicates.hasAnyOfTags("references").negate()))
.findFirst().orElse(null);
assertThat(rule2, is(notNullValue()));
RuleStatusInfo ruleStatus2 = ruleManager.getStatusInfo(rule2.getUID());
assertThat(ruleStatus2.getStatus(), is(RuleStatus.IDLE));
}, 10000, 200);
Rule rule = ruleRegistry.stream()
.filter(RulePredicates.hasAnyOfTags("jsonTest").and(RulePredicates.hasAnyOfTags("references").negate()))
.findFirst().orElse(null);
assertThat(rule, is(notNullValue()));
assertThat(rule.getName(), is("ItemSampleRule"));
assertTrue(rule.getTags().contains("sample"));
assertTrue(rule.getTags().contains("item"));
assertTrue(rule.getTags().contains("rule"));
Optional<? extends Trigger> trigger = rule.getTriggers().stream()
.filter(t -> t.getId().equals("ItemStateChangeTriggerID")).findFirst();
assertThat(trigger.isPresent(), is(true));
assertThat(trigger.get().getTypeUID(), is("core.GenericEventTrigger"));
assertThat(trigger.get().getConfiguration().get("eventSource"), is("myMotionItem"));
assertThat(trigger.get().getConfiguration().get("eventTopic"), is("smarthome/items/*"));
assertThat(trigger.get().getConfiguration().get("eventTypes"), is("ItemStateEvent"));
// def condition1 = rule.conditions.find{it.id.equals("ItemStateConditionID")} as Condition
// assertThat(condition1, is(notNullValue())
// assertThat(condition1.typeUID, is("core.GenericEventCondition")
// assertThat(condition1.configuration.get("topic"), is("smarthome/items/myMotionItem/state")
// assertThat(condition1.configuration.get("payload"), is(".*ON.*")
Optional<? extends Action> action = rule.getActions().stream()
.filter(a -> a.getId().equals("ItemPostCommandActionID")).findFirst();
assertThat(action.isPresent(), is(true));
assertThat(action.get().getTypeUID(), is("core.ItemCommandAction"));
assertThat(action.get().getConfiguration().get("itemName"), is("myLampItem"));
assertThat(action.get().getConfiguration().get("command"), is("ON"));
RuleStatusInfo ruleStatus = ruleManager.getStatusInfo(rule.getUID());
assertThat(ruleStatus.getStatus(), is(RuleStatus.IDLE));
}
@Test
public void assertThatARuleFromJsonFileIsAddedAutomaticallyAndTheRuntimeRuleHasResolvedModuleReferences() {
logger.info(
"assert that a rule from json file is added automatically and the runtime rule has resolved module references");
// WAIT until Rule modules types are parsed and the rule becomes IDLE
waitForAssert(() -> {
assertThat(ruleRegistry.getAll().isEmpty(), is(false));
Rule rule2 = ruleRegistry.stream().filter(RulePredicates.hasAllTags("jsonTest", "references")).findFirst()
.orElse(null);
assertThat(rule2, is(notNullValue()));
RuleStatusInfo ruleStatus2 = ruleManager.getStatusInfo(rule2.getUID());
assertThat(ruleStatus2.getStatus(), is(RuleStatus.IDLE));
}, 10000, 200);
Rule rule = ruleRegistry.stream().filter(RulePredicates.hasAllTags("jsonTest", "references")).findFirst()
.orElse(null);
assertThat(rule, is(notNullValue()));
assertThat(rule.getName(), is("ItemSampleRuleWithReferences"));
assertTrue(rule.getTags().contains("sample"));
assertTrue(rule.getTags().contains("item"));
assertTrue(rule.getTags().contains("rule"));
assertTrue(rule.getTags().contains("references"));
Optional<? extends Trigger> trigger = rule.getTriggers().stream()
.filter(t -> t.getId().equals("ItemStateChangeTriggerID")).findFirst();
assertThat(trigger.isPresent(), is(true));
assertThat(trigger.get().getTypeUID(), is("core.GenericEventTrigger"));
assertThat(trigger.get().getConfiguration().get("eventTopic"), is("smarthome/items/*"));
assertThat(trigger.get().getConfiguration().get("eventTypes"), is("ItemStateEvent"));
// def condition1 = rule.conditions.find{it.id.equals("ItemStateConditionID")} as Condition
// assertThat(condition1, is(notNullValue())
// assertThat(condition1.typeUID, is("core.GenericEventCondition")
// assertThat(condition1.configuration.get("topic"), is("smarthome/items/myMotionItem/state")
// assertThat(condition1.configuration.get("payload"), is(".*ON.*")
Optional<? extends Action> action = rule.getActions().stream()
.filter(a -> a.getId().equals("ItemPostCommandActionID")).findFirst();
assertThat(action.isPresent(), is(true));
assertThat(action.get().getTypeUID(), is("core.ItemCommandAction"));
assertThat(action.get().getConfiguration().get("command"), is("ON"));
RuleStatusInfo ruleStatus = ruleManager.getStatusInfo(rule.getUID());
assertThat(ruleStatus.getStatus(), is(RuleStatus.IDLE));
// run the rule to check if the runtime rule has resolved module references and is executed successfully
EventPublisher eventPublisher = getService(EventPublisher.class);
EventSubscriber itemEventHandler = new EventSubscriber() {
@Override
public @NonNull Set<@NonNull String> getSubscribedEventTypes() {
return Collections.singleton(ItemCommandEvent.TYPE);
}
@Override
public @Nullable EventFilter getEventFilter() {
return null;
}
@Override
public void receive(@NonNull Event e) {
logger.info("Event: {}", e.getTopic());
if (e.getTopic().contains("myLampItem")) {
itemEvent = e;
}
}
};
registerService(itemEventHandler);
eventPublisher.post(ItemEventFactory.createStateEvent("myMotionItem", OnOffType.ON));
waitForAssert(() -> {
assertThat(itemEvent, is(notNullValue()));
}, 3000, 100);
assertThat(itemEvent.getTopic(), is(equalTo("smarthome/items/myLampItem/command")));
assertThat(((ItemCommandEvent) itemEvent).getItemCommand(), is(OnOffType.ON));
}
@Test
public void assertThatARuleFromJsonFileIsExecutedCorrectly() throws ItemNotFoundException {
logger.info("assert that rule added by json is executed correctly");
waitForAssert(() -> {
assertThat(ruleRegistry.getAll().isEmpty(), is(false));
Rule r = ruleRegistry.get("ItemSampleRule");
assertThat(r, is(notNullValue()));
assertThat(ruleManager.getStatusInfo(r.getUID()).getStatus(), is(RuleStatus.IDLE));
}, 9000, 200);
SwitchItem myPresenceItem = (SwitchItem) itemRegistry.getItem("myPresenceItem");
myPresenceItem.setState(OnOffType.ON);
SwitchItem myLampItem = (SwitchItem) itemRegistry.getItem("myLampItem");
assertThat(myLampItem.getState(), is(UnDefType.NULL));
SwitchItem myMotionItem = (SwitchItem) itemRegistry.getItem("myMotionItem");
EventSubscriber eventHandler = new EventSubscriber() {
@Override
public @NonNull Set<@NonNull String> getSubscribedEventTypes() {
return Collections.singleton(ItemCommandEvent.TYPE);
}
@Override
public @Nullable EventFilter getEventFilter() {
return null;
}
@Override
public void receive(@NonNull Event e) {
logger.info("Event: {}", e.getTopic());
if (e.getTopic().equals("smarthome/items/myLampItem/command")) {
itemEvent = e;
}
}
};
registerService(eventHandler);
eventPublisher.post(ItemEventFactory.createStateEvent("myMotionItem", OnOffType.ON));
waitForAssert(() -> {
assertThat(itemEvent, is(notNullValue()));
assertThat(((ItemCommandEvent) itemEvent).getItemCommand(), is(OnOffType.ON));
});
}
}
@@ -0,0 +1,405 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.automation.integration.test;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.Locale;
import org.eclipse.smarthome.automation.type.ModuleTypeRegistry;
import org.eclipse.smarthome.core.storage.StorageService;
import org.eclipse.smarthome.test.java.JavaOSGiTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
import org.osgi.framework.FrameworkEvent;
import org.osgi.framework.FrameworkListener;
import org.osgi.service.packageadmin.PackageAdmin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This test class tests the Host - Fragment support for automation and localization resources
*
* @author Ana Dimova - initial contribution
* @author Kai Kreuzer - Refactored to Java
*/
@SuppressWarnings("deprecation")
public class HostFragmentSupportTest extends JavaOSGiTest {
final Logger logger = LoggerFactory.getLogger(HostFragmentSupportTest.class);
private ModuleTypeRegistry moduleTypeRegistry;
private PackageAdmin pkgAdmin;
private final String EXT = ".jar";
private final String PATH = "src/test/resources/";
private final String RESOURCES_TEST_BUNDLE_1 = "host-tb1";
private final String RESOURCES_TEST_BUNDLE_2 = "host-tb2";
private final String RESOURCES_TEST_BUNDLE_3 = "fragment-tb1";
private final String RESOURCES_TEST_BUNDLE_4 = "fragment-tb2";
private final String trigger1 = "Trigger1";
private final String trigger2 = "Trigger2";
private final String condition1 = "Condition1";
private final String condition2 = "Condition2";
private final String action1 = "Action1";
private final String trigger1LabelBG = "Тригер 1 Етикет";
private final String trigger1LabelDE = "Abzugshahn 1 Etikette";
private final String trigger1LabelUpdatedBG = "Тригер 1 Обновен Етикет";
private final String trigger1LabelUpdatedDE = "Abzugshahn 1 Aktualisiert Etikette";
private final String trigger2LabelBG = "Тригер 2 Етикет";
private final String trigger2LabelDE = "Abzugshahn 2 Etikette";
private final String trigger2LabelUpdatedBG = "Тригер 2 Обновен Етикет";
private final String trigger2LabelUpdatedDE = "Abzugshahn 2 Aktualisiert Etikette";
private final String condition1LabelBG = "Условие 1 Етикет";
private final String condition1LabelDE = "Bedingung 1 Etikette";
private final String condition1LabelUpdatedBG = "Условие 1 Обновен Етикет‚";
private final String condition1LabelUpdatedDE = "Bedingung 1 Aktualisiert Etikette";
private final String condition2LabelBG = "Условие 2 Етикет";
private final String condition2LabelDE = "Bedingung 2 Etikette";
private final String condition2LabelUpdatedBG = "Условие 2 Обновен Етикет";
private final String condition2LabelUpdatedDE = "Bedingung 2 Aktualisiert Etikette";
private final String action1LabelBG = "Действие 1 Етикет";
private final String action1LabelDE = "Aktion 1 Etikette";
private final String action1LabelUpdatedBG = "Действие 1 Обновен Етикет‚";
private final String action1LabelUpdatedDE = "Aktion 1 Aktualisiert Etikette";
boolean waiting = true;
@Before
public void before() {
logger.info("@Before.begin");
Locale.setDefault(Locale.ENGLISH);
registerVolatileStorageService();
StorageService storageService = getService(StorageService.class);
moduleTypeRegistry = getService(ModuleTypeRegistry.class);
pkgAdmin = getService(PackageAdmin.class);
waitForAssert(() -> {
assertThat(storageService, is(notNullValue()));
assertThat(moduleTypeRegistry, is(notNullValue()));
assertThat(pkgAdmin, is(notNullValue()));
}, 9000, 1000);
logger.info("@Before.finish");
}
@After
public void after() {
logger.info("@After");
}
@Override
protected void registerVolatileStorageService() {
registerService(AutomationIntegrationJsonTest.VOLATILE_STORAGE_SERVICE);
}
@Test
public void assertThatTheInstallationOfTheFragmentHostProvidesTheResourcesCorrectly() throws BundleException {
logger.info("asserting that the installation of the fragment-host provides the resources correctly");
FrameworkListener listener = new FrameworkListener() {
@Override
public void frameworkEvent(FrameworkEvent event) {
waiting = false;
}
};
// first install the fragment
Bundle fragment = bundleContext.installBundle(RESOURCES_TEST_BUNDLE_3,
getClass().getClassLoader().getResourceAsStream(PATH + RESOURCES_TEST_BUNDLE_3 + EXT));
assertThat(fragment, is(notNullValue()));
// assert that the host and fragment resources are not loaded
waitForAssert(() -> {
assertThat(fragment.getState(), is(Bundle.INSTALLED));
assertThat(moduleTypeRegistry.get(trigger2), is(nullValue()));
assertThat(moduleTypeRegistry.get(condition2), is(nullValue()));
}, 3000, 200);
// then install the host
Bundle host = bundleContext.installBundle(RESOURCES_TEST_BUNDLE_1,
getClass().getClassLoader().getResourceAsStream(PATH + RESOURCES_TEST_BUNDLE_1 + EXT));
assertThat(host, is(notNullValue()));
host.start();
// assert that the host and fragment resources are loaded
waitForAssert(() -> {
assertThat(host.getState(), is(Bundle.ACTIVE));
assertThat(fragment.getState(), is(Bundle.RESOLVED));
assertThat(moduleTypeRegistry.get(trigger1), is(notNullValue()));
assertThat(moduleTypeRegistry.get(trigger1, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(trigger1).getLabel()));
assertThat(moduleTypeRegistry.get(trigger1, new Locale("bg")).getLabel(), is(trigger1LabelBG));
assertThat(moduleTypeRegistry.get(trigger1, Locale.GERMANY).getLabel(), is(trigger1LabelDE));
assertThat(moduleTypeRegistry.get(condition1), is(notNullValue()));
assertThat(moduleTypeRegistry.get(condition1, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(condition1).getLabel()));
assertThat(moduleTypeRegistry.get(condition1, new Locale("bg")).getLabel(), is(condition1LabelBG));
assertThat(moduleTypeRegistry.get(condition1, Locale.GERMANY).getLabel(), is(condition1LabelDE));
assertThat(moduleTypeRegistry.get(action1), is(notNullValue()));
assertThat(moduleTypeRegistry.get(action1, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(action1).getLabel()));
assertThat(moduleTypeRegistry.get(action1, new Locale("bg")).getLabel(), is(action1LabelBG));
assertThat(moduleTypeRegistry.get(action1, Locale.GERMANY).getLabel(), is(action1LabelDE));
assertThat(moduleTypeRegistry.get(trigger2), is(notNullValue()));
assertThat(moduleTypeRegistry.get(trigger2, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(trigger2).getLabel()));
assertThat(moduleTypeRegistry.get(trigger2, new Locale("bg")).getLabel(), is(trigger2LabelBG));
assertThat(moduleTypeRegistry.get(trigger2, Locale.GERMANY).getLabel(), is(trigger2LabelDE));
assertThat(moduleTypeRegistry.get(condition2), is(notNullValue()));
assertThat(moduleTypeRegistry.get(condition2, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(condition2).getLabel()));
assertThat(moduleTypeRegistry.get(condition2, new Locale("bg")).getLabel(), is(condition2LabelBG));
assertThat(moduleTypeRegistry.get(condition2, Locale.GERMANY).getLabel(), is(condition2LabelDE));
}, 10000, 200);
// first uninstall the fragment
fragment.uninstall();
assertThat(fragment.getState(), is(Bundle.UNINSTALLED));
;
waiting = true;
bundleContext.addFrameworkListener(listener);
Bundle[] bundles = new Bundle[] { host, fragment };
pkgAdmin.refreshPackages(bundles);
waitForAssert(() -> assertFalse(waiting), 3000, 100);
bundleContext.removeFrameworkListener(listener);
waitForAssert(() -> {
// assert that the host is updated and only its resources are available
assertThat(moduleTypeRegistry.get(trigger1), is(notNullValue()));
assertThat(moduleTypeRegistry.get(trigger1, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(trigger1).getLabel()));
assertThat(moduleTypeRegistry.get(trigger1, new Locale("bg")).getLabel(), is(trigger1LabelBG));
assertThat(moduleTypeRegistry.get(trigger1, Locale.GERMANY).getLabel(), is(trigger1LabelDE));
assertThat(moduleTypeRegistry.get(condition1), is(notNullValue()));
assertThat(moduleTypeRegistry.get(condition1, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(condition1).getLabel()));
assertThat(moduleTypeRegistry.get(condition1, new Locale("bg")).getLabel(), is(condition1LabelBG));
assertThat(moduleTypeRegistry.get(condition1, Locale.GERMANY).getLabel(), is(condition1LabelDE));
assertThat(moduleTypeRegistry.get(action1), is(notNullValue()));
assertThat(moduleTypeRegistry.get(action1, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(action1).getLabel()));
assertThat(moduleTypeRegistry.get(action1, new Locale("bg")).getLabel(), is(action1LabelBG));
assertThat(moduleTypeRegistry.get(action1, Locale.GERMANY).getLabel(), is(action1LabelDE));
assertThat(moduleTypeRegistry.get(trigger2), is(nullValue()));
assertThat(moduleTypeRegistry.get(condition2), is(nullValue()));
}, 3000, 200);
// then uninstall the host
host.uninstall();
// assert that the host resources also are removed
waitForAssert(() -> {
assertThat(host.getState(), is(Bundle.UNINSTALLED));
assertThat(moduleTypeRegistry.get(trigger1), is(nullValue()));
assertThat(moduleTypeRegistry.get(condition1), is(nullValue()));
assertThat(moduleTypeRegistry.get(action1), is(nullValue()));
}, 3000, 200);
}
@Test
public void assertThatTheUpdateOfTheFragmentHostProvidesTheResourcesCorrectly() throws BundleException {
logger.info("asserting that the update of the fragment-host provides the resources correctly");
waiting = true;
FrameworkListener listener = new FrameworkListener() {
@Override
public void frameworkEvent(FrameworkEvent event) {
waiting = false;
}
};
// first install the fragment
Bundle fragment = bundleContext.installBundle(RESOURCES_TEST_BUNDLE_3,
getClass().getClassLoader().getResourceAsStream(PATH + RESOURCES_TEST_BUNDLE_3 + EXT));
assertThat(fragment, is(notNullValue()));
// assert that the host and fragment resources are not loaded
waitForAssert(() -> {
assertThat(fragment.getState(), is(Bundle.INSTALLED));
assertThat(moduleTypeRegistry.get(trigger2), is(nullValue()));
assertThat(moduleTypeRegistry.get(condition2), is(nullValue()));
}, 3000, 200);
// then install the host
Bundle host = bundleContext.installBundle(RESOURCES_TEST_BUNDLE_1,
getClass().getClassLoader().getResourceAsStream(PATH + RESOURCES_TEST_BUNDLE_1 + EXT));
assertThat(host, is(notNullValue()));
host.start();
// assert that the host and fragment resources are loaded
waitForAssert(() -> {
assertThat(host.getState(), is(Bundle.ACTIVE));
assertThat(fragment.getState(), is(Bundle.RESOLVED));
assertThat(moduleTypeRegistry.get(trigger1), is(notNullValue()));
assertThat(moduleTypeRegistry.get(trigger1, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(trigger1).getLabel()));
assertThat(moduleTypeRegistry.get(trigger1, new Locale("bg")).getLabel(), is(trigger1LabelBG));
assertThat(moduleTypeRegistry.get(trigger1, Locale.GERMANY).getLabel(), is(trigger1LabelDE));
assertThat(moduleTypeRegistry.get(condition1), is(notNullValue()));
assertThat(moduleTypeRegistry.get(condition1, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(condition1).getLabel()));
assertThat(moduleTypeRegistry.get(condition1, new Locale("bg")).getLabel(), is(condition1LabelBG));
assertThat(moduleTypeRegistry.get(condition1, Locale.GERMANY).getLabel(), is(condition1LabelDE));
assertThat(moduleTypeRegistry.get(action1), is(notNullValue()));
assertThat(moduleTypeRegistry.get(action1, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(action1).getLabel()));
assertThat(moduleTypeRegistry.get(action1, new Locale("bg")).getLabel(), is(action1LabelBG));
assertThat(moduleTypeRegistry.get(action1, Locale.GERMANY).getLabel(), is(action1LabelDE));
assertThat(moduleTypeRegistry.get(trigger2), is(notNullValue()));
assertThat(moduleTypeRegistry.get(trigger2, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(trigger2).getLabel()));
assertThat(moduleTypeRegistry.get(trigger2, new Locale("bg")).getLabel(), is(trigger2LabelBG));
assertThat(moduleTypeRegistry.get(trigger2, Locale.GERMANY).getLabel(), is(trigger2LabelDE));
assertThat(moduleTypeRegistry.get(condition2), is(notNullValue()));
assertThat(moduleTypeRegistry.get(condition2, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(condition2).getLabel()));
assertThat(moduleTypeRegistry.get(condition2, new Locale("bg")).getLabel(), is(condition2LabelBG));
assertThat(moduleTypeRegistry.get(condition2, Locale.GERMANY).getLabel(), is(condition2LabelDE));
}, 3000, 200);
// first update the fragment
fragment.update(getClass().getClassLoader().getResourceAsStream(PATH + RESOURCES_TEST_BUNDLE_4 + EXT));
waiting = true;
bundleContext.addFrameworkListener(listener);
Bundle[] bundles = new Bundle[] { host, fragment };
pkgAdmin.refreshPackages(bundles);
waitForAssert(() -> assertFalse(waiting), 3000, 100);
bundleContext.removeFrameworkListener(listener);
waitForAssert(() -> {
assertThat(host.getState(), is(Bundle.ACTIVE));
assertThat(fragment.getState(), is(Bundle.RESOLVED));
assertThat(moduleTypeRegistry.get(trigger1), is(notNullValue()));
assertThat(moduleTypeRegistry.get(trigger1, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(trigger1).getLabel()));
assertThat(moduleTypeRegistry.get(trigger1, new Locale("bg")).getLabel(), is(trigger1LabelBG));
assertThat(moduleTypeRegistry.get(trigger1, Locale.GERMANY).getLabel(), is(trigger1LabelDE));
assertThat(moduleTypeRegistry.get(condition1), is(notNullValue()));
assertThat(moduleTypeRegistry.get(condition1, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(condition1).getLabel()));
assertThat(moduleTypeRegistry.get(condition1, new Locale("bg")).getLabel(), is(condition1LabelBG));
assertThat(moduleTypeRegistry.get(condition1, Locale.GERMANY).getLabel(), is(condition1LabelDE));
assertThat(moduleTypeRegistry.get(action1), is(notNullValue()));
assertThat(moduleTypeRegistry.get(action1, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(action1).getLabel()));
assertThat(moduleTypeRegistry.get(action1, new Locale("bg")).getLabel(), is(action1LabelBG));
assertThat(moduleTypeRegistry.get(action1, Locale.GERMANY).getLabel(), is(action1LabelDE));
assertThat(moduleTypeRegistry.get(trigger2), is(notNullValue()));
assertThat(moduleTypeRegistry.get(trigger2, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(trigger2).getLabel()));
assertThat(moduleTypeRegistry.get(trigger2, new Locale("bg")).getLabel(), is(trigger2LabelUpdatedBG));
assertThat(moduleTypeRegistry.get(trigger2, Locale.GERMANY).getLabel(), is(trigger2LabelUpdatedDE));
assertThat(moduleTypeRegistry.get(condition2), is(notNullValue()));
assertThat(moduleTypeRegistry.get(condition2, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(condition2).getLabel()));
assertThat(moduleTypeRegistry.get(condition2, new Locale("bg")).getLabel(), is(condition2LabelUpdatedBG));
assertThat(moduleTypeRegistry.get(condition2, Locale.GERMANY).getLabel(), is(condition2LabelUpdatedDE));
}, 3000, 200);
// then update the host
host.update(getClass().getClassLoader().getResourceAsStream(PATH + RESOURCES_TEST_BUNDLE_2 + EXT));
waiting = true;
bundleContext.addFrameworkListener(listener);
pkgAdmin.refreshPackages(bundles);
waitForAssert(() -> assertFalse(waiting), 3000, 100);
bundleContext.removeFrameworkListener(listener);
waitForAssert(() -> {
assertThat(host.getState(), is(Bundle.ACTIVE));
assertThat(fragment.getState(), is(Bundle.RESOLVED));
assertThat(moduleTypeRegistry.get(trigger1), is(notNullValue()));
assertThat(moduleTypeRegistry.get(trigger1, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(trigger1).getLabel()));
assertThat(moduleTypeRegistry.get(trigger1, new Locale("bg")).getLabel(), is(trigger1LabelUpdatedBG));
assertThat(moduleTypeRegistry.get(trigger1, Locale.GERMANY).getLabel(), is(trigger1LabelUpdatedDE));
assertThat(moduleTypeRegistry.get(condition1), is(notNullValue()));
assertThat(moduleTypeRegistry.get(condition1, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(condition1).getLabel()));
assertThat(moduleTypeRegistry.get(condition1, new Locale("bg")).getLabel(), is(condition1LabelUpdatedBG));
assertThat(moduleTypeRegistry.get(condition1, Locale.GERMANY).getLabel(), is(condition1LabelUpdatedDE));
assertThat(moduleTypeRegistry.get(action1), is(notNullValue()));
assertThat(moduleTypeRegistry.get(action1, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(action1).getLabel()));
assertThat(moduleTypeRegistry.get(action1, new Locale("bg")).getLabel(), is(action1LabelUpdatedBG));
assertThat(moduleTypeRegistry.get(action1, Locale.GERMANY).getLabel(), is(action1LabelUpdatedDE));
assertThat(moduleTypeRegistry.get(trigger2), is(notNullValue()));
assertThat(moduleTypeRegistry.get(trigger2, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(trigger2).getLabel()));
assertThat(moduleTypeRegistry.get(trigger2, new Locale("bg")).getLabel(), is(trigger2LabelUpdatedBG));
assertThat(moduleTypeRegistry.get(trigger2, Locale.GERMANY).getLabel(), is(trigger2LabelUpdatedDE));
assertThat(moduleTypeRegistry.get(condition2), is(notNullValue()));
assertThat(moduleTypeRegistry.get(condition2, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(condition2).getLabel()));
assertThat(moduleTypeRegistry.get(condition2, new Locale("bg")).getLabel(), is(condition2LabelUpdatedBG));
assertThat(moduleTypeRegistry.get(condition2, Locale.GERMANY).getLabel(), is(condition2LabelUpdatedDE));
}, 3000, 200);
// first uninstall the fragment
fragment.uninstall();
assertThat(fragment.getState(), is(Bundle.UNINSTALLED));
waiting = true;
bundleContext.addFrameworkListener(listener);
pkgAdmin.refreshPackages(bundles);
waitForAssert(() -> assertFalse(waiting), 3000, 100);
bundleContext.removeFrameworkListener(listener);
// assert that the host is updated and only its resources are available
waitForAssert(() -> {
assertThat(moduleTypeRegistry.get(trigger1), is(notNullValue()));
assertThat(moduleTypeRegistry.get(trigger1, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(trigger1).getLabel()));
assertThat(moduleTypeRegistry.get(trigger1, new Locale("bg")).getLabel(), is(trigger1LabelUpdatedBG));
assertThat(moduleTypeRegistry.get(trigger1, Locale.GERMANY).getLabel(), is(trigger1LabelUpdatedDE));
assertThat(moduleTypeRegistry.get(condition1), is(notNullValue()));
assertThat(moduleTypeRegistry.get(condition1, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(condition1).getLabel()));
assertThat(moduleTypeRegistry.get(condition1, new Locale("bg")).getLabel(), is(condition1LabelUpdatedBG));
assertThat(moduleTypeRegistry.get(condition1, Locale.GERMANY).getLabel(), is(condition1LabelUpdatedDE));
assertThat(moduleTypeRegistry.get(action1), is(notNullValue()));
assertThat(moduleTypeRegistry.get(action1, Locale.getDefault()).getLabel(),
is(moduleTypeRegistry.get(action1).getLabel()));
assertThat(moduleTypeRegistry.get(action1, new Locale("bg")).getLabel(), is(action1LabelUpdatedBG));
assertThat(moduleTypeRegistry.get(action1, Locale.GERMANY).getLabel(), is(action1LabelUpdatedDE));
assertThat(moduleTypeRegistry.get(trigger2), is(nullValue()));
assertThat(moduleTypeRegistry.get(condition2), is(nullValue()));
}, 3000, 200);
// then uninstall the host
host.uninstall();
assertThat(host.getState(), is(Bundle.UNINSTALLED));
// assert that the host resources also are removed
waitForAssert(() -> {
assertThat(moduleTypeRegistry.get(trigger1), is(nullValue()));
assertThat(moduleTypeRegistry.get(condition1), is(nullValue()));
assertThat(moduleTypeRegistry.get(action1), is(nullValue()));
}, 3000, 200);
}
}
@@ -0,0 +1 @@
/test-classes/
@@ -0,0 +1,19 @@
This content is produced and maintained by the Eclipse SmartHome project.
* Project home: https://eclipse.org/smarthome/
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/eclipse/smarthome
== Copyright Holders
See the NOTICE file distributed with the source code at
https://github.com/eclipse/smarthome/blob/master/NOTICE
for detailed information regarding copyright ownership.
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.pde.ui.JunitLaunchConfig">
<booleanAttribute key="append.args" value="true"/>
<stringAttribute key="application" value="org.eclipse.pde.junit.runtime.coretestapplication"/>
<booleanAttribute key="askclear" value="false"/>
<booleanAttribute key="automaticAdd" value="false"/>
<booleanAttribute key="automaticValidate" value="true"/>
<stringAttribute key="bootstrap" value=""/>
<stringAttribute key="checked" value="[NONE]"/>
<booleanAttribute key="clearConfig" value="true"/>
<booleanAttribute key="clearws" value="true"/>
<booleanAttribute key="clearwslog" value="false"/>
<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/pde-junit"/>
<booleanAttribute key="default" value="false"/>
<booleanAttribute key="default_auto_start" value="true"/>
<booleanAttribute key="includeOptional" value="false"/>
<stringAttribute key="location" value="${workspace_loc}/../junit-workspace"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/org.eclipse.smarthome.automation.module.core.test"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.smarthome.automation.module.core.test"/>
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.smarthome.automation.module.core.test"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="pde.version" value="3.3"/>
<stringAttribute key="product" value="org.eclipse.equinox.p2.director.app.product"/>
<booleanAttribute key="run_in_ui_thread" value="true"/>
<stringAttribute key="selected_target_plugins" value="ch.qos.logback.classic@default:default,ch.qos.logback.core@default:default,ch.qos.logback.slf4j@default:false,com.eclipsesource.jaxrs.jersey-min@default:default,com.google.gson@default:default,com.google.guava@default:default,javax.measure.unit-api@default:default,javax.servlet@default:default,javax.transaction@default:false,javax.xml@default:default,net.bytebuddy.byte-buddy-agent@default:default,net.bytebuddy.byte-buddy@default:default,org.apache.ant@default:default,org.apache.commons.collections@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.felix.scr@1:true,org.codehaus.groovy@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.runtime@default:true,org.eclipse.emf.common@default:default,org.eclipse.emf.ecore.xmi@default:default,org.eclipse.emf.ecore@default:default,org.eclipse.equinox.app@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.ds@1:true,org.eclipse.equinox.event@default:default,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.region@default:false,org.eclipse.equinox.registry@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.equinox.util@default:default,org.eclipse.equinox.weaving.hook@default:false,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi.util@default:default,org.eclipse.osgi@-1:true,org.hamcrest.core@default:default,org.junit@default:default,org.mockito.mockito-core@default:default,org.objenesis@default:default,org.slf4j.api@default:default,tec.uom.lib.uom-lib-common@default:default,tec.uom.se@default:default"/>
<stringAttribute key="selected_workspace_plugins" value="org.eclipse.smarthome.automation.api@default:default,org.eclipse.smarthome.automation.core.test@default:false,org.eclipse.smarthome.automation.core@default:default,org.eclipse.smarthome.automation.module.core.test@default:false,org.eclipse.smarthome.automation.module.core@default:default,org.eclipse.smarthome.automation.parser.gson@default:default,org.eclipse.smarthome.automation.providers@default:default,org.eclipse.smarthome.config.core@default:default,org.eclipse.smarthome.config.xml@default:default,org.eclipse.smarthome.core.scheduler@default:default,org.eclipse.smarthome.core.thing@default:true,org.eclipse.smarthome.core@default:default,org.eclipse.smarthome.io.console@default:true,org.eclipse.smarthome.test@default:default"/>
<booleanAttribute key="show_selected_only" value="false"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfig" value="true"/>
<booleanAttribute key="useDefaultConfigArea" value="false"/>
<booleanAttribute key="useProduct" value="false"/>
</launchConfiguration>
@@ -0,0 +1,151 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.core.itests</groupId>
<artifactId>org.openhab.core.reactor.itests</artifactId>
<version>2.5.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.core.automation.module.core.tests</artifactId>
<packaging>eclipse-test-plugin</packaging>
<name>openHAB Core :: Integration Tests :: Automation Core Module Tests</name>
<build>
<plugins>
<plugin>
<groupId>${tycho-groupid}</groupId>
<artifactId>tycho-surefire-plugin</artifactId>
<configuration>
<dependencies>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.openhab.core.automation.api</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.openhab.core.config.core</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.openhab.core.config.xml</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.openhab.core</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.eclipse.core.runtime</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.eclipse.equinox.common</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.eclipse.equinox.ds</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.eclipse.equinox.event</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>org.eclipse.osgi</artifactId>
<version>0.0.0</version>
</dependency>
<!-- LOGGING -->
<dependency>
<type>eclipse-plugin</type>
<artifactId>ch.qos.logback.classic</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>ch.qos.logback.core</artifactId>
<version>0.0.0</version>
</dependency>
<dependency>
<type>eclipse-plugin</type>
<artifactId>ch.qos.logback.slf4j</artifactId>
<version>0.0.0</version>
</dependency>
</dependencies>
<bundleStartLevel>
<bundle>
<id>org.eclipse.smarthome.automation.api</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.core</id>
<level>3</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.module.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.parser.gson</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.providers</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.config.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.config.xml</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.core</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.core.runtime</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.common</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.ds</id>
<level>1</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.event</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
</bundleStartLevel>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,200 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.automation.module.core.internal;
import static org.junit.Assert.*;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.smarthome.automation.Rule;
import org.eclipse.smarthome.automation.RuleManager;
import org.eclipse.smarthome.automation.RuleRegistry;
import org.eclipse.smarthome.automation.RuleStatus;
import org.eclipse.smarthome.automation.core.util.ModuleBuilder;
import org.eclipse.smarthome.automation.core.util.RuleBuilder;
import org.eclipse.smarthome.config.core.Configuration;
import org.eclipse.smarthome.core.common.registry.ProviderChangeListener;
import org.eclipse.smarthome.core.events.Event;
import org.eclipse.smarthome.core.events.EventFilter;
import org.eclipse.smarthome.core.events.EventPublisher;
import org.eclipse.smarthome.core.events.EventSubscriber;
import org.eclipse.smarthome.core.items.Item;
import org.eclipse.smarthome.core.items.ItemNotFoundException;
import org.eclipse.smarthome.core.items.ItemProvider;
import org.eclipse.smarthome.core.items.ItemRegistry;
import org.eclipse.smarthome.core.items.events.ItemCommandEvent;
import org.eclipse.smarthome.core.items.events.ItemEventFactory;
import org.eclipse.smarthome.core.library.items.SwitchItem;
import org.eclipse.smarthome.core.library.types.OnOffType;
import org.eclipse.smarthome.test.java.JavaOSGiTest;
import org.eclipse.smarthome.test.storage.VolatileStorageService;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This tests the RunRuleAction
*
* @author Benedikt Niehues - initial contribution
* @author Markus Rathgeb - Migrated Groovy tests to pure Java ones and made it more robust
*/
public class RunRuleModuleTest extends JavaOSGiTest {
private final Logger logger = LoggerFactory.getLogger(RunRuleModuleTest.class);
private final VolatileStorageService volatileStorageService = new VolatileStorageService();
@Before
public void before() {
registerService(new ItemProvider() {
@Override
public void addProviderChangeListener(final ProviderChangeListener<Item> listener) {
}
@Override
public void removeProviderChangeListener(final ProviderChangeListener<Item> listener) {
}
@Override
public Collection<Item> getAll() {
return Arrays.asList(new Item[] { new SwitchItem("switch1"), new SwitchItem("switch2"),
new SwitchItem("switch3"), new SwitchItem("ruleTrigger") });
}
});
registerService(volatileStorageService);
}
private Rule createSceneRule() {
final Configuration sceneRuleAction1Config = new Configuration(Collections
.unmodifiableMap(Stream.of(new SimpleEntry<>("itemName", "switch1"), new SimpleEntry<>("command", "ON"))
.collect(Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue()))));
final Configuration sceneRuleAction2Config = new Configuration(Collections
.unmodifiableMap(Stream.of(new SimpleEntry<>("itemName", "switch2"), new SimpleEntry<>("command", "ON"))
.collect(Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue()))));
final Configuration sceneRuleAction3Config = new Configuration(Collections
.unmodifiableMap(Stream.of(new SimpleEntry<>("itemName", "switch3"), new SimpleEntry<>("command", "ON"))
.collect(Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue()))));
final Rule sceneRule = RuleBuilder.create("exampleSceneRule").withActions(
ModuleBuilder.createAction().withId("sceneItemPostCommandAction1").withTypeUID("core.ItemCommandAction")
.withConfiguration(sceneRuleAction1Config).build(),
ModuleBuilder.createAction().withId("sceneItemPostCommandAction2").withTypeUID("core.ItemCommandAction")
.withConfiguration(sceneRuleAction2Config).build(),
ModuleBuilder.createAction().withId("sceneItemPostCommandAction3").withTypeUID("core.ItemCommandAction")
.withConfiguration(sceneRuleAction3Config).build())
.withName("Example Scene").build();
return sceneRule;
}
private Rule createOuterRule() {
final Configuration outerRuleTriggerConfig = new Configuration(Collections.unmodifiableMap(Stream
.of(new SimpleEntry<>("eventSource", "ruleTrigger"), new SimpleEntry<>("eventTopic", "smarthome/*"),
new SimpleEntry<>("eventTypes", "ItemStateEvent"))
.collect(Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue()))));
final List<String> ruleUIDs = new ArrayList<>();
ruleUIDs.add("exampleSceneRule");
final Configuration outerRuleActionConfig = new Configuration(
Collections.unmodifiableMap(Stream.of(new SimpleEntry<>("ruleUIDs", ruleUIDs))
.collect(Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue()))));
final Rule outerRule = RuleBuilder.create("sceneActivationRule")
.withTriggers(ModuleBuilder.createTrigger().withId("ItemStateChangeTrigger2")
.withTypeUID("core.GenericEventTrigger").withConfiguration(outerRuleTriggerConfig).build())
.withActions(ModuleBuilder.createAction().withId("RunRuleAction1").withTypeUID("core.RunRuleAction")
.withConfiguration(outerRuleActionConfig).build())
.withName("scene activator").build();
return outerRule;
}
@Test
public void sceneActivatedByRule() throws ItemNotFoundException, InterruptedException {
final RuleRegistry ruleRegistry = getService(RuleRegistry.class);
final RuleManager ruleEngine = getService(RuleManager.class);
Assert.assertNotNull(ruleRegistry);
// Scene rule
final Rule sceneRule = createSceneRule();
logger.info("SceneRule created: {}", sceneRule.getUID());
ruleRegistry.add(sceneRule);
ruleEngine.setEnabled(sceneRule.getUID(), true);
waitForAssert(() -> {
Assert.assertEquals(RuleStatus.IDLE, ruleEngine.getStatusInfo(sceneRule.getUID()).getStatus());
});
// Outer rule
final Rule outerRule = createOuterRule();
logger.info("SceneActivationRule created: {}", outerRule.getUID());
ruleRegistry.add(outerRule);
ruleEngine.setEnabled(outerRule.getUID(), true);
waitForAssert(() -> {
Assert.assertEquals(RuleStatus.IDLE, ruleEngine.getStatusInfo(outerRule.getUID()).getStatus());
});
// Test rule
final EventPublisher eventPublisher = getService(EventPublisher.class);
Assert.assertNotNull(eventPublisher);
final ItemRegistry itemRegistry = getService(ItemRegistry.class);
Assert.assertNotNull(itemRegistry);
final Queue<Event> events = new LinkedList<>();
registerService(new EventSubscriber() {
@Override
public void receive(final Event event) {
logger.info("Event: {}", event.getTopic());
events.add(event);
}
@Override
public Set<String> getSubscribedEventTypes() {
return Collections.singleton(ItemCommandEvent.TYPE);
}
@Override
public EventFilter getEventFilter() {
return null;
}
});
// trigger rule by switching triggerItem ON
eventPublisher.post(ItemEventFactory.createStateEvent("ruleTrigger", OnOffType.ON));
waitForAssert(() -> {
assertFalse(events.isEmpty());
ItemCommandEvent event = (ItemCommandEvent) events.remove();
assertEquals("smarthome/items/switch3/command", event.getTopic());
assertEquals(OnOffType.ON, event.getItemCommand());
});
}
}
@@ -0,0 +1,500 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.automation.module.core.internal;
import static org.junit.Assert.*;
import java.util.AbstractMap.SimpleEntry;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.smarthome.automation.Condition;
import org.eclipse.smarthome.automation.Rule;
import org.eclipse.smarthome.automation.RuleManager;
import org.eclipse.smarthome.automation.RuleRegistry;
import org.eclipse.smarthome.automation.RuleStatus;
import org.eclipse.smarthome.automation.RuleStatusDetail;
import org.eclipse.smarthome.automation.core.util.ModuleBuilder;
import org.eclipse.smarthome.automation.core.util.RuleBuilder;
import org.eclipse.smarthome.automation.events.RuleStatusInfoEvent;
import org.eclipse.smarthome.automation.module.core.handler.CompareConditionHandler;
import org.eclipse.smarthome.automation.type.ModuleTypeRegistry;
import org.eclipse.smarthome.config.core.Configuration;
import org.eclipse.smarthome.core.common.registry.ProviderChangeListener;
import org.eclipse.smarthome.core.events.Event;
import org.eclipse.smarthome.core.events.EventFilter;
import org.eclipse.smarthome.core.events.EventPublisher;
import org.eclipse.smarthome.core.events.EventSubscriber;
import org.eclipse.smarthome.core.items.Item;
import org.eclipse.smarthome.core.items.ItemNotFoundException;
import org.eclipse.smarthome.core.items.ItemProvider;
import org.eclipse.smarthome.core.items.ItemRegistry;
import org.eclipse.smarthome.core.items.events.ItemCommandEvent;
import org.eclipse.smarthome.core.items.events.ItemEventFactory;
import org.eclipse.smarthome.core.library.items.SwitchItem;
import org.eclipse.smarthome.core.library.types.OnOffType;
import org.eclipse.smarthome.core.types.TypeParser;
import org.eclipse.smarthome.test.java.JavaOSGiTest;
import org.eclipse.smarthome.test.storage.VolatileStorageService;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This tests the RuleEngineImpl.
*
* @author Benedikt Niehues - initial contribution
* @author Markus Rathgeb - Migrated Groovy tests to pure Java ones and made it more robust
*/
public class RuntimeRuleTest extends JavaOSGiTest {
private final Logger logger = LoggerFactory.getLogger(RuntimeRuleTest.class);
private final VolatileStorageService volatileStorageService = new VolatileStorageService();
@Before
public void before() {
registerService(new ItemProvider() {
@Override
public void addProviderChangeListener(final ProviderChangeListener<Item> listener) {
}
@Override
public void removeProviderChangeListener(final ProviderChangeListener<Item> listener) {
}
@Override
public Collection<Item> getAll() {
return Arrays.asList(new Item[] { new SwitchItem("myMotionItem"), new SwitchItem("myPresenceItem"),
new SwitchItem("myLampItem"), new SwitchItem("myMotionItem2"),
new SwitchItem("myPresenceItem2"), new SwitchItem("myLampItem2"),
new SwitchItem("myMotionItem3"), new SwitchItem("myPresenceItem3"),
new SwitchItem("myLampItem3"), new SwitchItem("myMotionItem4"),
new SwitchItem("myPresenceItem4"), new SwitchItem("myLampItem4") });
}
});
registerService(volatileStorageService);
}
@Test
@Ignore
public void testPredefinedRule() throws ItemNotFoundException, InterruptedException {
final EventPublisher eventPublisher = getService(EventPublisher.class);
// final ItemRegistry itemRegistry = getService(ItemRegistry.class);
// final SwitchItem myMotionItem = (SwitchItem) itemRegistry.getItem("myMotionItem");
// eventPublisher.post(ItemEventFactory.createStateEvent("myPresenceItem", OnOffType.ON));
final Queue<Event> events = new LinkedList<>();
registerService(new EventSubscriber() {
@Override
public void receive(final Event event) {
logger.info("Event: {}", event.getTopic());
events.add(event);
}
@Override
public Set<String> getSubscribedEventTypes() {
return Collections.singleton(ItemCommandEvent.TYPE);
}
@Override
public EventFilter getEventFilter() {
return null;
}
});
eventPublisher.post(ItemEventFactory.createStateEvent("myMotionItem", OnOffType.ON));
waitForAssert(() -> {
assertFalse(events.isEmpty());
ItemCommandEvent event = (ItemCommandEvent) events.remove();
assertEquals("smarthome/items/myLampItem/command", event.getTopic());
assertEquals(OnOffType.ON, event.getItemCommand());
});
}
@Test
public void itemStateUpdatedBySimpleRule() throws ItemNotFoundException, InterruptedException {
final Configuration triggerConfig = new Configuration(Stream
.of(new SimpleEntry<>("eventSource", "myMotionItem2"), new SimpleEntry<>("eventTopic", "smarthome/*"),
new SimpleEntry<>("eventTypes", "ItemStateEvent"))
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue())));
final Configuration actionConfig = new Configuration(
Stream.of(new SimpleEntry<>("itemName", "myLampItem2"), new SimpleEntry<>("command", "ON"))
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue())));
final Rule rule = RuleBuilder.create("myRule21" + new Random().nextInt())
.withTriggers(ModuleBuilder.createTrigger().withId("ItemStateChangeTrigger2")
.withTypeUID("core.GenericEventTrigger").withConfiguration(triggerConfig).build())
.withActions(ModuleBuilder.createAction().withId("ItemPostCommandAction2")
.withTypeUID("core.ItemCommandAction").withConfiguration(actionConfig).build())
.withName("RuleByJAVA_API").build();
logger.info("RuleImpl created: {}", rule.getUID());
final RuleRegistry ruleRegistry = getService(RuleRegistry.class);
final RuleManager ruleEngine = getService(RuleManager.class);
ruleRegistry.add(rule);
ruleEngine.setEnabled(rule.getUID(), true);
waitForAssert(() -> {
Assert.assertEquals(RuleStatus.IDLE, ruleEngine.getStatusInfo(rule.getUID()).getStatus());
});
// Test rule
final EventPublisher eventPublisher = getService(EventPublisher.class);
Assert.assertNotNull(eventPublisher);
eventPublisher.post(ItemEventFactory.createStateEvent("myPresenceItem2", OnOffType.ON));
final Queue<Event> events = new LinkedList<>();
registerService(new EventSubscriber() {
@Override
public void receive(final Event event) {
logger.info("Event: {}", event.getTopic());
events.add(event);
}
@Override
public Set<String> getSubscribedEventTypes() {
return Collections.singleton(ItemCommandEvent.TYPE);
}
@Override
public EventFilter getEventFilter() {
return null;
}
});
eventPublisher.post(ItemEventFactory.createStateEvent("myMotionItem2", OnOffType.ON));
waitForAssert(() -> {
assertFalse(events.isEmpty());
ItemCommandEvent event = (ItemCommandEvent) events.remove();
assertEquals("smarthome/items/myLampItem2/command", event.getTopic());
assertEquals(OnOffType.ON, event.getItemCommand());
});
}
@Test
public void modeTypesRegistration() {
final ModuleTypeRegistry mtr = getService(ModuleTypeRegistry.class);
waitForAssert(() -> {
Assert.assertNotNull(mtr.get("core.GenericEventTrigger"));
Assert.assertNotNull(mtr.get("core.GenericEventCondition"));
Assert.assertNotNull(mtr.get("core.ItemStateChangeTrigger"));
Assert.assertNotNull(mtr.get("core.ItemStateUpdateTrigger"));
Assert.assertNotNull(mtr.get(CompareConditionHandler.MODULE_TYPE));
});
}
private Configuration newRightOperatorConfig(final Object right, final Object operator) {
return new Configuration(Stream.of(new SimpleEntry<>("right", right), new SimpleEntry<>("operator", operator))
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue())));
}
private Configuration newRightOperatorInputPropertyConfig(final Object right, final Object operator,
final Object inputProperty) {
return new Configuration(Stream
.of(new SimpleEntry<>("right", right), new SimpleEntry<>("operator", operator),
new SimpleEntry<>("inputproperty", inputProperty))
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue())));
}
private void assertSatisfiedHandlerInput(final CompareConditionHandler handler, final boolean expected,
final Object input) {
final boolean is = handler.isSatisfied(Collections.singletonMap("input", input));
if (expected) {
Assert.assertTrue(is);
} else {
Assert.assertFalse(is);
}
}
@Test
public void compareConditionWorks() {
final Configuration conditionConfig = newRightOperatorConfig("ON", "=");
final Map<String, String> inputs = Stream.of(new SimpleEntry<>("input", "someTrigger.someoutput"))
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
Condition condition = ModuleBuilder.createCondition().withId("id").withTypeUID("core.GenericCompareCondition")
.withConfiguration(conditionConfig).withInputs(inputs).build();
CompareConditionHandler handler = new CompareConditionHandler(condition);
assertSatisfiedHandlerInput(handler, true, OnOffType.ON);
assertSatisfiedHandlerInput(handler, true, "ON");
assertSatisfiedHandlerInput(handler, false, OnOffType.OFF);
assertSatisfiedHandlerInput(handler, false, "OFF");
condition = ModuleBuilder.createCondition(condition).withConfiguration(newRightOperatorConfig("21", "="))
.build();
handler = new CompareConditionHandler(condition);
assertSatisfiedHandlerInput(handler, true, 21);
assertSatisfiedHandlerInput(handler, false, 22);
condition = ModuleBuilder.createCondition(condition).withConfiguration(newRightOperatorConfig("21", "<"))
.build();
handler = new CompareConditionHandler(condition);
assertSatisfiedHandlerInput(handler, true, 20);
assertSatisfiedHandlerInput(handler, false, 22);
assertSatisfiedHandlerInput(handler, true, 20l);
assertSatisfiedHandlerInput(handler, false, 22l);
assertSatisfiedHandlerInput(handler, true, 20.9d);
assertSatisfiedHandlerInput(handler, false, 21.1d);
condition = ModuleBuilder.createCondition(condition).withConfiguration(newRightOperatorConfig("21", "<="))
.build();
handler = new CompareConditionHandler(condition);
assertSatisfiedHandlerInput(handler, true, 20);
assertSatisfiedHandlerInput(handler, true, 21);
assertSatisfiedHandlerInput(handler, false, 22);
assertSatisfiedHandlerInput(handler, true, 20l);
assertSatisfiedHandlerInput(handler, true, 21l);
assertSatisfiedHandlerInput(handler, false, 22l);
assertSatisfiedHandlerInput(handler, true, 20.9d);
assertSatisfiedHandlerInput(handler, true, 21.0d);
assertSatisfiedHandlerInput(handler, false, 21.1d);
condition = ModuleBuilder.createCondition(condition).withConfiguration(newRightOperatorConfig("21", "<"))
.build();
handler = new CompareConditionHandler(condition);
assertSatisfiedHandlerInput(handler, true, 20);
assertSatisfiedHandlerInput(handler, false, 22);
assertSatisfiedHandlerInput(handler, true, 20l);
assertSatisfiedHandlerInput(handler, false, 22l);
assertSatisfiedHandlerInput(handler, true, 20.9d);
assertSatisfiedHandlerInput(handler, false, 21.1d);
condition = ModuleBuilder.createCondition(condition).withConfiguration(newRightOperatorConfig("21", "<="))
.build();
handler = new CompareConditionHandler(condition);
assertSatisfiedHandlerInput(handler, true, 20);
assertSatisfiedHandlerInput(handler, true, 21);
assertSatisfiedHandlerInput(handler, false, 22);
assertSatisfiedHandlerInput(handler, true, 20l);
assertSatisfiedHandlerInput(handler, true, 21l);
assertSatisfiedHandlerInput(handler, false, 22l);
assertSatisfiedHandlerInput(handler, true, 20.9d);
assertSatisfiedHandlerInput(handler, true, 21.0d);
assertSatisfiedHandlerInput(handler, false, 21.1d);
condition = ModuleBuilder.createCondition(condition)
.withConfiguration(newRightOperatorConfig(".*anything.*", "matches")).build();
handler = new CompareConditionHandler(condition);
assertSatisfiedHandlerInput(handler, false, "something matches?");
assertSatisfiedHandlerInput(handler, true, "anything matches?");
Assert.assertFalse(handler.isSatisfied(Stream.of(new SimpleEntry<>("nothing", "nothing"))
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()))));
condition = ModuleBuilder.createCondition(condition)
.withConfiguration(newRightOperatorConfig("ONOFF", "matches")).build();
handler = new CompareConditionHandler(condition);
assertSatisfiedHandlerInput(handler, false, OnOffType.ON);
final Event event = ItemEventFactory.createStateEvent("itemName", OnOffType.OFF, "source");
condition = ModuleBuilder.createCondition(condition)
.withConfiguration(newRightOperatorInputPropertyConfig(".*ON.*", "matches", "itemName")).build();
handler = new CompareConditionHandler(condition);
assertSatisfiedHandlerInput(handler, false, event);
condition = ModuleBuilder.createCondition(condition)
.withConfiguration(newRightOperatorInputPropertyConfig("itemName", "matches", "itemName")).build();
handler = new CompareConditionHandler(condition);
assertSatisfiedHandlerInput(handler, true, event);
condition = ModuleBuilder.createCondition(condition).withConfiguration(newRightOperatorConfig("null", "="))
.build();
handler = new CompareConditionHandler(condition);
assertSatisfiedHandlerInput(handler, true, null);
condition = ModuleBuilder.createCondition(condition).withConfiguration(newRightOperatorConfig("notnull", "="))
.build();
handler = new CompareConditionHandler(condition);
assertSatisfiedHandlerInput(handler, false, null);
condition = ModuleBuilder.createCondition(condition).withConfiguration(newRightOperatorConfig("ON", "<"))
.build();
handler = new CompareConditionHandler(condition);
assertSatisfiedHandlerInput(handler, false, OnOffType.ON);
condition = ModuleBuilder.createCondition(condition)
.withConfiguration(newRightOperatorInputPropertyConfig("ON", "<", "nothing")).build();
handler = new CompareConditionHandler(condition);
assertSatisfiedHandlerInput(handler, false, event);
condition = ModuleBuilder.createCondition(condition)
.withConfiguration(newRightOperatorInputPropertyConfig("ON", "=", "nothing")).build();
handler = new CompareConditionHandler(condition);
assertSatisfiedHandlerInput(handler, true, "ON");
}
@Test
public void ruleTriggeredByCompositeTrigger() throws ItemNotFoundException, InterruptedException {
final Configuration triggerConfig = new Configuration(Stream.of(new SimpleEntry<>("itemName", "myMotionItem3"))
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue())));
final Configuration actionConfig = new Configuration(
Stream.of(new SimpleEntry<>("itemName", "myLampItem3"), new SimpleEntry<>("command", "ON"))
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue())));
final Rule rule = RuleBuilder.create("myRule21" + new Random().nextInt() + "_COMPOSITE")
.withTriggers(ModuleBuilder.createTrigger().withId("ItemStateChangeTrigger3")
.withTypeUID("core.ItemStateChangeTrigger").withConfiguration(triggerConfig).build())
.withActions(ModuleBuilder.createAction().withId("ItemPostCommandAction3")
.withTypeUID("core.ItemCommandAction").withConfiguration(actionConfig).build())
.withName("RuleByJAVA_API_WithCompositeTrigger").build();
logger.info("RuleImpl created: {}", rule.getUID());
final RuleRegistry ruleRegistry = getService(RuleRegistry.class);
final RuleManager ruleEngine = getService(RuleManager.class);
ruleRegistry.add(rule);
// Test rule
waitForAssert(() -> {
Assert.assertEquals(RuleStatus.IDLE, ruleEngine.getStatusInfo(rule.getUID()).getStatus());
});
final Queue<Event> events = new LinkedList<>();
registerService(new EventSubscriber() {
@Override
public void receive(final Event event) {
logger.info("RuleEvent: {}", event.getTopic());
events.add(event);
}
@Override
public Set<String> getSubscribedEventTypes() {
return Collections.singleton(RuleStatusInfoEvent.TYPE);
}
@Override
public EventFilter getEventFilter() {
return null;
}
});
final EventPublisher eventPublisher = getService(EventPublisher.class);
eventPublisher.post(ItemEventFactory.createStateEvent("myPresenceItem3", OnOffType.ON));
eventPublisher.post(ItemEventFactory.createStateEvent("myMotionItem3", OnOffType.ON));
waitForAssert(() -> {
assertFalse(events.isEmpty());
RuleStatusInfoEvent event = (RuleStatusInfoEvent) events.remove();
assertEquals(RuleStatus.RUNNING, event.getStatusInfo().getStatus());
});
waitForAssert(() -> {
assertFalse(events.isEmpty());
RuleStatusInfoEvent event = (RuleStatusInfoEvent) events.remove();
assertEquals(RuleStatus.IDLE, event.getStatusInfo().getStatus());
});
}
@Test
@Ignore
public void ruleEnableHandlerWorks() throws ItemNotFoundException {
final RuleRegistry ruleRegistry = getService(RuleRegistry.class);
final RuleManager ruleEngine = getService(RuleManager.class);
final String firstRuleUID = "FirstTestRule";
final String secondRuleUID = "SecondTestRule";
final String thirdRuleUID = "ThirdTestRule";
final String[] firstConfig = new String[] { "FirstTestRule", "SecondTestRule" };
final String[] secondConfig = new String[] { "FirstTestRule" };
final String firstRuleAction = "firstRuleAction";
final String secondRuleAction = "secondRuleAction";
try {
final Configuration triggerConfig = new Configuration(
Stream.of(new SimpleEntry<>("itemName", "myMotionItem3"))
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue())));
final Configuration actionConfig = new Configuration(
Stream.of(new SimpleEntry<>("enable", false), new SimpleEntry<>("ruleUIDs", firstConfig))
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue())));
final Rule rule = RuleBuilder.create(firstRuleAction)
.withTriggers(ModuleBuilder.createTrigger().withId("ItemStateChangeTrigger3")
.withTypeUID("core.ItemStateChangeTrigger").withConfiguration(triggerConfig).build())
.withActions(ModuleBuilder.createAction().withId("RuleAction")
.withTypeUID("core.RuleEnablementAction").withConfiguration(actionConfig).build())
.build();
ruleRegistry.add(RuleBuilder.create(firstRuleUID).build());
ruleRegistry.add(RuleBuilder.create(secondRuleUID).build());
ruleRegistry.add(RuleBuilder.create(thirdRuleUID).build());
ruleRegistry.add(rule);
final ItemRegistry itemRegistry = getService(ItemRegistry.class);
final EventPublisher eventPublisher = getService(EventPublisher.class);
final Item myMotionItem = itemRegistry.getItem("myMotionItem3");
eventPublisher.post(ItemEventFactory.createCommandEvent("myMotionItem3",
TypeParser.parseCommand(myMotionItem.getAcceptedCommandTypes(), "ON")));
waitForAssert(() -> {
Assert.assertEquals(RuleStatusDetail.DISABLED,
ruleEngine.getStatusInfo(firstRuleUID).getStatusDetail());
Assert.assertEquals(RuleStatusDetail.DISABLED,
ruleEngine.getStatusInfo(secondRuleUID).getStatusDetail());
Assert.assertEquals(RuleStatus.IDLE, ruleEngine.getStatus(thirdRuleUID));
});
final Configuration triggerConfig2 = new Configuration(
Stream.of(new SimpleEntry<>("itemName", "myMotionItem3"))
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue())));
final Configuration actionConfig2 = new Configuration(
Stream.of(new SimpleEntry<>("enable", true), new SimpleEntry<>("ruleUIDs", secondConfig))
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue())));
final Rule rule2 = RuleBuilder.create(secondRuleAction)
.withTriggers(ModuleBuilder.createTrigger().withId("ItemStateChangeTrigger3")
.withTypeUID("core.ItemStateChangeTrigger").withConfiguration(triggerConfig2).build())
.withActions(ModuleBuilder.createAction().withId("RuleAction")
.withTypeUID("core.RuleEnablementAction").withConfiguration(actionConfig2).build())
.build();
ruleRegistry.add(rule2);
eventPublisher.post(ItemEventFactory.createCommandEvent("myMotionItem3",
TypeParser.parseCommand(myMotionItem.getAcceptedCommandTypes(), "OFF")));
waitForAssert(() -> {
Assert.assertEquals(RuleStatus.IDLE, ruleEngine.getStatus(firstRuleUID));
Assert.assertEquals(RuleStatusDetail.DISABLED,
ruleEngine.getStatusInfo(secondRuleUID).getStatusDetail());
Assert.assertEquals(RuleStatus.IDLE, ruleEngine.getStatus(thirdRuleUID));
});
} finally {
ruleRegistry.remove(firstRuleUID);
ruleRegistry.remove(secondRuleUID);
ruleRegistry.remove(thirdRuleUID);
ruleRegistry.remove(firstRuleAction);
ruleRegistry.remove(secondRuleAction);
}
}
}
@@ -0,0 +1,210 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.automation.module.core.internal.provider;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.smarthome.automation.AnnotatedActions;
import org.eclipse.smarthome.automation.Visibility;
import org.eclipse.smarthome.automation.annotation.ActionInput;
import org.eclipse.smarthome.automation.annotation.ActionOutput;
import org.eclipse.smarthome.automation.annotation.ActionScope;
import org.eclipse.smarthome.automation.annotation.RuleAction;
import org.eclipse.smarthome.automation.module.core.provider.AnnotationActionModuleTypeHelper;
import org.eclipse.smarthome.automation.module.core.provider.i18n.ModuleTypeI18nService;
import org.eclipse.smarthome.automation.type.ActionType;
import org.eclipse.smarthome.automation.type.Input;
import org.eclipse.smarthome.automation.type.ModuleType;
import org.eclipse.smarthome.automation.type.Output;
import org.eclipse.smarthome.config.core.ConfigConstants;
import org.eclipse.smarthome.config.core.ConfigDescriptionParameter;
import org.eclipse.smarthome.config.core.ParameterOption;
import org.eclipse.smarthome.test.java.JavaTest;
import org.junit.Before;
import org.junit.Test;
/**
* Tests for the {@link AnnotatedActionModuleTypeProvider}
*
* @author Stefan Triller - initial contribution
*
*/
public class AnnotationActionModuleTypeProviderTest extends JavaTest {
private static final String TEST_ACTION_TYPE_ID = "binding.test.testMethod";
private static final String ACTION_LABEL = "Test Label";
private static final String ACTION_DESCRIPTION = "My Description";
private static final String ACTION_INPUT1 = "input1";
private static final String ACTION_INPUT1_DESCRIPTION = "input1 description";
private static final String ACTION_INPUT1_LABEL = "input1 label";
private static final String ACTION_INPUT1_DEFAULT_VALUE = "input1 default";
private static final String ACTION_INPUT1_REFERENCE = "input1 reference";
private static final String ACTION_INPUT2 = "input2";
private static final String ACTION_OUTPUT1 = "output1";
private static final String ACTION_OUTPUT1_DESCRIPTION = "output1 description";
private static final String ACTION_OUTPUT1_LABEL = "output1 label";
private static final String ACTION_OUTPUT1_DEFAULT_VALUE = "output1 default";
private static final String ACTION_OUTPUT1_REFERENCE = "output1 reference";
private static final String ACTION_OUTPUT1_TYPE = "java.lang.Integer";
private static final String ACTION_OUTPUT2 = "output2";
private static final String ACTION_OUTPUT2_TYPE = "java.lang.String";
private ModuleTypeI18nService moduleTypeI18nService;
private AnnotatedActions actionProviderConf1;
private AnnotatedActions actionProviderConf2;
@Before
public void setUp() {
actionProviderConf1 = new TestActionProvider();
actionProviderConf2 = new TestActionProvider();
moduleTypeI18nService = mock(ModuleTypeI18nService.class);
when(moduleTypeI18nService.getModuleTypePerLocale(any(ModuleType.class), any(), any()))
.thenAnswer(i -> i.getArguments()[0]);
}
@Test
public void testMultiServiceAnnotationActions() {
AnnotatedActionModuleTypeProvider prov = new AnnotatedActionModuleTypeProvider();
prov.setModuleTypeI18nService(moduleTypeI18nService);
HashMap<String, Object> properties1 = new HashMap<String, Object>();
properties1.put(ConfigConstants.SERVICE_CONTEXT, "conf1");
prov.addActionProvider(actionProviderConf1, properties1);
Collection<String> types = prov.getTypes();
assertEquals(1, types.size());
assertTrue(types.contains(TEST_ACTION_TYPE_ID));
HashMap<String, Object> properties2 = new HashMap<String, Object>();
properties2.put(ConfigConstants.SERVICE_CONTEXT, "conf2");
prov.addActionProvider(actionProviderConf2, properties2);
// we only have ONE type but TWO configurations for it
types = prov.getTypes();
assertEquals(1, types.size());
assertTrue(types.contains(TEST_ACTION_TYPE_ID));
ModuleType mt = prov.getModuleType(TEST_ACTION_TYPE_ID, null);
assertTrue(mt instanceof ActionType);
ActionType at = (ActionType) mt;
assertEquals(ACTION_LABEL, at.getLabel());
assertEquals(ACTION_DESCRIPTION, at.getDescription());
assertEquals(Visibility.HIDDEN, at.getVisibility());
assertEquals(TEST_ACTION_TYPE_ID, at.getUID());
Set<String> tags = at.getTags();
assertTrue(tags.contains("tag1"));
assertTrue(tags.contains("tag2"));
List<Input> inputs = at.getInputs();
assertEquals(2, inputs.size());
for (Input in : inputs) {
if (ACTION_INPUT1.equals(in.getName())) {
assertEquals(ACTION_INPUT1_LABEL, in.getLabel());
assertEquals(ACTION_INPUT1_DEFAULT_VALUE, in.getDefaultValue());
assertEquals(ACTION_INPUT1_DESCRIPTION, in.getDescription());
assertEquals(ACTION_INPUT1_REFERENCE, in.getReference());
assertEquals(true, in.isRequired());
assertEquals("Item", in.getType());
Set<String> inputTags = in.getTags();
assertTrue(inputTags.contains("tagIn11"));
assertTrue(inputTags.contains("tagIn12"));
} else if (ACTION_INPUT2.equals(in.getName())) {
// if the annotation does not specify a type, we use the java type
assertEquals("java.lang.String", in.getType());
}
}
List<Output> outputs = at.getOutputs();
assertEquals(2, outputs.size());
for (Output o : outputs) {
if (ACTION_OUTPUT1.equals(o.getName())) {
assertEquals(ACTION_OUTPUT1_LABEL, o.getLabel());
assertEquals(ACTION_OUTPUT1_DEFAULT_VALUE, o.getDefaultValue());
assertEquals(ACTION_OUTPUT1_DESCRIPTION, o.getDescription());
assertEquals(ACTION_OUTPUT1_REFERENCE, o.getReference());
assertEquals(ACTION_OUTPUT1_TYPE, o.getType());
Set<String> outputTags = o.getTags();
assertTrue(outputTags.contains("tagOut11"));
assertTrue(outputTags.contains("tagOut12"));
} else if (ACTION_INPUT2.equals(o.getName())) {
assertEquals(ACTION_OUTPUT2_TYPE, o.getType());
}
}
// remove the first configuration
prov.removeActionProvider(actionProviderConf1, properties1);
types = prov.getTypes();
assertEquals(1, types.size());
// check of the second configuration is still valid
mt = prov.getModuleType(TEST_ACTION_TYPE_ID, null);
List<ConfigDescriptionParameter> configParams = mt.getConfigurationDescriptions();
boolean found = false;
for (ConfigDescriptionParameter cdp : configParams) {
if (AnnotationActionModuleTypeHelper.CONFIG_PARAM.equals(cdp.getName())) {
found = true;
List<ParameterOption> parameterOptions = cdp.getOptions();
assertEquals(1, parameterOptions.size());
ParameterOption po = parameterOptions.get(0);
assertEquals("conf2", po.getValue());
}
}
assertTrue(found);
// remove the second configuration and there should be none left
prov.removeActionProvider(actionProviderConf2, properties2);
types = prov.getTypes();
assertEquals(0, types.size());
mt = prov.getModuleType(TEST_ACTION_TYPE_ID, null);
assertNull(mt);
}
@ActionScope(name = "binding.test")
private class TestActionProvider implements AnnotatedActions {
@RuleAction(label = ACTION_LABEL, description = ACTION_DESCRIPTION, visibility = Visibility.HIDDEN, tags = {
"tag1", "tag2" })
public @ActionOutput(name = ACTION_OUTPUT1, type = ACTION_OUTPUT1_TYPE, description = ACTION_OUTPUT1_DESCRIPTION, label = ACTION_OUTPUT1_LABEL, defaultValue = ACTION_OUTPUT1_DEFAULT_VALUE, reference = ACTION_OUTPUT1_REFERENCE, tags = {
"tagOut11",
"tagOut12" }) @ActionOutput(name = ACTION_OUTPUT2, type = ACTION_OUTPUT2_TYPE) Map<String, Object> testMethod(
@ActionInput(name = ACTION_INPUT1, label = ACTION_INPUT1_LABEL, defaultValue = ACTION_INPUT1_DEFAULT_VALUE, description = ACTION_INPUT1_DESCRIPTION, reference = ACTION_INPUT1_REFERENCE, required = true, type = "Item", tags = {
"tagIn11", "tagIn12" }) String input1,
@ActionInput(name = ACTION_INPUT2) String input2) {
Map<String, Object> result = new HashMap<>();
result.put("output1", 23);
result.put("output2", "hello world");
return result;
}
}
}
@@ -0,0 +1,19 @@
This content is produced and maintained by the Eclipse SmartHome project.
* Project home: https://eclipse.org/smarthome/
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/eclipse/smarthome
== Copyright Holders
See the NOTICE file distributed with the source code at
https://github.com/eclipse/smarthome/blob/master/NOTICE
for detailed information regarding copyright ownership.
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.pde.ui.JunitLaunchConfig">
<booleanAttribute key="append.args" value="true"/>
<stringAttribute key="application" value="org.eclipse.pde.junit.runtime.coretestapplication"/>
<booleanAttribute key="askclear" value="false"/>
<booleanAttribute key="automaticAdd" value="false"/>
<booleanAttribute key="automaticValidate" value="true"/>
<stringAttribute key="bootstrap" value=""/>
<stringAttribute key="checked" value="[NONE]"/>
<booleanAttribute key="clearConfig" value="true"/>
<booleanAttribute key="clearws" value="true"/>
<booleanAttribute key="clearwslog" value="false"/>
<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/pde-junit"/>
<booleanAttribute key="default" value="false"/>
<booleanAttribute key="default_auto_start" value="true"/>
<booleanAttribute key="includeOptional" value="false"/>
<stringAttribute key="location" value="${workspace_loc}/../junit-workspace"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/org.eclipse.smarthome.automation.module.script.defaultscope.test"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.smarthome.automation.module.script.defaultscope.test"/>
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JRE for JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.smarthome.automation.module.script.defaultscope.test"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Dorg.osgi.framework.bundle.parent=ext"/>
<stringAttribute key="pde.version" value="3.3"/>
<stringAttribute key="product" value="org.eclipse.equinox.p2.director.app.product"/>
<booleanAttribute key="run_in_ui_thread" value="true"/>
<stringAttribute key="selected_target_plugins" value="ch.qos.logback.classic@default:default,ch.qos.logback.core@default:default,ch.qos.logback.slf4j@default:false,com.eclipsesource.jaxrs.jersey-min@default:default,com.google.gson@default:default,com.google.guava@default:default,javax.activation@default:default,javax.measure.unit-api@default:default,javax.servlet@default:default,javax.transaction@default:false,javax.xml@default:default,net.bytebuddy.byte-buddy-agent@default:default,net.bytebuddy.byte-buddy@default:default,org.apache.ant@default:default,org.apache.commons.collections@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.felix.scr@1:true,org.codehaus.groovy@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.runtime@default:true,org.eclipse.emf.common@default:default,org.eclipse.emf.ecore.xmi@default:default,org.eclipse.emf.ecore@default:default,org.eclipse.equinox.app@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.equinox.ds@1:true,org.eclipse.equinox.event@default:default,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.region@default:false,org.eclipse.equinox.registry@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.equinox.util@default:default,org.eclipse.equinox.weaving.hook@default:false,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.osgi.alpn.fragment@default:false,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi.util@default:default,org.eclipse.osgi@-1:true,org.hamcrest.core@default:default,org.hamcrest.library@default:default,org.junit@default:default,org.mockito.mockito-core@default:default,org.objenesis@default:default,org.slf4j.api@default:default,tec.uom.lib.uom-lib-common@default:default,tec.uom.se@default:default"/>
<stringAttribute key="selected_workspace_plugins" value="org.eclipse.smarthome.automation.api@default:default,org.eclipse.smarthome.automation.core@default:default,org.eclipse.smarthome.automation.module.core@default:default,org.eclipse.smarthome.automation.module.script.defaultscope.test@default:false,org.eclipse.smarthome.automation.module.script.defaultscope@default:default,org.eclipse.smarthome.automation.module.script@default:default,org.eclipse.smarthome.automation.parser.gson@default:default,org.eclipse.smarthome.automation.providers@default:default,org.eclipse.smarthome.config.core@default:default,org.eclipse.smarthome.config.xml@default:default,org.eclipse.smarthome.core.thing@default:default,org.eclipse.smarthome.core@default:default,org.eclipse.smarthome.io.console.eclipse@default:default,org.eclipse.smarthome.io.console@default:default,org.eclipse.smarthome.io.monitor@default:default,org.eclipse.smarthome.test@default:default"/>
<booleanAttribute key="show_selected_only" value="false"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfig" value="true"/>
<booleanAttribute key="useDefaultConfigArea" value="false"/>
<booleanAttribute key="useProduct" value="false"/>
</launchConfiguration>
@@ -0,0 +1,264 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.core.itests</groupId>
<artifactId>org.openhab.core.reactor.itests</artifactId>
<version>2.5.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.core.automation.module.script.defaultscope.tests</artifactId>
<packaging>eclipse-test-plugin</packaging>
<name>openHAB Core :: Integration Tests :: Automation Script Module Defaultscope Tests</name>
<build>
<plugins>
<plugin>
<groupId>${tycho-groupid}</groupId>
<artifactId>target-platform-configuration</artifactId>
<configuration>
<environments combine.self="override"></environments>
<dependency-resolution>
<extraRequirements>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.config.core</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.config.xml</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.core</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.core.thing</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.core.runtime</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.equinox.common</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.equinox.ds</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.equinox.event</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.osgi</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.automation.api</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.automation.core</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.automation.module.core</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.automation.module.script</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.automation.module.script.defaultscope</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>ch.qos.logback.classic</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>ch.qos.logback.core</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>ch.qos.logback.slf4j</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.slf4j.api</id>
<versionRange>0.0.0</versionRange>
</requirement>
</extraRequirements>
</dependency-resolution>
</configuration>
</plugin>
<plugin>
<groupId>${tycho-groupid}</groupId>
<artifactId>tycho-surefire-plugin</artifactId>
<configuration>
<bundleStartLevel>
<bundle>
<id>org.eclipse.smarthome.automation.api</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.module.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.module.script</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.module.script.defaultscope</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.parser.gson</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.providers</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.config.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.config.xml</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.core.autoupdate</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.core.thing</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>ch.qos.logback.classic</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>ch.qos.logback.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>ch.qos.logback.slf4j</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.slf4j.api</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.core.runtime</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.app</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.common</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.ds</id>
<level>1</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.event</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.util</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.osgi.util</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>ch.qos.logback.classic</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>ch.qos.logback.core</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>ch.qos.logback.slf4j</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.slf4j.api</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
</bundleStartLevel>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,5 @@
'use strict';
if(FOOBAR === undefined && UnDefType.FOOBAR === undefined) {
throw "FOOBAR and UnDefType.FOOBAR not defined";
}
@@ -0,0 +1,194 @@
'use strict';
if(State === undefined) {
throw "State not defined";
}
if(Command === undefined) {
throw "Command not defined";
}
if(StringUtils === undefined) {
throw "StringUtils not defined";
}
if(URLEncoder === undefined) {
throw "URLEncoder not defined";
}
if(FileUtils === undefined) {
throw "FileUtils not defined";
}
if(FilenameUtils === undefined) {
throw "FilenameUtils not defined";
}
if(File === undefined) {
throw "File not defined";
}
//types
if(IncreaseDecreaseType === undefined) {
throw "IncreaseDecreaseType not defined";
}
if(DECREASE === undefined) {
throw "DECREASE not defined";
}
if(INCREASE === undefined) {
throw "INCREASE not defined";
}
if(OnOffType === undefined) {
throw "OnOffType not defined";
}
if(ON === undefined) {
throw "OFF not defined";
}
if(OpenClosedType === undefined) {
throw "OpenClosedType not defined";
}
if(CLOSED === undefined) {
throw "CLOSED not defined";
}
if(OPEN === undefined) {
throw "OPEN not defined";
}
if(StopMoveType === undefined) {
throw "StopMoveType not defined";
}
if(MOVE === undefined) {
throw "MOVE not defined";
}
if(STOP === undefined) {
throw "STOP not defined";
}
if(UpDownType === undefined) {
throw "UpDownType not defined";
}
if(DOWN === undefined) {
throw "DOWN not defined";
}
if(UP === undefined) {
throw "UP not defined";
}
if(UnDefType === undefined) {
throw "UnDefType not defined";
}
if(NULL === undefined) {
throw "NULL not defined";
}
if(NextPreviousType === undefined) {
throw "NextPreviousType not defined";
}
if(NEXT === undefined) {
throw "NEXT not defined";
}
if(PREVIOUS === undefined) {
throw "PREVIOUS not defined";
}
if(PlayPauseType === undefined) {
throw "PlayPauseType not defined";
}
if(PLAY === undefined) {
throw "PLAY not defined";
}
if(PAUSE === undefined) {
throw "PAUSE not defined";
}
if(RewindFastforwardType === undefined) {
throw "RewindFastforwardType not defined";
}
if(REWIND === undefined) {
throw "REWIND not defined";
}
if(FASTFORWARD === undefined) {
throw "FASTFORWARD not defined";
}
if(QuantityType === undefined) {
throw "QuantityType not defined";
}
if(StringListType === undefined) {
throw "StringListType not defined";
}
if(RawType === undefined) {
throw "RawType not defined";
}
if(DateTimeType === undefined) {
throw "DateTimeType not defined";
}
if(DecimalType === undefined) {
throw "DecimalType not defined";
}
if(DateTimeType === undefined) {
throw "DateTimeType not defined";
}
if(HSBType === undefined) {
throw "HSBType not defined";
}
if(PercentType === undefined) {
throw "PercentType not defined";
}
if(PointType === undefined) {
throw "PointType not defined";
}
if(StringType === undefined) {
throw "StringType not defined";
}
if(items === undefined) {
throw "items not defined";
}
if(ir === undefined) {
throw "ir not defined";
}
if(itemRegistry === undefined) {
throw "itemRegistry not defined";
}
if(things === undefined) {
throw "things not defined";
}
if(events === undefined) {
throw "events not defined";
}
if(rules === undefined) {
throw "rules not defined";
}
@@ -0,0 +1,61 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.automation.module.script.defaultscope.internal;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import org.eclipse.smarthome.automation.module.script.ScriptEngineContainer;
import org.eclipse.smarthome.automation.module.script.ScriptEngineManager;
import org.eclipse.smarthome.test.java.JavaOSGiTest;
import org.junit.Before;
import org.junit.Test;
/**
* This tests the script modules
*
* @author Kai Kreuzer - initial contribution
*
*/
public class ScopeTest extends JavaOSGiTest {
private ScriptEngine engine;
private final String path = "ESH-INF" + File.separator + "automation" + File.separator + "jsr223";
private final String workingFile = "scopeWorking.js";
private final String failureFile = "scopeFailure.js";
@Before
public void init() {
ScriptEngineManager scriptManager = getService(ScriptEngineManager.class);
ScriptEngineContainer container = scriptManager.createScriptEngine("js", "myJSEngine");
engine = container.getScriptEngine();
}
@Test
public void testScopeDefinesItemTypes() throws ScriptException, IOException {
URL url = bundleContext.getBundle().getResource(path + File.separator + workingFile);
engine.eval(new InputStreamReader(url.openStream()));
}
@Test(expected = ScriptException.class)
public void testScopeDoesNotDefineFoobar() throws ScriptException, IOException {
URL url = bundleContext.getBundle().getResource(path + File.separator + failureFile);
engine.eval(new InputStreamReader(url.openStream()));
}
}
@@ -0,0 +1,19 @@
This content is produced and maintained by the Eclipse SmartHome project.
* Project home: https://eclipse.org/smarthome/
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/eclipse/smarthome
== Copyright Holders
See the NOTICE file distributed with the source code at
https://github.com/eclipse/smarthome/blob/master/NOTICE
for detailed information regarding copyright ownership.
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.pde.ui.JunitLaunchConfig">
<booleanAttribute key="append.args" value="true"/>
<stringAttribute key="application" value="org.eclipse.pde.junit.runtime.coretestapplication"/>
<booleanAttribute key="askclear" value="false"/>
<booleanAttribute key="automaticAdd" value="false"/>
<booleanAttribute key="automaticValidate" value="true"/>
<stringAttribute key="bootstrap" value=""/>
<stringAttribute key="checked" value="[NONE]"/>
<booleanAttribute key="clearConfig" value="true"/>
<booleanAttribute key="clearws" value="true"/>
<booleanAttribute key="clearwslog" value="false"/>
<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/pde-junit"/>
<booleanAttribute key="default" value="false"/>
<booleanAttribute key="default_auto_start" value="true"/>
<booleanAttribute key="includeOptional" value="false"/>
<stringAttribute key="location" value="${workspace_loc}/../junit-workspace"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/org.eclipse.smarthome.automation.module.script.test"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.smarthome.automation.module.script.test"/>
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JRE for JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.smarthome.automation.module.script.test"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Dorg.osgi.framework.bundle.parent=ext"/>
<stringAttribute key="pde.version" value="3.3"/>
<stringAttribute key="product" value="org.eclipse.equinox.p2.director.app.product"/>
<booleanAttribute key="run_in_ui_thread" value="true"/>
<stringAttribute key="selected_target_plugins" value="ch.qos.logback.classic@default:default,ch.qos.logback.core@default:default,ch.qos.logback.slf4j@default:false,com.google.gson@default:default,com.google.guava@default:default,javax.measure.unit-api@default:default,javax.servlet@default:default,javax.transaction@default:false,javax.xml@default:default,net.bytebuddy.byte-buddy-agent@default:default,net.bytebuddy.byte-buddy@default:default,org.apache.ant@default:default,org.apache.commons.collections@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.felix.scr@1:true,org.codehaus.groovy@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.runtime@default:true,org.eclipse.equinox.app@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.equinox.ds@1:true,org.eclipse.equinox.event@default:default,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.region@default:false,org.eclipse.equinox.registry@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.equinox.util@default:default,org.eclipse.equinox.weaving.hook@default:false,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi.util@default:default,org.eclipse.osgi@-1:true,org.hamcrest.core@default:default,org.junit@default:default,org.mockito.mockito-core@default:default,org.objenesis@default:default,org.slf4j.api@default:default,tec.uom.lib.uom-lib-common@default:default,tec.uom.se@default:default"/>
<stringAttribute key="selected_workspace_plugins" value="org.eclipse.smarthome.automation.api@default:default,org.eclipse.smarthome.automation.core@default:default,org.eclipse.smarthome.automation.module.core@default:default,org.eclipse.smarthome.automation.module.script.defaultscope@default:default,org.eclipse.smarthome.automation.module.script.test@default:false,org.eclipse.smarthome.automation.module.script@default:default,org.eclipse.smarthome.automation.parser.gson@default:default,org.eclipse.smarthome.automation.providers@default:default,org.eclipse.smarthome.config.core@default:default,org.eclipse.smarthome.config.xml@default:default,org.eclipse.smarthome.core.thing@default:default,org.eclipse.smarthome.core@default:default,org.eclipse.smarthome.io.console.eclipse@default:default,org.eclipse.smarthome.io.console@default:default,org.eclipse.smarthome.io.monitor@default:default,org.eclipse.smarthome.test@default:default"/>
<booleanAttribute key="show_selected_only" value="false"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfig" value="true"/>
<booleanAttribute key="useDefaultConfigArea" value="false"/>
<booleanAttribute key="useProduct" value="false"/>
</launchConfiguration>
@@ -0,0 +1,259 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.core.itests</groupId>
<artifactId>org.openhab.core.reactor.itests</artifactId>
<version>2.5.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.core.automation.module.script.tests</artifactId>
<packaging>eclipse-test-plugin</packaging>
<name>openHAB Core :: Integration Tests :: Automation Script Module Tests</name>
<build>
<plugins>
<plugin>
<groupId>${tycho-groupid}</groupId>
<artifactId>target-platform-configuration</artifactId>
<configuration>
<environments combine.self="override"></environments>
<dependency-resolution>
<extraRequirements>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.config.core</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.config.xml</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.core</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.core.thing</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.core.runtime</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.equinox.common</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.equinox.ds</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.equinox.event</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.osgi</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.automation.api</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.automation.core</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.automation.module.core</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.automation.module.script</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.automation.module.script.defaultscope</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>ch.qos.logback.classic</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>ch.qos.logback.core</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>ch.qos.logback.slf4j</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.slf4j.api</id>
<versionRange>0.0.0</versionRange>
</requirement>
</extraRequirements>
</dependency-resolution>
</configuration>
</plugin>
<plugin>
<groupId>${tycho-groupid}</groupId>
<artifactId>tycho-surefire-plugin</artifactId>
<configuration>
<bundleStartLevel>
<bundle>
<id>org.eclipse.smarthome.automation.api</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.module.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.module.script</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.module.script.defaultscope</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.parser.gson</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.providers</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.config.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.config.xml</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.core.thing</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>ch.qos.logback.classic</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>ch.qos.logback.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>ch.qos.logback.slf4j</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.slf4j.api</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.core.runtime</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.app</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.common</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.ds</id>
<level>1</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.event</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.util</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.osgi.util</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>ch.qos.logback.classic</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>ch.qos.logback.core</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>ch.qos.logback.slf4j</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.slf4j.api</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
</bundleStartLevel>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,38 @@
[
{
"uid": "javascript.rule1",
"name": "DemoScriptRule",
"description": "Sample rule based on scripts",
"triggers": [
{
"id": "trigger",
"type": "core.GenericEventTrigger",
"configuration":{
"eventSource":"MyTrigger",
"eventTopic":"smarthome/items/MyTrigger/state",
"eventTypes":"ItemStateEvent"
}
}
],
"conditions": [
{
"id": "condition",
"type": "script.ScriptCondition",
"configuration": {
"type": "application/javascript",
"script": "event.itemState==ON"
}
}
],
"actions": [
{
"id": "action",
"type": "script.ScriptAction",
"configuration": {
"type": "application/javascript",
"script": "print(items.MyTrigger), print(things.getAll()), print(ctx.get('trigger.event')), events.sendCommand('ScriptItem', 'ON')"
}
}
]
}
]
@@ -0,0 +1,161 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.automation.module.script;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.smarthome.automation.Action;
import org.eclipse.smarthome.automation.Condition;
import org.eclipse.smarthome.automation.Rule;
import org.eclipse.smarthome.automation.RuleManager;
import org.eclipse.smarthome.automation.RuleRegistry;
import org.eclipse.smarthome.automation.RuleStatus;
import org.eclipse.smarthome.automation.RuleStatusInfo;
import org.eclipse.smarthome.automation.Trigger;
import org.eclipse.smarthome.core.common.registry.ProviderChangeListener;
import org.eclipse.smarthome.core.events.Event;
import org.eclipse.smarthome.core.events.EventFilter;
import org.eclipse.smarthome.core.events.EventPublisher;
import org.eclipse.smarthome.core.events.EventSubscriber;
import org.eclipse.smarthome.core.items.Item;
import org.eclipse.smarthome.core.items.ItemNotFoundException;
import org.eclipse.smarthome.core.items.ItemProvider;
import org.eclipse.smarthome.core.items.ItemRegistry;
import org.eclipse.smarthome.core.items.events.ItemCommandEvent;
import org.eclipse.smarthome.core.items.events.ItemEventFactory;
import org.eclipse.smarthome.core.library.items.SwitchItem;
import org.eclipse.smarthome.core.library.types.OnOffType;
import org.eclipse.smarthome.test.java.JavaOSGiTest;
import org.eclipse.smarthome.test.storage.VolatileStorageService;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This tests the script modules
*
* @author Kai Kreuzer - initial contribution
*
*/
public class ScriptRuleTest extends JavaOSGiTest {
final Logger logger = LoggerFactory.getLogger(ScriptRuleTest.class);
VolatileStorageService volatileStorageService = new VolatileStorageService();
ItemCommandEvent receivedEvent;
public ScriptRuleTest() {
}
@Before
public void before() {
ItemProvider itemProvider = new ItemProvider() {
@Override
public void addProviderChangeListener(@NonNull ProviderChangeListener<@NonNull Item> listener) {
}
@Override
public @NonNull Collection<@NonNull Item> getAll() {
return Arrays.asList(new Item[] { new SwitchItem("MyTrigger"), new SwitchItem("ScriptItem") });
}
@Override
public void removeProviderChangeListener(@NonNull ProviderChangeListener<@NonNull Item> listener) {
}
};
registerService(itemProvider);
registerService(volatileStorageService);
EventSubscriber eventSubscriber = new EventSubscriber() {
@Override
public void receive(Event event) {
receivedEvent = (ItemCommandEvent) event;
logger.info("received event from item {}, command {}", receivedEvent.getItemName(),
receivedEvent.getItemCommand());
}
@Override
public Set<String> getSubscribedEventTypes() {
return Collections.singleton(ItemCommandEvent.TYPE);
}
@Override
public EventFilter getEventFilter() {
return null;
}
};
registerService(eventSubscriber);
}
@Test
public void testPredefinedRule() throws ItemNotFoundException {
EventPublisher eventPublisher = getService(EventPublisher.class);
ItemRegistry itemRegistry = getService(ItemRegistry.class);
RuleRegistry ruleRegistry = getService(RuleRegistry.class);
RuleManager ruleEngine = getService(RuleManager.class);
// WAIT until Rule modules types are parsed and the rule becomes IDLE
waitForAssert(() -> {
assertThat(ruleRegistry.getAll().isEmpty(), is(false));
Rule rule2 = ruleRegistry.get("javascript.rule1");
assertThat(rule2, is(notNullValue()));
RuleStatusInfo ruleStatus2 = ruleEngine.getStatusInfo(rule2.getUID());
assertThat(ruleStatus2, is(notNullValue()));
assertThat(ruleStatus2.getStatus(), is(RuleStatus.IDLE));
}, 10000, 200);
Rule rule = ruleRegistry.get("javascript.rule1");
assertThat(rule, is(notNullValue()));
assertThat(rule.getName(), is("DemoScriptRule"));
Optional<? extends Trigger> trigger = rule.getTriggers().stream().filter(t -> t.getId().equals("trigger"))
.findFirst();
assertThat(trigger.isPresent(), is(true));
assertThat(trigger.get().getTypeUID(), is("core.GenericEventTrigger"));
assertThat(trigger.get().getConfiguration().get("eventSource"), is("MyTrigger"));
assertThat(trigger.get().getConfiguration().get("eventTopic"), is("smarthome/items/MyTrigger/state"));
assertThat(trigger.get().getConfiguration().get("eventTypes"), is("ItemStateEvent"));
Optional<? extends Condition> condition1 = rule.getConditions().stream()
.filter(c -> c.getId().equals("condition")).findFirst();
assertThat(condition1.isPresent(), is(true));
assertThat(condition1.get().getTypeUID(), is("script.ScriptCondition"));
assertThat(condition1.get().getConfiguration().get("type"), is("application/javascript"));
assertThat(condition1.get().getConfiguration().get("script"), is("event.itemState==ON"));
Optional<? extends Action> action = rule.getActions().stream().filter(a -> a.getId().equals("action"))
.findFirst();
assertThat(action.isPresent(), is(true));
assertThat(action.get().getTypeUID(), is("script.ScriptAction"));
assertThat(action.get().getConfiguration().get("type"), is("application/javascript"));
assertThat(action.get().getConfiguration().get("script"), is(
"print(items.MyTrigger), print(things.getAll()), print(ctx.get('trigger.event')), events.sendCommand('ScriptItem', 'ON')"));
RuleStatusInfo ruleStatus = ruleEngine.getStatusInfo(rule.getUID());
assertThat(ruleStatus.getStatus(), is(RuleStatus.IDLE));
SwitchItem myTriggerItem = (SwitchItem) itemRegistry.getItem("MyTrigger");
logger.info("Triggering item: {}", myTriggerItem.getName());
eventPublisher.post(ItemEventFactory.createStateEvent("MyTrigger", OnOffType.ON));
waitForAssert(() -> {
assertThat(receivedEvent, notNullValue());
});
assertThat(receivedEvent.getItemName(), is(equalTo("ScriptItem")));
assertThat(receivedEvent.getItemCommand(), is(OnOffType.ON));
}
}
@@ -0,0 +1 @@
/test-classes/
@@ -0,0 +1,19 @@
This content is produced and maintained by the Eclipse SmartHome project.
* Project home: https://eclipse.org/smarthome/
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/eclipse/smarthome
== Copyright Holders
See the NOTICE file distributed with the source code at
https://github.com/eclipse/smarthome/blob/master/NOTICE
for detailed information regarding copyright ownership.
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.pde.ui.JunitLaunchConfig">
<booleanAttribute key="append.args" value="true"/>
<stringAttribute key="application" value="org.eclipse.pde.junit.runtime.coretestapplication"/>
<booleanAttribute key="askclear" value="false"/>
<booleanAttribute key="automaticAdd" value="false"/>
<booleanAttribute key="automaticValidate" value="true"/>
<stringAttribute key="bootstrap" value=""/>
<stringAttribute key="checked" value="[NONE]"/>
<booleanAttribute key="clearConfig" value="true"/>
<booleanAttribute key="clearws" value="true"/>
<booleanAttribute key="clearwslog" value="false"/>
<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/pde-junit"/>
<booleanAttribute key="default" value="false"/>
<booleanAttribute key="default_auto_start" value="true"/>
<booleanAttribute key="includeOptional" value="false"/>
<stringAttribute key="location" value="${workspace_loc}/../junit-workspace"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/org.eclipse.smarthome.automation.module.timer.test"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.smarthome.automation.module.timer.test"/>
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JRE for JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.smarthome.automation.module.timer.test"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Dorg.osgi.framework.bundle.parent=ext"/>
<stringAttribute key="pde.version" value="3.3"/>
<stringAttribute key="product" value="org.eclipse.equinox.p2.director.app.product"/>
<booleanAttribute key="run_in_ui_thread" value="true"/>
<stringAttribute key="selected_target_plugins" value="ch.qos.logback.classic@default:default,ch.qos.logback.core@default:default,ch.qos.logback.slf4j@default:false,com.google.gson@default:default,com.google.guava@default:default,javax.measure.unit-api@default:default,javax.servlet@default:default,javax.transaction@default:false,javax.xml@default:default,net.bytebuddy.byte-buddy-agent@default:default,net.bytebuddy.byte-buddy@default:default,org.apache.ant@default:default,org.apache.commons.collections@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.felix.scr@1:true,org.codehaus.groovy@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.runtime@default:true,org.eclipse.equinox.app@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.equinox.ds@1:true,org.eclipse.equinox.event@default:default,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.region@default:false,org.eclipse.equinox.registry@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.equinox.util@default:default,org.eclipse.equinox.weaving.hook@default:false,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi.util@default:default,org.eclipse.osgi@-1:true,org.eclipse.smarthome.test@default:default,org.hamcrest.core@default:default,org.junit@default:default,org.mockito.mockito-core@default:default,org.objenesis@default:default,org.slf4j.api@default:default,tec.uom.lib.uom-lib-common@default:default,tec.uom.se@default:default"/>
<stringAttribute key="selected_workspace_plugins" value="org.eclipse.smarthome.automation.api@default:default,org.eclipse.smarthome.automation.core@default:default,org.eclipse.smarthome.automation.module.core@default:default,org.eclipse.smarthome.automation.module.timer.test@default:default,org.eclipse.smarthome.automation.module.timer@default:default,org.eclipse.smarthome.automation.parser.gson@default:default,org.eclipse.smarthome.automation.providers@default:default,org.eclipse.smarthome.config.core@default:default,org.eclipse.smarthome.config.xml@default:default,org.eclipse.smarthome.core.scheduler@default:default,org.eclipse.smarthome.core.thing@default:default,org.eclipse.smarthome.core@default:default,org.eclipse.smarthome.io.console.eclipse@default:default,org.eclipse.smarthome.io.console@default:default,org.eclipse.smarthome.io.monitor@default:default"/>
<booleanAttribute key="show_selected_only" value="false"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfig" value="true"/>
<booleanAttribute key="useDefaultConfigArea" value="false"/>
<booleanAttribute key="useProduct" value="false"/>
</launchConfiguration>
@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.core.itests</groupId>
<artifactId>org.openhab.core.reactor.itests</artifactId>
<version>2.5.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.core.automation.module.timer.tests</artifactId>
<packaging>eclipse-test-plugin</packaging>
<name>openHAB Core :: Integration Tests :: Automation Module Timer Tests</name>
<build>
<plugins>
<plugin>
<groupId>${tycho-groupid}</groupId>
<artifactId>target-platform-configuration</artifactId>
<configuration>
<environments combine.self="override"></environments>
<dependency-resolution>
<extraRequirements>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.automation.api</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.config.core</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.config.xml</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.core</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.core.runtime</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.equinox.common</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.equinox.ds</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.equinox.event</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.osgi</id>
<versionRange>0.0.0</versionRange>
</requirement>
<!-- LOGGING -->
<requirement>
<type>eclipse-plugin</type>
<id>ch.qos.logback.classic</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>ch.qos.logback.core</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>ch.qos.logback.slf4j</id>
<versionRange>0.0.0</versionRange>
</requirement>
</extraRequirements>
</dependency-resolution>
</configuration>
</plugin>
<plugin>
<groupId>${tycho-groupid}</groupId>
<artifactId>tycho-surefire-plugin</artifactId>
<configuration>
<bundleStartLevel>
<bundle>
<id>org.eclipse.smarthome.automation.api</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.core</id>
<level>3</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.module.core</id>
<level>3</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.module.timer</id>
<level>3</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.parser.gson</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.automation.providers</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.config.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.config.xml</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.core</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.core.runtime</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.common</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.ds</id>
<level>1</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.event</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.core.scheduler</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
</bundleStartLevel>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,217 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.automation.module.timer.internal;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.smarthome.automation.Action;
import org.eclipse.smarthome.automation.Condition;
import org.eclipse.smarthome.automation.Rule;
import org.eclipse.smarthome.automation.RuleManager;
import org.eclipse.smarthome.automation.RuleRegistry;
import org.eclipse.smarthome.automation.RuleStatus;
import org.eclipse.smarthome.automation.RuleStatusInfo;
import org.eclipse.smarthome.automation.Trigger;
import org.eclipse.smarthome.automation.core.util.ModuleBuilder;
import org.eclipse.smarthome.automation.core.util.RuleBuilder;
import org.eclipse.smarthome.automation.module.core.handler.ItemCommandActionHandler;
import org.eclipse.smarthome.automation.module.core.handler.ItemStateTriggerHandler;
import org.eclipse.smarthome.config.core.Configuration;
import org.eclipse.smarthome.core.common.registry.ProviderChangeListener;
import org.eclipse.smarthome.core.events.Event;
import org.eclipse.smarthome.core.events.EventFilter;
import org.eclipse.smarthome.core.events.EventPublisher;
import org.eclipse.smarthome.core.events.EventSubscriber;
import org.eclipse.smarthome.core.items.Item;
import org.eclipse.smarthome.core.items.ItemNotFoundException;
import org.eclipse.smarthome.core.items.ItemProvider;
import org.eclipse.smarthome.core.items.ItemRegistry;
import org.eclipse.smarthome.core.items.events.ItemCommandEvent;
import org.eclipse.smarthome.core.items.events.ItemEventFactory;
import org.eclipse.smarthome.core.library.items.SwitchItem;
import org.eclipse.smarthome.core.library.types.OnOffType;
import org.eclipse.smarthome.test.java.JavaOSGiTest;
import org.eclipse.smarthome.test.storage.VolatileStorageService;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This provides common functionality for all condition tests.
*
* @author Dominik Schlierf - extracting this base class from TimeOfDayConditionHandlerTest
* @author Kai Kreuzer - initial contribution of TimeOfDayConditionHandlerTest
*
*/
public abstract class BasicConditionHandlerTest extends JavaOSGiTest {
final Logger logger = LoggerFactory.getLogger(TimeOfDayConditionHandlerTest.class);
VolatileStorageService volatileStorageService = new VolatileStorageService();
RuleRegistry ruleRegistry;
RuleManager ruleEngine;
Event itemEvent = null;
/**
* This executes before every test and before the
*
* @Before-annotated methods in sub-classes.
*/
@Before
public void beforeBase() {
ItemProvider itemProvider = new ItemProvider() {
@Override
public void addProviderChangeListener(@NonNull ProviderChangeListener<@NonNull Item> listener) {
}
@Override
public @NonNull Collection<@NonNull Item> getAll() {
List<Item> items = new ArrayList<>();
items.add(new SwitchItem("TriggeredItem"));
items.add(new SwitchItem("SwitchedItem"));
return items;
}
@Override
public void removeProviderChangeListener(@NonNull ProviderChangeListener<@NonNull Item> listener) {
}
};
registerService(itemProvider);
registerService(volatileStorageService);
waitForAssert(() -> {
ruleRegistry = getService(RuleRegistry.class);
assertThat(ruleRegistry, is(notNullValue()));
}, 3000, 100);
waitForAssert(() -> {
ruleEngine = getService(RuleManager.class);
assertThat(ruleEngine, is(notNullValue()));
}, 3000, 100);
}
@Test
public void assertThatConditionWorksInRule() throws ItemNotFoundException {
String testItemName1 = "TriggeredItem";
String testItemName2 = "SwitchedItem";
ItemRegistry itemRegistry = getService(ItemRegistry.class);
SwitchItem triggeredItem = (SwitchItem) itemRegistry.getItem(testItemName1);
SwitchItem switchedItem = (SwitchItem) itemRegistry.getItem(testItemName2);
/*
* Create Rule
*/
logger.info("Create rule");
Configuration triggerConfig = new Configuration(Collections.singletonMap("itemName", testItemName1));
List<Trigger> triggers = Collections.singletonList(ModuleBuilder.createTrigger().withId("MyTrigger")
.withTypeUID(ItemStateTriggerHandler.UPDATE_MODULE_TYPE_ID).withConfiguration(triggerConfig).build());
List<Condition> conditions = Collections.singletonList(getPassingCondition());
Map<String, Object> cfgEntries = new HashMap<>();
cfgEntries.put("itemName", testItemName2);
cfgEntries.put("command", "ON");
Configuration actionConfig = new Configuration(cfgEntries);
List<Action> actions = Collections.singletonList(ModuleBuilder.createAction().withId("MyItemPostCommandAction")
.withTypeUID(ItemCommandActionHandler.ITEM_COMMAND_ACTION).withConfiguration(actionConfig).build());
// prepare the execution
EventPublisher eventPublisher = getService(EventPublisher.class);
EventSubscriber itemEventHandler = new EventSubscriber() {
@Override
public Set<String> getSubscribedEventTypes() {
return Collections.singleton(ItemCommandEvent.TYPE);
}
@Override
public EventFilter getEventFilter() {
return null;
}
@Override
public void receive(Event event) {
logger.info("Event: {}", event.getTopic());
if (event.getTopic().contains(testItemName2)) {
BasicConditionHandlerTest.this.itemEvent = event;
}
}
};
registerService(itemEventHandler);
Rule rule = RuleBuilder.create("MyRule" + new Random().nextInt()).withTriggers(triggers)
.withConditions(conditions).withActions(actions).withName("MyConditionTestRule").build();
logger.info("Rule created: {}", rule.getUID());
logger.info("Add rule");
ruleRegistry.add(rule);
logger.info("Rule added");
logger.info("Enable rule and wait for idle status");
ruleEngine.setEnabled(rule.getUID(), true);
waitForAssert(() -> {
final RuleStatusInfo ruleStatus = ruleEngine.getStatusInfo(rule.getUID());
assertThat(ruleStatus.getStatus(), is(RuleStatus.IDLE));
});
logger.info("Rule is enabled and idle");
logger.info("Send and wait for item state is ON");
eventPublisher.post(ItemEventFactory.createStateEvent(testItemName1, OnOffType.ON));
waitForAssert(() -> {
assertThat(itemEvent, is(notNullValue()));
assertThat(((ItemCommandEvent) itemEvent).getItemCommand(), is(OnOffType.ON));
});
logger.info("item state is ON");
// now make the condition fail
Rule rule2 = RuleBuilder.create(rule).withConditions(ModuleBuilder.createCondition(rule.getConditions().get(0))
.withConfiguration(getFailingConfiguration()).build()).build();
ruleRegistry.update(rule2);
// prepare the execution
itemEvent = null;
eventPublisher.post(ItemEventFactory.createStateEvent(testItemName1, OnOffType.ON));
waitForAssert(() -> {
assertThat(itemEvent, is(nullValue()));
});
}
/**
* This returns a Condition of the tested type, which is always evaluating as true.
*
* @return a Condition of the tested type, which is always evaluating as true.
*/
protected abstract Condition getPassingCondition();
/**
* This returns a Configuration for the tested type of condition,
* which makes the condition always evaluate as false.
*
* @return a Configuration for the tested type of condition,
* which makes the condition always evaluate as false.
*/
protected abstract Configuration getFailingConfiguration();
}
@@ -0,0 +1,91 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.automation.module.timer.internal;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Locale;
import org.eclipse.smarthome.automation.Condition;
import org.eclipse.smarthome.automation.core.util.ModuleBuilder;
import org.eclipse.smarthome.automation.module.timer.handler.DayOfWeekConditionHandler;
import org.eclipse.smarthome.automation.type.ModuleTypeRegistry;
import org.eclipse.smarthome.config.core.Configuration;
import org.junit.Test;
/**
* This tests the dayOfWeek Condition.
*
* @author Dominik Schlierf - added extension of BasicConditionHandlerTest
* @author Kai Kreuzer - initial contribution
*
*/
public class DayOfWeekConditionHandlerTest extends BasicConditionHandlerTest {
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("EEE", Locale.ENGLISH);
String dayOfWeek = sdf.format(cal.getTime()).toUpperCase();
public DayOfWeekConditionHandlerTest() {
logger.info("Today is {}", dayOfWeek);
}
@Test
public void assertThatConditionWorks() {
Configuration conditionConfiguration = new Configuration(Collections.singletonMap("days",
Arrays.asList(new String[] { "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN" })));
Condition condition = ModuleBuilder.createCondition().withId("id")
.withTypeUID(DayOfWeekConditionHandler.MODULE_TYPE_ID).withConfiguration(conditionConfiguration)
.build();
DayOfWeekConditionHandler handler = new DayOfWeekConditionHandler(condition);
assertThat(handler.isSatisfied(null), is(true));
condition = ModuleBuilder.createCondition(condition)
.withConfiguration(new Configuration(Collections.singletonMap("days", Collections.emptyList())))
.build();
handler = new DayOfWeekConditionHandler(condition);
assertThat(handler.isSatisfied(null), is(false));
condition = ModuleBuilder.createCondition(condition)
.withConfiguration(
new Configuration(Collections.singletonMap("days", Collections.singletonList(dayOfWeek))))
.build();
handler = new DayOfWeekConditionHandler(condition);
assertThat(handler.isSatisfied(null), is(true));
}
@Test
public void checkIfModuleTypeIsRegistered() {
ModuleTypeRegistry mtr = getService(ModuleTypeRegistry.class);
waitForAssert(() -> {
assertThat(mtr.get(DayOfWeekConditionHandler.MODULE_TYPE_ID), is(notNullValue()));
}, 3000, 100);
}
@Override
protected Condition getPassingCondition() {
Configuration conditionConfig = new Configuration(Collections.singletonMap("days", dayOfWeek));
return ModuleBuilder.createCondition().withId("MyDOWCondition")
.withTypeUID(DayOfWeekConditionHandler.MODULE_TYPE_ID).withConfiguration(conditionConfig).build();
}
@Override
protected Configuration getFailingConfiguration() {
return new Configuration(Collections.singletonMap("days", Collections.emptyList()));
}
}
@@ -0,0 +1,230 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.automation.module.timer.internal;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.smarthome.automation.Action;
import org.eclipse.smarthome.automation.Rule;
import org.eclipse.smarthome.automation.RuleManager;
import org.eclipse.smarthome.automation.RuleRegistry;
import org.eclipse.smarthome.automation.RuleStatus;
import org.eclipse.smarthome.automation.RuleStatusDetail;
import org.eclipse.smarthome.automation.RuleStatusInfo;
import org.eclipse.smarthome.automation.Trigger;
import org.eclipse.smarthome.automation.core.util.ModuleBuilder;
import org.eclipse.smarthome.automation.core.util.RuleBuilder;
import org.eclipse.smarthome.automation.module.timer.handler.GenericCronTriggerHandler;
import org.eclipse.smarthome.automation.type.ModuleTypeRegistry;
import org.eclipse.smarthome.config.core.Configuration;
import org.eclipse.smarthome.core.common.registry.ProviderChangeListener;
import org.eclipse.smarthome.core.events.Event;
import org.eclipse.smarthome.core.events.EventFilter;
import org.eclipse.smarthome.core.events.EventSubscriber;
import org.eclipse.smarthome.core.items.Item;
import org.eclipse.smarthome.core.items.ItemProvider;
import org.eclipse.smarthome.core.items.events.ItemCommandEvent;
import org.eclipse.smarthome.core.library.items.SwitchItem;
import org.eclipse.smarthome.test.java.JavaOSGiTest;
import org.eclipse.smarthome.test.storage.VolatileStorageService;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* this tests the Timer Trigger
*
* @author Christoph Knauf - initial contribution
* @author Markus Rathgeb - fix module timer test
* @author Kai Kreuzer - migrated to Java
*
*/
public class RuntimeRuleTest extends JavaOSGiTest {
final Logger logger = LoggerFactory.getLogger(RuntimeRuleTest.class);
VolatileStorageService volatileStorageService = new VolatileStorageService();
RuleRegistry ruleRegistry;
RuleManager ruleEngine;
public RuntimeRuleTest() {
}
@Before
public void before() {
ItemProvider itemProvider = new TestItemProvider(Collections.singleton(new SwitchItem("myLampItem")));
registerService(itemProvider);
registerService(volatileStorageService);
waitForAssert(() -> {
ruleRegistry = getService(RuleRegistry.class);
assertThat("RuleRegistry service not found", ruleRegistry, is(notNullValue()));
}, 3000, 100);
waitForAssert(() -> {
ruleEngine = getService(RuleManager.class);
assertThat("RuleManager service not found", ruleEngine, is(notNullValue()));
}, 3000, 100);
}
@Test
public void checkIfTimerTriggerModuleTypeIsRegistered() {
ModuleTypeRegistry mtr = getService(ModuleTypeRegistry.class);
waitForAssert(() -> {
assertThat(mtr.get(GenericCronTriggerHandler.MODULE_TYPE_ID), is(notNullValue()));
}, 3000, 100);
}
@Test
public void checkDisableAndEnableOfTimerTriggeredRule() {
/*
* Create Rule
*/
logger.info("Create rule");
String testExpression = "* * * * * ?";
;
Configuration triggerConfig = new Configuration(Collections.singletonMap("cronExpression", testExpression));
List<Trigger> triggers = Collections.singletonList(ModuleBuilder.createTrigger().withId("MyTimerTrigger")
.withTypeUID(GenericCronTriggerHandler.MODULE_TYPE_ID).withConfiguration(triggerConfig).build());
Rule rule = RuleBuilder.create("MyRule" + new Random().nextInt()).withTriggers(triggers)
.withName("MyTimerTriggerTestEnableDisableRule").build();
logger.info("Rule created: {}", rule.getUID());
logger.info("Add rule");
ruleRegistry.add(rule);
logger.info("Rule added");
int numberOfTests = 1000;
for (int i = 0; i < numberOfTests; ++i) {
logger.info("Disable rule");
ruleEngine.setEnabled(rule.getUID(), false);
waitForAssert(() -> {
final RuleStatusInfo ruleStatus = ruleEngine.getStatusInfo(rule.getUID());
logger.info("Rule status (should be DISABLED): {}", ruleStatus);
assertThat(ruleStatus.getStatusDetail(), is(RuleStatusDetail.DISABLED));
});
logger.info("Rule is disabled");
logger.info("Enable rule");
ruleEngine.setEnabled(rule.getUID(), true);
waitForAssert(() -> {
final RuleStatusInfo ruleStatus = ruleEngine.getStatusInfo(rule.getUID());
logger.info("Rule status (should be IDLE or RUNNING): {}", ruleStatus);
boolean allFine;
if (ruleStatus.getStatus().equals(RuleStatus.IDLE)
|| ruleStatus.getStatus().equals(RuleStatus.RUNNING)) {
allFine = true;
} else {
allFine = false;
}
assertThat(allFine, is(true));
});
logger.info("Rule is enabled");
}
}
@Test
public void assertThatTimerTriggerWorks() {
String testItemName = "myLampItem";
List<Event> itemEvents = new LinkedList<>();
EventSubscriber itemEventHandler = new EventSubscriber() {
@Override
public void receive(Event event) {
if (event.getTopic().contains(testItemName)) {
itemEvents.add(event);
}
};
@Override
public java.util.Set<String> getSubscribedEventTypes() {
return Collections.singleton(ItemCommandEvent.TYPE);
}
@Override
public EventFilter getEventFilter() {
return null;
};
};
registerService(itemEventHandler);
/*
* Create Rule
*/
logger.info("Create rule");
String testExpression = "* * * * * ?";
Configuration triggerConfig = new Configuration(Collections.singletonMap("cronExpression", testExpression));
List<Trigger> triggers = Collections.singletonList(ModuleBuilder.createTrigger().withId("MyTimerTrigger")
.withTypeUID(GenericCronTriggerHandler.MODULE_TYPE_ID).withConfiguration(triggerConfig).build());
Map<String, Object> cfgEntries = new HashMap<>();
cfgEntries.put("itemName", testItemName);
cfgEntries.put("command", "ON");
Configuration actionConfig = new Configuration(cfgEntries);
List<Action> actions = Collections.singletonList(ModuleBuilder.createAction().withId("MyItemPostCommandAction")
.withTypeUID("core.ItemCommandAction").withConfiguration(actionConfig).build());
Rule rule = RuleBuilder.create("MyRule" + new Random().nextInt()).withTriggers(triggers).withActions(actions)
.withName("MyTimerTriggerTestRule").build();
logger.info("Rule created: {}", rule.getUID());
logger.info("Add rule");
ruleRegistry.add(rule);
logger.info("Rule added");
logger.info("Enable rule and wait for idle status");
ruleEngine.setEnabled(rule.getUID(), true);
waitForAssert(() -> {
final RuleStatusInfo ruleStatus = ruleEngine.getStatusInfo(rule.getUID());
assertThat(ruleStatus.getStatus(), is(RuleStatus.IDLE));
});
logger.info("Rule is enabled and idle");
waitForAssert(() -> {
assertThat(itemEvents.size(), is(3));
});
}
class TestItemProvider implements ItemProvider {
private final Collection<Item> items;
TestItemProvider(Collection<Item> items) {
this.items = items;
}
@Override
public Collection<Item> getAll() {
return items;
}
@Override
public void addProviderChangeListener(@NonNull ProviderChangeListener<@NonNull Item> listener) {
}
@Override
public void removeProviderChangeListener(@NonNull ProviderChangeListener<@NonNull Item> listener) {
}
}
}
@@ -0,0 +1,121 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.automation.module.timer.internal;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
import java.time.Duration;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.smarthome.automation.Condition;
import org.eclipse.smarthome.automation.core.util.ModuleBuilder;
import org.eclipse.smarthome.automation.module.timer.handler.DayOfWeekConditionHandler;
import org.eclipse.smarthome.automation.module.timer.handler.TimeOfDayConditionHandler;
import org.eclipse.smarthome.automation.type.ModuleTypeRegistry;
import org.eclipse.smarthome.config.core.Configuration;
import org.junit.Test;
/**
* This tests the TimeOfDay Condition.
*
* @author Dominik Schlierf - initial contribution
*
*/
public class TimeOfDayConditionHandlerTest extends BasicConditionHandlerTest {
public TimeOfDayConditionHandlerTest() {
}
/**
* This checks if the condition on its own works properly.
*/
@Test
public void assertThatConditionWorks() {
LocalTime currentTime = LocalTime.now().truncatedTo(ChronoUnit.MINUTES);
LocalTime beforeCurrentTime = currentTime.minus(Duration.ofMinutes(2));
LocalTime afterCurrentTime = currentTime.plus(Duration.ofMinutes(2));
// Time is between start and end time -> should return true.
TimeOfDayConditionHandler handler = getTimeOfDayConditionHandler(beforeCurrentTime.toString(),
afterCurrentTime.toString());
assertThat(handler.isSatisfied(null), is(true));
// Time is equal to start time -> should return true
handler = getTimeOfDayConditionHandler(currentTime.toString(), afterCurrentTime.toString());
assertThat(handler.isSatisfied(null), is(true));
// Time is equal to end time -> should return false
handler = getTimeOfDayConditionHandler(beforeCurrentTime.toString(), currentTime.toString());
assertThat(handler.isSatisfied(null), is(false));
// Start value is in the future & end value is in the past
// -> should return false
handler = getTimeOfDayConditionHandler(afterCurrentTime.toString(), beforeCurrentTime.toString());
assertThat(handler.isSatisfied(null), is(false));
// Start & end time are in the future & start time is after the end time
// -> should return true
handler = getTimeOfDayConditionHandler(afterCurrentTime.plus(Duration.ofMinutes(2)).toString(),
afterCurrentTime.toString());
assertThat(handler.isSatisfied(null), is(true));
}
private TimeOfDayConditionHandler getTimeOfDayConditionHandler(String startTime, String endTime) {
TimeOfDayConditionHandler handler = new TimeOfDayConditionHandler(getTimeCondition(startTime, endTime));
return handler;
}
private Condition getTimeCondition(String startTime, String endTime) {
Configuration timeConfig = getTimeConfiguration(startTime, endTime);
Condition condition = ModuleBuilder.createCondition().withId("testTimeOfDayCondition")
.withTypeUID(TimeOfDayConditionHandler.MODULE_TYPE_ID).withConfiguration(timeConfig).build();
return condition;
}
private Configuration getTimeConfiguration(String startTime, String endTime) {
Map<String, Object> timeMap = new HashMap<>();
timeMap.put("startTime", startTime);
timeMap.put("endTime", endTime);
Configuration timeConfig = new Configuration(timeMap);
return timeConfig;
}
@Override
public Condition getPassingCondition() {
LocalTime currentTime = LocalTime.now().truncatedTo(ChronoUnit.MINUTES);
LocalTime beforeCurrentTime = currentTime.minus(Duration.ofMinutes(2));
LocalTime afterCurrentTime = currentTime.plus(Duration.ofMinutes(2));
return getTimeCondition(beforeCurrentTime.toString(), afterCurrentTime.toString());
}
@Override
public Configuration getFailingConfiguration() {
LocalTime currentTime = LocalTime.now().truncatedTo(ChronoUnit.MINUTES);
LocalTime beforeCurrentTime = currentTime.minus(Duration.ofMinutes(2));
LocalTime afterCurrentTime = currentTime.plus(Duration.ofMinutes(2));
return getTimeConfiguration(afterCurrentTime.toString(), beforeCurrentTime.toString());
}
@SuppressWarnings("null")
@Test
public void checkIfModuleTypeIsRegistered() {
ModuleTypeRegistry mtr = getService(ModuleTypeRegistry.class);
waitForAssert(() -> {
assertThat(mtr.get(DayOfWeekConditionHandler.MODULE_TYPE_ID), is(notNullValue()));
}, 3000, 100);
}
}
@@ -0,0 +1,59 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.automation.module.timer.internal;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
import org.eclipse.smarthome.automation.RuleRegistry;
import org.eclipse.smarthome.automation.module.timer.handler.TimeOfDayTriggerHandler;
import org.eclipse.smarthome.automation.type.ModuleTypeRegistry;
import org.eclipse.smarthome.test.java.JavaOSGiTest;
import org.eclipse.smarthome.test.storage.VolatileStorageService;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* this tests the timeOfDay trigger
*
* @author Kai Kreuzer - initial contribution
*
*/
public class TimeOfDayTriggerHandlerTest extends JavaOSGiTest {
final Logger logger = LoggerFactory.getLogger(RuntimeRuleTest.class);
VolatileStorageService volatileStorageService = new VolatileStorageService();
RuleRegistry ruleRegistry;
public TimeOfDayTriggerHandlerTest() {
}
@Before
public void before() {
registerService(volatileStorageService);
waitForAssert(() -> {
ruleRegistry = getService(RuleRegistry.class);
assertThat(ruleRegistry, is(notNullValue()));
}, 3000, 100);
}
@Test
public void checkIfModuleTypeIsRegistered() {
ModuleTypeRegistry mtr = getService(ModuleTypeRegistry.class);
waitForAssert(() -> {
assertThat(mtr.get(TimeOfDayTriggerHandler.MODULE_TYPE_ID), is(notNullValue()));
}, 3000, 100);
}
}
@@ -0,0 +1,19 @@
This content is produced and maintained by the Eclipse SmartHome project.
* Project home: https://eclipse.org/smarthome/
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/eclipse/smarthome
== Copyright Holders
See the NOTICE file distributed with the source code at
https://github.com/eclipse/smarthome/blob/master/NOTICE
for detailed information regarding copyright ownership.
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.pde.ui.JunitLaunchConfig">
<booleanAttribute key="append.args" value="true"/>
<stringAttribute key="application" value="org.eclipse.pde.junit.runtime.coretestapplication"/>
<booleanAttribute key="askclear" value="false"/>
<booleanAttribute key="automaticAdd" value="false"/>
<booleanAttribute key="automaticValidate" value="true"/>
<stringAttribute key="bootstrap" value=""/>
<stringAttribute key="checked" value="[NONE]"/>
<booleanAttribute key="clearConfig" value="true"/>
<booleanAttribute key="clearws" value="true"/>
<booleanAttribute key="clearwslog" value="false"/>
<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/pde-junit"/>
<booleanAttribute key="default" value="false"/>
<booleanAttribute key="includeOptional" value="false"/>
<stringAttribute key="location" value="${workspace_loc}/../junit-workspace"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/org.eclipse.smarthome.core.binding.xml.test"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.smarthome.core.binding.xml.test"/>
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.smarthome.core.binding.xml.test"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="pde.version" value="3.3"/>
<stringAttribute key="product" value="org.eclipse.equinox.p2.director.app.product"/>
<booleanAttribute key="run_in_ui_thread" value="false"/>
<stringAttribute key="selected_target_plugins" value="ch.qos.logback.classic@default:default,ch.qos.logback.core@default:default,ch.qos.logback.slf4j@default:false,com.google.gson@default:default,com.google.guava@default:default,javax.measure.unit-api@default:default,javax.servlet@default:default,javax.transaction@default:false,javax.xml@default:default,net.bytebuddy.byte-buddy-agent@default:default,net.bytebuddy.byte-buddy@default:default,org.apache.ant@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.felix.scr@1:true,org.codehaus.groovy@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.runtime@default:true,org.eclipse.equinox.app@default:default,org.eclipse.equinox.cm@3:true,org.eclipse.equinox.common@2:true,org.eclipse.equinox.ds@1:true,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.registry@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.equinox.util@default:default,org.eclipse.equinox.weaving.hook@default:false,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi.util@default:default,org.eclipse.osgi@-1:true,org.hamcrest.core@default:default,org.junit@default:default,org.mockito.mockito-core@default:default,org.objenesis@default:default,org.slf4j.api@default:default,org.slf4j.log4j@default:default,tec.uom.lib.uom-lib-common@default:default,tec.uom.se@default:default"/>
<stringAttribute key="selected_workspace_plugins" value="org.eclipse.smarthome.config.core@default:true,org.eclipse.smarthome.config.xml@default:true,org.eclipse.smarthome.core.binding.xml.test@default:false,org.eclipse.smarthome.core.binding.xml@default:true,org.eclipse.smarthome.core@default:true,org.eclipse.smarthome.io.console@default:default,org.eclipse.smarthome.test@default:true"/>
<booleanAttribute key="show_selected_only" value="false"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfig" value="true"/>
<booleanAttribute key="useDefaultConfigArea" value="false"/>
<booleanAttribute key="useProduct" value="false"/>
</launchConfiguration>
@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.core.itests</groupId>
<artifactId>org.openhab.core.reactor.itests</artifactId>
<version>2.5.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.core.binding.xml.tests</artifactId>
<packaging>eclipse-test-plugin</packaging>
<name>openHAB Core :: Integration Tests :: Binding XML Tests</name>
<build>
<plugins>
<plugin>
<groupId>${tycho-groupid}</groupId>
<artifactId>target-platform-configuration</artifactId>
<configuration>
<environments combine.self="override"></environments>
<dependency-resolution>
<extraRequirements>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.equinox.cm</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.equinox.ds</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.core</id>
<versionRange>0.0.0</versionRange>
</requirement>
</extraRequirements>
</dependency-resolution>
</configuration>
</plugin>
<plugin>
<groupId>${tycho-groupid}</groupId>
<artifactId>tycho-surefire-plugin</artifactId>
<configuration>
<bundleStartLevel>
<bundle>
<id>org.eclipse.equinox.cm</id>
<level>1</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.ds</id>
<level>1</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.config.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
</bundleStartLevel>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,137 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.core.binding.xml.test;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Set;
import org.eclipse.smarthome.core.binding.BindingInfo;
import org.eclipse.smarthome.core.binding.BindingInfoRegistry;
import org.eclipse.smarthome.core.i18n.LocaleProvider;
import org.eclipse.smarthome.test.SyntheticBundleInstaller;
import org.eclipse.smarthome.test.java.JavaOSGiTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
public class BindingInfoI18nTest extends JavaOSGiTest {
private static final String TEST_BUNDLE_NAME = "yahooweather.bundle";
private BindingInfoRegistry bindingInfoRegistry;
@Before
public void setUp() {
bindingInfoRegistry = getService(BindingInfoRegistry.class);
assertThat(bindingInfoRegistry, is(notNullValue()));
}
@After
public void tearDown() throws BundleException {
SyntheticBundleInstaller.uninstall(bundleContext, TEST_BUNDLE_NAME);
}
@Test
public void assertBindingInfosWereLocalizedInGerman() throws Exception {
int initialNumberOfBindingInfos = bindingInfoRegistry.getBindingInfos().size();
// install test bundle
Bundle bundle = SyntheticBundleInstaller.install(bundleContext, TEST_BUNDLE_NAME);
assertThat(bundle, is(notNullValue()));
Set<BindingInfo> bindingInfos = bindingInfoRegistry.getBindingInfos(Locale.GERMAN);
assertThat(bindingInfos.size(), is(initialNumberOfBindingInfos + 1));
BindingInfo bindingInfo = bindingInfos.iterator().next();
assertThat(bindingInfo, is(notNullValue()));
assertThat(bindingInfo.getName(), is("Yahoo Wetter Binding"));
assertThat(bindingInfo.getDescription(), is(
"Das Yahoo Wetter Binding stellt verschiedene Wetterdaten wie die Temperatur, die Luftfeuchtigkeit und den Luftdruck für konfigurierbare Orte vom yahoo Wetterdienst bereit"));
}
@Test
public void assertBindingInfosWereLocalizedInDutch() throws Exception {
int initialNumberOfBindingInfos = bindingInfoRegistry.getBindingInfos().size();
// install test bundle
Bundle bundle = SyntheticBundleInstaller.install(bundleContext, TEST_BUNDLE_NAME);
assertThat(bundle, is(notNullValue()));
Set<BindingInfo> bindingInfos = bindingInfoRegistry.getBindingInfos(new Locale("nl"));
assertThat(bindingInfos.size(), is(initialNumberOfBindingInfos + 1));
BindingInfo bindingInfo = bindingInfos.iterator().next();
assertThat(bindingInfo, is(notNullValue()));
assertThat(bindingInfo.getName(), is("Yahoo Weer Binding"));
assertThat(bindingInfo.getDescription(), is(
"De Yahoo Weer Binding biedt verschillende meteorologische gegevens zoals temperatuur, vochtigheid en luchtdruk voor configureerbare locaties uit yahoo weerdienst klaar"));
}
@Test
public void assertUsingOriginalBindingInfosIfProvidedLocaleIsNotSupported() throws Exception {
int initialNumberOfBindingInfos = bindingInfoRegistry.getBindingInfos().size();
// install test bundle
Bundle bundle = SyntheticBundleInstaller.install(bundleContext, TEST_BUNDLE_NAME);
assertThat(bundle, is(notNullValue()));
Set<BindingInfo> bindingInfos = bindingInfoRegistry.getBindingInfos(Locale.FRENCH);
assertThat(bindingInfos.size(), is(initialNumberOfBindingInfos + 1));
BindingInfo bindingInfo = bindingInfos.iterator().next();
assertThat(bindingInfo, is(notNullValue()));
assertThat(bindingInfo.getName(), is("YahooWeather Binding"));
assertThat(bindingInfo.getDescription(), is(
"The Yahoo Weather Binding requests the Yahoo Weather Service to show the current temperature, humidity and pressure."));
}
@Test
public void assertUsingDefaultLocale() throws Exception {
// Set german locale
ConfigurationAdmin configAdmin = getService(ConfigurationAdmin.class);
Configuration config = configAdmin.getConfiguration("org.eclipse.smarthome.core.i18nprovider", null);
Dictionary<String, String> localeCfg = new Hashtable<>();
localeCfg.put("language", "de");
localeCfg.put("country", "DE");
config.update(localeCfg);
// before running the test with a default locale make sure the locale has been set
LocaleProvider localeProvider = getService(LocaleProvider.class);
waitForAssert(() -> assertThat(localeProvider.getLocale().toString(), is("de")));
int initialNumberOfBindingInfos = bindingInfoRegistry.getBindingInfos().size();
// install test bundle
Bundle bundle = SyntheticBundleInstaller.install(bundleContext, TEST_BUNDLE_NAME);
assertThat(bundle, is(notNullValue()));
Set<BindingInfo> bindingInfos = bindingInfoRegistry.getBindingInfos(/* use default locale */ null);
assertThat(bindingInfos.size(), is(initialNumberOfBindingInfos + 1));
BindingInfo bindingInfo = bindingInfos.iterator().next();
assertThat(bindingInfo, is(notNullValue()));
assertThat(bindingInfo.getName(), is("Yahoo Wetter Binding"));
assertThat(bindingInfo.getDescription(), is(
"Das Yahoo Wetter Binding stellt verschiedene Wetterdaten wie die Temperatur, die Luftfeuchtigkeit und den Luftdruck für konfigurierbare Orte vom yahoo Wetterdienst bereit"));
}
}
@@ -0,0 +1,162 @@
/**
* Copyright (c) 2014,2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.core.binding.xml.test;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
import java.net.URI;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.smarthome.config.core.ConfigDescription;
import org.eclipse.smarthome.config.core.ConfigDescriptionParameter;
import org.eclipse.smarthome.config.core.ConfigDescriptionRegistry;
import org.eclipse.smarthome.core.binding.BindingInfo;
import org.eclipse.smarthome.core.binding.BindingInfoRegistry;
import org.eclipse.smarthome.test.SyntheticBundleInstaller;
import org.eclipse.smarthome.test.java.JavaOSGiTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
/**
* @author Alex Tugarev - Initial contribution
* @author Wouter Born - Migrate tests from Groovy to Java
*/
public class BindingInfoTest extends JavaOSGiTest {
private static final String TEST_BUNDLE_NAME = "BundleInfoTest.bundle";
private static final String TEST_BUNDLE_NAME2 = "BundleInfoTestNoAuthor.bundle";
private BindingInfoRegistry bindingInfoRegistry;
private ConfigDescriptionRegistry configDescriptionRegistry;
@Before
public void setUp() {
bindingInfoRegistry = getService(BindingInfoRegistry.class);
assertThat(bindingInfoRegistry, is(notNullValue()));
configDescriptionRegistry = getService(ConfigDescriptionRegistry.class);
assertThat(configDescriptionRegistry, is(notNullValue()));
}
@After
public void tearDown() throws BundleException {
SyntheticBundleInstaller.uninstall(bundleContext, TEST_BUNDLE_NAME);
}
@Test
public void assertThatBindingInfoIsReadProperly() throws Exception {
int initialNumberOfBindingInfos = bindingInfoRegistry.getBindingInfos().size();
// install test bundle
Bundle bundle = SyntheticBundleInstaller.install(bundleContext, TEST_BUNDLE_NAME);
assertThat(bundle, is(notNullValue()));
Set<BindingInfo> bindingInfos = bindingInfoRegistry.getBindingInfos();
assertThat(bindingInfos.size(), is(initialNumberOfBindingInfos + 1));
BindingInfo bindingInfo = bindingInfos.iterator().next();
assertThat(bindingInfo.getUID(), is("hue"));
assertThat(bindingInfo.getConfigDescriptionURI(), is(URI.create("binding:hue")));
assertThat(bindingInfo.getDescription(),
is("The hue Binding integrates the Philips hue system. It allows to control hue lights."));
assertThat(bindingInfo.getName(), is("hue Binding"));
assertThat(bindingInfo.getAuthor(), is("Deutsche Telekom AG"));
// uninstall test bundle
bundle.uninstall();
assertThat(bundle.getState(), is(Bundle.UNINSTALLED));
}
@Test
public void assertThatBindingInfoWithoutAuthorIsReadProperly() throws Exception {
int initialNumberOfBindingInfos = bindingInfoRegistry.getBindingInfos().size();
// install test bundle
Bundle bundle = SyntheticBundleInstaller.install(bundleContext, TEST_BUNDLE_NAME2);
assertThat(bundle, is(notNullValue()));
Set<BindingInfo> bindingInfos = bindingInfoRegistry.getBindingInfos();
assertThat(bindingInfos.size(), is(initialNumberOfBindingInfos + 1));
BindingInfo bindingInfo = bindingInfos.iterator().next();
assertThat(bindingInfo.getUID(), is("hue"));
assertThat(bindingInfo.getConfigDescriptionURI(), is(URI.create("binding:hue")));
assertThat(bindingInfo.getDescription(),
is("The hue Binding integrates the Philips hue system. It allows to control hue lights."));
assertThat(bindingInfo.getName(), is("hue Binding"));
assertThat(bindingInfo.getAuthor(), is((String) null));
// uninstall test bundle
bundle.uninstall();
assertThat(bundle.getState(), is(Bundle.UNINSTALLED));
}
@Test
public void assertThatBindingInfoIsRemovedAfterTheBundleWasUninstalled() throws Exception {
int initialNumberOfBindingInfos = bindingInfoRegistry.getBindingInfos().size();
// install test bundle
Bundle bundle = SyntheticBundleInstaller.install(bundleContext, TEST_BUNDLE_NAME);
assertThat(bundle, is(notNullValue()));
Set<BindingInfo> bindingInfos = bindingInfoRegistry.getBindingInfos();
assertThat(bindingInfos.size(), is(initialNumberOfBindingInfos + 1));
BindingInfo bindingInfo = bindingInfos.iterator().next();
// uninstall test bundle
bundle.uninstall();
assertThat(bundle.getState(), is(Bundle.UNINSTALLED));
bindingInfos = bindingInfoRegistry.getBindingInfos();
assertThat(bindingInfos.size(), is(initialNumberOfBindingInfos));
if (initialNumberOfBindingInfos > 0) {
for (BindingInfo bindingInfo_ : bindingInfos) {
assertThat(bindingInfo_.getUID(), is(not(bindingInfo.getUID())));
}
}
}
@Test
public void assertThatConfigWithOptionsAndFilterAreProperlyRead() throws Exception {
int initialNumberOfBindingInfos = bindingInfoRegistry.getBindingInfos().size();
// install test bundle
Bundle bundle = SyntheticBundleInstaller.install(bundleContext, TEST_BUNDLE_NAME);
assertThat(bundle, is(notNullValue()));
Set<BindingInfo> bindingInfos = bindingInfoRegistry.getBindingInfos();
assertThat(bindingInfos.size(), is(initialNumberOfBindingInfos + 1));
BindingInfo bindingInfo = bindingInfos.iterator().next();
URI configDescriptionURI = bindingInfo.getConfigDescriptionURI();
ConfigDescription configDescription = configDescriptionRegistry.getConfigDescription(configDescriptionURI);
List<ConfigDescriptionParameter> parameters = configDescription.getParameters();
assertThat(parameters.size(), is(2));
ConfigDescriptionParameter listParameter = parameters.stream().filter(p -> p.getName().equals("list"))
.findFirst().get();
assertThat(listParameter, is(notNullValue()));
assertThat(listParameter.getOptions().stream().map(p -> p.toString()).collect(Collectors.joining(", ")), is(
"ParameterOption [value=\"key1\", label=\"label1\"], ParameterOption [value=\"key2\", label=\"label2\"]"));
ConfigDescriptionParameter lightParameter = parameters.stream()
.filter(p -> p.getName().equals("color-alarming-light")).findFirst().get();
assertThat(lightParameter, is(notNullValue()));
assertThat(lightParameter.getFilterCriteria().stream().map(p -> p.toString()).collect(Collectors.joining(", ")),
is("FilterCriteria [name=\"tags\", value=\"alarm, light\"], FilterCriteria [name=\"type\", value=\"color\"], FilterCriteria [name=\"binding-id\", value=\"hue\"]"));
}
}
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="http://eclipse.org/smarthome/schemas/binding/v1.0.0"
xsi:schemaLocation="http://eclipse.org/smarthome/schemas/binding/v1.0.0 org.eclipse.smarthome.binding.xsd"
id="hue">
<name>hue Binding</name>
<description>The hue Binding integrates the Philips hue system. It
allows to control hue lights.</description>
<author>Deutsche Telekom AG</author>
<!-- Dummy config -->
<config-description>
<parameter name="list" type="text" multiple="true" min="2" max="3">
<options>
<option value="key1">label1</option>
<option value="key2">label2</option>
</options>
</parameter>
<parameter name="color-alarming-light" type="text" multiple="true">
<context>item</context>
<filter>
<criteria name="tags">alarm, light</criteria>
<criteria name="type">color</criteria>
<criteria name="binding-id">hue</criteria>
</filter>
</parameter>
</config-description>
</binding:binding>
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="hue"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:thing="http://eclipse.org/smarthome/schemas/thing-description/v1.0.0"
xsi:schemaLocation="http://eclipse.org/smarthome/schemas/thing-description/v1.0.0 org.eclipse.smarthome.thing-description.xsd">
<!-- HUE Bridge -->
<bridge-type id="bridge">
<label>HUE Bridge</label>
<description>The hue Bridge represents the Philips hue bridge.</description>
<config-description>
<parameter name="ip" type="text">
<context>network-address</context>
<label>Network Address</label>
<description>Network address of the hue bridge.</description>
<required>true</required>
</parameter>
<parameter name="username" type="text">
<context>password</context>
<label>Username</label>
<description>Name of a registered hue bridge user, that allows to
access the API.
</description>
</parameter>
</config-description>
</bridge-type>
<!-- HUE Lamp -->
<thing-type id="lamp">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge" />
</supported-bridge-type-refs>
<label>HUE Lamp</label>
<description>My own great HUE Lamp.</description>
<channels>
<channel id="color" typeId="color" />
<channel id="color_temperature" typeId="color_temperature" />
</channels>
</thing-type>
<!-- HUE Lamp Color Channel -->
<channel-type id="color">
<item-type>ColorItem</item-type>
<label>HUE Lamp Color</label>
<description>The color channel allows to control the color of the hue
lamp. It is also possible to dim values and switch the lamp on and
off.
</description>
<config-description>
<parameter name="lastDimValue" type="boolean" />
</config-description>
</channel-type>
<!-- HUE Lamp Color Temperature Channel -->
<channel-type id="color_temperature">
<item-type>DimmerItem</item-type>
<label>HUE Lamp Color Temperature</label>
<description>The color temperature channel allows to set the color
temperature from 0 (cold) to 100 (warm).</description>
</channel-type>
</thing:thing-descriptions>
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="http://eclipse.org/smarthome/schemas/binding/v1.0.0"
xsi:schemaLocation="http://eclipse.org/smarthome/schemas/binding/v1.0.0 org.eclipse.smarthome.binding.xsd"
id="hue">
<name>hue Binding</name>
<description>The hue Binding integrates the Philips hue system. It
allows to control hue lights.</description>
<!-- Dummy config -->
<config-description>
<parameter name="list" type="text" multiple="true" min="2" max="3">
<options>
<option value="key1">label1</option>
<option value="key2">label2</option>
</options>
</parameter>
<parameter name="color-alarming-light" type="text" multiple="true">
<context>item</context>
<filter>
<criteria name="tags">alarm, light</criteria>
<criteria name="type">color</criteria>
<criteria name="binding-id">hue</criteria>
</filter>
</parameter>
</config-description>
</binding:binding>
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="hue"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:thing="http://eclipse.org/smarthome/schemas/thing-description/v1.0.0"
xsi:schemaLocation="http://eclipse.org/smarthome/schemas/thing-description/v1.0.0 org.eclipse.smarthome.thing-description.xsd">
<!-- HUE Bridge -->
<bridge-type id="bridge">
<label>HUE Bridge</label>
<description>The hue Bridge represents the Philips hue bridge.</description>
<config-description>
<parameter name="ip" type="text">
<context>network-address</context>
<label>Network Address</label>
<description>Network address of the hue bridge.</description>
<required>true</required>
</parameter>
<parameter name="username" type="text">
<context>password</context>
<label>Username</label>
<description>Name of a registered hue bridge user, that allows to
access the API.
</description>
</parameter>
</config-description>
</bridge-type>
<!-- HUE Lamp -->
<thing-type id="lamp">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge" />
</supported-bridge-type-refs>
<label>HUE Lamp</label>
<description>My own great HUE Lamp.</description>
<channels>
<channel id="color" typeId="color" />
<channel id="color_temperature" typeId="color_temperature" />
</channels>
</thing-type>
<!-- HUE Lamp Color Channel -->
<channel-type id="color">
<item-type>ColorItem</item-type>
<label>HUE Lamp Color</label>
<description>The color channel allows to control the color of the hue
lamp. It is also possible to dim values and switch the lamp on and
off.
</description>
<config-description>
<parameter name="lastDimValue" type="boolean" />
</config-description>
</channel-type>
<!-- HUE Lamp Color Temperature Channel -->
<channel-type id="color_temperature">
<item-type>DimmerItem</item-type>
<label>HUE Lamp Color Temperature</label>
<description>The color temperature channel allows to set the color
temperature from 0 (cold) to 100 (warm).</description>
</channel-type>
</thing:thing-descriptions>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="yahooweather"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="http://eclipse.org/smarthome/schemas/binding/v1.0.0"
xsi:schemaLocation="http://eclipse.org/smarthome/schemas/binding/v1.0.0 http://eclipse.org/smarthome/schemas/binding-1.0.0.xsd">
<name>YahooWeather Binding</name>
<description>The Yahoo Weather Binding requests the Yahoo Weather Service
to show the current temperature, humidity and pressure.</description>
<author>Kai Kreuzer</author>
</binding:binding>
@@ -0,0 +1,3 @@
# binding
binding.yahooweather.name = Yahoo Wetter Binding
binding.yahooweather.description = Das Yahoo Wetter Binding stellt verschiedene Wetterdaten wie die Temperatur, die Luftfeuchtigkeit und den Luftdruck für konfigurierbare Orte vom yahoo Wetterdienst bereit
@@ -0,0 +1,4 @@
# translate.google.de
# :-)
binding.yahooweather.name = Yahoo Weer Binding
binding.yahooweather.description = De Yahoo Weer Binding biedt verschillende meteorologische gegevens zoals temperatuur, vochtigheid en luchtdruk voor configureerbare locaties uit yahoo weerdienst klaar
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.openhab.core.compat1x.tests</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>
@@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8
@@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1
@@ -0,0 +1,13 @@
This content is produced and maintained by the openHAB project.
* Project home: https://www.openhab.org
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/openhab/openhab-core
@@ -0,0 +1,110 @@
-standalone: \
../../bom/runtime-index/target/index.xml;name="runtime",\
../../bom/test-index/target/index.xml;name="test",\
target/index.xml;name="self"
-resolve.effective: active
# Run all integration tests which are named xyzTest
Test-Cases: ${classes;CONCRETE;PUBLIC;NAMED;*Test}
# A temporary inclusion until an R7 framework is available
Import-Package: org.osgi.framework.*;version="[1.8,2)",*
Bundle-SymbolicName: ${project.artifactId}
Fragment-Host: org.openhab.core.compat1x
Provide-Capability: osgi.service;objectClass:List<String>="org.eclipse.smarthome.core.storage.StorageService"
# Used by Objenesis/Mockito and not actually optional
-runsystempackages: sun.reflect
-runfw: org.eclipse.osgi
-runee: JavaSE-1.8
-runrequires: bnd.identity;id='org.openhab.core.compat1x.tests'
#
# done
#
-runbundles: \
ch.qos.logback.classic;version='[1.2.0,1.2.1)',\
ch.qos.logback.core;version='[1.2.0,1.2.1)',\
com.google.gson;version='[2.7.0,2.7.1)',\
com.google.guava;version='[15.0.0,15.0.1)',\
com.google.inject;version='[3.0.0,3.0.1)',\
javax.measure.unit-api;version='[1.0.0,1.0.1)',\
joda-time;version='[2.9.2,2.9.3)',\
log4j;version='[1.2.17,1.2.18)',\
org.antlr.runtime;version='[3.2.0,3.2.1)',\
org.apache.commons.collections;version='[3.2.1,3.2.2)',\
org.apache.commons.exec;version='[1.1.0,1.1.1)',\
org.apache.commons.io;version='[2.2.0,2.2.1)',\
org.apache.commons.lang;version='[2.6.0,2.6.1)',\
org.apache.felix.configadmin;version='[1.9.8,1.9.9)',\
org.apache.felix.http.servlet-api;version='[1.1.2,1.1.3)',\
org.apache.felix.scr;version='[2.1.10,2.1.11)',\
org.apache.servicemix.bundles.commons-codec;version='[1.3.0,1.3.1)',\
org.apache.servicemix.bundles.commons-httpclient;version='[3.1.0,3.1.1)',\
org.apache.xbean.bundleutils;version='[4.6.0,4.6.1)',\
org.apache.xbean.finder;version='[4.6.0,4.6.1)',\
org.eclipse.emf.common;version='[2.12.0,2.12.1)',\
org.eclipse.emf.ecore;version='[2.12.0,2.12.1)',\
org.eclipse.emf.ecore.xmi;version='[2.12.0,2.12.1)',\
org.eclipse.equinox.common;version='[3.8.0,3.8.1)',\
org.eclipse.equinox.event;version='[1.4.300,1.4.301)',\
org.eclipse.jetty.client;version='[9.4.11,9.4.12)',\
org.eclipse.jetty.http;version='[9.4.11,9.4.12)',\
org.eclipse.jetty.io;version='[9.4.11,9.4.12)',\
org.eclipse.jetty.proxy;version='[9.4.11,9.4.12)',\
org.eclipse.jetty.security;version='[9.4.11,9.4.12)',\
org.eclipse.jetty.server;version='[9.4.11,9.4.12)',\
org.eclipse.jetty.servlet;version='[9.4.11,9.4.12)',\
org.eclipse.jetty.util;version='[9.4.11,9.4.12)',\
org.eclipse.jetty.websocket.api;version='[9.4.11,9.4.12)',\
org.eclipse.jetty.websocket.client;version='[9.4.11,9.4.12)',\
org.eclipse.jetty.websocket.common;version='[9.4.11,9.4.12)',\
org.eclipse.jetty.xml;version='[9.4.11,9.4.12)',\
org.eclipse.xtend.lib;version='[2.14.0,2.14.1)',\
org.eclipse.xtend.lib.macro;version='[2.14.0,2.14.1)',\
org.eclipse.xtext;version='[2.14.0,2.14.1)',\
org.eclipse.xtext.common.types;version='[2.14.0,2.14.1)',\
org.eclipse.xtext.util;version='[2.14.0,2.14.1)',\
org.eclipse.xtext.xbase;version='[2.14.0,2.14.1)',\
org.eclipse.xtext.xbase.lib;version='[2.14.0,2.14.1)',\
org.glassfish.hk2.external.aopalliance-repackaged;version='[2.4.0,2.4.1)',\
org.glassfish.hk2.external.javax.inject;version='[2.4.0,2.4.1)',\
org.objectweb.asm;version='[6.1.1,6.1.2)',\
org.objectweb.asm.commons;version='[6.1.1,6.1.2)',\
org.objectweb.asm.tree;version='[6.1.1,6.1.2)',\
org.openhab.core.compat1x;version='[2.5.0,2.5.1)',\
org.ops4j.pax.swissbox.optional.jcl;version='[1.8.2,1.8.3)',\
org.ops4j.pax.web.pax-web-api;version='[7.2.3,7.2.4)',\
org.ops4j.pax.web.pax-web-jetty;version='[7.2.3,7.2.4)',\
org.ops4j.pax.web.pax-web-runtime;version='[7.2.3,7.2.4)',\
org.ops4j.pax.web.pax-web-spi;version='[7.2.3,7.2.4)',\
org.osgi.service.event;version='[1.4.0,1.4.1)',\
slf4j.api;version='[1.7.21,1.7.22)',\
tec.uom.lib.uom-lib-common;version='[1.0.2,1.0.3)',\
tec.uom.se;version='[1.0.8,1.0.9)',\
osgi.enroute.hamcrest.wrapper;version='[1.3.0,1.3.1)',\
osgi.enroute.junit.wrapper;version='[4.12.0,4.12.1)',\
org.openhab.core;version='[2.5.0,2.5.1)',\
org.openhab.core.audio;version='[2.5.0,2.5.1)',\
org.openhab.core.compat1x.tests;version='[2.5.0,2.5.1)',\
org.openhab.core.config.core;version='[2.5.0,2.5.1)',\
org.openhab.core.io.console;version='[2.5.0,2.5.1)',\
org.openhab.core.io.http;version='[2.5.0,2.5.1)',\
org.openhab.core.io.net;version='[2.5.0,2.5.1)',\
org.openhab.core.model.core;version='[2.5.0,2.5.1)',\
org.openhab.core.model.item;version='[2.5.0,2.5.1)',\
org.openhab.core.model.item.runtime;version='[2.5.0,2.5.1)',\
org.openhab.core.model.persistence;version='[2.5.0,2.5.1)',\
org.openhab.core.model.script;version='[2.5.0,2.5.1)',\
org.openhab.core.model.script.runtime;version='[2.5.0,2.5.1)',\
org.openhab.core.model.sitemap;version='[2.5.0,2.5.1)',\
org.openhab.core.persistence;version='[2.5.0,2.5.1)',\
org.openhab.core.scheduler;version='[2.5.0,2.5.1)',\
org.openhab.core.thing;version='[2.5.0,2.5.1)',\
org.openhab.core.transform;version='[2.5.0,2.5.1)',\
org.openhab.core.ui;version='[2.5.0,2.5.1)',\
org.openhab.core.voice;version='[2.5.0,2.5.1)'
@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.core.itests</groupId>
<artifactId>org.openhab.core.reactor.itests</artifactId>
<version>2.5.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.core.compat1x.tests</artifactId>
<name>openHAB Core :: Integration Tests :: 1.x Compatibility Layer Tests</name>
<dependencies>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.compat1x</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.model.item.runtime</artifactId>
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.model.script.runtime</artifactId>
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.scheduler</artifactId>
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.openhab.core.bom</groupId>
<artifactId>org.openhab.core.bom.test</artifactId>
<type>pom</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.openhab.core.bom</groupId>
<artifactId>org.openhab.core.bom.compile</artifactId>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.openhab.core.bom</groupId>
<artifactId>org.openhab.core.bom.runtime-index</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.openhab.core.bom</groupId>
<artifactId>org.openhab.core.bom.test-index</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>biz.aQute.bnd</groupId>
<artifactId>bnd-maven-plugin</artifactId>
<configuration>
<bndfile>integration-test.bndrun</bndfile>
</configuration>
</plugin>
<plugin>
<groupId>biz.aQute.bnd</groupId>
<artifactId>bnd-indexer-maven-plugin</artifactId>
<configuration>
<includeJar>true</includeJar>
</configuration>
</plugin>
<plugin>
<groupId>biz.aQute.bnd</groupId>
<artifactId>bnd-testing-maven-plugin</artifactId>
<configuration>
<bndruns>
<bndrun>integration-test.bndrun</bndrun>
</bndruns>
</configuration>
</plugin>
<plugin>
<groupId>biz.aQute.bnd</groupId>
<artifactId>bnd-resolver-maven-plugin</artifactId>
<configuration>
<bndruns>
<bndrun>integration-test.bndrun</bndrun>
</bndruns>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,109 @@
/**
* Copyright (c) 2010-2019 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.core.compat1x.internal;
import static org.junit.Assert.*;
import org.eclipse.smarthome.core.items.GroupItem;
import org.eclipse.smarthome.core.library.items.CallItem;
import org.eclipse.smarthome.core.library.items.ColorItem;
import org.eclipse.smarthome.core.library.items.ContactItem;
import org.eclipse.smarthome.core.library.items.DateTimeItem;
import org.eclipse.smarthome.core.library.items.DimmerItem;
import org.eclipse.smarthome.core.library.items.NumberItem;
import org.eclipse.smarthome.core.library.items.RollershutterItem;
import org.eclipse.smarthome.core.library.items.StringItem;
import org.eclipse.smarthome.core.library.items.SwitchItem;
import org.eclipse.smarthome.core.library.types.StringType;
import org.eclipse.smarthome.core.types.UnDefType;
import org.junit.Test;
import org.openhab.core.items.Item;
public class ItemMapperTest {
@Test
public void testESH2OHItemMapping() {
Item item = null;
item = ItemMapper.mapToOpenHABItem(new StringItem("test1"));
assertEquals(org.openhab.core.library.items.StringItem.class, item.getClass());
assertEquals("test1", item.getName());
item = ItemMapper.mapToOpenHABItem(new NumberItem("test2"));
assertEquals(org.openhab.core.library.items.NumberItem.class, item.getClass());
assertEquals("test2", item.getName());
item = ItemMapper.mapToOpenHABItem(new DimmerItem("test3"));
assertEquals(org.openhab.core.library.items.DimmerItem.class, item.getClass());
assertEquals("test3", item.getName());
item = ItemMapper.mapToOpenHABItem(new RollershutterItem("test4"));
assertEquals(org.openhab.core.library.items.RollershutterItem.class, item.getClass());
assertEquals("test4", item.getName());
item = ItemMapper.mapToOpenHABItem(new ColorItem("test5"));
assertEquals(org.openhab.core.library.items.ColorItem.class, item.getClass());
assertEquals("test5", item.getName());
item = ItemMapper.mapToOpenHABItem(new ContactItem("test6"));
assertEquals(org.openhab.core.library.items.ContactItem.class, item.getClass());
assertEquals("test6", item.getName());
item = ItemMapper.mapToOpenHABItem(new DateTimeItem("test7"));
assertEquals(org.openhab.core.library.items.DateTimeItem.class, item.getClass());
assertEquals("test7", item.getName());
item = ItemMapper.mapToOpenHABItem(new SwitchItem("test8"));
assertEquals(org.openhab.core.library.items.SwitchItem.class, item.getClass());
assertEquals("test8", item.getName());
item = ItemMapper.mapToOpenHABItem(new CallItem("test9"));
assertEquals(org.openhab.library.tel.items.CallItem.class, item.getClass());
assertEquals("test9", item.getName());
}
@Test
public void testGroupItemMapping() {
org.openhab.core.items.GroupItem group = (org.openhab.core.items.GroupItem) ItemMapper
.mapToOpenHABItem(new GroupItem("group1"));
assertEquals("group1", group.getName());
assertNull(group.getBaseItem());
group = (org.openhab.core.items.GroupItem) ItemMapper
.mapToOpenHABItem(new GroupItem("group2", new NumberItem("baseItem")));
assertEquals("group2", group.getName());
assertEquals(org.openhab.core.library.items.NumberItem.class, group.getBaseItem().getClass());
GroupItem eshGroup = new GroupItem("group3");
for (int i = 1; i <= 10; i++) {
eshGroup.addMember(new StringItem(Integer.toString(i)));
}
group = (org.openhab.core.items.GroupItem) ItemMapper.mapToOpenHABItem(eshGroup);
assertEquals("group3", group.getName());
assertEquals(10, group.getMembers().size());
assertEquals(org.openhab.core.library.items.StringItem.class, group.getMembers().iterator().next().getClass());
}
@Test
public void testItemStateMapping() {
StringItem item = new StringItem("test");
item.setState(UnDefType.NULL);
assertEquals(org.openhab.core.types.UnDefType.NULL, ItemMapper.mapToOpenHABItem(item).getState());
item.setState(UnDefType.UNDEF);
assertEquals(org.openhab.core.types.UnDefType.UNDEF, ItemMapper.mapToOpenHABItem(item).getState());
item.setState(new StringType("ABC"));
assertEquals(new org.openhab.core.library.types.StringType("ABC"),
ItemMapper.mapToOpenHABItem(item).getState());
}
}
@@ -0,0 +1,47 @@
/**
* Copyright (c) 2010-2019 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.core.compat1x.internal;
import static org.junit.Assert.assertEquals;
import javax.measure.quantity.Temperature;
import org.eclipse.smarthome.core.library.types.DecimalType;
import org.eclipse.smarthome.core.library.types.QuantityType;
import org.junit.Test;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.library.tel.types.CallType;
public class TypeMapperTest {
@Test
public void testDateTypeType() {
DateTimeType ohType1 = new DateTimeType();
DateTimeType ohType2 = (DateTimeType) TypeMapper.mapToOpenHABType(TypeMapper.mapToESHType(ohType1));
assertEquals(ohType1.toString(), ohType2.toString());
}
@Test
public void testCallType() {
CallType ohType1 = new CallType("123##456");
CallType ohType2 = (CallType) TypeMapper.mapToOpenHABType(TypeMapper.mapToESHType(ohType1));
assertEquals(ohType1, ohType2);
}
@Test
public void testQuantityType() {
QuantityType<Temperature> eshType1 = new QuantityType<>("10 °C");
DecimalType eshType2 = (DecimalType) TypeMapper.mapToESHType(TypeMapper.mapToOpenHABType(eshType1));
assertEquals(eshType1.as(DecimalType.class), eshType2);
}
}

Some files were not shown because too many files have changed in this diff Show More