@@ -13,11 +13,13 @@ import (
1313 "time"
1414
1515 "github.com/stretchr/testify/require"
16+ "go.uber.org/zap"
1617
1718 "storj.io/common/memory"
1819 "storj.io/common/testcontext"
1920 "storj.io/common/testrand"
2021 "storj.io/storj/private/testplanet"
22+ "storj.io/storj/satellite"
2123 "storj.io/uplink"
2224 "storj.io/uplink/private/testuplink"
2325)
@@ -360,10 +362,7 @@ func TestUploadEventuallyFailsWithNoNodes(t *testing.T) {
360362 require .NoError (t , planet .StopPeer (planet .StorageNodes [i ]))
361363 }
362364
363- project , err := planet .Uplinks [0 ].OpenProject (
364- testuplink .WithConcurrentSegmentUploadsDefaultConfig (ctx ),
365- planet .Satellites [0 ],
366- )
365+ project , err := planet .Uplinks [0 ].OpenProject (ctx , planet .Satellites [0 ])
367366 require .NoError (t , err )
368367 defer ctx .Check (project .Close )
369368
@@ -449,3 +448,147 @@ func TestConcurrentUploadToSamePath(t *testing.T) {
449448 require .Equal (t , expectedData , downloaded )
450449 })
451450}
451+
452+ func TestUploadLimits (t * testing.T ) {
453+ testplanet .Run (t , testplanet.Config {
454+ SatelliteCount : 1 , StorageNodeCount : 0 , UplinkCount : 2 ,
455+ Reconfigure : testplanet.Reconfigure {
456+ Satellite : func (log * zap.Logger , index int , config * satellite.Config ) {
457+ config .ProjectLimit .CacheCapacity = 0
458+ },
459+ },
460+ }, func (t * testing.T , tpCtx * testcontext.Context , planet * testplanet.Planet ) {
461+ data := testrand .Bytes (6 * memory .KiB )
462+
463+ ctx := testuplink .WithMaxSegmentSize (tpCtx , 5 * memory .KiB )
464+
465+ t .Run ("segment limit" , func (t * testing.T ) {
466+ upl := planet .Uplinks [0 ]
467+ accountingDB := planet .Satellites [0 ].DB .ProjectAccounting ()
468+ err := accountingDB .UpdateProjectSegmentLimit (ctx , upl .Projects [0 ].ID , 0 )
469+ require .NoError (t , err )
470+
471+ project , err := upl .OpenProject (ctx , planet .Satellites [0 ])
472+ require .NoError (t , err )
473+ defer tpCtx .Check (project .Close )
474+
475+ _ , err = project .CreateBucket (ctx , "testbucket" )
476+ require .NoError (t , err )
477+
478+ // should fail on Write beause we uploaded more than segment
479+ // and request to satellite were made. The Write call may not fail
480+ // immmediately, since writes are buffered and the segment uploads
481+ // are handled concurrently.
482+ upload , err := project .UploadObject (ctx , "testbucket" , "test/path/0" , nil )
483+ require .NoError (t , err )
484+ requireWriteEventuallyReturns (t , upload , data , uplink .ErrSegmentsLimitExceeded )
485+ require .ErrorIs (t , upload .Commit (), uplink .ErrSegmentsLimitExceeded )
486+
487+ // should fail on Commit as Write input is too small to create single segment
488+ upload , err = project .UploadObject (ctx , "testbucket" , "test/path/0" , nil )
489+ require .NoError (t , err )
490+ n , err := upload .Write (testrand .Bytes (3 * memory .KiB ))
491+ require .NoError (t , err )
492+ require .NotZero (t , n )
493+ require .ErrorIs (t , upload .Commit (), uplink .ErrSegmentsLimitExceeded )
494+
495+ // should fail on direct call to BeginObject
496+ _ , err = project .BeginUpload (ctx , "testbucket" , "test/path/0" , nil )
497+ require .ErrorIs (t , err , uplink .ErrSegmentsLimitExceeded )
498+
499+ // update limit to be able to call BeginUpload without error
500+ err = accountingDB .UpdateProjectSegmentLimit (ctx , upl .Projects [0 ].ID , 1 )
501+ require .NoError (t , err )
502+
503+ uploadInfo , err := project .BeginUpload (ctx , "testbucket" , "test/path/0" , nil )
504+ require .NoError (t , err )
505+
506+ err = accountingDB .UpdateProjectSegmentLimit (ctx , upl .Projects [0 ].ID , 0 )
507+ require .NoError (t , err )
508+
509+ // should fail on Write beause we uploaded more than segment
510+ // and request to satellite were made. The Write call may not fail
511+ // immmediately, since writes are buffered and the segment uploads
512+ // are handled concurrently.
513+ partUpload , err := project .UploadPart (ctx , "testbucket" , "test/path/0" , uploadInfo .UploadID , 0 )
514+ require .NoError (t , err )
515+ requireWriteEventuallyReturns (t , partUpload , data , uplink .ErrSegmentsLimitExceeded )
516+ require .ErrorIs (t , partUpload .Commit (), uplink .ErrSegmentsLimitExceeded )
517+
518+ // should fail on Commit as Write input is too small to create single segment
519+ partUpload , err = project .UploadPart (ctx , "testbucket" , "test/path/0" , uploadInfo .UploadID , 0 )
520+ require .NoError (t , err )
521+ _ , err = partUpload .Write (testrand .Bytes (3 * memory .KiB ))
522+ require .NoError (t , err )
523+ require .ErrorIs (t , partUpload .Commit (), uplink .ErrSegmentsLimitExceeded )
524+ })
525+ t .Run ("storage limit" , func (t * testing.T ) {
526+ upl := planet .Uplinks [1 ]
527+ accountingDB := planet .Satellites [0 ].DB .ProjectAccounting ()
528+ err := accountingDB .UpdateProjectUsageLimit (ctx , upl .Projects [0 ].ID , 0 )
529+ require .NoError (t , err )
530+
531+ project , err := upl .OpenProject (ctx , planet .Satellites [0 ])
532+ require .NoError (t , err )
533+ defer tpCtx .Check (project .Close )
534+
535+ _ , err = project .CreateBucket (ctx , "testbucket" )
536+ require .NoError (t , err )
537+
538+ // should fail on Write beause we uploaded more than segment
539+ // and request to satellite were made. The Write call may not fail
540+ // immmediately, since writes are buffered and the segment uploads
541+ // are handled concurrently.
542+ upload , err := project .UploadObject (ctx , "testbucket" , "test/path/0" , nil )
543+ require .NoError (t , err )
544+ requireWriteEventuallyReturns (t , upload , data , uplink .ErrStorageLimitExceeded )
545+ require .ErrorIs (t , upload .Commit (), uplink .ErrStorageLimitExceeded )
546+
547+ // should fail on Commit as Write input is too small to create single segment
548+ upload , err = project .UploadObject (ctx , "testbucket" , "test/path/0" , nil )
549+ require .NoError (t , err )
550+ _ , err = upload .Write (testrand .Bytes (3 * memory .KiB ))
551+ require .NoError (t , err )
552+ require .ErrorIs (t , upload .Commit (), uplink .ErrStorageLimitExceeded )
553+
554+ // should fail on direct call to BeginObject
555+ _ , err = project .BeginUpload (ctx , "testbucket" , "test/path/0" , nil )
556+ require .ErrorIs (t , err , uplink .ErrStorageLimitExceeded )
557+
558+ // update limit to be able to call BeginUpload without error
559+ err = accountingDB .UpdateProjectUsageLimit (ctx , upl .Projects [0 ].ID , 1 )
560+ require .NoError (t , err )
561+
562+ uploadInfo , err := project .BeginUpload (ctx , "testbucket" , "test/path/0" , nil )
563+ require .NoError (t , err )
564+
565+ err = accountingDB .UpdateProjectUsageLimit (ctx , upl .Projects [0 ].ID , 0 )
566+ require .NoError (t , err )
567+
568+ // should fail on Write beause we uploaded more than segment
569+ // and request to satellite were made. The Write call may not fail
570+ // immmediately, since writes are buffered and the segment uploads
571+ // are handled concurrently.
572+ partUpload , err := project .UploadPart (ctx , "testbucket" , "test/path/0" , uploadInfo .UploadID , 0 )
573+ require .NoError (t , err )
574+ requireWriteEventuallyReturns (t , partUpload , data , uplink .ErrStorageLimitExceeded )
575+ require .ErrorIs (t , partUpload .Commit (), uplink .ErrStorageLimitExceeded )
576+
577+ // should fail on Commit as Write input is too small to create single segment
578+ partUpload , err = project .UploadPart (ctx , "testbucket" , "test/path/0" , uploadInfo .UploadID , 0 )
579+ require .NoError (t , err )
580+ _ , err = partUpload .Write (testrand .Bytes (3 * memory .KiB ))
581+ require .NoError (t , err )
582+ require .ErrorIs (t , partUpload .Commit (), uplink .ErrStorageLimitExceeded )
583+ })
584+ })
585+ }
586+
587+ func requireWriteEventuallyReturns (tb testing.TB , w io.Writer , data []byte , expectErr error ) {
588+ require .Eventually (tb , func () bool {
589+ _ , err := w .Write (data )
590+ // only write the data on the first call to write.
591+ data = data [0 :]
592+ return errors .Is (err , expectErr )
593+ }, time .Second * 5 , time .Millisecond * 10 )
594+ }
0 commit comments