@@ -21,8 +21,13 @@ import (
2121 "fmt"
2222 "reflect"
2323 "testing"
24+ "time"
2425
26+ "github.com/cockroachdb/errors"
27+ "github.com/minio/minio-go/v7"
28+ "github.com/stretchr/testify/assert"
2529 "github.com/stretchr/testify/mock"
30+ "github.com/stretchr/testify/require"
2631
2732 "github.com/milvus-io/milvus-proto/go-api/v2/commonpb"
2833 "github.com/milvus-io/milvus-proto/go-api/v2/schemapb"
@@ -32,7 +37,9 @@ import (
3237 "github.com/milvus-io/milvus/internal/storage"
3338 "github.com/milvus-io/milvus/pkg/v2/common"
3439 "github.com/milvus-io/milvus/pkg/v2/proto/datapb"
40+ "github.com/milvus-io/milvus/pkg/v2/util/merr"
3541 "github.com/milvus-io/milvus/pkg/v2/util/paramtable"
42+ "github.com/milvus-io/milvus/pkg/v2/util/retry"
3643)
3744
3845func TestBulkPackWriter_Write (t * testing.T ) {
@@ -161,3 +168,53 @@ func TestBulkPackWriter_Write(t *testing.T) {
161168 })
162169 }
163170}
171+
172+ func TestBulkPackWriter_WriteLog_NonRetryableError (t * testing.T ) {
173+ paramtable .Get ().Init (paramtable .NewBaseTable ())
174+
175+ mc := metacache .NewMockMetaCache (t )
176+ mc .EXPECT ().Collection ().Return (int64 (1 )).Maybe ()
177+
178+ cm := mocks .NewChunkManager (t )
179+ cm .EXPECT ().RootPath ().Return ("files" ).Maybe ()
180+ // Return a permission-denied error — should NOT be retried
181+ callCount := 0
182+ cm .EXPECT ().Write (mock .Anything , mock .Anything , mock .Anything ).
183+ RunAndReturn (func (ctx context.Context , key string , data []byte ) error {
184+ callCount ++
185+ // Simulate MinIO AccessDenied — maps to ErrIoPermissionDenied via ToMilvusIoError
186+ return minio.ErrorResponse {Code : "AccessDenied" }
187+ })
188+
189+ schema := & schemapb.CollectionSchema {
190+ Fields : []* schemapb.FieldSchema {
191+ {FieldID : common .RowIDField , DataType : schemapb .DataType_Int64 },
192+ {FieldID : common .TimeStampField , DataType : schemapb .DataType_Int64 },
193+ {FieldID : 100 , Name : "pk" , DataType : schemapb .DataType_Int64 , IsPrimaryKey : true },
194+ {
195+ FieldID : 101 , Name : "vec" , DataType : schemapb .DataType_FloatVector ,
196+ TypeParams : []* commonpb.KeyValuePair {{Key : common .DimKey , Value : "4" }},
197+ },
198+ },
199+ }
200+
201+ bw := & BulkPackWriter {
202+ metaCache : mc ,
203+ schema : schema ,
204+ chunkManager : cm ,
205+ allocator : allocator .NewLocalAllocator (10000 , 100000 ),
206+ writeRetryOpts : []retry.Option {retry .AttemptAlways (), retry .MaxSleepTime (10 * time .Second )},
207+ }
208+
209+ // Use a timeout context so the test doesn't hang if retry loop is infinite
210+ ctx , cancel := context .WithTimeout (context .Background (), 3 * time .Second )
211+ defer cancel ()
212+
213+ blob := & storage.Blob {Value : []byte ("data" ), RowNum : 1 }
214+ _ , err := bw .writeLog (ctx , blob , "insert_log" , "1/2/3/100/1" , nil )
215+ require .Error (t , err )
216+ // Must stop after exactly 1 attempt — not retried
217+ assert .Equal (t , 1 , callCount , "non-retryable error should not be retried" )
218+ assert .True (t , merr .IsNonRetryableErr (err ))
219+ assert .True (t , errors .Is (err , merr .ErrIoPermissionDenied ))
220+ }
0 commit comments