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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/lib/openhab/core/entity_lookup.rb +1 -12
  3. data/lib/openhab/core/items/generic_item.rb +15 -7
  4. data/lib/openhab/core/items/metadata/hash.rb +81 -39
  5. data/lib/openhab/core/items/metadata/namespace_hash.rb +17 -19
  6. data/lib/openhab/core/items/metadata/provider.rb +48 -0
  7. data/lib/openhab/core/items/persistence.rb +2 -0
  8. data/lib/openhab/core/items/provider.rb +40 -0
  9. data/lib/openhab/core/items/proxy.rb +10 -0
  10. data/lib/openhab/core/items/registry.rb +16 -7
  11. data/lib/openhab/core/items/semantics/enumerable.rb +6 -4
  12. data/lib/openhab/core/items/state_storage.rb +3 -3
  13. data/lib/openhab/core/profile_factory.rb +3 -1
  14. data/lib/openhab/core/provider.rb +223 -0
  15. data/lib/openhab/core/registry.rb +30 -0
  16. data/lib/openhab/core/rules/provider.rb +25 -0
  17. data/lib/openhab/core/rules/registry.rb +76 -0
  18. data/lib/openhab/core/rules/rule.rb +150 -0
  19. data/lib/openhab/core/rules.rb +25 -0
  20. data/lib/openhab/core/script_handling.rb +50 -0
  21. data/lib/openhab/core/things/links/provider.rb +40 -0
  22. data/lib/openhab/core/things/provider.rb +25 -0
  23. data/lib/openhab/core/things/proxy.rb +10 -0
  24. data/lib/openhab/core/things/registry.rb +25 -2
  25. data/lib/openhab/core/timer.rb +17 -7
  26. data/lib/openhab/core/types/quantity_type.rb +5 -2
  27. data/lib/openhab/core/types.rb +1 -1
  28. data/lib/openhab/core.rb +3 -30
  29. data/lib/openhab/core_ext/java/class.rb +34 -0
  30. data/lib/openhab/core_ext/java/list.rb +436 -0
  31. data/lib/openhab/core_ext/java/local_time.rb +2 -1
  32. data/lib/openhab/core_ext/java/map.rb +66 -0
  33. data/lib/openhab/core_ext/java/month.rb +2 -1
  34. data/lib/openhab/core_ext/java/zoned_date_time.rb +1 -2
  35. data/lib/openhab/core_ext/ruby/date.rb +2 -0
  36. data/lib/openhab/core_ext/ruby/date_time.rb +53 -0
  37. data/lib/openhab/core_ext/ruby/time.rb +88 -86
  38. data/lib/openhab/dsl/events/watch_event.rb +1 -1
  39. data/lib/openhab/dsl/items/builder.rb +38 -100
  40. data/lib/openhab/dsl/items/ensure.rb +6 -2
  41. data/lib/openhab/dsl/items/timed_command.rb +10 -11
  42. data/lib/openhab/dsl/rules/automation_rule.rb +36 -13
  43. data/lib/openhab/dsl/rules/builder.rb +126 -8
  44. data/lib/openhab/dsl/rules/name_inference.rb +0 -5
  45. data/lib/openhab/dsl/rules/terse.rb +1 -2
  46. data/lib/openhab/dsl/rules/triggers/changed.rb +7 -4
  47. data/lib/openhab/dsl/rules/triggers/conditions/duration.rb +17 -53
  48. data/lib/openhab/dsl/rules/triggers/conditions/proc.rb +0 -3
  49. data/lib/openhab/dsl/rules/triggers/cron/cron.rb +1 -1
  50. data/lib/openhab/dsl/rules/triggers/trigger.rb +1 -1
  51. data/lib/openhab/dsl/rules/triggers/updated.rb +7 -3
  52. data/lib/openhab/dsl/rules/triggers/watch/watch_handler.rb +1 -1
  53. data/lib/openhab/dsl/rules.rb +0 -21
  54. data/lib/openhab/dsl/script_handling.rb +0 -49
  55. data/lib/openhab/dsl/things/builder.rb +8 -31
  56. data/lib/openhab/dsl/thread_local.rb +3 -2
  57. data/lib/openhab/dsl/timer_manager.rb +16 -8
  58. data/lib/openhab/dsl/version.rb +1 -1
  59. data/lib/openhab/dsl.rb +137 -120
  60. data/lib/openhab/log.rb +3 -3
  61. data/lib/openhab/rspec/example_group.rb +42 -0
  62. data/lib/openhab/rspec/helpers.rb +33 -27
  63. data/lib/openhab/rspec/hooks.rb +17 -23
  64. data/lib/openhab/rspec/karaf.rb +45 -27
  65. data/lib/openhab/rspec/mocks/synchronous_executor.rb +11 -4
  66. data/lib/openhab/rspec/mocks/timer.rb +7 -1
  67. data/lib/openhab/rspec/suspend_rules.rb +4 -2
  68. metadata +30 -3
  69. 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&.cancel
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.delete(timer.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 timer.is_a?(Core::Timer) || timer.nil?
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&.cancelled?
140
- timer&.cancel
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
- logger.trace("Canceling #{@timers.length} timers")
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
@@ -4,6 +4,6 @@ module OpenHAB
4
4
  module DSL
5
5
  # Version of OpenHAB helper libraries
6
6
  # @return [String]
7
- VERSION = "5.0.0.rc1"
7
+ VERSION = "5.0.0.rc3"
8
8
  end
9
9
  end
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, ScriptHandling].each do |mod|
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
- # Create a new rule
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
- # Create a new script
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
- # Manually trigger a rule by ID
110
+ # Fetches all rules from the rule registry.
212
111
  #
213
- # @param [String] uid The rule ID
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 trigger_rule(uid, event = nil)
218
- Rules.script_rules.fetch(uid).execute(nil, { "event" => event })
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::Builder#changed
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#{name}#{exception.backtrace&.join("\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.tr_s(":", "_")
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.delete("autoupdate"))
92
- @autoupdated_items << hash
93
- item.metadata["autoupdate"] = "true"
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
- now = Time.now
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 Time.now > now + how_long
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
- gmp = OSGi.service("org.openhab.core.model.item.internal.GenericMetadataProvider")
404
- mr = Core::Items::Metadata::NamespaceHash.registry
405
- mmp = mr.managed_provider.get
406
- to_add = []
407
- gmp.all.each do |metadata|
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
- to_add << metadata
411
- end
412
- gmp.remove_metadata_by_namespace("autoupdate")
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&.each(&:commit)
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
@@ -38,46 +38,40 @@ module OpenHAB
38
38
  item.state = NULL unless item.raw_state == NULL
39
39
  end
40
40
  end
41
- @known_rules = Core.rule_registry.all.map(&:uid)
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
- @item_provider = DSL::Items::ItemProvider.send(:new)
46
- allow(DSL::Items::ItemProvider).to receive(:instance).and_return(@item_provider)
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
- @log_index = File.size(log_file)
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