feat: 管理端网站监控,浏览量写入独立 monitor.db
请求日志按日 JSONL;page_views 不进主库,避免统计数据撑大 jiang13.db。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -47,7 +47,7 @@ func TestCommunityHeartbeatHubDisabled(t *testing.T) {
|
||||
Version: "1.0.0",
|
||||
Users: 1,
|
||||
Posts: 2,
|
||||
}, "127.0.0.1")
|
||||
}, "127.0.0.1", "https://other.example")
|
||||
if !errors.Is(err, ErrCommunityHubDisabled) {
|
||||
t.Fatalf("want ErrCommunityHubDisabled, got %v", err)
|
||||
}
|
||||
@@ -65,12 +65,12 @@ func TestCommunityHeartbeatAcceptAndList(t *testing.T) {
|
||||
Users: 10,
|
||||
Posts: 20,
|
||||
}
|
||||
if err := svc.ReceiveHeartbeat(payload, "203.0.113.9"); err != nil {
|
||||
if err := svc.ReceiveHeartbeat(payload, "203.0.113.9", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
payload.Users = 11
|
||||
payload.Posts = 21
|
||||
if err := svc.ReceiveHeartbeat(payload, "203.0.113.9"); err != nil {
|
||||
if err := svc.ReceiveHeartbeat(payload, "203.0.113.9", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ func TestCommunityHeartbeatBadURL(t *testing.T) {
|
||||
InstanceID: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
|
||||
SiteURL: "javascript:alert(1)",
|
||||
SiteName: "坏",
|
||||
}, "127.0.0.1")
|
||||
}, "127.0.0.1", "")
|
||||
if !errors.Is(err, ErrCommunityBadPayload) {
|
||||
t.Fatalf("want ErrCommunityBadPayload, got %v", err)
|
||||
}
|
||||
@@ -204,11 +204,11 @@ func TestCommunityFeatureAndShowcase(t *testing.T) {
|
||||
SiteName: "示例论坛",
|
||||
Version: "2.0.0",
|
||||
}
|
||||
if err := svc.ReceiveHeartbeat(payload, "127.0.0.1"); err != nil {
|
||||
if err := svc.ReceiveHeartbeat(payload, "127.0.0.1", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
empty, err := svc.ListShowcase()
|
||||
empty, err := svc.ListShowcase("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -227,7 +227,7 @@ func TestCommunityFeatureAndShowcase(t *testing.T) {
|
||||
t.Fatalf("unexpected view: %+v", view)
|
||||
}
|
||||
|
||||
items, err := svc.ListShowcase()
|
||||
items, err := svc.ListShowcase("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -237,10 +237,10 @@ func TestCommunityFeatureAndShowcase(t *testing.T) {
|
||||
|
||||
// 心跳更新不得清掉精选
|
||||
payload.Users = 9
|
||||
if err := svc.ReceiveHeartbeat(payload, "127.0.0.1"); err != nil {
|
||||
if err := svc.ReceiveHeartbeat(payload, "127.0.0.1", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
items, err = svc.ListShowcase()
|
||||
items, err = svc.ListShowcase("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -249,7 +249,7 @@ func TestCommunityFeatureAndShowcase(t *testing.T) {
|
||||
}
|
||||
|
||||
settings.SetCommunityHubEnabled(false)
|
||||
items, err = svc.ListShowcase()
|
||||
items, err = svc.ListShowcase("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -281,3 +281,154 @@ func TestCommunitySiteURLFromOrigin(t *testing.T) {
|
||||
t.Fatalf("payload site_url=%s", payload.SiteURL)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommunityHubByOfficialHost(t *testing.T) {
|
||||
settings, svc := setupCommunityTest(t)
|
||||
|
||||
// 其它域名、未开运维开关 → 拒绝
|
||||
err := svc.ReceiveHeartbeat(CommunityHeartbeatPayload{
|
||||
InstanceID: "bbbbbbbb-cccc-dddd-eeee-ffffffffffff",
|
||||
SiteURL: "https://forum.example.org",
|
||||
SiteName: "他站",
|
||||
Version: "1.0.0",
|
||||
}, "127.0.0.1", "https://other.example")
|
||||
if !errors.Is(err, ErrCommunityHubDisabled) {
|
||||
t.Fatalf("want disabled for other host, got %v", err)
|
||||
}
|
||||
|
||||
// 请求 Host 为官网 → 自动枢纽
|
||||
payload := CommunityHeartbeatPayload{
|
||||
InstanceID: "cccccccc-dddd-eeee-ffff-000000000001",
|
||||
SiteURL: "https://forum.example.org",
|
||||
SiteName: "上报站",
|
||||
Version: "1.1.0",
|
||||
Users: 3,
|
||||
Posts: 5,
|
||||
}
|
||||
if err := svc.ReceiveHeartbeat(payload, "203.0.113.1", "https://bbs.iioio.com"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !settings.CommunityHubEnabled("https://www.bbs.iioio.com") {
|
||||
t.Fatal("www 前缀也应识别为官网")
|
||||
}
|
||||
if !settings.CommunityConfigForRequest("https://bbs.iioio.com").HubEnabled {
|
||||
t.Fatal("CommunityConfigForRequest should enable hub for official host")
|
||||
}
|
||||
|
||||
list, err := svc.ListInstances()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(list) != 1 {
|
||||
t.Fatalf("want 1 instance, got %d", len(list))
|
||||
}
|
||||
|
||||
// 已存 ROOT_URL 为官网时,无请求上下文也应开启
|
||||
if err := settings.setString(SettingOIDCRootURL, DefaultCommunityHubURL); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !settings.CommunityHubEnabled("") {
|
||||
t.Fatal("ROOT_URL as official should enable hub without request hint")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommunityHubSkipsOutboundHeartbeat(t *testing.T) {
|
||||
settings, svc := setupCommunityTest(t)
|
||||
var hits atomic.Int32
|
||||
|
||||
hub := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
hits.Add(1)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte(`{"ok":true}`))
|
||||
}))
|
||||
t.Cleanup(hub.Close)
|
||||
|
||||
prevHub := communityHubBaseURL
|
||||
communityHubBaseURL = hub.URL
|
||||
t.Cleanup(func() { communityHubBaseURL = prevHub })
|
||||
|
||||
if err := settings.setString(SettingOIDCRootURL, DefaultCommunityHubURL); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := settings.UpdateCommunityConfig(CommunityConfig{ReportEnabled: true}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := svc.SendHeartbeatOnce(""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if hits.Load() != 0 {
|
||||
t.Fatal("hub site must not send outbound heartbeat")
|
||||
}
|
||||
|
||||
// 运维开关开启同样跳过
|
||||
settings2, svc2 := setupCommunityTest(t)
|
||||
settings2.SetCommunityHubEnabled(true)
|
||||
if err := settings2.setString(SettingOIDCRootURL, "http://mirror.local"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := settings2.UpdateCommunityConfig(CommunityConfig{ReportEnabled: true}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
prevHub2 := communityHubBaseURL
|
||||
communityHubBaseURL = hub.URL
|
||||
t.Cleanup(func() { communityHubBaseURL = prevHub2 })
|
||||
if err := svc2.SendHeartbeatOnce(""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if hits.Load() != 0 {
|
||||
t.Fatal("ops hub must not send outbound heartbeat")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHostFromURLOrHost(t *testing.T) {
|
||||
cases := []struct {
|
||||
in, want string
|
||||
}{
|
||||
{"https://bbs.iioio.com", "bbs.iioio.com"},
|
||||
{"https://www.bbs.iioio.com/", "bbs.iioio.com"},
|
||||
{"https://bbs.iioio.com:443/path", "bbs.iioio.com"},
|
||||
{"BBS.IIOIO.COM", "bbs.iioio.com"},
|
||||
{"https://other.example", "other.example"},
|
||||
{"", ""},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
if got := hostFromURLOrHost(tc.in); got != tc.want {
|
||||
t.Fatalf("hostFromURLOrHost(%q)=%q want %q", tc.in, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAsideShowcaseEntrySync(t *testing.T) {
|
||||
settings, _ := setupCommunityTest(t)
|
||||
if settings.NavShowShowcase() || settings.FooterShowShowcase() || settings.AsideShowShowcase() {
|
||||
t.Fatal("showcase entry should be off by default")
|
||||
}
|
||||
if err := settings.SetNavShowShowcase(true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := settings.SetFooterShowShowcase(true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := settings.SetAsideShowcaseEnabled(true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !settings.NavShowShowcase() || !settings.FooterShowShowcase() || !settings.AsideShowShowcase() {
|
||||
t.Fatal("showcase entry should be enabled")
|
||||
}
|
||||
cfg := settings.Limits()
|
||||
if !cfg.NavShowShowcase || !cfg.FooterShowShowcase || !cfg.AsideShowShowcase {
|
||||
t.Fatalf("limits missing showcase flags: %+v", cfg)
|
||||
}
|
||||
found := false
|
||||
for _, w := range cfg.AsideWidgets {
|
||||
if w.ID == AsideWidgetShowcase {
|
||||
found = true
|
||||
if !w.Enabled {
|
||||
t.Fatal("aside showcase widget should be enabled")
|
||||
}
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Fatal("aside widgets should include showcase")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user