a2bfa8ea71
Add srrdb_log table with composite primary key (day, category) and counters found, stored, ignored plus run_at. Replace the release-only persistence path with UpsertAllSrrdbWithDay so releases and their corresponding srrdb_log row are written in one SQLite transaction. Preserve existing error handling: rollback reports the release/day that failed, and commit errors return without writing a dump. Handle fully ignored days as closed. When every fetched release is skipped by ignore rules, still write the ledger row with zero stored releases. This prevents the automatic day walk from endlessly retrying a day whose releases are filtered out. Derive and validate the ledger day from the resolved request URI. Missing or invalid date: segments now fail before database writes. Keep run_at independent from created_at semantics and continue populating created_at from the run time. Preserve column and upsert semantics. category continues to use NOT NULL DEFAULT empty string; status keeps COALESCE behavior on conflict; nfo, content, and synced_at remain unchanged.
110 lines
2.5 KiB
Go
110 lines
2.5 KiB
Go
package repository
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
func TestSrrdbLoadGroupRules(t *testing.T) {
|
|
viper.Reset()
|
|
viper.Set("groups", map[string]any{
|
|
"status": map[string]any{
|
|
"neformat": []string{"SHGZ"},
|
|
"remove": []any{"BIGLOVE", "CT"},
|
|
"ignore": []string{"BABAS"},
|
|
},
|
|
})
|
|
|
|
rules, err := srrdbLoadGroupRules()
|
|
if err != nil {
|
|
t.Fatalf("srrdbLoadGroupRules: %v", err)
|
|
}
|
|
|
|
if got := rules.status["SHGZ"]; got != "neformat" {
|
|
t.Errorf("status[SHGZ] = %q, want neformat", got)
|
|
}
|
|
|
|
if got := rules.status["CT"]; got != "remove" {
|
|
t.Errorf("status[CT] = %q, want remove", got)
|
|
}
|
|
|
|
if !rules.ignore["BABAS"] {
|
|
t.Error("BABAS must be ignored")
|
|
}
|
|
|
|
if rules.ignore["CT"] {
|
|
t.Error("CT must not be ignored")
|
|
}
|
|
}
|
|
|
|
// The regression this guards: viper lowercases keys, and if the group names were
|
|
// read as keys, SHGZ would arrive as shgz and would never match a release line.
|
|
func TestSrrdbLoadGroupRulesKeepsGroupCase(t *testing.T) {
|
|
viper.Reset()
|
|
viper.Set("groups", map[string]any{
|
|
"status": map[string]any{
|
|
"neformat": []string{"SHGZ", "ENViED"},
|
|
},
|
|
})
|
|
|
|
rules, err := srrdbLoadGroupRules()
|
|
if err != nil {
|
|
t.Fatalf("srrdbLoadGroupRules: %v", err)
|
|
}
|
|
|
|
for _, group := range []string{"SHGZ", "ENViED"} {
|
|
if _, exists := rules.status[group]; !exists {
|
|
t.Errorf("group %q was not registered with its original case", group)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSrrdbLoadGroupRulesRejectsGroupInTwoLists(t *testing.T) {
|
|
viper.Reset()
|
|
viper.Set("groups", map[string]any{
|
|
"status": map[string]any{
|
|
"neformat": []string{"SHGZ"},
|
|
"remove": []string{"SHGZ"},
|
|
},
|
|
})
|
|
|
|
_, err := srrdbLoadGroupRules()
|
|
if err == nil {
|
|
t.Fatal("a group listed under two values must be rejected")
|
|
}
|
|
|
|
for _, want := range []string{"SHGZ", "neformat", "remove"} {
|
|
if !strings.Contains(err.Error(), want) {
|
|
t.Errorf("error %q does not name %q", err, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSrrdbLoadGroupRulesRejectsNumericGroup(t *testing.T) {
|
|
viper.Reset()
|
|
viper.Set("groups", map[string]any{
|
|
"status": map[string]any{
|
|
"ignore": []any{401},
|
|
},
|
|
})
|
|
|
|
if _, err := srrdbLoadGroupRules(); err == nil {
|
|
t.Error("an unquoted numeric group must be rejected instead of dropped silently")
|
|
}
|
|
}
|
|
|
|
func TestSrrdbLoadGroupRulesRejectsUnknownColumn(t *testing.T) {
|
|
viper.Reset()
|
|
viper.Set("groups", map[string]any{
|
|
"nfo": map[string]any{
|
|
"x": []string{"Y"},
|
|
},
|
|
})
|
|
|
|
if _, err := srrdbLoadGroupRules(); err == nil {
|
|
t.Error("a rule targeting a column other than status must be rejected")
|
|
}
|
|
}
|