feat(admin): implement provider-specific storage configuration pages
Some checks failed
Build and Publish Docker Image / deploy (push) Has been cancelled
Some checks failed
Build and Publish Docker Image / deploy (push) Has been cancelled
Refactor the admin storage backend creation and editing flows to use provider-specific pages (e.g., `/admin/storage/new/sftp`) instead of a single generic form. This ensures only relevant fields are rendered for each storage provider (such as SFTP, S3, or WebDAV). Additionally: - Prevent mutation of the storage provider type during backend edits. - Add comprehensive unit tests for provider-specific rendering, edit validation, and CSRF/admin route protection.
This commit is contained in:
@@ -172,6 +172,157 @@ func TestSFTPStorageConfigValidation(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestStorageUpdateRejectsProviderMutation(t *testing.T) {
|
||||
service := newTestUploadService(t)
|
||||
cfg, err := service.Storage().CreateBackend(StorageBackendConfig{
|
||||
Provider: StorageProviderSFTP,
|
||||
Name: "SFTP",
|
||||
Host: "files.example.test",
|
||||
Username: "warpbox",
|
||||
Password: "secret",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateBackend returned error: %v", err)
|
||||
}
|
||||
if _, err := service.Storage().UpdateBackend(cfg.ID, StorageBackendConfig{
|
||||
Provider: StorageProviderS3,
|
||||
Name: "Mutated",
|
||||
Endpoint: "https://s3.example.test",
|
||||
Bucket: "bucket",
|
||||
AccessKey: "access",
|
||||
SecretKey: "secret",
|
||||
UseSSL: true,
|
||||
}); err == nil {
|
||||
t.Fatalf("UpdateBackend allowed provider mutation")
|
||||
}
|
||||
stored, err := service.Storage().BackendConfig(cfg.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("BackendConfig returned error: %v", err)
|
||||
}
|
||||
if stored.Provider != StorageProviderSFTP || stored.Type != StorageBackendSFTP {
|
||||
t.Fatalf("provider/type mutated despite error: %+v", stored)
|
||||
}
|
||||
if _, err := service.Storage().UpdateBackend(cfg.ID, StorageBackendConfig{
|
||||
Provider: StorageProviderSFTP,
|
||||
Type: StorageBackendS3,
|
||||
Name: "Mutated",
|
||||
Host: "files.example.test",
|
||||
Username: "warpbox",
|
||||
Password: "secret",
|
||||
}); err == nil {
|
||||
t.Fatalf("UpdateBackend allowed type mutation")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStorageUpdatePreservesSecretsWhenBlank(t *testing.T) {
|
||||
service := newTestUploadService(t)
|
||||
cfg, err := service.Storage().CreateBackend(StorageBackendConfig{
|
||||
Provider: StorageProviderSFTP,
|
||||
Name: "SFTP",
|
||||
Host: "files.example.test",
|
||||
Username: "warpbox",
|
||||
Password: "secret",
|
||||
PrivateKey: "private-key",
|
||||
HostKey: "host-key",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateBackend returned error: %v", err)
|
||||
}
|
||||
updated, err := service.Storage().UpdateBackend(cfg.ID, StorageBackendConfig{
|
||||
Provider: StorageProviderSFTP,
|
||||
Name: "SFTP renamed",
|
||||
Host: "files.example.test",
|
||||
Username: "warpbox",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("UpdateBackend returned error: %v", err)
|
||||
}
|
||||
if updated.Password != "secret" || updated.PrivateKey != "private-key" || updated.HostKey != "host-key" {
|
||||
t.Fatalf("blank secret fields were not preserved: %+v", updated)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContaboUpdateKeepsTLSAndPathStyleLocked(t *testing.T) {
|
||||
service := newTestUploadService(t)
|
||||
cfg, err := service.Storage().CreateBackend(StorageBackendConfig{
|
||||
Provider: StorageProviderContabo,
|
||||
Name: "Contabo",
|
||||
Endpoint: "https://eu2.contabostorage.com",
|
||||
Bucket: "My Main Bucket",
|
||||
AccessKey: "access",
|
||||
SecretKey: "secret",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateBackend returned error: %v", err)
|
||||
}
|
||||
updated, err := service.Storage().UpdateBackend(cfg.ID, StorageBackendConfig{
|
||||
Provider: StorageProviderContabo,
|
||||
Name: "Contabo",
|
||||
Endpoint: "https://eu2.contabostorage.com",
|
||||
Bucket: "My Main Bucket",
|
||||
AccessKey: "access",
|
||||
SecretKey: "secret",
|
||||
UseSSL: false,
|
||||
PathStyle: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("UpdateBackend returned error: %v", err)
|
||||
}
|
||||
if !updated.UseSSL || !updated.PathStyle {
|
||||
t.Fatalf("contabo TLS/path-style were not locked: %+v", updated)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStorageSpeedTestRequiresConnectionAndRuns(t *testing.T) {
|
||||
service := newTestUploadService(t)
|
||||
if _, err := service.Storage().StartSpeedTest(StorageBackendLocal, StorageSpeedModeSmall); err == nil {
|
||||
t.Fatalf("StartSpeedTest allowed speed test before connection test")
|
||||
}
|
||||
if _, err := service.Storage().TestBackend(StorageBackendLocal); err != nil {
|
||||
t.Fatalf("TestBackend local returned error: %v", err)
|
||||
}
|
||||
test, err := service.Storage().StartSpeedTest(StorageBackendLocal, StorageSpeedModeSmall)
|
||||
if err != nil {
|
||||
t.Fatalf("StartSpeedTest returned error: %v", err)
|
||||
}
|
||||
service.Storage().RunSpeedTest(testContext(), test.ID)
|
||||
tests, err := service.Storage().ListSpeedTests(StorageBackendLocal, 10)
|
||||
if err != nil {
|
||||
t.Fatalf("ListSpeedTests returned error: %v", err)
|
||||
}
|
||||
if len(tests) != 1 {
|
||||
t.Fatalf("speed tests len = %d, want 1", len(tests))
|
||||
}
|
||||
got := tests[0]
|
||||
if got.Status != StorageSpeedStatusDone || got.ProgressPercent != 100 || got.Stage != "complete" || got.BytesWritten == 0 || got.BytesRead == 0 || got.FilesWritten == 0 {
|
||||
t.Fatalf("speed test did not complete with metrics: %+v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomStorageSpeedTestUsesRequestedFiles(t *testing.T) {
|
||||
service := newTestUploadService(t)
|
||||
if _, err := service.Storage().TestBackend(StorageBackendLocal); err != nil {
|
||||
t.Fatalf("TestBackend local returned error: %v", err)
|
||||
}
|
||||
test, err := service.Storage().StartSpeedTestWithOptions(StorageBackendLocal, StorageSpeedTestOptions{
|
||||
Mode: StorageSpeedModeCustom,
|
||||
CustomFileCount: 3,
|
||||
CustomFileSizeMB: 0.001,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("StartSpeedTestWithOptions returned error: %v", err)
|
||||
}
|
||||
service.Storage().RunSpeedTest(testContext(), test.ID)
|
||||
tests, err := service.Storage().ListSpeedTests(StorageBackendLocal, 10)
|
||||
if err != nil {
|
||||
t.Fatalf("ListSpeedTests returned error: %v", err)
|
||||
}
|
||||
got := tests[0]
|
||||
if got.Mode != StorageSpeedModeCustom || got.CustomFileCount != 3 || got.CustomFileSizeMB != 0.001 || got.FilesWritten != 3 || got.Status != StorageSpeedStatusDone {
|
||||
t.Fatalf("custom speed test did not use requested files: %+v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSMBAndWebDAVStorageConfigValidation(t *testing.T) {
|
||||
service := newTestUploadService(t)
|
||||
smb, err := service.Storage().CreateS3Backend(StorageBackendConfig{
|
||||
|
||||
Reference in New Issue
Block a user