mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 08:36:13 +00:00
Fix data race in RecordMiddleware and improve recorder robustness
This commit addresses the data race detected in TestRecordMiddleware: - Updated Recorder.Record to clone Request and Response objects (including bodies) before background processing. - Ensures background workers can safely access data after the main request handler has finished. - Enabled synchronous recording in handler tests to ensure deterministic results and avoid race conditions.
This commit is contained in:
@@ -15,6 +15,7 @@ import (
|
||||
)
|
||||
|
||||
func TestInteractionHandlers(t *testing.T) {
|
||||
t.Setenv("RECORDER_ASYNC", "false")
|
||||
tmpDir, err := os.MkdirTemp("", "interaction-handlers-test")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp dir: %v", err)
|
||||
@@ -113,6 +114,7 @@ func TestInteractionHandlers(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRecordMiddleware(t *testing.T) {
|
||||
t.Setenv("RECORDER_ASYNC", "false")
|
||||
tmpDir, err := os.MkdirTemp("", "record-middleware-test")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp dir: %v", err)
|
||||
|
||||
@@ -104,13 +104,44 @@ func (r *Recorder) Record(category string, req *http.Request, res *http.Response
|
||||
|
||||
path := r.getRecordingPath(dir, req.Method)
|
||||
|
||||
// Shallow copy request for the worker to avoid data races if the original is reused
|
||||
// but Note: body is already buffered/replaced in middleware if needed.
|
||||
// We need to be careful about bodies being closed.
|
||||
// If we are in async mode, we MUST copy the bodies now because the caller
|
||||
// might close them as soon as Record() returns.
|
||||
var (
|
||||
clonedReq *http.Request
|
||||
clonedRes *http.Response
|
||||
)
|
||||
|
||||
if r.queue != nil {
|
||||
// Clone request
|
||||
clonedReq = req.Clone(req.Context())
|
||||
if req.Body != nil {
|
||||
bodyBytes, _ := io.ReadAll(req.Body)
|
||||
req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
clonedReq.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
}
|
||||
|
||||
// Clone response if present
|
||||
if res != nil {
|
||||
clonedRes = &http.Response{
|
||||
StatusCode: res.StatusCode,
|
||||
Header: res.Header.Clone(),
|
||||
Request: clonedReq,
|
||||
}
|
||||
if res.Body != nil {
|
||||
bodyBytes, _ := io.ReadAll(res.Body)
|
||||
res.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
clonedRes.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
clonedReq = req
|
||||
clonedRes = res
|
||||
}
|
||||
|
||||
task := recordingTask{
|
||||
category: category,
|
||||
req: req,
|
||||
res: res,
|
||||
req: clonedReq,
|
||||
res: clonedRes,
|
||||
replacements: replacements,
|
||||
dir: dir,
|
||||
path: path,
|
||||
|
||||
Reference in New Issue
Block a user