You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

255 lines
6.1 KiB

package shell
import (
"testing"
"github.com/seaweedfs/seaweedfs/weed/pb/master_pb"
"github.com/seaweedfs/seaweedfs/weed/storage/needle"
"github.com/stretchr/testify/assert"
)
func buildTestTopologyWithRemoteVolumes() *master_pb.TopologyInfo {
return &master_pb.TopologyInfo{
Id: "topo",
DataCenterInfos: []*master_pb.DataCenterInfo{
{
Id: "dc1",
RackInfos: []*master_pb.RackInfo{
{
Id: "rack1",
DataNodeInfos: []*master_pb.DataNodeInfo{
{
Id: "server1:8080",
GrpcPort: 18080,
DiskInfos: map[string]*master_pb.DiskInfo{
"": {
VolumeInfos: []*master_pb.VolumeInformationMessage{
{
Id: 1,
Collection: "col1",
RemoteStorageName: "s3.default",
RemoteStorageKey: "col1/1.dat",
DeleteCount: 100,
DeletedByteCount: 1000,
Size: 5000,
},
{
Id: 2,
Collection: "col1",
RemoteStorageName: "",
RemoteStorageKey: "",
Size: 3000,
},
{
Id: 3,
Collection: "col2",
RemoteStorageName: "s3.archive",
RemoteStorageKey: "col2/3.dat",
DeleteCount: 50,
DeletedByteCount: 500,
Size: 2000,
},
},
},
},
},
},
},
},
},
{
Id: "dc2",
RackInfos: []*master_pb.RackInfo{
{
Id: "rack1",
DataNodeInfos: []*master_pb.DataNodeInfo{
{
Id: "server2:8080",
GrpcPort: 18080,
DiskInfos: map[string]*master_pb.DiskInfo{
"": {
VolumeInfos: []*master_pb.VolumeInformationMessage{
{
Id: 4,
Collection: "bucket1",
RemoteStorageName: "s3.default",
RemoteStorageKey: "bucket1/4.dat",
Size: 8000,
},
},
},
},
},
},
},
},
},
},
}
}
func TestFindRemoteVolumeInTopology(t *testing.T) {
topo := buildTestTopologyWithRemoteVolumes()
tests := []struct {
name string
vid needle.VolumeId
collection string
wantFound bool
wantDest string
}{
{
name: "find existing remote volume",
vid: 1,
wantFound: true,
wantDest: "s3.default",
},
{
name: "find remote volume with different backend",
vid: 3,
wantFound: true,
wantDest: "s3.archive",
},
{
name: "find remote volume on another server",
vid: 4,
wantFound: true,
wantDest: "s3.default",
},
{
name: "local volume not found as remote",
vid: 2,
wantFound: false,
},
{
name: "non-existent volume not found",
vid: 999,
wantFound: false,
},
{
name: "filter by matching collection exact",
vid: 1,
collection: "^col1$",
wantFound: true,
wantDest: "s3.default",
},
{
name: "filter by matching collection regex",
vid: 1,
collection: "col.*",
wantFound: true,
wantDest: "s3.default",
},
{
name: "filter by non-matching collection",
vid: 1,
collection: "^col2$",
wantFound: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
rv, found, err := findRemoteVolumeInTopology(topo, tt.vid, tt.collection)
assert.NoError(t, err)
assert.Equal(t, tt.wantFound, found)
if found {
assert.Equal(t, tt.vid, rv.vid)
assert.Equal(t, tt.wantDest, rv.remoteStorageName)
}
})
}
}
func TestFindRemoteVolumeInTopologyInvalidPattern(t *testing.T) {
topo := buildTestTopologyWithRemoteVolumes()
_, _, err := findRemoteVolumeInTopology(topo, 1, "[invalid")
assert.Error(t, err)
}
func TestCollectRemoteVolumesWithInfo(t *testing.T) {
topo := buildTestTopologyWithRemoteVolumes()
tests := []struct {
name string
collectionPattern string
wantCount int
wantVids []needle.VolumeId
}{
{
name: "empty pattern matches empty collection only",
collectionPattern: "",
wantCount: 0,
},
{
name: "match all collections",
collectionPattern: ".*",
wantCount: 3, // volumes 1, 3, 4
wantVids: []needle.VolumeId{1, 3, 4},
},
{
name: "match specific collection",
collectionPattern: "^col1$",
wantCount: 1,
wantVids: []needle.VolumeId{1},
},
{
name: "match collection prefix",
collectionPattern: "col.*",
wantCount: 2, // volumes 1, 3
wantVids: []needle.VolumeId{1, 3},
},
{
name: "match bucket collection",
collectionPattern: "bucket1",
wantCount: 1,
wantVids: []needle.VolumeId{4},
},
{
name: "no match",
collectionPattern: "^nonexistent$",
wantCount: 0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := collectRemoteVolumesWithInfo(topo, tt.collectionPattern)
assert.NoError(t, err)
assert.Equal(t, tt.wantCount, len(result))
if tt.wantVids != nil {
gotVids := make(map[needle.VolumeId]bool)
for _, rv := range result {
gotVids[rv.vid] = true
}
for _, vid := range tt.wantVids {
assert.True(t, gotVids[vid], "expected volume %d in results", vid)
}
}
})
}
}
func TestCollectRemoteVolumesWithInfoCaptures(t *testing.T) {
topo := buildTestTopologyWithRemoteVolumes()
result, err := collectRemoteVolumesWithInfo(topo, "^col1$")
assert.NoError(t, err)
assert.Equal(t, 1, len(result))
rv := result[0]
assert.Equal(t, needle.VolumeId(1), rv.vid)
assert.Equal(t, "col1", rv.collection)
assert.Equal(t, "s3.default", rv.remoteStorageName)
assert.Equal(t, "server1:8080", rv.serverUrl)
assert.NotEmpty(t, rv.serverAddress)
}
func TestCollectRemoteVolumesWithInfoInvalidPattern(t *testing.T) {
topo := buildTestTopologyWithRemoteVolumes()
_, err := collectRemoteVolumesWithInfo(topo, "[invalid")
assert.Error(t, err)
}