You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

364 lines
8.7 KiB

  1. package decoder
  2. import (
  3. "context"
  4. "testing"
  5. "time"
  6. "github.com/AFASystems/presence/internal/pkg/common/appcontext"
  7. "github.com/AFASystems/presence/internal/pkg/model"
  8. "github.com/segmentio/kafka-go"
  9. )
  10. func TestEventLoop_RawMessageProcessing(t *testing.T) {
  11. // Setup
  12. appState := appcontext.NewAppState()
  13. mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
  14. parserRegistry := &model.ParserRegistry{ParserList: make(map[string]model.BeaconParser)}
  15. chRaw := make(chan model.BeaconAdvertisement, 10)
  16. ctx, cancel := context.WithCancel(context.Background())
  17. defer cancel()
  18. // Create a test message
  19. msg := model.BeaconAdvertisement{
  20. ID: "test-beacon",
  21. Data: "020106",
  22. }
  23. // Simulate event loop processing
  24. go func() {
  25. for {
  26. select {
  27. case <-ctx.Done():
  28. return
  29. case m := <-chRaw:
  30. processIncoming(m, appState, mockWriter, parserRegistry)
  31. }
  32. }
  33. }()
  34. // Send message
  35. chRaw <- msg
  36. // Give it time to process
  37. time.Sleep(100 * time.Millisecond)
  38. // Cancel context
  39. cancel()
  40. // Verify message was processed (even if no parser matched, processIncoming was called)
  41. // We just verify no panic occurred
  42. }
  43. func TestEventLoop_ParserRegistryUpdates(t *testing.T) {
  44. // Setup
  45. parserRegistry := &model.ParserRegistry{ParserList: make(map[string]model.BeaconParser)}
  46. chParser := make(chan model.KafkaParser, 10)
  47. // Test ADD operation
  48. addMsg := model.KafkaParser{
  49. ID: "add",
  50. Name: "new-parser",
  51. Config: model.Config{
  52. Name: "new-parser",
  53. Min: 2,
  54. Max: 10,
  55. Pattern: []string{"0x02"},
  56. },
  57. }
  58. chParser <- addMsg
  59. // Simulate event loop handling
  60. select {
  61. case msg := <-chParser:
  62. switch msg.ID {
  63. case "add":
  64. config := msg.Config
  65. parserRegistry.Register(config.Name, config)
  66. case "delete":
  67. parserRegistry.Unregister(msg.Name)
  68. case "update":
  69. config := msg.Config
  70. parserRegistry.Register(config.Name, config)
  71. }
  72. case <-time.After(1 * time.Second):
  73. t.Fatal("Timeout waiting for parser message")
  74. }
  75. // Verify parser was added
  76. if len(parserRegistry.ParserList) != 1 {
  77. t.Errorf("Expected 1 parser after add, got %d", len(parserRegistry.ParserList))
  78. }
  79. // Test DELETE operation
  80. deleteMsg := model.KafkaParser{
  81. ID: "delete",
  82. Name: "new-parser",
  83. }
  84. chParser <- deleteMsg
  85. select {
  86. case msg := <-chParser:
  87. switch msg.ID {
  88. case "add":
  89. config := msg.Config
  90. parserRegistry.Register(config.Name, config)
  91. case "delete":
  92. parserRegistry.Unregister(msg.Name)
  93. case "update":
  94. config := msg.Config
  95. parserRegistry.Register(config.Name, config)
  96. }
  97. case <-time.After(1 * time.Second):
  98. t.Fatal("Timeout waiting for parser message")
  99. }
  100. // Verify parser was deleted
  101. if len(parserRegistry.ParserList) != 0 {
  102. t.Errorf("Expected 0 parsers after delete, got %d", len(parserRegistry.ParserList))
  103. }
  104. }
  105. func TestEventLoop_UpdateParser(t *testing.T) {
  106. // Setup
  107. parserRegistry := &model.ParserRegistry{ParserList: make(map[string]model.BeaconParser)}
  108. // Add initial parser
  109. parserRegistry.Register("test-parser", model.Config{
  110. Name: "test-parser",
  111. Min: 2,
  112. Max: 10,
  113. Pattern: []string{"0x02"},
  114. })
  115. chParser := make(chan model.KafkaParser, 10)
  116. // Test UPDATE operation
  117. updateMsg := model.KafkaParser{
  118. ID: "update",
  119. Name: "test-parser",
  120. Config: model.Config{
  121. Name: "test-parser",
  122. Min: 3,
  123. Max: 15,
  124. Pattern: []string{"0x03"},
  125. },
  126. }
  127. chParser <- updateMsg
  128. // Simulate event loop handling
  129. select {
  130. case msg := <-chParser:
  131. switch msg.ID {
  132. case "add":
  133. config := msg.Config
  134. parserRegistry.Register(config.Name, config)
  135. case "delete":
  136. parserRegistry.Unregister(msg.Name)
  137. case "update":
  138. config := msg.Config
  139. parserRegistry.Register(config.Name, config)
  140. }
  141. case <-time.After(1 * time.Second):
  142. t.Fatal("Timeout waiting for parser message")
  143. }
  144. // Verify parser still exists (was updated, not deleted)
  145. if len(parserRegistry.ParserList) != 1 {
  146. t.Errorf("Expected 1 parser after update, got %d", len(parserRegistry.ParserList))
  147. }
  148. if _, exists := parserRegistry.ParserList["test-parser"]; !exists {
  149. t.Error("Parser should still exist after update")
  150. }
  151. }
  152. func TestEventLoop_MultipleParserOperations(t *testing.T) {
  153. // Setup
  154. parserRegistry := &model.ParserRegistry{ParserList: make(map[string]model.BeaconParser)}
  155. chParser := make(chan model.KafkaParser, 10)
  156. // Send multiple operations
  157. operations := []model.KafkaParser{
  158. {ID: "add", Name: "parser-1", Config: model.Config{Name: "parser-1", Min: 2, Max: 10, Pattern: []string{"0x02"}}},
  159. {ID: "add", Name: "parser-2", Config: model.Config{Name: "parser-2", Min: 3, Max: 15, Pattern: []string{"0x03"}}},
  160. {ID: "add", Name: "parser-3", Config: model.Config{Name: "parser-3", Min: 4, Max: 20, Pattern: []string{"0x04"}}},
  161. {ID: "delete", Name: "parser-2"},
  162. {ID: "update", Name: "parser-1", Config: model.Config{Name: "parser-1", Min: 5, Max: 25, Pattern: []string{"0x05"}}},
  163. }
  164. for _, op := range operations {
  165. chParser <- op
  166. }
  167. // Process all operations
  168. for i := 0; i < len(operations); i++ {
  169. select {
  170. case msg := <-chParser:
  171. switch msg.ID {
  172. case "add":
  173. config := msg.Config
  174. parserRegistry.Register(config.Name, config)
  175. case "delete":
  176. parserRegistry.Unregister(msg.Name)
  177. case "update":
  178. config := msg.Config
  179. parserRegistry.Register(config.Name, config)
  180. }
  181. case <-time.After(1 * time.Second):
  182. t.Fatalf("Timeout processing operation %d", i)
  183. }
  184. }
  185. // Verify final state
  186. if len(parserRegistry.ParserList) != 2 {
  187. t.Errorf("Expected 2 parsers after all operations, got %d", len(parserRegistry.ParserList))
  188. }
  189. // parser-1 should exist (updated)
  190. if _, exists := parserRegistry.ParserList["parser-1"]; !exists {
  191. t.Error("parser-1 should exist")
  192. }
  193. // parser-2 should not exist (deleted)
  194. if _, exists := parserRegistry.ParserList["parser-2"]; exists {
  195. t.Error("parser-2 should not exist")
  196. }
  197. // parser-3 should exist (added)
  198. if _, exists := parserRegistry.ParserList["parser-3"]; !exists {
  199. t.Error("parser-3 should exist")
  200. }
  201. }
  202. func TestEventLoop_ContextCancellation(t *testing.T) {
  203. // Setup
  204. ctx, cancel := context.WithCancel(context.Background())
  205. defer cancel()
  206. chRaw := make(chan model.BeaconAdvertisement, 10)
  207. chParser := make(chan model.KafkaParser, 10)
  208. // Cancel immediately
  209. cancel()
  210. // Verify context is cancelled
  211. select {
  212. case <-ctx.Done():
  213. // Expected - context was cancelled
  214. return
  215. case msg := <-chRaw:
  216. t.Errorf("Should not receive raw messages after context cancellation, got: %+v", msg)
  217. case msg := <-chParser:
  218. t.Errorf("Should not receive parser messages after context cancellation, got: %+v", msg)
  219. case <-time.After(1 * time.Second):
  220. t.Error("Timeout - context cancellation should have been immediate")
  221. }
  222. }
  223. func TestEventLoop_ChannelBuffering(t *testing.T) {
  224. // Setup - create buffered channels (like in main)
  225. chRaw := make(chan model.BeaconAdvertisement, 2000)
  226. chParser := make(chan model.KafkaParser, 200)
  227. _, cancel := context.WithCancel(context.Background())
  228. defer cancel()
  229. // Send multiple messages without blocking
  230. for i := 0; i < 100; i++ {
  231. msg := model.BeaconAdvertisement{
  232. ID: "test-beacon",
  233. Data: "020106",
  234. }
  235. chRaw <- msg
  236. }
  237. // Verify all messages are buffered
  238. if len(chRaw) != 100 {
  239. t.Errorf("Expected 100 messages in buffer, got %d", len(chRaw))
  240. }
  241. // Send parser updates
  242. for i := 0; i < 10; i++ {
  243. msg := model.KafkaParser{
  244. ID: "add",
  245. Name: "parser-" + string(rune('A'+i)),
  246. Config: model.Config{
  247. Name: "parser-" + string(rune('A'+i)),
  248. Min: 2,
  249. Max: 10,
  250. Pattern: []string{"0x02"},
  251. },
  252. }
  253. chParser <- msg
  254. }
  255. // Verify all parser messages are buffered
  256. if len(chParser) != 10 {
  257. t.Errorf("Expected 10 parser messages in buffer, got %d", len(chParser))
  258. }
  259. // Cancel context
  260. cancel()
  261. }
  262. func TestEventLoop_ParserAndRawChannels(t *testing.T) {
  263. // Setup
  264. chRaw := make(chan model.BeaconAdvertisement, 10)
  265. chParser := make(chan model.KafkaParser, 10)
  266. _, cancel := context.WithCancel(context.Background())
  267. defer cancel()
  268. // Send both raw and parser messages
  269. rawMsg := model.BeaconAdvertisement{
  270. ID: "test-beacon",
  271. Data: "020106",
  272. }
  273. parserMsg := model.KafkaParser{
  274. ID: "add",
  275. Name: "test-parser",
  276. Config: model.Config{
  277. Name: "test-parser",
  278. Min: 2,
  279. Max: 10,
  280. Pattern: []string{"0x02"},
  281. },
  282. }
  283. chRaw <- rawMsg
  284. chParser <- parserMsg
  285. // Process both messages
  286. processedRaw := false
  287. processedParser := false
  288. for i := 0; i < 2; i++ {
  289. select {
  290. case <-chRaw:
  291. processedRaw = true
  292. case <-chParser:
  293. processedParser = true
  294. case <-time.After(1 * time.Second):
  295. t.Fatal("Timeout waiting for messages")
  296. }
  297. }
  298. if !processedRaw {
  299. t.Error("Raw message should have been processed")
  300. }
  301. if !processedParser {
  302. t.Error("Parser message should have been processed")
  303. }
  304. cancel()
  305. }