snapshot of https://github.com/seaweedfs/seaweedfs.git (master, 2026-09-16; blobs > 131072B omitted)
Some checks failed
go: build dev binaries / cleanup (push) Successful in 4s
Codespell / Check for spelling errors (push) Failing after 3s
docker: build dev containers / build-rust-binaries (amd64, x86_64-unknown-linux-musl) (push) Failing after 3s
docker: build dev containers / build-dev-containers (push) Has been skipped
docker: build dev containers / build-rust-binaries (arm64, true, aarch64-unknown-linux-musl) (push) Failing after 3s
End to End / FUSE Mount (push) Failing after 2s
EC Integration Tests / EC Integration Tests (push) Failing after 30s
FUSE DLM Integration Tests / FUSE DLM Integration Tests (push) Failing after 3s
FUSE Volume Server Failover Tests / FUSE Volume Server Failover (push) Failing after 3s
FUSE Integration Tests / FUSE Integration Testing (push) Failing after 2s
FUSE P2P Peer Chunk Sharing Integration Tests / FUSE P2P Peer Chunk Sharing (push) Failing after 3s
go: build binary / Go Vet (push) Failing after 2s
go: build binary / Go Vet 32-bit (push) Failing after 3s
go: build binary / Build (push) Failing after 4s
go: build binary / Build cross-platform (freebsd/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (darwin/arm64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/arm64) (push) Failing after 3s
go: build binary / Test (push) Failing after 2s
go: build binary / Test 32-bit (push) Failing after 3s
helm: lint and test charts / lint-test (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (11) (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (17) (push) Failing after 3s
go: build dev binaries / build_dev_linux_windows (amd64, linux) (push) Failing after 2s
go: build dev binaries / build_dev_linux_windows (amd64, windows) (push) Failing after 3s
go: build dev binaries / build_dev_darwin (amd64, darwin) (push) Has been skipped
go: build dev binaries / build_dev_darwin (arm64, darwin) (push) Has been skipped
Java Client Unit Tests / Java Unit Tests (11) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (17) (push) Failing after 2s
Java Client Unit Tests / Java Unit Tests (21) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (8) (push) Failing after 3s
Kafka Quick Test (Load Test with Schema Registry) / Kafka Client Load Test (Quick) (push) Failing after 3s
Kafka Gateway Tests / Kafka Unit Tests (unit-tests-1) (push) Failing after 11s
Kafka Gateway Tests / Kafka Integration Tests (Critical) (integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka End-to-End Tests (with SMQ) (e2e-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Consumer Group Tests (Highly Isolated) (consumer-group-1) (push) Failing after 2s
Kafka Gateway Tests / Kafka Client Compatibility (with SMQ) (client-compat-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka SMQ Integration Tests (Full Stack) (smq-integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Protocol Tests (Isolated) (protocol-1) (push) Failing after 3s
KMS Tests / KMS Provider Integration Tests (push) Failing after 2s
KMS Tests / S3 KMS End-to-End Tests (push) Failing after 3s
Master Cold Start Tests / Master Cold Start Tests (push) Failing after 4s
Metadata Subscribe Integration Tests / Metadata Subscribe Integration Tests (push) Failing after 3s
Multi-Master Tests / Multi-Master Failover Tests (push) Failing after 3s
Performance / CPU and Heap Profile (push) Failing after 2s
Performance / S3 Read/Write Benchmark (rust volume) (push) Failing after 3s
pjdfstest POSIX Compliance / pjdfstest (push) Failing after 2s
Plugin Worker Integration Tests / Plugin Worker: erasure_coding (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: vacuum (push) Failing after 3s
Rust Volume Server Tests / Rust Integration Tests (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 1) (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 1) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 3) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Distributed Tests (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Performance Tests (push) Failing after 3s
Performance / Throughput Benchmark (go volume) (push) Failing after 3s
Performance / Throughput Benchmark (rust volume) (push) Failing after 2s
Performance / S3 Read/Write Benchmark (go volume) (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: volume_balance (push) Failing after 3s
PostgreSQL Gateway Tests / PostgreSQL Basic Tests (push) Failing after 3s
Rust Volume Server Tests / Rust Unit Tests (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 3) (push) Failing after 3s
Rust Plugin Worker Tests / Rust Plugin Worker Build and Unit Tests (push) Failing after 3s
rust: build dev volume server binaries / cleanup (push) Successful in 3s
S3 ETag and ACL Tests / S3 ETag + ACL Integration Tests (push) Failing after 3s
S3 IAM Integration Tests / IAM Unit Tests (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (advanced) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (basic) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (group) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (policy-enforcement) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (sts) (push) Failing after 4s
S3 Keycloak Integration Tests / S3 Keycloak Integration Tests (push) Failing after 3s
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.11) (push) Failing after 3s
S3 PyArrow Parquet Tests / Go Unit Tests (Implicit Directory) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.12) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-amd64, x86_64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-arm64, aarch64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-linux (linux-amd64, x86_64-unknown-linux-gnu) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.9) (push) Has been cancelled
S3 Proxy Signature Tests / S3 Proxy Signature Verification Tests (push) Has been cancelled
S3 SDK V2 Route Disambiguation Tests / S3 SDK V2 Routing Tests (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (quick) (push) Has been cancelled
S3 SSE Tests / S3 SSE Compatibility Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Metadata Persistence Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Copy Operations Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Multipart Upload Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Performance Test (push) Has been cancelled
S3 SSE Tests / S3 Volume Encryption Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (comprehensive) (push) Has been cancelled
Spark Integration Tests / Spark Integration Tests (push) Failing after 2s
Telemetry Integration Tests / telemetry-integration-test (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 1) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 1) (push) Failing after 3s
Ceph S3 tests / Basic S3 tests (KV store) (push) Has been cancelled
Ceph S3 tests / S3 Versioning & Object Lock tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Unit Tests (push) Failing after 3s
Ceph S3 tests / S3 CORS tests (push) Has been cancelled
Ceph S3 tests / SeaweedFS Custom S3 Copy tests (push) Has been cancelled
Ceph S3 tests / Basic S3 tests (SQL store) (push) Has been cancelled
test s3 over https using aws-cli / awscli-tests (push) Has been cancelled
TLS Rotation Integration Tests / TLS Rotation Integration Tests (push) Has been cancelled
Vacuum Integration Tests / Vacuum Integration Tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Variables Integration Tests (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (advanced-policy) (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (basic-policy) (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (contextual-policy) (push) Failing after 4s
S3 Policy Integration Tests / Trusted Proxy Detection Tests (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Shell Integration Tests (push) Failing after 3s
Samba on FUSE Integration / samba-integration (push) Failing after 2s
SFTP Integration Tests / SFTP Integration Testing (push) Failing after 3s
terraform: validate and test modules / fmt, validate, plan-level tests (push) Failing after 3s
terraform: validate and test modules / local cluster smoke test (real weed) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 3) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 2) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 2) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 3) (push) Failing after 5s
mount: windows conformance / WinFsp conformance (push) Has been cancelled
mount: windows / Mount on Windows (push) Has been cancelled
Some checks failed
go: build dev binaries / cleanup (push) Successful in 4s
Codespell / Check for spelling errors (push) Failing after 3s
docker: build dev containers / build-rust-binaries (amd64, x86_64-unknown-linux-musl) (push) Failing after 3s
docker: build dev containers / build-dev-containers (push) Has been skipped
docker: build dev containers / build-rust-binaries (arm64, true, aarch64-unknown-linux-musl) (push) Failing after 3s
End to End / FUSE Mount (push) Failing after 2s
EC Integration Tests / EC Integration Tests (push) Failing after 30s
FUSE DLM Integration Tests / FUSE DLM Integration Tests (push) Failing after 3s
FUSE Volume Server Failover Tests / FUSE Volume Server Failover (push) Failing after 3s
FUSE Integration Tests / FUSE Integration Testing (push) Failing after 2s
FUSE P2P Peer Chunk Sharing Integration Tests / FUSE P2P Peer Chunk Sharing (push) Failing after 3s
go: build binary / Go Vet (push) Failing after 2s
go: build binary / Go Vet 32-bit (push) Failing after 3s
go: build binary / Build (push) Failing after 4s
go: build binary / Build cross-platform (freebsd/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (darwin/arm64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/arm64) (push) Failing after 3s
go: build binary / Test (push) Failing after 2s
go: build binary / Test 32-bit (push) Failing after 3s
helm: lint and test charts / lint-test (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (11) (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (17) (push) Failing after 3s
go: build dev binaries / build_dev_linux_windows (amd64, linux) (push) Failing after 2s
go: build dev binaries / build_dev_linux_windows (amd64, windows) (push) Failing after 3s
go: build dev binaries / build_dev_darwin (amd64, darwin) (push) Has been skipped
go: build dev binaries / build_dev_darwin (arm64, darwin) (push) Has been skipped
Java Client Unit Tests / Java Unit Tests (11) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (17) (push) Failing after 2s
Java Client Unit Tests / Java Unit Tests (21) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (8) (push) Failing after 3s
Kafka Quick Test (Load Test with Schema Registry) / Kafka Client Load Test (Quick) (push) Failing after 3s
Kafka Gateway Tests / Kafka Unit Tests (unit-tests-1) (push) Failing after 11s
Kafka Gateway Tests / Kafka Integration Tests (Critical) (integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka End-to-End Tests (with SMQ) (e2e-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Consumer Group Tests (Highly Isolated) (consumer-group-1) (push) Failing after 2s
Kafka Gateway Tests / Kafka Client Compatibility (with SMQ) (client-compat-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka SMQ Integration Tests (Full Stack) (smq-integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Protocol Tests (Isolated) (protocol-1) (push) Failing after 3s
KMS Tests / KMS Provider Integration Tests (push) Failing after 2s
KMS Tests / S3 KMS End-to-End Tests (push) Failing after 3s
Master Cold Start Tests / Master Cold Start Tests (push) Failing after 4s
Metadata Subscribe Integration Tests / Metadata Subscribe Integration Tests (push) Failing after 3s
Multi-Master Tests / Multi-Master Failover Tests (push) Failing after 3s
Performance / CPU and Heap Profile (push) Failing after 2s
Performance / S3 Read/Write Benchmark (rust volume) (push) Failing after 3s
pjdfstest POSIX Compliance / pjdfstest (push) Failing after 2s
Plugin Worker Integration Tests / Plugin Worker: erasure_coding (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: vacuum (push) Failing after 3s
Rust Volume Server Tests / Rust Integration Tests (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 1) (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 1) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 3) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Distributed Tests (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Performance Tests (push) Failing after 3s
Performance / Throughput Benchmark (go volume) (push) Failing after 3s
Performance / Throughput Benchmark (rust volume) (push) Failing after 2s
Performance / S3 Read/Write Benchmark (go volume) (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: volume_balance (push) Failing after 3s
PostgreSQL Gateway Tests / PostgreSQL Basic Tests (push) Failing after 3s
Rust Volume Server Tests / Rust Unit Tests (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 3) (push) Failing after 3s
Rust Plugin Worker Tests / Rust Plugin Worker Build and Unit Tests (push) Failing after 3s
rust: build dev volume server binaries / cleanup (push) Successful in 3s
S3 ETag and ACL Tests / S3 ETag + ACL Integration Tests (push) Failing after 3s
S3 IAM Integration Tests / IAM Unit Tests (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (advanced) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (basic) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (group) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (policy-enforcement) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (sts) (push) Failing after 4s
S3 Keycloak Integration Tests / S3 Keycloak Integration Tests (push) Failing after 3s
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.11) (push) Failing after 3s
S3 PyArrow Parquet Tests / Go Unit Tests (Implicit Directory) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.12) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-amd64, x86_64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-arm64, aarch64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-linux (linux-amd64, x86_64-unknown-linux-gnu) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.9) (push) Has been cancelled
S3 Proxy Signature Tests / S3 Proxy Signature Verification Tests (push) Has been cancelled
S3 SDK V2 Route Disambiguation Tests / S3 SDK V2 Routing Tests (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (quick) (push) Has been cancelled
S3 SSE Tests / S3 SSE Compatibility Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Metadata Persistence Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Copy Operations Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Multipart Upload Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Performance Test (push) Has been cancelled
S3 SSE Tests / S3 Volume Encryption Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (comprehensive) (push) Has been cancelled
Spark Integration Tests / Spark Integration Tests (push) Failing after 2s
Telemetry Integration Tests / telemetry-integration-test (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 1) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 1) (push) Failing after 3s
Ceph S3 tests / Basic S3 tests (KV store) (push) Has been cancelled
Ceph S3 tests / S3 Versioning & Object Lock tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Unit Tests (push) Failing after 3s
Ceph S3 tests / S3 CORS tests (push) Has been cancelled
Ceph S3 tests / SeaweedFS Custom S3 Copy tests (push) Has been cancelled
Ceph S3 tests / Basic S3 tests (SQL store) (push) Has been cancelled
test s3 over https using aws-cli / awscli-tests (push) Has been cancelled
TLS Rotation Integration Tests / TLS Rotation Integration Tests (push) Has been cancelled
Vacuum Integration Tests / Vacuum Integration Tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Variables Integration Tests (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (advanced-policy) (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (basic-policy) (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (contextual-policy) (push) Failing after 4s
S3 Policy Integration Tests / Trusted Proxy Detection Tests (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Shell Integration Tests (push) Failing after 3s
Samba on FUSE Integration / samba-integration (push) Failing after 2s
SFTP Integration Tests / SFTP Integration Testing (push) Failing after 3s
terraform: validate and test modules / fmt, validate, plan-level tests (push) Failing after 3s
terraform: validate and test modules / local cluster smoke test (real weed) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 3) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 2) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 2) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 3) (push) Failing after 5s
mount: windows conformance / WinFsp conformance (push) Has been cancelled
mount: windows / Mount on Windows (push) Has been cancelled
This commit is contained in:
476
weed/s3api/s3tables/handler_maintenance_test.go
Normal file
476
weed/s3api/s3tables/handler_maintenance_test.go
Normal file
@@ -0,0 +1,476 @@
|
||||
package s3tables
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func settingPtr(v int64) *int64 { return &v }
|
||||
|
||||
func TestValidateMaintenanceValueAcceptsScopedTypes(t *testing.T) {
|
||||
err := validateMaintenanceValue(MaintenanceTypeIcebergCompaction, tableMaintenanceTypes, &MaintenanceConfigurationValue{
|
||||
Status: MaintenanceStatusEnabled,
|
||||
Settings: &MaintenanceSettings{IcebergCompaction: &IcebergCompactionSettings{TargetFileSizeMB: settingPtr(512)}},
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("expected compaction accepted on a table, got %v", err)
|
||||
}
|
||||
|
||||
err = validateMaintenanceValue(MaintenanceTypeIcebergUnreferencedFileRemoval, bucketMaintenanceTypes, &MaintenanceConfigurationValue{
|
||||
Status: MaintenanceStatusDisabled,
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("expected unreferenced file removal accepted on a bucket, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateMaintenanceValueRejectsWrongScope(t *testing.T) {
|
||||
if err := validateMaintenanceValue(MaintenanceTypeIcebergCompaction, bucketMaintenanceTypes, &MaintenanceConfigurationValue{
|
||||
Status: MaintenanceStatusEnabled,
|
||||
}); err == nil {
|
||||
t.Error("expected compaction rejected on a table bucket")
|
||||
}
|
||||
|
||||
if err := validateMaintenanceValue(MaintenanceTypeIcebergUnreferencedFileRemoval, tableMaintenanceTypes, &MaintenanceConfigurationValue{
|
||||
Status: MaintenanceStatusEnabled,
|
||||
}); err == nil {
|
||||
t.Error("expected unreferenced file removal rejected on a table")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateMaintenanceValueRejectsBadInput(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
maintenanceType string
|
||||
value *MaintenanceConfigurationValue
|
||||
}{
|
||||
"empty type": {"", &MaintenanceConfigurationValue{Status: MaintenanceStatusEnabled}},
|
||||
"unknown type": {"icebergSomethingElse", &MaintenanceConfigurationValue{Status: MaintenanceStatusEnabled}},
|
||||
"nil value": {MaintenanceTypeIcebergCompaction, nil},
|
||||
"no status": {MaintenanceTypeIcebergCompaction, &MaintenanceConfigurationValue{}},
|
||||
"bad status": {MaintenanceTypeIcebergCompaction, &MaintenanceConfigurationValue{Status: "Enabled"}},
|
||||
"settings for another type": {MaintenanceTypeIcebergCompaction, &MaintenanceConfigurationValue{
|
||||
Status: MaintenanceStatusEnabled,
|
||||
Settings: &MaintenanceSettings{IcebergSnapshotManagement: &IcebergSnapshotManagementSettings{MinSnapshotsToKeep: settingPtr(3)}},
|
||||
}},
|
||||
}
|
||||
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if err := validateMaintenanceValue(tc.maintenanceType, tableMaintenanceTypes, tc.value); err == nil {
|
||||
t.Error("expected rejection")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// The stored attribute is the wire shape, so Get can hand it straight back.
|
||||
func TestMaintenanceConfigurationRoundTrip(t *testing.T) {
|
||||
original := MaintenanceConfiguration{
|
||||
MaintenanceTypeIcebergCompaction: {
|
||||
Status: MaintenanceStatusEnabled,
|
||||
Settings: &MaintenanceSettings{IcebergCompaction: &IcebergCompactionSettings{TargetFileSizeMB: settingPtr(512)}},
|
||||
},
|
||||
MaintenanceTypeIcebergSnapshotManagement: {
|
||||
Status: MaintenanceStatusDisabled,
|
||||
Settings: &MaintenanceSettings{IcebergSnapshotManagement: &IcebergSnapshotManagementSettings{
|
||||
MinSnapshotsToKeep: settingPtr(3),
|
||||
MaxSnapshotAgeHours: settingPtr(120),
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
data, err := json.Marshal(original)
|
||||
if err != nil {
|
||||
t.Fatalf("marshal: %v", err)
|
||||
}
|
||||
|
||||
var decoded MaintenanceConfiguration
|
||||
if err := json.Unmarshal(data, &decoded); err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
}
|
||||
|
||||
compaction := decoded[MaintenanceTypeIcebergCompaction]
|
||||
if compaction == nil || compaction.Settings == nil || compaction.Settings.IcebergCompaction == nil {
|
||||
t.Fatalf("expected compaction settings, got %s", data)
|
||||
}
|
||||
if got := compaction.Settings.IcebergCompaction.TargetFileSizeMB; got == nil || *got != 512 {
|
||||
t.Errorf("expected targetFileSizeMB=512, got %v", got)
|
||||
}
|
||||
|
||||
snapshots := decoded[MaintenanceTypeIcebergSnapshotManagement]
|
||||
if snapshots == nil || snapshots.Status != MaintenanceStatusDisabled {
|
||||
t.Fatalf("expected snapshot management disabled, got %s", data)
|
||||
}
|
||||
if got := snapshots.Settings.IcebergSnapshotManagement.MaxSnapshotAgeHours; got == nil || *got != 120 {
|
||||
t.Errorf("expected maxSnapshotAgeHours=120, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// Putting one type must not drop the others already stored.
|
||||
func TestMaintenanceConfigurationMergeKeepsOtherTypes(t *testing.T) {
|
||||
stored, err := json.Marshal(MaintenanceConfiguration{
|
||||
MaintenanceTypeIcebergCompaction: {Status: MaintenanceStatusEnabled},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("marshal: %v", err)
|
||||
}
|
||||
|
||||
config := MaintenanceConfiguration{}
|
||||
if err := json.Unmarshal(stored, &config); err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
}
|
||||
config[MaintenanceTypeIcebergSnapshotManagement] = &MaintenanceConfigurationValue{Status: MaintenanceStatusDisabled}
|
||||
|
||||
if len(config) != 2 {
|
||||
t.Errorf("expected both types retained, got %+v", config)
|
||||
}
|
||||
if config[MaintenanceTypeIcebergCompaction].Status != MaintenanceStatusEnabled {
|
||||
t.Error("expected the existing compaction entry preserved")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTableTarget(t *testing.T) {
|
||||
h := NewS3TablesHandler()
|
||||
arn := h.generateTableBucketARN(DefaultAccountID, "analytics")
|
||||
|
||||
bucketName, namespaceName, tableName, err := h.parseTableTarget(arn, []string{"sales"}, "orders")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if bucketName != "analytics" || namespaceName != "sales" || tableName != "orders" {
|
||||
t.Errorf("got %q/%q/%q", bucketName, namespaceName, tableName)
|
||||
}
|
||||
|
||||
for name, tc := range map[string]struct {
|
||||
arn string
|
||||
namespace []string
|
||||
table string
|
||||
}{
|
||||
"missing arn": {"", []string{"sales"}, "orders"},
|
||||
"missing namespace": {arn, nil, "orders"},
|
||||
"missing name": {arn, []string{"sales"}, ""},
|
||||
"bad arn": {"not-an-arn", []string{"sales"}, "orders"},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if _, _, _, err := h.parseTableTarget(tc.arn, tc.namespace, tc.table); err == nil {
|
||||
t.Error("expected rejection")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildJobStatusResponseReportsEveryType(t *testing.T) {
|
||||
status := buildJobStatusResponse(nil, nil)
|
||||
if len(status) != 3 {
|
||||
t.Fatalf("expected all three job types reported, got %v", status)
|
||||
}
|
||||
for jobType, value := range status {
|
||||
if value.Status != MaintenanceJobStatusNotYetRun {
|
||||
t.Errorf("expected %s not yet run, got %q", jobType, value.Status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildJobStatusResponseDisabledBeatsRecorded(t *testing.T) {
|
||||
recorded := MaintenanceJobStatus{
|
||||
MaintenanceTypeIcebergCompaction: {Status: MaintenanceJobStatusSuccessful},
|
||||
MaintenanceTypeIcebergSnapshotManagement: {Status: MaintenanceJobStatusFailed, FailureMessage: "boom"},
|
||||
}
|
||||
config := MaintenanceConfiguration{
|
||||
MaintenanceTypeIcebergCompaction: {Status: MaintenanceStatusDisabled},
|
||||
}
|
||||
|
||||
status := buildJobStatusResponse(recorded, config)
|
||||
if status[MaintenanceTypeIcebergCompaction].Status != MaintenanceJobStatusDisabled {
|
||||
t.Errorf("expected a disabled type reported as disabled, got %q", status[MaintenanceTypeIcebergCompaction].Status)
|
||||
}
|
||||
if status[MaintenanceTypeIcebergSnapshotManagement].FailureMessage != "boom" {
|
||||
t.Error("expected the recorded failure preserved")
|
||||
}
|
||||
if status[MaintenanceTypeIcebergUnreferencedFileRemoval].Status != MaintenanceJobStatusNotYetRun {
|
||||
t.Error("expected an unrun type reported as not yet run")
|
||||
}
|
||||
}
|
||||
|
||||
// A strategy the worker cannot carry out must be rejected, not accepted and
|
||||
// silently compacted some other way.
|
||||
func TestValidateMaintenanceValueCompactionStrategy(t *testing.T) {
|
||||
for _, strategy := range []string{"", CompactionStrategyAuto, CompactionStrategyBinpack, CompactionStrategySort} {
|
||||
if err := validateMaintenanceValue(MaintenanceTypeIcebergCompaction, tableMaintenanceTypes, &MaintenanceConfigurationValue{
|
||||
Status: MaintenanceStatusEnabled,
|
||||
Settings: &MaintenanceSettings{IcebergCompaction: &IcebergCompactionSettings{Strategy: strategy}},
|
||||
}); err != nil {
|
||||
t.Errorf("expected strategy %q accepted, got %v", strategy, err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, strategy := range []string{CompactionStrategyZOrder, "nonsense"} {
|
||||
if err := validateMaintenanceValue(MaintenanceTypeIcebergCompaction, tableMaintenanceTypes, &MaintenanceConfigurationValue{
|
||||
Status: MaintenanceStatusEnabled,
|
||||
Settings: &MaintenanceSettings{IcebergCompaction: &IcebergCompactionSettings{Strategy: strategy}},
|
||||
}); err == nil {
|
||||
t.Errorf("expected strategy %q rejected", strategy)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Put then Get must return the strategy unchanged.
|
||||
func TestMaintenanceConfigurationPreservesStrategy(t *testing.T) {
|
||||
data, err := json.Marshal(MaintenanceConfiguration{
|
||||
MaintenanceTypeIcebergCompaction: {
|
||||
Status: MaintenanceStatusEnabled,
|
||||
Settings: &MaintenanceSettings{IcebergCompaction: &IcebergCompactionSettings{Strategy: CompactionStrategySort, TargetFileSizeMB: settingPtr(512)}},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("marshal: %v", err)
|
||||
}
|
||||
|
||||
var decoded MaintenanceConfiguration
|
||||
if err := json.Unmarshal(data, &decoded); err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
}
|
||||
if got := decoded[MaintenanceTypeIcebergCompaction].Settings.IcebergCompaction.Strategy; got != CompactionStrategySort {
|
||||
t.Errorf("expected the strategy preserved, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
// Unreferenced file removal is configured on the bucket, so a bucket-level
|
||||
// disable has to surface here rather than a stale table status.
|
||||
func TestBuildJobStatusResponseHonoursBucketDisable(t *testing.T) {
|
||||
recorded := MaintenanceJobStatus{
|
||||
MaintenanceTypeIcebergUnreferencedFileRemoval: {Status: MaintenanceJobStatusSuccessful},
|
||||
}
|
||||
bucketConfig := MaintenanceConfiguration{
|
||||
MaintenanceTypeIcebergUnreferencedFileRemoval: {Status: MaintenanceStatusDisabled},
|
||||
}
|
||||
|
||||
status := buildJobStatusResponse(recorded, MergeMaintenanceConfiguration(bucketConfig, nil))
|
||||
if got := status[MaintenanceTypeIcebergUnreferencedFileRemoval].Status; got != MaintenanceJobStatusDisabled {
|
||||
t.Errorf("expected Disabled from the bucket configuration, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergeMaintenanceConfiguration(t *testing.T) {
|
||||
bucket := MaintenanceConfiguration{
|
||||
MaintenanceTypeIcebergUnreferencedFileRemoval: {Status: MaintenanceStatusEnabled},
|
||||
MaintenanceTypeIcebergCompaction: {Status: MaintenanceStatusEnabled},
|
||||
}
|
||||
table := MaintenanceConfiguration{
|
||||
MaintenanceTypeIcebergCompaction: {Status: MaintenanceStatusDisabled},
|
||||
}
|
||||
|
||||
merged := MergeMaintenanceConfiguration(bucket, table)
|
||||
if merged[MaintenanceTypeIcebergCompaction].Status != MaintenanceStatusDisabled {
|
||||
t.Error("expected the table entry to win")
|
||||
}
|
||||
if merged[MaintenanceTypeIcebergUnreferencedFileRemoval].Status != MaintenanceStatusEnabled {
|
||||
t.Error("expected the bucket-only entry retained")
|
||||
}
|
||||
if got := MergeMaintenanceConfiguration(nil, table); len(got) != 1 {
|
||||
t.Errorf("expected the table configuration passed through, got %v", got)
|
||||
}
|
||||
if got := MergeMaintenanceConfiguration(bucket, nil); len(got) != 2 {
|
||||
t.Errorf("expected the bucket configuration passed through, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateEntry rewrites the whole entry, so the precondition has to cover every
|
||||
// attribute this package stores — including the ones absent right now, which a
|
||||
// concurrent writer can create and this write would then delete.
|
||||
func TestSnapshotExtendedCoversEveryAttribute(t *testing.T) {
|
||||
extended := map[string][]byte{
|
||||
ExtendedKeyMetadata: []byte(`{"a":1}`),
|
||||
ExtendedKeyMaintenance: []byte(`{"icebergCompaction":{"status":"disabled"}}`),
|
||||
}
|
||||
|
||||
expected := SnapshotExtended(extended, ExtendedKeyMaintenanceStatus)
|
||||
|
||||
for key, want := range extended {
|
||||
if string(expected[key]) != string(want) {
|
||||
t.Errorf("attribute %s not carried into the precondition", key)
|
||||
}
|
||||
}
|
||||
for _, key := range s3tablesExtendedKeys {
|
||||
if _, ok := expected[key]; !ok {
|
||||
t.Errorf("attribute %s missing from the precondition", key)
|
||||
}
|
||||
}
|
||||
|
||||
// The absent ones are asserted absent, so a concurrent create fails the write.
|
||||
for _, key := range []string{ExtendedKeyMaintenanceStatus, ExtendedKeyPolicy, ExtendedKeyTags} {
|
||||
if got, ok := expected[key]; !ok || len(got) != 0 {
|
||||
t.Errorf("expected %s asserted absent, got %v", key, got)
|
||||
}
|
||||
}
|
||||
|
||||
// Mutating the snapshot must not disturb the entry it came from.
|
||||
expected[ExtendedKeyMetadata] = []byte("changed")
|
||||
if string(extended[ExtendedKeyMetadata]) != `{"a":1}` {
|
||||
t.Error("expected the source map left alone")
|
||||
}
|
||||
}
|
||||
|
||||
// The regression this closes: a maintenance configuration that did not exist
|
||||
// when the writer read the entry must still be asserted, or a first-time
|
||||
// disable lands between the read and the write and gets erased.
|
||||
func TestSnapshotExtendedAssertsAbsentMaintenanceKey(t *testing.T) {
|
||||
expected := SnapshotExtended(map[string][]byte{ExtendedKeyMetadata: []byte(`{}`)})
|
||||
|
||||
value, ok := expected[ExtendedKeyMaintenance]
|
||||
if !ok {
|
||||
t.Fatal("expected the maintenance key asserted even when absent")
|
||||
}
|
||||
if len(value) != 0 {
|
||||
t.Errorf("expected an absent assertion, got %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
// AWS bounds every numeric setting to 1..2147483647. Accepting anything else
|
||||
// would store a value the worker ignores or saturates, so the configuration
|
||||
// read back would not be the one that runs.
|
||||
func TestValidateMaintenanceSettingRange(t *testing.T) {
|
||||
compaction := func(v *int64) error {
|
||||
return validateMaintenanceValue(MaintenanceTypeIcebergCompaction, tableMaintenanceTypes, &MaintenanceConfigurationValue{
|
||||
Status: MaintenanceStatusEnabled,
|
||||
Settings: &MaintenanceSettings{IcebergCompaction: &IcebergCompactionSettings{TargetFileSizeMB: v}},
|
||||
})
|
||||
}
|
||||
|
||||
if err := compaction(nil); err != nil {
|
||||
t.Errorf("expected an unset setting accepted, got %v", err)
|
||||
}
|
||||
for _, v := range []int64{1, 512, maintenanceSettingMax} {
|
||||
if err := compaction(settingPtr(v)); err != nil {
|
||||
t.Errorf("expected %d accepted, got %v", v, err)
|
||||
}
|
||||
}
|
||||
for _, v := range []int64{0, -1, maintenanceSettingMax + 1, 1 << 62} {
|
||||
if err := compaction(settingPtr(v)); err == nil {
|
||||
t.Errorf("expected %d rejected", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateMaintenanceSettingRangeCoversEveryField(t *testing.T) {
|
||||
cases := map[string]*MaintenanceSettings{
|
||||
"minSnapshotsToKeep": {IcebergSnapshotManagement: &IcebergSnapshotManagementSettings{MinSnapshotsToKeep: settingPtr(0)}},
|
||||
"maxSnapshotAgeHours": {IcebergSnapshotManagement: &IcebergSnapshotManagementSettings{MaxSnapshotAgeHours: settingPtr(-5)}},
|
||||
"unreferencedDays": {IcebergUnreferencedFileRemoval: &IcebergUnreferencedFileRemovalSettings{UnreferencedDays: settingPtr(maintenanceSettingMax + 1)}},
|
||||
"nonCurrentDays": {IcebergUnreferencedFileRemoval: &IcebergUnreferencedFileRemovalSettings{NonCurrentDays: settingPtr(0)}},
|
||||
}
|
||||
|
||||
for name, settings := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if err := validateMaintenanceSettings(settings); err == nil {
|
||||
t.Errorf("expected %s out of range to be rejected", name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// An explicit zero has to be distinguishable from an omitted field, or it is
|
||||
// silently accepted and then ignored.
|
||||
func TestMaintenanceSettingsDistinguishZeroFromUnset(t *testing.T) {
|
||||
var decoded MaintenanceSettings
|
||||
if err := json.Unmarshal([]byte(`{"icebergCompaction":{"targetFileSizeMB":0}}`), &decoded); err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
}
|
||||
if decoded.IcebergCompaction.TargetFileSizeMB == nil {
|
||||
t.Fatal("expected an explicit zero to survive decoding")
|
||||
}
|
||||
|
||||
var omitted MaintenanceSettings
|
||||
if err := json.Unmarshal([]byte(`{"icebergCompaction":{}}`), &omitted); err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
}
|
||||
if omitted.IcebergCompaction.TargetFileSizeMB != nil {
|
||||
t.Error("expected an omitted field to stay unset")
|
||||
}
|
||||
}
|
||||
|
||||
// aws-cn and aws-us-gov ARNs are valid and must parse; the emitted ARN has to
|
||||
// use the partition its region belongs to so it round-trips.
|
||||
func TestARNPartitionsBeyondCommercial(t *testing.T) {
|
||||
for _, arn := range []string{
|
||||
"arn:aws:s3tables:us-east-1:123456789012:bucket/analytics",
|
||||
"arn:aws-cn:s3tables:cn-north-1:123456789012:bucket/analytics",
|
||||
"arn:aws-us-gov:s3tables:us-gov-west-1:123456789012:bucket/analytics",
|
||||
} {
|
||||
got, err := parseBucketNameFromARN(arn)
|
||||
if err != nil {
|
||||
t.Errorf("expected %s to parse, got %v", arn, err)
|
||||
continue
|
||||
}
|
||||
if got != "analytics" {
|
||||
t.Errorf("expected bucket analytics from %s, got %q", arn, got)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := parseBucketNameFromARN("arn:notaws:s3tables:us-east-1:123456789012:bucket/analytics"); err == nil {
|
||||
t.Error("expected a non-AWS partition to be rejected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestARNPartitionForRegion(t *testing.T) {
|
||||
for region, want := range map[string]string{
|
||||
"us-east-1": "aws",
|
||||
"eu-west-2": "aws",
|
||||
"cn-north-1": "aws-cn",
|
||||
"cn-northwest-1": "aws-cn",
|
||||
"us-gov-west-1": "aws-us-gov",
|
||||
"us-iso-east-1": "aws-iso",
|
||||
"us-isob-east-1": "aws-iso-b",
|
||||
"eu-isoe-west-1": "aws-iso-e",
|
||||
"us-isof-south-1": "aws-iso-f",
|
||||
"eusc-de-east-1": "aws-eusc",
|
||||
} {
|
||||
if got := arnPartitionForRegion(region); got != want {
|
||||
t.Errorf("region %s: expected partition %q, got %q", region, want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// An ARN this handler emits has to carry the partition its region belongs to,
|
||||
// not just parse back — a commercial ARN returned for a gov region still parses
|
||||
// but is wrong for IAM matching and for the caller.
|
||||
func TestGeneratedARNsUseTheRegionPartition(t *testing.T) {
|
||||
for region, partition := range map[string]string{
|
||||
"us-east-1": "aws",
|
||||
"cn-north-1": "aws-cn",
|
||||
"us-gov-west-1": "aws-us-gov",
|
||||
} {
|
||||
h := NewS3TablesHandler()
|
||||
h.SetRegion(region)
|
||||
|
||||
bucketARN := h.generateTableBucketARN(DefaultAccountID, "analytics")
|
||||
tableARN := h.generateTableARN(DefaultAccountID, "analytics", "sales/orders")
|
||||
viewARN := h.generateViewARN(DefaultAccountID, "analytics", "sales/v1")
|
||||
s3ARN := h.generateS3BucketARN("analytics")
|
||||
|
||||
for _, arn := range []string{bucketARN, tableARN, viewARN, s3ARN} {
|
||||
if !strings.HasPrefix(arn, "arn:"+partition+":") {
|
||||
t.Errorf("region %s: expected partition %q, got %s", region, partition, arn)
|
||||
}
|
||||
}
|
||||
|
||||
got, err := parseBucketNameFromARN(bucketARN)
|
||||
if err != nil {
|
||||
t.Errorf("generated ARN %s does not parse: %v", bucketARN, err)
|
||||
continue
|
||||
}
|
||||
if got != "analytics" {
|
||||
t.Errorf("expected analytics from %s, got %q", bucketARN, got)
|
||||
}
|
||||
|
||||
bucket, namespace, table, err := parseTableFromARN(tableARN)
|
||||
if err != nil {
|
||||
t.Errorf("generated table ARN %s does not parse: %v", tableARN, err)
|
||||
continue
|
||||
}
|
||||
if bucket != "analytics" || namespace != "sales" || table != "orders" {
|
||||
t.Errorf("unexpected parse of %s: %s/%s/%s", tableARN, bucket, namespace, table)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user