The issue tracker's history lasts seven days on the events stream and its bucket fills toward a cap with no warning (issues 501, 502). A module may now declare `logs`; the controller creates each as a stream on the bus (create-or-update, never deleted or recreated, reported when undeclared), issues it to the owner's assignments in their membership, grants the runtime exactly the append and direct-read subjects, and raises a condition when any module's bucket or log reaches 75% of its cap, cleared below 70%.
69 lines
2.9 KiB
Go
69 lines
2.9 KiB
Go
package catalogue
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// A module declares the logs it keeps (novox/hq ADR 0297 §1): a log by its bare name, or with its cap
|
|
// in MiB; the default cap where none is said.
|
|
func TestAManifestMaySayWhatLogsItKeeps(t *testing.T) {
|
|
m, err := ParseManifest([]byte(`{"module":"mesh-issues","version":"1",` +
|
|
`"logs":["changes",{"name":"moves","max-mib":2048}]}`))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(m.Logs) != 2 || m.Logs[0].Name != "changes" || m.Logs[1].Name != "moves" {
|
|
t.Fatalf("logs not read: %+v", m.Logs)
|
|
}
|
|
if m.Logs[0].Cap() != LogDefaultMiB || m.Logs[0].Cap() != 1024 || m.Logs[1].Cap() != 2048 {
|
|
t.Fatalf("caps read as %d and %d", m.Logs[0].Cap(), m.Logs[1].Cap())
|
|
}
|
|
out, _ := json.Marshal(m.Logs)
|
|
if string(out) != `["changes",{"name":"moves","max-mib":2048}]` {
|
|
t.Fatalf("written back as %s", out)
|
|
}
|
|
for _, edge := range []string{`{"name":"a","max-mib":1}`, `{"name":"a","max-mib":8192}`} {
|
|
if _, err := ParseManifest([]byte(`{"module":"a","version":"1","logs":[` + edge + `]}`)); err != nil {
|
|
t.Errorf("%s is inside the caps and was refused: %v", edge, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// The catalogue check refuses a log outside the caps, with a name that is not one plain token, with a
|
|
// field the mesh does not know, or kept by a module whose own name is not one plain token.
|
|
func TestALogIsNamedLocallyAndCapped(t *testing.T) {
|
|
for _, c := range []struct{ manifest, says string }{
|
|
{`{"module":"a","version":"1","logs":["mesh.changes"]}`, `keeps log "mesh.changes": a log is named locally`},
|
|
{`{"module":"a","version":"1","logs":["my_changes"]}`, `keeps log "my_changes"`},
|
|
{`{"module":"a","version":"1","logs":["Changes"]}`, `keeps log "Changes"`},
|
|
{`{"module":"a","version":"1","logs":["c","c"]}`, `keeps log "c" twice`},
|
|
{`{"module":"a","version":"1","logs":[{"name":"c","max-mib":8193}]}`, `between 1 and 8192 MiB`},
|
|
{`{"module":"a","version":"1","logs":[{"name":"c","max-mib":-1}]}`, `between 1 and 8192 MiB`},
|
|
{`{"module":"a","version":"1","logs":[{"name":"c","max-mib":0}]}`, `max-mib is between 1 and 8192, not 0`},
|
|
{`{"module":"a","version":"1","logs":[{"name":"c","stream":"LOG_x"}]}`, `{name, max-mib}`},
|
|
{`{"module":"a.b","version":"1","logs":["c"]}`, `no dot`},
|
|
} {
|
|
_, err := ParseManifest([]byte(c.manifest))
|
|
if err == nil {
|
|
t.Errorf("%s was accepted", c.manifest)
|
|
continue
|
|
}
|
|
if !strings.Contains(err.Error(), c.says) {
|
|
t.Errorf("%s refused for the wrong reason: %v", c.manifest, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// **Across the whole catalogue**: every log is named locally and capped within the mesh's caps.
|
|
func TestEveryManifestsLogsAreLocalAndCapped(t *testing.T) {
|
|
var problems []string
|
|
for _, m := range theCatalogue(t) {
|
|
problems = append(problems, LogProblems(m)...)
|
|
}
|
|
if len(problems) > 0 {
|
|
t.Fatalf("the catalogue's logs are not what ADR 0297 says:\n %s", strings.Join(problems, "\n "))
|
|
}
|
|
}
|