在测试期间同步测试服务器

摘要:我在测试过程中遇到了竞争状况,我的服务器在向其发出客户端请求之前尚未可靠地准备好服务请求。如何仅在侦听器准备好之前进行阻止,并且仍然维护可组合的公共 API,而不要求用户 BYO net.Listener

client.Do(req)我们看到以下错误,因为在我们调用测试函数之前,在后台启动(阻塞)服务器的 goroutine 没有监听TestRun

--- FAIL: TestRun/Server_accepts_HTTP_requests (0.00s)
        /home/matt/repos/admission-control/server_test.go:64: failed to make a request: Get https://127.0.0.1:37877: dial tcp 127.0.0.1:37877: connect: connection refused
  • 我没有httptest.Server直接使用,因为我正在尝试测试我自己的服务器组件的阻止和取消特性。

  • 我创建一个,在使用 启动它后将httptest.NewUnstartedServer其克隆*tls.Config到一个新的中,然后在调用 之前将其关闭。这还有一个好处是为我提供了配置了匹配的 RootCA。http.ServerStartTLS()*AdmissionServer.Run()*http.Client

  • 测试 TLS 在这里很重要,因为它公开的守护进程存在于仅 TLS 的环境中。

func newTestServer(ctx context.Context, t *testing.T) *httptest.Server {

    testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

        fmt.Fprintln(w, "OK")

    })


    testSrv := httptest.NewUnstartedServer(testHandler)

    admissionServer, err := NewServer(nil, &noopLogger{})

    if err != nil {

        t.Fatalf("admission server creation failed: %s", err)

        return nil

    }


    // We start the test server, copy its config out, and close it down so we can

    // start our own server. This is because httptest.Server only generates a

    // self-signed TLS config after starting it.

    testSrv.StartTLS()

    admissionServer.srv = &http.Server{

        Addr:      testSrv.Listener.Addr().String(),

        Handler:   testHandler,

        TLSConfig: testSrv.TLS.Clone(),

    }

    testSrv.Close()


    // We need a better synchronization primitive here that doesn't block

    // but allows the underlying listener to be ready before 

    // serving client requests.

    go func() {

        if err := admissionServer.Run(ctx); err != nil {

            t.Fatalf("server returned unexpectedly: %s", err)

        }

    }()


    return testSrv

}


慕无忌1623718
浏览 109回答 1
1回答

青春有我

作为初始化过程的一部分,您可以在启动测试套件之前尝试连接到服务器。例如,我在测试中通常有这样的函数:// waitForServer attempts to establish a TCP connection to localhost:<port>// in a given amount of time. It returns upon a successful connection; // ptherwise exits with an error.func waitForServer(port string) {    backoff := 50 * time.Millisecond    for i := 0; i < 10; i++ {        conn, err := net.DialTimeout("tcp", ":"+port, 1*time.Second)        if err != nil {            time.Sleep(backoff)            continue        }        err = conn.Close()        if err != nil {            log.Fatal(err)        }        return    }    log.Fatalf("Server on port %s not up after 10 attempts", port)}然后在我的TestMain()我做:func TestMain(m *testing.M) {    go startServer()    waitForServer(serverPort)    // run the suite    os.Exit(m.Run())}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go