您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

266 行
6.9 KiB

  1. package bridge
  2. import (
  3. "context"
  4. "encoding/json"
  5. "testing"
  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. // MockKafkaWriter is a mock implementation of kafkaWriter for testing
  11. type MockKafkaWriter struct {
  12. Messages []kafka.Message
  13. }
  14. func (m *MockKafkaWriter) WriteMessages(ctx context.Context, msgs ...kafka.Message) error {
  15. m.Messages = append(m.Messages, msgs...)
  16. return nil
  17. }
  18. func TestMQTTHandler_SingleReading(t *testing.T) {
  19. // Setup
  20. appState := appcontext.NewAppState()
  21. appState.AddBeaconToLookup("AA:BB:CC:DD:EE:FF", "test-beacon-1")
  22. mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
  23. // Create a test message with single reading
  24. reading := model.RawReading{
  25. Timestamp: "2025-01-16T10:00:00Z",
  26. Type: "BLE",
  27. MAC: "AA:BB:CC:DD:EE:FF",
  28. RSSI: -65,
  29. RawData: "0201060302A0",
  30. }
  31. messageBytes, _ := json.Marshal([]model.RawReading{reading})
  32. // Execute
  33. mqtthandler(mockWriter, "publish_out/gateway-1", messageBytes, appState)
  34. // Assert
  35. if len(mockWriter.Messages) != 1 {
  36. t.Errorf("Expected 1 message, got %d", len(mockWriter.Messages))
  37. }
  38. var adv model.BeaconAdvertisement
  39. err := json.Unmarshal(mockWriter.Messages[0].Value, &adv)
  40. if err != nil {
  41. t.Fatalf("Failed to unmarshal beacon advertisement: %v", err)
  42. }
  43. if adv.ID != "test-beacon-1" {
  44. t.Errorf("Expected ID 'test-beacon-1', got '%s'", adv.ID)
  45. }
  46. if adv.Hostname != "gateway-1" {
  47. t.Errorf("Expected hostname 'gateway-1', got '%s'", adv.Hostname)
  48. }
  49. if adv.MAC != "AA:BB:CC:DD:EE:FF" {
  50. t.Errorf("Expected MAC 'AA:BB:CC:DD:EE:FF', got '%s'", adv.MAC)
  51. }
  52. if adv.RSSI != -65 {
  53. t.Errorf("Expected RSSI -65, got %d", adv.RSSI)
  54. }
  55. }
  56. func TestMQTTHandler_MultipleReadings(t *testing.T) {
  57. // Setup
  58. appState := appcontext.NewAppState()
  59. appState.AddBeaconToLookup("AA:BB:CC:DD:EE:FF", "test-beacon-1")
  60. appState.AddBeaconToLookup("11:22:33:44:55:66", "test-beacon-2")
  61. mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
  62. // Create a test message with multiple readings
  63. readings := []model.RawReading{
  64. {
  65. Timestamp: "2025-01-16T10:00:00Z",
  66. Type: "BLE",
  67. MAC: "AA:BB:CC:DD:EE:FF",
  68. RSSI: -65,
  69. RawData: "0201060302A0",
  70. },
  71. {
  72. Timestamp: "2025-01-16T10:00:01Z",
  73. Type: "BLE",
  74. MAC: "11:22:33:44:55:66",
  75. RSSI: -72,
  76. RawData: "0201060302A1",
  77. },
  78. }
  79. messageBytes, _ := json.Marshal(readings)
  80. // Execute
  81. mqtthandler(mockWriter, "publish_out/gateway-1", messageBytes, appState)
  82. // Assert
  83. if len(mockWriter.Messages) != 2 {
  84. t.Errorf("Expected 2 messages, got %d", len(mockWriter.Messages))
  85. }
  86. }
  87. func TestMQTTHandler_GatewayTypeSkipped(t *testing.T) {
  88. // Setup
  89. appState := appcontext.NewAppState()
  90. appState.AddBeaconToLookup("AA:BB:CC:DD:EE:FF", "test-beacon-1")
  91. mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
  92. // Create a test message with Gateway type reading
  93. reading := model.RawReading{
  94. Timestamp: "2025-01-16T10:00:00Z",
  95. Type: "Gateway",
  96. MAC: "AA:BB:CC:DD:EE:FF",
  97. RSSI: -65,
  98. RawData: "0201060302A0",
  99. }
  100. messageBytes, _ := json.Marshal([]model.RawReading{reading})
  101. // Execute
  102. mqtthandler(mockWriter, "publish_out/gateway-1", messageBytes, appState)
  103. // Assert
  104. if len(mockWriter.Messages) != 0 {
  105. t.Errorf("Expected 0 messages (Gateway type should be skipped), got %d", len(mockWriter.Messages))
  106. }
  107. }
  108. func TestMQTTHandler_UnknownBeaconSkipped(t *testing.T) {
  109. // Setup
  110. appState := appcontext.NewAppState()
  111. // Don't add beacon to lookup
  112. mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
  113. // Create a test message
  114. reading := model.RawReading{
  115. Timestamp: "2025-01-16T10:00:00Z",
  116. Type: "BLE",
  117. MAC: "AA:BB:CC:DD:EE:FF",
  118. RSSI: -65,
  119. RawData: "0201060302A0",
  120. }
  121. messageBytes, _ := json.Marshal([]model.RawReading{reading})
  122. // Execute
  123. mqtthandler(mockWriter, "publish_out/gateway-1", messageBytes, appState)
  124. // Assert
  125. if len(mockWriter.Messages) != 0 {
  126. t.Errorf("Expected 0 messages (unknown beacon should be skipped), got %d", len(mockWriter.Messages))
  127. }
  128. }
  129. func TestMQTTHandler_InvalidJSON(t *testing.T) {
  130. // Setup
  131. appState := appcontext.NewAppState()
  132. mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
  133. // Create invalid JSON
  134. invalidJSON := []byte("{invalid json")
  135. // Execute - should not panic
  136. mqtthandler(mockWriter, "publish_out/gateway-1", invalidJSON, appState)
  137. // Assert
  138. if len(mockWriter.Messages) != 0 {
  139. t.Errorf("Expected 0 messages (invalid JSON), got %d", len(mockWriter.Messages))
  140. }
  141. }
  142. func TestMQTTHandler_HostnameExtraction(t *testing.T) {
  143. // Setup
  144. appState := appcontext.NewAppState()
  145. appState.AddBeaconToLookup("AA:BB:CC:DD:EE:FF", "test-beacon-1")
  146. mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
  147. // Test various topic formats
  148. testCases := []struct {
  149. topic string
  150. expectedHost string
  151. }{
  152. {"publish_out/gateway-1", "gateway-1"},
  153. {"publish_out/gateway-prod-02", "gateway-prod-02"},
  154. {"publish_out/192-168-1-100", "192-168-1-100"},
  155. }
  156. for _, tc := range testCases {
  157. t.Run(tc.topic, func(t *testing.T) {
  158. mockWriter.Messages = []kafka.Message{}
  159. reading := model.RawReading{
  160. Timestamp: "2025-01-16T10:00:00Z",
  161. Type: "BLE",
  162. MAC: "AA:BB:CC:DD:EE:FF",
  163. RSSI: -65,
  164. RawData: "0201060302A0",
  165. }
  166. messageBytes, _ := json.Marshal([]model.RawReading{reading})
  167. mqtthandler(mockWriter, tc.topic, messageBytes, appState)
  168. if len(mockWriter.Messages) != 1 {
  169. t.Fatalf("Expected 1 message, got %d", len(mockWriter.Messages))
  170. }
  171. var adv model.BeaconAdvertisement
  172. err := json.Unmarshal(mockWriter.Messages[0].Value, &adv)
  173. if err != nil {
  174. t.Fatalf("Failed to unmarshal beacon advertisement: %v", err)
  175. }
  176. if adv.Hostname != tc.expectedHost {
  177. t.Errorf("Expected hostname '%s', got '%s'", tc.expectedHost, adv.Hostname)
  178. }
  179. })
  180. }
  181. }
  182. func TestMQTTHandler_PreservesRawData(t *testing.T) {
  183. // Setup
  184. appState := appcontext.NewAppState()
  185. appState.AddBeaconToLookup("AA:BB:CC:DD:EE:FF", "test-beacon-1")
  186. mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
  187. // Create a test message with specific raw data
  188. rawData := "1A0201060302A0F4"
  189. reading := model.RawReading{
  190. Timestamp: "2025-01-16T10:00:00Z",
  191. Type: "BLE",
  192. MAC: "AA:BB:CC:DD:EE:FF",
  193. RSSI: -65,
  194. RawData: rawData,
  195. }
  196. messageBytes, _ := json.Marshal([]model.RawReading{reading})
  197. // Execute
  198. mqtthandler(mockWriter, "publish_out/gateway-1", messageBytes, appState)
  199. // Assert
  200. if len(mockWriter.Messages) != 1 {
  201. t.Fatalf("Expected 1 message, got %d", len(mockWriter.Messages))
  202. }
  203. var adv model.BeaconAdvertisement
  204. err := json.Unmarshal(mockWriter.Messages[0].Value, &adv)
  205. if err != nil {
  206. t.Fatalf("Failed to unmarshal beacon advertisement: %v", err)
  207. }
  208. if adv.Data != rawData {
  209. t.Errorf("Expected Data '%s', got '%s'", rawData, adv.Data)
  210. }
  211. }