openhab-jrubyscripting 5.0.0.rc1 → 5.0.0.rc3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|