mockfs

package module
v1.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 10, 2025 License: MIT Imports: 11 Imported by: 0

README

GoDoc GoMod Size License Go Go Report Card codecov

mockfs

A flexible and feature-rich filesystem mocking library for Go, built on top of testing/fstest.MapFS with powerful error injection and behavior simulation capabilities.

Perfect for testing code that interacts with the filesystem:

  • File I/O error handling
  • Filesystem edge cases
  • Race conditions
  • Performance degradation scenarios
  • Path handling issues

✨ Features

  • Simulates all standard filesystem operations (Open, Read, Write, Stat, ReadDir, Close)
  • Precise error injection with multiple strategies:
    • Exact path matching
    • Regular expression pattern matching
    • Operation-specific errors
    • One-time errors
    • Errors after N successful operations
  • Latency simulation for testing timeout handling
  • Write simulation (modify the filesystem in tests)
  • Operation statistics tracking for verification
  • Full implementation of the fs interfaces:
    • fs.FS
    • fs.ReadDirFS
    • fs.ReadFileFS
    • fs.StatFS
    • fs.SubFS

🚀 Usage

Basic Setup
import "github.com/balinomad/go-mockfs"

func TestMyFunction(t *testing.T) {
    // Create initial filesystem data
    fsData := map[string]*mockfs.MapFile{
        "config.json": {
            Data:    []byte(`{"setting": "value"}`),
            Mode:    0644,
            ModTime: time.Now(),
        },
        "data": {
            Mode:    fs.ModeDir | 0755,
            ModTime: time.Now(),
        },
    }

    // Create mockfs with 10ms simulated latency
    mock := mockfs.NewMockFS(fsData, mockfs.WithLatency(10*time.Millisecond))

    // Test your code that uses the filesystem
    result := YourFunction(mock)

    // Check stats
    stats := mock.GetStats()
    if stats.ReadCalls != 1 {
        t.Errorf("expected 1 read call, got %d", stats.ReadCalls)
    }
}
Error Injection
// Inject errors for specific paths and operations
mock.AddStatError("config.json", fs.ErrPermission)
mock.AddOpenError("secret.txt", fs.ErrNotExist)

// Inject errors using patterns
mock.AddErrorPattern(mockfs.OpRead, `\.log$`, mockfs.ErrCorrupted, mockfs.ErrorModeAlways, 0)

// Inject one-time errors
mock.AddOpenErrorOnce("data.db", mockfs.ErrTimeout)

// Inject errors after N successful operations
mock.AddReadErrorAfterN("large.bin", io.EOF, 3)

// Mark paths as non-existent
mock.MarkNonExistent("missing.txt", "config/old.json")
mock.MarkDirectoryNonExistent("temp")

// Add error for all operations on a path
mock.AddPathError("unstable.dat", mockfs.ErrCorrupted, mockfs.ErrorModeAlways, 0)
Write Simulation
// Enable write operations with a custom callback
mock := mockfs.NewMockFS(fsData, mockfs.WithWriteCallback(myWriteHandler))

// Or use the built-in write simulator
mock := mockfs.NewMockFS(fsData, mockfs.WithWritesEnabled())

// Then write to files
file, _ := mock.Open("newfile.txt")
writer := file.(io.Writer)
writer.Write([]byte("hello world"))
file.Close()
Adding or Modifying Files
// Add text files
mock.AddFileString("config.yml", "key: value", 0644)

// Add binary files
mock.AddFileBytes("image.png", pngData, 0644)

// Add directories
mock.AddDirectory("logs", 0755)

// Remove paths
mock.RemovePath("temp/cache.dat")

📌 Installation

go get github.com/balinomad/go-mockfs@latest

📘 API Reference

Constructors and Options
Function/Option Description
NewMockFS(data, ...options) Creates a new mock filesystem
WithLatency(duration) Adds simulated operation latency
WithWriteCallback(func) Enables writes with custom handler
WithWritesEnabled() Enables writes to modify the internal map
Error Injection
Method Description
AddErrorExactMatch(op, path, err, mode, successes) Adds error for exact path and operation
AddErrorPattern(op, pattern, err, mode, successes) Adds error for paths matching a pattern
AddPathError(path, err, mode, successes) Adds error for all operations on a path
AddPathErrorPattern(pattern, err, mode, successes) Adds error for all operations on matching paths
AddStatError(path, err) Adds error for Stat operation
AddOpenError(path, err) Adds error for Open operation
AddReadError(path, err) Adds error for Read operation
AddWriteError(path, err) Adds error for Write operation
AddReadDirError(path, err) Adds error for ReadDir operation
AddCloseError(path, err) Adds error for Close operation
AddOpenErrorOnce(path, err) Adds one-time error for Open operation
AddReadErrorAfterN(path, err, n) Adds error after N successful reads
MarkNonExistent(paths...) Marks paths as non-existent
MarkDirectoryNonExistent(dirPath) Marks directory and contents as non-existent
ClearErrors() Clears all configured errors
Error Modes
Mode Description
ErrorModeAlways Error is returned on every operation
ErrorModeOnce Error is returned once, then cleared
ErrorModeAfterSuccesses Error is returned after N successful operations
Predefined Errors
Error Description
ErrInvalid Invalid argument error
ErrPermission Permission denied error
ErrExist File already exists error
ErrNotExist File does not exist error
ErrClosed File already closed error
ErrDiskFull Disk full error
ErrTimeout Operation timeout error
ErrCorrupted Corrupted data error
ErrTooManyHandles Too many open files error
ErrNotDir Not a directory error
File and Directory Management
Method Description
AddFileString(path, content, mode) Adds a text file
AddFileBytes(path, content, mode) Adds a binary file
AddDirectory(path, mode) Adds a directory
RemovePath(path) Removes a file or directory
GetStats() Returns operation statistics
ResetStats() Resets all operation counters

🔍 Implementation Details

The mockfs library works by wrapping testing/fstest.MapFS with error injection and behavior simulation capabilities:

  1. File operations go through wrappers that check for configured errors
  2. If an error is configured for the operation and path, it's returned
  3. Otherwise, the operation proceeds with the underlying MapFS
  4. MockFile wraps fs.File to intercept Read/Write/Close operations
  5. Operations statistics are tracked for test verification

🧪 Advanced Testing Patterns

Testing Error Recovery
func TestErrorRecovery(t *testing.T) {
    mock := mockfs.NewMockFS(nil)
    mock.AddFileString("data.txt", "initial content", 0644)

    // First read will fail, second will succeed
    mock.AddReadErrorOnce("data.txt", io.ErrUnexpectedEOF)

    // Test that your code retries on error
    result := YourFunctionThatRetries(mock)

    if !result.Success {
        t.Error("function should have recovered from error")
    }
}
Testing Timeout Handling
func TestTimeoutHandling(t *testing.T) {
    mock := mockfs.NewMockFS(nil, mockfs.WithLatency(2*time.Second))

    // Set a context with timeout
    ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
    defer cancel()

    // Test your function handles timeout properly
    err := YourFunctionWithContext(ctx, mock)

    if !errors.Is(err, context.DeadlineExceeded) {
        t.Error("function should have timed out")
    }
}

⚖️ License

MIT License — see LICENSE file for details.

Documentation

Overview

Package mockfs provides a mock filesystem implementation based on testing/fstest.MapFS, allowing for controlled error injection and latency simulation for testing purposes.

Index

Constants

This section is empty.

Variables

View Source
var (
	// Standard fs errors
	ErrInvalid    = fs.ErrInvalid    // "invalid argument"
	ErrPermission = fs.ErrPermission // "permission denied"
	ErrExist      = fs.ErrExist      // "file already exists"
	ErrNotExist   = fs.ErrNotExist   // "file does not exist"
	ErrClosed     = fs.ErrClosed     // "file already closed"

	// Additional custom errors
	ErrDiskFull       = errors.New("disk full")
	ErrTimeout        = errors.New("operation timeout")
	ErrCorrupted      = errors.New("corrupted data")
	ErrTooManyHandles = errors.New("too many open files")
	ErrNotDir         = errors.New("not a directory")
)

Common errors that can be used with the mock

Functions

func AllOperations

func AllOperations() map[Operation]struct{}

AllOperations returns a map representing all known Operation types. Used for iteration.

Types

type ErrorConfig

type ErrorConfig struct {
	Error    error            // The error to return
	Mode     ErrorMode        // How the error is applied
	Counter  atomic.Int64     // Counter for behaviors like ErrorModeOnce and ErrorModeAfterSuccesses (using atomic for safety)
	Matches  []string         // Exact path matches
	Patterns []*regexp.Regexp // Pattern matches
	// contains filtered or unexported fields
}

ErrorConfig captures the settings for an error to be injected.

func NewErrorConfig

func NewErrorConfig(err error, mode ErrorMode, counter int, matches []string, patterns []*regexp.Regexp) *ErrorConfig

NewErrorConfig creates a new error configuration pointer. For ErrorModeAfterSuccesses, 'counter' is the number of successes *before* the error. For ErrorModeOnce, 'counter' is ignored.

func (*ErrorConfig) Clone

func (c *ErrorConfig) Clone() *ErrorConfig

Clone creates a deep copy of the ErrorConfig. It ensures atomic values are copied correctly and slices are handled appropriately.

type ErrorMode

type ErrorMode int

ErrorMode defines how an error is applied (always, once, etc.)

const (
	// ErrorModeAlways means the error is returned every time
	ErrorModeAlways ErrorMode = iota
	// ErrorModeOnce means the error is returned once, then cleared
	ErrorModeOnce
	// ErrorModeAfterSuccesses means the error is returned after N successful calls
	ErrorModeAfterSuccesses
)

type MapFile

type MapFile = fstest.MapFile

A MapFile describes a single file in a [MapFS]. See testing/fstest.MapFile.

type MockFS

type MockFS struct {
	// contains filtered or unexported fields
}

MockFS wraps fstest.MapFS to inject errors for specific paths and operations.

func NewMockFS

func NewMockFS(data map[string]*MapFile, opts ...Option) *MockFS

NewMockFS creates a new MockFS with the given MapFS data and options.

func (*MockFS) AddCloseError

func (m *MockFS) AddCloseError(path string, err error)

AddCloseError configures a path to return the specified error on Close calls. It is a convenience method for AddErrorExactMatch with ErrorModeAlways mode.

func (*MockFS) AddDirectory

func (m *MockFS) AddDirectory(path string, mode fs.FileMode)

AddDirectory adds a directory to the mock filesystem. Overwrites if exists.

func (*MockFS) AddError

func (m *MockFS) AddError(op Operation, config *ErrorConfig)

AddError adds an error configuration pointer for a specific operation.

func (*MockFS) AddErrorExactMatch

func (m *MockFS) AddErrorExactMatch(op Operation, path string, err error, mode ErrorMode, successes int)

AddErrorExactMatch adds an error for exact path matches on a specific operation.

func (*MockFS) AddErrorPattern

func (m *MockFS) AddErrorPattern(op Operation, pattern string, err error, mode ErrorMode, successes int) error

AddErrorPattern adds an error for pattern matches on a specific operation.

func (*MockFS) AddFileBytes

func (m *MockFS) AddFileBytes(path string, content []byte, mode fs.FileMode)

AddFileBytes adds a binary file to the mock filesystem. Overwrites if exists.

func (*MockFS) AddFileString

func (m *MockFS) AddFileString(path string, content string, mode fs.FileMode)

AddFileString adds a text file to the mock filesystem. Overwrites if exists.

func (*MockFS) AddOpenError

func (m *MockFS) AddOpenError(path string, err error)

AddOpenError configures a path to return the specified error on Open calls. It is a convenience method for AddErrorExactMatch with ErrorModeAlways mode.

func (*MockFS) AddOpenErrorOnce

func (m *MockFS) AddOpenErrorOnce(path string, err error)

AddOpenErrorOnce configures a path to return the specified error on Open once. It is a convenience method for AddErrorExactMatch with ErrorModeOnce mode.

func (*MockFS) AddPathError

func (m *MockFS) AddPathError(path string, err error, mode ErrorMode, successes int)

AddPathError adds the same error config for *all* operations on an exact path.

func (*MockFS) AddPathErrorPattern

func (m *MockFS) AddPathErrorPattern(pattern string, err error, mode ErrorMode, successes int) error

AddPathErrorPattern adds the same error config for *all* operations matching a pattern.

func (*MockFS) AddReadDirError

func (m *MockFS) AddReadDirError(path string, err error)

AddReadDirError configures a path to return the specified error on ReadDir calls. It is a convenience method for AddErrorExactMatch with ErrorModeAlways mode.

func (*MockFS) AddReadError

func (m *MockFS) AddReadError(path string, err error)

AddReadError configures a path to return the specified error on Read calls. It is a convenience method for AddErrorExactMatch with ErrorModeAlways mode.

func (*MockFS) AddReadErrorAfterN

func (m *MockFS) AddReadErrorAfterN(path string, err error, successes int)

AddReadErrorAfterN configures a read error after N successful reads. It is a convenience method for AddErrorExactMatch with ErrorModeAfterSuccesses mode.

func (*MockFS) AddStatError

func (m *MockFS) AddStatError(path string, err error)

AddStatError configures a path to return the specified error on Stat. It is a convenience method for AddErrorExactMatch with ErrorModeAlways mode.

func (*MockFS) AddWriteError

func (m *MockFS) AddWriteError(path string, err error)

AddWriteError configures a path to return the specified error on Write calls. It is a convenience method for AddErrorExactMatch with ErrorModeAlways mode.

func (*MockFS) ClearErrors

func (m *MockFS) ClearErrors()

ClearErrors removes all configured errors for all operations.

func (*MockFS) GetStats

func (m *MockFS) GetStats() Stats

GetStats returns the current operation counts.

func (*MockFS) MarkDirectoryNonExistent

func (m *MockFS) MarkDirectoryNonExistent(dirPath string)

MarkDirectoryNonExistent removes a directory and all its contents from the map and injects ErrNotExist errors for the directory path and a pattern matching its contents.

func (*MockFS) MarkNonExistent

func (m *MockFS) MarkNonExistent(paths ...string)

MarkNonExistent injects ErrNotExist for all operations on the given paths.

func (*MockFS) Open

func (m *MockFS) Open(name string) (fs.File, error)

Open intercepts the Open call and returns configured errors for paths. It implements the fs.FS interface.

func (*MockFS) ReadDir

func (m *MockFS) ReadDir(name string) ([]fs.DirEntry, error)

ReadDir implements the fs.ReadDirFS interface.

func (*MockFS) ReadFile

func (m *MockFS) ReadFile(name string) ([]byte, error)

ReadFile implements the fs.ReadFileFS interface. This implementation tries to use the mock's own methods for consistency.

func (*MockFS) RemovePath

func (m *MockFS) RemovePath(path string)

RemovePath removes a file or directory from the mock filesystem. Note: This does not recursively remove directory contents.

func (*MockFS) ResetStats

func (m *MockFS) ResetStats()

ResetStats resets all operation counters to zero.

func (*MockFS) Stat

func (m *MockFS) Stat(name string) (fs.FileInfo, error)

Stat intercepts the Stat call and returns configured errors for paths. It implements the fs.StatFS interface.

func (*MockFS) Sub

func (m *MockFS) Sub(dir string) (fs.FS, error)

Sub implements fs.SubFS to return a sub-filesystem.

type MockFile

type MockFile struct {
	// contains filtered or unexported fields
}

MockFile wraps fs.File to inject errors and track operations.

func (*MockFile) Close

func (f *MockFile) Close() error

Close implements the io.Closer interface for MockFile.

func (*MockFile) Read

func (f *MockFile) Read(b []byte) (int, error)

Read implements the io.Reader interface for MockFile.

func (*MockFile) Stat

func (f *MockFile) Stat() (fs.FileInfo, error)

Stat implements the fs.File interface's Stat method.

func (*MockFile) Write

func (f *MockFile) Write(b []byte) (int, error)

Write implements the io.Writer interface for files that support it or if a write callback is configured on the MockFS.

type Operation

type Operation int

Operation defines the type of filesystem operation for error injection context.

const (
	OpStat Operation = iota
	OpOpen
	OpRead
	OpWrite
	OpReadDir
	OpClose
)

type Option

type Option func(*MockFS)

Option is a function type for configuring MockFS.

func WithLatency

func WithLatency(d time.Duration) Option

WithLatency sets the simulated latency for operations.

func WithWriteCallback

func WithWriteCallback(callback func(path string, data []byte) error) Option

WithWriteCallback sets a callback function to handle writes. This allows simulating writes by updating external state or the internal map.

func WithWritesEnabled

func WithWritesEnabled() Option

WithWritesEnabled allows write operations, simulating them by modifying the internal MapFS. Note: This modifies the underlying map, use with caution if the original map data is important.

type Stats

type Stats struct {
	StatCalls    int
	OpenCalls    int
	ReadCalls    int
	WriteCalls   int
	ReadDirCalls int
	CloseCalls   int
}

Stats records operation counts for verification in tests. Ensure field names match those accessed in fs.go's incrementStat.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL