This repository has been archived by the owner on May 7, 2020. It is now read-only.
/
OSGiTest.groovy
216 lines (196 loc) · 8.49 KB
/
OSGiTest.groovy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/**
* Copyright (c) 2014-2015 openHAB UG (haftungsbeschraenkt) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.smarthome.test
import static org.hamcrest.CoreMatchers.*
import static org.junit.Assert.*
import static org.junit.matchers.JUnitMatchers.*
import org.eclipse.smarthome.core.autoupdate.AutoUpdateBindingConfigProvider
import org.eclipse.smarthome.test.storage.VolatileStorageService
import org.junit.After
import org.junit.Assert
import org.junit.Before
import org.osgi.framework.BundleContext
import org.osgi.framework.FrameworkUtil
import org.osgi.framework.ServiceReference
import org.osgi.framework.ServiceRegistration
/**
* {@link OSGiTest} is an abstract base class for OSGi based tests. It provides
* convenience methods to register and unregister mocks as OSGi services. All services, which
* are registered through the {@link OSGiTest#registerService} methods, are unregistered
* automatically in the tear down of the test.
*
* @author Dennis Nobel - Initial contribution
*/
abstract class OSGiTest {
BundleContext bundleContext
Map<String, ServiceRegistration<?>> registeredServices = [:]
@Before
public void bindBundleContext() {
bundleContext = getBundleContext()
assertThat bundleContext, is(notNullValue())
}
/**
* Returns the {@link BundleContext}, which is used for registration and unregistration of OSGi
* services. By default it uses the bundle context of the test class itself. This method can be overridden
* by concrete implementations to provide another bundle context.
*
* @return bundle context
*/
protected BundleContext getBundleContext() {
def bundle = FrameworkUtil.getBundle(this.getClass())
return bundle?.getBundleContext()
}
/**
* Returns an OSGi service for the given class.
*
* @param clazz class under which the OSGi service is registered
* @return OSGi service or null if no service can be found for the given class
*/
protected <T> T getService(Class<T> clazz){
def serviceReference = bundleContext.getServiceReference(clazz.name)
return serviceReference ? bundleContext.getService(serviceReference) : null
}
/**
* Returns an OSGi service for the given class and the given filter.
*
* @param clazz class under which the OSGi service is registered
* @param filter
* @return OSGi service or null if no service can be found for the given class
*/
protected <T> T getService(Class<T> clazz, Closure<Boolean> filter){
def serviceReferences = bundleContext.getServiceReferences(clazz.name, null)
def filteredServiceReferences = serviceReferences.findAll(filter)
if (filteredServiceReferences.size() > 1) {
Assert.fail("More than 1 service matching the filter is registered.")
}
if (filteredServiceReferences.empty) {
null
} else {
bundleContext.getService(filteredServiceReferences.first())
}
}
/**
* Returns an OSGi service for the given class and the given filter.
*
* @param clazz class under which the OSGi service is registered
* @param filter
* @return OSGi service or null if no service can be found for the given class
*/
protected <T> T getService(Class<T> clazz, Class<? extends T> implementationClass){
getService(clazz, {ServiceReference<?> serviceReference -> implementationClass.isAssignableFrom(bundleContext.getService(serviceReference).getClass())})
}
/**
* Registers the given object as OSGi service. The first interface is used as OSGi service
* interface name.
*
* @param service service to be registered
* @param properties OSGi service properties
* @return service registration object
*/
protected registerService(def service, Hashtable properties = [:]) {
def interfaceName = getInterfaceName(service)
assertThat interfaceName, is(notNullValue())
registeredServices.put(interfaceName, bundleContext.registerService(interfaceName, service, properties))
}
/**
* Registers the given object as OSGi service. The given interface name as String is used as OSGi service
* interface name.
*
* @param service service to be registered
* @param interfaceName interface name of the OSGi service
* @param properties OSGi service properties
* @return service registration object
*/
protected registerService(def service, String interfaceName, Hashtable properties = [:]) {
assertThat interfaceName, is(notNullValue())
registeredServices.put(interfaceName, bundleContext.registerService(interfaceName, service, properties))
}
/**
* Unregisters an OSGi service by the given object, that was registered before. If the object is
* a String the service is unregistered by the interface name. If the given service parameter is
* the service itself the interface name is taken from the first interface of the service object.
*
* @param service service or service interface name
* @return the service registration that was unregistered or null if no service could be found
*/
protected unregisterService(def service) {
def interfaceName = service instanceof String ? service : getInterfaceName(service)
registeredServices.get(interfaceName)?.unregister()
registeredServices.remove(interfaceName)
}
/**
* When this method is called it waits until the condition is fulfilled or the timeout is reached.
* The condition is specified by a closure, that must return a boolean object. When the condition is
* not fulfilled Thread.sleep is called at the current Thread for a specified time. After this time
* the condition is checked again. By a default the specified sleep time is 50 ms. The default timeout
* is 1000 ms.
*
* @param condition closure that must not have an argument and must return a boolean value
* @param timeout timeout, default is 1000ms
* @param sleepTime interval for checking the condition, default is 50ms
*/
protected void waitFor(Closure<?> condition, int timeout = 1000, int sleepTime = 50) {
def waitingTime = 0
while(!condition() && waitingTime < timeout) {
waitingTime += sleepTime
sleep sleepTime
}
}
/**
* When this method is called it waits until the assertion is fulfilled or the timeout is reached.
* The assertion is specified by a closure, that must throw an Exception, if the assertion is not fulfilled.
* When the assertion is not fulfilled Thread.sleep is called at the current Thread for a specified time.
* After this time the condition is checked again. By a default the specified sleep time is 50 ms.
* The default timeout is 1000 ms.
*
* @param condition closure that must not have an argument
* @param timeout timeout, default is 1000ms
* @param sleepTime interval for checking the condition, default is 50ms
*/
protected void waitForAssert(Closure<?> assertion, int timeout = 1000, int sleepTime = 50) {
def waitingTime = 0
while(waitingTime < timeout) {
try {
assertion()
return
} catch(Error error) {
waitingTime += sleepTime
sleep sleepTime
}
}
assertion()
}
/**
* Returns the interface name for a given service object by choosing the first interface.
*
* @param service service object
* @return name of the first interface or null if the object has no interfaces
*/
protected getInterfaceName(def service) {
service.class.interfaces?.find({it})?.name
}
/**
* Registers a volatile storage service.
*/
protected void registerVolatileStorageService() {
registerService(new VolatileStorageService());
}
@After
public void unregisterMocks() {
registeredServices.each() { interfaceName, service ->
service.unregister()
}
registeredServices.clear()
}
protected void enableItemAutoUpdate(){
def autoupdateConfig = [
autoUpdate: { String itemName -> return true }
] as AutoUpdateBindingConfigProvider
registerService(autoupdateConfig)
}
}