Skip to content

Commit

Permalink
IMPROVEMENT-35: In progress
Browse files Browse the repository at this point in the history
  • Loading branch information
grafviktor committed Jan 22, 2024
1 parent d04bbd8 commit 4cc944b
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 27 deletions.
1 change: 1 addition & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

type iLogger interface {
Debug(format string, args ...any)
Info(format string, args ...any)
Error(format string, args ...any)
Close()
}
Expand Down
17 changes: 16 additions & 1 deletion internal/mock/logger.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
package mock

type MockLogger struct{}
import "fmt"

type MockLogger struct {
Logs []string
}

func (ml *MockLogger) print(format string, args ...interface{}) {
logMessage := format
if len(args) > 0 {
logMessage = fmt.Sprintf(format, args...)
}
ml.Logs = append(ml.Logs, logMessage)
}

func (l *MockLogger) Debug(format string, args ...any) {
print(format, args)
}

func (l *MockLogger) Info(format string, args ...any) {
print(format, args)
}

func (l *MockLogger) Error(format string, args ...any) {
print(format, args)
}

func (l *MockLogger) Close() {
Expand Down
13 changes: 10 additions & 3 deletions internal/state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ var (

type iLogger interface {
Debug(format string, args ...any)
Info(format string, args ...any)
Error(format string, args ...any)
}

// ApplicationState stores application state.
Expand All @@ -43,30 +45,32 @@ type ApplicationState struct {

// Get - reads application stat from disk.
func Get(appHomePath string, lg iLogger) *ApplicationState {
lg.Debug("[APPSTATE] Get application state")
once.Do(func() {
appState = &ApplicationState{
appStateFilePath: path.Join(appHomePath, stateFile),
logger: lg,
}

// If we cannot read previously created application state, that's fine - we can continue execution.
lg.Debug("[APPSTATE] Application is not ready, should read from file")
_ = appState.readFromFile()
})

return appState
}

func (as *ApplicationState) readFromFile() error {
as.logger.Debug("Read application state from %s\n", as.appStateFilePath)
as.logger.Debug("[APPSTATE] Read application state from: %s", as.appStateFilePath)
fileData, err := os.ReadFile(as.appStateFilePath)
if err != nil {
as.logger.Debug("Can't read application state %v\n", err)
as.logger.Info("[APPSTATE] Can't read application state %v", err)
return err
}

err = yaml.Unmarshal(fileData, as)
if err != nil {
as.logger.Debug("Can't read parse application state %v\n", err)
as.logger.Error("[APPSTATE] Can't parse application state %v", err)
return err
}

Expand All @@ -75,13 +79,16 @@ func (as *ApplicationState) readFromFile() error {

// Persist saves app state to disk.
func (as *ApplicationState) Persist() error {
as.logger.Debug("[APPSTATE] Persist application state to file: %s", as.appStateFilePath)
result, err := yaml.Marshal(as)
if err != nil {
as.logger.Error("[APPSTATE] Cannot marshall application state. %v", err)
return err
}

err = os.WriteFile(as.appStateFilePath, result, 0o600)
if err != nil {
as.logger.Error("[APPSTATE] Cannot save application state. %v", err)
return err
}

Expand Down
21 changes: 4 additions & 17 deletions internal/state/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,17 @@
package state

import (
"fmt"
"os"
"path"
"testing"

"github.com/grafviktor/goto/internal/mock"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v2"
)

// MockLogger implements the iLogger interface for testing.
type MockLogger struct {
Logs []string
}

func (ml *MockLogger) Debug(format string, args ...interface{}) {
logMessage := format
if len(args) > 0 {
logMessage = fmt.Sprintf(format, args...)
}
ml.Logs = append(ml.Logs, logMessage)
}

// That's a wrapper function for state.Get which is required to overcome sync.Once restrictions
func stateGet(tempDir string, mockLogger *MockLogger) *ApplicationState {
func stateGet(tempDir string, mockLogger *mock.MockLogger) *ApplicationState {
appState := Get(tempDir, mockLogger)

// We need this hack because state.Get function utilizes `sync.once`. That means, if all unit tests
Expand All @@ -46,7 +33,7 @@ func Test_GetApplicationState(t *testing.T) {
defer os.RemoveAll(tempDir)

// Create a mock logger for testing
mockLogger := &MockLogger{}
mockLogger := &mock.MockLogger{}

// Call the Get function with the temporary directory and mock logger
appState := stateGet(tempDir, mockLogger)
Expand All @@ -69,7 +56,7 @@ func Test_PersistApplicationState(t *testing.T) {
defer os.RemoveAll(tempDir)

// Create a mock logger for testing
mockLogger := &MockLogger{}
mockLogger := &mock.MockLogger{}

// Call the Get function with the temporary directory and mock logger
appState := stateGet(tempDir, mockLogger)
Expand Down
35 changes: 29 additions & 6 deletions internal/storage/yaml_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ const (

type iLogger interface {
Debug(format string, args ...any)
Info(format string, args ...any)
Error(format string, args ...any)
}

// NewYAML creates new YAML storage.
func NewYAML(ctx context.Context, appFolder string, logger iLogger) (*yamlStorage, error) {
logger.Debug("Config folder %s", appFolder)
logger.Debug("[STORAGE]: Init YAML storage. Config folder %s", appFolder)
fsDataPath := path.Join(appFolder, hostsFile)

return &yamlStorage{
Expand Down Expand Up @@ -74,38 +76,55 @@ func (s *yamlStorage) flushToDisk() error {

func (s *yamlStorage) Save(host model.Host) (model.Host, error) {
if host.ID == idEmpty {
s.logger.Debug("[STORAGE]: Generate new id for new host with title: %s", host.Title)
s.nextID++
host.ID = s.nextID
}

s.logger.Debug("[STORAGE]: Save host with id: %d, title: %s", host.ID, host.Title)
s.innerStorage[host.ID] = yamlHostWrapper{host}

return host, s.flushToDisk()
err := s.flushToDisk()
if err != nil {
s.logger.Error("[STORAGE]: Cannot flush database changes to disk. %v", err)
}

return host, err
}

func (s *yamlStorage) Delete(id int) error {
delete(s.innerStorage, id)
func (s *yamlStorage) Delete(hostID int) error {
s.logger.Debug("[STORAGE]: Delete host with id: %d", hostID)
delete(s.innerStorage, hostID)

return s.flushToDisk()
err := s.flushToDisk()
if err != nil {
s.logger.Error("[STORAGE]: Error deleting host id: %d from the database. %v", hostID, err)
}
return err
}

func (s *yamlStorage) GetAll() ([]model.Host, error) {
// re-create innerStorage before reading file data
s.innerStorage = make(map[int]yamlHostWrapper)
s.logger.Debug("Read hosts file list %s\n", s.fsDataPath)
s.logger.Debug("[STORAGE]: Read hosts from file: %s\n", s.fsDataPath)
fileData, err := os.ReadFile(s.fsDataPath)
if err != nil {
var pathErr *os.PathError
if errors.As(err, &pathErr) {
s.logger.Info("[STORAGE]: Path no found: %s. Assuming it's not created yet", s.fsDataPath)

return make([]model.Host, 0), nil
}

s.logger.Error("[STORAGE]: Read hosts error. %v", err)
return nil, err
}

var yamlHosts []yamlHostWrapper
s.logger.Debug("[STORAGE]: Unmarshal hosts data from yaml storage")
err = yaml.Unmarshal(fileData, &yamlHosts)
if err != nil {
s.logger.Error("[STORAGE]: Could not unmarshal hosts data. %v", err)
return nil, err
}

Expand All @@ -122,15 +141,19 @@ func (s *yamlStorage) GetAll() ([]model.Host, error) {
return value.Host
})

s.logger.Debug("[STORAGE]: Found %d items in the database", len(hosts))
return hosts, nil
}

func (s *yamlStorage) Get(hostID int) (model.Host, error) {
s.logger.Debug("[STORAGE]: Read host with id %d from the database", hostID)
found, ok := s.innerStorage[hostID]

if !ok {
s.logger.Debug("[STORAGE]: Host id %d NOT found in the database", hostID)
return model.Host{}, constant.ErrNotFound
}

s.logger.Debug("[STORAGE]: Host id %d found in the database", hostID)
return found.Host, nil
}

0 comments on commit 4cc944b

Please sign in to comment.