3

I'm testing an http server in golang and everything seems pretty smooth except for one annoying thing.

At some point, when I'm configuring the server, before performing a http.ListenAndServe I register an handler with http.Handle("/", myrouter) , the problem is that on the following test, when the configuration method gets called again, I receive the following panic:

panic: http: multiple registrations for / [recovered]

I'd like to run each test in a clean environment, but haven't found a way to tear down http.DefaultServeMux, is there a convenient way for doing this by either "nulling" something or re-configuring the test environment so every test is executed on a fresh environment ?


Edit: To give some context, as asked, I post here some code and the test I wanted to write, I have to be clear tough on the fact that I'm not even sure on the implementation choices made here (I think I would have configured the server in a slightly different way, but the code's not mine).

package httpserver

import (
    "github.com/gorilla/mux"
    "github.com/private/private/httpserver/rpchandler"
    "net/http"
)

type HTTPServer struct {
    router *mux.Router
    port   int
}

// Config is used to override the default port of the http server.
type Config struct {
    Port *int
}

func NewHTTPServer(config *Config) (*HTTPServer, error) {
    hs := &HTTPServer{
        port: 80,
    }

    // Overwrite default port if passed.
    if config != nil && config.Port != nil {
        hs.port = *config.Port
    }

    err := hs.router = mux.NewRouter().StrictSlash(false)
    if err != nil {
        return nil, err
    }
    // other mux router configs here...

    http.Handle("/", hs.router)

    return hs, nil
}

Now, the tests I wanted to write were quite simple, like:

func TestThatServerIsInitializedWithDefaultPort(t *testing.T) {
    sut, _ := NewHTTPServer(nil)

    if sut.port != 80 {
        t.Fatal("default port not configured")
    }

}

func TestThatServerDefaultPortIsOverriddenWithConfig(t *testing.T) {
    mockPort := 8080

    c := Config{
        Port: &mockPort,
    }

    sut, _ := NewHTTPServer(&c)
    if sut.port != 8080 {
        t.Fatal("the port has not been overridden with the one passed in configuration")
    }

}

However, since I call the handle binding on http twice, I get the panic.

dev_mush
  • 2,136
  • 3
  • 22
  • 38

2 Answers2

5

I think I've found a solution: basically after each test I reinitialize http.DefaultServeMux with http.DefaultServeMux = new(http.ServeMux) I'm still not sure this is a clean way to workaround the problem tough.

I kindly ask you to give me any hints or point me some bad practices used here, since I'm quite new to the language and to backend development in general. I think there might be some code smell in the configuration of the HTTP Server shown above, if you point it out I might make it clear to the rest of my team and work a better solution out.

dev_mush
  • 2,136
  • 3
  • 22
  • 38
  • well, judging by their examples, this is what you should do to opt into `gorilla/mux`you bind it on the root and than configure the `gorilla/mux` instead : https://github.com/gorilla/mux#examples – dev_mush Nov 24 '16 at 16:31
0

I think you should look at using the httptest pkg. It has servers that you can start fresh every test.

matt.s
  • 1,698
  • 1
  • 20
  • 29