|
- package bridge
-
- import (
- "context"
- "encoding/json"
- "testing"
-
- "github.com/AFASystems/presence/internal/pkg/common/appcontext"
- "github.com/AFASystems/presence/internal/pkg/model"
- "github.com/segmentio/kafka-go"
- )
-
- // MockKafkaWriter is a mock implementation of kafkaWriter for testing
- type MockKafkaWriter struct {
- Messages []kafka.Message
- }
-
- func (m *MockKafkaWriter) WriteMessages(ctx context.Context, msgs ...kafka.Message) error {
- m.Messages = append(m.Messages, msgs...)
- return nil
- }
-
- func TestMQTTHandler_SingleReading(t *testing.T) {
- // Setup
- appState := appcontext.NewAppState()
- appState.AddBeaconToLookup("AA:BB:CC:DD:EE:FF", "test-beacon-1")
-
- mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
-
- // Create a test message with single reading
- reading := model.RawReading{
- Timestamp: "2025-01-16T10:00:00Z",
- Type: "BLE",
- MAC: "AA:BB:CC:DD:EE:FF",
- RSSI: -65,
- RawData: "0201060302A0",
- }
-
- messageBytes, _ := json.Marshal([]model.RawReading{reading})
-
- // Execute
- mqtthandler(mockWriter, "publish_out/gateway-1", messageBytes, appState)
-
- // Assert
- if len(mockWriter.Messages) != 1 {
- t.Errorf("Expected 1 message, got %d", len(mockWriter.Messages))
- }
-
- var adv model.BeaconAdvertisement
- err := json.Unmarshal(mockWriter.Messages[0].Value, &adv)
- if err != nil {
- t.Fatalf("Failed to unmarshal beacon advertisement: %v", err)
- }
-
- if adv.ID != "test-beacon-1" {
- t.Errorf("Expected ID 'test-beacon-1', got '%s'", adv.ID)
- }
-
- if adv.Hostname != "gateway-1" {
- t.Errorf("Expected hostname 'gateway-1', got '%s'", adv.Hostname)
- }
-
- if adv.MAC != "AA:BB:CC:DD:EE:FF" {
- t.Errorf("Expected MAC 'AA:BB:CC:DD:EE:FF', got '%s'", adv.MAC)
- }
-
- if adv.RSSI != -65 {
- t.Errorf("Expected RSSI -65, got %d", adv.RSSI)
- }
- }
-
- func TestMQTTHandler_MultipleReadings(t *testing.T) {
- // Setup
- appState := appcontext.NewAppState()
- appState.AddBeaconToLookup("AA:BB:CC:DD:EE:FF", "test-beacon-1")
- appState.AddBeaconToLookup("11:22:33:44:55:66", "test-beacon-2")
-
- mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
-
- // Create a test message with multiple readings
- readings := []model.RawReading{
- {
- Timestamp: "2025-01-16T10:00:00Z",
- Type: "BLE",
- MAC: "AA:BB:CC:DD:EE:FF",
- RSSI: -65,
- RawData: "0201060302A0",
- },
- {
- Timestamp: "2025-01-16T10:00:01Z",
- Type: "BLE",
- MAC: "11:22:33:44:55:66",
- RSSI: -72,
- RawData: "0201060302A1",
- },
- }
-
- messageBytes, _ := json.Marshal(readings)
-
- // Execute
- mqtthandler(mockWriter, "publish_out/gateway-1", messageBytes, appState)
-
- // Assert
- if len(mockWriter.Messages) != 2 {
- t.Errorf("Expected 2 messages, got %d", len(mockWriter.Messages))
- }
- }
-
- func TestMQTTHandler_GatewayTypeSkipped(t *testing.T) {
- // Setup
- appState := appcontext.NewAppState()
- appState.AddBeaconToLookup("AA:BB:CC:DD:EE:FF", "test-beacon-1")
-
- mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
-
- // Create a test message with Gateway type reading
- reading := model.RawReading{
- Timestamp: "2025-01-16T10:00:00Z",
- Type: "Gateway",
- MAC: "AA:BB:CC:DD:EE:FF",
- RSSI: -65,
- RawData: "0201060302A0",
- }
-
- messageBytes, _ := json.Marshal([]model.RawReading{reading})
-
- // Execute
- mqtthandler(mockWriter, "publish_out/gateway-1", messageBytes, appState)
-
- // Assert
- if len(mockWriter.Messages) != 0 {
- t.Errorf("Expected 0 messages (Gateway type should be skipped), got %d", len(mockWriter.Messages))
- }
- }
-
- func TestMQTTHandler_UnknownBeaconSkipped(t *testing.T) {
- // Setup
- appState := appcontext.NewAppState()
- // Don't add beacon to lookup
-
- mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
-
- // Create a test message
- reading := model.RawReading{
- Timestamp: "2025-01-16T10:00:00Z",
- Type: "BLE",
- MAC: "AA:BB:CC:DD:EE:FF",
- RSSI: -65,
- RawData: "0201060302A0",
- }
-
- messageBytes, _ := json.Marshal([]model.RawReading{reading})
-
- // Execute
- mqtthandler(mockWriter, "publish_out/gateway-1", messageBytes, appState)
-
- // Assert
- if len(mockWriter.Messages) != 0 {
- t.Errorf("Expected 0 messages (unknown beacon should be skipped), got %d", len(mockWriter.Messages))
- }
- }
-
- func TestMQTTHandler_InvalidJSON(t *testing.T) {
- // Setup
- appState := appcontext.NewAppState()
- mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
-
- // Create invalid JSON
- invalidJSON := []byte("{invalid json")
-
- // Execute - should not panic
- mqtthandler(mockWriter, "publish_out/gateway-1", invalidJSON, appState)
-
- // Assert
- if len(mockWriter.Messages) != 0 {
- t.Errorf("Expected 0 messages (invalid JSON), got %d", len(mockWriter.Messages))
- }
- }
-
- func TestMQTTHandler_HostnameExtraction(t *testing.T) {
- // Setup
- appState := appcontext.NewAppState()
- appState.AddBeaconToLookup("AA:BB:CC:DD:EE:FF", "test-beacon-1")
-
- mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
-
- // Test various topic formats
- testCases := []struct {
- topic string
- expectedHost string
- }{
- {"publish_out/gateway-1", "gateway-1"},
- {"publish_out/gateway-prod-02", "gateway-prod-02"},
- {"publish_out/192-168-1-100", "192-168-1-100"},
- }
-
- for _, tc := range testCases {
- t.Run(tc.topic, func(t *testing.T) {
- mockWriter.Messages = []kafka.Message{}
-
- reading := model.RawReading{
- Timestamp: "2025-01-16T10:00:00Z",
- Type: "BLE",
- MAC: "AA:BB:CC:DD:EE:FF",
- RSSI: -65,
- RawData: "0201060302A0",
- }
-
- messageBytes, _ := json.Marshal([]model.RawReading{reading})
- mqtthandler(mockWriter, tc.topic, messageBytes, appState)
-
- if len(mockWriter.Messages) != 1 {
- t.Fatalf("Expected 1 message, got %d", len(mockWriter.Messages))
- }
-
- var adv model.BeaconAdvertisement
- err := json.Unmarshal(mockWriter.Messages[0].Value, &adv)
- if err != nil {
- t.Fatalf("Failed to unmarshal beacon advertisement: %v", err)
- }
-
- if adv.Hostname != tc.expectedHost {
- t.Errorf("Expected hostname '%s', got '%s'", tc.expectedHost, adv.Hostname)
- }
- })
- }
- }
-
- func TestMQTTHandler_PreservesRawData(t *testing.T) {
- // Setup
- appState := appcontext.NewAppState()
- appState.AddBeaconToLookup("AA:BB:CC:DD:EE:FF", "test-beacon-1")
-
- mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
-
- // Create a test message with specific raw data
- rawData := "1A0201060302A0F4"
- reading := model.RawReading{
- Timestamp: "2025-01-16T10:00:00Z",
- Type: "BLE",
- MAC: "AA:BB:CC:DD:EE:FF",
- RSSI: -65,
- RawData: rawData,
- }
-
- messageBytes, _ := json.Marshal([]model.RawReading{reading})
-
- // Execute
- mqtthandler(mockWriter, "publish_out/gateway-1", messageBytes, appState)
-
- // Assert
- if len(mockWriter.Messages) != 1 {
- t.Fatalf("Expected 1 message, got %d", len(mockWriter.Messages))
- }
-
- var adv model.BeaconAdvertisement
- err := json.Unmarshal(mockWriter.Messages[0].Value, &adv)
- if err != nil {
- t.Fatalf("Failed to unmarshal beacon advertisement: %v", err)
- }
-
- if adv.Data != rawData {
- t.Errorf("Expected Data '%s', got '%s'", rawData, adv.Data)
- }
- }
|