[#644] Support keepalive during listing

Send whitespaces every time as new object in list is ready
to prevent client from context cancelling.

Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
Denis Kirillov 2025-02-19 17:27:51 +03:00
parent 776fd042ef
commit 07b60b15b3
13 changed files with 309 additions and 17 deletions

View file

@ -1,7 +1,9 @@
package handler
import (
"bytes"
"context"
"encoding/xml"
"fmt"
"net/http"
"net/http/httptest"
@ -841,6 +843,101 @@ func TestListingsWithInvalidEncodingType(t *testing.T) {
listObjectsV1Err(hc, bktName, "invalid", apierr.GetAPIError(apierr.ErrInvalidEncodingMethod))
}
func TestPeriodicWriter(t *testing.T) {
const dur = 100 * time.Millisecond
const whitespaces = 8
expected := []byte(xml.Header)
for i := 0; i < whitespaces; i++ {
expected = append(expected, []byte(" ")...)
}
t.Run("writes data", func(t *testing.T) {
ch := make(chan struct{})
go func() {
defer close(ch)
for range whitespaces {
ch <- struct{}{}
time.Sleep(dur)
}
}()
buf := bytes.NewBuffer(nil)
stop := periodicXMLWriter(buf, time.Nanosecond, ch)
// N number of whitespaces + half durations to guarantee at least N writes in buffer
time.Sleep(whitespaces*dur + dur/2)
require.True(t, stop())
require.Equal(t, string(expected), buf.String())
t.Run("no additional data after stop", func(t *testing.T) {
time.Sleep(2 * dur)
require.Equal(t, string(expected), buf.String())
})
})
t.Run("does not write data", func(t *testing.T) {
buf := bytes.NewBuffer(nil)
ch := make(chan struct{})
go func() {
defer close(ch)
for range whitespaces {
time.Sleep(2 * dur)
ch <- struct{}{}
}
}()
stop := periodicXMLWriter(buf, time.Nanosecond, ch)
require.False(t, stop())
require.Empty(t, buf.Bytes())
})
t.Run("throttling works", func(t *testing.T) {
buf := bytes.NewBuffer(nil)
ch := make(chan struct{})
go func() {
defer close(ch)
for range whitespaces {
ch <- struct{}{}
time.Sleep(dur / 2)
}
}()
stop := periodicXMLWriter(buf, dur, ch)
// N number of whitespaces + half durations to guarantee at least N writes in buffer
time.Sleep(whitespaces*dur + dur/2)
require.True(t, stop())
require.Equal(t, string(expected[:len(expected)-4]), buf.String())
})
t.Run("disabled", func(t *testing.T) {
buf := bytes.NewBuffer(nil)
ch := make(chan struct{})
go func() {
defer close(ch)
for range whitespaces {
select {
case ch <- struct{}{}:
default:
}
time.Sleep(dur / 2)
}
}()
stop := periodicXMLWriter(buf, 0, ch)
// N number of whitespaces + half durations to guarantee at least N writes in buffer
time.Sleep(whitespaces*dur + dur/2)
require.False(t, stop())
require.Empty(t, buf.String())
})
}
func checkVersionsNames(t *testing.T, versions *ListObjectsVersionsResponse, names []string) {
for i, v := range versions.Version {
require.Equal(t, names[i], v.Key)