mirror of
https://github.com/gofiber/storage.git
synced 2025-10-06 00:57:38 +08:00
Added Testcases and updated code
This commit is contained in:
2
.github/workflows/benchmark.yml
vendored
2
.github/workflows/benchmark.yml
vendored
@@ -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"
|
||||||
|
2
.github/workflows/test-cassandra.yml
vendored
2
.github/workflows/test-cassandra.yml
vendored
@@ -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
|
||||||
|
@@ -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.
|
||||||
|
@@ -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)
|
||||||
|
}
|
||||||
|
@@ -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.
|
||||||
|
@@ -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
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user