package web import ( "testing" ) // ---------- 专题:归人不归数据集 ---------- // // 专题是「一段时间 + 一块区域」的定义,不是备份里的数据:换数据集之后它照旧成立 // (内容照当前生效数据集算),删掉旧数据集不该把它带走。 // 早期版本 `topics.dataset_id` 带 ON DELETE CASCADE,实测丢过一批专题,而且**只存在这张表里**, // 没有别的恢复来源。这两条用例守的就是「删数据集之后专题还在、还列得出来」。 // insertTopic 直接插一条专题(与页面同一张表,省去构造表单)。 func insertTopic(t *testing.T, f *movementFixture, title string) int64 { t.Helper() uid := userFrom(f.ctx).ID var id int64 if err := f.pg.QueryRowContext(f.ctx, `INSERT INTO topics (user_id, dataset_id, title, subtitle, description, start_at, end_at, center_lat, center_lon, radius_km, show_fog, enabled, sort_order) VALUES ($1,$2,$3,'','',now() - interval '30 days', now(), 0,0,0, true, true, 0) RETURNING id`, uid, f.dsID, title).Scan(&id); err != nil { t.Fatalf("插专题失败: %v", err) } return id } func topicIDs(t *testing.T, f *movementFixture, uid int64) []int64 { t.Helper() list, err := f.srv.loadTopics(f.ctx, uid, false) if err != nil { t.Fatalf("读专题失败: %v", err) } var out []int64 for _, tp := range list { out = append(out, tp.ID) } return out } // TestTopicsSurviveDatasetDelete 删数据集不再带走专题,删完还能按属主列出来。 func TestTopicsSurviveDatasetDelete(t *testing.T) { f := newMovementFixture(t) uid := userFrom(f.ctx).ID want := insertTopic(t, f, "2026 国庆") if got := topicIDs(t, f, uid); len(got) != 1 || got[0] != want { t.Fatalf("建完之后应当能按属主列出这一条,实际 %v", got) } // 外键已摘:删数据集不级联到专题 if _, err := f.pg.ExecContext(f.ctx, `DELETE FROM datasets WHERE id=$1`, f.dsID); err != nil { t.Fatalf("删数据集失败: %v", err) } var n int if err := f.pg.QueryRowContext(f.ctx, `SELECT count(*) FROM topics WHERE id=$1`, want).Scan(&n); err != nil { t.Fatal(err) } if n != 1 { t.Fatalf("删数据集把专题带走了(外键没摘干净?)") } if got := topicIDs(t, f, uid); len(got) != 1 || got[0] != want { t.Errorf("没有生效数据集时也该列得出来(专题归人),实际 %v", got) } } // TestTopicsForeignKeyDropped 直接盯住迁移本身:外键约束必须不在。 // 只看「删数据集没删专题」有可能被别的原因弄绿(比如根本没建数据集约束), // 这里把判据钉在 `pg_constraint` 上。 func TestTopicsForeignKeyDropped(t *testing.T) { f := newMovementFixture(t) var del string err := f.pg.QueryRowContext(f.ctx, `SELECT confdeltype FROM pg_constraint WHERE conname='topics_dataset_id_fkey'`).Scan(&del) if err == nil { t.Errorf("topics 上还有 datasets 的外键(删除行为=%s):删数据集会把专题一起带走", del) } // 专题只该跟着**用户**走:删用户时它必须一起没,不能留下孤儿 uid := userFrom(f.ctx).ID insertTopic(t, f, "会被用户带走") if _, err := f.pg.ExecContext(f.ctx, `DELETE FROM users WHERE id=$1`, uid); err != nil { t.Fatalf("删用户失败: %v", err) } var left int if err := f.pg.QueryRowContext(f.ctx, `SELECT count(*) FROM topics WHERE user_id=$1`, uid).Scan(&left); err != nil { t.Fatal(err) } if left != 0 { t.Errorf("删用户后专题还留着 %d 条", left) } }