@ -1,10 +1,6 @@
package caddyhugo
package caddyhugo
import (
import (
"encoding/json"
"io/ioutil"
"os"
"os/exec"
"path"
"path"
"sync"
"sync"
"testing"
"testing"
@ -13,136 +9,70 @@ import (
"git.stephensearles.com/stephen/acedoc"
"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 ) {
func TestEdits ( t * testing . T ) {
w := NewWorld ( t )
w := NewWorld ( t )
defer w . Clean ( )
defer w . Clean ( )
const title = "sometitle"
const title = "sometitle"
var contentPath = path . Join ( "content" , title + ".md" )
w . CH . NewContent ( title , "" )
var (
mtx sync . Mutex
send := [ ] acedoc . Delta {
contentPath = path . Join ( "content" , title + ".md" )
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 )
// we will send these to the doc
send = [ ] acedoc . Delta {
acedoc . Insert ( 0 , 0 , "hello" ) ,
acedoc . Insert ( 0 , 5 , " world" ) ,
acedoc . Insert ( 0 , 11 , " world" ) ,
}
// we will use this to track what we get out of the doc
received = [ ] acedoc . Delta { }
)
// prepare a new post
w . CH . NewContent ( title , "" )
// start an edit session
es , err := w . CH . editSession ( contentPath )
if err != nil {
if err != nil {
t . Fatal ( "error creating document client:" , err )
t . Fatal ( "error creating document client:" , err )
}
}
doc . doc . Client ( acedoc . DeltaHandlerFunc ( func ( ds [ ] acedoc . Delta ) error {
// register a client that we will use to push the deltas. we dont need
// receive some deltas...
// to actually do anything to receive deltas here, though.
c := es . doc . Client ( acedoc . DeltaHandlerFunc ( func ( ds [ ] acedoc . Delta ) error {
return nil
} ) )
// register an *extra* client that just adds to the received delta
// slice we're tracking
es . doc . Client ( acedoc . DeltaHandlerFunc ( func ( ds [ ] acedoc . Delta ) error {
mtx . Lock ( )
mtx . Lock ( )
defer mtx . Unlock ( )
defer mtx . Unlock ( )
received = append ( received , ds ... )
received = append ( received , ds ... )
return nil
return nil
} ) )
} ) )
// make sure we have an edit session
_ , ok := w . CH . hasEditSession ( contentPath )
_ , ok := w . CH . hasEditSession ( contentPath )
if ! ok {
if ! ok {
t . Fatal ( "expected there to be an established client" )
t . Fatal ( "expected there to be an established client" )
}
}
doc . doc . Apply ( send ... )
// push the deltas
c . PushDeltas ( send ... )
// wait...
<- time . After ( 5 * time . Second )
<- time . After ( 5 * time . Second )
// be sure we got the correct number of deltas back
mtx . Lock ( )
mtx . Lock ( )
defer mtx . Unlock ( )
defer mtx . Unlock ( )
if len ( received ) != len ( send ) {
if len ( received ) != len ( send ) {
t . Errorf ( "expected %d deltas, received %d; expected: %v, received: %v" , len ( send ) , len ( received ) , send , received )
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 ) {
func TestDeltasSingle ( t * testing . T ) {
@ -158,12 +88,12 @@ func TestDeltasSingle(t *testing.T) {
client := new ( WebsocketTester )
client := new ( WebsocketTester )
doc , err := w . CH . editSession ( "content/" + title + ".md" )
es , err := w . CH . editSession ( "content/" + title + ".md" )
if err != nil {
if err != nil {
t . Fatal ( "couldn't establish docref for client 0:" , err )
t . Fatal ( "couldn't establish docref for client 0:" , err )
}
}
go w . CH . handleDeltaConn ( client , doc )
go w . CH . handleDeltaConn ( client , es )
a := acedoc . Insert ( 0 , 0 , "a" )
a := acedoc . Insert ( 0 , 0 , "a" )
@ -174,9 +104,11 @@ func TestDeltasSingle(t *testing.T) {
time . Sleep ( 50 * time . Millisecond )
time . Sleep ( 50 * time . Millisecond )
// we shouldn't have written back to the client,
// we shouldn't have written back to the client,
// so we expect to have written 0 messages
// so we expect to have written 0 *deltas*. (we may have written
if len ( client . wroteMessages ) != 0 {
// empty messages without deltas because of the pings to the client)
t . Errorf ( "client wrote %d messages, should have written %d" , len ( client . wroteMessages ) , 0 )
if len ( client . wroteDeltas ) != 0 {
t . Errorf ( "client wrote %d deltas, should have written %d" , len ( client . wroteMessages ) , 0 )
t . Logf ( "%v" , client . wroteMessages )
}
}
// we received one, so make sure that's counted properly
// we received one, so make sure that's counted properly
@ -217,7 +149,7 @@ func TestDeltasDouble(t *testing.T) {
// so we expect clientA to have written 0 messages, and
// so we expect clientA to have written 0 messages, and
// clientB to have written 1
// clientB to have written 1
if len ( clientA . wroteMessage s ) != 0 || len ( clientB . wroteMessage s ) != 1 {
if len ( clientA . wroteDelta s ) != 0 || len ( clientB . wroteDelta s ) != 1 {
t . Errorf ( "clientA wrote %d messages, should have written 0. clientB wrote %d, should have written 1" , len ( clientA . wroteMessages ) , len ( clientB . wroteMessages ) )
t . Errorf ( "clientA wrote %d messages, should have written 0. clientB wrote %d, should have written 1" , len ( clientA . wroteMessages ) , len ( clientB . wroteMessages ) )
}
}
@ -238,9 +170,9 @@ func TestDeltasDouble(t *testing.T) {
clientA . mtx . Lock ( )
clientA . mtx . Lock ( )
clientB . mtx . Lock ( )
clientB . mtx . Lock ( )
// so we expect clientA to have written 1 message this time, and
// so we expect clientA to have written 1 delta this time, and
// clientB to have written nothing new, so 1 still
// clientB to have written nothing new, so 1 still
if len ( clientA . wroteMessage s ) != 1 || len ( clientB . wroteMessage s ) != 1 {
if len ( clientA . wroteDelta s ) != 1 || len ( clientB . wroteDelta s ) != 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 ) )
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 ) )
}
}
@ -268,13 +200,15 @@ func TestDeltasMulti(t *testing.T) {
doc , err := w . CH . editSession ( "content/" + title + ".md" )
doc , err := w . CH . editSession ( "content/" + title + ".md" )
if err != nil {
if err != nil {
t . Fatal ( "couldn't establish docref :" , err )
t . Fatal ( "couldn't establish edit session :" , err )
}
}
go w . CH . handleDeltaConn ( clients [ 0 ] , doc )
go w . CH . handleDeltaConn ( clients [ 0 ] , doc )
go w . CH . handleDeltaConn ( clients [ 1 ] , doc )
go w . CH . handleDeltaConn ( clients [ 1 ] , doc )
go w . CH . handleDeltaConn ( clients [ 2 ] , doc )
go w . CH . handleDeltaConn ( clients [ 2 ] , doc )
time . Sleep ( 100 * time . Millisecond )
a := acedoc . Insert ( 0 , 0 , "a" )
a := acedoc . Insert ( 0 , 0 , "a" )
b := acedoc . Insert ( 0 , 0 , "b" )
b := acedoc . Insert ( 0 , 0 , "b" )
c := acedoc . Insert ( 0 , 0 , "c" )
c := acedoc . Insert ( 0 , 0 , "c" )
@ -283,12 +217,12 @@ func TestDeltasMulti(t *testing.T) {
clients [ 1 ] . ReceiveJSON ( w . CH . Message ( b ) )
clients [ 1 ] . ReceiveJSON ( w . CH . Message ( b ) )
clients [ 2 ] . ReceiveJSON ( w . CH . Message ( c ) )
clients [ 2 ] . ReceiveJSON ( w . CH . Message ( c ) )
time . Sleep ( 4 00 * time . Millisecond )
time . Sleep ( 10 00 * time . Millisecond )
for i , client := range clients {
for i , client := range clients {
client . mtx . Lock ( )
client . mtx . Lock ( )
// all clients should have "written" 2 deltas (could be the same
// all clients should have "written" 2 deltas out to their "browser"
// message) that came from the other clients
// that came from the other clients
if len ( client . wroteDeltas ) != 2 {
if len ( client . wroteDeltas ) != 2 {
t . Errorf ( "client %d wrote %d deltas, should have written 2" , i , len ( client . wroteDeltas ) )
t . Errorf ( "client %d wrote %d deltas, should have written 2" , i , len ( client . wroteDeltas ) )
}
}