Added Testcases and updated code

This commit is contained in:
MitulShah1
2025-04-15 11:56:43 +05:30
parent 6ab1dd1c75
commit 4805f9f14b
6 changed files with 120 additions and 23 deletions

View File

@@ -131,7 +131,7 @@ jobs:
TEST_AZURITE_IMAGE: mcr.microsoft.com/azure-storage/azurite:latest TEST_AZURITE_IMAGE: mcr.microsoft.com/azure-storage/azurite:latest
TEST_AEROSPIKE_IMAGE: aerospike/aerospike-server:latest TEST_AEROSPIKE_IMAGE: aerospike/aerospike-server:latest
TEST_CLICKHOUSE_IMAGE: "clickhouse/clickhouse-server:23-alpine" TEST_CLICKHOUSE_IMAGE: "clickhouse/clickhouse-server:23-alpine"
TEST_CASSANDRA_IMAGE: "cassandra:4.1.3" TEST_CASSANDRA_IMAGE: "cassandra:latest"
TEST_COUCHBASE_IMAGE: "couchbase:enterprise-7.6.5" TEST_COUCHBASE_IMAGE: "couchbase:enterprise-7.6.5"
TEST_DYNAMODB_IMAGE: amazon/dynamodb-local:latest TEST_DYNAMODB_IMAGE: amazon/dynamodb-local:latest
TEST_MINIO_IMAGE: "docker.io/minio/minio:RELEASE.2024-08-17T01-24-54Z" TEST_MINIO_IMAGE: "docker.io/minio/minio:RELEASE.2024-08-17T01-24-54Z"

View File

@@ -26,5 +26,5 @@ jobs:
go-version: '${{ matrix.go-version }}' go-version: '${{ matrix.go-version }}'
- name: Run Test - name: Run Test
env: env:
TEST_CASSANDRA_IMAGE: cassandra:4.1.3 TEST_CASSANDRA_IMAGE: cassandra:latest
run: cd ./cassandra && go clean -testcache && go test ./... -v -race run: cd ./cassandra && go clean -testcache && go test ./... -v -race

View File

@@ -49,7 +49,7 @@ necessary for the client to operate correctly.
To start Cassandra using Docker, issue the following: To start Cassandra using Docker, issue the following:
```bash ```bash
docker run --name cassandra --network host -d cassandra:tag docker run --name cassandra --network host -d cassandra:latest
``` ```
After running this command you're ready to start using the storage and connecting to the database. After running this command you're ready to start using the storage and connecting to the database.
@@ -82,7 +82,7 @@ type Config struct {
// Keyspace is the name of the Cassandra keyspace to use. // Keyspace is the name of the Cassandra keyspace to use.
Keyspace string Keyspace string
// Optional. Default is kv_store // Optional. Default is kv_store
/// Table is the name of the Cassandra table to use. // Table is the name of the Cassandra table to use.
Table string Table string
// Optional. Default is Quorum // Optional. Default is Quorum
// Consistency is the Cassandra consistency level. // Consistency is the Cassandra consistency level.

View File

@@ -8,44 +8,48 @@ import (
"time" "time"
"github.com/gocql/gocql" "github.com/gocql/gocql"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/testcontainers/testcontainers-go"
cassandracontainer "github.com/testcontainers/testcontainers-go/modules/cassandra" cassandracontainer "github.com/testcontainers/testcontainers-go/modules/cassandra"
) )
const ( const (
// cassandraImage is the default image used for running cassandra in tests. // cassandraImage is the default image used for running cassandra in tests.
cassandraImage = "cassandra:4.1.3" cassandraImage = "cassandra:latest"
cassandraImageEnvVar string = "TEST_CASSANDRA_IMAGE" cassandraImageEnvVar string = "TEST_CASSANDRA_IMAGE"
cassandraPort = "9042/tcp" cassandraPort = "9042/tcp"
) )
// setupCassandraContainer creates a Cassandra container using the official module // newTestStore creates a Cassandra container using the official module
func setupCassandraContainer(ctx context.Context) (*cassandracontainer.CassandraContainer, string, error) { func newTestStore(t testing.TB) (*cassandracontainer.CassandraContainer, string, error) {
t.Helper()
img := cassandraImage img := cassandraImage
if imgFromEnv := os.Getenv(cassandraImageEnvVar); imgFromEnv != "" { if imgFromEnv := os.Getenv(cassandraImageEnvVar); imgFromEnv != "" {
img = imgFromEnv img = imgFromEnv
} }
cassandraContainer, err := cassandracontainer.Run(ctx, img) ctx := context.Background()
c, err := cassandracontainer.Run(ctx, img)
testcontainers.CleanupContainer(t, c)
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
// Get connection parameters // Get connection parameters
host, err := cassandraContainer.Host(ctx) host, err := c.Host(ctx)
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
mappedPort, err := cassandraContainer.MappedPort(ctx, cassandraPort) mappedPort, err := c.MappedPort(ctx, cassandraPort)
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
connectionURL := host + ":" + mappedPort.Port() connectionURL := host + ":" + mappedPort.Port()
return cassandraContainer, connectionURL, nil return c, connectionURL, nil
} }
// TestCassandraStorage tests the Cassandra storage implementation // TestCassandraStorage tests the Cassandra storage implementation
@@ -53,7 +57,7 @@ func TestCassandraStorage(t *testing.T) {
ctx := context.Background() ctx := context.Background()
// Start Cassandra container // Start Cassandra container
cassandraContainer, connectionURL, err := setupCassandraContainer(ctx) cassandraContainer, connectionURL, err := newTestStore(t)
if err != nil { if err != nil {
t.Fatalf("Failed to start Cassandra container: %v", err) t.Fatalf("Failed to start Cassandra container: %v", err)
} }
@@ -185,15 +189,15 @@ func testExpirableKeys(t *testing.T, connectionURL string) {
// Verify all keys exist initially // Verify all keys exist initially
value, err := store.Get("key_default_ttl") value, err := store.Get("key_default_ttl")
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, []byte("value1"), value) require.Equal(t, []byte("value1"), value)
value, err = store.Get("key_specific_ttl") value, err = store.Get("key_specific_ttl")
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, []byte("value2"), value) require.Equal(t, []byte("value2"), value)
value, err = store.Get("key_no_ttl") value, err = store.Get("key_no_ttl")
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, []byte("value3"), value) require.Equal(t, []byte("value3"), value)
// Wait for specific TTL to expire // Wait for specific TTL to expire
time.Sleep(1500 * time.Millisecond) time.Sleep(1500 * time.Millisecond)
@@ -201,15 +205,15 @@ func testExpirableKeys(t *testing.T, connectionURL string) {
// Specific TTL key should be gone, others should remain // Specific TTL key should be gone, others should remain
value, err = store.Get("key_specific_ttl") value, err = store.Get("key_specific_ttl")
require.NoError(t, err) require.NoError(t, err)
assert.Nil(t, value, "Key with 1s TTL should have expired") require.Nil(t, value, "Key with 1s TTL should have expired")
value, err = store.Get("key_default_ttl") value, err = store.Get("key_default_ttl")
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, []byte("value1"), value, "Key with default TTL should still exist") require.Equal(t, []byte("value1"), value, "Key with default TTL should still exist")
value, err = store.Get("key_no_ttl") value, err = store.Get("key_no_ttl")
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, []byte("value3"), value, "Key with no TTL should still exist") require.Equal(t, []byte("value3"), value, "Key with no TTL should still exist")
// Wait for default TTL to expire // Wait for default TTL to expire
time.Sleep(4 * time.Second) time.Sleep(4 * time.Second)
@@ -217,11 +221,11 @@ func testExpirableKeys(t *testing.T, connectionURL string) {
// Default TTL key should be gone, no TTL key should remain // Default TTL key should be gone, no TTL key should remain
value, err = store.Get("key_default_ttl") value, err = store.Get("key_default_ttl")
require.NoError(t, err) require.NoError(t, err)
assert.Nil(t, value, "Key with default TTL should have expired") require.Nil(t, value, "Key with default TTL should have expired")
value, err = store.Get("key_no_ttl") value, err = store.Get("key_no_ttl")
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, []byte("value3"), value, "Key with no TTL should still exist") require.Equal(t, []byte("value3"), value, "Key with no TTL should still exist")
} }
// / testReset tests the Reset method. // / testReset tests the Reset method.
@@ -326,3 +330,96 @@ func testConcurrentAccess(t *testing.T, connectionURL string) {
<-done <-done
} }
} }
func Benchmark_Cassandra_Set(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
c, connectionURL, err := newTestStore(b)
if err != nil {
b.Fatalf("Failed to start Cassandra container: %v", err)
}
defer func() {
if err := c.Terminate(context.TODO()); err != nil {
b.Logf("Failed to terminate container: %v", err)
}
}()
require.NoError(b, err)
// Create new storage
store := New(Config{
Hosts: []string{connectionURL},
Keyspace: "test_concurrent",
Table: "test_kv",
})
defer store.Close()
for i := 0; i < b.N; i++ {
err = store.Set("john", []byte("doe"), 0)
}
require.NoError(b, err)
}
func Benchmark_Cassandra_Get(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
c, connectionURL, err := newTestStore(b)
if err != nil {
b.Fatalf("Failed to start Cassandra container: %v", err)
}
defer func() {
if err := c.Terminate(context.TODO()); err != nil {
b.Logf("Failed to terminate container: %v", err)
}
}()
require.NoError(b, err)
// Create new storage
client := New(Config{
Hosts: []string{connectionURL},
Keyspace: "test_concurrent",
Table: "test_kv",
})
defer client.Close()
err = client.Set("john", []byte("doe"), 0)
for i := 0; i < b.N; i++ {
_, err = client.Get("john")
}
require.NoError(b, err)
}
func Benchmark_Cassandra_Set_And_Delete(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
c, connectionURL, err := newTestStore(b)
if err != nil {
b.Fatalf("Failed to start Cassandra container: %v", err)
}
defer func() {
if err := c.Terminate(context.TODO()); err != nil {
b.Logf("Failed to terminate container: %v", err)
}
}()
require.NoError(b, err)
// Create new storage
client := New(Config{
Hosts: []string{connectionURL},
Keyspace: "test_concurrent",
Table: "test_kv",
})
defer client.Close()
for i := 0; i < b.N; i++ {
_ = client.Set("john", []byte("doe"), 0)
err = client.Delete("john")
}
require.NoError(b, err)
}

View File

@@ -15,7 +15,7 @@ type Config struct {
// Keyspace is the name of the Cassandra keyspace to use. // Keyspace is the name of the Cassandra keyspace to use.
Keyspace string Keyspace string
// Optional. Default is kv_store // Optional. Default is kv_store
/// Table is the name of the Cassandra table to use. // Table is the name of the Cassandra table to use.
Table string Table string
// Optional. Default is Quorum // Optional. Default is Quorum
// Consistency is the Cassandra consistency level. // Consistency is the Cassandra consistency level.

View File

@@ -1,4 +1,4 @@
module github.com/gofiber/storage/cassandra/v2 module github.com/gofiber/storage/cassandra
go 1.23.0 go 1.23.0