diff --git a/builtin/logical/cassandra/backend_test.go b/builtin/logical/cassandra/backend_test.go index cfeb329b8..bb460ad1c 100644 --- a/builtin/logical/cassandra/backend_test.go +++ b/builtin/logical/cassandra/backend_test.go @@ -4,73 +4,76 @@ import ( "fmt" "log" "os" + "strconv" "sync" "testing" - "time" + "github.com/gocql/gocql" "github.com/hashicorp/vault/logical" logicaltest "github.com/hashicorp/vault/logical/testing" "github.com/mitchellh/mapstructure" - dockertest "gopkg.in/ory-am/dockertest.v2" + dockertest "gopkg.in/ory-am/dockertest.v3" ) var ( testImagePull sync.Once ) -func prepareTestContainer(t *testing.T, s logical.Storage, b logical.Backend) (cid dockertest.ContainerID, retURL string) { +func prepareCassandraTestContainer(t *testing.T) (func(), string, int) { if os.Getenv("CASSANDRA_HOST") != "" { - return "", os.Getenv("CASSANDRA_HOST") + return func() {}, os.Getenv("CASSANDRA_HOST"), 0 } - // Without this the checks for whether the container has started seem to - // never actually pass. There's really no reason to expose the test - // containers, so don't. - dockertest.BindDockerToLocalhost = "yep" - - testImagePull.Do(func() { - dockertest.Pull("cassandra") - }) + pool, err := dockertest.NewPool("") + if err != nil { + t.Fatalf("Failed to connect to docker: %s", err) + } cwd, _ := os.Getwd() + cassandraMountPath := fmt.Sprintf("%s/test-fixtures/:/etc/cassandra/", cwd) - cid, connErr := dockertest.ConnectToCassandra("latest", 60, 1000*time.Millisecond, func(connURL string) bool { - // This will cause a validation to run - resp, err := b.HandleRequest(&logical.Request{ - Storage: s, - Operation: logical.UpdateOperation, - Path: "config/connection", - Data: map[string]interface{}{ - "hosts": connURL, - "username": "cassandra", - "password": "cassandra", - "protocol_version": 3, - }, - }) - if err != nil || (resp != nil && resp.IsError()) { - // It's likely not up and running yet, so return false and try again - return false - } - - retURL = connURL - return true - }, []string{"-v", cwd + "/test-fixtures/:/etc/cassandra/"}...) - - if connErr != nil { - if cid != "" { - cid.KillRemove() - } - t.Fatalf("could not connect to database: %v", connErr) + ro := &dockertest.RunOptions{ + Repository: "cassandra", + Tag: "latest", + Env: []string{"CASSANDRA_BROADCAST_ADDRESS=127.0.0.1"}, + Mounts: []string{cassandraMountPath}, } - - return -} - -func cleanupTestContainer(t *testing.T, cid dockertest.ContainerID) { - err := cid.KillRemove() + resource, err := pool.RunWithOptions(ro) if err != nil { - t.Fatal(err) + t.Fatalf("Could not start local cassandra docker container: %s", err) } + + cleanup := func() { + err := pool.Purge(resource) + if err != nil { + t.Fatalf("Failed to cleanup local container: %s", err) + } + } + + port, _ := strconv.Atoi(resource.GetPort("9042/tcp")) + address := fmt.Sprintf("127.0.0.1:%d", port) + + // exponential backoff-retry + if err = pool.Retry(func() error { + clusterConfig := gocql.NewCluster(address) + clusterConfig.Authenticator = gocql.PasswordAuthenticator{ + Username: "cassandra", + Password: "cassandra", + } + clusterConfig.ProtoVersion = 4 + clusterConfig.Port = port + + session, err := clusterConfig.CreateSession() + if err != nil { + return fmt.Errorf("error creating session: %s", err) + } + defer session.Close() + return nil + }); err != nil { + cleanup() + t.Fatalf("Could not connect to cassandra docker container: %s", err) + } + return cleanup, address, port } func TestBackend_basic(t *testing.T) { @@ -84,10 +87,8 @@ func TestBackend_basic(t *testing.T) { t.Fatal(err) } - cid, hostname := prepareTestContainer(t, config.StorageView, b) - if cid != "" { - defer cleanupTestContainer(t, cid) - } + cleanup, hostname, _ := prepareCassandraTestContainer(t) + defer cleanup() logicaltest.Test(t, logicaltest.TestCase{ Backend: b, @@ -110,10 +111,8 @@ func TestBackend_roleCrud(t *testing.T) { t.Fatal(err) } - cid, hostname := prepareTestContainer(t, config.StorageView, b) - if cid != "" { - defer cleanupTestContainer(t, cid) - } + cleanup, hostname, _ := prepareCassandraTestContainer(t) + defer cleanup() logicaltest.Test(t, logicaltest.TestCase{ Backend: b, diff --git a/builtin/logical/cassandra/test-fixtures/cassandra.yaml b/builtin/logical/cassandra/test-fixtures/cassandra.yaml index 5b12c8cf4..004c04e68 100644 --- a/builtin/logical/cassandra/test-fixtures/cassandra.yaml +++ b/builtin/logical/cassandra/test-fixtures/cassandra.yaml @@ -421,7 +421,7 @@ seed_provider: parameters: # seeds is actually a comma-delimited list of addresses. # Ex: ",," - - seeds: "172.17.0.3" + - seeds: "127.0.0.1" # For workloads with more data than can fit in memory, Cassandra's # bottleneck will be reads that need to fetch data from @@ -572,7 +572,7 @@ ssl_storage_port: 7001 # # Setting listen_address to 0.0.0.0 is always wrong. # -listen_address: 172.17.0.3 +listen_address: 172.17.0.2 # Set listen_address OR listen_interface, not both. Interfaces must correspond # to a single address, IP aliasing is not supported. @@ -586,7 +586,7 @@ listen_address: 172.17.0.3 # Address to broadcast to other Cassandra nodes # Leaving this blank will set it to the same value as listen_address -broadcast_address: 172.17.0.3 +broadcast_address: 127.0.0.1 # When using multiple physical network interfaces, set this # to true to listen on broadcast_address in addition to @@ -668,7 +668,7 @@ rpc_port: 9160 # be set to 0.0.0.0. If left blank, this will be set to the value of # rpc_address. If rpc_address is set to 0.0.0.0, broadcast_rpc_address must # be set. -broadcast_rpc_address: 172.17.0.3 +broadcast_rpc_address: 127.0.0.1 # enable or disable keepalive on rpc/native connections rpc_keepalive: true