|
- package decoder
-
- import (
- "context"
- "encoding/json"
- "os"
- "testing"
- "time"
-
- "github.com/AFASystems/presence/internal/pkg/common/appcontext"
- "github.com/AFASystems/presence/internal/pkg/model"
- "github.com/segmentio/kafka-go"
- )
-
- // TestIntegration_DecoderEndToEnd tests the complete decoder flow
- func TestIntegration_DecoderEndToEnd(t *testing.T) {
- if testing.Short() {
- t.Skip("Skipping integration test in short mode")
- }
-
- // Check if Kafka is available
- kafkaURL := os.Getenv("KAFKA_URL")
- if kafkaURL == "" {
- kafkaURL = "localhost:9092"
- }
-
- // Create test topics
- rawTopic := "test-rawbeacons-" + time.Now().Format("20060102150405")
- alertTopic := "test-alertbeacons-" + time.Now().Format("20060102150405")
-
- // Setup
- appState := appcontext.NewAppState()
- parserRegistry := &model.ParserRegistry{}
-
- // Register a test parser
- config := model.Config{
- Name: "integration-test-parser",
- Prefix: "02",
- Length: 2,
- MinLength: 2,
- MaxLength: 20,
- }
- parserRegistry.Register("integration-test-parser", config)
-
- // Create Kafka writer
- writer := kafka.NewWriter(kafka.WriterConfig{
- Brokers: []string{kafkaURL},
- Topic: alertTopic,
- })
- defer writer.Close()
-
- // Create Kafka reader to verify messages
- reader := kafka.NewReader(kafka.ReaderConfig{
- Brokers: []string{kafkaURL},
- Topic: alertTopic,
- GroupID: "test-group-" + time.Now().Format("20060102150405"),
- })
- defer reader.Close()
-
- // Create a test beacon advertisement
- adv := model.BeaconAdvertisement{
- ID: "integration-test-beacon",
- Data: "020106", // Valid hex data
- }
-
- // Process the beacon
- err := decodeBeacon(adv, appState, writer, parserRegistry)
- if err != nil {
- t.Logf("Decode beacon returned error (may be expected if no parser matches): %v", err)
- }
-
- // Give Kafka time to propagate
- time.Sleep(1 * time.Second)
-
- // Verify event was stored in appState
- event, exists := appState.GetBeaconEvent("integration-test-beacon")
- if exists {
- t.Logf("Event stored in appState: %+v", event)
- }
- }
-
- // TestIntegration_ParserRegistryOperations tests parser registry with real Kafka
- func TestIntegration_ParserRegistryOperations(t *testing.T) {
- if testing.Short() {
- t.Skip("Skipping integration test in short mode")
- }
-
- kafkaURL := os.Getenv("KAFKA_URL")
- if kafkaURL == "" {
- kafkaURL = "localhost:9092"
- }
-
- alertTopic := "test-alertbeacons-registry-" + time.Now().Format("20060102150405")
-
- // Setup
- appState := appcontext.NewAppState()
- parserRegistry := &model.ParserRegistry{}
-
- writer := kafka.NewWriter(kafka.WriterConfig{
- Brokers: []string{kafkaURL},
- Topic: alertTopic,
- })
- defer writer.Close()
-
- // Test parser registration through Kafka message flow
- parserMsg := model.KafkaParser{
- ID: "add",
- Name: "kafka-test-parser",
- Config: model.Config{
- Name: "kafka-test-parser",
- Prefix: "02",
- Length: 2,
- MinLength: 2,
- MaxLength: 20,
- },
- }
-
- // Simulate parser registry update
- switch parserMsg.ID {
- case "add":
- config := parserMsg.Config
- parserRegistry.Register(config.Name, config)
- case "delete":
- parserRegistry.Unregister(parserMsg.Name)
- case "update":
- config := parserMsg.Config
- parserRegistry.Register(config.Name, config)
- }
-
- // Verify parser was registered
- if len(parserRegistry.ParserList) != 1 {
- t.Errorf("Expected 1 parser in registry, got %d", len(parserRegistry.ParserList))
- }
-
- if _, exists := parserRegistry.ParserList["kafka-test-parser"]; !exists {
- t.Error("Parser should exist in registry")
- }
- }
-
- // TestIntegration_MultipleBeaconsSequential tests processing multiple beacons
- func TestIntegration_MultipleBeaconsSequential(t *testing.T) {
- if testing.Short() {
- t.Skip("Skipping integration test in short mode")
- }
-
- kafkaURL := os.Getenv("KAFKA_URL")
- if kafkaURL == "" {
- kafkaURL = "localhost:9092"
- }
-
- alertTopic := "test-alertbeacons-multi-" + time.Now().Format("20060102150405")
-
- // Setup
- appState := appcontext.NewAppState()
- parserRegistry := &model.ParserRegistry{}
-
- // Register parser
- config := model.Config{
- Name: "multi-test-parser",
- Prefix: "02",
- Length: 2,
- MinLength: 2,
- MaxLength: 20,
- }
- parserRegistry.Register("multi-test-parser", config)
-
- writer := kafka.NewWriter(kafka.WriterConfig{
- Brokers: []string{kafkaURL},
- Topic: alertTopic,
- })
- defer writer.Close()
-
- reader := kafka.NewReader(kafka.ReaderConfig{
- Brokers: []string{kafkaURL},
- Topic: alertTopic,
- GroupID: "test-group-multi-" + time.Now().Format("20060102150405"),
- MinBytes: 10e3,
- MaxBytes: 10e6,
- })
- defer reader.Close()
-
- // Process multiple 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, writer, parserRegistry)
- if err != nil {
- t.Logf("Processing beacon %s returned error: %v", adv.ID, err)
- }
- }
-
- // Give Kafka time to propagate
- time.Sleep(2 * time.Second)
-
- // Verify events in appState
- for _, adv := range beacons {
- event, exists := appState.GetBeaconEvent(adv.ID)
- if exists {
- t.Logf("Event for %s: %+v", adv.ID, event)
- }
- }
- }
-
- // TestIntegration_EventDeduplication tests that duplicate events are not published
- func TestIntegration_EventDeduplication(t *testing.T) {
- if testing.Short() {
- t.Skip("Skipping integration test in short mode")
- }
-
- kafkaURL := os.Getenv("KAFKA_URL")
- if kafkaURL == "" {
- kafkaURL = "localhost:9092"
- }
-
- alertTopic := "test-alertbeacons-dedup-" + time.Now().Format("20060102150405")
-
- // Setup
- appState := appcontext.NewAppState()
- parserRegistry := &model.ParserRegistry{}
-
- // Register parser
- config := model.Config{
- Name: "dedup-test-parser",
- Prefix: "02",
- Length: 2,
- MinLength: 2,
- MaxLength: 20,
- }
- parserRegistry.Register("dedup-test-parser", config)
-
- writer := kafka.NewWriter(kafka.WriterConfig{
- Brokers: []string{kafkaURL},
- Topic: alertTopic,
- })
- defer writer.Close()
-
- reader := kafka.NewReader(kafka.ReaderConfig{
- Brokers: []string{kafkaURL},
- Topic: alertTopic,
- GroupID: "test-group-dedup-" + time.Now().Format("20060102150405"),
- })
- defer reader.Close()
-
- // Create identical beacon advertisement
- adv := model.BeaconAdvertisement{
- ID: "dedup-test-beacon",
- Data: "020106",
- }
-
- // Process first time
- err := decodeBeacon(adv, appState, writer, parserRegistry)
- if err != nil {
- t.Logf("First processing returned error: %v", err)
- }
-
- // Process second time with identical data
- err = decodeBeacon(adv, appState, writer, parserRegistry)
- if err != nil {
- t.Logf("Second processing returned error: %v", err)
- }
-
- // Give Kafka time to propagate
- time.Sleep(1 * time.Second)
-
- // Try to read from Kafka - should have at most 1 message due to deduplication
- ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
- defer cancel()
-
- messageCount := 0
- for {
- msg, err := reader.ReadMessage(ctx)
- if err != nil {
- break
- }
-
- messageCount++
- t.Logf("Read message %d: %s", messageCount, string(msg.Value))
-
- if messageCount > 1 {
- t.Error("Expected at most 1 message due to deduplication, got more")
- break
- }
- }
-
- t.Logf("Total messages read: %d", messageCount)
- }
-
- // TestIntegration_AppStatePersistence tests that events persist in AppState
- func TestIntegration_AppStatePersistence(t *testing.T) {
- if testing.Short() {
- t.Skip("Skipping integration test in short mode")
- }
-
- kafkaURL := os.Getenv("KAFKA_URL")
- if kafkaURL == "" {
- kafkaURL = "localhost:9092"
- }
-
- alertTopic := "test-alertbeacons-persist-" + time.Now().Format("20060102150405")
-
- // Setup
- appState := appcontext.NewAppState()
- parserRegistry := &model.ParserRegistry{}
-
- config := model.Config{
- Name: "persist-test-parser",
- Prefix: "02",
- Length: 2,
- MinLength: 2,
- MaxLength: 20,
- }
- parserRegistry.Register("persist-test-parser", config)
-
- writer := kafka.NewWriter(kafka.WriterConfig{
- Brokers: []string{kafkaURL},
- Topic: alertTopic,
- })
- defer writer.Close()
-
- // Process beacon
- adv := model.BeaconAdvertisement{
- ID: "persist-test-beacon",
- Data: "020106",
- }
-
- err := decodeBeacon(adv, appState, writer, parserRegistry)
- if err != nil {
- t.Logf("Processing returned error: %v", err)
- }
-
- // Verify event persists in AppState
- event, exists := appState.GetBeaconEvent("persist-test-beacon")
- if !exists {
- t.Error("Event should exist in AppState after processing")
- } else {
- t.Logf("Event persisted: ID=%s, Type=%s, Battery=%d",
- event.ID, event.Type, event.Battery)
-
- // Verify event can be serialized to JSON
- jsonData, err := event.ToJSON()
- if err != nil {
- t.Errorf("Failed to serialize event to JSON: %v", err)
- } else {
- t.Logf("Event JSON: %s", string(jsonData))
- }
- }
- }
-
- // TestIntegration_ParserUpdateFlow tests updating parsers during runtime
- func TestIntegration_ParserUpdateFlow(t *testing.T) {
- if testing.Short() {
- t.Skip("Skipping integration test in short mode")
- }
-
- kafkaURL := os.Getenv("KAFKA_URL")
- if kafkaURL == "" {
- kafkaURL = "localhost:9092"
- }
-
- alertTopic := "test-alertbeacons-update-" + time.Now().Format("20060102150405")
-
- // Setup
- appState := appcontext.NewAppState()
- parserRegistry := &model.ParserRegistry{}
-
- writer := kafka.NewWriter(kafka.WriterConfig{
- Brokers: []string{kafkaURL},
- Topic: alertTopic,
- })
- defer writer.Close()
-
- // Initial parser config
- config1 := model.Config{
- Name: "update-test-parser",
- Prefix: "02",
- Length: 2,
- MinLength: 2,
- MaxLength: 20,
- }
- parserRegistry.Register("update-test-parser", config1)
-
- // Process with initial config
- adv := model.BeaconAdvertisement{
- ID: "update-test-beacon",
- Data: "020106",
- }
-
- err := decodeBeacon(adv, appState, writer, parserRegistry)
- t.Logf("First processing: %v", err)
-
- // Update parser config
- config2 := model.Config{
- Name: "update-test-parser",
- Prefix: "03",
- Length: 3,
- MinLength: 3,
- MaxLength: 25,
- }
- parserRegistry.Register("update-test-parser", config2)
-
- // Process again with updated config
- adv2 := model.BeaconAdvertisement{
- ID: "update-test-beacon-2",
- Data: "030107",
- }
-
- err = decodeBeacon(adv2, appState, writer, parserRegistry)
- t.Logf("Second processing with updated parser: %v", err)
-
- // Verify parser still exists
- if _, exists := parserRegistry.ParserList["update-test-parser"]; !exists {
- t.Error("Parser should exist after update")
- }
- }
|