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.
248 lines
6.3 KiB
248 lines
6.3 KiB
package s3api
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/pb/master_pb"
|
|
)
|
|
|
|
func TestIsSOSAPIObject(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
object string
|
|
expected bool
|
|
}{
|
|
{
|
|
name: "system.xml should be detected",
|
|
object: ".system-d26a9498-cb7c-4a87-a44a-8ae204f5ba6c/system.xml",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "capacity.xml should be detected",
|
|
object: ".system-d26a9498-cb7c-4a87-a44a-8ae204f5ba6c/capacity.xml",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "regular object should not be detected",
|
|
object: "myfile.txt",
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "similar but different path should not be detected",
|
|
object: ".system-other-uuid/system.xml",
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "nested path should not be detected",
|
|
object: "prefix/.system-d26a9498-cb7c-4a87-a44a-8ae204f5ba6c/system.xml",
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "empty string should not be detected",
|
|
object: "",
|
|
expected: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := isSOSAPIObject(tt.object)
|
|
if result != tt.expected {
|
|
t.Errorf("isSOSAPIObject(%q) = %v, want %v", tt.object, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIsSOSAPIClient(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
userAgent string
|
|
expected bool
|
|
}{
|
|
{
|
|
name: "Veeam backup client should be detected",
|
|
userAgent: "APN/1.0 Veeam/1.0 Backup/10.0",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "exact match should be detected",
|
|
userAgent: "APN/1.0 Veeam/1.0",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "AWS CLI should not be detected",
|
|
userAgent: "aws-cli/2.0.0 Python/3.8",
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "empty user agent should not be detected",
|
|
userAgent: "",
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "partial match should not be detected",
|
|
userAgent: "Veeam/1.0",
|
|
expected: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/bucket/object", nil)
|
|
req.Header.Set("User-Agent", tt.userAgent)
|
|
result := isSOSAPIClient(req)
|
|
if result != tt.expected {
|
|
t.Errorf("isSOSAPIClient() with User-Agent %q = %v, want %v", tt.userAgent, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGenerateSystemXML(t *testing.T) {
|
|
xmlData, err := generateSystemXML()
|
|
if err != nil {
|
|
t.Fatalf("generateSystemXML() failed: %v", err)
|
|
}
|
|
|
|
// Verify it's valid XML
|
|
var si SystemInfo
|
|
if err := xml.Unmarshal(xmlData, &si); err != nil {
|
|
t.Fatalf("generated XML is invalid: %v", err)
|
|
}
|
|
|
|
// Verify required fields
|
|
if si.ProtocolVersion != sosAPIProtocolVersion {
|
|
t.Errorf("ProtocolVersion = %q, want %q", si.ProtocolVersion, sosAPIProtocolVersion)
|
|
}
|
|
|
|
if !strings.Contains(si.ModelName, "SeaweedFS") {
|
|
t.Errorf("ModelName = %q, should contain 'SeaweedFS'", si.ModelName)
|
|
}
|
|
|
|
if !si.ProtocolCapabilities.CapacityInfo {
|
|
t.Error("ProtocolCapabilities.CapacityInfo should be true")
|
|
}
|
|
|
|
if si.SystemRecommendations == nil {
|
|
t.Fatal("SystemRecommendations should not be nil")
|
|
}
|
|
|
|
if si.SystemRecommendations.KBBlockSize != sosAPIDefaultBlockSizeKB {
|
|
t.Errorf("KBBlockSize = %d, want %d", si.SystemRecommendations.KBBlockSize, sosAPIDefaultBlockSizeKB)
|
|
}
|
|
}
|
|
|
|
func TestSOSAPIObjectDetectionEdgeCases(t *testing.T) {
|
|
edgeCases := []struct {
|
|
object string
|
|
expected bool
|
|
}{
|
|
// With leading slash
|
|
{"/.system-d26a9498-cb7c-4a87-a44a-8ae204f5ba6c/system.xml", false},
|
|
// URL encoded
|
|
{".system-d26a9498-cb7c-4a87-a44a-8ae204f5ba6c%2Fsystem.xml", false},
|
|
// Mixed case
|
|
{".System-d26a9498-cb7c-4a87-a44a-8ae204f5ba6c/system.xml", false},
|
|
// Extra slashes
|
|
{".system-d26a9498-cb7c-4a87-a44a-8ae204f5ba6c//system.xml", false},
|
|
// Correct paths
|
|
{".system-d26a9498-cb7c-4a87-a44a-8ae204f5ba6c/system.xml", true},
|
|
{".system-d26a9498-cb7c-4a87-a44a-8ae204f5ba6c/capacity.xml", true},
|
|
}
|
|
|
|
for _, tc := range edgeCases {
|
|
result := isSOSAPIObject(tc.object)
|
|
if result != tc.expected {
|
|
t.Errorf("isSOSAPIObject(%q) = %v, want %v", tc.object, result, tc.expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCollectBucketUsageFromTopology(t *testing.T) {
|
|
topo := &master_pb.TopologyInfo{
|
|
DataCenterInfos: []*master_pb.DataCenterInfo{
|
|
{
|
|
RackInfos: []*master_pb.RackInfo{
|
|
{
|
|
DataNodeInfos: []*master_pb.DataNodeInfo{
|
|
{
|
|
DiskInfos: map[string]*master_pb.DiskInfo{
|
|
"hdd": {
|
|
VolumeInfos: []*master_pb.VolumeInformationMessage{
|
|
{Id: 1, Size: 100, Collection: "bucket1"},
|
|
{Id: 2, Size: 200, Collection: "bucket2"},
|
|
{Id: 3, Size: 300, Collection: "bucket1"},
|
|
{Id: 1, Size: 100, Collection: "bucket1"}, // Duplicate (replica), should be ignored
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
usage := collectBucketUsageFromTopology(topo, "bucket1")
|
|
expected := int64(400) // 100 + 300
|
|
if usage != expected {
|
|
t.Errorf("collectBucketUsageFromTopology = %d, want %d", usage, expected)
|
|
}
|
|
|
|
usage2 := collectBucketUsageFromTopology(topo, "bucket2")
|
|
expected2 := int64(200)
|
|
if usage2 != expected2 {
|
|
t.Errorf("collectBucketUsageFromTopology = %d, want %d", usage2, expected2)
|
|
}
|
|
}
|
|
|
|
func TestCalculateClusterCapacity(t *testing.T) {
|
|
topo := &master_pb.TopologyInfo{
|
|
DataCenterInfos: []*master_pb.DataCenterInfo{
|
|
{
|
|
RackInfos: []*master_pb.RackInfo{
|
|
{
|
|
DataNodeInfos: []*master_pb.DataNodeInfo{
|
|
{
|
|
DiskInfos: map[string]*master_pb.DiskInfo{
|
|
"hdd": {
|
|
MaxVolumeCount: 100,
|
|
FreeVolumeCount: 40,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
DiskInfos: map[string]*master_pb.DiskInfo{
|
|
"hdd": {
|
|
MaxVolumeCount: 200,
|
|
FreeVolumeCount: 160,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
volumeSizeLimitMb := uint64(1000) // 1GB
|
|
volumeSizeBytes := int64(1000) * 1024 * 1024
|
|
|
|
total, available := calculateClusterCapacity(topo, volumeSizeLimitMb)
|
|
|
|
expectedTotal := int64(300) * volumeSizeBytes
|
|
expectedAvailable := int64(200) * volumeSizeBytes
|
|
|
|
if total != expectedTotal {
|
|
t.Errorf("calculateClusterCapacity total = %d, want %d", total, expectedTotal)
|
|
}
|
|
if available != expectedAvailable {
|
|
t.Errorf("calculateClusterCapacity available = %d, want %d", available, expectedAvailable)
|
|
}
|
|
}
|