85 lines
2.8 KiB
Go
85 lines
2.8 KiB
Go
package main
|
|
|
|
// Unit tests for the schema (novox/hq ADR 0459 §4, issue 1517): the migrations are read with no gap and a
|
|
// bad name is refused (AC1), and no table holds a mail body or text taken from one (AC3). AC2 (the manifest
|
|
// requires postgres-database, binds it, renders database-url and runs prepare) is manifest_test.go's; AC4
|
|
// (against a real postgres) is pgstore_integration_test.go, compiled but never run from here.
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"testing/fstest"
|
|
)
|
|
|
|
// 1517/AC1: Migrations() reads migrations/0001-*.sql onward with no gap.
|
|
func TestMigrationsReadsTheRealOnesWithNoGap(t *testing.T) {
|
|
ms, err := Migrations()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(ms) == 0 {
|
|
t.Fatal("no migrations found")
|
|
}
|
|
for i, m := range ms {
|
|
if m.Number != i+1 {
|
|
t.Fatalf("migration %d is numbered %04d, want %04d", i, m.Number, i+1)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 1517/AC1: a gap in the numbering is refused.
|
|
func TestMigrationsRefusesAGap(t *testing.T) {
|
|
fsys := fstest.MapFS{
|
|
"m/0001-first.sql": {Data: []byte("create table a (id int);")},
|
|
"m/0003-third.sql": {Data: []byte("create table b (id int);")},
|
|
}
|
|
if _, err := migrationsFrom(fsys, "m"); err == nil || !strings.Contains(err.Error(), "gap") {
|
|
t.Fatalf("migrationsFrom with a gap: %v, want an error naming the gap", err)
|
|
}
|
|
}
|
|
|
|
// 1517/AC1: a file whose name is not NNNN-what-it-does.sql is refused by name.
|
|
func TestMigrationsRefusesABadName(t *testing.T) {
|
|
fsys := fstest.MapFS{
|
|
"m/0001-first.sql": {Data: []byte("create table a (id int);")},
|
|
"m/not-a-migration.sql": {Data: []byte("create table b (id int);")},
|
|
}
|
|
if _, err := migrationsFrom(fsys, "m"); err == nil || !strings.Contains(err.Error(), "not a migration's name") {
|
|
t.Fatalf("migrationsFrom with a bad name: %v, want an error naming it", err)
|
|
}
|
|
}
|
|
|
|
// forbiddenColumn is 1517/AC3: no table in schema.sql or any migration has a column for a mail body or text.
|
|
var forbiddenColumns = []string{"body", "text", "content", "snippet"}
|
|
|
|
// 1517/AC3: no table in schema.sql or any migration has a column named body, text, content or snippet, and
|
|
// summary is bounded to 160 characters by a CHECK.
|
|
func TestTheSchemaKeepsNoMailBodyOrText(t *testing.T) {
|
|
for _, sql := range allSchemaSQL(t) {
|
|
for _, line := range strings.Split(sql, "\n") {
|
|
word := strings.ToLower(strings.TrimSpace(strings.Fields(line + " x")[0]))
|
|
for _, forbidden := range forbiddenColumns {
|
|
if word == forbidden {
|
|
t.Fatalf("a column is named %q, which may hold a mail body or text taken from one: %q", forbidden, line)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if !strings.Contains(consolidated, "char_length(summary) <= 160") {
|
|
t.Fatal("summary has no CHECK bounding it to 160 characters")
|
|
}
|
|
}
|
|
|
|
func allSchemaSQL(t *testing.T) []string {
|
|
t.Helper()
|
|
ms, err := Migrations()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
out := []string{consolidated}
|
|
for _, m := range ms {
|
|
out = append(out, m.SQL)
|
|
}
|
|
return out
|
|
}
|