package storage_test import ( "errors" "reflect" "testing" "sneak.berlin/go/vaultik/internal/storage" ) // TestParseStorageURLValid checks that each supported scheme parses into // the expected fields, since those fields decide which backend is built. func TestParseStorageURLValid(t *testing.T) { t.Parallel() const bucket = "mybucket" cases := []struct { name string raw string want *storage.URL }{ { name: "file absolute path", raw: "file:///var/backups/vaultik", want: &storage.URL{Scheme: "file", Prefix: "/var/backups/vaultik"}, }, { name: "s3 bucket and prefix, ssl defaults on", raw: "s3://mybucket/backups/host", want: &storage.URL{ Scheme: "s3", Bucket: bucket, Prefix: "backups/host", UseSSL: true, }, }, { name: "s3 bucket only", raw: "s3://mybucket", want: &storage.URL{Scheme: "s3", Bucket: bucket, UseSSL: true}, }, { name: "s3 with endpoint, region, ssl off", raw: "s3://mybucket?endpoint=minio.example.com®ion=us-west-2&ssl=false", want: &storage.URL{ Scheme: "s3", Bucket: bucket, Endpoint: "minio.example.com", Region: "us-west-2", UseSSL: false, }, }, { name: "rclone remote and path", raw: "rclone://gdrive/backups/host", want: &storage.URL{ Scheme: "rclone", RcloneRemote: "gdrive", Prefix: "backups/host", }, }, { name: "rclone remote only", raw: "rclone://gdrive", want: &storage.URL{Scheme: "rclone", RcloneRemote: "gdrive"}, }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { t.Parallel() got, err := storage.ParseStorageURL(tc.raw) if err != nil { t.Fatalf("ParseStorageURL(%q) returned error: %v", tc.raw, err) } if !reflect.DeepEqual(got, tc.want) { t.Errorf("ParseStorageURL(%q) = %+v, want %+v", tc.raw, got, tc.want) } }) } } // TestParseStorageURLErrors checks that empty, missing, and unknown-scheme // inputs fail with the documented sentinel errors instead of parsing to a // wrong destination. func TestParseStorageURLErrors(t *testing.T) { t.Parallel() cases := []struct { name string raw string wantErr error }{ {"empty url", "", storage.ErrEmptyStorageURL}, {"file empty path", "file://", storage.ErrEmptyFilePath}, {"s3 missing bucket", "s3://", storage.ErrMissingBucket}, {"s3 missing bucket with path", "s3:///justprefix", storage.ErrMissingBucket}, {"rclone missing remote", "rclone://", storage.ErrMissingRemote}, {"unknown scheme", "gs://bucket/x", storage.ErrUnsupportedScheme}, {"no scheme", "/local/path", storage.ErrUnsupportedScheme}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { t.Parallel() _, err := storage.ParseStorageURL(tc.raw) if !errors.Is(err, tc.wantErr) { t.Errorf("ParseStorageURL(%q) error = %v, want %v", tc.raw, err, tc.wantErr) } }) } }