0

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.

aDev
  • 43
  • 9

1 Answers1

0

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."

mkopriva
  • 35,176
  • 4
  • 57
  • 71
  • Hey nice catch, I tried the change but unfortunately still experiencing the same error. – aDev Aug 21 '22 at 05:20
  • @aDev update the question by including the complete stack-trace and by including the full `loginGET`. – mkopriva Aug 21 '22 at 05:21
  • @aDev note that `os.Getwd` during tests will always return the test file's package directory. It will not necessarily return the directory from which you are executing the tests. If your code is relying on that, then that's not good. – mkopriva Aug 21 '22 at 05:24
  • I checked by logging out `os.Getwd()` it did provide the path as expected. – aDev Aug 21 '22 at 05:29
  • 1
    @aDev ok, the full stack-trace suggests that in `templates.ExecuteTemplate(...)`, the `templates` variable is `nil`, try printing its value before calling `ExecuteTemplate` to confirm. Whatever initialization code you have for that variable, it did not run, or it did run but failed, perhaps because it was being executed from the test file's wd. – mkopriva Aug 21 '22 at 05:32
  • OH, you're right it's NIL – aDev Aug 21 '22 at 05:34
  • Yup this resolved the issue thanks, but I am not able to pick up where it's mentioned that `templates` is `nil`, could you please let me know how you figured it out with the stack trace? – aDev Aug 21 '22 at 05:40
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/247420/discussion-between-adev-and-mkopriva). – aDev Aug 21 '22 at 05:55