Skip to content

Commit

Permalink
use filesystem for the file driver
Browse files Browse the repository at this point in the history
  • Loading branch information
kkumar-gcc committed Feb 28, 2024
1 parent 644472f commit d62c8b6
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 70 deletions.
41 changes: 22 additions & 19 deletions session/driver/file.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package driver

import (
"os"
"path/filepath"

"github.com/goravel/framework/contracts/filesystem"
"github.com/goravel/framework/support/carbon"
"github.com/goravel/framework/support/file"
)

type FileDriver struct {
files filesystem.Storage
path string
minutes int
}

func NewFileDriver(path string, minutes int) *FileDriver {
func NewFileDriver(files filesystem.Storage, path string, minutes int) *FileDriver {
return &FileDriver{
files: files,
path: path,
minutes: minutes,
}
Expand All @@ -25,27 +24,31 @@ func (f *FileDriver) Close() bool {
}

func (f *FileDriver) Destroy(id string) error {
return file.Remove(f.path + "/" + id)
return f.files.Delete(f.path + "/" + id)
}

func (f *FileDriver) Gc(maxLifetime int) int {
cutoffTime := carbon.Now().SubSeconds(maxLifetime)
deletedSessions := 0

_ = filepath.Walk(f.path, func(path string, info os.FileInfo, err error) error {
files, err := f.files.Files(f.path)
if err != nil {
return 0
}

for _, file := range files {
modified, err := f.files.LastModified(f.path + "/" + file)
if err != nil {
return err
continue
}

if !info.IsDir() && info.ModTime().Before(cutoffTime.StdTime()) {
err := os.Remove(path)
if modified.Before(cutoffTime.StdTime()) {
err = f.files.Delete(f.path + "/" + file)
if err == nil {
deletedSessions++
}
}

return nil
})
}

return deletedSessions
}
Expand All @@ -56,24 +59,24 @@ func (f *FileDriver) Open(string, string) bool {

func (f *FileDriver) Read(id string) string {
path := f.path + "/" + id
if file.Exists(path) {
modified, err := file.LastModified(path, "UTC")
if f.files.Exists(path) {
modified, err := f.files.LastModified(path)
if err != nil {
return ""
}

if modified.Unix() >= carbon.Now(carbon.UTC).SubMinutes(f.minutes).StdTime().Unix() {
data, err := os.ReadFile(path)
if modified.After(carbon.Now().SubMinutes(f.minutes).StdTime()) {
data, err := f.files.Get(path)
if err != nil {
return ""
}
return string(data)
return data
}
}

return ""
}

func (f *FileDriver) Write(id string, data string) error {
return file.Create(f.path+"/"+id, data)
return f.files.Put(f.path+"/"+id, data)
}
88 changes: 47 additions & 41 deletions session/driver/file_test.go
Original file line number Diff line number Diff line change
@@ -1,30 +1,27 @@
package driver

import (
"os"
"errors"
"testing"
"time"

"github.com/stretchr/testify/suite"

mockfilesystem "github.com/goravel/framework/mocks/filesystem"
"github.com/goravel/framework/support/carbon"
"github.com/goravel/framework/support/env"
"github.com/goravel/framework/support/file"
)

type FileDriverTestSuite struct {
suite.Suite
mockFiles *mockfilesystem.Storage
}

func TestFileDriverTestSuite(t *testing.T) {
suite.Run(t, &FileDriverTestSuite{})
}

func (f *FileDriverTestSuite) AfterTest() {
f.Nil(file.Remove(f.getPath()))
}

func (f *FileDriverTestSuite) BeforeTest() {
f.Nil(file.Remove(f.getPath()))
func (f *FileDriverTestSuite) SetupTest() {
f.mockFiles = mockfilesystem.NewStorage(f.T())
}

func (f *FileDriverTestSuite) TestClose() {
Expand All @@ -34,34 +31,44 @@ func (f *FileDriverTestSuite) TestClose() {

func (f *FileDriverTestSuite) TestDestroy() {
driver := f.getDriver()

f.mockFiles.On("Delete", f.getPath()+"/foo").Return(nil).Once()
f.Nil(driver.Destroy("foo"))

f.mockFiles.On("Put", f.getPath()+"/foo", "bar").Return(nil).Once()
err := driver.Write("foo", "bar")
f.Nil(err)

f.mockFiles.On("Exists", f.getPath()+"/foo").Return(true).Once()
f.mockFiles.On("LastModified", f.getPath()+"/foo").Once().Return(time.Now(), nil)
f.mockFiles.On("Get", f.getPath()+"/foo").Once().Return("bar", nil)
f.Equal("bar", driver.Read("foo"))

f.mockFiles.On("Delete", f.getPath()+"/foo").Return(nil).Once()
f.Nil(driver.Destroy("foo"))

f.mockFiles.On("Exists", f.getPath()+"/foo").Return(false).Once()
f.Equal("", driver.Read("foo"))
}

func (f *FileDriverTestSuite) TestGc() {
driver := f.getDriver()

f.mockFiles.On("Files", f.getPath()).Return([]string{}, errors.New("error")).Once()
f.Equal(0, driver.Gc(300))

f.Nil(driver.Write("foo", "bar"))
f.mockFiles.On("Files", f.getPath()).Return([]string{"foo"}, nil).Once()
f.mockFiles.On("LastModified", f.getPath()+"/foo").Return(time.Now(), nil).Once()
f.Equal(0, driver.Gc(300))
f.Equal("bar", driver.Read("foo"))

carbon.SetTestNow(carbon.Now().AddSecond())
f.Nil(driver.Write("baz", "qux"))
carbon.UnsetTestNow()
f.mockFiles.On("Files", f.getPath()).Return([]string{"foo"}, nil).Once()
f.mockFiles.On("LastModified", f.getPath()+"/foo").Return(time.Time{}, errors.New("error")).Once()
f.Equal(0, driver.Gc(300))

carbon.SetTestNow(carbon.Now(carbon.UTC).AddMinutes(6).AddSecond())
f.Equal(2, driver.Gc(300))
f.Equal("", driver.Read("foo"))
f.Equal("", driver.Read("baz"))
carbon.UnsetTestNow()
f.mockFiles.On("Files", f.getPath()).Return([]string{"foo"}, nil).Once()
f.mockFiles.On("LastModified", f.getPath()+"/foo").Return(carbon.Now().SubMinutes(f.getMinutes()).StdTime(), nil).Once()
f.mockFiles.On("Delete", f.getPath()+"/foo").Return(nil).Once()
f.Equal(1, driver.Gc(300))
}

func (f *FileDriverTestSuite) TestOpen() {
Expand All @@ -71,44 +78,43 @@ func (f *FileDriverTestSuite) TestOpen() {

func (f *FileDriverTestSuite) TestRead() {
driver := f.getDriver()
err := driver.Write("foo", "bar")
f.Nil(err)

f.mockFiles.On("Exists", f.getPath()+"/foo").Return(true).Once()
f.mockFiles.On("LastModified", f.getPath()+"/foo").Once().Return(time.Now(), nil)
f.mockFiles.On("Get", f.getPath()+"/foo").Once().Return("bar", nil)
f.Equal("bar", driver.Read("foo"))

carbon.SetTestNow(carbon.Now(carbon.UTC).AddMinutes(f.getMinutes()))
f.mockFiles.On("Exists", f.getPath()+"/foo").Return(true).Once()
f.mockFiles.On("LastModified", f.getPath()+"/foo").
Return(carbon.Now().SubMinutes(f.getMinutes()).AddSecond().StdTime(), nil).Once()
f.mockFiles.On("Get", f.getPath()+"/foo").Return("bar", nil).Once()
f.Equal("bar", driver.Read("foo"))
carbon.UnsetTestNow()

carbon.SetTestNow(carbon.Now().AddMinutes(f.getMinutes()).AddSecond())
f.mockFiles.On("Exists", f.getPath()+"/foo").Return(true).Once()
f.mockFiles.On("LastModified", f.getPath()+"/foo").
Return(carbon.Now().SubMinutes(f.getMinutes()).StdTime(), nil).Once()
f.Equal("", driver.Read("foo"))

f.mockFiles.On("Exists", f.getPath()+"/foo").Return(true).Once()
f.mockFiles.On("LastModified", f.getPath()+"/foo").Return(time.Time{}, errors.New("error")).Once()
f.Equal("", driver.Read("foo"))
carbon.UnsetTestNow()

// error when reading file content
restrictedFilePath := f.getPath() + "/foo"
f.Nil(os.Chmod(restrictedFilePath, 0000))
if env.IsWindows() {
f.Equal("bar", driver.Read("foo"))
} else {
f.Equal("", driver.Read("foo"))
}
f.Nil(os.Chmod(restrictedFilePath, 0777))
f.mockFiles.On("Exists", f.getPath()+"/foo").Return(true).Once()
f.mockFiles.On("LastModified", f.getPath()+"/foo").Once().Return(time.Now(), nil)
f.mockFiles.On("Get", f.getPath()+"/foo").Once().Return("", errors.New("error"))
f.Equal("", driver.Read("foo"))
}

func (f *FileDriverTestSuite) TestWrite() {
driver := f.getDriver()

f.Nil(driver.Write("bar", "baz"))
f.Equal("baz", driver.Read("bar"))

f.Nil(driver.Write("bar", "qux"))
f.Equal("qux", driver.Read("bar"))

f.Nil(file.Remove(f.getPath()))
f.mockFiles.On("Put", f.getPath()+"/foo", "bar").Return(nil).Once()
f.Nil(driver.Write("foo", "bar"))
}

func (f *FileDriverTestSuite) getDriver() *FileDriver {
return NewFileDriver(f.getPath(), f.getMinutes())
return NewFileDriver(f.mockFiles, f.getPath(), f.getMinutes())
}

func (f *FileDriverTestSuite) getPath() string {
Expand Down
9 changes: 6 additions & 3 deletions session/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,22 @@ import (
"fmt"

"github.com/goravel/framework/contracts/config"
"github.com/goravel/framework/contracts/foundation"
sessioncontract "github.com/goravel/framework/contracts/session"
"github.com/goravel/framework/session/driver"
)

type Manager struct {
app foundation.Application
config config.Config
customDrivers map[string]func() sessioncontract.Driver
drivers map[string]func() sessioncontract.Driver
}

func NewManager(config config.Config) *Manager {
func NewManager(app foundation.Application) *Manager {
manager := &Manager{
config: config,
app: app,
config: app.MakeConfig(),
customDrivers: make(map[string]func() sessioncontract.Driver),
drivers: make(map[string]func() sessioncontract.Driver),
}
Expand Down Expand Up @@ -58,7 +61,7 @@ func (m *Manager) getDefaultDriver() string {

func (m *Manager) createFileDriver() sessioncontract.Driver {
lifetime := m.config.GetInt("session.lifetime")
return driver.NewFileDriver(m.config.GetString("session.files"), lifetime)
return driver.NewFileDriver(m.app.MakeStorage(), m.config.GetString("session.files"), lifetime)
}

func (m *Manager) registerDrivers() {
Expand Down
23 changes: 18 additions & 5 deletions session/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,33 @@ import (

sessioncontract "github.com/goravel/framework/contracts/session"
mockconfig "github.com/goravel/framework/mocks/config"
mockfilesystem "github.com/goravel/framework/mocks/filesystem"
mockfoundation "github.com/goravel/framework/mocks/foundation"
)

type ManagerTestSuite struct {
suite.Suite
mockConfig *mockconfig.Config
mockApp *mockfoundation.Application
mockConfig *mockconfig.Config
mockStorage *mockfilesystem.Storage
}

func TestManagerTestSuite(t *testing.T) {
suite.Run(t, &ManagerTestSuite{})
}

func (m *ManagerTestSuite) SetupTest() {
m.mockApp = mockfoundation.NewApplication(m.T())
m.mockConfig = mockconfig.NewConfig(m.T())
m.mockStorage = mockfilesystem.NewStorage(m.T())
}

func (m *ManagerTestSuite) TestDriver() {
manager := NewManager(m.mockConfig)
manager := m.getManager()
m.mockConfig.On("GetInt", "session.lifetime").Once().Return(120)
m.mockConfig.On("GetString", "session.files").Once().Return("storage/framework/sessions")
// provide driver name
m.mockApp.On("MakeStorage").Once().Return(m.mockStorage)
driver, err := manager.Driver("file")
m.Nil(err)
m.NotNil(driver)
Expand All @@ -38,6 +45,7 @@ func (m *ManagerTestSuite) TestDriver() {
m.mockConfig.On("GetInt", "session.lifetime").Once().Return(120)
m.mockConfig.On("GetString", "session.files").Once().Return("storage/framework/sessions")

m.mockApp.On("MakeStorage").Once().Return(m.mockStorage)
driver, err = manager.Driver()
m.Nil(err)
m.NotNil(driver)
Expand All @@ -61,7 +69,7 @@ func (m *ManagerTestSuite) TestDriver() {
}

func (m *ManagerTestSuite) TestExtend() {
manager := NewManager(m.mockConfig)
manager := m.getManager()
manager.Extend("test", func() sessioncontract.Driver {
return NewCustomDriver()
})
Expand All @@ -72,19 +80,24 @@ func (m *ManagerTestSuite) TestExtend() {
}

func (m *ManagerTestSuite) TestBuildSession() {
manager := NewManager(m.mockConfig)
manager := m.getManager()
m.mockConfig.On("GetString", "session.cookie").Once().Return("test_cookie")
session := manager.BuildSession(nil)
m.NotNil(session)
m.Equal("test_cookie", session.GetName())
}

func (m *ManagerTestSuite) TestGetDefaultDriver() {
manager := NewManager(m.mockConfig)
manager := m.getManager()
m.mockConfig.On("GetString", "session.driver").Return("file")
m.Equal("file", manager.getDefaultDriver())
}

func (m *ManagerTestSuite) getManager() *Manager {
m.mockApp.On("MakeConfig").Once().Return(m.mockConfig)
return NewManager(m.mockApp)
}

type CustomDriver struct{}

func NewCustomDriver() sessioncontract.Driver {
Expand Down
3 changes: 1 addition & 2 deletions session/service_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ type ServiceProvider struct {

func (receiver *ServiceProvider) Register(app foundation.Application) {
app.Singleton(Binding, func(app foundation.Application) (any, error) {
config := app.MakeConfig()
return NewManager(config), nil
return NewManager(app), nil
})

Check warning on line 15 in session/service_provider.go

View check run for this annotation

Codecov / codecov/patch

session/service_provider.go#L12-L15

Added lines #L12 - L15 were not covered by tests
}

Expand Down

0 comments on commit d62c8b6

Please sign in to comment.