2022-01-26 11:10:28 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package metainfo_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"strconv"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/zeebo/errs"
|
|
|
|
|
|
|
|
"storj.io/common/errs2"
|
|
|
|
"storj.io/common/memory"
|
|
|
|
"storj.io/common/pb"
|
|
|
|
"storj.io/common/rpc/rpcstatus"
|
|
|
|
"storj.io/common/storj"
|
|
|
|
"storj.io/common/testcontext"
|
|
|
|
"storj.io/common/testrand"
|
|
|
|
"storj.io/storj/private/testplanet"
|
2023-04-13 13:04:07 +01:00
|
|
|
"storj.io/storj/satellite/buckets"
|
2022-01-26 11:10:28 +00:00
|
|
|
"storj.io/uplink"
|
|
|
|
"storj.io/uplink/private/metaclient"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestBucketExistenceCheck(t *testing.T) {
|
|
|
|
testplanet.Run(t, testplanet.Config{
|
2022-02-04 10:27:38 +00:00
|
|
|
SatelliteCount: 1, UplinkCount: 1,
|
2022-01-26 11:10:28 +00:00
|
|
|
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
|
|
|
apiKey := planet.Uplinks[0].APIKey[planet.Satellites[0].ID()]
|
|
|
|
|
|
|
|
metainfoClient, err := planet.Uplinks[0].DialMetainfo(ctx, planet.Satellites[0], apiKey)
|
|
|
|
require.NoError(t, err)
|
|
|
|
defer ctx.Check(metainfoClient.Close)
|
|
|
|
|
|
|
|
// test object methods for bucket existence check
|
|
|
|
_, err = metainfoClient.BeginObject(ctx, metaclient.BeginObjectParams{
|
|
|
|
Bucket: []byte("non-existing-bucket"),
|
|
|
|
EncryptedObjectKey: []byte("encrypted-path"),
|
|
|
|
})
|
|
|
|
require.Error(t, err)
|
|
|
|
require.True(t, errs2.IsRPC(err, rpcstatus.NotFound))
|
2023-04-13 13:04:07 +01:00
|
|
|
require.Equal(t, buckets.ErrBucketNotFound.New("%s", "non-existing-bucket").Error(), errs.Unwrap(err).Error())
|
2022-01-26 11:10:28 +00:00
|
|
|
|
|
|
|
_, _, err = metainfoClient.ListObjects(ctx, metaclient.ListObjectsParams{
|
|
|
|
Bucket: []byte("non-existing-bucket"),
|
|
|
|
})
|
|
|
|
require.Error(t, err)
|
|
|
|
require.True(t, errs2.IsRPC(err, rpcstatus.NotFound))
|
2023-04-13 13:04:07 +01:00
|
|
|
require.Equal(t, buckets.ErrBucketNotFound.New("%s", "non-existing-bucket").Error(), errs.Unwrap(err).Error())
|
2022-01-26 11:10:28 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMaxOutBuckets(t *testing.T) {
|
|
|
|
testplanet.Run(t, testplanet.Config{
|
2022-02-04 10:27:38 +00:00
|
|
|
SatelliteCount: 1, UplinkCount: 1,
|
2022-01-26 11:10:28 +00:00
|
|
|
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
|
|
|
limit := planet.Satellites[0].Config.Metainfo.ProjectLimits.MaxBuckets
|
|
|
|
for i := 1; i <= limit; i++ {
|
|
|
|
name := "test" + strconv.Itoa(i)
|
|
|
|
err := planet.Uplinks[0].CreateBucket(ctx, planet.Satellites[0], name)
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
err := planet.Uplinks[0].CreateBucket(ctx, planet.Satellites[0], fmt.Sprintf("test%d", limit+1))
|
|
|
|
require.Error(t, err)
|
|
|
|
require.Contains(t, err.Error(), fmt.Sprintf("number of allocated buckets (%d) exceeded", limit))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBucketNameValidation(t *testing.T) {
|
|
|
|
testplanet.Run(t, testplanet.Config{
|
2022-02-04 10:27:38 +00:00
|
|
|
SatelliteCount: 1, UplinkCount: 1,
|
2022-01-26 11:10:28 +00:00
|
|
|
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
|
|
|
apiKey := planet.Uplinks[0].APIKey[planet.Satellites[0].ID()]
|
|
|
|
|
|
|
|
metainfoClient, err := planet.Uplinks[0].DialMetainfo(ctx, planet.Satellites[0], apiKey)
|
|
|
|
require.NoError(t, err)
|
|
|
|
defer ctx.Check(metainfoClient.Close)
|
|
|
|
|
|
|
|
validNames := []string{
|
|
|
|
"tes", "testbucket",
|
|
|
|
"test-bucket", "testbucket9",
|
|
|
|
"9testbucket", "a.b",
|
|
|
|
"test.bucket", "test-one.bucket-one",
|
|
|
|
"test.bucket.one",
|
|
|
|
"testbucket-63-0123456789012345678901234567890123456789012345abc",
|
|
|
|
}
|
|
|
|
for _, name := range validNames {
|
|
|
|
_, err = metainfoClient.CreateBucket(ctx, metaclient.CreateBucketParams{
|
|
|
|
Name: []byte(name),
|
|
|
|
})
|
|
|
|
require.NoError(t, err, "bucket name: %v", name)
|
|
|
|
|
|
|
|
_, err = metainfoClient.BeginObject(ctx, metaclient.BeginObjectParams{
|
|
|
|
Bucket: []byte(name),
|
|
|
|
EncryptedObjectKey: []byte("123"),
|
|
|
|
Version: 0,
|
|
|
|
ExpiresAt: time.Now().Add(16 * 24 * time.Hour),
|
|
|
|
EncryptionParameters: storj.EncryptionParameters{
|
|
|
|
CipherSuite: storj.EncAESGCM,
|
|
|
|
BlockSize: 256,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
require.NoError(t, err, "bucket name: %v", name)
|
|
|
|
}
|
|
|
|
|
|
|
|
invalidNames := []string{
|
|
|
|
"", "t", "te", "-testbucket",
|
|
|
|
"testbucket-", "-testbucket-",
|
|
|
|
"a.b.", "test.bucket-.one",
|
|
|
|
"test.-bucket.one", "1.2.3.4",
|
|
|
|
"192.168.1.234", "testBUCKET",
|
|
|
|
"test/bucket",
|
|
|
|
"testbucket-64-0123456789012345678901234567890123456789012345abcd",
|
2023-07-03 12:23:00 +01:00
|
|
|
"test\\", "test%",
|
2022-01-26 11:10:28 +00:00
|
|
|
}
|
|
|
|
for _, name := range invalidNames {
|
2023-07-17 09:42:03 +01:00
|
|
|
|
|
|
|
_, err = metainfoClient.CreateBucket(ctx, metaclient.CreateBucketParams{
|
|
|
|
Name: []byte(name),
|
2022-01-26 11:10:28 +00:00
|
|
|
})
|
|
|
|
require.Error(t, err, "bucket name: %v", name)
|
2023-07-03 12:23:00 +01:00
|
|
|
require.True(t, errs2.IsRPC(err, rpcstatus.InvalidArgument))
|
2023-07-17 09:42:03 +01:00
|
|
|
}
|
2022-01-26 11:10:28 +00:00
|
|
|
|
2023-07-17 09:42:03 +01:00
|
|
|
invalidNames = []string{
|
|
|
|
"", "t", "te",
|
|
|
|
"testbucket-64-0123456789012345678901234567890123456789012345abcd",
|
|
|
|
}
|
|
|
|
for _, name := range invalidNames {
|
|
|
|
// BeginObject validates only bucket name length
|
|
|
|
_, err = metainfoClient.BeginObject(ctx, metaclient.BeginObjectParams{
|
|
|
|
Bucket: []byte(name),
|
|
|
|
EncryptedObjectKey: []byte("123"),
|
2022-01-26 11:10:28 +00:00
|
|
|
})
|
|
|
|
require.Error(t, err, "bucket name: %v", name)
|
2023-07-03 12:23:00 +01:00
|
|
|
require.True(t, errs2.IsRPC(err, rpcstatus.InvalidArgument))
|
2022-01-26 11:10:28 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBucketEmptinessBeforeDelete(t *testing.T) {
|
|
|
|
testplanet.Run(t, testplanet.Config{
|
2022-02-04 10:27:38 +00:00
|
|
|
SatelliteCount: 1, UplinkCount: 1,
|
2022-01-26 11:10:28 +00:00
|
|
|
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
2022-02-04 10:27:38 +00:00
|
|
|
for i := 0; i < 5; i++ {
|
2022-01-26 11:10:28 +00:00
|
|
|
err := planet.Uplinks[0].Upload(ctx, planet.Satellites[0], "test-bucket", "object-key"+strconv.Itoa(i), testrand.Bytes(memory.KiB))
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
2022-02-04 10:27:38 +00:00
|
|
|
for i := 0; i < 5; i++ {
|
2022-01-26 11:10:28 +00:00
|
|
|
err := planet.Uplinks[0].DeleteBucket(ctx, planet.Satellites[0], "test-bucket")
|
|
|
|
require.Error(t, err)
|
|
|
|
require.True(t, errors.Is(err, uplink.ErrBucketNotEmpty))
|
|
|
|
|
|
|
|
err = planet.Uplinks[0].DeleteObject(ctx, planet.Satellites[0], "test-bucket", "object-key"+strconv.Itoa(i))
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err := planet.Uplinks[0].DeleteBucket(ctx, planet.Satellites[0], "test-bucket")
|
|
|
|
require.NoError(t, err)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDeleteBucket(t *testing.T) {
|
|
|
|
testplanet.Run(t, testplanet.Config{
|
|
|
|
Reconfigure: testplanet.Reconfigure{
|
|
|
|
Satellite: testplanet.Combine(
|
|
|
|
testplanet.ReconfigureRS(2, 2, 4, 4),
|
|
|
|
testplanet.MaxSegmentSize(13*memory.KiB),
|
|
|
|
),
|
|
|
|
},
|
|
|
|
SatelliteCount: 1, StorageNodeCount: 4, UplinkCount: 1,
|
|
|
|
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
|
|
|
apiKey := planet.Uplinks[0].APIKey[planet.Satellites[0].ID()]
|
|
|
|
satelliteSys := planet.Satellites[0]
|
|
|
|
uplnk := planet.Uplinks[0]
|
|
|
|
|
|
|
|
expectedBucketName := "remote-segments-bucket"
|
|
|
|
|
|
|
|
err := uplnk.Upload(ctx, planet.Satellites[0], expectedBucketName, "single-segment-object", testrand.Bytes(10*memory.KiB))
|
|
|
|
require.NoError(t, err)
|
|
|
|
err = uplnk.Upload(ctx, planet.Satellites[0], expectedBucketName, "multi-segment-object", testrand.Bytes(50*memory.KiB))
|
|
|
|
require.NoError(t, err)
|
|
|
|
err = uplnk.Upload(ctx, planet.Satellites[0], expectedBucketName, "remote-segment-inline-object", testrand.Bytes(33*memory.KiB))
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
objects, err := satelliteSys.API.Metainfo.Metabase.TestingAllObjects(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, objects, 3)
|
|
|
|
|
|
|
|
delResp, err := satelliteSys.API.Metainfo.Endpoint.DeleteBucket(ctx, &pb.BucketDeleteRequest{
|
|
|
|
Header: &pb.RequestHeader{
|
|
|
|
ApiKey: apiKey.SerializeRaw(),
|
|
|
|
},
|
|
|
|
Name: []byte(expectedBucketName),
|
|
|
|
DeleteAll: true,
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, int64(3), delResp.DeletedObjectsCount)
|
|
|
|
|
|
|
|
// confirm the bucket is deleted
|
|
|
|
buckets, err := satelliteSys.Metainfo.Endpoint.ListBuckets(ctx, &pb.BucketListRequest{
|
|
|
|
Header: &pb.RequestHeader{
|
|
|
|
ApiKey: apiKey.SerializeRaw(),
|
|
|
|
},
|
2023-04-19 13:25:12 +01:00
|
|
|
Direction: buckets.DirectionForward,
|
2022-01-26 11:10:28 +00:00
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, buckets.GetItems(), 0)
|
|
|
|
})
|
|
|
|
}
|
2022-07-12 16:53:12 +01:00
|
|
|
|
|
|
|
func TestListBucketsWithAttribution(t *testing.T) {
|
|
|
|
testplanet.Run(t, testplanet.Config{
|
|
|
|
SatelliteCount: 1, StorageNodeCount: 4, UplinkCount: 1,
|
|
|
|
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
|
|
|
satellite := planet.Satellites[0]
|
|
|
|
apiKey := planet.Uplinks[0].APIKey[planet.Satellites[0].ID()]
|
|
|
|
|
|
|
|
type testCase struct {
|
|
|
|
UserAgent string
|
|
|
|
Bucket string
|
|
|
|
}
|
|
|
|
|
|
|
|
var testCases = []testCase{
|
|
|
|
{
|
|
|
|
Bucket: "bucket-without-user-agent",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
UserAgent: "storj",
|
|
|
|
Bucket: "bucket-with-user-agent",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
bucketExists := func(tc testCase, buckets *pb.BucketListResponse) bool {
|
|
|
|
for _, bucket := range buckets.Items {
|
|
|
|
if string(bucket.Name) == tc.Bucket {
|
|
|
|
require.EqualValues(t, tc.UserAgent, string(bucket.UserAgent))
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
t.Fatalf("bucket was not found in results:%s", tc.Bucket)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range testCases {
|
|
|
|
config := uplink.Config{
|
|
|
|
UserAgent: tc.UserAgent,
|
|
|
|
}
|
|
|
|
|
|
|
|
project, err := config.OpenProject(ctx, planet.Uplinks[0].Access[satellite.ID()])
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
_, err = project.CreateBucket(ctx, tc.Bucket)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
buckets, err := satellite.Metainfo.Endpoint.ListBuckets(ctx, &pb.BucketListRequest{
|
|
|
|
Header: &pb.RequestHeader{
|
|
|
|
ApiKey: apiKey.SerializeRaw(),
|
|
|
|
},
|
2023-04-19 13:25:12 +01:00
|
|
|
Direction: buckets.DirectionForward,
|
2022-07-12 16:53:12 +01:00
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, bucketExists(tc, buckets))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2023-06-07 10:50:27 +01:00
|
|
|
|
|
|
|
func TestBucketCreationWithDefaultPlacement(t *testing.T) {
|
|
|
|
testplanet.Run(t, testplanet.Config{
|
|
|
|
SatelliteCount: 1, UplinkCount: 1,
|
|
|
|
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
|
|
|
projectID := planet.Uplinks[0].Projects[0].ID
|
|
|
|
|
|
|
|
// change the default_placement of the project
|
|
|
|
project, err := planet.Satellites[0].API.DB.Console().Projects().Get(ctx, projectID)
|
|
|
|
project.DefaultPlacement = storj.EU
|
|
|
|
require.NoError(t, err)
|
|
|
|
err = planet.Satellites[0].API.DB.Console().Projects().Update(ctx, project)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// create a new bucket
|
|
|
|
up, err := planet.Uplinks[0].GetProject(ctx, planet.Satellites[0])
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
_, err = up.CreateBucket(ctx, "eu1")
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// check if placement is set
|
|
|
|
placement, err := planet.Satellites[0].API.DB.Buckets().GetBucketPlacement(ctx, []byte("eu1"), projectID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, storj.EU, placement)
|
|
|
|
|
|
|
|
})
|
|
|
|
}
|