package deploy import ( "strings" "testing" ) func TestValidateName(t *testing.T) { good := []string{"book", "chat", "a", "my-app", "app1", "1book"} for _, n := range good { if err := ValidateName(n); err != nil { t.Errorf("ValidateName(%q) = %v, want nil", n, err) } } bad := []string{"", "Book", "book.local", "-book", "book-", "a_b", "café", "two words"} for _, n := range bad { if err := ValidateName(n); err == nil { t.Errorf("ValidateName(%q) = nil, want error", n) } } long := make([]byte, 64) for i := range long { long[i] = 'a' } if err := ValidateName(string(long)); err == nil { t.Errorf("ValidateName(64 chars) = nil, want error") } } func TestParseHosts(t *testing.T) { // Two app containers' `once` labels concatenated, as docker inspect emits. blob := `{"image":"ghcr.io/basecamp/writebook","host":"Book.local","tls":false} {"host":"chat.local","image":"once-campfire"} {"host":"public.example.com"}` got := parseHosts(blob) if !got["book.local"] { // lowercased t.Errorf("expected book.local in %v", got) } if !got["chat.local"] { t.Errorf("expected chat.local in %v", got) } if got["public.example.com"] { t.Errorf("non-.local host should be excluded: %v", got) } if len(got) != 2 { t.Errorf("got %d hosts, want 2: %v", len(got), got) } } func TestHost(t *testing.T) { if Host("book") != "book.local" { t.Errorf("Host(book) = %q", Host("book")) } } func TestFilterHostLines(t *testing.T) { in := "127.0.1.1\tdevbox\n" + "127.0.0.1 book.local\n" + "127.0.0.1 mybook.local\n" + // must NOT match book.local "127.0.0.1 book.local2\n" + // must NOT match book.local "127.0.0.1 chat.local\n" out, removed := filterHostLines(in, "book.local") if !removed { t.Fatal("expected book.local to be removed") } if strings.Contains(out, "\n127.0.0.1 book.local\n") || strings.HasSuffix(out, "127.0.0.1 book.local") { t.Errorf("book.local line still present:\n%s", out) } for _, keep := range []string{"devbox", "mybook.local", "book.local2", "chat.local"} { if !strings.Contains(out, keep) { t.Errorf("filter wrongly dropped %q:\n%s", keep, out) } } if _, removed := filterHostLines(in, "absent.local"); removed { t.Error("absent.local should report nothing removed") } } func TestRemoveDoneMsg(t *testing.T) { cases := []struct { appRemoved, hostsRemoved bool want string }{ {true, true, "Removed book.local"}, {true, false, "Removed book.local (no /etc/hosts entry to clean)"}, {false, true, "Cleaned orphan /etc/hosts entry for book.local"}, {false, false, "Nothing to remove for book.local"}, } for _, c := range cases { if got := removeDoneMsg("book.local", c.appRemoved, c.hostsRemoved); got != c.want { t.Errorf("removeDoneMsg(_, %v, %v) = %q, want %q", c.appRemoved, c.hostsRemoved, got, c.want) } } }