getting to 20% test coverage

pull/8/head
Stephen Searles 7 years ago
parent 968c50e3e2
commit f49229d723
  1. 8
      caddyhugo.go
  2. 164
      client.go
  3. 16
      content.go
  4. 93
      doc_test.go
  5. 2
      http.go

@ -6,6 +6,7 @@ import (
"net/http" "net/http"
_ "net/http/pprof" _ "net/http/pprof"
"os/exec" "os/exec"
"path/filepath"
"strings" "strings"
"sync" "sync"
@ -61,10 +62,15 @@ func (ch CaddyHugo) BasePath() string {
return "/hugo" return "/hugo"
} }
func (ch *CaddyHugo) docname(orig string) string { func docname(orig string) string {
orig = strings.Replace(orig, " ", "-", -1)
return strings.ToLower(orig) return strings.ToLower(orig)
} }
func (ch *CaddyHugo) docFilename(orig string) string {
return filepath.Join(ch.Dir, "content", docname(orig))
}
func (ch *CaddyHugo) Publish() error { func (ch *CaddyHugo) Publish() error {
cmd := exec.Command("hugo") cmd := exec.Command("hugo")
cmd.Dir = ch.Dir cmd.Dir = ch.Dir

@ -8,8 +8,6 @@ import (
"os" "os"
"os/exec" "os/exec"
"path" "path"
"path/filepath"
"strings"
"time" "time"
"git.stephensearles.com/stephen/acedoc" "git.stephensearles.com/stephen/acedoc"
@ -22,93 +20,109 @@ type docref struct {
tmpdir string tmpdir string
} }
func (ch *CaddyHugo) doc(r *http.Request) (*docref, error) { func (ch *CaddyHugo) newClient(docName string) (*docref, error) {
ch.mtx.Lock() filename := ch.docFilename(docName)
defer ch.mtx.Unlock()
name := r.URL.Path[len("/hugo/edit/"):]
name = filepath.Join(ch.Dir, name)
name = strings.ToLower(name)
_, ok := ch.docs[ch.docname(name)] fmt.Println("opening", filename)
if !ok { contents, err := ioutil.ReadFile(filename)
fmt.Println("opening", name) if err != nil {
contents, err := ioutil.ReadFile(name) return nil, err
if err != nil { }
return nil, err
}
draftPrefix := fmt.Sprintf("draft-%s", base64.RawURLEncoding.EncodeToString([]byte(name))) draftPrefix := fmt.Sprintf("draft-%s", base64.RawURLEncoding.EncodeToString([]byte(docName)))
tmpdir := path.Join(os.TempDir(), draftPrefix) tmpdir := path.Join(os.TempDir(), draftPrefix)
ref := &docref{ ref := &docref{
name: name, name: docName,
doc: acedoc.NewString(string(contents)), doc: acedoc.NewString(string(contents)),
tmpdir: tmpdir, tmpdir: tmpdir,
} }
err = ref.doc.LogToFile(path.Join(ch.Dir, "logs", r.URL.Path[len("/hugo/edit/"):])) err = ref.doc.LogToFile(path.Join(ch.Dir, "logs", docName))
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return nil, err return nil, err
} }
ch.docs[ch.docname(name)] = ref ch.docs[filename] = ref
hugoCmd := exec.Command("hugo", "--watch", "-D", "-d", ref.tmpdir) hugoCmd := exec.Command("hugo", "--watch", "-D", "-d", ref.tmpdir)
hugoCmd.Dir = ch.Dir hugoCmd.Dir = ch.Dir
err = hugoCmd.Start() err = hugoCmd.Start()
if err != nil { if err != nil {
return nil, fmt.Errorf("error starting hugo: %v", err) return nil, fmt.Errorf("error starting hugo: %v", err)
} }
go func() { go func() {
ticker := time.NewTicker(WebsocketFileTicker) ticker := time.NewTicker(WebsocketFileTicker)
idleTicks := 0 idleTicks := 0
defer func() { defer func() {
err := hugoCmd.Process.Signal(os.Interrupt) err := hugoCmd.Process.Signal(os.Interrupt)
if err != nil { if err != nil {
fmt.Println("error signaling to hugo:", err) fmt.Println("error signaling to hugo:", err)
} }
err = hugoCmd.Wait() err = hugoCmd.Wait()
if err != nil { if err != nil {
fmt.Println("error waiting for hugo:", err) fmt.Println("error waiting for hugo:", err)
} }
}() }()
for { for {
<-ticker.C <-ticker.C
ch.mtx.Lock() ch.mtx.Lock()
err := ioutil.WriteFile(name, []byte(ref.doc.Contents()), 0644) err := ioutil.WriteFile(filename, []byte(ref.doc.Contents()), 0644)
if err != nil { if err != nil {
fmt.Println("error saving document contents:", err) fmt.Println("error saving document contents:", err)
} }
if ref.clients == 0 { if ref.clients == 0 {
idleTicks++ idleTicks++
idleTime := time.Duration(idleTicks) * WebsocketFileTicker idleTime := time.Duration(idleTicks) * WebsocketFileTicker
if idleTime >= IdleWebsocketTimeout { if idleTime >= IdleWebsocketTimeout {
err := ch.Publish() err := ch.Publish()
fmt.Printf("idle for %v, quitting\n", idleTime) fmt.Printf("idle for %v, quitting\n", idleTime)
if err != nil { if err != nil {
fmt.Printf(", error publishing: %v\n", err) fmt.Printf(", error publishing: %v\n", err)
}
ref.doc.Close()
os.RemoveAll(tmpdir)
delete(ch.docs, ch.docname(name))
ch.mtx.Unlock()
return
} }
} else {
idleTicks = 0 ref.doc.Close()
os.RemoveAll(tmpdir)
delete(ch.docs, filename)
ch.mtx.Unlock()
return
} }
ch.mtx.Unlock() } else {
idleTicks = 0
} }
}() ch.mtx.Unlock()
}
}()
return ref, nil
}
func (ch *CaddyHugo) hasdocref(docName string) (*docref, bool) {
dr, ok := ch.docs[ch.docFilename(docName)]
return dr, ok
}
func (ch *CaddyHugo) client(docName string) (*docref, error) {
ch.mtx.Lock()
defer ch.mtx.Unlock()
var err error
dr, ok := ch.hasdocref(docName)
if !ok {
dr, err = ch.newClient(docName)
} }
return ch.docs[ch.docname(name)], nil return dr, err
}
func (ch *CaddyHugo) doc(r *http.Request) (*docref, error) {
name := r.URL.Path[len("/hugo/edit/"):]
return ch.client(name)
} }

@ -7,7 +7,6 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"sort" "sort"
"strings"
"time" "time"
"github.com/gohugoio/hugo/hugolib" "github.com/gohugoio/hugo/hugolib"
@ -25,10 +24,8 @@ type Metadata struct {
Date, Lastmod time.Time Date, Lastmod time.Time
} }
func ListContent() ([]Content, error) { // GetContent fetches the list of available content from the site directory. If
return nil, nil // possible, the return value will be enriched with metadata from Hugo.
}
func GetContent(siteRoot string, sites *hugolib.HugoSites) ([]Content, error) { func GetContent(siteRoot string, sites *hugolib.HugoSites) ([]Content, error) {
var files = []Content{} var files = []Content{}
@ -83,6 +80,10 @@ func GetContent(siteRoot string, sites *hugolib.HugoSites) ([]Content, error) {
return files, nil return files, nil
} }
// NewContent initializes new content with the name (title) and content type.
// If ctype is empty string, "default" is used. The return value is the filename,
// which may be modified from the title and includes the content type if other than
// default, but does not include the full directory relative to the site.
func (ch CaddyHugo) NewContent(name, ctype string) (string, error) { func (ch CaddyHugo) NewContent(name, ctype string) (string, error) {
if filepath.Ext(name) != ".md" { if filepath.Ext(name) != ".md" {
name += ".md" name += ".md"
@ -92,9 +93,10 @@ func (ch CaddyHugo) NewContent(name, ctype string) (string, error) {
ctype = "default" ctype = "default"
} }
filename := path.Join(ctype, strings.ToLower(name)) name = docname(name)
filename := path.Join(ctype, name)
if ctype == "default" { if ctype == "default" {
filename = strings.ToLower(name) filename = name
} }
_, err := os.Stat(path.Join(ch.Dir, "content", filename)) _, err := os.Stat(path.Join(ch.Dir, "content", filename))

@ -4,7 +4,12 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
"path"
"sync"
"testing" "testing"
"time"
"git.stephensearles.com/stephen/acedoc"
) )
type World struct { type World struct {
@ -38,10 +43,53 @@ func NewWorld(t *testing.T) World {
return w return w
} }
func TestDoc(t *testing.T) { func TestEdits(t *testing.T) {
w := NewWorld(t) w := NewWorld(t)
defer w.Clean() defer w.Clean()
const title = "sometitle"
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.client(title + ".md")
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.hasdocref(title + ".md")
if !ok {
t.Fatal("expected there to be an established client")
}
doc.doc.Apply(send...)
<-time.After(5 * time.Second)
if len(received) != len(send) {
t.Errorf("expected %d deltas, received %d; expected: %v, received: %v", len(send), len(received), send, received)
}
}
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) c, err := GetContent(w.BlogFolder, w.CH.HugoSites)
if err != nil { if err != nil {
t.Fatalf("couldn't get content from a blank test environment: %v", err) t.Fatalf("couldn't get content from a blank test environment: %v", err)
@ -50,21 +98,46 @@ func TestDoc(t *testing.T) {
t.Fatalf("expected a blank test environment, but saw %d pages", len(c)) t.Fatalf("expected a blank test environment, but saw %d pages", len(c))
} }
w.CH.NewContent("test1", "") titles := []string{
c, err = GetContent(w.BlogFolder, w.CH.HugoSites) "test1",
if err != nil { "TEST 2!!",
t.Fatalf("couldn't get content from the test environment: %v", err)
} }
if len(c) != 1 {
t.Fatalf("expected 1 page, but saw %d pages", len(c)) 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))
}
} }
w.CH.NewContent("TEST 2!!", "") // make sure we get the content out that we just created
c, err = GetContent(w.BlogFolder, w.CH.HugoSites) c, err = GetContent(w.BlogFolder, w.CH.HugoSites)
if err != nil { if err != nil {
t.Fatalf("couldn't get content from the test environment: %v", err) t.Fatalf("couldn't get content from the test environment: %v", err)
} }
if len(c) != 2 {
t.Fatalf("expected 2 pages, but saw %d pages", len(c)) for _, content := range c {
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)
} }
} }

@ -179,7 +179,7 @@ func (ch *CaddyHugo) serveDraft(w http.ResponseWriter, r *http.Request) (int, er
ch.mtx.Lock() ch.mtx.Lock()
defer ch.mtx.Unlock() defer ch.mtx.Unlock()
docref, ok := ch.docs[ch.docname(name)] docref, ok := ch.docs[docname(name)]
if !ok { if !ok {
return http.StatusNotFound, fmt.Errorf("draft not found") return http.StatusNotFound, fmt.Errorf("draft not found")
} }

Loading…
Cancel
Save