You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
caddy-hugo2/doc_test.go

362 lines
8.6 KiB

package caddyhugo
import (
"encoding/json"
"io/ioutil"
"os"
"os/exec"
"path"
"sync"
"testing"
"time"
"git.stephensearles.com/stephen/acedoc"
)
type World struct {
CH *CaddyHugo
BlogFolder string
}
func (w *World) Clean() {
if w.BlogFolder != "" {
os.RemoveAll(w.BlogFolder)
}
}
func NewWorld(t *testing.T) *World {
dir, err := ioutil.TempDir("", "caddy-hugo2-test-")
if err != nil {
t.Fatalf("error initializing test environment: %v", err)
}
w := &World{BlogFolder: dir}
cmd := exec.Command("hugo", "new", "site", dir)
cmd.Dir = dir
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("error initializing test site: %v\n\n%v", err, string(out))
}
w.CH = &CaddyHugo{}
w.CH.Setup(dir)
return w
}
func TestEdits(t *testing.T) {
w := NewWorld(t)
defer w.Clean()
const title = "sometitle"
var contentPath = path.Join("content", title+".md")
w.CH.NewContent(title, "")
send := []acedoc.Delta{
acedoc.Insert(0, 0, "hello"),
acedoc.Insert(0, 5, " world"),
acedoc.Insert(0, 11, " world"),
}
var mtx sync.Mutex
received := []acedoc.Delta{}
doc, err := w.CH.editSession(contentPath)
if err != nil {
t.Fatal("error creating document client:", err)
}
doc.doc.Client(acedoc.DeltaHandlerFunc(func(ds []acedoc.Delta) error {
// receive some deltas...
mtx.Lock()
defer mtx.Unlock()
received = append(received, ds...)
return nil
}))
_, ok := w.CH.hasEditSession(contentPath)
if !ok {
t.Fatal("expected there to be an established client")
}
doc.doc.Apply(send...)
<-time.After(5 * time.Second)
mtx.Lock()
defer mtx.Unlock()
if len(received) != len(send) {
t.Errorf("expected %d deltas, received %d; expected: %v, received: %v", len(send), len(received), send, received)
}
}
type WebsocketTester struct {
receivedPointer int
received [][]byte
wroteMessages []Message
wroteDeltas []acedoc.Delta
mtx sync.Mutex
}
func (ws *WebsocketTester) ReadJSON(v interface{}) error {
ws.mtx.Lock()
defer ws.mtx.Unlock()
if len(ws.received) <= ws.receivedPointer {
return nil
}
err := json.Unmarshal(ws.received[ws.receivedPointer], v)
ws.receivedPointer++
return err
}
func (ws *WebsocketTester) WriteJSON(v interface{}) error {
ws.mtx.Lock()
defer ws.mtx.Unlock()
m, ok := v.(Message)
if !ok {
panic("wrong type written to WebsocketTester")
}
if len(m.Deltas) == 0 {
return nil
}
ws.wroteMessages = append(ws.wroteMessages, m)
ws.wroteDeltas = append(ws.wroteDeltas, m.Deltas...)
return nil
}
func (ws *WebsocketTester) ReceiveJSON(v interface{}) error {
ws.mtx.Lock()
defer ws.mtx.Unlock()
out, err := json.Marshal(v)
if err != nil {
return err
}
ws.received = append(ws.received, out)
return nil
}
func TestDeltasSingle(t *testing.T) {
w := NewWorld(t)
defer w.Clean()
const title = "test"
_, err := w.CH.NewContent(title, "")
if err != nil {
t.Fatal("couldn't create new content:", err)
}
client := new(WebsocketTester)
doc, err := w.CH.editSession("content/" + title + ".md")
if err != nil {
t.Fatal("couldn't establish docref for client 0:", err)
}
go w.CH.handleDeltaConn(client, doc)
a := acedoc.Insert(0, 0, "a")
// pretend to get one sent from the "browser"
client.ReceiveJSON(w.CH.Message(a))
// wait to make sure it was processed
time.Sleep(50 * time.Millisecond)
// we shouldn't have written back to the client,
// so we expect to have written 0 messages
if len(client.wroteMessages) != 0 {
t.Errorf("client wrote %d messages, should have written %d", len(client.wroteMessages), 0)
}
// we received one, so make sure that's counted properly
if len(client.received) != 1 {
t.Errorf("client has %d messages, should have received %d", len(client.received), 1)
}
}
func TestDeltasDouble(t *testing.T) {
w := NewWorld(t)
defer w.Clean()
const title = "test"
_, err := w.CH.NewContent(title, "")
if err != nil {
t.Fatal("couldn't create new content:", err)
}
clientA := new(WebsocketTester)
clientB := new(WebsocketTester)
doc, err := w.CH.editSession("content/" + title + ".md")
if err != nil {
t.Fatal("couldn't establish docref for client 0:", err)
}
go w.CH.handleDeltaConn(clientA, doc)
go w.CH.handleDeltaConn(clientB, doc)
// send the first message, simulating the browser on clientA
clientA.ReceiveJSON(w.CH.Message(acedoc.Insert(0, 0, "a")))
time.Sleep(100 * time.Millisecond)
clientA.mtx.Lock()
clientB.mtx.Lock()
// so we expect clientA to have written 0 messages, and
// clientB to have written 1
if len(clientA.wroteMessages) != 0 || len(clientB.wroteMessages) != 1 {
t.Errorf("clientA wrote %d messages, should have written 0. clientB wrote %d, should have written 1", len(clientA.wroteMessages), len(clientB.wroteMessages))
}
// we received one via clientA and zero via clientB, so make sure
// that's counted properly
if len(clientA.received) != 1 || len(clientB.received) != 0 {
t.Errorf("clientA has %d messages, should have received 1; clientB has %d messages, should have received 0", len(clientA.received), len(clientB.received))
}
clientA.mtx.Unlock()
clientB.mtx.Unlock()
// send the second message, via clientB
clientB.ReceiveJSON(w.CH.Message(acedoc.Insert(0, 0, "b")))
time.Sleep(400 * time.Millisecond)
clientA.mtx.Lock()
clientB.mtx.Lock()
// so we expect clientA to have written 1 message this time, and
// clientB to have written nothing new, so 1 still
if len(clientA.wroteMessages) != 1 || len(clientB.wroteMessages) != 1 {
t.Errorf("clientA wrote %d messages, should have written 1. clientB wrote %d, should have written 1 (just from before)", len(clientA.wroteMessages), len(clientB.wroteMessages))
}
// we received zero (new) via clientA and one via clientB, so make sure
// that's counted properly
if len(clientA.received) != 1 || len(clientB.received) != 1 {
t.Errorf("clientA has %d messages, should have received 1; clientB has %d messages, should have received 1", len(clientA.received), len(clientB.received))
}
clientA.mtx.Unlock()
clientB.mtx.Unlock()
}
func TestDeltasMulti(t *testing.T) {
w := NewWorld(t)
defer w.Clean()
const title = "test"
_, err := w.CH.NewContent(title, "")
if err != nil {
t.Fatal("couldn't create new content:", err)
}
clients := []*WebsocketTester{{}, {}, {}}
doc, err := w.CH.editSession("content/" + title + ".md")
if err != nil {
t.Fatal("couldn't establish docref:", err)
}
go w.CH.handleDeltaConn(clients[0], doc)
go w.CH.handleDeltaConn(clients[1], doc)
go w.CH.handleDeltaConn(clients[2], doc)
a := acedoc.Insert(0, 0, "a")
b := acedoc.Insert(0, 0, "b")
c := acedoc.Insert(0, 0, "c")
clients[0].ReceiveJSON(w.CH.Message(a))
clients[1].ReceiveJSON(w.CH.Message(b))
clients[2].ReceiveJSON(w.CH.Message(c))
time.Sleep(400 * time.Millisecond)
for i, client := range clients {
client.mtx.Lock()
// all clients should have "written" 2 deltas (could be the same
// message) that came from the other clients
if len(client.wroteDeltas) != 2 {
t.Errorf("client %d wrote %d deltas, should have written 2", i, len(client.wroteDeltas))
}
// all clients "received" 1 message from the "browser"
if len(client.received) != 1 {
t.Errorf("client %d has %d messages, should have received 1", i, len(client.received))
}
client.mtx.Unlock()
}
}
func TestPagesInPagesOut(t *testing.T) {
w := NewWorld(t)
defer w.Clean()
// check there's no content at first
c, err := GetContent(w.BlogFolder, w.CH.HugoSites)
if err != nil {
t.Fatalf("couldn't get content from a blank test environment: %v", err)
}
if len(c) != 0 {
t.Fatalf("expected a blank test environment, but saw %d pages", len(c))
}
titles := []string{
"test1",
"TEST 2!!",
}
found := map[string]bool{}
// create some known content
for i, title := range titles {
w.CH.NewContent(title, "")
c, err = GetContent(w.BlogFolder, w.CH.HugoSites)
if err != nil {
t.Fatalf("couldn't get content from the test environment: %v", err)
}
if len(c)-1 != i {
t.Fatalf("expected %d page, but saw %d pages", i+1, len(c))
}
}
// make sure we get the content out that we just created
c, err = GetContent(w.BlogFolder, w.CH.HugoSites)
if err != nil {
t.Fatalf("couldn't get content from the test environment: %v", err)
}
for _, content := range c {
if content.Metadata == nil {
t.Errorf("didn't see metadata for %q", content.Filename)
}
found[content.Filename] = true
}
var missingSomething bool
for _, title := range titles {
adjusted := path.Join("content", docname(title)+".md")
if !found[adjusted] {
missingSomething = true
t.Errorf("expected to find title %q, but didn't see it", adjusted)
}
}
if missingSomething {
t.Logf("found titles: %v", found)
}
}