//go:build integration package integration import ( "context" "testing" "time" "github.com/mulgadc/spinifex/spinifex/bootstrap/config" ec2volume "github.com/mulgadc/spinifex/spinifex/domains/ec2/volume" "github.com/mulgadc/spinifex/spinifex/providers/ebs" "github.com/mulgadc/spinifex/spinifex/providers/ebs/viperblock" "github.com/mulgadc/spinifex/spinifex/providers/objectstore" testpredastore "github.com/mulgadc/spinifex/tests/fixtures/predastore" "github.com/stretchr/testify/require" ) // testVolumeBucket is the real predastore bucket StartVolumeDaemonLite's // VolumeServiceImpl is wired against. Unlike testPredastoreBucket // (memory-backed, name never resolved — see StartDaemonLite), this bucket // genuinely exists on the shared predastore fixture: viperblock's S3 backend // dials it for real, so chunk uploads and config.json persistence are real. const testVolumeBucket = "integration-test-volumes" // testProviderNodeName names the node the in-process provider answers as. Only // publish and unpublish are node-addressed, and nothing here publishes, but an // empty name makes the provider log a warning about attachments it cannot serve. const testProviderNodeName = "integration-node" // providerRequestTimeout bounds a control-plane call to the provider. Generous // because the first CreateVolume pays the real predastore's cold start. const providerRequestTimeout = 60 * time.Second // StartVolumeDaemonLite subscribes a real ec2volume.VolumeServiceImpl // — the same production code a live daemon runs (daemon/daemon_handlers_volume.go) // — to its ec2.* subjects, backed by a // real predastore daemon (testpredastore.Start) rather than the memory-backed // stores DaemonLite's other resources use. // // This is deliberately a separate opt-in wiring rather than part of // StartDaemonLite: CreateVolume constructs viperblock.New and calls // Backend.Init() unconditionally (domains/ec2/volume/service_impl.go), so it // needs a reachable Predastore to do anything beyond input validation, while // every other DaemonLite-wired resource is happy with an in-memory stand-in. // Only a test that actually exercises volume storage should pay the shared // predastore daemon's startup cost. // // Must be called before a test issues a volume request; like // StartECRDaemonLite it wires its own subjects independent of StartDaemonLite. func StartVolumeDaemonLite(t *testing.T, gw *Gateway) *ec2volume.VolumeServiceImpl { t.Helper() fixture := testpredastore.Start(t) store := objectstore.NewS3ObjectStoreFromConfig(fixture.Host, fixture.Region, fixture.AccessKey, fixture.SecretKey) require.NoError(t, store.EnsureBucket(context.Background(), testVolumeBucket), "ensure volume test bucket") cfg := &config.Config{ AZ: testAZ, Predastore: config.PredastoreConfig{ Host: fixture.Host, Bucket: testVolumeBucket, Region: fixture.Region, AccessKey: fixture.AccessKey, SecretKey: fixture.SecretKey, }, // Real WAL/chunk files land here (viperblock.VB.BaseDir); a per-test // dir is safe since only the predastore daemon itself is shared. WalDir: t.TempDir(), } nc := gw.NATSConn svc := ec2volume.NewVolumeServiceImplWithStore(cfg, store, nc) // The control plane no longer builds volumes itself; it asks a provider. // Serve the provider contract from viperblockd against the same fixture, // so the blocks are still written by real viperblock to real predastore. require.NoError(t, viperblock.RegisterProviderSubjects(&viperblock.Config{ S3Host: "https://" + fixture.Host, Bucket: testVolumeBucket, Region: fixture.Region, AccessKey: fixture.AccessKey, SecretKey: fixture.SecretKey, BaseDir: cfg.WalDir, NodeName: testProviderNodeName, }, nc), "register provider subjects") svc.SetEBSProvider(ebsprovider.NewNATSProvider(nc, providerRequestTimeout)) subscribeServiceMethods(t, nc, "ec2", svc) return svc }