rspec-openhab-scripting 0.0.16-java → 0.0.19-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/rspec/openhab/api.rb +18 -1
- data/lib/rspec/openhab/core/mocks/channel_type_provider.rb +30 -0
- data/lib/rspec/openhab/core/mocks/item_channel_link_provider.rb +36 -0
- data/lib/rspec/openhab/core/mocks/thing_handler.rb +48 -0
- data/lib/rspec/openhab/core/mocks/thing_type_provider.rb +30 -0
- data/lib/rspec/openhab/core/osgi.rb +7 -1
- data/lib/rspec/openhab/dsl/imports.rb +105 -11
- data/lib/rspec/openhab/helpers.rb +311 -0
- data/lib/rspec/openhab/hooks.rb +26 -13
- data/lib/rspec/openhab/version.rb +1 -1
- data/lib/rspec-openhab-scripting.rb +6 -18
- metadata +7 -4
- data/lib/rspec/openhab/items.rb +0 -54
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ea386c264164b6c12be46d5483fdd349c3e5fdadcba22bff4987a2db5c6a9803
|
4
|
+
data.tar.gz: 20c364d137e43d5de1a1ab5eda9341318132cbde7532cf9c84901badce83ed49
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13ae42f75b1bcaa898969e4077cefd1bbbc0979a7a081b7e904db9ff2c0b9550205bef2f4d20e3c502c2d12c449b64886819622101cb4425ee8ce4083cc02ea8
|
7
|
+
data.tar.gz: dd85b3c9249e88031ed3bf297dd09c1e7698cdb6d0958b04b0efbe35117dc6c71043b22f258b49fa0b52bb58a98ff3c3d5e6e492c6f551c393ce5a16187e9f75
|
data/lib/rspec/openhab/api.rb
CHANGED
@@ -4,11 +4,12 @@ require "faraday"
|
|
4
4
|
|
5
5
|
module OpenHAB
|
6
6
|
class API
|
7
|
-
def initialize(url)
|
7
|
+
def initialize(url, token = nil)
|
8
8
|
@faraday = Faraday.new(url) do |f|
|
9
9
|
f.response :raise_error
|
10
10
|
f.response :json
|
11
11
|
f.path_prefix = "/rest/"
|
12
|
+
f.headers = { "X-OPENHAB-TOKEN" => token } if token
|
12
13
|
end
|
13
14
|
end
|
14
15
|
|
@@ -36,6 +37,22 @@ module OpenHAB
|
|
36
37
|
nil
|
37
38
|
end
|
38
39
|
|
40
|
+
def channel_types
|
41
|
+
@faraday.get("channel-types").body
|
42
|
+
end
|
43
|
+
|
44
|
+
def thing_types
|
45
|
+
@faraday.get("thing-types").body
|
46
|
+
end
|
47
|
+
|
48
|
+
def things
|
49
|
+
@faraday.get("things").body
|
50
|
+
end
|
51
|
+
|
52
|
+
def authenticated?
|
53
|
+
@faraday.headers.key?("X-OPENHAB-TOKEN")
|
54
|
+
end
|
55
|
+
|
39
56
|
private
|
40
57
|
|
41
58
|
def root_data
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module OpenHAB
|
5
|
+
module Core
|
6
|
+
module Mocks
|
7
|
+
class ChannelTypeProvider
|
8
|
+
include org.openhab.core.thing.type.ChannelTypeProvider
|
9
|
+
include Singleton
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@types = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def add(type)
|
16
|
+
@types[type.uid] = type
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_channel_types(_locale)
|
20
|
+
@types.values
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_channel_type(uid, _locale)
|
24
|
+
@types[uid]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module OpenHAB
|
5
|
+
module Core
|
6
|
+
module Mocks
|
7
|
+
class ItemChannelLinkProvider
|
8
|
+
include org.openhab.core.thing.link.ItemChannelLinkProvider
|
9
|
+
include Singleton
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@listeners = []
|
13
|
+
@links = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_provider_change_listener(listener)
|
17
|
+
@listeners << listener
|
18
|
+
end
|
19
|
+
|
20
|
+
def remove_provider_change_listener(listener)
|
21
|
+
@listeners.delete(listener)
|
22
|
+
end
|
23
|
+
|
24
|
+
def all
|
25
|
+
@links
|
26
|
+
end
|
27
|
+
|
28
|
+
def add(link)
|
29
|
+
@links << link
|
30
|
+
@listeners.each { |l| l.added(self, link) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop:disable Naming have to follow java interface names
|
4
|
+
module RSpec
|
5
|
+
module OpenHAB
|
6
|
+
module Core
|
7
|
+
module Mocks
|
8
|
+
class ThingHandler
|
9
|
+
include org.openhab.core.thing.binding.BridgeHandler
|
10
|
+
|
11
|
+
attr_reader :thing, :callback
|
12
|
+
|
13
|
+
def initialize(thing = nil)
|
14
|
+
# have to handle the interface method
|
15
|
+
if thing.nil?
|
16
|
+
status_info = org.openhab.core.thing.binding.builder.ThingStatusInfoBuilder
|
17
|
+
.create(org.openhab.core.thing.ThingStatus::ONLINE).build
|
18
|
+
@callback.status_updated(self.thing, status_info)
|
19
|
+
return
|
20
|
+
end
|
21
|
+
|
22
|
+
# ruby initializer here
|
23
|
+
@thing = thing
|
24
|
+
end
|
25
|
+
|
26
|
+
def handle_command(channel, command); end
|
27
|
+
|
28
|
+
def set_callback(callback)
|
29
|
+
@callback = callback
|
30
|
+
end
|
31
|
+
|
32
|
+
def child_handler_initialized(child_handler, child_thing); end
|
33
|
+
end
|
34
|
+
|
35
|
+
class ThingHandlerFactory < org.openhab.core.thing.binding.BaseThingHandlerFactory
|
36
|
+
def supportsThingType(_type)
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
40
|
+
def createHandler(thing)
|
41
|
+
ThingHandler.new(thing)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
# rubocop:enable Naming
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module OpenHAB
|
5
|
+
module Core
|
6
|
+
module Mocks
|
7
|
+
class ThingTypeProvider
|
8
|
+
include org.openhab.core.thing.binding.ThingTypeProvider
|
9
|
+
include Singleton
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@types = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def add(type)
|
16
|
+
@types[type.uid] = type
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_thing_types(_locale)
|
20
|
+
@types.values
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_thing_type(uid, _locale)
|
24
|
+
@types[uid]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -4,11 +4,17 @@ module OpenHAB
|
|
4
4
|
module Core
|
5
5
|
class OSGI
|
6
6
|
class << self
|
7
|
-
def register_service(name, service)
|
7
|
+
def register_service(name, service = nil)
|
8
|
+
if service.nil?
|
9
|
+
service = name
|
10
|
+
name = service.java_class.interfaces.first&.name || service.java_class.name
|
11
|
+
end
|
8
12
|
(@services ||= {})[name] = service
|
9
13
|
end
|
10
14
|
|
11
15
|
def service(name)
|
16
|
+
name = name.java_class if name.is_a?(Class)
|
17
|
+
name = name.name if name.is_a?(java.lang.Class)
|
12
18
|
@services&.[](name)
|
13
19
|
end
|
14
20
|
|
@@ -68,6 +68,22 @@ module OpenHAB
|
|
68
68
|
def add_bundle_listener(listener); end
|
69
69
|
end
|
70
70
|
|
71
|
+
class BundleResolver
|
72
|
+
include org.openhab.core.util.BundleResolver
|
73
|
+
|
74
|
+
def initialize
|
75
|
+
@bundles = {}
|
76
|
+
end
|
77
|
+
|
78
|
+
def register(klass, bundle)
|
79
|
+
@bundles[klass] = bundle
|
80
|
+
end
|
81
|
+
|
82
|
+
def resolve_bundle(klass)
|
83
|
+
@bundles[klass]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
71
87
|
# don't depend on org.openhab.core.test
|
72
88
|
class VolatileStorageService
|
73
89
|
include org.openhab.core.storage.StorageService
|
@@ -98,13 +114,15 @@ module OpenHAB
|
|
98
114
|
INSTALLED = 2
|
99
115
|
|
100
116
|
def initialize(*jar_args)
|
117
|
+
return if jar_args.empty?
|
118
|
+
|
101
119
|
file = Jars.find_jar(*jar_args)
|
102
120
|
@jar = java.util.jar.JarFile.new(file)
|
103
121
|
@symbolic_name = jar_args[1]
|
104
122
|
@version = org.osgi.framework.Version.new(jar_args[2].tr("-", "."))
|
105
123
|
end
|
106
124
|
|
107
|
-
|
125
|
+
attr_accessor :symbolic_name, :version
|
108
126
|
|
109
127
|
def state
|
110
128
|
INSTALLED
|
@@ -190,7 +208,7 @@ module OpenHAB
|
|
190
208
|
event_factory.create_event(type, topic, payload, source)
|
191
209
|
rescue Exception => e
|
192
210
|
logger.warn("Creation of event failed, because one of the " \
|
193
|
-
"registered event factories has thrown an exception: #{e}")
|
211
|
+
"registered event factories has thrown an exception: #{e.inspect}")
|
194
212
|
nil
|
195
213
|
end
|
196
214
|
|
@@ -201,7 +219,9 @@ module OpenHAB
|
|
201
219
|
begin
|
202
220
|
event_subscriber.receive(event)
|
203
221
|
rescue Exception => e
|
204
|
-
logger.warn(
|
222
|
+
logger.warn(
|
223
|
+
"Dispatching/filtering event for subscriber '#{event_subscriber.class}' failed: #{e.inspect}"
|
224
|
+
)
|
205
225
|
end
|
206
226
|
else
|
207
227
|
logger.trace("Skip event subscriber (#{event_subscriber.class}) because of its filter.")
|
@@ -217,7 +237,7 @@ module OpenHAB
|
|
217
237
|
include Singleton
|
218
238
|
|
219
239
|
def submit(runnable)
|
220
|
-
runnable.run
|
240
|
+
runnable.respond_to?(:run) ? runnable.run : runnable.call
|
221
241
|
|
222
242
|
java.util.concurrent.CompletableFuture.completed_future(nil)
|
223
243
|
end
|
@@ -233,6 +253,40 @@ module OpenHAB
|
|
233
253
|
end
|
234
254
|
end
|
235
255
|
|
256
|
+
class SafeCaller
|
257
|
+
include org.openhab.core.common.SafeCaller
|
258
|
+
include org.openhab.core.common.SafeCallerBuilder
|
259
|
+
|
260
|
+
def create(target, _interface_type)
|
261
|
+
@target = target
|
262
|
+
self
|
263
|
+
end
|
264
|
+
|
265
|
+
def build
|
266
|
+
@target
|
267
|
+
end
|
268
|
+
|
269
|
+
def with_timeout(_timeout)
|
270
|
+
self
|
271
|
+
end
|
272
|
+
|
273
|
+
def with_identifier(_identifier)
|
274
|
+
self
|
275
|
+
end
|
276
|
+
|
277
|
+
def on_exception(_handler)
|
278
|
+
self
|
279
|
+
end
|
280
|
+
|
281
|
+
def on_timeout(_handler)
|
282
|
+
self
|
283
|
+
end
|
284
|
+
|
285
|
+
def with_async
|
286
|
+
self
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
236
290
|
class CallbacksMap < java.util.HashMap
|
237
291
|
def put(_rule_uid, trigger_handler)
|
238
292
|
trigger_handler.executor.shutdown_now
|
@@ -271,11 +325,12 @@ module OpenHAB
|
|
271
325
|
bc = BundleContext.new(em)
|
272
326
|
cc = ComponentContext.new(bc)
|
273
327
|
cc.properties["measurementSystem"] = api.measurement_system if api
|
328
|
+
resolver = BundleResolver.new
|
274
329
|
|
275
330
|
# the registries!
|
276
331
|
ss = VolatileStorageService.new
|
277
332
|
mr = org.openhab.core.internal.items.MetadataRegistryImpl.new
|
278
|
-
OpenHAB::Core::OSGI.register_service(
|
333
|
+
OpenHAB::Core::OSGI.register_service(mr)
|
279
334
|
mr.managed_provider = mmp = org.openhab.core.internal.items.ManagedMetadataProviderImpl.new(ss)
|
280
335
|
mr.add_provider(mmp)
|
281
336
|
gmp = org.openhab.core.model.item.internal.GenericMetadataProvider.new
|
@@ -286,16 +341,25 @@ module OpenHAB
|
|
286
341
|
ir.event_publisher = ep
|
287
342
|
up = org.openhab.core.internal.i18n.I18nProviderImpl.new(cc)
|
288
343
|
ir.unit_provider = up
|
289
|
-
ir.item_state_converter = org.openhab.core.internal.items.ItemStateConverterImpl.new(up)
|
344
|
+
ir.item_state_converter = isc = org.openhab.core.internal.items.ItemStateConverterImpl.new(up)
|
290
345
|
tr = org.openhab.core.thing.internal.ThingRegistryImpl.new
|
346
|
+
tr.managed_provider = mtp = org.openhab.core.thing.ManagedThingProvider.new(ss)
|
347
|
+
tr.add_provider(mtp)
|
291
348
|
mtr = org.openhab.core.automation.internal.type.ModuleTypeRegistryImpl.new
|
292
349
|
rr = org.openhab.core.automation.internal.RuleRegistryImpl.new
|
293
350
|
rr.module_type_registry = mtr
|
294
351
|
rr.managed_provider = mrp = org.openhab.core.automation.ManagedRuleProvider.new(ss)
|
295
352
|
rr.add_provider(mrp)
|
296
353
|
iclr = org.openhab.core.thing.link.ItemChannelLinkRegistry.new(tr, ir)
|
354
|
+
iclr.add_provider(RSpec::OpenHAB::Core::Mocks::ItemChannelLinkProvider.instance)
|
355
|
+
OpenHAB::Core::OSGI.register_service(iclr)
|
297
356
|
ctr = org.openhab.core.thing.type.ChannelTypeRegistry.new
|
357
|
+
OpenHAB::Core::OSGI.register_service(ctr)
|
358
|
+
ctr.add_channel_type_provider(RSpec::OpenHAB::Core::Mocks::ChannelTypeProvider.instance)
|
298
359
|
ttr = org.openhab.core.thing.type.ThingTypeRegistry.new(ctr)
|
360
|
+
OpenHAB::Core::OSGI.register_service(ttr)
|
361
|
+
ttr.add_thing_type_provider(RSpec::OpenHAB::Core::Mocks::ThingTypeProvider.instance)
|
362
|
+
cgtr = org.openhab.core.thing.type.ChannelGroupTypeRegistry.new
|
299
363
|
|
300
364
|
safe_emf = org.openhab.core.model.core.internal.SafeEMFImpl.new
|
301
365
|
model_repository = org.openhab.core.model.core.internal.ModelRepositoryImpl.new(safe_emf)
|
@@ -360,15 +424,18 @@ module OpenHAB
|
|
360
424
|
|
361
425
|
# link up event bus infrastructure
|
362
426
|
iu = org.openhab.core.internal.items.ItemUpdater.new(ir)
|
363
|
-
ief = org.openhab.core.items.events.ItemEventFactory.new
|
364
427
|
|
365
|
-
sc =
|
366
|
-
aum = org.openhab.core.thing.internal.AutoUpdateManager.new(
|
367
|
-
|
428
|
+
sc = SafeCaller.new
|
429
|
+
aum = org.openhab.core.thing.internal.AutoUpdateManager.new(
|
430
|
+
{ "enabled" => true, "sendOptimisticUpdates" => true }, ctr, ep, iclr, mr, tr
|
431
|
+
)
|
432
|
+
spf = org.openhab.core.thing.internal.profiles.SystemProfileFactory.new(ctr, nil, resolver)
|
433
|
+
cm = org.openhab.core.thing.internal.CommunicationManager.new(aum, ctr, spf, iclr, ir, isc, ep, sc, tr)
|
368
434
|
|
369
435
|
em.add_event_subscriber(iu)
|
370
436
|
em.add_event_subscriber(cm)
|
371
|
-
em.add_event_factory(
|
437
|
+
em.add_event_factory(org.openhab.core.items.events.ItemEventFactory.new)
|
438
|
+
em.add_event_factory(org.openhab.core.thing.events.ThingEventFactory.new)
|
372
439
|
|
373
440
|
# set up the rules engine part 2
|
374
441
|
k = org.openhab.core.automation.internal.module.factory.CoreModuleHandlerFactory
|
@@ -385,6 +452,8 @@ module OpenHAB
|
|
385
452
|
|
386
453
|
rs = org.openhab.core.internal.service.ReadyServiceImpl.new
|
387
454
|
re = org.openhab.core.automation.internal.RuleEngineImpl.new(mtr, rr, ss, rs)
|
455
|
+
OpenHAB::Core::OSGI.register_service(re)
|
456
|
+
|
388
457
|
# overwrite thCallbacks to one that will spy to remove threading
|
389
458
|
field = re.class.java_class.declared_field("thCallbacks")
|
390
459
|
field.accessible = true
|
@@ -411,6 +480,31 @@ module OpenHAB
|
|
411
480
|
pm = org.openhab.core.persistence.internal.PersistenceManagerImpl.new(nil, ir, sc, rs)
|
412
481
|
pm.add_persistence_service(ps)
|
413
482
|
pm.on_ready_marker_added(nil)
|
483
|
+
|
484
|
+
# set up ThingManager so we can trigger channels
|
485
|
+
localizer = org.openhab.core.thing.i18n.ThingStatusInfoI18nLocalizationService.new
|
486
|
+
tm = org.openhab.core.thing.internal.ThingManagerImpl.new(
|
487
|
+
resolver,
|
488
|
+
cgtr,
|
489
|
+
ctr,
|
490
|
+
cm,
|
491
|
+
nil,
|
492
|
+
nil,
|
493
|
+
ep,
|
494
|
+
iclr,
|
495
|
+
rs,
|
496
|
+
sc,
|
497
|
+
ss,
|
498
|
+
tr,
|
499
|
+
localizer,
|
500
|
+
ttr
|
501
|
+
)
|
502
|
+
thf = RSpec::OpenHAB::Core::Mocks::ThingHandlerFactory.new
|
503
|
+
this_bundle = Bundle.new
|
504
|
+
this_bundle.symbolic_name = "org.openhab.automation.jrubyscripting.rspec"
|
505
|
+
resolver.register(thf.class.java_class, this_bundle)
|
506
|
+
tm.add_thing_handler_factory(thf)
|
507
|
+
tm.on_ready_marker_added(org.openhab.core.service.ReadyMarker.new(nil, this_bundle.symbolic_name))
|
414
508
|
end
|
415
509
|
end
|
416
510
|
end
|
@@ -1,8 +1,51 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module OpenHAB
|
4
|
+
module Transform
|
5
|
+
class << self
|
6
|
+
def add_script(modules, script)
|
7
|
+
full_name = modules.join("/")
|
8
|
+
name = modules.pop
|
9
|
+
(@scripts ||= {})[full_name] = engine_factory.script_engine.compile(script)
|
10
|
+
|
11
|
+
mod = modules.inject(self) { |m, n| m.const_get(n, false) }
|
12
|
+
mod.singleton_class.define_method(name) do |input, **kwargs|
|
13
|
+
Transform.send(:transform, full_name, input, kwargs)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def engine_factory
|
20
|
+
@engine_factory ||= org.jruby.embed.jsr223.JRubyEngineFactory.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def transform(name, input, kwargs)
|
24
|
+
script = @scripts[name]
|
25
|
+
ctx = script.engine.context
|
26
|
+
ctx.set_attribute("input", input.to_s, javax.script.ScriptContext::ENGINE_SCOPE)
|
27
|
+
kwargs.each do |(k, v)|
|
28
|
+
ctx.set_attribute(k.to_s, v.to_s, javax.script.ScriptContext::ENGINE_SCOPE)
|
29
|
+
end
|
30
|
+
script.eval
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
3
36
|
module RSpec
|
4
37
|
module OpenHAB
|
5
38
|
module Helpers
|
39
|
+
module BindingHelper
|
40
|
+
def add_kwargs_to_current_binding(binding, kwargs)
|
41
|
+
kwargs.each { |(k, v)| binding.local_variable_set(k, v) }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private_constant :BindingHelper
|
46
|
+
|
47
|
+
singleton_class.include(Helpers)
|
48
|
+
|
6
49
|
def autoupdate_all_items
|
7
50
|
@autoupdated_items ||= {}
|
8
51
|
$ir.for_each do |_provider, item|
|
@@ -24,8 +67,158 @@ module RSpec
|
|
24
67
|
@rules.fetch(rule_name).execute(nil, { "event" => event })
|
25
68
|
end
|
26
69
|
|
70
|
+
def trigger_channel(channel, event)
|
71
|
+
channel = org.openhab.core.thing.ChannelUID.new(channel) if channel.is_a?(String)
|
72
|
+
channel = channel.uid if channel.is_a?(org.openhab.core.thing.Channel)
|
73
|
+
thing = channel.thing
|
74
|
+
thing.handler.callback.channel_triggered(nil, channel, event)
|
75
|
+
end
|
76
|
+
|
77
|
+
def populate_items_from_api
|
78
|
+
api = ::OpenHAB::DSL::Imports.api
|
79
|
+
all_items = api.items
|
80
|
+
|
81
|
+
item_factory = org.openhab.core.library.CoreItemFactory.new
|
82
|
+
|
83
|
+
all_items.each do |item_json|
|
84
|
+
full_type = item_json["type"]
|
85
|
+
name = item_json["name"]
|
86
|
+
|
87
|
+
type, _dimension = full_type.split(":")
|
88
|
+
if type == "Group"
|
89
|
+
base_item = item_factory.create_item(item_json["groupType"], name) if item_json["groupType"]
|
90
|
+
if item_json["function"]
|
91
|
+
dto = org.openhab.core.items.dto.GroupFunctionDTO.new
|
92
|
+
dto.name = item_json.dig("function", "name")
|
93
|
+
dto.params = item_json.dig("function", "params")
|
94
|
+
function = org.openhab.core.items.dto.ItemDTOMapper.map_function(base_item, dto)
|
95
|
+
end
|
96
|
+
item = GroupItem.new(name, base_item, function)
|
97
|
+
else
|
98
|
+
item = item_factory.create_item(full_type, name)
|
99
|
+
end
|
100
|
+
|
101
|
+
item.label = item_json["label"]
|
102
|
+
item_json["tags"].each do |tag|
|
103
|
+
item.add_tag(tag)
|
104
|
+
end
|
105
|
+
item_json["metadata"]&.each do |key, config|
|
106
|
+
item.meta[key] = config["value"], config["config"]
|
107
|
+
end
|
108
|
+
item.meta["stateDescription"] = item_json["stateDescription"] if item_json["stateDescription"]
|
109
|
+
item.category = item_json["category"] if item_json["category"]
|
110
|
+
|
111
|
+
$ir.add(item)
|
112
|
+
|
113
|
+
next unless item.meta["channel"]&.value
|
114
|
+
|
115
|
+
channel_uid = org.openhab.core.thing.ChannelUID.new(item.meta["channel"].value)
|
116
|
+
channel = $things.get_channel(channel_uid)
|
117
|
+
next unless channel
|
118
|
+
|
119
|
+
link = org.openhab.core.thing.link.ItemChannelLink.new(item.name, channel_uid)
|
120
|
+
Core::Mocks::ItemChannelLinkProvider.instance.add(link)
|
121
|
+
end
|
122
|
+
all_items.each do |item_json| # rubocop:disable Style/CombinableLoops
|
123
|
+
item_json["groupNames"].each do |group_name|
|
124
|
+
next unless (group = $ir.get(group_name))
|
125
|
+
|
126
|
+
group.add_member($ir.get(item_json["name"]))
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def populate_things_from_api
|
132
|
+
api = ::OpenHAB::DSL::Imports.api
|
133
|
+
populate_channel_types_from_api(api)
|
134
|
+
populate_thing_types_from_api(api)
|
135
|
+
|
136
|
+
thing_type_registry = ::OpenHAB::Core::OSGI.service("org.openhab.core.thing.type.ThingTypeRegistry")
|
137
|
+
|
138
|
+
api.things.each do |thing_json|
|
139
|
+
uid = org.openhab.core.thing.ThingUID.new(thing_json["UID"])
|
140
|
+
type_uid = org.openhab.core.thing.ThingTypeUID.new(thing_json["thingTypeUID"])
|
141
|
+
bridge_uid = org.openhab.core.thing.ThingUID.new(thing_json["bridgeUID"]) if thing_json["bridgeUID"]
|
142
|
+
|
143
|
+
type = thing_type_registry.get_thing_type(type_uid)
|
144
|
+
klass = if type.is_a?(org.openhab.core.thing.type.BridgeType)
|
145
|
+
org.openhab.core.thing.binding.builder.BridgeBuilder
|
146
|
+
else
|
147
|
+
org.openhab.core.thing.binding.builder.ThingBuilder
|
148
|
+
end
|
149
|
+
builder = klass.create(type_uid, uid)
|
150
|
+
builder.with_bridge(bridge_uid) if bridge_uid
|
151
|
+
|
152
|
+
thing_json.each do |(k, v)|
|
153
|
+
case k
|
154
|
+
when "UID", "thingTypeUID", "bridgeUID", "statusInfo", "editable"
|
155
|
+
nil
|
156
|
+
when "channels"
|
157
|
+
builder.with_channels(v.map { |c| build_channel(c) })
|
158
|
+
when "configuration"
|
159
|
+
builder.with_configuration(org.openhab.core.config.core.Configuration.new(v))
|
160
|
+
else
|
161
|
+
builder.send(:"with_#{k}", v)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
$things.add(builder.build)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def load_rules
|
170
|
+
automation_path = "#{org.openhab.core.OpenHAB.config_folder}/automation/jsr223/ruby/personal"
|
171
|
+
|
172
|
+
RSpec::OpenHAB::SuspendRules.suspend_rules do
|
173
|
+
Dir["#{automation_path}/*.rb"].each do |f|
|
174
|
+
load f
|
175
|
+
rescue Exception => e
|
176
|
+
warn "Failed loading #{f}: #{e.inspect}"
|
177
|
+
warn e.backtrace
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def load_transforms
|
183
|
+
transform_path = "#{org.openhab.core.OpenHAB.config_folder}/transform"
|
184
|
+
Dir["#{transform_path}/**/*.script"].each do |filename|
|
185
|
+
script = File.read(filename)
|
186
|
+
next unless ruby_file?(script)
|
187
|
+
|
188
|
+
filename.slice!(0..transform_path.length)
|
189
|
+
dir = File.dirname(filename)
|
190
|
+
modules = dir == "." ? [] : moduleize(dir)
|
191
|
+
basename = File.basename(filename)
|
192
|
+
method = basename[0...-7]
|
193
|
+
modules << method
|
194
|
+
::OpenHAB::Transform.add_script(modules, script)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
27
198
|
private
|
28
199
|
|
200
|
+
EMACS_MODELINE_REGEXP = /# -\*-(.+)-\*-/.freeze
|
201
|
+
|
202
|
+
def parse_emacs_modeline(line)
|
203
|
+
line[EMACS_MODELINE_REGEXP, 1]
|
204
|
+
&.split(";")
|
205
|
+
&.map(&:strip)
|
206
|
+
&.map { |l| l.split(":", 2).map(&:strip).tap { |a| a[1] ||= nil } }
|
207
|
+
&.to_h
|
208
|
+
end
|
209
|
+
|
210
|
+
def ruby_file?(script)
|
211
|
+
# check the first 1KB for an emacs magic comment
|
212
|
+
script[0..1024].split("\n").any? { |line| parse_emacs_modeline(line)&.dig("mode") == "ruby" }
|
213
|
+
end
|
214
|
+
|
215
|
+
def moduleize(term)
|
216
|
+
term
|
217
|
+
.sub(/^[a-z\d]*/, &:capitalize)
|
218
|
+
.gsub(%r{(?:_|(/))([a-z\d]*)}) { "#{$1}#{$2.capitalize}" }
|
219
|
+
.split("/")
|
220
|
+
end
|
221
|
+
|
29
222
|
def restore_autoupdate_items
|
30
223
|
return unless instance_variable_defined?(:@autoupdated_items)
|
31
224
|
|
@@ -33,6 +226,124 @@ module RSpec
|
|
33
226
|
item.meta["autoupdate"] = meta
|
34
227
|
end
|
35
228
|
end
|
229
|
+
|
230
|
+
def populate_channel_types_from_api(api)
|
231
|
+
api.channel_types.each do |ct_json|
|
232
|
+
uid = org.openhab.core.thing.type.ChannelTypeUID.new(ct_json["UID"])
|
233
|
+
builder = case ct_json["kind"]
|
234
|
+
when "STATE"
|
235
|
+
org.openhab.core.thing.type.ChannelTypeBuilder.state(uid, ct_json["label"], ct_json["itemType"])
|
236
|
+
when "TRIGGER"
|
237
|
+
org.openhab.core.thing.type.ChannelTypeBuilder.trigger(uid, ct_json["label"])
|
238
|
+
else
|
239
|
+
raise ArgumentError, "Unrecognized channel type kind #{ct_json["kind"]} for #{uid}"
|
240
|
+
end
|
241
|
+
|
242
|
+
ct_json.each do |(k, v)|
|
243
|
+
case k
|
244
|
+
when "parameters", "parameterGroups", "label", "kind", "UID", "itemType"
|
245
|
+
nil
|
246
|
+
when "commandDescription"
|
247
|
+
builder.with_command_description(build_command_description(v))
|
248
|
+
when "stateDescription"
|
249
|
+
builder.with_state_description_fragment(build_state_description_fragment(v))
|
250
|
+
when "advanced"
|
251
|
+
builder.is_advanced(v)
|
252
|
+
else
|
253
|
+
builder.send(:"with_#{k}", v)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
ct = builder.build
|
258
|
+
Core::Mocks::ChannelTypeProvider.instance.add(ct)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
def build_command_description(json)
|
263
|
+
org.openhab.core.types.CommandDescriptionBuilder.create
|
264
|
+
.with_command_options(json["commandOptions"].map do |o|
|
265
|
+
org.openhab.core.types.CommandOption.new(o["command"], o["label"])
|
266
|
+
end)
|
267
|
+
.build
|
268
|
+
end
|
269
|
+
|
270
|
+
def build_state_description_fragment(json)
|
271
|
+
org.openhab.core.types.StateDescriptionFragmentBuilder.create
|
272
|
+
.with_minimum(json["minimum"]&.to_d)
|
273
|
+
.with_maximum(json["maximum"]&.to_d)
|
274
|
+
.with_step(json["step"&.to_d])
|
275
|
+
.with_pattern(json["pattern"])
|
276
|
+
.with_read_only(json["readOnly"])
|
277
|
+
.with_options(json["options"].map { |o| org.openhab.core.types.StateOption.new(o["value"], o["label"]) })
|
278
|
+
.build
|
279
|
+
end
|
280
|
+
|
281
|
+
def populate_thing_types_from_api(api)
|
282
|
+
api.thing_types.each do |tt_json|
|
283
|
+
uid = org.openhab.core.thing.ThingTypeUID.new(tt_json["UID"])
|
284
|
+
builder = org.openhab.core.thing.type.ThingTypeBuilder.instance(uid, tt_json["label"])
|
285
|
+
tt_json.each do |(k, v)|
|
286
|
+
case k
|
287
|
+
when "UID", "label", "bridge"
|
288
|
+
nil
|
289
|
+
when "listed"
|
290
|
+
builder.is_listed(v)
|
291
|
+
when "channels"
|
292
|
+
builder.with_channels(v.map { |c| build_channel_definition(c) })
|
293
|
+
when "channelGroups"
|
294
|
+
builder.with_channel_groups(v.map { |cg| build_channel_group_definition(cg) })
|
295
|
+
else
|
296
|
+
builder.send(:"with#{k[0].upcase}#{k[1..]}", v)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
tt = tt_json["bridge"] ? builder.build_bridge : builder.build
|
301
|
+
Core::Mocks::ThingTypeProvider.instance.add(tt)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
def build_channel_definition(json)
|
306
|
+
org.openhab.core.thing.type.ChannelDefinition.new(
|
307
|
+
json["uid"],
|
308
|
+
org.openhab.core.thing.type.ChannelTypeUID.new(json["typeUID"]),
|
309
|
+
json["description"],
|
310
|
+
json["properties"],
|
311
|
+
nil
|
312
|
+
)
|
313
|
+
end
|
314
|
+
|
315
|
+
def build_channel_group_definition(json)
|
316
|
+
org.openhab.core.thing.type.ChannelGroupDefinition.new(
|
317
|
+
json["uid"],
|
318
|
+
org.openhab.core.thing.type.ChannelGroupTypeUID.new(json["typeUID"]),
|
319
|
+
json["label"],
|
320
|
+
json["description"]
|
321
|
+
)
|
322
|
+
end
|
323
|
+
|
324
|
+
def build_channel(json)
|
325
|
+
uid = org.openhab.core.thing.ChannelUID.new(json["uid"])
|
326
|
+
builder = org.openhab.core.thing.binding.builder.ChannelBuilder.create(uid)
|
327
|
+
|
328
|
+
json.each do |(k, v)|
|
329
|
+
case k
|
330
|
+
when "uid", "id", "linkedItems", "itemType"
|
331
|
+
nil
|
332
|
+
when "channelTypeUID"
|
333
|
+
builder.with_type(org.openhab.core.thing.type.ChannelTypeUID.new((v)))
|
334
|
+
when "configuration"
|
335
|
+
builder.with_configuration(org.openhab.core.config.core.Configuration.new(v))
|
336
|
+
when "kind"
|
337
|
+
builder.with_kind(org.openhab.core.thing.type.ChannelKind.const_get(v, false))
|
338
|
+
when "defaultTags"
|
339
|
+
builder.with_default_tags(v.to_set)
|
340
|
+
else
|
341
|
+
builder.send("with_#{k}", v)
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
builder.build
|
346
|
+
end
|
36
347
|
end
|
37
348
|
|
38
349
|
RSpec.configure do |config|
|
data/lib/rspec/openhab/hooks.rb
CHANGED
@@ -1,20 +1,33 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
RSpec
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
module RSpec
|
4
|
+
module OpenHAB
|
5
|
+
RSpec.configure do |config|
|
6
|
+
config.before(:suite) do
|
7
|
+
Helpers.populate_things_from_api if ::OpenHAB::DSL::Imports.api.authenticated?
|
8
|
+
Helpers.populate_items_from_api
|
9
|
+
Helpers.load_transforms
|
10
|
+
Helpers.suspend_rules do
|
11
|
+
Helpers.load_rules
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
config.before do
|
16
|
+
suspend_rules do
|
17
|
+
$ir.for_each do |_provider, item|
|
18
|
+
next if item.is_a?(GroupItem) # groups only have calculated states
|
8
19
|
|
9
|
-
|
20
|
+
item.state = NULL unless item.raw_state == NULL
|
21
|
+
end
|
22
|
+
end
|
10
23
|
end
|
11
|
-
end
|
12
|
-
end
|
13
24
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
25
|
+
config.after do
|
26
|
+
::OpenHAB::DSL::Timers.timer_manager.cancel_all
|
27
|
+
Timecop.return
|
28
|
+
restore_autoupdate_items
|
29
|
+
Core::Mocks::PersistenceService.instance.reset
|
30
|
+
end
|
31
|
+
end
|
19
32
|
end
|
20
33
|
end
|
@@ -5,7 +5,8 @@
|
|
5
5
|
$LOAD_PATH.unshift(File.expand_path("../vendor/gems/jar-dependencies-1.0.0/lib", __dir__))
|
6
6
|
|
7
7
|
require "rspec/openhab/api"
|
8
|
-
api = OpenHAB::API.new("http://#{ENV.fetch("OPENHAB_HOST", "localhost")}:#{ENV.fetch("OPENHAB_HTTP_PORT", "8080")}/"
|
8
|
+
api = OpenHAB::API.new("http://#{ENV.fetch("OPENHAB_HOST", "localhost")}:#{ENV.fetch("OPENHAB_HTTP_PORT", "8080")}/",
|
9
|
+
ENV.fetch("OPENHAB_TOKEN", nil))
|
9
10
|
|
10
11
|
module OpenHAB
|
11
12
|
module Core
|
@@ -66,7 +67,11 @@ require "rspec/openhab/core/logger"
|
|
66
67
|
# during testing, we don't want "regular" output from rules
|
67
68
|
OpenHAB::Log.logger("org.openhab.automation.jruby.runtime").level = :warn
|
68
69
|
OpenHAB::Log.logger("org.openhab.automation.jruby.logger").level = :warn
|
70
|
+
require "rspec/openhab/core/mocks/channel_type_provider"
|
71
|
+
require "rspec/openhab/core/mocks/item_channel_link_provider"
|
69
72
|
require "rspec/openhab/core/mocks/persistence_service"
|
73
|
+
require "rspec/openhab/core/mocks/thing_handler"
|
74
|
+
require "rspec/openhab/core/mocks/thing_type_provider"
|
70
75
|
require "openhab/dsl/imports"
|
71
76
|
OpenHAB::DSL::Imports.api = api
|
72
77
|
OpenHAB::DSL::Imports.import_presets
|
@@ -83,7 +88,6 @@ require_relative "rspec/openhab/dsl/rules/triggers/watch"
|
|
83
88
|
|
84
89
|
# RSpec additions
|
85
90
|
require "rspec/core"
|
86
|
-
require "rspec/openhab/items"
|
87
91
|
require "rspec/openhab/helpers"
|
88
92
|
require "rspec/openhab/hooks"
|
89
93
|
require "rspec/openhab/suspend_rules"
|
@@ -92,25 +96,9 @@ RSpec.configure do |config|
|
|
92
96
|
config.include OpenHAB::Core::EntityLookup
|
93
97
|
end
|
94
98
|
|
95
|
-
RSpec::OpenHAB::SuspendRules.suspend_rules do
|
96
|
-
RSpec::OpenHAB::Items.populate_items_from_api(api)
|
97
|
-
end
|
98
|
-
|
99
99
|
# make bundler/inline _not_ destroy the already existing load path
|
100
100
|
module Bundler
|
101
101
|
module SharedHelpers
|
102
102
|
def clean_load_path; end
|
103
103
|
end
|
104
104
|
end
|
105
|
-
|
106
|
-
# load rules files
|
107
|
-
OPENHAB_AUTOMATION_PATH = "#{org.openhab.core.OpenHAB.config_folder}/automation/jsr223/ruby/personal"
|
108
|
-
|
109
|
-
RSpec::OpenHAB::SuspendRules.suspend_rules do
|
110
|
-
Dir["#{OPENHAB_AUTOMATION_PATH}/*.rb"].each do |f|
|
111
|
-
load f
|
112
|
-
rescue Exception => e
|
113
|
-
warn "Failed loading #{f}: #{e.inspect}"
|
114
|
-
warn e.backtrace
|
115
|
-
end
|
116
|
-
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-openhab-scripting
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.19
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Cody Cutrer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-08-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -192,7 +192,11 @@ files:
|
|
192
192
|
- lib/rspec/openhab/core/item_proxy.rb
|
193
193
|
- lib/rspec/openhab/core/load_path.rb
|
194
194
|
- lib/rspec/openhab/core/logger.rb
|
195
|
+
- lib/rspec/openhab/core/mocks/channel_type_provider.rb
|
196
|
+
- lib/rspec/openhab/core/mocks/item_channel_link_provider.rb
|
195
197
|
- lib/rspec/openhab/core/mocks/persistence_service.rb
|
198
|
+
- lib/rspec/openhab/core/mocks/thing_handler.rb
|
199
|
+
- lib/rspec/openhab/core/mocks/thing_type_provider.rb
|
196
200
|
- lib/rspec/openhab/core/openhab_setup.rb
|
197
201
|
- lib/rspec/openhab/core/osgi.rb
|
198
202
|
- lib/rspec/openhab/core/script_handling.rb
|
@@ -201,7 +205,6 @@ files:
|
|
201
205
|
- lib/rspec/openhab/dsl/timers/timer.rb
|
202
206
|
- lib/rspec/openhab/helpers.rb
|
203
207
|
- lib/rspec/openhab/hooks.rb
|
204
|
-
- lib/rspec/openhab/items.rb
|
205
208
|
- lib/rspec/openhab/suspend_rules.rb
|
206
209
|
- lib/rspec/openhab/version.rb
|
207
210
|
- vendor/gems/jar-dependencies-1.0.0/lib/jar-dependencies.rb
|
@@ -237,7 +240,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
237
240
|
requirements:
|
238
241
|
- - ">="
|
239
242
|
- !ruby/object:Gem::Version
|
240
|
-
version: '2.
|
243
|
+
version: '2.6'
|
241
244
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
242
245
|
requirements:
|
243
246
|
- - ">="
|
data/lib/rspec/openhab/items.rb
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RSpec
|
4
|
-
module OpenHAB
|
5
|
-
module Items
|
6
|
-
class << self
|
7
|
-
def populate_items_from_api(api)
|
8
|
-
all_items = api.items
|
9
|
-
|
10
|
-
gfh = org.openhab.core.internal.items.GroupFunctionHelper.new
|
11
|
-
item_factory = org.openhab.core.library.CoreItemFactory.new
|
12
|
-
|
13
|
-
all_items.each do |item_json|
|
14
|
-
full_type = item_json["type"]
|
15
|
-
name = item_json["name"]
|
16
|
-
|
17
|
-
type, _dimension = full_type.split(":")
|
18
|
-
if type == "Group"
|
19
|
-
base_item = item_factory.create_item(item_json["groupType"], name) if item_json["groupType"]
|
20
|
-
if item_json["function"]
|
21
|
-
dto = org.openhab.core.items.dto.GroupFunctionDTO.new
|
22
|
-
dto.name = item_json.dig("function", "name")
|
23
|
-
dto.params = item_json.dig("function", "params")
|
24
|
-
function = gfh.create_group_function(dto, base_item)
|
25
|
-
end
|
26
|
-
item = GroupItem.new(name, base_item, function)
|
27
|
-
else
|
28
|
-
item = item_factory.create_item(full_type, name)
|
29
|
-
end
|
30
|
-
|
31
|
-
item.label = item_json["label"]
|
32
|
-
item_json["tags"].each do |tag|
|
33
|
-
item.add_tag(tag)
|
34
|
-
end
|
35
|
-
item_json["metadata"]&.each do |key, config|
|
36
|
-
item.meta[key] = config["value"], config["config"]
|
37
|
-
end
|
38
|
-
item.meta["stateDescription"] = item_json["stateDescription"] if item_json["stateDescription"]
|
39
|
-
item.category = item_json["category"] if item_json["category"]
|
40
|
-
|
41
|
-
$ir.add(item)
|
42
|
-
end
|
43
|
-
all_items.each do |item_json| # rubocop:disable Style/CombinableLoops
|
44
|
-
item_json["groupNames"].each do |group_name|
|
45
|
-
next unless (group = $ir.get(group_name))
|
46
|
-
|
47
|
-
group.add_member($ir.get(item_json["name"]))
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|