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.
@@ -0,0 +1,252 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe EventSystem::Visualization::TimelineGenerator do
6
+ let(:temp_dir) { @temp_dir }
7
+ let(:storage) { EventSystem::Storage::FileStore.new(temp_dir, 'test_session') }
8
+ let(:generator) { EventSystem::Visualization::TimelineGenerator.new(storage) }
9
+
10
+ before do
11
+ # Add some test events
12
+ storage.store(create_test_event(:user_created, 'UserService', { user_id: 123, name: 'John Doe' }))
13
+ storage.store(create_test_event(:order_placed, 'OrderService', { order_id: 456, amount: 99.99 }))
14
+ storage.store(create_test_event(:payment_received, 'PaymentService', { payment_id: 789, amount: 99.99 }))
15
+ end
16
+
17
+ describe '#initialize' do
18
+ it 'initializes with storage' do
19
+ expect(generator.storage).to eq(storage)
20
+ end
21
+ end
22
+
23
+ describe '#generate_timeline' do
24
+ it 'generates HTML timeline for current session' do
25
+ output_path = generator.generate_timeline
26
+
27
+ expect(output_path).to be_a(String)
28
+ expect(File.exist?(output_path)).to be true
29
+ expect(output_path).to end_with('.html')
30
+ end
31
+
32
+ it 'generates HTML timeline for specific session' do
33
+ output_path = generator.generate_timeline('test_session')
34
+
35
+ expect(output_path).to be_a(String)
36
+ expect(File.exist?(output_path)).to be true
37
+ end
38
+
39
+ it 'generates HTML timeline with custom output file' do
40
+ output_path = generator.generate_timeline('test_session', 'custom_timeline.html')
41
+
42
+ expect(output_path).to include('custom_timeline.html')
43
+ expect(File.exist?(output_path)).to be true
44
+ end
45
+
46
+ it 'returns nil when no events found' do
47
+ # Create a storage with no session files
48
+ empty_storage = EventSystem::Storage::FileStore.new(temp_dir)
49
+ # Mock list_sessions to return empty array
50
+ allow(empty_storage).to receive(:list_sessions).and_return([])
51
+ empty_generator = EventSystem::Visualization::TimelineGenerator.new(empty_storage)
52
+
53
+ result = empty_generator.generate_timeline
54
+ expect(result).to be_nil
55
+ end
56
+
57
+ it 'creates event_visualizations directory' do
58
+ generator.generate_timeline
59
+ expect(Dir.exist?('event_visualizations')).to be true
60
+ end
61
+
62
+ it 'generates valid HTML content' do
63
+ output_path = generator.generate_timeline
64
+ content = File.read(output_path)
65
+
66
+ expect(content).to include('<!DOCTYPE html>')
67
+ expect(content).to include('<html lang="en">')
68
+ expect(content).to include('Event Timeline')
69
+ expect(content).to include('test_session')
70
+ end
71
+
72
+ it 'includes event statistics' do
73
+ output_path = generator.generate_timeline
74
+ content = File.read(output_path)
75
+
76
+ expect(content).to include('Total Events')
77
+ expect(content).to include('Event Types')
78
+ expect(content).to include('Sources')
79
+ end
80
+
81
+ it 'includes filter controls' do
82
+ output_path = generator.generate_timeline
83
+ content = File.read(output_path)
84
+
85
+ expect(content).to include('Filter by type:')
86
+ expect(content).to include('Search events...')
87
+ end
88
+
89
+ it 'includes JavaScript for filtering' do
90
+ output_path = generator.generate_timeline
91
+ content = File.read(output_path)
92
+
93
+ expect(content).to include('function filterEvents()')
94
+ expect(content).to include('addEventListener')
95
+ end
96
+ end
97
+
98
+ describe '#latest_session_id' do
99
+ it 'returns the most recent session ID' do
100
+ # Create files with different names (alphabetically sorted)
101
+ older_file = File.join(@temp_dir, 'events_a_session.jsonl')
102
+ newer_file = File.join(@temp_dir, 'events_z_session.jsonl')
103
+
104
+ # Create older file
105
+ File.write(older_file, '{"type":"test","source":"test","timestamp":"2023-01-01T00:00:00.000Z","id":"old-id","data":{}}')
106
+
107
+ # Create newer file
108
+ File.write(newer_file, '{"type":"test","source":"test","timestamp":"2023-01-02T00:00:00.000Z","id":"new-id","data":{}}')
109
+
110
+ # Create generator with the directory
111
+ generator = EventSystem::Visualization::TimelineGenerator.new(EventSystem::Storage::FileStore.new(@temp_dir))
112
+ latest = generator.latest_session_id
113
+ expect(latest).to eq('z_session')
114
+ end
115
+
116
+ it 'returns nil when no sessions exist' do
117
+ empty_storage = EventSystem::Storage::FileStore.new(temp_dir)
118
+ allow(empty_storage).to receive(:list_sessions).and_return([])
119
+ empty_generator = EventSystem::Visualization::TimelineGenerator.new(empty_storage)
120
+
121
+ result = empty_generator.latest_session_id
122
+ expect(result).to be_nil
123
+ end
124
+ end
125
+
126
+ describe '#event_summary' do
127
+ it 'returns summary of events by type' do
128
+ summary = generator.event_summary('test_session')
129
+
130
+ expect(summary).to be_a(Hash)
131
+ expect(summary['user_created']).to eq(1)
132
+ expect(summary['order_placed']).to eq(1)
133
+ expect(summary['payment_received']).to eq(1)
134
+ end
135
+
136
+ it 'returns summary for latest session by default' do
137
+ summary = generator.event_summary
138
+
139
+ expect(summary).to be_a(Hash)
140
+ expect(summary.keys).to include('user_created', 'order_placed', 'payment_received')
141
+ end
142
+
143
+ it 'returns empty hash for non-existent session' do
144
+ summary = generator.event_summary('non_existent')
145
+ expect(summary).to eq({})
146
+ end
147
+ end
148
+
149
+ describe '#timeline_data' do
150
+ it 'returns timeline data structure' do
151
+ data = generator.timeline_data('test_session')
152
+
153
+ expect(data).to be_an(Array)
154
+ expect(data.length).to eq(3)
155
+
156
+ event_data = data.first
157
+ expect(event_data).to have_key(:id)
158
+ expect(event_data).to have_key(:type)
159
+ expect(event_data).to have_key(:timestamp)
160
+ expect(event_data).to have_key(:source)
161
+ expect(event_data).to have_key(:data)
162
+ expect(event_data).to have_key(:duration)
163
+ end
164
+
165
+ it 'includes proper event data' do
166
+ data = generator.timeline_data('test_session')
167
+ event_data = data.find { |e| e[:type] == 'user_created' }
168
+
169
+ expect(event_data[:source]).to eq('UserService')
170
+ expect(event_data[:data][:user_id]).to eq(123)
171
+ expect(event_data[:data][:name]).to eq('John Doe')
172
+ end
173
+
174
+ it 'returns data for latest session by default' do
175
+ data = generator.timeline_data
176
+
177
+ expect(data).to be_an(Array)
178
+ expect(data.length).to eq(3)
179
+ end
180
+
181
+ it 'returns empty array for non-existent session' do
182
+ data = generator.timeline_data('non_existent')
183
+ expect(data).to eq([])
184
+ end
185
+ end
186
+
187
+ describe 'HTML generation' do
188
+ let(:output_path) { generator.generate_timeline }
189
+
190
+ it 'includes all event types in filter dropdown' do
191
+ content = File.read(output_path)
192
+
193
+ expect(content).to include('<option value="user_created">user_created</option>')
194
+ expect(content).to include('<option value="order_placed">order_placed</option>')
195
+ expect(content).to include('<option value="payment_received">payment_received</option>')
196
+ end
197
+
198
+ it 'includes event data in timeline' do
199
+ content = File.read(output_path)
200
+
201
+ expect(content).to include('user_id')
202
+ expect(content).to include('John Doe')
203
+ expect(content).to include('order_id')
204
+ expect(content).to include('99.99')
205
+ end
206
+
207
+ it 'includes proper CSS styling' do
208
+ content = File.read(output_path)
209
+
210
+ expect(content).to include('body { font-family: Arial, sans-serif;')
211
+ expect(content).to include('.timeline-item')
212
+ expect(content).to include('.event-header')
213
+ end
214
+
215
+ it 'includes JavaScript functionality' do
216
+ content = File.read(output_path)
217
+
218
+ expect(content).to include('const events =')
219
+ expect(content).to include('filterEvents()')
220
+ expect(content).to include('generateEventHTML')
221
+ end
222
+ end
223
+
224
+ describe 'error handling' do
225
+ it 'handles storage errors gracefully' do
226
+ # Mock storage to raise an error
227
+ allow(storage).to receive(:load_session).and_raise(StandardError, 'Storage error')
228
+
229
+ expect { generator.generate_timeline }.to raise_error(StandardError, 'Storage error')
230
+ end
231
+
232
+ it 'handles file writing errors gracefully' do
233
+ # Mock File.write to raise an error
234
+ allow(File).to receive(:write).and_raise(StandardError, 'File write error')
235
+
236
+ expect { generator.generate_timeline }.to raise_error(StandardError, 'File write error')
237
+ end
238
+ end
239
+
240
+ describe 'integration with different storage types' do
241
+ it 'works with memory storage' do
242
+ memory_storage = EventSystem::Storage::MemoryStore.new('memory_session')
243
+ memory_storage.store(create_test_event(:test_event, 'TestSource', { key: 'value' }))
244
+
245
+ memory_generator = EventSystem::Visualization::TimelineGenerator.new(memory_storage)
246
+ output_path = memory_generator.generate_timeline
247
+
248
+ expect(output_path).to be_a(String)
249
+ expect(File.exist?(output_path)).to be true
250
+ end
251
+ end
252
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe EventSystem do
6
+ describe '.version' do
7
+ it 'returns the current version' do
8
+ expect(EventSystem.version).to eq('0.1.0')
9
+ end
10
+ end
11
+
12
+ describe '.create_manager' do
13
+ it 'creates a manager with default configuration' do
14
+ manager = EventSystem.create_manager
15
+ expect(manager).to be_a(EventSystem::EventManager)
16
+ expect(manager.config.storage_type).to eq(:memory)
17
+ end
18
+
19
+ it 'creates a manager with custom configuration hash' do
20
+ config = { storage_type: :file, storage_options: { directory: 'test_logs' } }
21
+ manager = EventSystem.create_manager(config)
22
+ expect(manager.config.storage_type).to eq(:file)
23
+ expect(manager.config.storage_options[:directory]).to eq('test_logs')
24
+ end
25
+
26
+ it 'creates a manager with Configuration object' do
27
+ config = EventSystem::Configuration.new
28
+ config.storage_type = :file
29
+ manager = EventSystem.create_manager(config)
30
+ expect(manager.config).to eq(config)
31
+ end
32
+ end
33
+
34
+ describe '.create_event' do
35
+ it 'creates an event with type only' do
36
+ event = EventSystem.create_event(:test_type)
37
+ expect(event).to be_a(EventSystem::Event)
38
+ expect(event.type).to eq('test_type')
39
+ expect(event.source).to be_nil
40
+ expect(event.data).to eq({})
41
+ end
42
+
43
+ it 'creates an event with type and source' do
44
+ event = EventSystem.create_event(:test_type, 'TestSource')
45
+ expect(event.type).to eq('test_type')
46
+ expect(event.source).to eq('TestSource')
47
+ end
48
+
49
+ it 'creates an event with all parameters' do
50
+ data = { key: 'value' }
51
+ event = EventSystem.create_event(:test_type, 'TestSource', data)
52
+ expect(event.type).to eq('test_type')
53
+ expect(event.source).to eq('TestSource')
54
+ expect(event.data).to eq(data)
55
+ end
56
+ end
57
+ end