Explicitly returning an error to test http.Shutdown function


(BentCoder) #1

Hi,

I tested the “good” test case but wondering how to test “bad” test case. Passing an expired context but no luck.

Thanks

Bad

func TestServer_Stop(t *testing.T) {
	srv := New(":1234")

	ctx, _ := context.WithTimeout(context.Background(), 1 * time.Millisecond)
	time.Sleep(5 * time.Millisecond)

	assert.Equal(t, "bad", srv.Stop(ctx)) // THIS IS RETURNING good
}

CODE

func (s Server) Stop(ctx context.Context) string {
	if e := s.Shutdown(ctx); e != nil {
		return "bad"
	} else {
		return "good"
	}
}

Good This is fine

func TestServer_Stop(t *testing.T) {
	srv := New(":1234")

	assert.Equal(t, "good", srv.Stop(context.Background()))
}

(Christophe Meessen) #2

Apparently the Shutdown succeeds because the server shutdown succeeds.
Looking at the Shutdown code below, we see that it will only check the ctx error if it fails to close all connections.

In order to get an error out of Shutdown you need to have a connection that is not idle. I suggest you try performing a get operation without reading the data. This might leave a connection not idle. In case this is not enough, try increasing the amount of data returned by the server in case the data is buffered on the client side.

Also, you could create a context WithDeadline and a time in the past. This will avoid the need to sleep.

func (srv *Server) Shutdown(ctx context.Context) error {
	atomic.StoreInt32(&srv.inShutdown, 1)

	srv.mu.Lock()
	lnerr := srv.closeListenersLocked()
	srv.closeDoneChanLocked()
	for _, f := range srv.onShutdown {
		go f()
	}
	srv.mu.Unlock()

	ticker := time.NewTicker(shutdownPollInterval)
	defer ticker.Stop()
	for {
		if srv.closeIdleConns() {
			return lnerr
		}
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-ticker.C:
		}
	}
}