lens

package
v0.1.12 Latest Latest
Warning

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

Go to latest
Published: Dec 19, 2025 License: AGPL-3.0 Imports: 61 Imported by: 0

Documentation

Index

Constants

View Source
const ErrorLogPrefix = "!! "

ErrorLogPrefix is used to prefix unexpected error log messages.

View Source
const GeneratedTestFileSuffix = "_modlensgen_test.go"
View Source
const GeneratedTestFunctionPrefix = "TestGen_"
View Source
const (
	HashFieldValuePrefix = "vsha1-"
)
View Source
const MinGoVersion = "1.13" // Go 1.13+ is required due to signed shift count operations in generated code.

MinGoVersion defines the minimum Go version required for instrumentation.

Variables

View Source
var ErrNoFunctionBody = errors.New("function has no body (likely assembly or external implementation)")

ErrNoFunctionBody indicates a function has no body (e.g., assembly-only or external).

Functions

func AnalyzeModuleChanges

func AnalyzeModuleChanges(gomodcache string, includeTransitive bool, projectDir string, moduleChanges []*ModuleChange,
	neighbourRadius int) (map[string][]*ModuleFunction, map[string][]*packages.Package, error)

AnalyzeModuleChanges loads all Go packages for a module between two versions and returns the functions that are new or whose definitions have changed. It also checks for go.mod differences to analyze dependency changes (if the dependency is also used in the project's go.mod).

Both old and new module versions are loaded in parallel from the module cache. The returned changed functions contain the OLD version's Definition with LineChangeBitmap marking changed lines in the old definition.

Returns:

  • map[string][]*ModuleFunction: Changed functions by module (keyed by module name)
  • map[string][]*packages.Package: NEW version packages for each module (keyed by module name)
  • []*ModuleFunction: All changed functions (flat list)
  • []string: Module names that were analyzed
  • error: Any error during analysis

func CallerStaticAnalysis

func CallerStaticAnalysis(moduleChanges []*ModuleFunction, projectDir, gopath, gomodcache string) ([]*CallerFunction, ReachableModuleChange, *callgraph.Graph, []*packages.Package, []*packages.Package, error)

CallerStaticAnalysis performs static analysis to determine which project functions call the provided moduleChanges. Returned are the functions in the project that may delegate to the updated module functions, along with the call graph, project packages, and module packages with type information.

func CopyDir

func CopyDir(ctx context.Context, src, dst string, progressNotify func(string, os.FileInfo)) error

CopyDir recursively copies src directory contents into dst.

func CopyFile

func CopyFile(src, dst string) (err error)

CopyFile copies src to dst. If src is a symlink, it recreates the symlink at dst pointing to the same target. Otherwise, it copies the file’s contents (using os.Create’s default mode).

func ErrGroupLimitCPU

func ErrGroupLimitCPU() *errgroup.Group

ErrGroupLimitCPU returns an errgroup limited to NumCPU.

func ExecGoTest

func ExecGoTest(dir string, env []string, output io.Writer, tFunc *TestFunction) error

ExecGoTest runs go test for a single test function in the given directory.

func FileExists

func FileExists(filename string) bool

FileExists reports whether the named file exists.

func FindModulePathInCache added in v0.1.0

func FindModulePathInCache(gomodcache, modPath, version string) (string, error)

FindModulePathInCache attempts to locate a module@version in the local module cache. Returns the filesystem directory where the module source is located.

func FindModuleVersion

func FindModuleVersion(projectDir, modName string) (string, bool, error)

FindModuleVersion searches for modName across all go.mod files in projectDir.

func FindModuleVersionInGoMod

func FindModuleVersionInGoMod(goModFile, modName string) (string, bool, error)

FindModuleVersionInGoMod parses the given go.mod file to find the version of the specified module. Returns empty string if the module is not found in the go.mod file.

func GoEnv

func GoEnv(gopath, gomodcache string) []string

GoEnv returns environment entries for GOPATH and GOMODCACHE.

func IsGeneratedFile

func IsGeneratedFile(filename string) bool

IsGeneratedFile returns true if the filename follows known patterns for generated go files.

func IsGoVersionBelowMinimum added in v0.1.12

func IsGoVersionBelowMinimum(goVersion string) bool

IsGoVersionBelowMinimum returns true if goVersion is below MinGoVersion.

func IsNormalAstError added in v0.1.12

func IsNormalAstError(err error) bool

IsNormalAstError returns true if the error should be skipped rather than failing.

func LoadProjectCallGraph added in v0.1.0

func LoadProjectCallGraph(projectDir, gopath, gomodcache string, includeTests bool) (*callgraph.Graph, *ssa.Program, []*packages.Package, []*packages.Package, error)

LoadProjectCallGraph loads the project packages and creates an SSA Program and call-graph. Returns the call graph, SSA program, project packages, module packages, and any error encountered.

func MakeFunctionIdent

func MakeFunctionIdent(pkgName string, funcDecl *ast.FuncDecl) string

MakeFunctionIdent creates a normalized key with package and receiver type.

func MakeSSAFunctionIdent added in v0.1.0

func MakeSSAFunctionIdent(fn *ssa.Function) (string, bool)

MakeSSAFunctionIdent creates a normalized key for a SSA function, incorporating package and (if any) receiver type. Returns the function identifier string and a boolean indicating if it was successfully extracted from AST.

func NewProjectCapturedOutputExec

func NewProjectCapturedOutputExec(projectDir string, env []string, name string, arg ...string) ([]byte, error)

NewProjectCapturedOutputExec runs a command in projectDir with env, streams output, and returns combined stdout and stderr.

func NewProjectExec

func NewProjectExec(projectDir string, env []string, name string, arg ...string) *exec.Cmd

NewProjectExec creates a command that runs in projectDir with env applied.

func NewProjectLoggedExec

func NewProjectLoggedExec(projectDir string, env []string, name string, arg ...string) *exec.Cmd

NewProjectLoggedExec runs a command in projectDir with env and logs output to stdout and stderr.

func PrepareReportData added in v0.1.0

func PrepareReportData(changedModules []*ModuleChange, projectCallingFunctions []*CallerFunction,
	relevantTestFunctions []*TestFunction, testResults []TestReport,
	moduleChangeFuncCount int) (reachableModuleFunctionsIdents []string,
	relevantProjectFunctionIdents []string, relevantTestFunctionsIdents []string,
	performanceChanges []PerformanceChange, testDetails []TestDetail,
	rootM ModuleChange, syntheticTestFuncCount int)

PrepareReportData prepares all the data needed for report generation.

func ProjectGoModFiles

func ProjectGoModFiles(projectDir string) ([]string, error)

ProjectGoModFiles returns all go.mod files for the project directory, supporting workspaces via go.work.

func ProjectPackagePatterns

func ProjectPackagePatterns(projectDir string) ([]string, error)

ProjectPackagePatterns returns go test patterns for all modules in projectDir. Each pattern includes "/..." for recursive package loading.

func RenderReportChartsFromJson

func RenderReportChartsFromJson(report ReportMetrics) ([]byte, error)

RenderReportChartsFromJson takes a ReportMetrics and renders the report to a png.

func RunModuleUpdateAnalysis

func RunModuleUpdateAnalysis(gopath, gomodcache, projectDir string, portStart int,
	storage Storage, maxVariableRecurse, maxFieldLen int,
	changedModules []*ModuleChange, reachableModuleChanges ReachableModuleChange,
	callingFunctions []*CallerFunction, testFunctions []*TestFunction,
	preUpdateExtensionConfig func(*ASTModifier) (map[uint32]*string, error),
	postUpdateExtensionConfig func(*ASTModifier) (map[uint32]*string, error)) (int, int, int, Storage, Storage, error)

RunModuleUpdateAnalysis modifies the project and modules AST to include hooks for calls into the AST client. Our astServer accepts these calls, and invokes back into our code here so that we can analyze the project execution.

Extension point configurations allow custom monitoring to be injected into module code:

  • preUpdateExtensionConfig: Called before first test run (old version)
  • postUpdateExtensionConfig: Called before second test run (new version)

Both hooks are optional (can be nil). The returned point IDs from both are merged for monitoring. Returns: projectFieldChecks, moduleChangesReached, skippedModuleFuncs, preResults, postResults, error

func SnappyCompress

func SnappyCompress(dst, data []byte) []byte

SnappyCompress compresses a byte slice using snappy and returns the compressed data.

func SnappyDecompress

func SnappyDecompress(dst, data []byte) ([]byte, error)

SnappyDecompress decompresses a snappy-compressed byte slice and returns the decompressed data. Returns nil if the input is invalid or decompression fails.

func StackFramesKey added in v0.1.0

func StackFramesKey(bb *bytes.Buffer, frames []StackFrame) string

StackFramesKey creates a unique key from stack frames for frame matching. This is used to match call frames across pre/post update executions.

func TeeWriter

func TeeWriter(writers ...io.Writer) io.WriteCloser

TeeWriter duplicates writes across chained writers.

func WriteChmod

func WriteChmod(ctx context.Context, root string) error

WriteChmod adds write permissions for owner/group/others on every file and directory under root.

func ZstdCompress

func ZstdCompress(dst, data []byte) []byte

ZstdCompress compresses a byte slice using zstd and returns the compressed data.

func ZstdDecompress

func ZstdDecompress(dst, data []byte) ([]byte, error)

ZstdDecompress decompresses a zstd-compressed byte slice and returns the original data.

Types

type ASTModifier added in v0.1.0

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

ASTModifier provides utilities for modifying Go AST. Extensions can use this to inject custom monitoring at specific points in code.

func (*ASTModifier) Commit added in v0.1.0

func (m *ASTModifier) Commit() error

Commit flushes all pending AST modifications to disk.

func (*ASTModifier) CommitFile added in v0.1.0

func (m *ASTModifier) CommitFile(filepath string) error

CommitFile writes pending edits for a single file.

func (*ASTModifier) InjectASTClient added in v0.1.0

func (m *ASTModifier) InjectASTClient(pkgDir string, srvPort int, maxFieldRecurse, maxFieldLen int) error

InjectASTClient prepares a package directory by inserting the configured client code to enable other AST point functions.

func (*ASTModifier) InjectFuncPointBeforeCall added in v0.1.0

func (m *ASTModifier) InjectFuncPointBeforeCall(fn *Function, shouldInject func(*ast.CallExpr) (metadata any, inject bool)) (map[uint32]any, error)

InjectFuncPointBeforeCall injects monitoring points before call expressions that match the predicate. The predicate function is called for each CallExpr in the function body. If it returns true for inject, a state monitoring point is injected immediately before that call, and the returned metadata is associated with that point ID.

The monitoring point captures only the arguments passed to the matched call, not all visible variables, to reduce memory overhead and focus on the specific data being passed to the function.

Returns a map from point ID to caller-provided metadata for all injection points.

func (*ASTModifier) InjectFuncPointEntry added in v0.1.0

func (m *ASTModifier) InjectFuncPointEntry(fn *Function) (uint32, error)

InjectFuncPointEntry injects a sendLensPointMessage call at function entry for coverage tracking.

func (*ASTModifier) InjectFuncPointFinish added in v0.1.0

func (m *ASTModifier) InjectFuncPointFinish(fn *Function) (uint32, error)

InjectFuncPointFinish injects a deferred sendLensPointMessage call to track function completion.

func (*ASTModifier) InjectFuncPointPanic added in v0.1.0

func (m *ASTModifier) InjectFuncPointPanic(f *Function) (uint32, error)

InjectFuncPointPanic inserts a defer recovery at the start of the function. This recovery will invoke the client to communicate the state, but then re-panic. Because this is the first defer statement, it will trigger only if no other recovery exists.

func (*ASTModifier) InjectFuncPointReturnStates added in v0.1.0

func (m *ASTModifier) InjectFuncPointReturnStates(fn *Function) ([]uint32, error)

InjectFuncPointReturnStates inserts a state point right before the return points within the function. If the return line has a function call, the return point will be inserted after the call.

func (*ASTModifier) InsertFuncLines added in v0.1.0

func (m *ASTModifier) InsertFuncLines(fn *Function, cb func(i int, line string) (insertText string, keepGoing bool)) error

InsertFuncLines walks each source‐line of the given function and lets the caller insert an arbitrary comment (or other text) before any line. The callback returns three values:

  • insertText: the text to insert above the current line (e.g. “// …”). If empty, nothing will be inserted.
  • keepGoing: true if we should continue processing subsequent lines.

func (*ASTModifier) MaxPointId added in v0.1.0

func (m *ASTModifier) MaxPointId() int

MaxPointId returns the highest point currently tracked.

func (*ASTModifier) Restore added in v0.1.0

func (m *ASTModifier) Restore(goenv []string) (result []error)

Restore restores the modified files to their original state. The go environment must be provided so the build cache can be cleared.

type AnalysisEngine

type AnalysisEngine struct {
	Config                 *Config
	ModuleChangeProvider   ModuleChangeProvider
	CallerAnalysisProvider CallerAnalysisProvider
	TestProvider           TestProvider
	UpdateAnalysisProvider UpdateAnalysisProvider
	MutationTester         MutationTester
	TestResultAnalyzer     TestResultAnalyzer
	StorageProvider        StorageProvider
	ReportWriter           ReportWriter
}

AnalysisEngine orchestrates module change analysis, testing, and reporting.

func NewAnalysisEngine

func NewAnalysisEngine(config *Config) *AnalysisEngine

NewAnalysisEngine creates an AnalysisEngine with default providers.

func NewAnalysisEngineWithProviders

func NewAnalysisEngineWithProviders(config *Config, moduleChangeProvider ModuleChangeProvider,
	callerAnalysisProvider CallerAnalysisProvider, testProvider TestProvider,
	updateAnalysisProvider UpdateAnalysisProvider, mutationTester MutationTester,
	testResultAnalyzer TestResultAnalyzer, storageProvider StorageProvider,
	reportWriter ReportWriter) *AnalysisEngine

NewAnalysisEngineWithProviders creates an AnalysisEngine using the supplied providers.

func (*AnalysisEngine) Run

func (e *AnalysisEngine) Run() error

Run executes the analysis workflow using configured providers.

type CallFrame

type CallFrame struct {
	// FieldValues records the captured state.
	FieldValues FieldValues `msgpack:"f"`
	// Stack holds the call stack.
	Stack []StackFrame `msgpack:"s"`
	// TimeMillis is the execution time in milliseconds since process start.
	TimeMillis uint32 `msgpack:"t"`
}

CallFrame records field values for a single call and its stack

type CallerAnalysisProvider

type CallerAnalysisProvider interface {
	// PerformCallerStaticAnalysis analyzes the project's source code to find all
	// functions that directly or indirectly call the changed module functions.
	// It builds a call graph to trace how module changes might affect project code.
	//
	// Parameters:
	//   - config: configuration containing paths and settings for analysis
	//   - moduleChanges: list of functions in dependencies that have changed
	//
	// Returns:
	//   - []*CallerFunction: list of project functions that call changed module functions
	//   - ReachableModuleChange: mapping of which module changes are reachable from project code
	//   - error: any error encountered during static analysis
	PerformCallerStaticAnalysis(config Config, moduleChanges []*ModuleFunction) ([]*CallerFunction, ReachableModuleChange, error)

	// Cleanup is invoked after engine analysis is complete, allowing freeing of resources used during static analysis.
	Cleanup()
}

CallerAnalysisProvider performs static analysis to identify project functions that call changed module functions. This establishes the call graph from the project code to the modified dependency functions.

type CallerFunction

type CallerFunction struct {
	Function

	// ChangeFunctions lists changed functions invoked by this caller.
	ChangeFunctions []*ModuleFunction
}

CallerFunction ties a caller in the project to a changed function.

func (CallerFunction) ChangeFunctionIdents

func (f CallerFunction) ChangeFunctionIdents() string

ChangeFunctionIdents returns short idents of invoked changes.

type Config

type Config struct {
	ProjectDir, ModuleVersionFlag, ModulesVersionFlag     string
	UpdatedGoModFile, UpdatedGoWorkFile                   string
	AstMonitorPort, MaxFieldRecurse, MaxFieldLen, CacheMB int
	ReportJsonFile, ReportChartsFile                      string
	MutationScope, MutationMode, MutationTests            string
	TmpCopy                                               bool
	TimeMultiplier                                        int
	// Computed fields
	Gopath, Gomodcache, AbsProjDir string
	// Parsed target modules from flags
	TargetModules []TargetModule
	// Custom flags support - all stored as strings for ease of use
	CustomFlags map[string]string
	// contains filtered or unexported fields
}

Config holds settings and state for an AnalysisEngine.

func (*Config) Prepare

func (c *Config) Prepare() error

Prepare performs comprehensive validation and preparation of the configuration

type DefaultCallerAnalysisProvider

type DefaultCallerAnalysisProvider struct {
	// PostCallerAnalysis is an optional hook called after project caller static analysis completes.
	//
	// The hook is called once after all project callers have been identified.
	//
	// Parameters:
	//   - projectPackages: Project packages with type information from static analysis
	//   - modulePackages: Module (dependency) packages with type information from static analysis
	//   - identEdges: Call graph edges mapping function idents to callees
	//   - moduleChanges: All functions that changed in module updates
	//   - callers: Project functions that call into changed module functions
	//   - reachable: Map of which module changes are reachable from project code
	//
	// The package parameters provide access to type information for accurate analysis.
	// Project and module packages are separated to enable targeted analysis.
	// The identEdges parameter provides a simplified view of the project call graph,
	// enabling extensions to perform additional reachability analysis without needing
	// to reload the expensive SSA call graph.
	//
	// Returns:
	//   - error: Any fatal error encountered during analysis.
	PostCallerAnalysis func(projectPackages []*packages.Package, modulePackages []*packages.Package,
		identEdges map[string][]string, callers []*CallerFunction, reachable ReachableModuleChange) error
}

DefaultCallerAnalysisProvider provides the standard implementation of CallerAnalysisProvider.

func (*DefaultCallerAnalysisProvider) Cleanup

func (d *DefaultCallerAnalysisProvider) Cleanup()

func (*DefaultCallerAnalysisProvider) PerformCallerStaticAnalysis

func (d *DefaultCallerAnalysisProvider) PerformCallerStaticAnalysis(config Config, moduleChanges []*ModuleFunction) ([]*CallerFunction, ReachableModuleChange, error)

type DefaultModuleChangeProvider

type DefaultModuleChangeProvider struct{}

DefaultModuleChangeProvider provides the standard implementation of ModuleChangeProvider.

func (*DefaultModuleChangeProvider) AnalyzeModuleChanges

func (d *DefaultModuleChangeProvider) AnalyzeModuleChanges(config Config, analyzeExpandTransitive bool,
	changedModules []*ModuleChange,
	neighbourRadius int) (map[string][]*ModuleFunction, map[string][]*packages.Package, error)

func (*DefaultModuleChangeProvider) Cleanup

func (d *DefaultModuleChangeProvider) Cleanup()

type DefaultMutationTester

type DefaultMutationTester struct{}

DefaultMutationTester provides the standard implementation of MutationTester.

func (*DefaultMutationTester) Cleanup

func (d *DefaultMutationTester) Cleanup()

func (*DefaultMutationTester) RunMutationTesting

func (d *DefaultMutationTester) RunMutationTesting(config Config, fastMutations, lineScopedMutations,
	runTargetedTests bool, moduleChanges []*ModuleFunction, testFunctions []*TestFunction) (MutationResult, error)

type DefaultReportWriter

type DefaultReportWriter struct{}

DefaultReportWriter provides the standard implementation of ReportWriter.

func (*DefaultReportWriter) WriteReportFiles

func (d *DefaultReportWriter) WriteReportFiles(jsonPath, chartPath string, startTime time.Time,
	analysisDuration, testDiscoveryDuration, fieldCheckDuration, mutationDuration time.Duration,
	changedModules []*ModuleChange, checkedModules []string, moduleChangeFuncCount, moduleChangesReachedInTesting, untrackedModuleFuncs int,
	projectFieldChecks int, projectCallingFunctions []*CallerFunction, relevantTestFunctions []*TestFunction,
	testFieldSameCount, testFieldDiffCount int, testResults []TestReport,
	globalMutations MutationResult) error

type DefaultStorageProvider

type DefaultStorageProvider struct {
	Path    string
	CacheMB int
	// contains filtered or unexported fields
}

DefaultStorageProvider provides the standard implementation of StorageProvider using BadgerDB.

func (*DefaultStorageProvider) NewStorage

func (d *DefaultStorageProvider) NewStorage() (Storage, error)

type DefaultTestProvider

type DefaultTestProvider struct{}

DefaultTestProvider provides the standard implementation of TestProvider for static test discovery only.

func (*DefaultTestProvider) Cleanup

func (d *DefaultTestProvider) Cleanup()

func (*DefaultTestProvider) ProvideTests

func (d *DefaultTestProvider) ProvideTests(config Config, callingFunctions []*CallerFunction) ([]*TestFunction, error)

type DefaultTestResultAnalyzer

type DefaultTestResultAnalyzer struct{}

DefaultTestResultAnalyzer provides the standard implementation of TestResultAnalyzer.

func (*DefaultTestResultAnalyzer) CompareTestResults

func (d *DefaultTestResultAnalyzer) CompareTestResults(preResultStorage, postResultStorage Storage, timeMultiplier int) (int, int, []TestReport, error)

func (*DefaultTestResultAnalyzer) DiffValues

func (d *DefaultTestResultAnalyzer) DiffValues(v1, v2 string) string

DiffValues provides a simple human-readable diff explanation of two complex value types. If the values are identical an empty string will be returned.

type DefaultUpdateAnalysisProvider

type DefaultUpdateAnalysisProvider struct {
	// PreUpdateExtensionConfig is an optional function called before the first test run (old module version).
	// Returns a map of point IDs to frame keys for storage.
	PreUpdateExtensionConfig func(astEditor *ASTModifier) (map[uint32]*string, error)

	// PostUpdateExtensionConfig is an optional function called before the second test run (new module version).
	// Returns a map of point IDs to frame keys for storage.
	PostUpdateExtensionConfig func(astEditor *ASTModifier) (map[uint32]*string, error)
}

DefaultUpdateAnalysisProvider provides the standard implementation of UpdateAnalysisProvider.

func (*DefaultUpdateAnalysisProvider) Cleanup

func (d *DefaultUpdateAnalysisProvider) Cleanup()

func (*DefaultUpdateAnalysisProvider) RunModuleUpdateAnalysis

func (d *DefaultUpdateAnalysisProvider) RunModuleUpdateAnalysis(config Config,
	storage Storage, changedModules []*ModuleChange, reachableModuleChanges ReachableModuleChange,
	callingFunctions []*CallerFunction, testFunctions []*TestFunction) (int, int, int, Storage, Storage, error)

type FieldValue

type FieldValue struct {
	// Value holds the string representation.
	Value string `msgpack:"v"`
	// Children contains nested field values.
	Children FieldValues `msgpack:"c,omitempty"`
}

FieldValue represents a value and optional nested children

func (*FieldValue) ID

func (fv *FieldValue) ID() string

ID returns a key for the value and children.

type FieldValues

type FieldValues map[string]*FieldValue

FieldValues is a map of field names to FieldValue

func (FieldValues) FlattenFieldValues

func (fv FieldValues) FlattenFieldValues() map[string]string

FlattenFieldValues converts the hierarchical FieldValues tree back into the flat dot-separated key => value form.

func (FieldValues) ID

func (fv FieldValues) ID() string

ID returns the hash of field values.

type Function

type Function struct {
	// FilePath is the full path to the source file.
	FilePath string
	// PackageName is the package containing the function.
	PackageName string
	// FunctionIdent is the fully qualified identifier.
	FunctionIdent string
	// FunctionName is the short function name.
	FunctionName string
	// EntryLineNumber is the entry line.
	EntryLineNumber uint32
	// ReturnPoints lists source return locations.
	ReturnPoints []FunctionReturn
	// ReturnPanic reports if the function always panics.
	ReturnPanic bool
}

Function holds info about a function after static analysis.

func (Function) ShortIdent

func (f Function) ShortIdent() string

ShortIdent returns the function identifier without path.

type FunctionReturn

type FunctionReturn struct {
	// Line is the return line number.
	Line uint32
	// CallCount is the number of call expressions returned.
	CallCount uint32
}

FunctionReturn holds the return line and call count.

func AnalyzeASTFunctionReturnPoints

func AnalyzeASTFunctionReturnPoints(fset *token.FileSet, decl *ast.FuncDecl) (uint32, []FunctionReturn, bool)

AnalyzeASTFunctionReturnPoints collects entry line and return lines; bool signals panic.

type LensMonitorField

type LensMonitorField struct {
	Name     string // field name or path
	Type     string // Go type specific
	Value    interface{}
	Children []LensMonitorField // nested fields for structs, maps, etc
}

LensMonitorField represents a named value or nested composite.

type LensMonitorMessageError

type LensMonitorMessageError struct {
	PointID uint32 // instrumented point id (provided to client from AST)
	Message string
	Stack   []lensMonitorStackFrame // call stack frames
}

LensMonitorMessageError is sent when an unexpected error occurs to assist with debugging.

type LensMonitorMessagePoint

type LensMonitorMessagePoint struct {
	PointID uint32                  // instrumented point id (provided to client from AST)
	TimeNS  int64                   // nanoseconds since the process start
	Stack   []lensMonitorStackFrame // call stack frames
}

LensMonitorMessagePoint is sent at a specific point within the function (determined by the point id when added).

type LensMonitorMessagePointPanic

type LensMonitorMessagePointPanic struct {
	PointID uint32 // instrumented point id (provided to client from AST)
	TimeNS  int64  // nanoseconds since the process start
	Message string // value from the panic recovery
}

LensMonitorMessagePointPanic is sent when a function has an unrecovered panic.

type LensMonitorMessagePointState

type LensMonitorMessagePointState struct {
	PointID uint32                  // instrumented point id (provided to client from AST)
	TimeNS  int64                   // nanoseconds since the process start
	Stack   []lensMonitorStackFrame // call stack frames
	Fields  []LensMonitorField      // variables reachable within the function scope (parameters, local values, etc)
}

LensMonitorMessagePointState is sent when you want the full field snapshot at a point within a function.

type LimitingWaitGroup

type LimitingWaitGroup interface {
	// Take blocks until the wait group has capacity.
	Take()
	// Release should be invoked (typically in defer) to indicate the activity following Take() has completed.
	Release()
	// Join will block until all activities have completed. This implementation expects that once Join() is invoked, Take() will NOT be invoked again.
	Join()
}

LimitingWaitGroup restricts concurrent work and waits for completion.

func NewLimitingWaitGroup

func NewLimitingWaitGroup(concurrencyLimit int) LimitingWaitGroup

NewLimitingWaitGroup creates a LimitingWaitGroup with the given limit.

type MinimumTestFunction

type MinimumTestFunction struct {
	// FunctionIdent is the fully qualified identifier.
	FunctionIdent string
	// FunctionName is the short name.
	FunctionName string
}

MinimumTestFunction provides the minimum information about a test function to associate to the TestResult.

type ModuleChange

type ModuleChange struct {
	// Name is the module name.
	Name string
	// PriorVersion is the version before update.
	PriorVersion string
	// NewVersion is the version after update.
	NewVersion string
	// Indirect indicates the module is an indirect dependency.
	Indirect bool
	// GoVersion is the minimum Go version from the module's go.mod (oldest of old/new versions).
	GoVersion string
}

ModuleChange describes a Go module upgrade.

func DiffModulesFromGoModFiles

func DiffModulesFromGoModFiles(oldGoModPath, newGoModPath string) ([]*ModuleChange, error)

DiffModulesFromGoModFiles returns all direct (non-indirect) modules whose versions differ between the “old” and “new” go.mod files.

func DiffModulesFromGoWorkFiles

func DiffModulesFromGoWorkFiles(projectDir, newWorkPath string) ([]*ModuleChange, error)

DiffModulesFromGoWorkFiles returns changed modules across all go.mod files referenced by a go.work workspace.

type ModuleChangeProvider

type ModuleChangeProvider interface {
	// AnalyzeModuleChanges examines the differences between module versions to identify changed functions.
	//
	// Parameters:
	//   - config: configuration containing paths and settings for analysis
	//   - analyzeExpandTransitive: if true, recursively analyzes transitive dependency changes
	//   - changedModules: list of modules that have version changes to analyze
	//   - neighbourRadius: radius for marking changed lines in function definitions (used for mutation testing scope)
	//
	// Returns:
	//   - map[string][]*ModuleFunction: changed functions organized by module name (OLD version)
	//   - map[string][]*packages.Package: NEW version packages with type information (keyed by module name)
	//   - error: any error encountered during analysis
	AnalyzeModuleChanges(config Config, analyzeExpandTransitive bool,
		changedModules []*ModuleChange, neighbourRadius int) (map[string][]*ModuleFunction, map[string][]*packages.Package, error)

	// Cleanup is invoked after engine analysis is complete, allowing freeing of resources used during analysis.
	Cleanup()
}

ModuleChangeProvider analyzes changes in Go module dependencies between versions. It identifies functions that have been modified, added, or removed when a module is updated from one version to another.

type ModuleFunction

type ModuleFunction struct {
	Function

	// Definition contains the function's source code from the analyzed version.
	Definition string
	// LineChangeBitmap marks which lines changed between versions.
	// The bitmap indices correspond to lines in this function's Definition.
	// For unchanged functions, this is empty/nil.
	// New function defs will always have a LineChangeBitmap of radius 0 to show exact line changes.
	LineChangeBitmap []bool
	// Module identifies which module this function belongs to, including version information.
	Module *ModuleChange
}

ModuleFunction represents a function from a module version being analyzed. Depending on context, this may represent either the old or new version of a function:

  • In ModuleAnalysisData.ChangedFunctions: OLD version
  • In AnalyzeModuleChanges return value: OLD version

func ExtractModuleFunctionsFromPackages added in v0.1.7

func ExtractModuleFunctionsFromPackages(pkgs []*packages.Package, moduleChange *ModuleChange) ([]*ModuleFunction, error)

ExtractModuleFunctionsFromPackages extracts function definitions from pre-loaded packages. Useful for extension configs that need to analyze module functions without re-parsing.

func FilterModulesByGoVersion added in v0.1.12

func FilterModulesByGoVersion(reachableModuleChanges ReachableModuleChange) (filtered []*ModuleFunction, skippedCount int)

FilterModulesByGoVersion removes functions from modules with Go versions below MinGoVersion.

type ModuleMetrics

type ModuleMetrics struct {
	RootModuleName            string   `json:"root_module_name"`
	RootModuleStartVersion    string   `json:"root_module_start_version"`
	RootModuleUpdateVersion   string   `json:"root_module_update_version"`
	ChangedModules            []string `json:"changed_modules"`
	ChangedModuleCount        int      `json:"changed_module_count"`
	ChangeFuncCount           int      `json:"changed_function_count"`
	ReachableChangedFunctions []string `json:"reachable_changed_functions"`
	ReachableChangedFuncCount int      `json:"reachable_changed_function_count"`
	UntrackedModuleFuncCount  int      `json:"untracked_module_function_count"`
}

ModuleMetrics summarizes module change statistics.

type MutationResult

type MutationResult struct {
	// MutationCount is the total mutations executed.
	MutationCount int
	// SquashedCount is the number of deduplicated mutations.
	SquashedCount int
}

MutationResult summarizes mutation testing results.

func RunMutationTesting

func RunMutationTesting(gopath, gomodcache, projectDir string, fastMutations, lineScopedMutations, runTargetedTests bool,
	moduleChanges []*ModuleFunction, testFunctions []*TestFunction) (MutationResult, error)

RunMutationTesting runs mutation testing targeted to the module changes.

type MutationTester

type MutationTester interface {
	// RunMutationTesting applies mutations to the changed module functions and runs
	// the relevant tests to validate test coverage. It uses go-mutesting to introduce
	// code mutations and checks if the test suite can detect the introduced changes.
	//
	// Parameters:
	//   - config: configuration containing paths and settings for analysis
	//   - fastMutations: if true, use fast mutation mode (fewer mutations for speed)
	//   - lineScopedMutations: if true, limit mutations to specific changed lines
	//   - runTargetedTests: if true, run only tests that target the changed functions
	//   - moduleChanges: list of module functions that have changed
	//   - testFunctions: list of test functions to run during mutation testing
	//
	// Returns:
	//   - MutationResult: results of mutation testing including mutation scores and details
	//   - error: any error encountered during mutation testing
	RunMutationTesting(config Config, fastMutations, lineScopedMutations,
		runTargetedTests bool, moduleChanges []*ModuleFunction, testFunctions []*TestFunction) (MutationResult, error)

	// Cleanup is invoked after engine analysis is complete, allowing freeing resources used during mutation testing.
	Cleanup()
}

MutationTester performs mutation testing on the changed module code to validate that the discovered tests adequately cover the behavioral changes. It introduces deliberate mutations in the changed code and verifies that tests catch them.

type PerformanceChange

type PerformanceChange struct {
	TestFunctionIdent string `json:"test_function_ident"` // identifier of the test function
	TestFunctionName  string `json:"test_function_name"`  // name of the test function
	CallerIdent       string `json:"caller_ident"`        // identifier of the caller function
	TimeDiffMs        int64  `json:"time_diff_ms"`        // time interval difference in milliseconds (positive = slower, negative = faster)
	PreTimeMs         uint32 `json:"pre_time_ms"`         // call interval before change in milliseconds
	PostTimeMs        uint32 `json:"post_time_ms"`        // call interval after change in milliseconds
}

PerformanceChange represents a performance change detected between test runs

type PerformanceTimeChange

type PerformanceTimeChange struct {
	TimeDiff   time.Duration // time interval difference (positive = slower, negative = faster)
	PreTimeMs  uint32        // call interval before change in milliseconds
	PostTimeMs uint32        // call interval after change in milliseconds
}

PerformanceTimeChange stores detailed timing information for a caller

type ReachableModuleChange

type ReachableModuleChange map[string]*ModuleFunction

ReachableModuleChange maps function identifiers to changed functions.

type ReportMap added in v0.1.0

type ReportMap map[string]interface{}

ReportMap represents a report as an extensible map structure. Custom implementations can add additional fields before writing to JSON.

func BuildReportMap added in v0.1.0

func BuildReportMap(startTime time.Time,
	analysisDuration, testDiscoveryDuration, fieldCheckDuration, mutationDuration time.Duration,
	moduleName, startVersion, changeVersion string,
	checkedModules []string, moduleChangeFuncCount, moduleChangesReachedInTesting, untrackedModuleFuncs int,
	reachableModuleFunctionsIdents, relevantProjectFunctionIdents []string,
	projectFieldChecks int,
	relevantTestFunctionsIdents []string, testFieldSameCount, testFieldDiffCount, syntheticTestFuncCount int,
	globalMutations MutationResult, performanceChanges []PerformanceChange, testDetails []TestDetail) (ReportMap, error)

BuildReportMap creates the report as a ReportMap that can be extended by custom implementations before writing to JSON.

func (ReportMap) WriteToFile added in v0.1.0

func (rm ReportMap) WriteToFile(path string) error

WriteToFile writes the report map to a JSON file. This method allows custom implementations to write extended reports.

type ReportMetrics

type ReportMetrics struct {
	GeneratedAt           time.Time         `json:"generated_at"`
	RunDuration           int64             `json:"run_ms"`
	AnalysisDuration      int64             `json:"analysis_ms"`
	TestDiscoveryDuration int64             `json:"test_discovery_ms"`
	FieldCheckDuration    int64             `json:"field_check_ms"`
	MutationDuration      int64             `json:"mutation_ms"`
	Module                ModuleMetrics     `json:"module"`
	Validation            ValidationMetrics `json:"validation"`
}

ReportMetrics contains run and validation metrics.

type ReportWriter

type ReportWriter interface {
	// WriteReportFiles generates and writes analysis reports to the specified file paths.
	// It creates both JSON and chart-based reports containing all analysis results,
	// including timing information, test results, mutation testing results, and
	// behavioral change summaries.
	//
	// Parameters:
	//   - reportJsonFile: path where the JSON report should be written
	//   - reportChartsFile: path where the chart report should be written
	//   - startTime: when the analysis started (for computing total duration)
	//   - analysisTime: duration of module change analysis
	//   - testDiscoveryTime: duration of test discovery or generation
	//   - testExecutionTime: duration of test execution with monitoring
	//   - mutationTime: duration of mutation testing
	//   - changedModules: list of modules with version changes
	//   - checkedModules: list of all modules that were analyzed
	//   - moduleChangeCount: total number of changed functions across all modules
	//   - moduleChangesReachedInTesting: number of module changes exercised by tests
	//   - untrackedModuleFuncs: number of module functions skipped due to Go version incompatibility
	//   - projectFieldChecks: number of field value checks performed on project code
	//   - callingFunctions: project functions that call changed module functions
	//   - testFunctions: test functions that exercise the affected code
	//   - sameCount: number of test cases with identical behavior before/after update
	//   - diffCount: number of test cases with different behavior before/after update
	//   - testReports: detailed reports of behavioral differences found
	//   - globalMutations: results from mutation testing
	//
	// Returns:
	//   - error: any error encountered during report generation or file writing
	WriteReportFiles(reportJsonFile, reportChartsFile string, startTime time.Time,
		analysisTime, testDiscoveryTime, testExecutionTime, mutationTime time.Duration,
		changedModules []*ModuleChange, checkedModules []string, moduleChangeCount, moduleChangesReachedInTesting, untrackedModuleFuncs int,
		projectFieldChecks int, callingFunctions []*CallerFunction, testFunctions []*TestFunction,
		sameCount, diffCount int, testReports []TestReport,
		globalMutations MutationResult) error
}

ReportWriter generates analysis reports in various formats (JSON, charts, etc.) containing the results of module update analysis. It consolidates all analysis data into comprehensive reports for review and decision-making.

type SingletonStorageProvider added in v0.1.0

type SingletonStorageProvider struct {
	Store Storage
}

SingletonStorageProvider is a StorageProvider that returns a single consistent storage instance.

func (*SingletonStorageProvider) NewStorage added in v0.1.0

func (s *SingletonStorageProvider) NewStorage() (Storage, error)

type StackFrame

type StackFrame struct {
	// File is the source file path.
	File string `msgpack:"fi"`
	// Line is the line number.
	Line uint32 `msgpack:"li"`
	// Function is the function identifier.
	Function string `msgpack:"fu"`
}

StackFrame represents one frame in a call stack

func ProjectFrames added in v0.1.0

func ProjectFrames(frames []StackFrame) []StackFrame

ProjectFrames filters a stack to only include frames from project code. It excludes frames from vendor, stdlib, and external modules.

func (*StackFrame) Equal

func (sf *StackFrame) Equal(other *StackFrame) bool

Equal reports whether frames match.

func (*StackFrame) ID

func (sf *StackFrame) ID() string

ID returns a key for the stack frame.

type Storage

type Storage interface {
	SaveState(key string, blob []byte) error
	LoadState(key string) ([]byte, bool, error)
	DeleteState(key string) error
	// ListKeysPrefix returns all keys in the store that begin with the given prefix.
	ListKeysPrefix(prefix string) ([]string, error)
	// ListKeys returns all keys in the store.
	ListKeys() ([]string, error)
	Clear() error
	Close()
}

Storage defines persistence methods for call frame blobs.

func KeyPrefixStorage

func KeyPrefixStorage(s Storage, prefix string) Storage

KeyPrefixStorage wraps another Storage, prepending a fixed prefix to all keys. Its ListKeys and ListKeysPrefix methods strip the prefix before returning.

func NewBadgerStorage

func NewBadgerStorage(path string, maxMemMB int) (Storage, error)

NewBadgerStorage opens a Badger‐backed Storage.

func NewMemStorage

func NewMemStorage() Storage

NewMemStorage returns an in-memory Storage implementation.

type StorageProvider

type StorageProvider interface {
	// NewStorage creates a new storage instance for persisting test results and
	// other analysis data. The storage is used to save captured runtime information
	// during test execution and retrieve it during result comparison.
	//
	// Returns:
	//   - Storage: a new storage interface instance
	//   - error: any error encountered during storage creation
	NewStorage() (Storage, error)
}

StorageProvider creates storage instances for persisting test execution results and analysis data. It abstracts the storage backend to allow different implementations (file-based, in-memory, database, etc.).

type TargetModule

type TargetModule struct {
	Name    string
	Version string
}

TargetModule specifies a module name and version to analyze.

type TestDetail

type TestDetail struct {
	TestFunctionIdent    string                       `json:"test_function_ident"` // ident of the test
	TestFunctionName     string                       `json:"test_function_name"`
	BaselineFailure      bool                         `json:"baseline_failure"`
	PassRegression       bool                         `json:"pass_regression"`         // Did the test fail only after the change
	DiffFieldCount       int                          `json:"diff_field_count"`        // how many fields changed
	ModuleChangeHitCount int                          `json:"module_change_hit_count"` // how many module functions that test reached
	FieldChanges         map[string]map[string]string `json:"field_changes"`           // [callerIdent][fieldName]valueDiff
}

TestDetail summarizes per-test changes.

type TestFunction

type TestFunction struct {
	Function

	// Targets lists callers tested by this function.
	Targets []*CallerFunction
}

TestFunction ties a test function to a caller in the project to a changed function.

func TestStaticAnalysis

func TestStaticAnalysis(callers []*CallerFunction, projectDir, gopath, gomodcache string) ([]*TestFunction, error)

TestStaticAnalysis loads all packages (including test packages), then for each provided CallerFunction (project function from module analysis), performs a reverse DFS to find any test functions that eventually lead to the given project functions.

func (TestFunction) Minimum

func (f TestFunction) Minimum() MinimumTestFunction

Minimum returns the minimal test function info.

func (TestFunction) TargetFunctionIdents

func (f TestFunction) TargetFunctionIdents() string

TargetFunctionIdents returns short idents of target callers.

type TestProvider

type TestProvider interface {
	// ProvideTests discovers existing test functions that exercise the calling functions.
	// Advanced implementations may optionally generate additional tests to improve coverage.
	//
	// Parameters:
	//   - config: configuration containing paths and settings for analysis
	//   - callingFunctions: list of project functions that call changed module functions
	//
	// Returns:
	//   - []*TestFunction: list of test functions that exercise the affected code
	//   - error: any error encountered during test discovery or generation
	ProvideTests(config Config, callingFunctions []*CallerFunction) ([]*TestFunction, error)

	// Cleanup is invoked after engine analysis is complete, allowing freeing resources used during test provision.
	Cleanup()
}

TestProvider discovers and optionally generates test functions that exercise the project code affected by module changes.

type TestReport

type TestReport struct {
	OriginalResult      TestResult // OriginalResult must be used to get mutation hit counts
	PostUpdateResult    TestResult
	CallerFieldChanges  map[string]map[string]string     // [callerIdent][fieldName]valueDiff
	CallerTimeChanges   map[string]PerformanceTimeChange // [callerIdent]detailed timing info
	TestRegressionCount int
	SameFieldCount      int
	DiffFieldCount      int
}

TestReport compares test results.

type TestResult

type TestResult struct {
	// TestFunction identifies the test.
	TestFunction MinimumTestFunction
	// CallerResults maps callers to captured field values.
	CallerResults map[string][]CallFrame
	// ProjectPanics records panic messages from project functions.
	ProjectPanics map[string][]string
	// ModulePanics records panic messages from module functions.
	ModulePanics map[string][]string
	// ModuleChangesHit counts the changed functions hit.
	ModuleChangesHit int
	// TestFailure reports if the test failed.
	TestFailure bool
	// ExtensionFrames are filled in if extension AST modifications are configured through ExtensionPointConfig.
	// ExtensionFrames shares the same deduplication pool as CallerResults for efficient storage.
	// Keys should be namespaced (e.g., "security:network:dial").
	ExtensionFrames map[string][]CallFrame
}

TestResult represents the recorded field values per test function.

func (*TestResult) MarshalMsgpack

func (tr *TestResult) MarshalMsgpack() ([]byte, error)

func (*TestResult) UnmarshalMsgpack

func (tr *TestResult) UnmarshalMsgpack(data []byte) error

type TestResultAnalyzer

type TestResultAnalyzer interface {
	// CompareTestResults analyzes the differences between pre-update and post-update
	// test execution results. It compares captured field values, function call sequences,
	// timing information, and other runtime behavior to detect changes.
	//
	// Parameters:
	//   - preResults: storage containing test results from before the module update
	//   - postResults: storage containing test results from after the module update
	//   - timeMultiplier: multiplier for timing tolerances (higher values are more lenient)
	//
	// Returns:
	//   - int: number of test cases with identical behavior (same results)
	//   - int: number of test cases with different behavior (different results)
	//   - []TestReport: detailed reports of differences found between test runs
	//   - error
	CompareTestResults(preResults, postResults Storage, timeMultiplier int) (int, int, []TestReport, error)
}

TestResultAnalyzer compares test execution results from before and after module updates to identify behavioral changes. It analyzes captured field values, execution paths, and performance metrics.

type UpdateAnalysisProvider

type UpdateAnalysisProvider interface {
	// RunModuleUpdateAnalysis runs tests with AST instrumentation to capture runtime
	// behavior before and after module updates. It injects monitoring code to record
	// function calls, field states, panics, and timing information.
	//
	// Parameters:
	//   - config: configuration containing paths and settings for analysis
	//   - storage: storage interface for persisting test results
	//   - changedModules: list of modules that have version changes
	//   - reachableModuleChanges: mapping of module changes reachable from project code
	//   - callingFunctions: project functions that call changed module functions
	//   - testFunctions: test functions that exercise the affected code
	//
	// Returns:
	//   - int: number of project field checks performed
	//   - int: number of module changes reached during testing
	//   - int: number of module functions skipped due to Go version incompatibility
	//   - Storage: pre-update test results storage
	//   - Storage: post-update test results storage
	//   - error: any error encountered during analysis
	RunModuleUpdateAnalysis(config Config, storage Storage, changedModules []*ModuleChange, reachableModuleChanges ReachableModuleChange,
		callingFunctions []*CallerFunction, testFunctions []*TestFunction) (int, int, int, Storage, Storage, error)

	// Cleanup is invoked after engine analysis is complete, allowing freeing of resources used during update analysis.
	Cleanup()
}

UpdateAnalysisProvider executes tests with runtime monitoring to capture the behavior of code before and after module updates.

type ValidationMetrics

type ValidationMetrics struct {
	RelevantProjectFunctions   []string            `json:"relevant_project_functions"`
	RelevantProjectFuncCount   int                 `json:"relevant_project_function_count"`
	RelevantTestFunctions      []string            `json:"relevant_test_functions"`
	RelevantTestFuncCount      int                 `json:"relevant_test_function_count"`
	ProjectFieldCheckPoints    int                 `json:"project_field_check_point_count"`
	ModuleChangeHitInTestCount int                 `json:"module_change_hit_in_test_count"`
	TestFieldMatchCount        int                 `json:"test_field_match_count"`
	TestFieldDiffCount         int                 `json:"test_field_diff_count"`
	GeneratedTestFuncCount     int                 `json:"generated_test_function_count"`
	MutationCount              int                 `json:"mutation_count"`
	MutationsSquashed          int                 `json:"mutations_squashed"`
	PerformanceChanges         []PerformanceChange `json:"performance_changes"` // detected performance changes
	TestDetails                []TestDetail        `json:"test_details"`
}

ValidationMetrics aggregates test and mutation statistics.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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