mirror of
https://github.com/pgsty/minio.git
synced 2026-08-09 15:53:28 +03:00
test(s3select): stop racing minio-go's parser for the response body
SelectResults spawns a parser goroutine that drains and closes the response body when the stream ends; deferring res.Close() had the test drain and close the same bytes.Reader concurrently, which the race detector catches reliably. Give the test body a close signal and wait for the parser to finish instead of competing with it. The double-close lives in minio-go's client parser, which no server code path uses; it remains worth an upstream report. Co-authored-by: ChatGPT <noreply@openai.com> Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/klauspost/cpuid/v2"
|
"github.com/klauspost/cpuid/v2"
|
||||||
@@ -70,6 +71,17 @@ func (w *testResponseWriter) WriteHeader(statusCode int) {
|
|||||||
func (w *testResponseWriter) Flush() {
|
func (w *testResponseWriter) Flush() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type testResponseBody struct {
|
||||||
|
io.Reader
|
||||||
|
closed chan struct{}
|
||||||
|
closeOnce sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *testResponseBody) Close() error {
|
||||||
|
b.closeOnce.Do(func() { close(b.closed) })
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func evaluateSelectForTest(t *testing.T, requestXML, input []byte) ([]byte, error) {
|
func evaluateSelectForTest(t *testing.T, requestXML, input []byte) ([]byte, error) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
@@ -85,18 +97,24 @@ func evaluateSelectForTest(t *testing.T, requestXML, input []byte) ([]byte, erro
|
|||||||
s3Select.Evaluate(w)
|
s3Select.Evaluate(w)
|
||||||
s3Select.Close()
|
s3Select.Close()
|
||||||
|
|
||||||
|
body := &testResponseBody{
|
||||||
|
Reader: bytes.NewReader(w.response),
|
||||||
|
closed: make(chan struct{}),
|
||||||
|
}
|
||||||
resp := http.Response{
|
resp := http.Response{
|
||||||
StatusCode: http.StatusOK,
|
StatusCode: http.StatusOK,
|
||||||
Body: io.NopCloser(bytes.NewReader(w.response)),
|
Body: body,
|
||||||
ContentLength: int64(len(w.response)),
|
ContentLength: int64(len(w.response)),
|
||||||
}
|
}
|
||||||
res, err := minio.NewSelectResults(&resp, "testbucket")
|
res, err := minio.NewSelectResults(&resp, "testbucket")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer res.Close()
|
result, readErr := io.ReadAll(res)
|
||||||
|
// minio-go's parser closes the response after signaling EOF or an event
|
||||||
return io.ReadAll(res)
|
// error. Wait for that owner instead of racing it with SelectResults.Close.
|
||||||
|
<-body.closed
|
||||||
|
return result, readErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestJSONLinesRejectsOversizedRecord(t *testing.T) {
|
func TestJSONLinesRejectsOversizedRecord(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user