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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5dd7ea9915aa3edecf86f75d7331bfe77ad3fbbbee4c278fd130895e4bc1e6c
4
- data.tar.gz: 489db2879bf94009c027fcbb87572ae5b3834d31fab17f473cddc2fdecfebdfd
3
+ metadata.gz: ea386c264164b6c12be46d5483fdd349c3e5fdadcba22bff4987a2db5c6a9803
4
+ data.tar.gz: 20c364d137e43d5de1a1ab5eda9341318132cbde7532cf9c84901badce83ed49
5
5
  SHA512:
6
- metadata.gz: 967d33cd26a809179324637df7ebb9243ec901ae6c75aaa97a1615a6f699082bb83050727502c326bcf85732f86521f93ce253877306d8e6cf86b4ed84030708
7
- data.tar.gz: 375c3ebb1c64176b3da00a8489b8b9574e5636d767a2cb981100dc3b6b3128cbf23fc8b7ab9998ed3b7154a9d0754be6f349d3711ef326e7714ec360cac89732
6
+ metadata.gz: 13ae42f75b1bcaa898969e4077cefd1bbbc0979a7a081b7e904db9ff2c0b9550205bef2f4d20e3c502c2d12c449b64886819622101cb4425ee8ce4083cc02ea8
7
+ data.tar.gz: dd85b3c9249e88031ed3bf297dd09c1e7698cdb6d0958b04b0efbe35117dc6c71043b22f258b49fa0b52bb58a98ff3c3d5e6e492c6f551c393ce5a16187e9f75
@@ -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
- attr_reader :symbolic_name, :version
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("Dispatching/filtering event for subscriber '#{event_subscriber.class}' failed: #{e}")
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("org.openhab.core.items.MetadataRegistry", mr)
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 = org.openhab.core.internal.common.SafeCallerImpl.new({})
366
- aum = org.openhab.core.thing.internal.AutoUpdateManager.new({ "enabled" => "true" }, nil, ep, iclr, mr, tr)
367
- cm = org.openhab.core.thing.internal.CommunicationManager.new(aum, nil, nil, iclr, ir, nil, ep, sc, tr)
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(ief)
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|
@@ -1,20 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- RSpec.configure do |config|
4
- config.before do
5
- suspend_rules do
6
- $ir.for_each do |_provider, item|
7
- next if item.is_a?(GroupItem) # groups only have calculated states
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
- item.state = NULL unless item.raw_state == NULL
20
+ item.state = NULL unless item.raw_state == NULL
21
+ end
22
+ end
10
23
  end
11
- end
12
- end
13
24
 
14
- config.after do
15
- OpenHAB::DSL::Timers.timer_manager.cancel_all
16
- Timecop.return
17
- restore_autoupdate_items
18
- RSpec::OpenHAB::Core::Mocks::PersistenceService.instance.reset
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RSpec
4
4
  module OpenHAB
5
- VERSION = "0.0.16"
5
+ VERSION = "0.0.19"
6
6
  end
7
7
  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.16
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-07-18 00:00:00.000000000 Z
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.5'
243
+ version: '2.6'
241
244
  required_rubygems_version: !ruby/object:Gem::Requirement
242
245
  requirements:
243
246
  - - ">="
@@ -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