This commit is contained in:
@@ -0,0 +1,238 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"plumber/internal/events"
|
||||
"plumber/internal/pacific"
|
||||
"plumber/internal/store"
|
||||
)
|
||||
|
||||
func TestPostHandlersPublishEvents(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rec := &events.Recording{}
|
||||
srv, mem := newTestServer(t, Config{
|
||||
Events: rec,
|
||||
BaseURL: "https://www.askaplumberfirst.com",
|
||||
})
|
||||
handler := srv.Handler()
|
||||
homeowner := seedUser(t, mem, uniq("homeowner"), "hunter22", store.RoleUser)
|
||||
admin := seedUser(t, mem, uniq("admin"), "hunter22", store.RoleAdmin)
|
||||
homeownerCookies := loginUser(t, handler, homeowner.Username, "hunter22")
|
||||
adminCookies := loginUser(t, handler, admin.Username, "hunter22")
|
||||
homeownerCSRF := csrfForCookies(t, handler, homeownerCookies)
|
||||
adminCSRF := csrfForCookies(t, handler, adminCookies)
|
||||
|
||||
submit := postForm(handler, "/submit", url.Values{
|
||||
"_csrf": {homeownerCSRF},
|
||||
"title": {"Leaky sink"},
|
||||
"body": {"Water under the cabinet."},
|
||||
"city": {"Oakland"},
|
||||
}, homeownerCookies)
|
||||
if submit.Code != http.StatusSeeOther {
|
||||
t.Fatalf("submit status = %d: %s", submit.Code, submit.Body.String())
|
||||
}
|
||||
|
||||
create := postForm(handler, "/posts", url.Values{
|
||||
"_csrf": {homeownerCSRF},
|
||||
"title": {"Second question"},
|
||||
"body": {"Another leak."},
|
||||
"city": {"Berkeley"},
|
||||
}, homeownerCookies)
|
||||
if create.Code != http.StatusSeeOther {
|
||||
t.Fatalf("create status = %d: %s", create.Code, create.Body.String())
|
||||
}
|
||||
|
||||
roots, err := mem.ListRootPosts(context.Background(), pacific.Today(), homeowner.ID)
|
||||
if err != nil || len(roots) != 2 {
|
||||
t.Fatalf("roots = %+v, %v", roots, err)
|
||||
}
|
||||
var submitRoot, createRoot store.Post
|
||||
for _, root := range roots {
|
||||
switch root.Title {
|
||||
case "Leaky sink":
|
||||
submitRoot = root
|
||||
case "Second question":
|
||||
createRoot = root
|
||||
}
|
||||
}
|
||||
if submitRoot.ID == "" || createRoot.ID == "" {
|
||||
t.Fatalf("missing created roots: %+v", roots)
|
||||
}
|
||||
|
||||
reply := postForm(handler, "/posts", url.Values{
|
||||
"_csrf": {adminCSRF},
|
||||
"parent_id": {createRoot.ID},
|
||||
"body": {"Replace the cartridge."},
|
||||
}, adminCookies)
|
||||
if reply.Code != http.StatusSeeOther {
|
||||
t.Fatalf("reply status = %d: %s", reply.Code, reply.Body.String())
|
||||
}
|
||||
thread, err := mem.GetPostThread(context.Background(), createRoot.ID)
|
||||
if err != nil || len(thread.Replies) != 1 {
|
||||
t.Fatalf("thread = %+v, %v", thread, err)
|
||||
}
|
||||
adminReply := thread.Replies[0]
|
||||
|
||||
edit := postForm(handler, "/posts/"+createRoot.ID+"/edit", url.Values{
|
||||
"_csrf": {homeownerCSRF},
|
||||
"body": {"Updated leak description."},
|
||||
}, homeownerCookies)
|
||||
if edit.Code != http.StatusSeeOther {
|
||||
t.Fatalf("edit status = %d: %s", edit.Code, edit.Body.String())
|
||||
}
|
||||
|
||||
empty := postForm(handler, "/posts", url.Values{
|
||||
"_csrf": {homeownerCSRF},
|
||||
"title": {"Missing body"},
|
||||
}, homeownerCookies)
|
||||
if empty.Code != http.StatusBadRequest {
|
||||
t.Fatalf("empty body status = %d, want 400", empty.Code)
|
||||
}
|
||||
|
||||
hidden := &store.Post{
|
||||
AuthorID: homeowner.ID,
|
||||
Title: "Hidden thread",
|
||||
Body: "Not public.",
|
||||
PostDate: pacific.Today(),
|
||||
PostState: store.PostStateHidden,
|
||||
}
|
||||
if err := mem.CreatePost(context.Background(), hidden); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hiddenReply := postForm(handler, "/posts", url.Values{
|
||||
"_csrf": {homeownerCSRF},
|
||||
"parent_id": {hidden.ID},
|
||||
"body": {"Should not publish."},
|
||||
}, homeownerCookies)
|
||||
if hiddenReply.Code != http.StatusNotFound {
|
||||
t.Fatalf("hidden reply status = %d, want 404", hiddenReply.Code)
|
||||
}
|
||||
hiddenEdit := postForm(handler, "/posts/"+hidden.ID+"/edit", url.Values{
|
||||
"_csrf": {homeownerCSRF},
|
||||
"body": {"Still hidden."},
|
||||
}, homeownerCookies)
|
||||
if hiddenEdit.Code != http.StatusSeeOther {
|
||||
t.Fatalf("hidden edit status = %d: %s", hiddenEdit.Code, hiddenEdit.Body.String())
|
||||
}
|
||||
|
||||
got := rec.Snapshot()
|
||||
if len(got) != 4 {
|
||||
t.Fatalf("published %d events, want 4: %#v", len(got), got)
|
||||
}
|
||||
|
||||
submitEv, ok := got[0].(events.PostCreated)
|
||||
if !ok {
|
||||
t.Fatalf("first event %T, want PostCreated", got[0])
|
||||
}
|
||||
assertPostEvent(t, submitEv.PostEvent, events.PostEvent{
|
||||
PostID: submitRoot.ID,
|
||||
RootID: submitRoot.ID,
|
||||
Title: "Leaky sink",
|
||||
Body: "Water under the cabinet.",
|
||||
City: "Oakland",
|
||||
AuthorID: homeowner.ID,
|
||||
AuthorName: homeowner.Name,
|
||||
AuthorRole: string(store.RoleUser),
|
||||
Permalink: "https://www.askaplumberfirst.com/questions/" + submitRoot.ID + "#post-" + submitRoot.ID,
|
||||
})
|
||||
|
||||
createEv, ok := got[1].(events.PostCreated)
|
||||
if !ok {
|
||||
t.Fatalf("second event %T, want PostCreated", got[1])
|
||||
}
|
||||
assertPostEvent(t, createEv.PostEvent, events.PostEvent{
|
||||
PostID: createRoot.ID,
|
||||
RootID: createRoot.ID,
|
||||
Title: "Second question",
|
||||
Body: "Another leak.",
|
||||
City: "Berkeley",
|
||||
AuthorID: homeowner.ID,
|
||||
AuthorName: homeowner.Name,
|
||||
AuthorRole: string(store.RoleUser),
|
||||
Permalink: "https://www.askaplumberfirst.com/questions/" + createRoot.ID + "#post-" + createRoot.ID,
|
||||
})
|
||||
|
||||
replyEv, ok := got[2].(events.PostCreated)
|
||||
if !ok {
|
||||
t.Fatalf("third event %T, want PostCreated", got[2])
|
||||
}
|
||||
assertPostEvent(t, replyEv.PostEvent, events.PostEvent{
|
||||
PostID: adminReply.ID,
|
||||
RootID: createRoot.ID,
|
||||
ParentID: createRoot.ID,
|
||||
Body: "Replace the cartridge.",
|
||||
AuthorID: admin.ID,
|
||||
AuthorName: admin.Name,
|
||||
AuthorRole: string(store.RoleAdmin),
|
||||
Permalink: "https://www.askaplumberfirst.com/questions/" + createRoot.ID + "#post-" + adminReply.ID,
|
||||
})
|
||||
|
||||
editEv, ok := got[3].(events.PostUpdated)
|
||||
if !ok {
|
||||
t.Fatalf("fourth event %T, want PostUpdated", got[3])
|
||||
}
|
||||
assertPostEvent(t, editEv.PostEvent, events.PostEvent{
|
||||
PostID: createRoot.ID,
|
||||
RootID: createRoot.ID,
|
||||
Title: "Second question",
|
||||
Body: "Updated leak description.",
|
||||
City: "Berkeley",
|
||||
AuthorID: homeowner.ID,
|
||||
AuthorName: homeowner.Name,
|
||||
AuthorRole: string(store.RoleUser),
|
||||
Permalink: "https://www.askaplumberfirst.com/questions/" + createRoot.ID + "#post-" + createRoot.ID,
|
||||
})
|
||||
|
||||
for i, ev := range got {
|
||||
raw, err := json.Marshal(ev)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if strings.Contains(strings.ToLower(string(raw)), "discord") {
|
||||
t.Fatalf("event %d contains discord fields: %s", i, raw)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStoreCreateDoesNotPublish(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rec := &events.Recording{}
|
||||
_, mem := newTestServer(t, Config{Events: rec})
|
||||
homeowner := seedUser(t, mem, uniq("homeowner"), "hunter22", store.RoleUser)
|
||||
if err := mem.CreatePost(context.Background(), &store.Post{
|
||||
AuthorID: homeowner.ID,
|
||||
Title: "Direct write",
|
||||
Body: "No handler.",
|
||||
PostDate: pacific.Today(),
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if rec.Len() != 0 {
|
||||
t.Fatalf("store.CreatePost published %d events", rec.Len())
|
||||
}
|
||||
}
|
||||
|
||||
func assertPostEvent(t *testing.T, got, want events.PostEvent) {
|
||||
t.Helper()
|
||||
if got.PostID != want.PostID ||
|
||||
got.RootID != want.RootID ||
|
||||
got.ParentID != want.ParentID ||
|
||||
got.Title != want.Title ||
|
||||
got.Body != want.Body ||
|
||||
got.City != want.City ||
|
||||
got.AuthorID != want.AuthorID ||
|
||||
got.AuthorName != want.AuthorName ||
|
||||
got.AuthorRole != want.AuthorRole ||
|
||||
got.Permalink != want.Permalink ||
|
||||
len(got.Images) != 0 {
|
||||
t.Fatalf("event = %+v, want %+v", got, want)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user