diff --git a/cache/driver.go b/cache/driver.go
index 103418522..a41b8fb71 100644
--- a/cache/driver.go
+++ b/cache/driver.go
@@ -1,7 +1,6 @@
 package cache
 
 import (
-	"context"
 	"fmt"
 
 	"github.com/gookit/color"
@@ -28,8 +27,6 @@ func NewDriverImpl(config config.Config) *DriverImpl {
 func (d *DriverImpl) New(store string) cache.Driver {
 	driver := d.config.GetString(fmt.Sprintf("cache.stores.%s.driver", store))
 	switch driver {
-	case "redis":
-		return d.redis(store)
 	case "memory":
 		return d.memory()
 	case "custom":
@@ -40,19 +37,6 @@ func (d *DriverImpl) New(store string) cache.Driver {
 	}
 }
 
-func (d *DriverImpl) redis(store string) cache.Driver {
-	redis, err := NewRedis(context.Background(), d.config, store)
-	if err != nil {
-		color.Redf("[Cache] Init redis driver error: %v\n", err)
-		return nil
-	}
-	if redis == nil {
-		return nil
-	}
-
-	return redis
-}
-
 func (d *DriverImpl) memory() cache.Driver {
 	memory, err := NewMemory(d.config)
 	if err != nil {
diff --git a/cache/driver_test.go b/cache/driver_test.go
index 7110b8d0d..40de55ca5 100644
--- a/cache/driver_test.go
+++ b/cache/driver_test.go
@@ -2,47 +2,23 @@ package cache
 
 import (
 	"context"
-	"log"
 	"testing"
 	"time"
 
-	"github.com/ory/dockertest/v3"
 	"github.com/stretchr/testify/suite"
 
 	"github.com/goravel/framework/contracts/cache"
 	configmock "github.com/goravel/framework/contracts/config/mocks"
-	testingdocker "github.com/goravel/framework/testing/docker"
 )
 
 type DriverTestSuite struct {
 	suite.Suite
-	driver      *DriverImpl
-	mockConfig  *configmock.Config
-	stores      map[string]cache.Driver
-	redisDocker *dockertest.Resource
+	driver     *DriverImpl
+	mockConfig *configmock.Config
 }
 
 func TestDriverTestSuite(t *testing.T) {
-	redisPool, redisDocker, redisStore, err := getRedisDocker()
-	if err != nil {
-		log.Fatalf("Get redis store error: %s", err)
-	}
-	memoryStore, err := getMemoryStore()
-	if err != nil {
-		log.Fatalf("Get memory store error: %s", err)
-	}
-
-	suite.Run(t, &DriverTestSuite{
-		stores: map[string]cache.Driver{
-			"redis":  redisStore,
-			"memory": memoryStore,
-		},
-		redisDocker: redisDocker,
-	})
-
-	if err := redisPool.Purge(redisDocker); err != nil {
-		log.Fatalf("Could not purge resource: %s", err)
-	}
+	suite.Run(t, new(DriverTestSuite))
 }
 
 func (s *DriverTestSuite) SetupTest() {
@@ -55,43 +31,6 @@ func (s *DriverTestSuite) TestMemory() {
 	s.NotNil(s.driver.memory())
 }
 
-func (s *DriverTestSuite) TestRedis() {
-	tests := []struct {
-		description string
-		setup       func()
-		expectErr   bool
-	}{
-		{
-			description: "success",
-			setup: func() {
-				s.mockConfig.On("GetString", "cache.stores.redis.connection", "default").Return("default").Once()
-				s.mockConfig.On("GetString", "database.redis.default.host").Return("localhost").Once()
-				s.mockConfig.On("GetString", "database.redis.default.port").Return(s.redisDocker.GetPort("6379/tcp")).Once()
-				s.mockConfig.On("GetString", "database.redis.default.password").Return("").Once()
-				s.mockConfig.On("GetInt", "database.redis.default.database").Return(0).Once()
-				s.mockConfig.On("GetString", "cache.prefix").Return("goravel_cache").Once()
-			},
-		},
-		{
-			description: "error",
-			setup: func() {
-				s.mockConfig.On("GetString", "cache.stores.redis.connection", "default").Return("default").Once()
-				s.mockConfig.On("GetString", "database.redis.default.host").Return("").Once()
-			},
-			expectErr: true,
-		},
-	}
-
-	for _, test := range tests {
-		s.Run(test.description, func() {
-			test.setup()
-			redis := s.driver.redis("redis")
-			s.Equal(test.expectErr, redis == nil)
-			s.mockConfig.AssertExpectations(s.T())
-		})
-	}
-}
-
 func (s *DriverTestSuite) TestCustom() {
 	s.mockConfig.On("Get", "cache.stores.store.via").Return(&Store{}).Once()
 
@@ -103,470 +42,26 @@ func (s *DriverTestSuite) TestCustom() {
 }
 
 func (s *DriverTestSuite) TestStore() {
-	mockConfig := &configmock.Config{}
-	mockConfig.On("GetString", "cache.stores.memory.driver").Return("memory").Once()
-	mockConfig.On("GetString", "cache.prefix").Return("goravel_cache").Once()
+	s.mockConfig.On("GetString", "cache.stores.memory.driver").Return("memory").Once()
+	s.mockConfig.On("GetString", "cache.prefix").Return("goravel_cache").Once()
 
-	memory := NewApplication(mockConfig, "memory")
+	memory := NewApplication(s.mockConfig, "memory")
 	s.NotNil(memory)
 	s.True(memory.Add("hello", "goravel", 5*time.Second))
 	s.Equal("goravel", memory.GetString("hello"))
 
-	mockConfig.On("GetString", "cache.stores.redis.driver").Return("redis").Once()
-	mockConfig.On("GetString", "cache.stores.redis.connection", "default").Return("default").Once()
-	mockConfig.On("GetString", "database.redis.default.host").Return("localhost").Once()
-	mockConfig.On("GetString", "database.redis.default.port").Return(s.redisDocker.GetPort("6379/tcp")).Once()
-	mockConfig.On("GetString", "database.redis.default.password").Return("").Once()
-	mockConfig.On("GetInt", "database.redis.default.database").Return(0).Once()
-	mockConfig.On("GetString", "cache.prefix").Return("goravel_cache").Once()
+	s.mockConfig.On("GetString", "cache.stores.custom.driver").Return("custom").Once()
+	s.mockConfig.On("Get", "cache.stores.custom.via").Return(&Store{}).Once()
 
-	redis := memory.Store("redis")
-	s.NotNil(redis)
-	s.Equal("", redis.GetString("hello"))
-	s.True(redis.Add("hello", "world", 5*time.Second))
-	s.Equal("world", redis.GetString("hello"))
+	custom := memory.Store("custom")
+	s.NotNil(custom)
+	s.Equal("", custom.GetString("hello"))
+	s.True(custom.Add("hello", "world", 5*time.Second))
+	s.Equal("", custom.GetString("hello"))
 
 	s.Equal("goravel", memory.GetString("hello"))
 
-	mockConfig.AssertExpectations(s.T())
-}
-
-func (s *DriverTestSuite) TestAdd() {
-	for name, store := range s.stores {
-		s.Run(name, func() {
-			s.Nil(store.Put("name", "Goravel", 1*time.Second))
-			s.False(store.Add("name", "World", 1*time.Second))
-			s.True(store.Add("name1", "World", 1*time.Second))
-			s.True(store.Has("name1"))
-			time.Sleep(2 * time.Second)
-			s.False(store.Has("name1"))
-			s.True(store.Flush())
-		})
-	}
-}
-
-func (s *DriverTestSuite) TestDecrement() {
-	for name, store := range s.stores {
-		s.Run(name, func() {
-			res, err := store.Decrement("decrement")
-			s.Equal(-1, res)
-			s.Nil(err)
-
-			s.Equal(-1, store.GetInt("decrement"))
-
-			res, err = store.Decrement("decrement", 2)
-			s.Equal(-3, res)
-			s.Nil(err)
-
-			res, err = store.Decrement("decrement1", 2)
-			s.Equal(-2, res)
-			s.Nil(err)
-
-			s.Equal(-2, store.GetInt("decrement1"))
-
-			s.True(store.Add("decrement2", 4, 2*time.Second))
-			res, err = store.Decrement("decrement2")
-			s.Equal(3, res)
-			s.Nil(err)
-
-			res, err = store.Decrement("decrement2", 2)
-			s.Equal(1, res)
-			s.Nil(err)
-		})
-	}
-}
-
-func (s *DriverTestSuite) TestForever() {
-	for name, store := range s.stores {
-		s.Run(name, func() {
-			s.True(store.Forever("name", "Goravel"))
-			s.Equal("Goravel", store.Get("name", "").(string))
-			s.True(store.Flush())
-		})
-	}
-}
-
-func (s *DriverTestSuite) TestForget() {
-	for name, store := range s.stores {
-		s.Run(name, func() {
-			val := store.Forget("test-forget")
-			s.True(val)
-
-			err := store.Put("test-forget", "goravel", 5*time.Second)
-			s.Nil(err)
-			s.True(store.Forget("test-forget"))
-		})
-	}
-}
-
-func (s *DriverTestSuite) TestFlush() {
-	for name, store := range s.stores {
-		s.Run(name, func() {
-			s.Nil(store.Put("test-flush", "goravel", 5*time.Second))
-			s.Equal("goravel", store.Get("test-flush", nil).(string))
-
-			s.True(store.Flush())
-			s.False(store.Has("test-flush"))
-		})
-	}
-}
-
-func (s *DriverTestSuite) TestGet() {
-	for name, store := range s.stores {
-		s.Run(name, func() {
-			s.Nil(store.Put("name", "Goravel", 1*time.Second))
-			s.Equal("Goravel", store.Get("name", "").(string))
-			s.Equal("World", store.Get("name1", "World").(string))
-			s.Equal("World1", store.Get("name2", func() any {
-				return "World1"
-			}).(string))
-			s.True(store.Forget("name"))
-			s.True(store.Flush())
-		})
-	}
-}
-
-func (s *DriverTestSuite) TestGetBool() {
-	for name, store := range s.stores {
-		s.Run(name, func() {
-			s.Equal(true, store.GetBool("test-get-bool", true))
-			s.Nil(store.Put("test-get-bool", true, 2*time.Second))
-			s.Equal(true, store.GetBool("test-get-bool", false))
-		})
-	}
-}
-
-func (s *DriverTestSuite) TestGetInt() {
-	for name, store := range s.stores {
-		s.Run(name, func() {
-			s.Equal(2, store.GetInt("test-get-int", 2))
-			s.Nil(store.Put("test-get-int", 3, 2*time.Second))
-			s.Equal(3, store.GetInt("test-get-int", 2))
-		})
-	}
-}
-
-func (s *DriverTestSuite) TestGetString() {
-	for name, store := range s.stores {
-		s.Run(name, func() {
-			s.Equal("2", store.GetString("test-get-string", "2"))
-			s.Nil(store.Put("test-get-string", "3", 2*time.Second))
-			s.Equal("3", store.GetString("test-get-string", "2"))
-		})
-	}
-}
-
-func (s *DriverTestSuite) TestHas() {
-	for name, store := range s.stores {
-		s.Run(name, func() {
-			s.False(store.Has("test-has"))
-			s.Nil(store.Put("test-has", "goravel", 5*time.Second))
-			s.True(store.Has("test-has"))
-		})
-	}
-}
-
-func (s *DriverTestSuite) TestIncrement() {
-	for name, store := range s.stores {
-		s.Run(name, func() {
-			res, err := store.Increment("Increment")
-			s.Equal(1, res)
-			s.Nil(err)
-
-			s.Equal(1, store.GetInt("Increment"))
-
-			res, err = store.Increment("Increment", 2)
-			s.Equal(3, res)
-			s.Nil(err)
-
-			res, err = store.Increment("Increment1", 2)
-			s.Equal(2, res)
-			s.Nil(err)
-
-			s.Equal(2, store.GetInt("Increment1"))
-
-			s.True(store.Add("Increment2", 1, 2*time.Second))
-			res, err = store.Increment("Increment2")
-			s.Equal(2, res)
-			s.Nil(err)
-
-			res, err = store.Increment("Increment2", 2)
-			s.Equal(4, res)
-			s.Nil(err)
-		})
-	}
-}
-
-func (s *DriverTestSuite) TestLock() {
-	for _, store := range s.stores {
-		tests := []struct {
-			name  string
-			setup func()
-		}{
-			{
-				name: "once got lock, lock can't be got again",
-				setup: func() {
-					lock := store.Lock("lock")
-					s.True(lock.Get())
-
-					lock1 := store.Lock("lock")
-					s.False(lock1.Get())
-
-					lock.Release()
-				},
-			},
-			{
-				name: "lock can be got again when had been released",
-				setup: func() {
-					lock := store.Lock("lock")
-					s.True(lock.Get())
-
-					s.True(lock.Release())
-
-					lock1 := store.Lock("lock")
-					s.True(lock1.Get())
-
-					s.True(lock1.Release())
-				},
-			},
-			{
-				name: "lock cannot be released when had been got",
-				setup: func() {
-					lock := store.Lock("lock")
-					s.True(lock.Get())
-
-					lock1 := store.Lock("lock")
-					s.False(lock1.Get())
-					s.False(lock1.Release())
-
-					s.True(lock.Release())
-				},
-			},
-			{
-				name: "lock can be force released",
-				setup: func() {
-					lock := store.Lock("lock")
-					s.True(lock.Get())
-
-					lock1 := store.Lock("lock")
-					s.False(lock1.Get())
-					s.False(lock1.Release())
-					s.True(lock1.ForceRelease())
-
-					s.True(lock.Release())
-				},
-			},
-			{
-				name: "lock can be got again when timeout",
-				setup: func() {
-					lock := store.Lock("lock", 1*time.Second)
-					s.True(lock.Get())
-
-					time.Sleep(2 * time.Second)
-
-					lock1 := store.Lock("lock")
-					s.True(lock1.Get())
-					s.True(lock1.Release())
-				},
-			},
-			{
-				name: "lock can be got again when had been released by callback",
-				setup: func() {
-					lock := store.Lock("lock")
-					s.True(lock.Get(func() {
-						s.True(true)
-					}))
-
-					lock1 := store.Lock("lock")
-					s.True(lock1.Get())
-					s.True(lock1.Release())
-				},
-			},
-			{
-				name: "block wait out",
-				setup: func() {
-					lock := store.Lock("lock")
-					s.True(lock.Get())
-
-					go func() {
-						lock1 := store.Lock("lock")
-						s.NotNil(lock1.Block(1 * time.Second))
-					}()
-
-					time.Sleep(2 * time.Second)
-
-					lock.Release()
-				},
-			},
-			{
-				name: "get lock by block when just timeout",
-				setup: func() {
-					lock := store.Lock("lock")
-					s.True(lock.Get())
-
-					go func() {
-						lock1 := store.Lock("lock")
-						s.True(lock1.Block(2 * time.Second))
-						s.True(lock1.Release())
-					}()
-
-					time.Sleep(1 * time.Second)
-
-					lock.Release()
-
-					time.Sleep(2 * time.Second)
-				},
-			},
-			{
-				name: "get lock by block",
-				setup: func() {
-					lock := store.Lock("lock")
-					s.True(lock.Get())
-
-					go func() {
-						lock1 := store.Lock("lock")
-						s.True(lock1.Block(3 * time.Second))
-						s.True(lock1.Release())
-					}()
-
-					time.Sleep(1 * time.Second)
-
-					lock.Release()
-
-					time.Sleep(3 * time.Second)
-				},
-			},
-			{
-				name: "get lock by block with callback",
-				setup: func() {
-					lock := store.Lock("lock")
-					s.True(lock.Get())
-
-					go func() {
-						lock1 := store.Lock("lock")
-						s.True(lock1.Block(2*time.Second, func() {
-							s.True(true)
-						}))
-					}()
-
-					time.Sleep(1 * time.Second)
-
-					lock.Release()
-
-					time.Sleep(2 * time.Second)
-				},
-			},
-		}
-
-		for _, test := range tests {
-			s.Run(test.name, func() {
-				test.setup()
-			})
-		}
-	}
-}
-
-func (s *DriverTestSuite) TestPull() {
-	for name, store := range s.stores {
-		s.Run(name, func() {
-			s.Nil(store.Put("name", "Goravel", 1*time.Second))
-			s.True(store.Has("name"))
-			s.Equal("Goravel", store.Pull("name", "").(string))
-			s.False(store.Has("name"))
-		})
-	}
-}
-
-func (s *DriverTestSuite) TestPut() {
-	for name, store := range s.stores {
-		s.Run(name, func() {
-			s.Nil(store.Put("name", "Goravel", 1*time.Second))
-			s.True(store.Has("name"))
-			s.Equal("Goravel", store.Get("name", "").(string))
-			time.Sleep(2 * time.Second)
-			s.False(store.Has("name"))
-		})
-	}
-}
-
-func (s *DriverTestSuite) TestRemember() {
-	for name, store := range s.stores {
-		s.Run(name, func() {
-			s.Nil(store.Put("name", "Goravel", 1*time.Second))
-			value, err := store.Remember("name", 1*time.Second, func() any {
-				return "World"
-			})
-			s.Nil(err)
-			s.Equal("Goravel", value)
-
-			value, err = store.Remember("name1", 1*time.Second, func() any {
-				return "World1"
-			})
-			s.Nil(err)
-			s.Equal("World1", value)
-			time.Sleep(2 * time.Second)
-			s.False(store.Has("name1"))
-			s.True(store.Flush())
-		})
-	}
-}
-
-func (s *DriverTestSuite) TestRememberForever() {
-	for name, store := range s.stores {
-		s.Run(name, func() {
-			s.Nil(store.Put("name", "Goravel", 1*time.Second))
-			value, err := store.RememberForever("name", func() any {
-				return "World"
-			})
-			s.Nil(err)
-			s.Equal("Goravel", value)
-
-			value, err = store.RememberForever("name1", func() any {
-				return "World1"
-			})
-			s.Nil(err)
-			s.Equal("World1", value)
-			s.True(store.Flush())
-		})
-	}
-}
-
-func getRedisDocker() (*dockertest.Pool, *dockertest.Resource, cache.Driver, error) {
-	mockConfig := &configmock.Config{}
-	pool, resource, err := testingdocker.Redis()
-	if err != nil {
-		return nil, nil, nil, err
-	}
-
-	var store cache.Driver
-	if err := pool.Retry(func() error {
-		var err error
-		mockConfig.On("GetString", "cache.stores.redis.connection", "default").Return("default").Once()
-		mockConfig.On("GetString", "database.redis.default.host").Return("localhost").Once()
-		mockConfig.On("GetString", "database.redis.default.port").Return(resource.GetPort("6379/tcp")).Once()
-		mockConfig.On("GetString", "database.redis.default.password").Return(resource.GetPort("")).Once()
-		mockConfig.On("GetInt", "database.redis.default.database").Return(0).Once()
-		mockConfig.On("GetString", "cache.prefix").Return("goravel_cache").Once()
-		store, err = NewRedis(context.Background(), mockConfig, "redis")
-
-		return err
-	}); err != nil {
-		return nil, nil, nil, err
-	}
-
-	return pool, resource, store, nil
-}
-
-func getMemoryStore() (*Memory, error) {
-	mockConfig := &configmock.Config{}
-	mockConfig.On("GetString", "cache.prefix").Return("goravel_cache").Once()
-
-	memory, err := NewMemory(mockConfig)
-	if err != nil {
-		return nil, err
-	}
-
-	return memory, nil
+	s.mockConfig.AssertExpectations(s.T())
 }
 
 type Store struct {
diff --git a/cache/memory_test.go b/cache/memory_test.go
new file mode 100644
index 000000000..231676a67
--- /dev/null
+++ b/cache/memory_test.go
@@ -0,0 +1,377 @@
+package cache
+
+import (
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/suite"
+
+	configmock "github.com/goravel/framework/contracts/config/mocks"
+)
+
+type MemoryTestSuite struct {
+	suite.Suite
+	mockConfig *configmock.Config
+	memory     *Memory
+}
+
+func TestMemoryTestSuite(t *testing.T) {
+	suite.Run(t, new(MemoryTestSuite))
+}
+
+func (s *MemoryTestSuite) SetupTest() {
+	s.mockConfig = &configmock.Config{}
+	memoryStore, err := getMemoryStore()
+	s.Nil(err)
+	s.memory = memoryStore
+}
+
+func (s *MemoryTestSuite) TestAdd() {
+	s.Nil(s.memory.Put("name", "Goravel", 1*time.Second))
+	s.False(s.memory.Add("name", "World", 1*time.Second))
+	s.True(s.memory.Add("name1", "World", 1*time.Second))
+	s.True(s.memory.Has("name1"))
+	time.Sleep(2 * time.Second)
+	s.False(s.memory.Has("name1"))
+	s.True(s.memory.Flush())
+}
+
+func (s *MemoryTestSuite) TestDecrement() {
+	res, err := s.memory.Decrement("decrement")
+	s.Equal(-1, res)
+	s.Nil(err)
+
+	s.Equal(-1, s.memory.GetInt("decrement"))
+
+	res, err = s.memory.Decrement("decrement", 2)
+	s.Equal(-3, res)
+	s.Nil(err)
+
+	res, err = s.memory.Decrement("decrement1", 2)
+	s.Equal(-2, res)
+	s.Nil(err)
+
+	s.Equal(-2, s.memory.GetInt("decrement1"))
+
+	s.True(s.memory.Add("decrement2", 4, 2*time.Second))
+	res, err = s.memory.Decrement("decrement2")
+	s.Equal(3, res)
+	s.Nil(err)
+
+	res, err = s.memory.Decrement("decrement2", 2)
+	s.Equal(1, res)
+	s.Nil(err)
+}
+
+func (s *MemoryTestSuite) TestForever() {
+	s.True(s.memory.Forever("name", "Goravel"))
+	s.Equal("Goravel", s.memory.Get("name", "").(string))
+	s.True(s.memory.Flush())
+}
+
+func (s *MemoryTestSuite) TestForget() {
+	val := s.memory.Forget("test-forget")
+	s.True(val)
+
+	err := s.memory.Put("test-forget", "goravel", 5*time.Second)
+	s.Nil(err)
+	s.True(s.memory.Forget("test-forget"))
+}
+
+func (s *MemoryTestSuite) TestFlush() {
+	s.Nil(s.memory.Put("test-flush", "goravel", 5*time.Second))
+	s.Equal("goravel", s.memory.Get("test-flush", nil).(string))
+
+	s.True(s.memory.Flush())
+	s.False(s.memory.Has("test-flush"))
+}
+
+func (s *MemoryTestSuite) TestGet() {
+	s.Nil(s.memory.Put("name", "Goravel", 1*time.Second))
+	s.Equal("Goravel", s.memory.Get("name", "").(string))
+	s.Equal("World", s.memory.Get("name1", "World").(string))
+	s.Equal("World1", s.memory.Get("name2", func() any {
+		return "World1"
+	}).(string))
+	s.True(s.memory.Forget("name"))
+	s.True(s.memory.Flush())
+}
+
+func (s *MemoryTestSuite) TestGetBool() {
+	s.Equal(true, s.memory.GetBool("test-get-bool", true))
+	s.Nil(s.memory.Put("test-get-bool", true, 2*time.Second))
+	s.Equal(true, s.memory.GetBool("test-get-bool", false))
+}
+
+func (s *MemoryTestSuite) TestGetInt() {
+	s.Equal(2, s.memory.GetInt("test-get-int", 2))
+	s.Nil(s.memory.Put("test-get-int", 3, 2*time.Second))
+	s.Equal(3, s.memory.GetInt("test-get-int", 2))
+}
+
+func (s *MemoryTestSuite) TestGetString() {
+	s.Equal("2", s.memory.GetString("test-get-string", "2"))
+	s.Nil(s.memory.Put("test-get-string", "3", 2*time.Second))
+	s.Equal("3", s.memory.GetString("test-get-string", "2"))
+}
+
+func (s *MemoryTestSuite) TestHas() {
+	s.False(s.memory.Has("test-has"))
+	s.Nil(s.memory.Put("test-has", "goravel", 5*time.Second))
+	s.True(s.memory.Has("test-has"))
+}
+
+func (s *MemoryTestSuite) TestIncrement() {
+	res, err := s.memory.Increment("Increment")
+	s.Equal(1, res)
+	s.Nil(err)
+
+	s.Equal(1, s.memory.GetInt("Increment"))
+
+	res, err = s.memory.Increment("Increment", 2)
+	s.Equal(3, res)
+	s.Nil(err)
+
+	res, err = s.memory.Increment("Increment1", 2)
+	s.Equal(2, res)
+	s.Nil(err)
+
+	s.Equal(2, s.memory.GetInt("Increment1"))
+
+	s.True(s.memory.Add("Increment2", 1, 2*time.Second))
+	res, err = s.memory.Increment("Increment2")
+	s.Equal(2, res)
+	s.Nil(err)
+
+	res, err = s.memory.Increment("Increment2", 2)
+	s.Equal(4, res)
+	s.Nil(err)
+}
+
+func (s *MemoryTestSuite) TestLock() {
+	tests := []struct {
+		name  string
+		setup func()
+	}{
+		{
+			name: "once got lock, lock can't be got again",
+			setup: func() {
+				lock := s.memory.Lock("lock")
+				s.True(lock.Get())
+
+				lock1 := s.memory.Lock("lock")
+				s.False(lock1.Get())
+
+				lock.Release()
+			},
+		},
+		{
+			name: "lock can be got again when had been released",
+			setup: func() {
+				lock := s.memory.Lock("lock")
+				s.True(lock.Get())
+
+				s.True(lock.Release())
+
+				lock1 := s.memory.Lock("lock")
+				s.True(lock1.Get())
+
+				s.True(lock1.Release())
+			},
+		},
+		{
+			name: "lock cannot be released when had been got",
+			setup: func() {
+				lock := s.memory.Lock("lock")
+				s.True(lock.Get())
+
+				lock1 := s.memory.Lock("lock")
+				s.False(lock1.Get())
+				s.False(lock1.Release())
+
+				s.True(lock.Release())
+			},
+		},
+		{
+			name: "lock can be force released",
+			setup: func() {
+				lock := s.memory.Lock("lock")
+				s.True(lock.Get())
+
+				lock1 := s.memory.Lock("lock")
+				s.False(lock1.Get())
+				s.False(lock1.Release())
+				s.True(lock1.ForceRelease())
+
+				s.True(lock.Release())
+			},
+		},
+		{
+			name: "lock can be got again when timeout",
+			setup: func() {
+				lock := s.memory.Lock("lock", 1*time.Second)
+				s.True(lock.Get())
+
+				time.Sleep(2 * time.Second)
+
+				lock1 := s.memory.Lock("lock")
+				s.True(lock1.Get())
+				s.True(lock1.Release())
+			},
+		},
+		{
+			name: "lock can be got again when had been released by callback",
+			setup: func() {
+				lock := s.memory.Lock("lock")
+				s.True(lock.Get(func() {
+					s.True(true)
+				}))
+
+				lock1 := s.memory.Lock("lock")
+				s.True(lock1.Get())
+				s.True(lock1.Release())
+			},
+		},
+		{
+			name: "block wait out",
+			setup: func() {
+				lock := s.memory.Lock("lock")
+				s.True(lock.Get())
+
+				go func() {
+					lock1 := s.memory.Lock("lock")
+					s.NotNil(lock1.Block(1 * time.Second))
+				}()
+
+				time.Sleep(2 * time.Second)
+
+				lock.Release()
+			},
+		},
+		{
+			name: "get lock by block when just timeout",
+			setup: func() {
+				lock := s.memory.Lock("lock")
+				s.True(lock.Get())
+
+				go func() {
+					lock1 := s.memory.Lock("lock")
+					s.True(lock1.Block(2 * time.Second))
+					s.True(lock1.Release())
+				}()
+
+				time.Sleep(1 * time.Second)
+
+				lock.Release()
+
+				time.Sleep(2 * time.Second)
+			},
+		},
+		{
+			name: "get lock by block",
+			setup: func() {
+				lock := s.memory.Lock("lock")
+				s.True(lock.Get())
+
+				go func() {
+					lock1 := s.memory.Lock("lock")
+					s.True(lock1.Block(3 * time.Second))
+					s.True(lock1.Release())
+				}()
+
+				time.Sleep(1 * time.Second)
+
+				lock.Release()
+
+				time.Sleep(3 * time.Second)
+			},
+		},
+		{
+			name: "get lock by block with callback",
+			setup: func() {
+				lock := s.memory.Lock("lock")
+				s.True(lock.Get())
+
+				go func() {
+					lock1 := s.memory.Lock("lock")
+					s.True(lock1.Block(2*time.Second, func() {
+						s.True(true)
+					}))
+				}()
+
+				time.Sleep(1 * time.Second)
+
+				lock.Release()
+
+				time.Sleep(2 * time.Second)
+			},
+		},
+	}
+
+	for _, test := range tests {
+		s.Run(test.name, func() {
+			test.setup()
+		})
+	}
+}
+
+func (s *MemoryTestSuite) TestPull() {
+	s.Nil(s.memory.Put("name", "Goravel", 1*time.Second))
+	s.True(s.memory.Has("name"))
+	s.Equal("Goravel", s.memory.Pull("name", "").(string))
+	s.False(s.memory.Has("name"))
+}
+
+func (s *MemoryTestSuite) TestPut() {
+	s.Nil(s.memory.Put("name", "Goravel", 1*time.Second))
+	s.True(s.memory.Has("name"))
+	s.Equal("Goravel", s.memory.Get("name", "").(string))
+	time.Sleep(2 * time.Second)
+	s.False(s.memory.Has("name"))
+}
+
+func (s *MemoryTestSuite) TestRemember() {
+	s.Nil(s.memory.Put("name", "Goravel", 1*time.Second))
+	value, err := s.memory.Remember("name", 1*time.Second, func() any {
+		return "World"
+	})
+	s.Nil(err)
+	s.Equal("Goravel", value)
+
+	value, err = s.memory.Remember("name1", 1*time.Second, func() any {
+		return "World1"
+	})
+	s.Nil(err)
+	s.Equal("World1", value)
+	time.Sleep(2 * time.Second)
+	s.False(s.memory.Has("name1"))
+	s.True(s.memory.Flush())
+}
+
+func (s *MemoryTestSuite) TestRememberForever() {
+	s.Nil(s.memory.Put("name", "Goravel", 1*time.Second))
+	value, err := s.memory.RememberForever("name", func() any {
+		return "World"
+	})
+	s.Nil(err)
+	s.Equal("Goravel", value)
+
+	value, err = s.memory.RememberForever("name1", func() any {
+		return "World1"
+	})
+	s.Nil(err)
+	s.Equal("World1", value)
+	s.True(s.memory.Flush())
+}
+
+func getMemoryStore() (*Memory, error) {
+	mockConfig := &configmock.Config{}
+	mockConfig.On("GetString", "cache.prefix").Return("goravel_cache").Once()
+
+	memory, err := NewMemory(mockConfig)
+	if err != nil {
+		return nil, err
+	}
+
+	return memory, nil
+}
diff --git a/cache/redis.go b/cache/redis.go
deleted file mode 100644
index 9db50f21d..000000000
--- a/cache/redis.go
+++ /dev/null
@@ -1,259 +0,0 @@
-package cache
-
-import (
-	"context"
-	"fmt"
-	"strconv"
-	"time"
-
-	"github.com/go-redis/redis/v8"
-	"github.com/pkg/errors"
-	"github.com/spf13/cast"
-
-	"github.com/goravel/framework/contracts/cache"
-	"github.com/goravel/framework/contracts/config"
-)
-
-type Redis struct {
-	ctx      context.Context
-	config   config.Config
-	prefix   string
-	instance *redis.Client
-	store    string
-}
-
-func NewRedis(ctx context.Context, config config.Config, store string) (*Redis, error) {
-	connection := config.GetString(fmt.Sprintf("cache.stores.%s.connection", store), "default")
-	host := config.GetString("database.redis." + connection + ".host")
-	if host == "" {
-		return nil, nil
-	}
-
-	client := redis.NewClient(&redis.Options{
-		Addr:     host + ":" + config.GetString("database.redis."+connection+".port"),
-		Password: config.GetString("database.redis." + connection + ".password"),
-		DB:       config.GetInt("database.redis." + connection + ".database"),
-	})
-
-	if _, err := client.Ping(context.Background()).Result(); err != nil {
-		return nil, errors.WithMessage(err, "init connection error")
-	}
-
-	return &Redis{
-		ctx:      ctx,
-		prefix:   prefix(config),
-		instance: client,
-		store:    store,
-	}, nil
-}
-
-//Add Driver an item in the cache if the key does not exist.
-func (r *Redis) Add(key string, value any, t time.Duration) bool {
-	val, err := r.instance.SetNX(r.ctx, r.key(key), value, t).Result()
-	if err != nil {
-		return false
-	}
-
-	return val
-}
-
-func (r *Redis) Decrement(key string, value ...int) (int, error) {
-	if len(value) == 0 {
-		value = append(value, 1)
-	}
-
-	res, err := r.instance.DecrBy(r.ctx, r.key(key), int64(value[0])).Result()
-
-	return int(res), err
-}
-
-//Forever Driver an item in the cache indefinitely.
-func (r *Redis) Forever(key string, value any) bool {
-	if err := r.Put(key, value, 0); err != nil {
-		return false
-	}
-
-	return true
-}
-
-//Forget Remove an item from the cache.
-func (r *Redis) Forget(key string) bool {
-	_, err := r.instance.Del(r.ctx, r.key(key)).Result()
-
-	return err == nil
-}
-
-//Flush Remove all items from the cache.
-func (r *Redis) Flush() bool {
-	res, err := r.instance.FlushAll(r.ctx).Result()
-
-	if err != nil || res != "OK" {
-		return false
-	}
-
-	return true
-}
-
-//Get Retrieve an item from the cache by key.
-func (r *Redis) Get(key string, def ...any) any {
-	val, err := r.instance.Get(r.ctx, r.key(key)).Result()
-	if err != nil {
-		if len(def) == 0 {
-			return nil
-		}
-
-		switch s := def[0].(type) {
-		case func() any:
-			return s()
-		default:
-			return s
-		}
-	}
-
-	return val
-}
-
-func (r *Redis) GetBool(key string, def ...bool) bool {
-	if len(def) == 0 {
-		def = append(def, false)
-	}
-	res := r.Get(key, def[0])
-	if val, ok := res.(string); ok {
-		return val == "1"
-	}
-
-	return cast.ToBool(res)
-}
-
-func (r *Redis) GetInt(key string, def ...int) int {
-	if len(def) == 0 {
-		def = append(def, 1)
-	}
-	res := r.Get(key, def[0])
-	if val, ok := res.(string); ok {
-		i, err := strconv.Atoi(val)
-		if err != nil {
-			return def[0]
-		}
-
-		return i
-	}
-
-	return cast.ToInt(res)
-}
-
-func (r *Redis) GetInt64(key string, def ...int64) int64 {
-	if len(def) == 0 {
-		def = append(def, 1)
-	}
-	res := r.Get(key, def[0])
-	if val, ok := res.(string); ok {
-		i, err := strconv.ParseInt(val, 10, 64)
-		if err != nil {
-			return def[0]
-		}
-
-		return i
-	}
-
-	return cast.ToInt64(res)
-}
-
-func (r *Redis) GetString(key string, def ...string) string {
-	if len(def) == 0 {
-		def = append(def, "")
-	}
-	return cast.ToString(r.Get(key, def[0]))
-}
-
-//Has Check an item exists in the cache.
-func (r *Redis) Has(key string) bool {
-	value, err := r.instance.Exists(r.ctx, r.key(key)).Result()
-
-	if err != nil || value == 0 {
-		return false
-	}
-
-	return true
-}
-
-func (r *Redis) Increment(key string, value ...int) (int, error) {
-	if len(value) == 0 {
-		value = append(value, 1)
-	}
-
-	res, err := r.instance.IncrBy(r.ctx, r.key(key), int64(value[0])).Result()
-
-	return int(res), err
-}
-
-func (r *Redis) Lock(key string, t ...time.Duration) cache.Lock {
-	return NewLock(r, key, t...)
-}
-
-//Put Driver an item in the cache for a given time.
-func (r *Redis) Put(key string, value any, t time.Duration) error {
-	err := r.instance.Set(r.ctx, r.key(key), value, t).Err()
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-//Pull Retrieve an item from the cache and delete it.
-func (r *Redis) Pull(key string, def ...any) any {
-	var res any
-	if len(def) == 0 {
-		res = r.Get(key)
-	} else {
-		res = r.Get(key, def[0])
-	}
-	r.Forget(key)
-
-	return res
-}
-
-//Remember Get an item from the cache, or execute the given Closure and store the result.
-func (r *Redis) Remember(key string, seconds time.Duration, callback func() any) (any, error) {
-	val := r.Get(key, nil)
-
-	if val != nil {
-		return val, nil
-	}
-
-	val = callback()
-
-	if err := r.Put(key, val, seconds); err != nil {
-		return nil, err
-	}
-
-	return val, nil
-}
-
-//RememberForever Get an item from the cache, or execute the given Closure and store the result forever.
-func (r *Redis) RememberForever(key string, callback func() any) (any, error) {
-	val := r.Get(key, nil)
-
-	if val != nil {
-		return val, nil
-	}
-
-	val = callback()
-
-	if err := r.Put(key, val, 0); err != nil {
-		return nil, err
-	}
-
-	return val, nil
-}
-
-func (r *Redis) WithContext(ctx context.Context) cache.Driver {
-	store, _ := NewRedis(ctx, r.config, r.store)
-
-	return store
-}
-
-func (r *Redis) key(key string) string {
-	return r.prefix + key
-}