Merge pull request #211 from Dvorinka/feat/extract-bomb-guard
Bound cumulative output and entry count on archive extractionpull/3589/head
commit
89a9b7f269
@ -0,0 +1,92 @@
|
||||
package workflows
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
iofs "io/fs"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/queue"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func testProgress(count, size int64) queue.Progresses {
|
||||
return queue.Progresses{
|
||||
ProgressTypeExtractCount: &queue.Progress{Current: count},
|
||||
ProgressTypeExtractSize: &queue.Progress{Current: size},
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckExtractGuards(t *testing.T) {
|
||||
// Under all limits.
|
||||
require.NoError(t, checkExtractGuards(testProgress(10, 100), 1000))
|
||||
|
||||
// At the cumulative size limit — aborts as non-retryable.
|
||||
err := checkExtractGuards(testProgress(10, 1000), 1000)
|
||||
require.Error(t, err)
|
||||
require.True(t, errors.Is(err, queue.CriticalErr))
|
||||
|
||||
// At the entry cap — aborts as non-retryable.
|
||||
err = checkExtractGuards(testProgress(maxExtractEntries, 10), 1000)
|
||||
require.Error(t, err)
|
||||
require.True(t, errors.Is(err, queue.CriticalErr))
|
||||
|
||||
// Zero size limit disables the size bound; entry cap still applies.
|
||||
require.NoError(t, checkExtractGuards(testProgress(10, 1<<62), 0))
|
||||
require.Error(t, checkExtractGuards(testProgress(maxExtractEntries, 0), 0))
|
||||
}
|
||||
|
||||
type stubFile struct {
|
||||
io.Reader
|
||||
}
|
||||
|
||||
func (stubFile) Stat() (iofs.FileInfo, error) { return nil, nil }
|
||||
func (stubFile) Close() error { return nil }
|
||||
|
||||
func TestCappedFileExactBoundary(t *testing.T) {
|
||||
// Entry ends exactly at the budget — stream must terminate with EOF.
|
||||
capped := &cappedFile{File: stubFile{strings.NewReader("12345")}, remaining: 5}
|
||||
buf := make([]byte, 8)
|
||||
|
||||
n, err := capped.Read(buf)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 5, n)
|
||||
require.Equal(t, "12345", string(buf[:n]))
|
||||
|
||||
_, err = capped.Read(buf)
|
||||
require.Equal(t, io.EOF, err)
|
||||
}
|
||||
|
||||
func TestCappedFileBomb(t *testing.T) {
|
||||
// Entry data beyond the budget — read fails with the critical limit error.
|
||||
capped := &cappedFile{File: stubFile{strings.NewReader("123456")}, remaining: 5}
|
||||
buf := make([]byte, 8)
|
||||
|
||||
n, err := capped.Read(buf)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 5, n)
|
||||
|
||||
_, err = capped.Read(buf)
|
||||
require.Error(t, err)
|
||||
require.True(t, errors.Is(err, queue.CriticalErr))
|
||||
}
|
||||
|
||||
func TestCappedFileShortReads(t *testing.T) {
|
||||
// Budget caps each read; consecutive reads drain only the remaining bytes.
|
||||
capped := &cappedFile{File: stubFile{strings.NewReader("abcdef")}, remaining: 3}
|
||||
buf := make([]byte, 2)
|
||||
|
||||
var got []byte
|
||||
var err error
|
||||
for {
|
||||
var n int
|
||||
n, err = capped.Read(buf)
|
||||
got = append(got, buf[:n]...)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
require.Equal(t, "abc", string(got))
|
||||
require.True(t, errors.Is(err, queue.CriticalErr))
|
||||
}
|
||||
Loading…
Reference in new issue