Introduce seed-telegrams tool for generating synthetic telegrams for testing and development. Enhance README with detailed usage instructions, command-line parameters, and examples. Add unit tests for telegram generation and status selection logic to ensure robustness. Update documentation to reflect new features and usage scenarios.

This commit is contained in:
windyboy
2025-11-16 17:24:16 +08:00
parent 06b2495d77
commit 12fda00df9
9 changed files with 730 additions and 80 deletions
+211
View File
@@ -0,0 +1,211 @@
package main
import (
"testing"
"time"
)
// Test buildBody generates syntactically plausible bodies for each category.
func TestBuildBodyFormats(t *testing.T) {
tests := []struct {
category string
prefix string
suffix string
}{
{"ARR", "(ARR-", ")"},
{"DEP", "(DEP-", ")"},
{"CNL", "(CNL-", ")"},
{"DLA", "(DLA-", ")"},
{"FPL", "(FPL-", ")"},
}
for _, tt := range tests {
body, invalid := buildBody(tt.category)
if !invalid && body == "" {
t.Fatalf("category %s: expected non-empty body", tt.category)
}
if body[0:len(tt.prefix)] != tt.prefix {
t.Fatalf("category %s: expected prefix %q, got %q", tt.category, tt.prefix, body[0:len(tt.prefix)])
}
if body[len(body)-len(tt.suffix):] != tt.suffix {
t.Fatalf("category %s: expected suffix %q, got %q", tt.category, tt.suffix, body[len(body)-len(tt.suffix):])
}
}
}
// Test buildTelegram wires header and body into a full telegram.
func TestBuildTelegramBasicFields(t *testing.T) {
tg, _ := buildTelegram("ARR")
if tg.Category != "ARR" {
t.Fatalf("expected category ARR, got %s", tg.Category)
}
if tg.MessageID == "" {
t.Fatalf("expected non-empty MessageID")
}
if tg.UUID == "" {
t.Fatalf("expected non-empty UUID")
}
if tg.Content == "" {
t.Fatalf("expected non-empty Content")
}
if tg.ReceivedAt.IsZero() {
t.Fatalf("expected ReceivedAt to be set")
}
if tg.Metadata != nil {
t.Fatalf("expected Metadata to be nil from buildTelegram")
}
}
func TestBuildCategories(t *testing.T) {
all := []string{"ARR", "DEP", "CNL", "DLA", "FPL"}
got := buildCategories("mixed", all)
if len(got) != len(all) {
t.Fatalf("expected all categories for mixed, got %d", len(got))
}
got = buildCategories("", all)
if len(got) != len(all) {
t.Fatalf("expected all categories for empty flag, got %d", len(got))
}
got = buildCategories("arr", all)
if len(got) != 1 || got[0] != "ARR" {
t.Fatalf("expected single category ARR, got %#v", got)
}
}
func TestBuildStatuses(t *testing.T) {
all := []string{"parsed", "header_error", "body_error"}
got := buildStatuses("random", all)
if len(got) != len(all) {
t.Fatalf("expected all statuses for random, got %d", len(got))
}
got = buildStatuses("", all)
if len(got) != len(all) {
t.Fatalf("expected all statuses for empty flag, got %d", len(got))
}
got = buildStatuses("parsed", all)
if len(got) != 1 || got[0] != "parsed" {
t.Fatalf("expected single status parsed, got %#v", got)
}
}
func TestChooseStatusNonRandomUsesProvidedList(t *testing.T) {
statuses := []string{"parsed"}
for i := 0; i < 10; i++ {
got := chooseStatus(false, "parsed", statuses)
if got != "parsed" {
t.Fatalf("expected parsed, got %s", got)
}
}
}
func TestChooseStatusRandomOnlyReturnsKnownStatuses(t *testing.T) {
statuses := []string{"parsed", "header_error", "body_error"}
for i := 0; i < 100; i++ {
got := chooseStatus(false, "random", statuses)
if !contains(statuses, got) && got != "body_error" && got != "parsed" {
t.Fatalf("unexpected status from chooseStatus: %s", got)
}
}
}
func contains(list []string, v string) bool {
for _, s := range list {
if s == v {
return true
}
}
return false
}
// Test RunSeed burst mode publishes Count messages.
func TestRunSeedBurstPublishesCount(t *testing.T) {
cfg := SeedConfig{
Count: 5,
Mode: "burst",
DryRun: false,
}
categories := []string{"ARR"}
statuses := []string{"parsed"}
var published int
pub := func(*telegram) error {
published++
return nil
}
if err := RunSeed(cfg, categories, statuses, pub); err != nil {
t.Fatalf("RunSeed burst returned error: %v", err)
}
if published != cfg.Count {
t.Fatalf("expected %d published messages, got %d", cfg.Count, published)
}
}
// Test RunSeed interval mode respects Count and does not sleep in DryRun.
func TestRunSeedIntervalRespectsCount(t *testing.T) {
origSleep := sleepFunc
defer func() { sleepFunc = origSleep }()
sleepFunc = func(time.Duration) {}
cfg := SeedConfig{
Count: 3,
Mode: "interval",
IntervalMin: 10 * time.Millisecond,
IntervalMax: 20 * time.Millisecond,
DryRun: true,
}
categories := []string{"ARR"}
statuses := []string{"parsed"}
var published int
pub := func(*telegram) error {
published++
return nil
}
if err := RunSeed(cfg, categories, statuses, pub); err != nil {
t.Fatalf("RunSeed interval returned error: %v", err)
}
if published != cfg.Count {
t.Fatalf("expected %d published messages, got %d", cfg.Count, published)
}
}
// Test RunSeed mixed mode still results in exactly Count messages when Count>0.
func TestRunSeedMixedPublishesCount(t *testing.T) {
origSleep := sleepFunc
defer func() { sleepFunc = origSleep }()
sleepFunc = func(time.Duration) {}
cfg := SeedConfig{
Count: 6,
Mode: "mixed",
IntervalMin: 1 * time.Millisecond,
IntervalMax: 2 * time.Millisecond,
DryRun: true,
}
categories := []string{"ARR"}
statuses := []string{"parsed"}
var published int
pub := func(*telegram) error {
published++
return nil
}
if err := RunSeed(cfg, categories, statuses, pub); err != nil {
t.Fatalf("RunSeed mixed returned error: %v", err)
}
if published != cfg.Count {
t.Fatalf("expected %d published messages, got %d", cfg.Count, published)
}
}