rspec-openhab-scripting 1.0.0
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 +7 -0
- data/lib/rspec/openhab/actions.rb +20 -0
- data/lib/rspec/openhab/api.rb +62 -0
- data/lib/rspec/openhab/core/item_proxy.rb +19 -0
- data/lib/rspec/openhab/core/logger.rb +43 -0
- data/lib/rspec/openhab/core/mocks/bundle_install_support.rb +26 -0
- data/lib/rspec/openhab/core/mocks/bundle_resolver.rb +32 -0
- data/lib/rspec/openhab/core/mocks/event_admin.rb +148 -0
- data/lib/rspec/openhab/core/mocks/persistence_service.rb +144 -0
- data/lib/rspec/openhab/core/mocks/synchronous_executor.rb +56 -0
- data/lib/rspec/openhab/core/mocks/thing_handler.rb +77 -0
- data/lib/rspec/openhab/core/openhab_setup.rb +11 -0
- data/lib/rspec/openhab/dsl/rules/triggers/watch.rb +11 -0
- data/lib/rspec/openhab/dsl/timers/timer.rb +88 -0
- data/lib/rspec/openhab/helpers.rb +249 -0
- data/lib/rspec/openhab/hooks.rb +56 -0
- data/lib/rspec/openhab/jruby.rb +45 -0
- data/lib/rspec/openhab/karaf.rb +733 -0
- data/lib/rspec/openhab/shell.rb +30 -0
- data/lib/rspec/openhab/suspend_rules.rb +56 -0
- data/lib/rspec/openhab/version.rb +7 -0
- data/lib/rspec-openhab-scripting.rb +17 -0
- metadata +232 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1f9f1f804d263fe2179ef5680704f14bc2ba476dc4525f014329aa30ea6e01d0
|
4
|
+
data.tar.gz: 924e7e3a2cc0f2578ff526d21a9a4050e216c7555004ebf21a7a76eca62a5e9c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 292ebc4f0386a670ee9b02528e13880e9c9801c397ada5bc83cc9193ff5728f056a27b6b780f6b5b8b789970da03fec6fa63fe6bc3420140ceaedba06f909e9e
|
7
|
+
data.tar.gz: b8c0d8e5619c50499189bfc1b85fa496d76549c03bbb23cae531e61afbac87a16b9f2d37cf4b6cb5518a55a5557570a248a0525ad4be66a84bcdb84a03b96bbf
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OpenHAB
|
4
|
+
module DSL
|
5
|
+
module Actions
|
6
|
+
# redefine these to do nothing so that rules won't fail
|
7
|
+
def notify(msg, email: nil) # rubocop:disable Lint/UnusedMethodArgument:
|
8
|
+
logger.debug("notify: #{msg}")
|
9
|
+
end
|
10
|
+
|
11
|
+
def say(text, voice: nil, sink: nil, volume: nil) # rubocop:disable Lint/UnusedMethodArgument:
|
12
|
+
logger.debug("say: #{text}")
|
13
|
+
end
|
14
|
+
|
15
|
+
def play_sound(filename, sink: nil, volume: nil) # rubocop:disable Lint/UnusedMethodArgument:
|
16
|
+
logger.debug("play_sound: #{filename}")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "faraday"
|
4
|
+
|
5
|
+
module OpenHAB
|
6
|
+
class API
|
7
|
+
def initialize(url, token = nil)
|
8
|
+
@faraday = Faraday.new(url) do |f|
|
9
|
+
f.response :raise_error
|
10
|
+
f.response :json
|
11
|
+
f.path_prefix = "/rest/"
|
12
|
+
f.headers = { "X-OPENHAB-TOKEN" => token } if token
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def version
|
17
|
+
version = root_data.dig("runtimeInfo", "version")
|
18
|
+
version = "#{version}-SNAPSHOT" if root_data.dig("runtimeInfo", "buildString")&.start_with?("Build #")
|
19
|
+
version
|
20
|
+
end
|
21
|
+
|
22
|
+
def locale
|
23
|
+
root_data["locale"]
|
24
|
+
end
|
25
|
+
|
26
|
+
def measurement_system
|
27
|
+
root_data["measurementSystem"]
|
28
|
+
end
|
29
|
+
|
30
|
+
def items
|
31
|
+
@faraday.get("items", metadata: ".*").body
|
32
|
+
end
|
33
|
+
|
34
|
+
def item(name)
|
35
|
+
@faraday.get("items/#{name}").body
|
36
|
+
rescue Faraday::ResourceNotFound
|
37
|
+
nil
|
38
|
+
end
|
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
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def root_data
|
59
|
+
@root_data ||= @faraday.get.body
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OpenHAB
|
4
|
+
module Core
|
5
|
+
class ItemProxy
|
6
|
+
@proxies = {}
|
7
|
+
|
8
|
+
class << self
|
9
|
+
# ensure each item only has a single proxy, so that
|
10
|
+
# expect(item).to receive(:method) works
|
11
|
+
def new(item)
|
12
|
+
@proxies.fetch(item.name) do
|
13
|
+
@proxies[item.name] = super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OpenHAB
|
4
|
+
module Core
|
5
|
+
class Logger
|
6
|
+
class << self
|
7
|
+
def log_service
|
8
|
+
@log_service = OSGI.service("org.apache.karaf.log.core.LogService")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def name
|
13
|
+
@sl4fj_logger.name
|
14
|
+
end
|
15
|
+
|
16
|
+
def level
|
17
|
+
self.class.log_service.get_level(name)[name]&.downcase&.to_sym
|
18
|
+
end
|
19
|
+
|
20
|
+
def level=(level)
|
21
|
+
self.class.log_service.set_level(name, level.to_s)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module Log
|
27
|
+
class << self
|
28
|
+
def root
|
29
|
+
logger(org.slf4j.Logger::ROOT_LOGGER_NAME)
|
30
|
+
end
|
31
|
+
|
32
|
+
def events
|
33
|
+
logger("openhab.event")
|
34
|
+
end
|
35
|
+
|
36
|
+
def logger(object)
|
37
|
+
logger_name = object if object.is_a?(String)
|
38
|
+
logger_name ||= logger_name(object)
|
39
|
+
@loggers[logger_name] ||= Core::Logger.new(logger_name)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "delegate"
|
4
|
+
|
5
|
+
module RSpec
|
6
|
+
module OpenHAB
|
7
|
+
module Core
|
8
|
+
module Mocks
|
9
|
+
class BundleInstallSupport < SimpleDelegator
|
10
|
+
include org.apache.karaf.features.internal.service.BundleInstallSupport
|
11
|
+
|
12
|
+
def initialize(parent, karaf_wrapper)
|
13
|
+
super(parent)
|
14
|
+
@karaf_wrapper = karaf_wrapper
|
15
|
+
end
|
16
|
+
|
17
|
+
def set_bundle_start_level(bundle, _start_level)
|
18
|
+
return if @karaf_wrapper.send(:blocked_bundle?, bundle)
|
19
|
+
|
20
|
+
super
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "singleton"
|
4
|
+
|
5
|
+
module RSpec
|
6
|
+
module OpenHAB
|
7
|
+
module Core
|
8
|
+
module Mocks
|
9
|
+
class BundleResolver
|
10
|
+
include org.openhab.core.util.BundleResolver
|
11
|
+
include Singleton
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@classes = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def register_class(klass, bundle)
|
18
|
+
# ensure we have an individual java class already
|
19
|
+
@classes[klass.become_java!] = bundle
|
20
|
+
end
|
21
|
+
|
22
|
+
def resolve_bundle(clazz)
|
23
|
+
bundle = @classes[clazz]
|
24
|
+
return bundle if bundle
|
25
|
+
|
26
|
+
org.osgi.framework.FrameworkUtil.get_bundle(clazz)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "singleton"
|
4
|
+
|
5
|
+
module RSpec
|
6
|
+
module OpenHAB
|
7
|
+
module Core
|
8
|
+
module Mocks
|
9
|
+
# reimplement to not use a thread
|
10
|
+
class OSGiEventManager
|
11
|
+
attr_reader :logger
|
12
|
+
|
13
|
+
def initialize(typed_event_factories, typed_event_subscribers)
|
14
|
+
@typed_event_factories = typed_event_factories
|
15
|
+
@typed_event_subscribers = typed_event_subscribers
|
16
|
+
@logger = org.slf4j.LoggerFactory.get_logger("rspec.openhab.core.mocks.event_handler")
|
17
|
+
end
|
18
|
+
|
19
|
+
def handle_event(osgi_event)
|
20
|
+
type = osgi_event.get_property("type")
|
21
|
+
payload = osgi_event.get_property("payload")
|
22
|
+
topic = osgi_event.get_property("topic")
|
23
|
+
source = osgi_event.get_property("source")
|
24
|
+
|
25
|
+
if type.is_a?(String) && payload.is_a?(String) && topic.is_a?(String)
|
26
|
+
handle_event_internal(type, payload, topic, source) unless type.empty? || payload.empty? || topic.empty?
|
27
|
+
else
|
28
|
+
logger.error("The handled OSGi event is invalid. " \
|
29
|
+
"Expect properties as string named 'type', 'payload', and 'topic'. " \
|
30
|
+
"Received event properties are: #{osgi_event.property_names.inspect}")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def handle_event_internal(type, payload, topic, source)
|
37
|
+
event_factory = @typed_event_factories[type]
|
38
|
+
unless event_factory
|
39
|
+
logger.debug("Could not find an Event Factory for the event type '#{type}'.")
|
40
|
+
return
|
41
|
+
end
|
42
|
+
|
43
|
+
event_subscribers = event_subscribers(type)
|
44
|
+
return if event_subscribers.empty?
|
45
|
+
|
46
|
+
event = create_event(event_factory, type, payload, topic, source)
|
47
|
+
return unless event
|
48
|
+
|
49
|
+
dispatch_event(event_subscribers, event)
|
50
|
+
end
|
51
|
+
|
52
|
+
def event_subscribers(event_type)
|
53
|
+
event_type_subscribers = @typed_event_subscribers[event_type]
|
54
|
+
all_event_type_subscribers = @typed_event_subscribers["ALL"]
|
55
|
+
|
56
|
+
subscribers = java.util.HashSet.new
|
57
|
+
subscribers.add_all(event_type_subscribers) if event_type_subscribers
|
58
|
+
subscribers.add_all(all_event_type_subscribers) if all_event_type_subscribers
|
59
|
+
subscribers
|
60
|
+
end
|
61
|
+
|
62
|
+
def create_event(event_factory, type, payload, topic, source)
|
63
|
+
event_factory.create_event(type, topic, payload, source)
|
64
|
+
rescue Exception => e
|
65
|
+
logger.warn("Creation of event failed, because one of the " \
|
66
|
+
"registered event factories has thrown an exception: #{e.inspect}")
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
|
70
|
+
def dispatch_event(event_subscribers, event)
|
71
|
+
event_subscribers.each do |event_subscriber|
|
72
|
+
filter = event_subscriber.event_filter
|
73
|
+
if filter.nil? || filter.apply(event)
|
74
|
+
begin
|
75
|
+
event_subscriber.receive(event)
|
76
|
+
rescue Exception => e
|
77
|
+
logger.warn(
|
78
|
+
"Dispatching/filtering event for subscriber '#{event_subscriber.class}' failed: #{e.inspect}"
|
79
|
+
)
|
80
|
+
end
|
81
|
+
else
|
82
|
+
logger.trace("Skip event subscriber (#{event_subscriber.class}) because of its filter.")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class EventAdmin < org.osgi.util.tracker.ServiceTracker
|
89
|
+
include org.osgi.service.event.EventAdmin
|
90
|
+
|
91
|
+
def initialize(bundle_context)
|
92
|
+
super(bundle_context, "org.osgi.service.event.EventHandler", nil)
|
93
|
+
|
94
|
+
@handlers_matching_all_events = []
|
95
|
+
@handlers_matching_topics = Hash.new { |h, k| h[k] = [] }
|
96
|
+
open
|
97
|
+
end
|
98
|
+
|
99
|
+
def addingService(reference) # rubocop:disable Naming/MethodName
|
100
|
+
topics = Array(reference.get_property(org.osgi.service.event.EventConstants::EVENT_TOPIC))
|
101
|
+
topics = nil if topics.empty? || topics.include?("*")
|
102
|
+
|
103
|
+
service = ::OpenHAB::Core::OSGI.send(:bundle_context).get_service(reference)
|
104
|
+
|
105
|
+
if reference.get_property("component.name") == "org.openhab.core.internal.events.OSGiEventManager"
|
106
|
+
# OSGiEventManager will create a ThreadedEventHandler on OSGi activation;
|
107
|
+
# we're skipping that, and directly sending to a non-threaded event handler.
|
108
|
+
service.class.field_reader :typedEventFactories, :typedEventSubscribers
|
109
|
+
service = OSGiEventManager.new(service.typedEventFactories, service.typedEventSubscribers)
|
110
|
+
end
|
111
|
+
if topics.nil?
|
112
|
+
@handlers_matching_all_events << service
|
113
|
+
else
|
114
|
+
topics.each do |topic|
|
115
|
+
@handlers_matching_topics[topic] << service
|
116
|
+
end
|
117
|
+
end
|
118
|
+
service
|
119
|
+
end
|
120
|
+
|
121
|
+
def postEvent(event) # rubocop:disable Naming/MethodName
|
122
|
+
sendEvent(event)
|
123
|
+
end
|
124
|
+
|
125
|
+
def sendEvent(event) # rubocop:disable Naming/MethodName
|
126
|
+
# prevent re-entrancy
|
127
|
+
if (pending_events = Thread.current[:event_admin_pending_events])
|
128
|
+
pending_events << event
|
129
|
+
return
|
130
|
+
end
|
131
|
+
|
132
|
+
pending_events = Thread.current[:event_admin_pending_events] = []
|
133
|
+
handle_event(event)
|
134
|
+
handle_event(pending_events.shift) until pending_events.empty?
|
135
|
+
Thread.current[:event_admin_pending_events] = nil
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
def handle_event(event)
|
141
|
+
@handlers_matching_all_events.each { |h| h.handle_event(event) }
|
142
|
+
@handlers_matching_topics[event.topic].each { |h| h.handle_event(event) }
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module OpenHAB
|
5
|
+
module Core
|
6
|
+
module Mocks
|
7
|
+
class PersistenceService
|
8
|
+
include org.openhab.core.persistence.ModifiablePersistenceService
|
9
|
+
include Singleton
|
10
|
+
|
11
|
+
class HistoricItem
|
12
|
+
include org.openhab.core.persistence.HistoricItem
|
13
|
+
|
14
|
+
attr_reader :timestamp, :state, :name
|
15
|
+
|
16
|
+
def initialize(timestamp, state, name)
|
17
|
+
@timestamp = timestamp
|
18
|
+
@state = state
|
19
|
+
@name = name
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :id
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
@id = "default"
|
27
|
+
reset
|
28
|
+
end
|
29
|
+
|
30
|
+
def reset
|
31
|
+
@data = Hash.new { |h, k| h[k] = [] }
|
32
|
+
end
|
33
|
+
|
34
|
+
def store(item, date = nil, state = nil)
|
35
|
+
date = nil if date.is_a?(String) # alias overload
|
36
|
+
state ||= item.state
|
37
|
+
date ||= ZonedDateTime.now
|
38
|
+
|
39
|
+
new_item = HistoricItem.new(date, state, item.name)
|
40
|
+
|
41
|
+
item_history = @data[item.name]
|
42
|
+
|
43
|
+
insert_index = item_history.bsearch_index do |i|
|
44
|
+
i.timestamp.compare_to(date).positive?
|
45
|
+
end
|
46
|
+
|
47
|
+
return item_history << new_item unless insert_index
|
48
|
+
|
49
|
+
return item_history[insert_index].state = state if item_history[insert_index].timestamp == date
|
50
|
+
|
51
|
+
item_history.insert(insert_index, new_item)
|
52
|
+
end
|
53
|
+
|
54
|
+
def remove(filter)
|
55
|
+
query_internal(filter) do |item_history, index|
|
56
|
+
historic_item = item_history.delete_at(index)
|
57
|
+
@data.delete(historic_item.name) if item_history.empty?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def query(filter)
|
62
|
+
result = []
|
63
|
+
|
64
|
+
query_internal(filter) do |item_history, index|
|
65
|
+
result << item_history[index]
|
66
|
+
|
67
|
+
return result if filter.page_number.zero? && result.length == filter.page_size && filter.item_name
|
68
|
+
end
|
69
|
+
|
70
|
+
result.sort_by! { |hi| hi.timestamp.to_instant.to_epoch_milli } unless filter.item_name
|
71
|
+
|
72
|
+
unless filter.page_number.zero?
|
73
|
+
result = result.slice(filter.page_number * filter.page_size, filter.page_size)
|
74
|
+
end
|
75
|
+
|
76
|
+
result
|
77
|
+
end
|
78
|
+
|
79
|
+
def get_item_info # rubocop:disable Naming/AccessorMethodName must match Java interface
|
80
|
+
@data.map do |(n, entries)|
|
81
|
+
[n, entries.length, entries.first.timestamp, entries.last.timestamp]
|
82
|
+
end.to_set
|
83
|
+
end
|
84
|
+
|
85
|
+
def get_default_strategies # rubocop:disable Naming/AccessorMethodName must match Java interface
|
86
|
+
[org.openhab.core.persistence.strategy.PersistenceStrategy::Globals::CHANGE]
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def query_internal(filter, &block)
|
92
|
+
if filter.item_name
|
93
|
+
return unless @data.key?(filter.item_name)
|
94
|
+
|
95
|
+
query_item_internal(@data[filter.item_name], filter, &block)
|
96
|
+
else
|
97
|
+
@data.each_value do |item_history|
|
98
|
+
query_item_internal(item_history, filter, &block)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def query_item_internal(item_history, filter)
|
104
|
+
first_index = 0
|
105
|
+
last_index = item_history.length
|
106
|
+
|
107
|
+
if filter.begin_date
|
108
|
+
first_index = item_history.bsearch_index do |i|
|
109
|
+
i.timestamp.compare_to(filter.begin_date).positive?
|
110
|
+
end
|
111
|
+
return if first_index.nil?
|
112
|
+
end
|
113
|
+
|
114
|
+
if filter.end_date
|
115
|
+
last_index = item_history.bsearch_index do |i|
|
116
|
+
i.timestamp.compare_to(filter.end_date).positive?
|
117
|
+
end
|
118
|
+
return if last_index.zero?
|
119
|
+
|
120
|
+
last_index ||= item_history.length
|
121
|
+
end
|
122
|
+
|
123
|
+
range = first_index...last_index
|
124
|
+
|
125
|
+
operator = filter.operator.symbol
|
126
|
+
operator = "==" if operator == "="
|
127
|
+
|
128
|
+
block = lambda do |i|
|
129
|
+
next if filter.state && !item_history[i].state.send(operator, filter.state)
|
130
|
+
|
131
|
+
yield(item_history, i)
|
132
|
+
end
|
133
|
+
|
134
|
+
if filter.ordering == filter.class::Ordering::DESCENDING
|
135
|
+
range.reverse_each(&block)
|
136
|
+
else
|
137
|
+
range.each(&block)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "singleton"
|
4
|
+
|
5
|
+
module RSpec
|
6
|
+
module OpenHAB
|
7
|
+
module Core
|
8
|
+
module Mocks
|
9
|
+
class CallbacksMap < java.util.HashMap
|
10
|
+
def put(_rule_uid, trigger_handler)
|
11
|
+
trigger_handler.executor.shutdown_now
|
12
|
+
trigger_handler.executor = SynchronousExecutor.instance
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class SynchronousExecutor < java.util.concurrent.ScheduledThreadPoolExecutor
|
18
|
+
class << self
|
19
|
+
def instance
|
20
|
+
@instance ||= new(1)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def submit(runnable)
|
25
|
+
runnable.respond_to?(:run) ? runnable.run : runnable.call
|
26
|
+
|
27
|
+
java.util.concurrent.CompletableFuture.completed_future(nil)
|
28
|
+
end
|
29
|
+
|
30
|
+
def execute(runnable)
|
31
|
+
runnable.run
|
32
|
+
end
|
33
|
+
|
34
|
+
def shutdown; end
|
35
|
+
|
36
|
+
def shutdown_now
|
37
|
+
[]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class SynchronousExecutorMap
|
42
|
+
include java.util.Map
|
43
|
+
include Singleton
|
44
|
+
|
45
|
+
def get(_key)
|
46
|
+
SynchronousExecutor.instance
|
47
|
+
end
|
48
|
+
|
49
|
+
def key_set
|
50
|
+
java.util.HashSet.new
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "singleton"
|
4
|
+
|
5
|
+
# rubocop:disable Naming have to follow java interface names
|
6
|
+
module RSpec
|
7
|
+
module OpenHAB
|
8
|
+
module Core
|
9
|
+
module Mocks
|
10
|
+
class ThingHandler
|
11
|
+
include org.openhab.core.thing.binding.BridgeHandler
|
12
|
+
|
13
|
+
attr_reader :thing, :callback
|
14
|
+
|
15
|
+
def initialize(thing = nil)
|
16
|
+
# have to handle the interface method
|
17
|
+
if thing.nil?
|
18
|
+
status_info = org.openhab.core.thing.binding.builder.ThingStatusInfoBuilder
|
19
|
+
.create(org.openhab.core.thing.ThingStatus::ONLINE).build
|
20
|
+
@callback.status_updated(self.thing, status_info)
|
21
|
+
return
|
22
|
+
end
|
23
|
+
|
24
|
+
# ruby initializer here
|
25
|
+
@thing = thing
|
26
|
+
end
|
27
|
+
|
28
|
+
def thing_updated(thing)
|
29
|
+
@thing = thing
|
30
|
+
end
|
31
|
+
|
32
|
+
def handle_command(channel, command); end
|
33
|
+
|
34
|
+
def set_callback(callback)
|
35
|
+
@callback = callback
|
36
|
+
end
|
37
|
+
|
38
|
+
def child_handler_initialized(child_handler, child_thing); end
|
39
|
+
def child_handler_disposed(child_handler, child_thing); end
|
40
|
+
|
41
|
+
def channel_linked(_channel_uid); end
|
42
|
+
def channel_unlinked(_channel_uid); end
|
43
|
+
|
44
|
+
def dispose; end
|
45
|
+
end
|
46
|
+
|
47
|
+
class ThingHandlerFactory < org.openhab.core.thing.binding.BaseThingHandlerFactory
|
48
|
+
include Singleton
|
49
|
+
|
50
|
+
class ComponentContext
|
51
|
+
include org.osgi.service.component.ComponentContext
|
52
|
+
include Singleton
|
53
|
+
|
54
|
+
def getBundleContext
|
55
|
+
org.osgi.framework.FrameworkUtil.get_bundle(org.openhab.core.thing.Thing).bundle_context
|
56
|
+
end
|
57
|
+
end
|
58
|
+
private_constant :ComponentContext
|
59
|
+
|
60
|
+
def initialize
|
61
|
+
super
|
62
|
+
activate(ComponentContext.instance)
|
63
|
+
end
|
64
|
+
|
65
|
+
def supportsThingType(_type)
|
66
|
+
true
|
67
|
+
end
|
68
|
+
|
69
|
+
def createHandler(thing)
|
70
|
+
ThingHandler.new(thing)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
# rubocop:enable Naming
|