// Copyright 2026 tamakyi. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. package cmd import ( "testing" "github.com/tamakyi/TamaBox/internal/db" ) // TestMergeSourcesByKey 验证来源排行按「封禁口径」合并(IPv6 折成 /64)。 // // 元数据表存的是精确地址(取证需要),若排行榜也按精确地址分组, // 一个在 /64 内轮换地址的扫描器会碎成几十条各 1 次的记录 —— // 看起来像「很多人在扫」,其实只有一台机器。合并口径必须与 autoban 一致。 func TestMergeSourcesByKey(t *testing.T) { rows := []*db.HoneypotSourceStat{ {IP: "2408:8207:1234:5678::1", Count: 5, Provider: "联通"}, {IP: "2408:8207:1234:5678::2", Count: 3}, {IP: "1.2.3.4", Count: 4, Provider: "Azure"}, {IP: "2408:8207:9999:0001::1", Count: 2}, } got := mergeSourcesByKey(rows, 10) if len(got) != 3 { t.Fatalf("合并后条目数 = %d, want 3(同 /64 必须合并)", len(got)) } if got[0].IP != "2408:8207:1234:5678::/64" || got[0].Count != 8 { t.Errorf("第一名 = %s / %d, want 2408:8207:1234:5678::/64 / 8", got[0].IP, got[0].Count) } if got[0].Provider != "联通" { t.Errorf("合并后应保留首个非空归属,got %q", got[0].Provider) } if got[1].IP != "1.2.3.4" || got[1].Count != 4 { t.Errorf("第二名 = %s / %d, want 1.2.3.4 / 4(IPv4 原样保留)", got[1].IP, got[1].Count) } if limited := mergeSourcesByKey(rows, 1); len(limited) != 1 { t.Errorf("limit=1 时条目数 = %d, want 1", len(limited)) } if out := mergeSourcesByKey(nil, 10); len(out) != 0 { t.Errorf("空输入应返回空,got %d", len(out)) } }