package main import ( "encoding/json" "fmt" "strings" "testing" "testing/fstest" "text/template" ) func stringPointer(value string) *string { return &value } func floatPointer(value float64) *float64 { return &value } func boolPointer(value bool) *bool { return &value } func TestFormatHelpers(t *testing.T) { tests := []struct { value float64 want string }{ {0, "0.00 MiB"}, {1023, "1023.00 MiB"}, {1024, "1.00 GiB"}, {1536, "1.50 GiB"}, } for _, test := range tests { if got := formatSize(test.value); got != test.want { t.Errorf("formatSize(%v) = %q, want %q", test.value, got, test.want) } } if got := formatSeconds(42.5); got != "42.5 seconds" { t.Fatalf("formatSeconds() = %q", got) } literal, err := jsonLiteral("line\n\"quoted\"") if err != nil || literal != "\"line\\n\\\"quoted\\\"\"" { t.Fatalf("jsonLiteral() = %q, %v", literal, err) } } func TestTemplateRenderer(t *testing.T) { renderer, err := newTemplateRenderer() if err != nil { t.Fatal(err) } backup, err := renderer.renderBackup(backupRequest{ Title: stringPointer("Nightly"), Asset: stringPointer("photos"), BackupSizeInMB: floatPointer(1024), Extra: []extraRequest{{Name: stringPointer("Host"), Value: stringPointer("nebula")}}, }) if err != nil || backup.Embeds[0].Fields[0].Value != "1.00 GiB" || len(backup.Embeds[0].Fields) != 2 { t.Fatalf("backup render = %+v, %v", backup, err) } update, err := renderer.renderUpdate(updateRequest{Host: stringPointer("nexus"), Asset: stringPointer("k3s"), Time: floatPointer(0)}) if err != nil || update.Embeds[0].Fields[0].Value != "0 seconds" { t.Fatalf("update render = %+v, %v", update, err) } errorPayload, err := renderer.renderError(errorRequest{ Caller: stringPointer("job"), Message: stringPointer("\"quoted\" "), Critical: boolPointer(false), }) if err != nil || errorPayload.Embeds[0].Fields[0].Value != "\"quoted\" " || errorPayload.Embeds[0].Color != 15844367 { t.Fatalf("error render = %+v, %v", errorPayload, err) } if _, err := renderer.render("missing", struct{}{}); err == nil { t.Fatal("unknown template rendered") } encoded, err := json.Marshal(errorPayload) if err != nil || !json.Valid(encoded) || strings.Contains(string(encoded), """) { t.Fatalf("rendered JSON = %s, %v", encoded, err) } } func TestTemplateExtraFieldCap(t *testing.T) { renderer, err := newTemplateRenderer() if err != nil { t.Fatal(err) } extra := make([]extraRequest, 40) for index := range extra { extra[index] = extraRequest{Name: stringPointer(fmt.Sprintf("field-%02d", index)), Value: stringPointer("value")} } payload, err := renderer.renderError(errorRequest{ Caller: stringPointer("job"), Message: stringPointer("failure"), Critical: boolPointer(true), Extra: extra, }) if err != nil { t.Fatal(err) } if len(payload.Embeds[0].Fields) != 25 { t.Fatalf("fields = %d, want 25", len(payload.Embeds[0].Fields)) } if payload.Embeds[0].Fields[24].Name != "field-23" { t.Fatalf("last retained field = %q", payload.Embeds[0].Fields[24].Name) } } func TestTemplateRendererFailures(t *testing.T) { if _, err := newTemplateRendererFromFS(fstest.MapFS{}); err == nil { t.Fatal("missing templates were accepted") } invalidFS := fstest.MapFS{ "template/backup.tmpl": {Data: []byte("{{")}, "template/update.tmpl": {Data: []byte("{}")}, "template/error.tmpl": {Data: []byte("{}")}, } if _, err := newTemplateRendererFromFS(invalidFS); err == nil { t.Fatal("invalid template was accepted") } renderer := &templateRenderer{templates: map[string]*template.Template{}} renderer.templates["invalid-json"] = template.Must(template.New("invalid-json").Parse("not-json")) if _, err := renderer.render("invalid-json", nil); err == nil { t.Fatal("invalid JSON template rendered") } renderer.templates["execute-error"] = template.Must(template.New("execute-error").Parse("{{index . 0}}")) if _, err := renderer.render("execute-error", nil); err == nil { t.Fatal("template execution error was ignored") } }