This package provides file system scanning and tracking functionality for both local file systems and Google Drive.
The filesys package contains:
- Scanner Interface: Defines the interface for scanning directories and returning tree nodes
- File System Scanner: Implementation for local Unix file systems
- Google Drive Scanner: Implementation for Google Drive directories
- Context-Aware Tracker: Tracks files/directories based on the current context (local or gdrive)
This package uses mockery to generate mocks for testing. The mocks are generated for interfaces to enable unit testing without external dependencies.
-
Install mockery:
go install github.com/vektra/mockery/v3@latest
-
Install gomock dependency (required for expecter-style mocks):
go get go.uber.org/mock/gomock
-
Generate mocks:
# From the project root mockeryThis will generate mocks based on the
.mockery.yamlconfiguration file in the project root.Note: Mock generation requires network access to download Go dependencies if needed.
The following mocks are generated in the mocks/ directory:
mocks/services/mock_GDriveServiceInterface.go- Mock for Google Drive servicemocks/filesys/mock_Scanner.go- Mock for Scanner interfacemocks/filesys/mock_ScannableNode.go- Mock for ScannableNode interfacemocks/filesys/mock_Tracker.go- Mock for Tracker interfacemocks/repository/filesys/mock_ContextRepository.go- Mock for ContextRepository interfacemocks/storage/- Mocks for TreeReader, TreeWriter, TreeRW, RWFactorymocks/file/- Mocks for NodeInformable, SerializableNode, TagsPrinter, NodePrinter, IdPrintermocks/printer/- Mocks for ListPrintable, PrintingContextmocks/ds/- Mocks for TreeIterable, NodeIterable, InfoSerializer, TreeNodeInformable
All mocks use package mocks and can be imported from their respective subdirectories.
package cmd_test
import (
"context"
"testing"
"github.com/heroku/self/MetaManager/internal/filesys"
"github.com/heroku/self/MetaManager/internal/services"
servicemocks "github.com/heroku/self/MetaManager/mocks/services"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/mock"
)
func TestTrackGDrive(t *testing.T) {
// Create a mock GDrive service
mockSvc := servicemocks.NewMockGDriveServiceInterface(t)
// Set up expectations using testify mock pattern
mockSvc.On("ResolvePath", mock.Anything, "Folder1").
Return("folder1", nil)
mockSvc.On("ListFolder", mock.Anything, "folder1").
Return([]services.RootEntry{
{Id: "sub1", Name: "Sub", IsFolder: true, MimeType: services.DriveFolderMimeType},
{Id: "file1", Name: "file1.txt", IsFolder: false, MimeType: "text/plain"},
}, nil)
// Create scanner with mock
scanner := filesys.NewGDriveScanner(mockSvc)
// Test the functionality
tree, err := scanner.TrackGDrive(context.Background(), "/Folder1", false)
require.NoError(t, err)
require.NotNil(t, tree)
// Assert all expectations were met
mockSvc.AssertExpectations(t)
}Note: The mockery-generated mocks use go.uber.org/mock/gomock for expecter-style mocking. Make sure to add this dependency:
go get go.uber.org/mock/gomockimport (
filesysmocks "github.com/heroku/self/MetaManager/mocks/filesys"
"github.com/stretchr/testify/mock"
)
func TestContextAwareTracker(t *testing.T) {
// Create a mock scanner
mockScanner := filesysmocks.NewMockScanner(t)
// Set up expectations
mockScanner.On("Scan", "/some/path").
Return(&ds.TreeNode{...}, nil)
// Use the mock in your test
// ...
// Assert all expectations were met
mockScanner.AssertExpectations(t)
}After modifying interfaces, regenerate the mocks:
mockeryOr regenerate specific interfaces using the interface name:
mockery --name GDriveServiceInterface --dir internal/servicesNote: Mock generation requires network access if Go dependencies need to be downloaded.
The mockery configuration is stored in .mockery.yaml at the project root. Key settings:
template: testify- Uses the testify mock template (supports expecter-style mocks)template-data.with-expecter: true- Generates expecter-style mocks (gomock compatible)structname: "Mock{{.InterfaceName}}"- Naming convention for generated mocksdir: "mocks"- Output directory for mocks (relative to interface package)filename: "{{.MockName}}.go"- Filename pattern for generated mocks
The configuration generates mocks in subdirectories under mocks/:
GDriveServiceInterfaceinmocks/services/Scanner,ScannableNode, andTrackerinmocks/filesys/ContextRepositoryinmocks/repository/filesys/- Storage interfaces in
mocks/storage/ - File interfaces in
mocks/file/ - Printer interfaces in
mocks/printer/ - Data structure interfaces in
mocks/ds/
All mocks use package mocks and can be imported from their respective subdirectories.
- Always use mocks in tests - Don't rely on real external services (like Google Drive API) in unit tests
- Set up expectations - Use
EXPECT()to define what methods should be called and what they should return - Verify calls - Use
gomock.Controllerto ensure all expected calls were made - Keep mocks in sync - Regenerate mocks after interface changes
- Commit mocks - Include generated mock files in version control for consistency
Issue: Mocks not generating
- Solution: Ensure mockery is installed and
.mockery.yamlis in the project root
Issue: Import errors in generated mocks
- Solution: Run
go mod tidyafter generating mocks
Issue: Mocks out of date
- Solution: Regenerate mocks with
mockerycommand
internal/filesys/
├── scanner.go # Scanner interface and factory
├── file_scanner.go # Local file system scanner
├── gdrive_scanner.go # Google Drive scanner
├── track.go # Context-aware tracker
├── mocks/ # Generated mocks (git tracked)
│ ├── MockScanner.go
│ └── MockScannableNode.go
└── README.md # This file
internal/services- Google Drive service implementationinternal/data- Tree data structures and managementinternal/file- File node definitionsinternal/repository/filesys- Context repository for file system contexts