mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-06 16:04:23 +00:00
Implement storage git tests
This commit is contained in:
@@ -92,7 +92,10 @@ func TestFileNode(t *testing.T) {
|
|||||||
|
|
||||||
func TestListFilesRecursively(t *testing.T) {
|
func TestListFilesRecursively(t *testing.T) {
|
||||||
mockFS := NewMockFS()
|
mockFS := NewMockFS()
|
||||||
s := storage.NewServiceWithFS("test-root", mockFS)
|
s := storage.NewServiceWithOptions("test-root", storage.Options{
|
||||||
|
Fs: mockFS,
|
||||||
|
NewGitClient: nil,
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("empty directory", func(t *testing.T) {
|
t.Run("empty directory", func(t *testing.T) {
|
||||||
mockFS.ReadDirReturns = map[string]struct {
|
mockFS.ReadDirReturns = map[string]struct {
|
||||||
@@ -183,7 +186,10 @@ func TestListFilesRecursively(t *testing.T) {
|
|||||||
|
|
||||||
func TestGetFileContent(t *testing.T) {
|
func TestGetFileContent(t *testing.T) {
|
||||||
mockFS := NewMockFS()
|
mockFS := NewMockFS()
|
||||||
s := storage.NewServiceWithFS("test-root", mockFS)
|
s := storage.NewServiceWithOptions("test-root", storage.Options{
|
||||||
|
Fs: mockFS,
|
||||||
|
NewGitClient: nil,
|
||||||
|
})
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -257,7 +263,10 @@ func TestGetFileContent(t *testing.T) {
|
|||||||
|
|
||||||
func TestSaveFile(t *testing.T) {
|
func TestSaveFile(t *testing.T) {
|
||||||
mockFS := NewMockFS()
|
mockFS := NewMockFS()
|
||||||
s := storage.NewServiceWithFS("test-root", mockFS)
|
s := storage.NewServiceWithOptions("test-root", storage.Options{
|
||||||
|
Fs: mockFS,
|
||||||
|
NewGitClient: nil,
|
||||||
|
})
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -327,7 +336,10 @@ func TestSaveFile(t *testing.T) {
|
|||||||
|
|
||||||
func TestDeleteFile(t *testing.T) {
|
func TestDeleteFile(t *testing.T) {
|
||||||
mockFS := NewMockFS()
|
mockFS := NewMockFS()
|
||||||
s := storage.NewServiceWithFS("test-root", mockFS)
|
s := storage.NewServiceWithOptions("test-root", storage.Options{
|
||||||
|
Fs: mockFS,
|
||||||
|
NewGitClient: nil,
|
||||||
|
})
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ func (s *Service) SetupGitRepo(userID, workspaceID int, gitURL, gitUser, gitToke
|
|||||||
if _, ok := s.GitRepos[userID]; !ok {
|
if _, ok := s.GitRepos[userID]; !ok {
|
||||||
s.GitRepos[userID] = make(map[int]git.Client)
|
s.GitRepos[userID] = make(map[int]git.Client)
|
||||||
}
|
}
|
||||||
s.GitRepos[userID][workspaceID] = git.New(gitURL, gitUser, gitToken, workspacePath)
|
s.GitRepos[userID][workspaceID] = s.newGitClient(gitURL, gitUser, gitToken, workspacePath)
|
||||||
return s.GitRepos[userID][workspaceID].EnsureRepo()
|
return s.GitRepos[userID][workspaceID].EnsureRepo()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
258
server/internal/storage/git_test.go
Normal file
258
server/internal/storage/git_test.go
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
package storage_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"novamd/internal/git"
|
||||||
|
"novamd/internal/storage"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockGitClient implements git.Client interface for testing
|
||||||
|
type MockGitClient struct {
|
||||||
|
CloneCalled bool
|
||||||
|
PullCalled bool
|
||||||
|
CommitCalled bool
|
||||||
|
PushCalled bool
|
||||||
|
EnsureCalled bool
|
||||||
|
CommitMessage string
|
||||||
|
ReturnError error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockGitClient) Clone() error {
|
||||||
|
m.CloneCalled = true
|
||||||
|
return m.ReturnError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockGitClient) Pull() error {
|
||||||
|
m.PullCalled = true
|
||||||
|
return m.ReturnError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockGitClient) Commit(message string) error {
|
||||||
|
m.CommitCalled = true
|
||||||
|
m.CommitMessage = message
|
||||||
|
return m.ReturnError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockGitClient) Push() error {
|
||||||
|
m.PushCalled = true
|
||||||
|
return m.ReturnError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockGitClient) EnsureRepo() error {
|
||||||
|
m.EnsureCalled = true
|
||||||
|
return m.ReturnError
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetupGitRepo(t *testing.T) {
|
||||||
|
mockFS := NewMockFS()
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
userID int
|
||||||
|
workspaceID int
|
||||||
|
gitURL string
|
||||||
|
gitUser string
|
||||||
|
gitToken string
|
||||||
|
mockErr error
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "successful setup",
|
||||||
|
userID: 1,
|
||||||
|
workspaceID: 1,
|
||||||
|
gitURL: "https://github.com/user/repo",
|
||||||
|
gitUser: "user",
|
||||||
|
gitToken: "token",
|
||||||
|
mockErr: nil,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "git initialization error",
|
||||||
|
userID: 1,
|
||||||
|
workspaceID: 2,
|
||||||
|
gitURL: "https://github.com/user/repo",
|
||||||
|
gitUser: "user",
|
||||||
|
gitToken: "token",
|
||||||
|
mockErr: errors.New("git initialization failed"),
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
// Create a mock client with the desired error behavior
|
||||||
|
mockClient := &MockGitClient{ReturnError: tc.mockErr}
|
||||||
|
|
||||||
|
// Create a client factory that returns our configured mock
|
||||||
|
mockClientFactory := func(_, _, _, _ string) git.Client {
|
||||||
|
return mockClient
|
||||||
|
}
|
||||||
|
|
||||||
|
s := storage.NewServiceWithOptions("test-root", storage.Options{
|
||||||
|
Fs: mockFS,
|
||||||
|
NewGitClient: mockClientFactory,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Setup the git repo
|
||||||
|
err := s.SetupGitRepo(tc.userID, tc.workspaceID, tc.gitURL, tc.gitUser, tc.gitToken)
|
||||||
|
|
||||||
|
if tc.wantErr {
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected error, got nil")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if client was stored correctly
|
||||||
|
client, ok := s.GitRepos[tc.userID][tc.workspaceID]
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("git client was not stored in service")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !mockClient.EnsureCalled {
|
||||||
|
t.Error("EnsureRepo was not called")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify it's our mock client
|
||||||
|
if client != mockClient {
|
||||||
|
t.Error("stored client is not our mock client")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGitOperations(t *testing.T) {
|
||||||
|
mockFS := NewMockFS()
|
||||||
|
s := storage.NewServiceWithOptions("test-root", storage.Options{
|
||||||
|
Fs: mockFS,
|
||||||
|
NewGitClient: func(_, _, _, _ string) git.Client { return &MockGitClient{} },
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("operations on non-configured workspace", func(t *testing.T) {
|
||||||
|
err := s.StageCommitAndPush(1, 1, "test commit")
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected error for non-configured workspace, got nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.Pull(1, 1)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected error for non-configured workspace, got nil")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("successful operations", func(t *testing.T) {
|
||||||
|
// Initialize GitRepos map
|
||||||
|
s.GitRepos = make(map[int]map[int]git.Client)
|
||||||
|
s.GitRepos[1] = make(map[int]git.Client)
|
||||||
|
mockClient := &MockGitClient{}
|
||||||
|
s.GitRepos[1][1] = mockClient
|
||||||
|
|
||||||
|
// Test commit and push
|
||||||
|
err := s.StageCommitAndPush(1, 1, "test commit")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if !mockClient.CommitCalled {
|
||||||
|
t.Error("Commit was not called")
|
||||||
|
}
|
||||||
|
if mockClient.CommitMessage != "test commit" {
|
||||||
|
t.Errorf("Commit message = %q, want %q", mockClient.CommitMessage, "test commit")
|
||||||
|
}
|
||||||
|
if !mockClient.PushCalled {
|
||||||
|
t.Error("Push was not called")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test pull
|
||||||
|
err = s.Pull(1, 1)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if !mockClient.PullCalled {
|
||||||
|
t.Error("Pull was not called")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("operation errors", func(t *testing.T) {
|
||||||
|
// Initialize GitRepos map with error-returning client
|
||||||
|
s.GitRepos = make(map[int]map[int]git.Client)
|
||||||
|
s.GitRepos[1] = make(map[int]git.Client)
|
||||||
|
mockClient := &MockGitClient{ReturnError: errors.New("git operation failed")}
|
||||||
|
s.GitRepos[1][1] = mockClient
|
||||||
|
|
||||||
|
// Test commit error
|
||||||
|
err := s.StageCommitAndPush(1, 1, "test commit")
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected error for commit, got nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test pull error
|
||||||
|
err = s.Pull(1, 1)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected error for pull, got nil")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDisableGitRepo(t *testing.T) {
|
||||||
|
mockFS := NewMockFS()
|
||||||
|
s := storage.NewServiceWithOptions("test-root", storage.Options{
|
||||||
|
Fs: mockFS,
|
||||||
|
NewGitClient: func(_, _, _, _ string) git.Client { return &MockGitClient{} },
|
||||||
|
})
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
userID int
|
||||||
|
workspaceID int
|
||||||
|
setupRepo bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "disable existing repo",
|
||||||
|
userID: 1,
|
||||||
|
workspaceID: 1,
|
||||||
|
setupRepo: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "disable non-existent repo",
|
||||||
|
userID: 2,
|
||||||
|
workspaceID: 1,
|
||||||
|
setupRepo: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
// Reset GitRepos for each test
|
||||||
|
s.GitRepos = make(map[int]map[int]git.Client)
|
||||||
|
|
||||||
|
if tc.setupRepo {
|
||||||
|
// Setup initial repo
|
||||||
|
s.GitRepos[tc.userID] = make(map[int]git.Client)
|
||||||
|
s.GitRepos[tc.userID][tc.workspaceID] = &MockGitClient{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable the repo
|
||||||
|
s.DisableGitRepo(tc.userID, tc.workspaceID)
|
||||||
|
|
||||||
|
// Verify repo was removed
|
||||||
|
if userRepos, exists := s.GitRepos[tc.userID]; exists {
|
||||||
|
if _, repoExists := userRepos[tc.workspaceID]; repoExists {
|
||||||
|
t.Error("git repo still exists after disable")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this was the user's last repo, verify user entry was cleaned up
|
||||||
|
if tc.setupRepo {
|
||||||
|
if len(s.GitRepos[tc.userID]) > 0 {
|
||||||
|
t.Error("user's git repos map not cleaned up when last repo removed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,28 +14,39 @@ type Manager interface {
|
|||||||
// Service represents the file system structure.
|
// Service represents the file system structure.
|
||||||
type Service struct {
|
type Service struct {
|
||||||
fs fileSystem
|
fs fileSystem
|
||||||
|
newGitClient func(url, user, token, path string) git.Client
|
||||||
RootDir string
|
RootDir string
|
||||||
GitRepos map[int]map[int]git.Client // map[userID]map[workspaceID]*git.Client
|
GitRepos map[int]map[int]git.Client // map[userID]map[workspaceID]*git.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Options represents the options for the storage service.
|
||||||
|
type Options struct {
|
||||||
|
Fs fileSystem
|
||||||
|
NewGitClient func(url, user, token, path string) git.Client
|
||||||
|
}
|
||||||
|
|
||||||
// NewService creates a new Storage instance.
|
// NewService creates a new Storage instance.
|
||||||
// Parameters:
|
// Parameters:
|
||||||
// - rootDir: the root directory for the storage
|
// - rootDir: the root directory for the storage
|
||||||
// Returns:
|
// Returns:
|
||||||
// - result: the new Storage instance
|
// - result: the new Storage instance
|
||||||
func NewService(rootDir string) *Service {
|
func NewService(rootDir string) *Service {
|
||||||
return NewServiceWithFS(rootDir, &osFS{})
|
return NewServiceWithOptions(rootDir, Options{
|
||||||
|
Fs: &osFS{},
|
||||||
|
NewGitClient: git.New,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewServiceWithFS creates a new Storage instance with the given filesystem.
|
// NewServiceWithOptions creates a new Storage instance with the given options.
|
||||||
// Parameters:
|
// Parameters:
|
||||||
// - rootDir: the root directory for the storage
|
// - rootDir: the root directory for the storage
|
||||||
// - fs: the filesystem implementation to use
|
// - opts: the options for the storage service
|
||||||
// Returns:
|
// Returns:
|
||||||
// - result: the new Storage instance
|
// - result: the new Storage instance
|
||||||
func NewServiceWithFS(rootDir string, fs fileSystem) *Service {
|
func NewServiceWithOptions(rootDir string, opts Options) *Service {
|
||||||
return &Service{
|
return &Service{
|
||||||
fs: fs,
|
fs: opts.Fs,
|
||||||
|
newGitClient: opts.NewGitClient,
|
||||||
RootDir: rootDir,
|
RootDir: rootDir,
|
||||||
GitRepos: make(map[int]map[int]git.Client),
|
GitRepos: make(map[int]map[int]git.Client),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,10 @@ import (
|
|||||||
|
|
||||||
func TestValidatePath(t *testing.T) {
|
func TestValidatePath(t *testing.T) {
|
||||||
mockFS := NewMockFS()
|
mockFS := NewMockFS()
|
||||||
s := storage.NewServiceWithFS("test-root", mockFS)
|
s := storage.NewServiceWithOptions("test-root", storage.Options{
|
||||||
|
Fs: mockFS,
|
||||||
|
NewGitClient: nil,
|
||||||
|
})
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -94,7 +97,10 @@ func TestValidatePath(t *testing.T) {
|
|||||||
|
|
||||||
func TestGetWorkspacePath(t *testing.T) {
|
func TestGetWorkspacePath(t *testing.T) {
|
||||||
mockFS := NewMockFS()
|
mockFS := NewMockFS()
|
||||||
s := storage.NewServiceWithFS("test-root", mockFS)
|
s := storage.NewServiceWithOptions("test-root", storage.Options{
|
||||||
|
Fs: mockFS,
|
||||||
|
NewGitClient: nil,
|
||||||
|
})
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -134,7 +140,10 @@ func TestGetWorkspacePath(t *testing.T) {
|
|||||||
|
|
||||||
func TestInitializeUserWorkspace(t *testing.T) {
|
func TestInitializeUserWorkspace(t *testing.T) {
|
||||||
mockFS := NewMockFS()
|
mockFS := NewMockFS()
|
||||||
s := storage.NewServiceWithFS("test-root", mockFS)
|
s := storage.NewServiceWithOptions("test-root", storage.Options{
|
||||||
|
Fs: mockFS,
|
||||||
|
NewGitClient: nil,
|
||||||
|
})
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -199,7 +208,10 @@ func TestInitializeUserWorkspace(t *testing.T) {
|
|||||||
|
|
||||||
func TestDeleteUserWorkspace(t *testing.T) {
|
func TestDeleteUserWorkspace(t *testing.T) {
|
||||||
mockFS := NewMockFS()
|
mockFS := NewMockFS()
|
||||||
s := storage.NewServiceWithFS("test-root", mockFS)
|
s := storage.NewServiceWithOptions("test-root", storage.Options{
|
||||||
|
Fs: mockFS,
|
||||||
|
NewGitClient: nil,
|
||||||
|
})
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
Reference in New Issue
Block a user