event_system 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/README.md +362 -0
- data/Rakefile +4 -0
- data/docs/event_visualizations/example_timeline.html +142 -0
- data/docs/example_logs/events_20251027_151744.jsonl +3 -0
- data/docs/example_logs/events_20251027_151802.jsonl +3 -0
- data/docs/examples/basic_usage.rb +64 -0
- data/exe/event_system +139 -0
- data/lib/event_system/configuration.rb +125 -0
- data/lib/event_system/event.rb +139 -0
- data/lib/event_system/event_manager.rb +191 -0
- data/lib/event_system/event_subscriber.rb +29 -0
- data/lib/event_system/storage/base.rb +64 -0
- data/lib/event_system/storage/file_store.rb +187 -0
- data/lib/event_system/storage/memory_store.rb +134 -0
- data/lib/event_system/version.rb +5 -0
- data/lib/event_system/visualization/timeline_generator.rb +237 -0
- data/lib/event_system.rb +37 -0
- data/spec/event_system/configuration_spec.rb +197 -0
- data/spec/event_system/event_manager_spec.rb +341 -0
- data/spec/event_system/event_spec.rb +193 -0
- data/spec/event_system/event_subscriber_spec.rb +295 -0
- data/spec/event_system/storage/file_store_spec.rb +341 -0
- data/spec/event_system/storage/memory_store_spec.rb +248 -0
- data/spec/event_system/visualization/timeline_generator_spec.rb +252 -0
- data/spec/event_system_spec.rb +57 -0
- data/spec/integration/readme_examples_spec.rb +447 -0
- data/spec/spec_helper.rb +80 -0
- metadata +171 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
RSpec.describe EventSystem::Configuration do
|
|
6
|
+
let(:config) { EventSystem::Configuration.new }
|
|
7
|
+
|
|
8
|
+
describe '#initialize' do
|
|
9
|
+
it 'sets default values' do
|
|
10
|
+
expect(config.storage_type).to eq(:memory)
|
|
11
|
+
expect(config.storage_options).to eq({})
|
|
12
|
+
expect(config.logger).to be_a(Logger) # Logger is created on first access
|
|
13
|
+
expect(config.session_id).to be_a(String) # Session ID is generated on first access
|
|
14
|
+
expect(config.auto_flush).to be true
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe '#storage_class' do
|
|
19
|
+
it 'returns MemoryStore for memory type' do
|
|
20
|
+
config.storage_type = :memory
|
|
21
|
+
expect(config.storage_class).to eq(EventSystem::Storage::MemoryStore)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'returns FileStore for file type' do
|
|
25
|
+
config.storage_type = :file
|
|
26
|
+
expect(config.storage_class).to eq(EventSystem::Storage::FileStore)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'raises error for unknown storage type' do
|
|
30
|
+
config.storage_type = :unknown
|
|
31
|
+
expect { config.storage_class }.to raise_error(ArgumentError, /Unknown storage type/)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
describe '#create_storage' do
|
|
36
|
+
it 'creates MemoryStore with session_id' do
|
|
37
|
+
config.storage_type = :memory
|
|
38
|
+
config.session_id = 'test_session'
|
|
39
|
+
|
|
40
|
+
storage = config.create_storage
|
|
41
|
+
expect(storage).to be_a(EventSystem::Storage::MemoryStore)
|
|
42
|
+
expect(storage.current_session).to eq('test_session')
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'creates FileStore with directory and session_id' do
|
|
46
|
+
config.storage_type = :file
|
|
47
|
+
config.storage_options = { directory: 'test_logs' }
|
|
48
|
+
config.session_id = 'test_session'
|
|
49
|
+
|
|
50
|
+
storage = config.create_storage
|
|
51
|
+
expect(storage).to be_a(EventSystem::Storage::FileStore)
|
|
52
|
+
expect(storage.current_session).to eq('test_session')
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'uses default directory for file storage' do
|
|
56
|
+
config.storage_type = :file
|
|
57
|
+
storage = config.create_storage
|
|
58
|
+
expect(storage).to be_a(EventSystem::Storage::FileStore)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
describe '#logger' do
|
|
63
|
+
it 'creates default logger when none set' do
|
|
64
|
+
logger = config.logger
|
|
65
|
+
expect(logger).to be_a(Logger)
|
|
66
|
+
expect(logger.level).to eq(Logger::INFO)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it 'returns set logger' do
|
|
70
|
+
custom_logger = Logger.new(StringIO.new)
|
|
71
|
+
config.logger = custom_logger
|
|
72
|
+
expect(config.logger).to eq(custom_logger)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
describe '#session_id' do
|
|
77
|
+
it 'generates timestamp-based session ID when none set' do
|
|
78
|
+
session_id = config.session_id
|
|
79
|
+
expect(session_id).to match(/\d{8}_\d{6}/)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it 'returns set session ID' do
|
|
83
|
+
config.session_id = 'custom_session'
|
|
84
|
+
expect(config.session_id).to eq('custom_session')
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
describe '#reset!' do
|
|
89
|
+
it 'resets to default values' do
|
|
90
|
+
config.storage_type = :file
|
|
91
|
+
config.storage_options = { directory: 'test' }
|
|
92
|
+
config.logger = Logger.new(StringIO.new)
|
|
93
|
+
config.session_id = 'test_session'
|
|
94
|
+
config.auto_flush = false
|
|
95
|
+
|
|
96
|
+
config.reset!
|
|
97
|
+
|
|
98
|
+
expect(config.storage_type).to eq(:memory)
|
|
99
|
+
expect(config.storage_options).to eq({})
|
|
100
|
+
expect(config.logger).to be_a(Logger) # Logger is recreated on first access
|
|
101
|
+
expect(config.session_id).to be_a(String) # Session ID is generated on first access
|
|
102
|
+
expect(config.auto_flush).to be true
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe '#valid?' do
|
|
107
|
+
it 'returns true for valid memory configuration' do
|
|
108
|
+
config.storage_type = :memory
|
|
109
|
+
expect(config.valid?).to be true
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it 'returns true for valid file configuration with directory' do
|
|
113
|
+
config.storage_type = :file
|
|
114
|
+
config.storage_options = { directory: 'test_logs' }
|
|
115
|
+
expect(config.valid?).to be true
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it 'returns false for file configuration without directory' do
|
|
119
|
+
config.storage_type = :file
|
|
120
|
+
config.storage_options = {}
|
|
121
|
+
expect(config.valid?).to be false
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
it 'returns false for file configuration with empty directory' do
|
|
125
|
+
config.storage_type = :file
|
|
126
|
+
config.storage_options = { directory: '' }
|
|
127
|
+
expect(config.valid?).to be false
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it 'returns false for unknown storage type' do
|
|
131
|
+
config.storage_type = :unknown
|
|
132
|
+
expect(config.valid?).to be false
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it 'returns false for nil storage options' do
|
|
136
|
+
config.storage_type = :memory
|
|
137
|
+
config.storage_options = nil
|
|
138
|
+
expect(config.valid?).to be false
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
it 'handles string keys in storage options' do
|
|
142
|
+
config.storage_type = :file
|
|
143
|
+
config.storage_options = { 'directory' => 'test_logs' }
|
|
144
|
+
expect(config.valid?).to be true
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
describe '#to_h' do
|
|
149
|
+
it 'returns configuration as hash' do
|
|
150
|
+
config.storage_type = :file
|
|
151
|
+
config.storage_options = { directory: 'test' }
|
|
152
|
+
config.session_id = 'test_session'
|
|
153
|
+
config.auto_flush = false
|
|
154
|
+
|
|
155
|
+
hash = config.to_h
|
|
156
|
+
expect(hash[:storage_type]).to eq(:file)
|
|
157
|
+
expect(hash[:storage_options]).to eq({ directory: 'test' })
|
|
158
|
+
expect(hash[:session_id]).to eq('test_session')
|
|
159
|
+
expect(hash[:auto_flush]).to be false
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
describe 'storage constructor args' do
|
|
164
|
+
it 'returns correct args for memory storage' do
|
|
165
|
+
config.storage_type = :memory
|
|
166
|
+
config.session_id = 'test_session'
|
|
167
|
+
|
|
168
|
+
args = config.send(:storage_constructor_args)
|
|
169
|
+
expect(args).to eq(['test_session'])
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it 'returns correct args for file storage' do
|
|
173
|
+
config.storage_type = :file
|
|
174
|
+
config.storage_options = { directory: 'test_logs' }
|
|
175
|
+
config.session_id = 'test_session'
|
|
176
|
+
|
|
177
|
+
args = config.send(:storage_constructor_args)
|
|
178
|
+
expect(args).to eq(['test_logs', 'test_session'])
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
it 'uses default directory for file storage' do
|
|
182
|
+
config.storage_type = :file
|
|
183
|
+
config.storage_options = {}
|
|
184
|
+
|
|
185
|
+
args = config.send(:storage_constructor_args)
|
|
186
|
+
expect(args).to eq(['event_logs', nil])
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
it 'handles string keys in storage options' do
|
|
190
|
+
config.storage_type = :file
|
|
191
|
+
config.storage_options = { 'directory' => 'test_logs' }
|
|
192
|
+
|
|
193
|
+
args = config.send(:storage_constructor_args)
|
|
194
|
+
expect(args).to eq(['test_logs', nil])
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
RSpec.describe EventSystem::EventManager do
|
|
6
|
+
let(:manager) { create_test_manager }
|
|
7
|
+
|
|
8
|
+
describe '#initialize' do
|
|
9
|
+
it 'initializes with default configuration' do
|
|
10
|
+
manager = EventSystem::EventManager.new
|
|
11
|
+
expect(manager.config).to be_a(EventSystem::Configuration)
|
|
12
|
+
expect(manager.config.storage_type).to eq(:memory)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'initializes with hash configuration' do
|
|
16
|
+
config = { storage_type: :file, storage_options: { directory: 'test' } }
|
|
17
|
+
manager = EventSystem::EventManager.new(config)
|
|
18
|
+
expect(manager.config.storage_type).to eq(:file)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'initializes with Configuration object' do
|
|
22
|
+
config = EventSystem::Configuration.new
|
|
23
|
+
config.storage_type = :file
|
|
24
|
+
manager = EventSystem::EventManager.new(config)
|
|
25
|
+
expect(manager.config).to eq(config)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe '#subscribe' do
|
|
30
|
+
it 'subscribes a subscriber to a specific event type' do
|
|
31
|
+
subscriber = create_test_subscriber
|
|
32
|
+
manager.subscribe(:test_event, subscriber)
|
|
33
|
+
|
|
34
|
+
event = create_test_event(:test_event)
|
|
35
|
+
manager.publish(event)
|
|
36
|
+
|
|
37
|
+
expect(subscriber.events_received).to include(event)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'converts event type to string' do
|
|
41
|
+
subscriber = create_test_subscriber
|
|
42
|
+
manager.subscribe(:test_event, subscriber)
|
|
43
|
+
|
|
44
|
+
event = create_test_event('test_event')
|
|
45
|
+
manager.publish(event)
|
|
46
|
+
|
|
47
|
+
expect(subscriber.events_received).to include(event)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'allows multiple subscribers for same event type' do
|
|
51
|
+
subscriber1 = create_test_subscriber('Sub1')
|
|
52
|
+
subscriber2 = create_test_subscriber('Sub2')
|
|
53
|
+
|
|
54
|
+
manager.subscribe(:test_event, subscriber1)
|
|
55
|
+
manager.subscribe(:test_event, subscriber2)
|
|
56
|
+
|
|
57
|
+
event = create_test_event(:test_event)
|
|
58
|
+
manager.publish(event)
|
|
59
|
+
|
|
60
|
+
expect(subscriber1.events_received).to include(event)
|
|
61
|
+
expect(subscriber2.events_received).to include(event)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe '#unsubscribe' do
|
|
66
|
+
it 'unsubscribes a subscriber from an event type' do
|
|
67
|
+
subscriber = create_test_subscriber
|
|
68
|
+
manager.subscribe(:test_event, subscriber)
|
|
69
|
+
manager.unsubscribe(:test_event, subscriber)
|
|
70
|
+
|
|
71
|
+
event = create_test_event(:test_event)
|
|
72
|
+
manager.publish(event)
|
|
73
|
+
|
|
74
|
+
expect(subscriber.events_received).to be_empty
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it 'handles unsubscribing non-existent subscriber gracefully' do
|
|
78
|
+
subscriber = create_test_subscriber
|
|
79
|
+
expect { manager.unsubscribe(:test_event, subscriber) }.not_to raise_error
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
describe '#subscribe_all' do
|
|
84
|
+
it 'subscribes a subscriber to all event types' do
|
|
85
|
+
subscriber = create_test_subscriber
|
|
86
|
+
manager.subscribe_all(subscriber)
|
|
87
|
+
|
|
88
|
+
event1 = create_test_event(:event1)
|
|
89
|
+
event2 = create_test_event(:event2)
|
|
90
|
+
|
|
91
|
+
manager.publish(event1)
|
|
92
|
+
manager.publish(event2)
|
|
93
|
+
|
|
94
|
+
expect(subscriber.events_received).to include(event1, event2)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe '#unsubscribe_all' do
|
|
99
|
+
it 'unsubscribes a subscriber from all events' do
|
|
100
|
+
subscriber = create_test_subscriber
|
|
101
|
+
manager.subscribe_all(subscriber)
|
|
102
|
+
manager.unsubscribe_all(subscriber)
|
|
103
|
+
|
|
104
|
+
event = create_test_event(:test_event)
|
|
105
|
+
manager.publish(event)
|
|
106
|
+
|
|
107
|
+
expect(subscriber.events_received).to be_empty
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
describe '#publish' do
|
|
112
|
+
it 'publishes an event to subscribers' do
|
|
113
|
+
subscriber = create_test_subscriber
|
|
114
|
+
manager.subscribe(:test_event, subscriber)
|
|
115
|
+
|
|
116
|
+
event = create_test_event(:test_event)
|
|
117
|
+
manager.publish(event)
|
|
118
|
+
|
|
119
|
+
expect(subscriber.events_received).to include(event)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it 'stores event in storage' do
|
|
123
|
+
manager = create_file_manager
|
|
124
|
+
event = create_test_event(:test_event)
|
|
125
|
+
|
|
126
|
+
manager.publish(event)
|
|
127
|
+
|
|
128
|
+
events = manager.query_events(type: 'test_event')
|
|
129
|
+
expect(events).to include(event)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it 'delivers to both type-specific and universal subscribers' do
|
|
133
|
+
type_subscriber = create_test_subscriber('TypeSub')
|
|
134
|
+
universal_subscriber = create_test_subscriber('UniversalSub')
|
|
135
|
+
|
|
136
|
+
manager.subscribe(:test_event, type_subscriber)
|
|
137
|
+
manager.subscribe_all(universal_subscriber)
|
|
138
|
+
|
|
139
|
+
event = create_test_event(:test_event)
|
|
140
|
+
manager.publish(event)
|
|
141
|
+
|
|
142
|
+
expect(type_subscriber.events_received).to include(event)
|
|
143
|
+
expect(universal_subscriber.events_received).to include(event)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it 'handles subscriber errors gracefully' do
|
|
147
|
+
error_subscriber = Class.new do
|
|
148
|
+
include EventSystem::EventSubscriber
|
|
149
|
+
def handle_event(event)
|
|
150
|
+
raise StandardError, 'Test error'
|
|
151
|
+
end
|
|
152
|
+
end.new
|
|
153
|
+
|
|
154
|
+
manager.subscribe(:test_event, error_subscriber)
|
|
155
|
+
|
|
156
|
+
event = create_test_event(:test_event)
|
|
157
|
+
expect { manager.publish(event) }.not_to raise_error
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
describe '#publish_event' do
|
|
162
|
+
it 'creates and publishes an event' do
|
|
163
|
+
subscriber = create_test_subscriber
|
|
164
|
+
manager.subscribe(:test_event, subscriber)
|
|
165
|
+
|
|
166
|
+
event = manager.publish_event(:test_event, 'TestSource', { key: 'value' })
|
|
167
|
+
|
|
168
|
+
expect(event).to be_a(EventSystem::Event)
|
|
169
|
+
expect(event.type).to eq('test_event')
|
|
170
|
+
expect(event.source).to eq('TestSource')
|
|
171
|
+
expect(event.data).to eq({ key: 'value' })
|
|
172
|
+
expect(subscriber.events_received).to include(event)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it 'creates event with minimal parameters' do
|
|
176
|
+
event = manager.publish_event(:test_event)
|
|
177
|
+
expect(event.type).to eq('test_event')
|
|
178
|
+
expect(event.source).to be_nil
|
|
179
|
+
expect(event.data).to eq({})
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
describe '#query_events' do
|
|
184
|
+
it 'queries events from storage' do
|
|
185
|
+
manager = create_file_manager
|
|
186
|
+
event1 = create_test_event(:type1)
|
|
187
|
+
event2 = create_test_event(:type2)
|
|
188
|
+
|
|
189
|
+
manager.publish(event1)
|
|
190
|
+
manager.publish(event2)
|
|
191
|
+
|
|
192
|
+
events = manager.query_events(type: 'type1')
|
|
193
|
+
expect(events).to include(event1)
|
|
194
|
+
expect(events).not_to include(event2)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
it 'returns empty array when no storage' do
|
|
198
|
+
manager = create_test_manager(:memory)
|
|
199
|
+
events = manager.query_events
|
|
200
|
+
expect(events).to eq([])
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
describe '#current_session' do
|
|
205
|
+
it 'returns current session from storage' do
|
|
206
|
+
manager = create_file_manager
|
|
207
|
+
expect(manager.current_session).to be_a(String)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
it 'returns current session from memory storage' do
|
|
211
|
+
manager = create_test_manager(:memory)
|
|
212
|
+
expect(manager.current_session).to be_a(String)
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
describe '#switch_session' do
|
|
217
|
+
it 'switches to different session' do
|
|
218
|
+
manager = create_file_manager
|
|
219
|
+
original_session = manager.current_session
|
|
220
|
+
|
|
221
|
+
manager.switch_session('new_session')
|
|
222
|
+
|
|
223
|
+
expect(manager.current_session).to eq('new_session')
|
|
224
|
+
expect(manager.current_session).not_to eq(original_session)
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
describe '#create_session' do
|
|
229
|
+
it 'creates new session with given ID' do
|
|
230
|
+
manager = create_file_manager
|
|
231
|
+
session_id = manager.create_session('custom_session')
|
|
232
|
+
|
|
233
|
+
expect(session_id).to eq('custom_session')
|
|
234
|
+
expect(manager.current_session).to eq('custom_session')
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
it 'creates new session with auto-generated ID' do
|
|
238
|
+
manager = create_file_manager
|
|
239
|
+
session_id = manager.create_session
|
|
240
|
+
|
|
241
|
+
expect(session_id).to match(/\d{8}_\d{6}/)
|
|
242
|
+
expect(manager.current_session).to eq(session_id)
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
describe '#stats' do
|
|
247
|
+
it 'returns system statistics' do
|
|
248
|
+
stats = manager.stats
|
|
249
|
+
|
|
250
|
+
expect(stats).to have_key(:subscribers)
|
|
251
|
+
expect(stats).to have_key(:storage)
|
|
252
|
+
expect(stats).to have_key(:config)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
it 'includes subscriber counts' do
|
|
256
|
+
subscriber1 = create_test_subscriber
|
|
257
|
+
subscriber2 = create_test_subscriber
|
|
258
|
+
|
|
259
|
+
manager.subscribe(:event1, subscriber1)
|
|
260
|
+
manager.subscribe(:event1, subscriber2)
|
|
261
|
+
manager.subscribe(:event2, subscriber1)
|
|
262
|
+
|
|
263
|
+
stats = manager.stats
|
|
264
|
+
expect(stats[:subscribers]['event1']).to eq(2)
|
|
265
|
+
expect(stats[:subscribers]['event2']).to eq(1)
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
describe '#close' do
|
|
270
|
+
it 'closes the event manager' do
|
|
271
|
+
manager = create_file_manager
|
|
272
|
+
expect { manager.close }.not_to raise_error
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
describe '#ready?' do
|
|
277
|
+
it 'returns true when storage is available' do
|
|
278
|
+
manager = create_file_manager
|
|
279
|
+
expect(manager.ready?).to be true
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
it 'returns true when memory storage is available' do
|
|
283
|
+
manager = create_test_manager(:memory)
|
|
284
|
+
expect(manager.ready?).to be true
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
describe 'subscriber priority' do
|
|
289
|
+
it 'processes subscribers in priority order' do
|
|
290
|
+
high_priority = Class.new do
|
|
291
|
+
include EventSystem::EventSubscriber
|
|
292
|
+
attr_reader :events_received
|
|
293
|
+
def initialize; @events_received = []; end
|
|
294
|
+
def handle_event(event); @events_received << "high_#{event.type}"; end
|
|
295
|
+
def event_priority; 1; end
|
|
296
|
+
end.new
|
|
297
|
+
|
|
298
|
+
low_priority = Class.new do
|
|
299
|
+
include EventSystem::EventSubscriber
|
|
300
|
+
attr_reader :events_received
|
|
301
|
+
def initialize; @events_received = []; end
|
|
302
|
+
def handle_event(event); @events_received << "low_#{event.type}"; end
|
|
303
|
+
def event_priority; 10; end
|
|
304
|
+
end.new
|
|
305
|
+
|
|
306
|
+
manager.subscribe(:test_event, high_priority)
|
|
307
|
+
manager.subscribe(:test_event, low_priority)
|
|
308
|
+
|
|
309
|
+
event = create_test_event(:test_event)
|
|
310
|
+
manager.publish(event)
|
|
311
|
+
|
|
312
|
+
# High priority should be processed first (lower number = higher priority)
|
|
313
|
+
expect(high_priority.events_received).to include('high_test_event')
|
|
314
|
+
expect(low_priority.events_received).to include('low_test_event')
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
describe 'event type filtering' do
|
|
319
|
+
it 'respects subscriber event type filtering' do
|
|
320
|
+
filtered_subscriber = Class.new do
|
|
321
|
+
include EventSystem::EventSubscriber
|
|
322
|
+
attr_reader :events_received
|
|
323
|
+
def initialize; @events_received = []; end
|
|
324
|
+
def handle_event(event); @events_received << event; end
|
|
325
|
+
def handles_event_type?(event_type); event_type == 'allowed_event'; end
|
|
326
|
+
end.new
|
|
327
|
+
|
|
328
|
+
manager.subscribe(:allowed_event, filtered_subscriber)
|
|
329
|
+
manager.subscribe(:blocked_event, filtered_subscriber)
|
|
330
|
+
|
|
331
|
+
allowed_event = create_test_event(:allowed_event)
|
|
332
|
+
blocked_event = create_test_event(:blocked_event)
|
|
333
|
+
|
|
334
|
+
manager.publish(allowed_event)
|
|
335
|
+
manager.publish(blocked_event)
|
|
336
|
+
|
|
337
|
+
expect(filtered_subscriber.events_received).to include(allowed_event)
|
|
338
|
+
expect(filtered_subscriber.events_received).not_to include(blocked_event)
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
end
|