packageloggerimport("honeypot/internal/database""honeypot/internal/types""log/slog""net/http""os""testing""time")typemockMetricsCollectorstruct{events[]types.LogEvent}func(m*mockMetricsCollector)RecordEvent(etypes.LogEvent){m.events=append(m.events,e)}func(m*mockMetricsCollector)GetHandler()http.Handler{returnnil}func(m*mockMetricsCollector)SetDatabase(db*database.Database){}typemockEventSinkstruct{events[]types.LogEvent}func(m*mockEventSink)EmitEvent(etypes.LogEvent){m.events=append(m.events,e)}funcTestLogEvent(t*testing.T){logger:=slog.New(slog.NewJSONHandler(os.Stdout,nil))metrics:=&mockMetricsCollector{}sink:=&mockEventSink{}RegisterMetricsCollector(metrics)RegisterEventSink(sink)e:=types.LogEvent{Type:"test",Event:"unit_test",RemoteAddr:"1.2.3.4",Fields:map[string]interface{}{"foo":"bar"},}LogEvent(logger,e)iflen(metrics.events)!=1{t.Errorf("expected 1 event in metrics, got %v",len(metrics.events))}iflen(sink.events)!=1{t.Errorf("expected 1 event in sink, got %v",len(sink.events))}ifmetrics.events[0].Type!="test"{t.Errorf("expected type 'test', got %v",metrics.events[0].Type)}}funcTestLogEvent_Blocklist(t*testing.T){tempDB:="test_blocklist.db"deferos.Remove(tempDB)deferos.Remove(tempDB+".wal")db:=database.NewDatabase(tempDB)ifdb==nil{t.Fatal("failed to create database")}deferdb.Close()// Block an IP and a CIDRdb.InsertBlocklist("1.1.1.1","test",time.Hour)db.InsertBlocklist("10.0.0.0/24","botnet",time.Hour)// UpdateBlocklistCache is called by InsertBlocklistRegisterDatabase(db)metrics:=&mockMetricsCollector{}RegisterMetricsCollector(metrics)logger:=slog.New(slog.NewJSONHandler(os.Stdout,nil))// Log event from blocked IP (exact match)LogEvent(logger,types.LogEvent{RemoteAddr:"1.1.1.1",Type:"ssh",Event:"auth_attempt",})iflen(metrics.events)!=0{t.Errorf("expected 0 events for blocked IP 1.1.1.1, got %v",len(metrics.events))}// Log event from blocked IP (CIDR match)LogEvent(logger,types.LogEvent{RemoteAddr:"10.0.0.50",Type:"ssh",Event:"auth_attempt",})iflen(metrics.events)!=0{t.Errorf("expected 0 events for blocked IP 10.0.0.50 (CIDR match), got %v",len(metrics.events))}// Log event from non-blocked IPLogEvent(logger,types.LogEvent{RemoteAddr:"2.2.2.2",Type:"ssh",Event:"auth_attempt",})iflen(metrics.events)!=1{t.Errorf("expected 1 event for non-blocked IP, got %v",len(metrics.events))}}funcTestSetup(t*testing.T){logFile:="test.log"deferos.Remove(logFile)logger,err:=Setup(logFile)iferr!=nil{t.Fatalf("Setup failed: %v",err)}iflogger==nil{t.Fatal("Setup returned nil logger")}if_,err:=os.Stat(logFile);os.IsNotExist(err){t.Error("log file was not created")}}funcTestRegisterDatabase(t*testing.T){db:=&database.Database{}RegisterDatabase(db)ifglobalDatabase.DB!=db.DB{t.Error("database was not registered correctly")}}funcTestLogError(t*testing.T){logger:=slog.New(slog.NewJSONHandler(os.Stdout,nil))LogError(logger,"test","error_event",os.ErrNotExist,[]any{"extra","info"})// Primarily verifying it doesn't panic and prints to stderr}funcTestLogInfo(t*testing.T){logger:=slog.New(slog.NewJSONHandler(os.Stdout,nil))LogInfo(logger,"test","info message",[]any{"extra","info"})// Primarily verifying it doesn't panic and prints to stdout}typetopNMockstruct{mockMetricsCollectorregisteredTypestringregisteredFieldstring}func(m*topNMock)RegisterTopNField(honeypotType,fieldNamestring){m.registeredType=honeypotTypem.registeredField=fieldName}funcTestRegisterTopNField(t*testing.T){mock:=&topNMock{}RegisterMetricsCollector(mock)RegisterTopNField("ssh","username")ifmock.registeredType!="ssh"||mock.registeredField!="username"{t.Errorf("expected ssh/username, got %v/%v",mock.registeredType,mock.registeredField)}}