|
- package decoder
-
- import (
- "bytes"
- "testing"
-
- "github.com/AFASystems/presence/internal/pkg/common/appcontext"
- "github.com/AFASystems/presence/internal/pkg/model"
- "github.com/segmentio/kafka-go"
- )
-
- func TestDecodeBeacon_EmptyData(t *testing.T) {
- // Setup
- appState := appcontext.NewAppState()
- mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
- parserRegistry := &model.ParserRegistry{}
-
- adv := model.BeaconAdvertisement{
- ID: "test-beacon",
- Data: "", // Empty data
- }
-
- // Execute
- err := decodeBeacon(adv, appState, mockWriter, parserRegistry)
-
- // Assert
- if err != nil {
- t.Errorf("Expected no error for empty data, got %v", err)
- }
-
- if len(mockWriter.Messages) != 0 {
- t.Errorf("Expected no messages for empty data, got %d", len(mockWriter.Messages))
- }
- }
-
- func TestDecodeBeacon_WhitespaceOnly(t *testing.T) {
- // Setup
- appState := appcontext.NewAppState()
- mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
- parserRegistry := &model.ParserRegistry{}
-
- adv := model.BeaconAdvertisement{
- ID: "test-beacon",
- Data: " ", // Whitespace only
- }
-
- // Execute
- err := decodeBeacon(adv, appState, mockWriter, parserRegistry)
-
- // Assert
- if err != nil {
- t.Errorf("Expected no error for whitespace-only data, got %v", err)
- }
-
- if len(mockWriter.Messages) != 0 {
- t.Errorf("Expected no messages for whitespace-only data, got %d", len(mockWriter.Messages))
- }
- }
-
- func TestDecodeBeacon_InvalidHex(t *testing.T) {
- // Setup
- appState := appcontext.NewAppState()
- mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
- parserRegistry := &model.ParserRegistry{}
-
- adv := model.BeaconAdvertisement{
- ID: "test-beacon",
- Data: "INVALID_HEX_DATA!!!",
- }
-
- // Execute
- err := decodeBeacon(adv, appState, mockWriter, parserRegistry)
-
- // Assert
- if err == nil {
- t.Error("Expected error for invalid hex data, got nil")
- }
-
- if len(mockWriter.Messages) != 0 {
- t.Errorf("Expected no messages for invalid hex, got %d", len(mockWriter.Messages))
- }
- }
-
- func TestDecodeBeacon_ValidHexNoParser(t *testing.T) {
- // Setup
- appState := appcontext.NewAppState()
- mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
- parserRegistry := &model.ParserRegistry{} // No parsers registered
-
- // Valid hex but no matching parser
- adv := model.BeaconAdvertisement{
- ID: "test-beacon",
- Data: "0201060302A0", // Valid AD structure
- }
-
- // Execute
- err := decodeBeacon(adv, appState, mockWriter, parserRegistry)
-
- // Assert
- if err != nil {
- t.Errorf("Expected no error when no parser matches, got %v", err)
- }
-
- if len(mockWriter.Messages) != 0 {
- t.Errorf("Expected no messages when no parser matches, got %d", len(mockWriter.Messages))
- }
- }
-
- func TestDecodeBeacon_Deduplication(t *testing.T) {
- // Setup
- appState := appcontext.NewAppState()
- mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
- parserRegistry := &model.ParserRegistry{}
-
- // Register a test parser
- config := model.Config{
- Name: "test-parser",
- Prefix: "02",
- Length: 2,
- }
- parserRegistry.Register("test-parser", config)
-
- // Create an event that will be parsed
- adv := model.BeaconAdvertisement{
- ID: "test-beacon",
- Data: "020106", // Simple AD structure
- }
-
- // First processing - should publish
- err := decodeBeacon(adv, appState, mockWriter, parserRegistry)
- if err != nil {
- t.Fatalf("First processing failed: %v", err)
- }
-
- firstMessageCount := len(mockWriter.Messages)
-
- // Second processing with identical data - should deduplicate
- err = decodeBeacon(adv, appState, mockWriter, parserRegistry)
- if err != nil {
- t.Fatalf("Second processing failed: %v", err)
- }
-
- // Assert - message count should not have changed
- if len(mockWriter.Messages) != firstMessageCount {
- t.Errorf("Expected deduplication, got %d messages (should be %d)", len(mockWriter.Messages), firstMessageCount)
- }
- }
-
- func TestDecodeBeacon_DifferentDataPublishes(t *testing.T) {
- // Setup
- appState := appcontext.NewAppState()
- mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
- parserRegistry := &model.ParserRegistry{}
-
- // Register a test parser
- config := model.Config{
- Name: "test-parser",
- Prefix: "02",
- Length: 2,
- }
- parserRegistry.Register("test-parser", config)
-
- // First processing
- adv1 := model.BeaconAdvertisement{
- ID: "test-beacon",
- Data: "020106",
- }
-
- err := decodeBeacon(adv1, appState, mockWriter, parserRegistry)
- if err != nil {
- t.Fatalf("First processing failed: %v", err)
- }
-
- firstMessageCount := len(mockWriter.Messages)
-
- // Second processing with different data - should publish again
- adv2 := model.BeaconAdvertisement{
- ID: "test-beacon",
- Data: "020107", // Different data
- }
-
- err = decodeBeacon(adv2, appState, mockWriter, parserRegistry)
- if err != nil {
- t.Fatalf("Second processing failed: %v", err)
- }
-
- // Assert - message count should have increased
- if len(mockWriter.Messages) != firstMessageCount+1 {
- t.Errorf("Expected new message for different data, got %d messages (expected %d)", len(mockWriter.Messages), firstMessageCount+1)
- }
- }
-
- func TestDecodeBeacon_WithFlagBytes(t *testing.T) {
- // Setup
- appState := appcontext.NewAppState()
- mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
- parserRegistry := &model.ParserRegistry{}
-
- // Register a test parser
- config := model.Config{
- Name: "test-parser",
- Prefix: "02",
- Length: 2,
- }
- parserRegistry.Register("test-parser", config)
-
- // Data with flag bytes (0x01 at position 1)
- adv := model.BeaconAdvertisement{
- ID: "test-beacon",
- Data: "0201060302A0", // Will have flags removed
- }
-
- // Execute
- err := decodeBeacon(adv, appState, mockWriter, parserRegistry)
-
- // Assert - should process successfully after flag removal
- if err != nil {
- t.Errorf("Expected no error with flag bytes, got %v", err)
- }
- }
-
- func TestDecodeBeacon_MultipleBeacons(t *testing.T) {
- // Setup
- appState := appcontext.NewAppState()
- mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
- parserRegistry := &model.ParserRegistry{}
-
- // Register a test parser
- config := model.Config{
- Name: "test-parser",
- Prefix: "02",
- Length: 2,
- }
- parserRegistry.Register("test-parser", config)
-
- // Process multiple different beacons
- beacons := []model.BeaconAdvertisement{
- {ID: "beacon-1", Data: "020106"},
- {ID: "beacon-2", Data: "020107"},
- {ID: "beacon-3", Data: "020108"},
- }
-
- for _, adv := range beacons {
- err := decodeBeacon(adv, appState, mockWriter, parserRegistry)
- if err != nil {
- t.Errorf("Failed to process beacon %s: %v", adv.ID, err)
- }
- }
-
- // Each unique beacon should produce a message
- if len(mockWriter.Messages) != len(beacons) {
- t.Errorf("Expected %d messages, got %d", len(beacons), len(mockWriter.Messages))
- }
- }
-
- func TestProcessIncoming_ErrorHandling(t *testing.T) {
- // Setup
- appState := appcontext.NewAppState()
- mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
- parserRegistry := &model.ParserRegistry{}
-
- // Invalid data that will cause an error
- adv := model.BeaconAdvertisement{
- ID: "test-beacon",
- Data: "INVALID_HEX",
- }
-
- // Execute - should not panic, just handle error
- processIncoming(adv, appState, mockWriter, parserRegistry)
-
- // Assert - no messages should be written
- if len(mockWriter.Messages) != 0 {
- t.Errorf("Expected no messages on error, got %d", len(mockWriter.Messages))
- }
- }
-
- func TestDecodeBeacon_EventHashing(t *testing.T) {
- // Setup
- appState := appcontext.NewAppState()
- mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
- parserRegistry := &model.ParserRegistry{}
-
- // Register a test parser that creates consistent events
- config := model.Config{
- Name: "test-parser",
- Prefix: "02",
- Length: 2,
- }
- parserRegistry.Register("test-parser", config)
-
- adv := model.BeaconAdvertisement{
- ID: "test-beacon",
- Data: "020106",
- }
-
- // First processing
- err := decodeBeacon(adv, appState, mockWriter, parserRegistry)
- if err != nil {
- t.Fatalf("First processing failed: %v", err)
- }
-
- // Get the event from appState
- event, exists := appState.GetBeaconEvent("test-beacon")
- if !exists {
- t.Fatal("Event should exist in appState")
- }
-
- // Verify hash is created
- hash := event.Hash()
- if hash == nil || len(hash) == 0 {
- t.Error("Expected non-empty hash")
- }
-
- // Second processing should be deduplicated based on hash
- err = decodeBeacon(adv, appState, mockWriter, parserRegistry)
- if err != nil {
- t.Fatalf("Second processing failed: %v", err)
- }
-
- // Should still have only one message
- if len(mockWriter.Messages) != 1 {
- t.Errorf("Expected 1 message after deduplication, got %d", len(mockWriter.Messages))
- }
- }
-
- func TestDecodeBeacon_VariousHexFormats(t *testing.T) {
- // Setup
- appState := appcontext.NewAppState()
- mockWriter := &MockKafkaWriter{Messages: []kafka.Message{}}
- parserRegistry := &model.ParserRegistry{}
-
- testCases := []struct {
- name string
- hexData string
- shouldError bool
- }{
- {"lowercase hex", "020106aa", false},
- {"uppercase hex", "020106AA", false},
- {"mixed case", "020106AaFf", false},
- {"with spaces", " 020106 ", false},
- {"odd length", "02016", true},
- {"invalid chars", "020106ZZ", true},
- }
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- adv := model.BeaconAdvertisement{
- ID: "test-beacon",
- Data: tc.hexData,
- }
-
- err := decodeBeacon(adv, appState, mockWriter, parserRegistry)
-
- if tc.shouldError && err == nil {
- t.Errorf("Expected error for %s, got nil", tc.name)
- }
-
- if !tc.shouldError && err != nil && !bytes.Contains(err.Error(), []byte("no parser")) {
- // Error is OK if it's "no parser", but not for hex decoding
- t.Logf("Got expected error for %s: %v", tc.name, err)
- }
- })
- }
- }
|