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.
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