Module: OpenHAB::RSpec::Helpers

Defined in:
lib/openhab/rspec/helpers.rb

Overview

Provides helper methods for use in specs, to easily work with and adjust the openHAB environment.

These methods are automatically available in RSpec spec blocks, as well as other per-spec hooks like before and after. You can also call them explicitly.

Class Method Summary collapse

Class Method Details

.autorequiresvoid

This method returns an undefined value.

Require all files configured to be autorequired with the jrubyscripting addon in openHAB.

This method is normally called by RSpec hooks.



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/openhab/rspec/helpers.rb', line 181

def autorequires
  ENV["RUBYLIB"] ||= ""
  ENV["RUBYLIB"] += ":" unless ENV["RUBYLIB"].empty?
  ENV["RUBYLIB"] += rubylib_dirs.join(":")

  $LOAD_PATH.unshift(*ENV["RUBYLIB"]
    .split(File::PATH_SEPARATOR)
      .reject(&:empty?)
      .reject do |path|
                       $LOAD_PATH.include?(path)
                     end)

  requires = jrubyscripting_config&.get("require") || ""
  requires.split(",").each do |f|
    require f.strip
  end
end

.autoupdate_all_itemsvoid

This method returns an undefined value.

Reconfigure all items to autoupdate

To bypass any items configured to not autoupdate, waiting for the binding to update them.



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/openhab/rspec/helpers.rb', line 80

def autoupdate_all_items
  if instance_variable_defined?(:@autoupdated_items)
    raise RuntimeError "You should only call `autoupdate_all_items` once per spec"
  end

  @autoupdated_items = []
  @spec_metadata_provider = Core::Items::Metadata::Provider.current

  $ir.for_each do |_provider, item|
    if (hash = item.metadata["autoupdate"])
      provider = Core::Items::Metadata::Provider.registry.provider_for(hash.uid)
      provider.remove(hash.uid)
      @autoupdated_items << [provider, hash]
      provider(@spec_metadata_provider) do
        item.metadata["autoupdate"] = "true"
      end
    end
  end
end

.execute_timersvoid

This method returns an undefined value.

Execute all pending timers



105
106
107
108
109
110
111
112
# File 'lib/openhab/rspec/helpers.rb', line 105

def execute_timers
  raise "Cannot execute timers when timers aren't mocked" unless self.class.mock_timers?

  now = ZonedDateTime.now
  DSL::TimerManager.instance.instance_variable_get(:@timers).each_key do |t|
    t.execute if t.active? && t.execution_time <= now
  end
end

.install_addon(addon_id, wait: true, ready_markers: nil) ⇒ void

This method returns an undefined value.

Install an openHAB addon

Parameters:

  • addon_id (String)

    The addon id, such as "binding-mqtt"

  • wait (true, false) (defaults to: true)

    Wait until OSGi has confirmed the bundle is installed and running before returning.

  • ready_markers (String, Array<String>) (defaults to: nil)

    Array of ready marker types to wait for. The addon's bundle id is used as the identifier.



320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
# File 'lib/openhab/rspec/helpers.rb', line 320

def install_addon(addon_id, wait: true, ready_markers: nil)
  service_filter = "(component.name=org.openhab.core.karafaddons)"
  addon_service = OSGi.service("org.openhab.core.addon.AddonService", filter: service_filter)
  addon_service.install(addon_id)
  return unless wait

  addon = nil
  loop do
    addon = addon_service.get_addon(addon_id, nil)
    break if addon.installed?

    sleep 0.25
  end

  return unless ready_markers

  package_id = addon.logger_packages.first

  ready_markers = Array(ready_markers).map do |marker|
    case marker
    when String
      org.openhab.core.service.ReadyMarker.new(marker, package_id)
    else
      marker
    end
  end

  rs = OSGi.service("org.openhab.core.service.ReadyService")
  loop do
    break if ready_markers.all? { |rm| rs.ready?(rm) }

    sleep 0.25
  end
end

.launch_karaf(include_bindings: true, include_jsondb: true, private_confdir: false, use_root_instance: false) ⇒ void

This method returns an undefined value.

Launch the karaf instance

This method is normally called by RSpec hooks.

See Also:



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/openhab/rspec/helpers.rb', line 207

def launch_karaf(include_bindings: true,
                 include_jsondb: true,
                 private_confdir: false,
                 use_root_instance: false)
  karaf = Karaf.new("#{Dir.pwd}/.karaf")
  karaf.include_bindings = include_bindings
  karaf.include_jsondb = include_jsondb
  karaf.private_confdir = private_confdir
  karaf.use_root_instance = use_root_instance
  main = karaf.launch

  require "openhab/dsl"

  require_relative "mocks/persistence_service"
  require_relative "mocks/timer"

  # override several DSL methods
  require_relative "openhab/core/items/proxy"
  require_relative "openhab/core/things/proxy"
  require_relative "openhab/core/actions"

  ps = Mocks::PersistenceService.instance
  bundle = org.osgi.framework.FrameworkUtil.get_bundle(org.openhab.core.persistence.PersistenceService.java_class)
  bundle.bundle_context.register_service(org.openhab.core.persistence.PersistenceService.java_class, ps, nil)

  # wait for the rule engine
  rs = OSGi.service("org.openhab.core.service.ReadyService")
  filter = org.openhab.core.service.ReadyMarkerFilter.new
              .with_type(org.openhab.core.service.StartLevelService::STARTLEVEL_MARKER_TYPE)
              .with_identifier(org.openhab.core.service.StartLevelService::STARTLEVEL_RULEENGINE.to_s)

  karaf.send(:wait) do |continue|
    rs.register_tracker(org.openhab.core.service.ReadyService::ReadyTracker.impl { continue.call }, filter)
  end

  # RSpec additions
  require_relative "suspend_rules"

  if defined?(::RSpec)
    ::RSpec.configure do |config|
      config.include OpenHAB::DSL
    end
  end
  main
rescue Exception => e
  puts e.inspect
  puts e.backtrace
  raise
end

.load_rulesvoid

This method returns an undefined value.

Load all Ruby rules in the config/automation directory

This method is normally called by RSpec hooks.



264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/openhab/rspec/helpers.rb', line 264

def load_rules
  automation_paths = Array(::RSpec.configuration.openhab_automation_search_paths)

  lib_dirs = rubylib_dirs.map { |d| File.join(d, "") }
  lib_dirs << File.join(gem_home, "")

  SuspendRules.suspend_rules do
    files = automation_paths.map { |p| Dir["#{p}/**/*.rb"] }.flatten
    files.reject! do |f|
      lib_dirs.any? { |l| f.start_with?(l) }
    end
    files.sort_by { |f| [get_start_level(f), f] }.each do |f|
      load f
    rescue Exception => e
      warn "Failed loading #{f}: #{e.inspect}"
      warn e.backtrace
    end
  end
end

.load_transformsvoid

This method returns an undefined value.

Load all Ruby transformations in the config/transform directory

Since Ruby transformations must end with the .script extension, you must include an Emacs modeline comment (# -*- mode: ruby -*-) in your script for it to be recognized.

This method is normally called by RSpec hooks.



295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
# File 'lib/openhab/rspec/helpers.rb', line 295

def load_transforms
  transform_path = "#{org.openhab.core.OpenHAB.config_folder}/transform"
  Dir["#{transform_path}/**/*.script"].each do |filename|
    script = File.read(filename)
    next unless ruby_file?(script)

    filename.slice!(0..transform_path.length)
    dir = File.dirname(filename)
    modules = (dir == ".") ? [] : moduleize(dir)
    basename = File.basename(filename)
    method = basename[0...-7]
    modules << method
    Transform.add_script(modules, script)
  end
end

.log_fileString

Returns The filename of the openHAB log.

Returns:

  • (String)

    The filename of the openHAB log.



356
357
358
# File 'lib/openhab/rspec/helpers.rb', line 356

def log_file
  "#{java.lang.System.get_property("openhab.logdir", nil)}/openhab.log"
end

.spec_log_linesArray<String>

Returns The log lines since this spec started.

Examples:

it "logs" do
  logger.trace("log line")
  expect(spec_log_lines).to include(match(/TRACE.*log line/))
end

Returns:

  • (Array<String>)

    The log lines since this spec started.



369
370
371
372
373
374
# File 'lib/openhab/rspec/helpers.rb', line 369

def spec_log_lines
  File.open(log_file, "rb") do |f|
    f.seek(@log_index) if @log_index
    f.read.split("\n")
  end
end

.suspend_rules(&block) ⇒ Object

Suspend rules for the duration of the block

Returns:

  • (Object)

    The return value from the block.



136
137
138
# File 'lib/openhab/rspec/helpers.rb', line 136

def suspend_rules(&block)
  SuspendRules.suspend_rules(&block)
end

.time_travel_and_execute_timers(duration) ⇒ void

This method returns an undefined value.

Wait duration seconds, then execute any pending timers

If timers are mocked, it will use Timecop. If they're not mocked, it will just sleep for duration



122
123
124
125
126
127
128
129
# File 'lib/openhab/rspec/helpers.rb', line 122

def time_travel_and_execute_timers(duration)
  if self.class.mock_timers?
    Timecop.frozen? ? Timecop.freeze(duration) : Timecop.travel(duration)
    execute_timers
  else
    sleep duration
  end
end

.trigger_channel(channel, event = "") ⇒ void

This method returns an undefined value.

Manually send an event to a trigger channel

Parameters:



167
168
169
170
171
172
# File 'lib/openhab/rspec/helpers.rb', line 167

def trigger_channel(channel, event = "")
  channel = org.openhab.core.thing.ChannelUID.new(channel) if channel.is_a?(String)
  channel = channel.uid if channel.is_a?(org.openhab.core.thing.Channel)
  thing = channel.thing
  thing.handler.callback.channel_triggered(nil, channel, event)
end

.wait(how_long = 2.seconds) { ... } ⇒ void

This method returns an undefined value.

Calls the block repeatedly until the expectations inside pass.

Parameters:

  • how_long (Duration) (defaults to: 2.seconds)

    how long to keep trying before giving up

Yields:



146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/openhab/rspec/helpers.rb', line 146

def wait(how_long = 2.seconds)
  start = Process.clock_gettime(Process::CLOCK_MONOTONIC)

  begin
    yield
  rescue ::RSpec::Expectations::ExpectationNotMetError,
         ::RSpec::Mocks::MockExpectationError
    raise if Process.clock_gettime(Process::CLOCK_MONOTONIC) > start + how_long.to_f

    sleep 0.1
    retry
  end
end