Improve test coverage, fix various error handling bugs (#40)

- [x] Bring test coverage back up to around 90%.
- [x] Fix various bugs in error handling
- [x] Remove panic behaviour when templates can't be found

Closes #39

Co-authored-by: Nicolas Herry <beastieboy@beastieboy.net>
Reviewed-on: #40
master 0.1.1
beastieboy 1 year ago
parent ee8290bf49
commit ba3e2eaa6f
  1. 16
      gopher/dynamic.go
  2. 98
      gopher/dynamic_test.go
  3. 8
      gopher/errorcodes.go
  4. 26
      gopher/files_test.go
  5. 64
      gopher/transformers_test.go
  6. 1
      testdata/attic/broken.gt
  7. 1
      testdata/attic/hello.gt
  8. 0
      testdata/errors-empty/.keep

@ -20,23 +20,23 @@ type DynamicContext struct {
}
func RunTemplate(dc *DynamicContext, p string) ([]string, error) {
var err error
// read the template found in the FullPath
t := template.Must(template.ParseFiles(p))
if t != nil {
var buf bytes.Buffer
if err := t.Execute(io.Writer(&buf), dc); err == nil {
return []string{buf.String()}, err
if t, err := template.ParseFiles(p); err != nil {
return []string{}, err
} else {
var buf bytes.Buffer
if err = t.Execute(io.Writer(&buf), dc); err != nil {
log.Error().
Err(err).
Str("Template Path", p).
Msg("Could not generate dynamic content via template")
return []string{}, err
} else {
return []string{buf.String()}, err
}
}
return []string{}, err
}

@ -0,0 +1,98 @@
package gopher
import (
"testing"
"os"
"time"
"bytes"
"text/template"
"github.com/google/go-cmp/cmp"
)
func TestRunTemplate(t *testing.T) {
d, _ := os.Getwd()
c := Context { Root: d + "/../testdata" }
p := "/attic/hello.gt"
rq, _ := NewRequest(c, p)
rs := NewResponse(c, *rq)
dc := DynamicContext {
ServerContext: c,
RequestInfo: *rq,
ResponseInfo: *rs,
ErrorInfo: GopherErrorInfo{},
CurrentTime: time.Now(),
}
lines, _ := os.ReadFile(rq.FullPath)
tmpl, err := template.New("test").Parse(string(lines))
var b bytes.Buffer
err = tmpl.Execute(&b, dc)
expected := []string{b.String()}
got, err := RunTemplate(&dc, rq.FullPath);
if err != nil {
t.Errorf("Received an unexpected error when running a template with path %s; %s", p, err.Error())
}
if ! cmp.Equal(got, expected) {
t.Errorf("Unexpected return value when generating a template: %s", cmp.Diff(expected, got))
}
p = "/attic/broken.gt"
rq, _ = NewRequest(c, p)
rs = NewResponse(c, *rq)
dc = DynamicContext {
ServerContext: c,
RequestInfo: *rq,
ResponseInfo: *rs,
ErrorInfo: GopherErrorInfo{},
CurrentTime: time.Now(),
}
expected = []string{}
got, err = RunTemplate(&dc, rq.FullPath);
if err == nil {
t.Errorf("Failed to received an error when running a broken template with path %s", p)
}
if ! cmp.Equal(got, expected) {
t.Errorf("Unexpected return value when generating a broken template: %s", cmp.Diff(expected, got))
}
p = "/attic/non-existent.gt"
rq, _ = NewRequest(c, p)
rs = NewResponse(c, *rq)
dc = DynamicContext {
ServerContext: c,
RequestInfo: *rq,
ResponseInfo: *rs,
ErrorInfo: GopherErrorInfo{},
CurrentTime: time.Now(),
}
expected = []string{}
got, err = RunTemplate(&dc, rq.FullPath);
if err == nil {
t.Errorf("Failed to received an error when running a non-existent template with path %s", p)
}
if ! cmp.Equal(got, expected) {
t.Errorf("Unexpected return value when generating a non-existent template: %s", cmp.Diff(expected, got))
}
}

@ -1,9 +1,5 @@
package gopher
import (
"fmt"
)
type GopherErrorCode string
const GopherErrorNoError GopherErrorCode = "00"
@ -11,10 +7,6 @@ const GopherErrorSelectorNotFound GopherErrorCode = "10"
const GopherErrorWrongPermissions GopherErrorCode = "20"
const GopherErrorDataRetrieval GopherErrorCode = "30"
func (e GopherErrorCode) String() string {
return fmt.Sprint(string(e))
}
type GopherErrorInfo struct {
Selector string
}

@ -5,6 +5,8 @@ import (
"os"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
)
func TestFileType(t *testing.T) {
@ -115,3 +117,27 @@ func TestGopherMapFixLine(t *testing.T) {
}
}
func TestGopherMapFixLines(t *testing.T) {
d, _ := os.Getwd()
c := Context { Host: "myhost", Port: 7777, Root: d + "/../testdata" }
l1 := "An info line with no tab\r\n"
expected1 := "i" + strings.TrimRight(l1, "\r\n") + "\tfake.host\t1\r\n"
l2 := "An info line\twith\ttabs\r\n"
expected2 := l2
l3 := "0A menu line with no server and no port\tfile.txt\r\n"
expected3 := strings.TrimRight(l3, "\r\n") + "\t" + c.Host + "\t" + fmt.Sprintf("%d", c.Port) + "\r\n"
l4 := "0A menu line with a server and a port\tfile.txt\tsomeserver.com\t70\r\n"
expected4 := l4
got := GopherMapFixLines(c, []string{ l1, l2, l3, l4})
expected := []string { expected1, expected2, expected3, expected4 }
if ! cmp.Equal(expected, got) {
t.Errorf("Unexpected info lines from GopherMapFixLines: %s", cmp.Diff(expected, got))
}
}

@ -4,6 +4,7 @@ import (
"testing"
"os"
"path/filepath"
"fmt"
"github.com/google/go-cmp/cmp"
)
@ -239,7 +240,7 @@ func TestSelectorRewriteTransformer(t *testing.T) {
func TestExecutableTransformer(t *testing.T) {
d, _ := os.Getwd()
c := Context { Root: d + "/../testdata", Footers: map[string][]string{"default": {"powered", "by", "marmotte"}} }
c := Context { Root: d + "/../testdata", Footers: map[string][]string{"default": {"powered", "by", "marmotte"}}, ErrorRoot: d + "/../testdata/errors" }
p:= "/createtextfile.sh"
rq, _ := NewRequest(c, p)
_, newRq, rs, err := ExecutableTransformer(&c, *rq, &Response{}, nil)
@ -254,4 +255,65 @@ func TestExecutableTransformer(t *testing.T) {
if int(got) != expected {
t.Errorf("Unexpected Response type for a file created by an executable: %s, expected: %d, got: %d", newRq.FullPath, expected, got)
}
p = "/bin/ls"
rq, _ = NewRequest(c, p)
// overwrite rq.FullPath with an absolute path
rq.FullPath = "/bin/ls"
_, newRq, rs, err = ExecutableTransformer(&c, *rq, &Response{}, nil)
// This should redirect to an error handling function, which should not fail
if err != nil {
t.Errorf("Unexpected error received when running an ExecutableTransformer for %s: %s", p, err.Error())
}
// The selector should become not found
expectedCode := GopherErrorSelectorNotFound
gotCode := rs.ErrorCode
if gotCode != expectedCode {
t.Errorf("Failed to receive the expected error code in the response when running an ExecutableTransformer for %s, expected %s, got %s", p, expectedCode, gotCode)
}
}
func TestErrorRedirectTransformer(t *testing.T) {
d, _ := os.Getwd()
c := Context { Root: d + "/../testdata", Footers: map[string][]string{"default": {"powered", "by", "marmotte"}}, ErrorRoot: d + "/../testdata/errors-empty" }
p:= "/non-existent"
rq, _ := NewRequest(c, p)
// error in rendering pipeline, e.g. in data retrieval
rs := &Response{ErrorCode: GopherErrorDataRetrieval, ContentText: []string{"Some text retrieved but..."}}
_, _, rs, err := ErrorRedirectTransformer(&c, *rq, rs, nil)
if err == nil {
t.Errorf("Failed to receive an error when running an ErrorRedirectTransformer with a missing error template for %s: %s", p, err.Error())
}
expected := []string {fmt.Sprint("Error retrieving the error page for the request. The original error code was ", rs.ErrorCode, " for the selector ", rq.Path)}
if ! cmp.Equal(expected, rs.ContentText) {
t.Errorf("Received unexpected ContentText is Reponse after an ErrorRedirectTransformer with a missing error template for %s: %s", p, cmp.Diff(expected, rs.ContentText))
}
}
func TestDynamicRenderingTransformer(t *testing.T) {
d, _ := os.Getwd()
c := Context { Root: d + "/../testdata", Footers: map[string][]string{"default": {"powered", "by", "marmotte"}}, ErrorRoot: d + "/../testdata/errors" }
p:= "/attic/hello.gt"
rq, _ := NewRequest(c, p)
rs := NewResponse(c, *rq)
_, _, rs, err := DynamicRenderingTransformer(&c, *rq, rs, nil)
if err != nil {
t.Errorf("Unexpected error received when running a DynamicRenderingTransformer for a valid template %s: %s", p, err.Error())
}
if len(rs.ContentText) == 0 {
t.Errorf("Unexpected empty ContentText in Response when running a DynamicRenderingTransformer for a valid template %s", p)
}
}

@ -0,0 +1 @@
This template is broken and should generate an error. {{ .NonExistentField }}

@ -14,4 +14,3 @@ Current Configuration:
- Path: {{- .RequestInfo.Path }}
- Additional parameters
- Current time: {{- .CurrentTime }}
Loading…
Cancel
Save