145 lines
4.6 KiB
Go
145 lines
4.6 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"gitea.maximumdirect.net/eric/narratio/internal/adapters/storage"
|
|
"gitea.maximumdirect.net/eric/narratio/internal/config"
|
|
)
|
|
|
|
func TestNewCommandObjectStoreLoadsSecretsBeforeFactory(t *testing.T) {
|
|
accessKeyEnv := "NARRATIO_TEST_COMMAND_STORE_KEY_ID"
|
|
secretKeyEnv := "NARRATIO_TEST_COMMAND_STORE_SECRET"
|
|
restoreEnvAfterTest(t, accessKeyEnv, secretKeyEnv)
|
|
|
|
secretsDir := t.TempDir()
|
|
mustWriteSecretFile(t, filepath.Join(secretsDir, accessKeyEnv), "loaded-key-id\n")
|
|
mustWriteSecretFile(t, filepath.Join(secretsDir, secretKeyEnv), "loaded-secret\n")
|
|
|
|
cfg := commandObjectStoreTestConfig(secretsDir)
|
|
fake := &storage.FakeBackend{}
|
|
called := false
|
|
origStoreFn := newObjectStoreFromConfigFn
|
|
newObjectStoreFromConfigFn = func(context.Context, *config.Config) (storage.ObjectStore, error) {
|
|
called = true
|
|
if got := os.Getenv(accessKeyEnv); got != "loaded-key-id" {
|
|
return nil, errors.New("access key was not loaded before object store init")
|
|
}
|
|
if got := os.Getenv(secretKeyEnv); got != "loaded-secret" {
|
|
return nil, errors.New("secret key was not loaded before object store init")
|
|
}
|
|
return fake, nil
|
|
}
|
|
t.Cleanup(func() {
|
|
newObjectStoreFromConfigFn = origStoreFn
|
|
})
|
|
|
|
store, err := newCommandObjectStore(context.Background(), cfg, nil)
|
|
if err != nil {
|
|
t.Fatalf("newCommandObjectStore() error = %v", err)
|
|
}
|
|
if store != fake {
|
|
t.Fatalf("store = %#v, want fake backend", store)
|
|
}
|
|
if !called {
|
|
t.Fatal("object store factory was not called")
|
|
}
|
|
}
|
|
|
|
func TestNewCommandObjectStorePreservesExistingEnv(t *testing.T) {
|
|
accessKeyEnv := "NARRATIO_TEST_COMMAND_STORE_EXISTING_KEY_ID"
|
|
secretKeyEnv := "NARRATIO_TEST_COMMAND_STORE_EXISTING_SECRET"
|
|
t.Setenv(accessKeyEnv, "existing-key-id")
|
|
t.Setenv(secretKeyEnv, "existing-secret")
|
|
|
|
secretsDir := t.TempDir()
|
|
mustWriteSecretFile(t, filepath.Join(secretsDir, accessKeyEnv), "file-key-id\n")
|
|
mustWriteSecretFile(t, filepath.Join(secretsDir, secretKeyEnv), "file-secret\n")
|
|
|
|
cfg := commandObjectStoreTestConfig(secretsDir)
|
|
origStoreFn := newObjectStoreFromConfigFn
|
|
newObjectStoreFromConfigFn = func(context.Context, *config.Config) (storage.ObjectStore, error) {
|
|
if got := os.Getenv(accessKeyEnv); got != "existing-key-id" {
|
|
return nil, errors.New("existing access key was overwritten")
|
|
}
|
|
if got := os.Getenv(secretKeyEnv); got != "existing-secret" {
|
|
return nil, errors.New("existing secret key was overwritten")
|
|
}
|
|
return &storage.FakeBackend{}, nil
|
|
}
|
|
t.Cleanup(func() {
|
|
newObjectStoreFromConfigFn = origStoreFn
|
|
})
|
|
|
|
if _, err := newCommandObjectStore(context.Background(), cfg, nil); err != nil {
|
|
t.Fatalf("newCommandObjectStore() error = %v", err)
|
|
}
|
|
}
|
|
|
|
func TestNewCommandObjectStoreSecretErrorStopsFactory(t *testing.T) {
|
|
cfg := commandObjectStoreTestConfig(filepath.Join(t.TempDir(), "missing"))
|
|
called := false
|
|
origStoreFn := newObjectStoreFromConfigFn
|
|
newObjectStoreFromConfigFn = func(context.Context, *config.Config) (storage.ObjectStore, error) {
|
|
called = true
|
|
return &storage.FakeBackend{}, nil
|
|
}
|
|
t.Cleanup(func() {
|
|
newObjectStoreFromConfigFn = origStoreFn
|
|
})
|
|
|
|
_, err := newCommandObjectStore(context.Background(), cfg, nil)
|
|
if err == nil {
|
|
t.Fatal("expected error, got nil")
|
|
}
|
|
if called {
|
|
t.Fatal("object store factory was called after secret load failure")
|
|
}
|
|
if !strings.Contains(err.Error(), "load secrets from files") {
|
|
t.Fatalf("error = %q, want secret loading context", err.Error())
|
|
}
|
|
}
|
|
|
|
func TestNewCommandObjectStoreFactoryErrorIsContextual(t *testing.T) {
|
|
cfg := commandObjectStoreTestConfig("")
|
|
origStoreFn := newObjectStoreFromConfigFn
|
|
newObjectStoreFromConfigFn = func(context.Context, *config.Config) (storage.ObjectStore, error) {
|
|
return nil, errors.New("factory boom")
|
|
}
|
|
t.Cleanup(func() {
|
|
newObjectStoreFromConfigFn = origStoreFn
|
|
})
|
|
|
|
_, err := newCommandObjectStore(context.Background(), cfg, nil)
|
|
if err == nil {
|
|
t.Fatal("expected error, got nil")
|
|
}
|
|
if !strings.Contains(err.Error(), "initialize object store backend") || !strings.Contains(err.Error(), "factory boom") {
|
|
t.Fatalf("error = %q, want factory context", err.Error())
|
|
}
|
|
}
|
|
|
|
func commandObjectStoreTestConfig(secretsDir string) *config.Config {
|
|
cfg := &config.Config{
|
|
Pipeline: &config.PipelineConfig{
|
|
Storage: config.StorageConfig{
|
|
Backend: "s3",
|
|
S3: &config.StorageS3Config{
|
|
Bucket: "test-bucket",
|
|
AccessKeyIDEnv: "NARRATIO_TEST_COMMAND_STORE_KEY_ID",
|
|
SecretKeyEnv: "NARRATIO_TEST_COMMAND_STORE_SECRET",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
if strings.TrimSpace(secretsDir) != "" {
|
|
cfg.Pipeline.Secrets = &config.SecretsConfig{EnvDir: secretsDir}
|
|
}
|
|
return cfg
|
|
}
|