getting to 20% test coverage
This commit is contained in:
+7
-1
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
func (ch *CaddyHugo) newClient(docName string) (*docref, error) {
|
||||
filename := ch.docFilename(docName)
|
||||
|
||||
fmt.Println("opening", filename)
|
||||
contents, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
draftPrefix := fmt.Sprintf("draft-%s", base64.RawURLEncoding.EncodeToString([]byte(docName)))
|
||||
tmpdir := path.Join(os.TempDir(), draftPrefix)
|
||||
|
||||
ref := &docref{
|
||||
name: docName,
|
||||
doc: acedoc.NewString(string(contents)),
|
||||
tmpdir: tmpdir,
|
||||
}
|
||||
|
||||
err = ref.doc.LogToFile(path.Join(ch.Dir, "logs", docName))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
<-ticker.C
|
||||
ch.mtx.Lock()
|
||||
|
||||
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, filename)
|
||||
ch.mtx.Unlock()
|
||||
return
|
||||
}
|
||||
} 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()
|
||||
|
||||
name := r.URL.Path[len("/hugo/edit/"):]
|
||||
name = filepath.Join(ch.Dir, name)
|
||||
name = strings.ToLower(name)
|
||||
var err error
|
||||
|
||||
_, ok := ch.docs[ch.docname(name)]
|
||||
dr, ok := ch.hasdocref(docName)
|
||||
if !ok {
|
||||
fmt.Println("opening", name)
|
||||
contents, err := ioutil.ReadFile(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
draftPrefix := fmt.Sprintf("draft-%s", base64.RawURLEncoding.EncodeToString([]byte(name)))
|
||||
tmpdir := path.Join(os.TempDir(), draftPrefix)
|
||||
|
||||
ref := &docref{
|
||||
name: name,
|
||||
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
|
||||
}
|
||||
|
||||
ch.docs[ch.docname(name)] = 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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}()
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
} else {
|
||||
idleTicks = 0
|
||||
}
|
||||
ch.mtx.Unlock()
|
||||
}
|
||||
}()
|
||||
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
@@ -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))
|
||||
|
||||
+84
-11
@@ -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)
|
||||
}
|
||||
if len(c) != 1 {
|
||||
t.Fatalf("expected 1 page, but saw %d pages", len(c))
|
||||
titles := []string{
|
||||
"test1",
|
||||
"TEST 2!!",
|
||||
}
|
||||
|
||||
w.CH.NewContent("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)
|
||||
}
|
||||
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()
|
||||
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")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user