openhab-jrubyscripting 5.0.0.rc1 → 5.0.0.rc3
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/openhab/core/entity_lookup.rb +1 -12
- data/lib/openhab/core/items/generic_item.rb +15 -7
- data/lib/openhab/core/items/metadata/hash.rb +81 -39
- data/lib/openhab/core/items/metadata/namespace_hash.rb +17 -19
- data/lib/openhab/core/items/metadata/provider.rb +48 -0
- data/lib/openhab/core/items/persistence.rb +2 -0
- data/lib/openhab/core/items/provider.rb +40 -0
- data/lib/openhab/core/items/proxy.rb +10 -0
- data/lib/openhab/core/items/registry.rb +16 -7
- data/lib/openhab/core/items/semantics/enumerable.rb +6 -4
- data/lib/openhab/core/items/state_storage.rb +3 -3
- data/lib/openhab/core/profile_factory.rb +3 -1
- data/lib/openhab/core/provider.rb +223 -0
- data/lib/openhab/core/registry.rb +30 -0
- data/lib/openhab/core/rules/provider.rb +25 -0
- data/lib/openhab/core/rules/registry.rb +76 -0
- data/lib/openhab/core/rules/rule.rb +150 -0
- data/lib/openhab/core/rules.rb +25 -0
- data/lib/openhab/core/script_handling.rb +50 -0
- data/lib/openhab/core/things/links/provider.rb +40 -0
- data/lib/openhab/core/things/provider.rb +25 -0
- data/lib/openhab/core/things/proxy.rb +10 -0
- data/lib/openhab/core/things/registry.rb +25 -2
- data/lib/openhab/core/timer.rb +17 -7
- data/lib/openhab/core/types/quantity_type.rb +5 -2
- data/lib/openhab/core/types.rb +1 -1
- data/lib/openhab/core.rb +3 -30
- data/lib/openhab/core_ext/java/class.rb +34 -0
- data/lib/openhab/core_ext/java/list.rb +436 -0
- data/lib/openhab/core_ext/java/local_time.rb +2 -1
- data/lib/openhab/core_ext/java/map.rb +66 -0
- data/lib/openhab/core_ext/java/month.rb +2 -1
- data/lib/openhab/core_ext/java/zoned_date_time.rb +1 -2
- data/lib/openhab/core_ext/ruby/date.rb +2 -0
- data/lib/openhab/core_ext/ruby/date_time.rb +53 -0
- data/lib/openhab/core_ext/ruby/time.rb +88 -86
- data/lib/openhab/dsl/events/watch_event.rb +1 -1
- data/lib/openhab/dsl/items/builder.rb +38 -100
- data/lib/openhab/dsl/items/ensure.rb +6 -2
- data/lib/openhab/dsl/items/timed_command.rb +10 -11
- data/lib/openhab/dsl/rules/automation_rule.rb +36 -13
- data/lib/openhab/dsl/rules/builder.rb +126 -8
- data/lib/openhab/dsl/rules/name_inference.rb +0 -5
- data/lib/openhab/dsl/rules/terse.rb +1 -2
- data/lib/openhab/dsl/rules/triggers/changed.rb +7 -4
- data/lib/openhab/dsl/rules/triggers/conditions/duration.rb +17 -53
- data/lib/openhab/dsl/rules/triggers/conditions/proc.rb +0 -3
- data/lib/openhab/dsl/rules/triggers/cron/cron.rb +1 -1
- data/lib/openhab/dsl/rules/triggers/trigger.rb +1 -1
- data/lib/openhab/dsl/rules/triggers/updated.rb +7 -3
- data/lib/openhab/dsl/rules/triggers/watch/watch_handler.rb +1 -1
- data/lib/openhab/dsl/rules.rb +0 -21
- data/lib/openhab/dsl/script_handling.rb +0 -49
- data/lib/openhab/dsl/things/builder.rb +8 -31
- data/lib/openhab/dsl/thread_local.rb +3 -2
- data/lib/openhab/dsl/timer_manager.rb +16 -8
- data/lib/openhab/dsl/version.rb +1 -1
- data/lib/openhab/dsl.rb +137 -120
- data/lib/openhab/log.rb +3 -3
- data/lib/openhab/rspec/example_group.rb +42 -0
- data/lib/openhab/rspec/helpers.rb +33 -27
- data/lib/openhab/rspec/hooks.rb +17 -23
- data/lib/openhab/rspec/karaf.rb +45 -27
- data/lib/openhab/rspec/mocks/synchronous_executor.rb +11 -4
- data/lib/openhab/rspec/mocks/timer.rb +7 -1
- data/lib/openhab/rspec/suspend_rules.rb +4 -2
- metadata +30 -3
- data/lib/openhab/rspec/mocks/metadata_provider.rb +0 -75
@@ -11,11 +11,12 @@ module OpenHAB
|
|
11
11
|
|
12
12
|
# Keys to persist
|
13
13
|
KNOWN_KEYS = %i[
|
14
|
+
openhab_ensure_states
|
15
|
+
openhab_persistence_service
|
16
|
+
openhab_providers
|
14
17
|
openhab_rule_uid
|
15
18
|
openhab_rule_type
|
16
19
|
openhab_units
|
17
|
-
openhab_persistence_service
|
18
|
-
openhab_ensure_states
|
19
20
|
].freeze
|
20
21
|
|
21
22
|
#
|
@@ -11,7 +11,7 @@ module OpenHAB
|
|
11
11
|
class TimerManager
|
12
12
|
include Singleton
|
13
13
|
|
14
|
-
ScriptHandling.script_unloaded { instance.cancel_all }
|
14
|
+
Core::ScriptHandling.script_unloaded { instance.cancel_all }
|
15
15
|
|
16
16
|
# @!visibility private
|
17
17
|
def initialize
|
@@ -31,7 +31,10 @@ module OpenHAB
|
|
31
31
|
# timer when one doesn't already exist
|
32
32
|
next old_timer if !reschedule && old_timer
|
33
33
|
|
34
|
-
old_timer
|
34
|
+
if old_timer
|
35
|
+
old_timer.cancel!
|
36
|
+
@timers.remove(old_timer)
|
37
|
+
end
|
35
38
|
Core::Timer.new(duration, id: id, thread_locals: thread_locals, block: block)
|
36
39
|
end
|
37
40
|
end
|
@@ -55,7 +58,7 @@ module OpenHAB
|
|
55
58
|
@timers.remove(timer)
|
56
59
|
return unless timer.id
|
57
60
|
|
58
|
-
@timers_by_id.
|
61
|
+
@timers_by_id.remove(timer.id)
|
59
62
|
end
|
60
63
|
|
61
64
|
#
|
@@ -67,7 +70,9 @@ module OpenHAB
|
|
67
70
|
def cancel(id)
|
68
71
|
result = false
|
69
72
|
@timers_by_id.compute_if_present(id) do |_key, timer|
|
70
|
-
result = timer.cancel
|
73
|
+
result = timer.cancel!
|
74
|
+
@timers.remove(timer)
|
75
|
+
|
71
76
|
nil
|
72
77
|
end
|
73
78
|
result
|
@@ -127,7 +132,7 @@ module OpenHAB
|
|
127
132
|
def schedule(id)
|
128
133
|
@timers_by_id.compute(id) do |_key, timer|
|
129
134
|
new_timer = yield timer
|
130
|
-
raise ArgumentError, "Block must return a timer or nil" unless
|
135
|
+
raise ArgumentError, "Block must return a timer or nil" unless new_timer.is_a?(Core::Timer) || new_timer.nil?
|
131
136
|
|
132
137
|
if !new_timer.equal?(timer) && new_timer&.id
|
133
138
|
raise ArgumentError,
|
@@ -136,8 +141,9 @@ module OpenHAB
|
|
136
141
|
|
137
142
|
if timer&.cancelled?
|
138
143
|
new_timer = nil
|
139
|
-
elsif new_timer.nil? && !timer
|
140
|
-
timer
|
144
|
+
elsif new_timer.nil? && timer && !timer.cancelled?
|
145
|
+
timer.cancel!
|
146
|
+
@timers.remove(timer)
|
141
147
|
end
|
142
148
|
next unless new_timer
|
143
149
|
|
@@ -179,9 +185,11 @@ module OpenHAB
|
|
179
185
|
# @return [void]
|
180
186
|
#
|
181
187
|
def cancel_all
|
182
|
-
|
188
|
+
logged = false
|
183
189
|
# don't use #each, in case timers are scheduling more timers
|
184
190
|
until @timers.empty?
|
191
|
+
logger.trace("Canceling #{@timers.length} timers") unless logged
|
192
|
+
logged = true
|
185
193
|
timer = @timers.keys.first
|
186
194
|
timer.cancel
|
187
195
|
end
|
data/lib/openhab/dsl/version.rb
CHANGED
data/lib/openhab/dsl.rb
CHANGED
@@ -30,7 +30,7 @@ module OpenHAB
|
|
30
30
|
# include this before Core::Actions so that Core::Action's method_missing
|
31
31
|
# takes priority
|
32
32
|
include Core::EntityLookup
|
33
|
-
[Core::Actions, Rules::Terse
|
33
|
+
[Core::Actions, Core::ScriptHandling, Rules::Terse].each do |mod|
|
34
34
|
# make these available both as regular and class methods
|
35
35
|
include mod
|
36
36
|
singleton_class.include mod
|
@@ -41,92 +41,14 @@ module OpenHAB
|
|
41
41
|
|
42
42
|
# @!group Rule Creation
|
43
43
|
|
44
|
-
#
|
45
|
-
|
46
|
-
|
47
|
-
# @param [String] name The rule name
|
48
|
-
# @yield Block executed in the context of a {Rules::Builder}
|
49
|
-
# @yieldparam [Rules::Builder] rule
|
50
|
-
# Optional parameter to access the rule configuration from within execution blocks and guards.
|
51
|
-
# @return [org.openhab.core.automation.Rule] The OpenHAB Rule object
|
52
|
-
#
|
53
|
-
# @see OpenHAB::DSL::Rules::Builder Rule builder for details on rule triggers, guards and execution blocks
|
54
|
-
# @see Rules::Terse Terse Rules
|
55
|
-
#
|
56
|
-
# @example
|
57
|
-
# require "openhab/dsl"
|
58
|
-
#
|
59
|
-
# rule "name" do
|
60
|
-
# <zero or more triggers>
|
61
|
-
# <zero or more execution blocks>
|
62
|
-
# <zero or more guards>
|
63
|
-
# end
|
64
|
-
#
|
65
|
-
def rule(name = nil, id: nil, script: nil, binding: nil, &block)
|
66
|
-
raise ArgumentError, "Block is required" unless block
|
67
|
-
|
68
|
-
id ||= Rules::NameInference.infer_rule_id_from_name(name) if name
|
69
|
-
id ||= Rules::NameInference.infer_rule_id_from_block(block)
|
70
|
-
script ||= block.source rescue nil # rubocop:disable Style/RescueModifier
|
71
|
-
|
72
|
-
builder = nil
|
73
|
-
|
74
|
-
ThreadLocal.thread_local(openhab_rule_type: "rule", openhab_rule_uid: id) do
|
75
|
-
builder = Rules::Builder.new(binding || block.binding)
|
76
|
-
builder.uid(id)
|
77
|
-
builder.instance_exec(builder, &block)
|
78
|
-
builder.guard = Rules::Guard.new(run_context: builder.caller, only_if: builder.only_if,
|
79
|
-
not_if: builder.not_if)
|
80
|
-
|
81
|
-
name ||= Rules::NameInference.infer_rule_name(builder)
|
82
|
-
name ||= id
|
83
|
-
|
84
|
-
builder.name(name)
|
85
|
-
logger.trace { builder.inspect }
|
86
|
-
builder.build(script)
|
87
|
-
rescue Exception => e
|
88
|
-
if (defined?(::RSpec::Expectations::ExpectationNotMetError) &&
|
89
|
-
e.is_a?(::RSpec::Expectations::ExpectationNotMetError)) ||
|
90
|
-
(defined?(::RSpec::Mocks::MockExpectationError) && e.is_a?(::RSpec::Mocks::MockExpectationError))
|
91
|
-
raise e
|
92
|
-
end
|
93
|
-
|
94
|
-
builder.send(:logger).log_exception(e)
|
95
|
-
end
|
44
|
+
# (see Rules::Builder#rule)
|
45
|
+
def rule(name = nil, **kwargs, &block)
|
46
|
+
rules.build { rule(name, **kwargs, &block) }
|
96
47
|
end
|
97
48
|
|
98
|
-
#
|
99
|
-
|
100
|
-
|
101
|
-
# A script is a rule with no triggers. It can be called by various other actions,
|
102
|
-
# such as the Run Rules action.
|
103
|
-
#
|
104
|
-
# @param [String] id The script's ID
|
105
|
-
# @param [String] name A descriptive name
|
106
|
-
# @yield [] Block executed when the script is executed.
|
107
|
-
#
|
108
|
-
def script(name = nil, id: nil, script: nil, &block)
|
109
|
-
raise ArgumentError, "Block is required" unless block
|
110
|
-
|
111
|
-
id ||= Rules::NameInference.infer_rule_id_from_name(name) if name
|
112
|
-
id ||= Rules::NameInference.infer_rule_id_from_block(block)
|
113
|
-
name ||= id
|
114
|
-
script ||= block.source rescue nil # rubocop:disable Style/RescueModifier
|
115
|
-
|
116
|
-
builder = nil
|
117
|
-
ThreadLocal.thread_local(openhab_rule_type: "script", openhab_rule_uid: id) do
|
118
|
-
begin
|
119
|
-
builder = Rules::Builder.new(block.binding)
|
120
|
-
builder.uid(id)
|
121
|
-
builder.tags(["Script"])
|
122
|
-
builder.name(name)
|
123
|
-
builder.script(&block)
|
124
|
-
logger.trace { builder.inspect }
|
125
|
-
builder.build(script)
|
126
|
-
end
|
127
|
-
rescue Exception => e
|
128
|
-
builder.send(:logger).log_exception(e)
|
129
|
-
end
|
49
|
+
# (see Rules::Builder#script)
|
50
|
+
def script(name = nil, id: nil, **kwargs, &block)
|
51
|
+
rules.build { script(name, id: id, **kwargs, &block) }
|
130
52
|
end
|
131
53
|
|
132
54
|
# @!group Rule Support
|
@@ -182,44 +104,17 @@ module OpenHAB
|
|
182
104
|
end
|
183
105
|
end
|
184
106
|
|
185
|
-
#
|
186
|
-
# Remove a rule
|
187
|
-
#
|
188
|
-
# @param [String, org.openhab.core.automation.Rule] uid The rule UID or the Rule object to remove.
|
189
|
-
# @return [void]
|
190
|
-
#
|
191
|
-
# @example
|
192
|
-
# my_rule = rule do
|
193
|
-
# every :day
|
194
|
-
# run { nil }
|
195
|
-
# end
|
196
|
-
#
|
197
|
-
# remove_rule(my_rule)
|
198
|
-
#
|
199
|
-
def remove_rule(uid)
|
200
|
-
uid = uid.uid if uid.respond_to?(:uid)
|
201
|
-
automation_rule = Rules.script_rules.delete(uid)
|
202
|
-
raise "Rule #{uid} doesn't exist to remove" unless automation_rule
|
203
|
-
|
204
|
-
automation_rule.cleanup
|
205
|
-
# automation_manager doesn't have a remove method, so just have to
|
206
|
-
# remove it directly from the provider
|
207
|
-
Rules.scripted_rule_provider.remove_rule(uid)
|
208
|
-
end
|
107
|
+
# @!group Object Access
|
209
108
|
|
210
109
|
#
|
211
|
-
#
|
110
|
+
# Fetches all rules from the rule registry.
|
212
111
|
#
|
213
|
-
# @
|
214
|
-
# @param [Object, nil] event The event to pass to the rule's execution blocks.
|
215
|
-
# @return [void]
|
112
|
+
# @return [Core::Rules::Registry]
|
216
113
|
#
|
217
|
-
def
|
218
|
-
Rules.
|
114
|
+
def rules
|
115
|
+
Core::Rules::Registry.instance
|
219
116
|
end
|
220
117
|
|
221
|
-
# @!group Object Access
|
222
|
-
|
223
118
|
#
|
224
119
|
# Fetches all items from the item registry
|
225
120
|
#
|
@@ -308,7 +203,7 @@ module OpenHAB
|
|
308
203
|
# different files.
|
309
204
|
#
|
310
205
|
# @see timers
|
311
|
-
# @see Rules::
|
206
|
+
# @see Rules::BuilderDSL#changed
|
312
207
|
# @see Items::TimedCommand
|
313
208
|
#
|
314
209
|
# @param [java.time.temporal.TemporalAmount, #to_zoned_date_time, Proc] duration
|
@@ -614,7 +509,7 @@ module OpenHAB
|
|
614
509
|
# properly restored.
|
615
510
|
#
|
616
511
|
# {unit!} calls are cumulative - additional calls will not erase the effects
|
617
|
-
# previous calls unless they are for the same dimension.
|
512
|
+
# of previous calls unless they are for the same dimension.
|
618
513
|
#
|
619
514
|
# @return [Hash<javax.measure.Dimension=>javax.measure.Unit>]
|
620
515
|
# the prior unit configuration
|
@@ -657,6 +552,129 @@ module OpenHAB
|
|
657
552
|
old_units
|
658
553
|
end
|
659
554
|
|
555
|
+
#
|
556
|
+
# Sets the implicit provider(s) for operations inside the block.
|
557
|
+
#
|
558
|
+
# @param (see #provider!)
|
559
|
+
# @yield [] The block will be executed in the context of the specified unit(s).
|
560
|
+
# @return [Object] the result of the block
|
561
|
+
#
|
562
|
+
# @example
|
563
|
+
# provider(metadata: :persistent) do
|
564
|
+
# Switch1.metadata[:last_status_from_service] = status
|
565
|
+
# end
|
566
|
+
#
|
567
|
+
# provider!(metadata: { last_status_from_service: :persistent }, Switch2: :persistent)
|
568
|
+
# Switch1.metadata[:last_status_from_service] = status # this will persist in JSONDB
|
569
|
+
# Switch1.metadata[:homekit] = "Lightbulb" # this will be removed when the script is deleted
|
570
|
+
# Switch2.metadata[:homekit] = "Lightbulb" # this will persist in JSONDB
|
571
|
+
#
|
572
|
+
# @see provider!
|
573
|
+
# @see OpenHAB::Core::Provider.current Provider.current for how the current provider is calculated
|
574
|
+
#
|
575
|
+
def provider(*args, **kwargs)
|
576
|
+
raise ArgumentError, "You must give a block to set the provider for the duration of" unless block_given?
|
577
|
+
|
578
|
+
begin
|
579
|
+
old_providers = provider!(*args, **kwargs)
|
580
|
+
yield
|
581
|
+
ensure
|
582
|
+
Thread.current[:openhab_providers] = old_providers
|
583
|
+
end
|
584
|
+
end
|
585
|
+
|
586
|
+
#
|
587
|
+
# Permanently set the implicit provider(s) for this thread.
|
588
|
+
#
|
589
|
+
# @note This method is only intended for use at the top level of rule
|
590
|
+
# scripts. If it's used within library methods, or hap-hazardly within
|
591
|
+
# rules, things can get very confusing because the prior state won't be
|
592
|
+
# properly restored.
|
593
|
+
#
|
594
|
+
# {provider!} calls are cumulative - additional calls will not erase the effects
|
595
|
+
# of previous calls unless they are for the same provider type.
|
596
|
+
#
|
597
|
+
# @overload provider!(things: nil, items: nil, metadata: nil, links: nil, **metadata_items)
|
598
|
+
#
|
599
|
+
# @param [Core::Provider, org.openhab.core.registry.common.ManagedProvider, :persistent, :transient, Proc] providers
|
600
|
+
# An explicit provider to use. If it's a {Core::Provider}, the type will be inferred automatically.
|
601
|
+
# Otherwise it's applied to all types.
|
602
|
+
# @param [Hash] providers_by_type
|
603
|
+
# A list of providers by type. Type can be `:items`, `:metadata`, `:things`, `:links`,
|
604
|
+
# a {GenericItem} applying the provider to all metadata on that item, or a String or Symbol
|
605
|
+
# applying the provider to all metadata of that namespace.
|
606
|
+
#
|
607
|
+
# The provider can be a {org.openhab.core.common.registry.Provider Provider}, `:persistent`,
|
608
|
+
# `:transient`, or a Proc returning one of those types. When the Proc is called for metadata
|
609
|
+
# elements, the {Core::Items::Metadata::Hash} will be passed as an argument. Therefore it's
|
610
|
+
# recommended that you use a Proc, not a Lambda, for permissive argument matching.
|
611
|
+
#
|
612
|
+
# @return [void]
|
613
|
+
#
|
614
|
+
# @see provider
|
615
|
+
# @see OpenHAB::Core::Provider.current Provider.current for how the current provider is calculated
|
616
|
+
#
|
617
|
+
def provider!(*providers, **providers_by_type)
|
618
|
+
thread_providers = Thread.current[:openhab_providers] ||= {}
|
619
|
+
old_providers = thread_providers.dup
|
620
|
+
|
621
|
+
providers.each do |provider|
|
622
|
+
case provider
|
623
|
+
when Core::Provider
|
624
|
+
thread_providers[provider.class.type] = provider
|
625
|
+
when org.openhab.core.common.registry.ManagedProvider
|
626
|
+
type = provider.type
|
627
|
+
unless type
|
628
|
+
raise ArgumentError, "#{provider.inspect} is for objects which are not supported by openhab-jrubyscripting"
|
629
|
+
end
|
630
|
+
|
631
|
+
thread_providers[type] = provider
|
632
|
+
when Proc,
|
633
|
+
:transient,
|
634
|
+
:persistent
|
635
|
+
Core::Provider::KNOWN_TYPES.each do |known_type|
|
636
|
+
thread_providers[known_type] = provider
|
637
|
+
end
|
638
|
+
when Hash
|
639
|
+
# non-symbols can't be used as kwargs, so Item keys show up as a separate hash here
|
640
|
+
# just merge it in, and allow it to be handled below
|
641
|
+
providers_by_type.merge!(provider)
|
642
|
+
else
|
643
|
+
raise ArgumentError, "#{provider.inspect} is not a valid provider"
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
647
|
+
providers_by_type.each do |type, provider|
|
648
|
+
case provider
|
649
|
+
when Proc,
|
650
|
+
org.openhab.core.common.registry.ManagedProvider,
|
651
|
+
:transient,
|
652
|
+
:persistent,
|
653
|
+
nil
|
654
|
+
nil
|
655
|
+
else
|
656
|
+
raise ArgumentError, "#{provider.inspect} is not a valid provider"
|
657
|
+
end
|
658
|
+
|
659
|
+
case type
|
660
|
+
when :items, :metadata, :things, :links
|
661
|
+
if provider.is_a?(org.openhab.core.common.registry.ManagedProvider) && provider.type != type
|
662
|
+
raise ArgumentError, "#{provider.inspect} is not a provider for #{type}"
|
663
|
+
end
|
664
|
+
|
665
|
+
thread_providers[type] = provider
|
666
|
+
when Symbol, String
|
667
|
+
(thread_providers[:metadata_namespaces] ||= {})[type.to_s] = provider
|
668
|
+
when GenericItem
|
669
|
+
(thread_providers[:metadata_items] ||= {})[type.name] = provider
|
670
|
+
else
|
671
|
+
raise ArgumentError, "#{type.inspect} is not provider type"
|
672
|
+
end
|
673
|
+
end
|
674
|
+
|
675
|
+
old_providers
|
676
|
+
end
|
677
|
+
|
660
678
|
# @!visibility private
|
661
679
|
def try_parse_time_like(string)
|
662
680
|
return string unless string.is_a?(String)
|
@@ -675,7 +693,6 @@ module OpenHAB
|
|
675
693
|
end
|
676
694
|
|
677
695
|
OpenHAB::Core.wait_till_openhab_ready
|
678
|
-
OpenHAB::Core.add_rubylib_to_load_path
|
679
696
|
|
680
697
|
# import Items classes into global namespace
|
681
698
|
OpenHAB::Core::Items.import_into_global_namespace
|
data/lib/openhab/log.rb
CHANGED
@@ -264,7 +264,7 @@ module OpenHAB
|
|
264
264
|
def log_exception(exception)
|
265
265
|
exception = clean_backtrace(exception)
|
266
266
|
error do
|
267
|
-
"#{exception.message} (#{exception.class})\n#{
|
267
|
+
"#{exception.message} (#{exception.class})\n#{exception.backtrace&.join("\n")}"
|
268
268
|
end
|
269
269
|
end
|
270
270
|
|
@@ -332,8 +332,8 @@ module OpenHAB
|
|
332
332
|
rule_type = Thread.current[:openhab_rule_type]
|
333
333
|
full_id = "#{rule_type}:#{rule_uid}"
|
334
334
|
|
335
|
-
self.class.rule_loggers[full_id] ||= Logger.new("#{Logger::PREFIX}.#{rule_type}.#{rule_uid
|
336
|
-
.gsub(/[^A-Za-z0-9_
|
335
|
+
self.class.rule_loggers[full_id] ||= Logger.new("#{Logger::PREFIX}.#{rule_type}.#{rule_uid
|
336
|
+
.gsub(/[^A-Za-z0-9_.:-]/, "")}")
|
337
337
|
end
|
338
338
|
|
339
339
|
extend Forwardable
|
@@ -79,6 +79,48 @@ module OpenHAB
|
|
79
79
|
|
80
80
|
true
|
81
81
|
end
|
82
|
+
|
83
|
+
# @!attribute [w] propagate_exceptions
|
84
|
+
#
|
85
|
+
# Set if exceptions in rules should be propagated in specs, instead of just logged.
|
86
|
+
#
|
87
|
+
# @param value [true, false, nil]
|
88
|
+
# @return [true, false, nil]
|
89
|
+
#
|
90
|
+
# @example
|
91
|
+
# describe "my_rule" do
|
92
|
+
# self.propagate_exceptions = false
|
93
|
+
#
|
94
|
+
# it "logs exceptions in rule execution" do
|
95
|
+
# expect(self.class.propagate_exceptions?).to be false
|
96
|
+
# rule do
|
97
|
+
# on_start
|
98
|
+
# run { raise "exception is logged" }
|
99
|
+
# end
|
100
|
+
# expect(spec_log_lines).to include(match(/exception is logged/))
|
101
|
+
# end
|
102
|
+
# end
|
103
|
+
#
|
104
|
+
def propagate_exceptions=(value)
|
105
|
+
@propagate_exceptions = value
|
106
|
+
end
|
107
|
+
|
108
|
+
#
|
109
|
+
# If timers are mocked for this example group
|
110
|
+
#
|
111
|
+
# It will search through parent groups until it finds one where it's
|
112
|
+
# explicitly defined, or defaults to `true` if none are.
|
113
|
+
#
|
114
|
+
# @return [true, false]
|
115
|
+
#
|
116
|
+
def propagate_exceptions?
|
117
|
+
if instance_variable_defined?(:@propagate_exceptions) && !@propagate_exceptions.nil?
|
118
|
+
return @propagate_exceptions
|
119
|
+
end
|
120
|
+
return superclass.propagate_exceptions? if superclass.is_a?(ClassMethods)
|
121
|
+
|
122
|
+
true
|
123
|
+
end
|
82
124
|
end
|
83
125
|
|
84
126
|
# @!visibility private
|
@@ -86,11 +86,16 @@ module OpenHAB
|
|
86
86
|
end
|
87
87
|
|
88
88
|
@autoupdated_items = []
|
89
|
+
@spec_metadata_provider = Core::Items::Metadata::Provider.current
|
89
90
|
|
90
91
|
$ir.for_each do |_provider, item|
|
91
|
-
if (hash = item.metadata
|
92
|
-
|
93
|
-
|
92
|
+
if (hash = item.metadata["autoupdate"])
|
93
|
+
provider = Core::Items::Metadata::Provider.registry.provider_for(hash.uid)
|
94
|
+
provider.remove(hash.uid)
|
95
|
+
@autoupdated_items << [provider, hash]
|
96
|
+
provider(@spec_metadata_provider) do
|
97
|
+
item.metadata["autoupdate"] = "true"
|
98
|
+
end
|
94
99
|
end
|
95
100
|
end
|
96
101
|
end
|
@@ -142,13 +147,13 @@ module OpenHAB
|
|
142
147
|
# @yield
|
143
148
|
# @return [void]
|
144
149
|
def wait(how_long = 2.seconds)
|
145
|
-
|
150
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
146
151
|
|
147
152
|
begin
|
148
153
|
yield
|
149
154
|
rescue ::RSpec::Expectations::ExpectationNotMetError,
|
150
155
|
::RSpec::Mocks::MockExpectationError
|
151
|
-
raise if
|
156
|
+
raise if Process.clock_gettime(Process::CLOCK_MONOTONIC) > start + how_long.to_f
|
152
157
|
|
153
158
|
sleep 0.1
|
154
159
|
retry
|
@@ -177,6 +182,17 @@ module OpenHAB
|
|
177
182
|
# @return [void]
|
178
183
|
#
|
179
184
|
def autorequires
|
185
|
+
ENV["RUBYLIB"] ||= ""
|
186
|
+
ENV["RUBYLIB"] += ":" unless ENV["RUBYLIB"].empty?
|
187
|
+
ENV["RUBYLIB"] += rubylib_dir
|
188
|
+
|
189
|
+
$LOAD_PATH.unshift(*ENV["RUBYLIB"]
|
190
|
+
.split(File::PATH_SEPARATOR)
|
191
|
+
.reject(&:empty?)
|
192
|
+
.reject do |path|
|
193
|
+
$LOAD_PATH.include?(path)
|
194
|
+
end)
|
195
|
+
|
180
196
|
requires = jrubyscripting_config&.get("require") || ""
|
181
197
|
requires.split(",").each do |f|
|
182
198
|
require f.strip
|
@@ -202,13 +218,9 @@ module OpenHAB
|
|
202
218
|
karaf.use_root_instance = use_root_instance
|
203
219
|
main = karaf.launch
|
204
220
|
|
205
|
-
ENV["RUBYLIB"] ||= ""
|
206
|
-
ENV["RUBYLIB"] += ":" unless ENV["RUBYLIB"].empty?
|
207
|
-
ENV["RUBYLIB"] += rubylib_dir
|
208
221
|
require "openhab/dsl"
|
209
222
|
|
210
223
|
require_relative "mocks/persistence_service"
|
211
|
-
require_relative "mocks/metadata_provider"
|
212
224
|
require_relative "mocks/timer"
|
213
225
|
|
214
226
|
# override several DSL methods
|
@@ -400,32 +412,26 @@ module OpenHAB
|
|
400
412
|
# need to transfer autoupdate metadata from GenericMetadataProvider to ManagedMetadataProvider
|
401
413
|
# so that we can mutate it in the future
|
402
414
|
def set_up_autoupdates
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
415
|
+
registry = Core::Items::Metadata::Provider.registry
|
416
|
+
registry.class.field_reader :identifierToElement
|
417
|
+
|
418
|
+
autoupdate_provider = Core::Items::Metadata::Provider.send(:new)
|
419
|
+
registry.all.each do |metadata|
|
408
420
|
next unless metadata.uid.namespace == "autoupdate"
|
409
421
|
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
to_add.each do |m|
|
415
|
-
# we can't just update; we need to remove and add
|
416
|
-
# because this was a duplicate key, so the ManagedProvider
|
417
|
-
# knows about it, but the registry does not. So
|
418
|
-
# removing and adding gets it to notify the registry
|
419
|
-
# that it has it
|
420
|
-
mmp.remove(m.uid) if mmp.get(m.uid)
|
421
|
-
mmp.add(m)
|
422
|
+
# tweak the registry to allow us to overwrite this element
|
423
|
+
registry.identifierToElement.delete(metadata.uid)
|
424
|
+
autoupdate_provider.add(metadata)
|
422
425
|
end
|
423
426
|
end
|
424
427
|
|
425
428
|
def restore_autoupdate_items
|
426
429
|
return unless instance_variable_defined?(:@autoupdated_items)
|
427
430
|
|
428
|
-
@autoupdated_items
|
431
|
+
@autoupdated_items.each do |(provider, hash)|
|
432
|
+
@spec_metadata_provider.remove(hash.uid)
|
433
|
+
provider.add(hash.instance_variable_get(:@metadata))
|
434
|
+
end
|
429
435
|
@autoupdated_items = nil
|
430
436
|
end
|
431
437
|
end
|
data/lib/openhab/rspec/hooks.rb
CHANGED
@@ -38,46 +38,40 @@ module OpenHAB
|
|
38
38
|
item.state = NULL unless item.raw_state == NULL
|
39
39
|
end
|
40
40
|
end
|
41
|
-
|
41
|
+
end
|
42
|
+
|
43
|
+
# Each spec gets temporary providers
|
44
|
+
[Core::Items::Provider,
|
45
|
+
Core::Items::Metadata::Provider,
|
46
|
+
Core::Rules::Provider,
|
47
|
+
Core::Things::Provider,
|
48
|
+
Core::Things::Links::Provider].each do |klass|
|
49
|
+
config.around do |example|
|
50
|
+
klass.new(&example)
|
51
|
+
end
|
42
52
|
end
|
43
53
|
|
44
54
|
config.before do |example|
|
45
|
-
|
46
|
-
|
47
|
-
@thing_provider = DSL::Things::ThingProvider.send(:new)
|
48
|
-
allow(DSL::Things::ThingProvider).to receive(:instance).and_return(@thing_provider)
|
49
|
-
@item_channel_link_provider = DSL::Items::ItemChannelLinkProvider.send(:new)
|
50
|
-
allow(DSL::Items::ItemChannelLinkProvider).to receive(:instance).and_return(@item_channel_link_provider)
|
51
|
-
mr = Core::Items::Metadata::NamespaceHash.registry
|
52
|
-
@metadata_provider = Mocks::MetadataProvider.new(mr.managed_provider.get)
|
53
|
-
mr.add_provider(@metadata_provider)
|
54
|
-
mr.set_managed_provider(@metadata_provider)
|
55
|
-
tm = OSGi.service("org.openhab.core.thing.ThingManager")
|
55
|
+
# clear persisted thing status
|
56
|
+
tm = Core::Things.manager
|
56
57
|
tm.class.field_reader :storage
|
57
58
|
tm.storage.keys.each { |k| tm.storage.remove(k) } # rubocop:disable Style/HashEachMethods not a hash
|
58
|
-
|
59
|
+
|
59
60
|
profile_factory = Core::ProfileFactory.send(:new)
|
60
61
|
@profile_factory_registration = OSGi.register_service(profile_factory)
|
61
62
|
allow(Core::ProfileFactory).to receive(:instance).and_return(profile_factory)
|
63
|
+
|
62
64
|
stub_const("OpenHAB::Core::Timer", Mocks::Timer) if self.class.mock_timers?
|
65
|
+
|
63
66
|
log_line = "rspec #{example.location} # #{example.full_description}"
|
64
67
|
logger.info(log_line)
|
65
68
|
Logger.events.info(log_line)
|
69
|
+
@log_index = File.size(log_file)
|
66
70
|
end
|
67
71
|
|
68
72
|
config.after do
|
69
|
-
# remove rules created during the spec
|
70
|
-
(Core.rule_registry.all.map(&:uid) - @known_rules).each do |uid|
|
71
|
-
remove_rule(uid) if defined?(remove_rule)
|
72
|
-
end
|
73
|
-
$ir.remove_provider(@item_provider)
|
74
73
|
Core::Items::Proxy.reset_cache
|
75
|
-
$things.remove_provider(@thing_provider)
|
76
74
|
Core::Things::Proxy.reset_cache
|
77
|
-
registry = OSGi.service("org.openhab.core.thing.link.ItemChannelLinkRegistry")
|
78
|
-
registry.remove_provider(@item_channel_link_provider)
|
79
|
-
Core::Items::Metadata::NamespaceHash.registry.remove_provider(@metadata_provider)
|
80
|
-
@metadata_provider.restore_parent
|
81
75
|
@profile_factory_registration.unregister
|
82
76
|
timers.cancel_all
|
83
77
|
# timers and rules have already been canceled, so we can safely just
|