Browse Source

getting to 20% test coverage

pull/8/head
Stephen Searles 2 years ago
parent
commit
f49229d723
5 changed files with 189 additions and 94 deletions
  1. 7
    1
      caddyhugo.go
  2. 89
    75
      client.go
  3. 9
    7
      content.go
  4. 83
    10
      doc_test.go
  5. 1
    1
      http.go

+ 7
- 1
caddyhugo.go View File

@@ -6,6 +6,7 @@ import (
"net/http"
_ "net/http/pprof"
"os/exec"
"path/filepath"
"strings"
"sync"

@@ -61,10 +62,15 @@ func (ch CaddyHugo) BasePath() string {
return "/hugo"
}

func (ch *CaddyHugo) docname(orig string) string {
func docname(orig string) string {
orig = strings.Replace(orig, " ", "-", -1)
return strings.ToLower(orig)
}

func (ch *CaddyHugo) docFilename(orig string) string {
return filepath.Join(ch.Dir, "content", docname(orig))
}

func (ch *CaddyHugo) Publish() error {
cmd := exec.Command("hugo")
cmd.Dir = ch.Dir

+ 89
- 75
client.go View File

@@ -8,8 +8,6 @@ import (
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"time"

"git.stephensearles.com/stephen/acedoc"
@@ -22,93 +20,109 @@ type docref struct {
tmpdir string
}

func (ch *CaddyHugo) doc(r *http.Request) (*docref, error) {
ch.mtx.Lock()
defer ch.mtx.Unlock()

name := r.URL.Path[len("/hugo/edit/"):]
name = filepath.Join(ch.Dir, name)
name = strings.ToLower(name)
func (ch *CaddyHugo) newClient(docName string) (*docref, error) {
filename := ch.docFilename(docName)

_, ok := ch.docs[ch.docname(name)]
if !ok {
fmt.Println("opening", name)
contents, err := ioutil.ReadFile(name)
if err != nil {
return nil, err
}
fmt.Println("opening", filename)
contents, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}

draftPrefix := fmt.Sprintf("draft-%s", base64.RawURLEncoding.EncodeToString([]byte(name)))
tmpdir := path.Join(os.TempDir(), draftPrefix)
draftPrefix := fmt.Sprintf("draft-%s", base64.RawURLEncoding.EncodeToString([]byte(docName)))
tmpdir := path.Join(os.TempDir(), draftPrefix)

ref := &docref{
name: name,
doc: acedoc.NewString(string(contents)),
tmpdir: tmpdir,
}
ref := &docref{
name: docName,
doc: acedoc.NewString(string(contents)),
tmpdir: tmpdir,
}

err = ref.doc.LogToFile(path.Join(ch.Dir, "logs", r.URL.Path[len("/hugo/edit/"):]))
if err != nil {
fmt.Println(err)
return nil, err
}
err = ref.doc.LogToFile(path.Join(ch.Dir, "logs", docName))
if err != nil {
fmt.Println(err)
return nil, err
}

ch.docs[ch.docname(name)] = ref
ch.docs[filename] = ref

hugoCmd := exec.Command("hugo", "--watch", "-D", "-d", ref.tmpdir)
hugoCmd.Dir = ch.Dir
err = hugoCmd.Start()
if err != nil {
return nil, fmt.Errorf("error starting hugo: %v", err)
}
hugoCmd := exec.Command("hugo", "--watch", "-D", "-d", ref.tmpdir)
hugoCmd.Dir = ch.Dir
err = hugoCmd.Start()
if err != nil {
return nil, fmt.Errorf("error starting hugo: %v", err)
}

go func() {
ticker := time.NewTicker(WebsocketFileTicker)
idleTicks := 0
go func() {
ticker := time.NewTicker(WebsocketFileTicker)
idleTicks := 0

defer func() {
err := hugoCmd.Process.Signal(os.Interrupt)
if err != nil {
fmt.Println("error signaling to hugo:", err)
}
err = hugoCmd.Wait()
if err != nil {
fmt.Println("error waiting for hugo:", err)
}
}()
defer func() {
err := hugoCmd.Process.Signal(os.Interrupt)
if err != nil {
fmt.Println("error signaling to hugo:", err)
}
err = hugoCmd.Wait()
if err != nil {
fmt.Println("error waiting for hugo:", err)
}
}()

for {
<-ticker.C
ch.mtx.Lock()
for {
<-ticker.C
ch.mtx.Lock()

err := ioutil.WriteFile(name, []byte(ref.doc.Contents()), 0644)
if err != nil {
fmt.Println("error saving document contents:", err)
}
err := ioutil.WriteFile(filename, []byte(ref.doc.Contents()), 0644)
if err != nil {
fmt.Println("error saving document contents:", err)
}

if ref.clients == 0 {
idleTicks++
idleTime := time.Duration(idleTicks) * WebsocketFileTicker
if idleTime >= IdleWebsocketTimeout {
err := ch.Publish()
fmt.Printf("idle for %v, quitting\n", idleTime)
if err != nil {
fmt.Printf(", error publishing: %v\n", err)
}

ref.doc.Close()
os.RemoveAll(tmpdir)
delete(ch.docs, ch.docname(name))
ch.mtx.Unlock()
return
if ref.clients == 0 {
idleTicks++
idleTime := time.Duration(idleTicks) * WebsocketFileTicker
if idleTime >= IdleWebsocketTimeout {
err := ch.Publish()
fmt.Printf("idle for %v, quitting\n", idleTime)
if err != nil {
fmt.Printf(", error publishing: %v\n", err)
}
} 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)
}

+ 9
- 7
content.go View File

@@ -7,7 +7,6 @@ import (
"path"
"path/filepath"
"sort"
"strings"
"time"

"github.com/gohugoio/hugo/hugolib"
@@ -25,10 +24,8 @@ type Metadata struct {
Date, Lastmod time.Time
}

func ListContent() ([]Content, error) {
return nil, nil
}

// GetContent fetches the list of available content from the site directory. If
// possible, the return value will be enriched with metadata from Hugo.
func GetContent(siteRoot string, sites *hugolib.HugoSites) ([]Content, error) {
var files = []Content{}

@@ -83,6 +80,10 @@ func GetContent(siteRoot string, sites *hugolib.HugoSites) ([]Content, error) {
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) {
if filepath.Ext(name) != ".md" {
name += ".md"
@@ -92,9 +93,10 @@ func (ch CaddyHugo) NewContent(name, ctype string) (string, error) {
ctype = "default"
}

filename := path.Join(ctype, strings.ToLower(name))
name = docname(name)
filename := path.Join(ctype, name)
if ctype == "default" {
filename = strings.ToLower(name)
filename = name
}

_, err := os.Stat(path.Join(ch.Dir, "content", filename))

+ 83
- 10
doc_test.go View File

@@ -4,7 +4,12 @@ import (
"io/ioutil"
"os"
"os/exec"
"path"
"sync"
"testing"
"time"

"git.stephensearles.com/stephen/acedoc"
)

type World struct {
@@ -38,10 +43,53 @@ func NewWorld(t *testing.T) World {
return w
}

func TestDoc(t *testing.T) {
func TestEdits(t *testing.T) {
w := NewWorld(t)
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)
if err != nil {
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))
}

w.CH.NewContent("test1", "")
c, err = GetContent(w.BlogFolder, w.CH.HugoSites)
if err != nil {
t.Fatalf("couldn't get content from the test environment: %v", err)
titles := []string{
"test1",
"TEST 2!!",
}
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)
if err != nil {
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)
}
}

+ 1
- 1
http.go View File

@@ -179,7 +179,7 @@ func (ch *CaddyHugo) serveDraft(w http.ResponseWriter, r *http.Request) (int, er
ch.mtx.Lock()
defer ch.mtx.Unlock()

docref, ok := ch.docs[ch.docname(name)]
docref, ok := ch.docs[docname(name)]
if !ok {
return http.StatusNotFound, fmt.Errorf("draft not found")
}

Loading…
Cancel
Save