From 4e154cc17b74386dc26c139e123bf46e30ec3049 Mon Sep 17 00:00:00 2001 From: starainrt Date: Thu, 21 Aug 2025 21:37:21 +0800 Subject: [PATCH] update benchmark --- curl.go | 21 ++--- curl_test.go | 2 +- curlbench_test.go | 198 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 211 insertions(+), 10 deletions(-) create mode 100644 curlbench_test.go diff --git a/curl.go b/curl.go index 5b21038..199729f 100644 --- a/curl.go +++ b/curl.go @@ -277,7 +277,7 @@ type RequestOpts struct { contentLength int64 // 人工设置 } -func (r *RequestOpts) ContentLength() int64 { +func (r *Request) ContentLength() int64 { return r.contentLength } @@ -286,24 +286,27 @@ func (r *RequestOpts) ContentLength() int64 { // if the length is less than 0, it will not set the Content-Length header. chunked transfer encoding will be used instead. // chunked transfer encoding may cause some servers to reject the request if they do not support it. // Note that this function will not work if doRawRequest is true -func (r *RequestOpts) SetContentLength(contextLength int64) { +func (r *Request) SetContentLength(contextLength int64) *Request { r.contentLength = contextLength + return r } -func (r *RequestOpts) CustomTransport() bool { +func (r *Request) CustomTransport() bool { return r.customTransport } -func (r *RequestOpts) SetCustomTransport(customTransport bool) { +func (r *Request) SetCustomTransport(customTransport bool) *Request { r.customTransport = customTransport + return r } -func (r *RequestOpts) FileUploadRecallFn() func(filename string, upPos int64, total int64) { +func (r *Request) FileUploadRecallFn() func(filename string, upPos int64, total int64) { return r.fileUploadRecallFn } -func (r *RequestOpts) SetFileUploadRecallFn(FileUploadRecallFn func(filename string, upPos int64, total int64)) { +func (r *Request) SetFileUploadRecallFn(FileUploadRecallFn func(filename string, upPos int64, total int64)) *Request { r.fileUploadRecallFn = FileUploadRecallFn + return r } func (r *Request) DialFn() func(ctx context.Context, network, addr string) (net.Conn, error) { @@ -338,13 +341,13 @@ func (r *Request) SetAutoCalcContentLengthNoError(autoCalcContentLength bool) *R } // BasicAuth returns the username and password provided in the request's Authorization header. -func (r *RequestOpts) BasicAuth() (string, string) { +func (r *Request) BasicAuth() (string, string) { return r.basicAuth[0], r.basicAuth[1] } // SetBasicAuth sets the request's Authorization header to use HTTP Basic Authentication with the provided username and password. // Note: If doRawRequest is true, this function will nolonger work -func (r *RequestOpts) SetBasicAuth(username, password string) *RequestOpts { +func (r *Request) SetBasicAuth(username, password string) *Request { r.basicAuth = [2]string{username, password} return r } @@ -687,7 +690,7 @@ func (r *Request) SetDoRawRequest(doRawRequest bool) *Request { } // SkipTLSVerify returns whether the request will skip TLS verification. -func (r *RequestOpts) SkipTLSVerify() bool { +func (r *Request) SkipTLSVerify() bool { return r.skipTLSVerify } diff --git a/curl_test.go b/curl_test.go index 9c4d4d2..e8a853c 100644 --- a/curl_test.go +++ b/curl_test.go @@ -90,7 +90,7 @@ func TestGetRequest(t *testing.T) { })) defer server.Close() - resp, err := Get(server.URL) + resp, err := Get(server.URL, WithSkipTLSVerify(true), WithHeader("hello", "world"), WithUserAgent("hello world")) if err != nil { t.Errorf("Unexpected error: %v", err) } diff --git a/curlbench_test.go b/curlbench_test.go new file mode 100644 index 0000000..3894989 --- /dev/null +++ b/curlbench_test.go @@ -0,0 +1,198 @@ +package starnet + +import ( + "fmt" + "net/http" + "net/http/httptest" + "runtime" + "testing" +) + +// BenchmarkGetRequest 测试单个 GET 请求的性能 +func BenchmarkGetRequest(b *testing.B) { + // 创建测试服务器 + server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + rw.Write([]byte(`OK`)) + })) + defer server.Close() + + // 重置计时器,排除设置代码的影响 + b.ResetTimer() + + // 报告内存分配情况 + b.ReportAllocs() + + // 运行基准测试 + for i := 0; i < b.N; i++ { + resp, err := Get(server.URL, WithSkipTLSVerify(true)) + if err != nil { + b.Errorf("Unexpected error: %v", err) + } + + body := resp.Body().String() + if body != "OK" { + b.Errorf("Expected OK, got %v", body) + } + } +} + +// BenchmarkGetRequestWithHeaders 测试带请求头的 GET 请求性能 +func BenchmarkGetRequestWithHeaders(b *testing.B) { + server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + // 验证请求头 + if req.Header.Get("hello") != "world" { + rw.WriteHeader(http.StatusBadRequest) + return + } + rw.Write([]byte(`OK`)) + })) + defer server.Close() + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + resp, err := Get(server.URL, + WithSkipTLSVerify(true), + WithHeader("hello", "world"), + WithUserAgent("hello world")) + if err != nil { + b.Errorf("Unexpected error: %v", err) + } + + body := resp.Body().String() + if body != "OK" { + b.Errorf("Expected OK, got %v", body) + } + } +} + +// BenchmarkPostRequest 测试 POST 请求的性能 +func BenchmarkPostRequest(b *testing.B) { + server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + // 读取并返回请求体 + body := make([]byte, req.ContentLength) + req.Body.Read(body) + rw.Write(body) + })) + defer server.Close() + + testData := "This is a test payload for POST request" + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + resp, err := Post(server.URL, + WithSkipTLSVerify(true), + WithBytes([]byte(testData)), + WithContentType("text/plain")) + if err != nil { + b.Errorf("Unexpected error: %v", err) + } + + body := resp.Body().String() + if body != testData { + b.Errorf("Expected %s, got %v", testData, body) + } + } +} + +// BenchmarkConcurrentRequests 测试并发请求性能 +func BenchmarkConcurrentRequests(b *testing.B) { + server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + rw.Write([]byte(`OK`)) + })) + defer server.Close() + + b.ResetTimer() + b.ReportAllocs() + + // 运行并发基准测试 + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + resp, err := Get(server.URL, WithSkipTLSVerify(true)) + if err != nil { + b.Errorf("Unexpected error: %v", err) + } + + body := resp.Body().String() + if body != "OK" { + b.Errorf("Expected OK, got %v", body) + } + } + }) +} + +// BenchmarkMemoryUsage 专门测试内存使用情况 +func BenchmarkMemoryUsage(b *testing.B) { + server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + rw.Write([]byte(`OK`)) + })) + defer server.Close() + + // 禁用默认的测试时间,只关注内存分配 + b.ReportAllocs() + + var memStatsStart, memStatsEnd runtime.MemStats + runtime.GC() + runtime.ReadMemStats(&memStatsStart) + + for i := 0; i < b.N; i++ { + resp, err := Get(server.URL, WithSkipTLSVerify(true)) + if err != nil { + b.Errorf("Unexpected error: %v", err) + } + + body := resp.Body().String() + if body != "OK" { + b.Errorf("Expected OK, got %v", body) + } + } + + runtime.GC() + runtime.ReadMemStats(&memStatsEnd) + + // 计算每次操作的平均内存分配 + allocsPerOp := float64(memStatsEnd.Mallocs-memStatsStart.Mallocs) / float64(b.N) + bytesPerOp := float64(memStatsEnd.TotalAlloc-memStatsStart.TotalAlloc) / float64(b.N) + + b.ReportMetric(allocsPerOp, "allocs/op") + b.ReportMetric(bytesPerOp, "bytes/op") +} + +// BenchmarkDifferentResponseSizes 测试不同响应大小的性能 +func BenchmarkDifferentResponseSizes(b *testing.B) { + // 测试不同大小的响应 + responseSizes := []int{100, 1024, 10240, 102400} // 100B, 1KB, 10KB, 100KB + + for _, size := range responseSizes { + // 生成指定大小的响应数据 + responseData := make([]byte, size) + for i := 0; i < size; i++ { + responseData[i] = 'A' + } + + b.Run(fmt.Sprintf("Size_%d", size), func(b *testing.B) { + server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + rw.Write(responseData) + })) + defer server.Close() + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + resp, err := Get(server.URL, WithSkipTLSVerify(true)) + if err != nil { + b.Errorf("Unexpected error: %v", err) + } + + body := resp.Body().Bytes() + if len(body) != size { + b.Errorf("Expected size %d, got %d", size, len(body)) + } + } + }) + } +}