gotestinggo-html-template

Unit test for html/template golang facing invalid memory address error


So I have a simple application that is supposed to render an Html page on GET requests /login/. The requests work fine when I run the web server locally, but when I run unit tests there seems to be an error.(go test -v is being used to run the tests.)

--- FAIL: TestLoginRequest (0.00s)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
        panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x76ddf0]

goroutine 8 [running]:
testing.tRunner.func1.2({0x841660, 0xbeb720})
        /usr/local/go/src/testing/testing.go:1396 +0x24e
testing.tRunner.func1()
        /usr/local/go/src/testing/testing.go:1399 +0x39f
panic({0x841660, 0xbeb720})
        /usr/local/go/src/runtime/panic.go:884 +0x212
html/template.(*Template).lookupAndEscapeTemplate(0x0, {0xc000036640, 0x4c})
        /usr/local/go/src/html/template/template.go:146 +0x50
html/template.(*Template).ExecuteTemplate(0x8ab914?, {0x7faf3da99c78, 0xc0001c4340}, {0xc000036640?, 0x0?}, {0x8148c0, 0xc0001beee0})
        /usr/local/go/src/html/template/template.go:135 +0x38
github.com/vedicsociety/brucheion.renderLoginTemplate({0x9691b8?, 0xc0001c4340}, {0x8ab914?, 0xbff840?}, 0xc0001a0600?)
        /home/abdurrehman/Documents/work/martin-gluckman/Brucheion/templates.go:52 +0x85
github.com/vedicsociety/brucheion.loginGET({0x9691b8, 0xc0001c4340}, 0xc0001b8900?)
        /home/abdurrehman/Documents/work/martin-gluckman/Brucheion/login.go:72 +0x325
net/http.HandlerFunc.ServeHTTP(0xc0001a0500?, {0x9691b8?, 0xc0001c4340?}, 0x203000?)
        /usr/local/go/src/net/http/server.go:2109 +0x2f
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0001c80c0, {0x9691b8, 0xc0001c4340}, 0xc0001a0400)
        /home/abdurrehman/go/pkg/mod/github.com/gorilla/mux@v1.7.4/mux.go:210 +0x1cf
github.com/vedicsociety/brucheion.executeRequest(0x8aa772?)
        /home/abdurrehman/Documents/work/martin-gluckman/Brucheion/api_test.go:41 +0xaf
github.com/vedicsociety/brucheion.TestLoginRequest(0x0?)
        /home/abdurrehman/Documents/work/martin-gluckman/Brucheion/api_test.go:32 +0x7f
testing.tRunner(0xc0000d7860, 0x8ea660)
        /usr/local/go/src/testing/testing.go:1446 +0x10b
created by testing.(*T).Run
        /usr/local/go/src/testing/testing.go:1493 +0x35f
exit status 2
FAIL    github.com/vedicsociety/brucheion       0.005s

unit test

func TestLoginRequest(t *testing.T) {
    setupRouter()

    req, _ := http.NewRequest("GET", "/login/", nil)
    response := executeRequest(req)

    assert.Equal(t, 200, response.Code)
}

// Helper functions.

func executeRequest(req *http.Request) *httptest.ResponseRecorder {
    requestRecorder := httptest.NewRecorder()
    router.ServeHTTP(requestRecorder, req)

    return requestRecorder
}

func setupRouter() {
    router = mux.NewRouter().StrictSlash(true)
    router.HandleFunc("/login/", loginGET).Methods("GET")
    router.NotFoundHandler = http.HandlerFunc(NotFoundRedirect)
}

The issue seems to be here

func renderLoginTemplate(res http.ResponseWriter, tmpl string, loginPage *LoginPage) {
    fmt.Println(generateFilePath(tmpl))
    err := templates.ExecuteTemplate(res, generateFilePath(tmpl), loginPage)
    if err != nil {
        http.Error(res, err.Error(), http.StatusInternalServerError)
    }
}


func generateFilePath(tName string) string {
    s, err := os.Getwd()
    if err != nil {
        panic(err)
    }
    return filepath.Join(s, "/tmpl/", tName+".html")
}

The templates.ExecuteTemplate function is being problematic. I came across these two StackOverflow questions (link1, link2) where the developer seems to have encountered the same issue and thus created the function generateFilePath to get an absolute path haven't had any luck.


Solution

  • http.NewRequest returns an instance of *http.Request that is intended for clients to send outgoing requests. loginGET is a handler that expects an instance of *http.Request intended for servers, for an incoming request. Do NOT use the output of http.NewRequest as a direct argument to ServeHTTP.

    For handler tests, instead of http.NewRequest, use httptest.NewRequest: "NewRequest returns a new incoming server Request, suitable for passing to an http.Handler for testing."