Documentation
¶
Index ¶
- Constants
- Variables
- func AnalyzeModuleChanges(gomodcache string, includeTransitive bool, projectDir string, ...) (map[string][]*ModuleFunction, map[string][]*packages.Package, error)
- func CallerStaticAnalysis(moduleChanges []*ModuleFunction, projectDir, gopath, gomodcache string) ([]*CallerFunction, ReachableModuleChange, *callgraph.Graph, ...)
- func CopyDir(ctx context.Context, src, dst string, progressNotify func(string, os.FileInfo)) error
- func CopyFile(src, dst string) (err error)
- func ErrGroupLimitCPU() *errgroup.Group
- func ExecGoTest(dir string, env []string, output io.Writer, tFunc *TestFunction) error
- func FileExists(filename string) bool
- func FindModulePathInCache(gomodcache, modPath, version string) (string, error)
- func FindModuleVersion(projectDir, modName string) (string, bool, error)
- func FindModuleVersionInGoMod(goModFile, modName string) (string, bool, error)
- func GoEnv(gopath, gomodcache string) []string
- func IsGeneratedFile(filename string) bool
- func IsGoVersionBelowMinimum(goVersion string) bool
- func IsNormalAstError(err error) bool
- func LoadProjectCallGraph(projectDir, gopath, gomodcache string, includeTests bool) (*callgraph.Graph, *ssa.Program, []*packages.Package, []*packages.Package, ...)
- func MakeFunctionIdent(pkgName string, funcDecl *ast.FuncDecl) string
- func MakeSSAFunctionIdent(fn *ssa.Function) (string, bool)
- func NewProjectCapturedOutputExec(projectDir string, env []string, name string, arg ...string) ([]byte, error)
- func NewProjectExec(projectDir string, env []string, name string, arg ...string) *exec.Cmd
- func NewProjectLoggedExec(projectDir string, env []string, name string, arg ...string) *exec.Cmd
- func PrepareReportData(changedModules []*ModuleChange, projectCallingFunctions []*CallerFunction, ...) (reachableModuleFunctionsIdents []string, ...)
- func ProjectGoModFiles(projectDir string) ([]string, error)
- func ProjectPackagePatterns(projectDir string) ([]string, error)
- func RenderReportChartsFromJson(report ReportMetrics) ([]byte, error)
- func RunModuleUpdateAnalysis(gopath, gomodcache, projectDir string, portStart int, storage Storage, ...) (int, int, int, Storage, Storage, error)
- func SnappyCompress(dst, data []byte) []byte
- func SnappyDecompress(dst, data []byte) ([]byte, error)
- func StackFramesKey(bb *bytes.Buffer, frames []StackFrame) string
- func TeeWriter(writers ...io.Writer) io.WriteCloser
- func WriteChmod(ctx context.Context, root string) error
- func ZstdCompress(dst, data []byte) []byte
- func ZstdDecompress(dst, data []byte) ([]byte, error)
- type ASTModifier
- func (m *ASTModifier) Commit() error
- func (m *ASTModifier) CommitFile(filepath string) error
- func (m *ASTModifier) InjectASTClient(pkgDir string, srvPort int, maxFieldRecurse, maxFieldLen int) error
- func (m *ASTModifier) InjectFuncPointBeforeCall(fn *Function, shouldInject func(*ast.CallExpr) (metadata any, inject bool)) (map[uint32]any, error)
- func (m *ASTModifier) InjectFuncPointEntry(fn *Function) (uint32, error)
- func (m *ASTModifier) InjectFuncPointFinish(fn *Function) (uint32, error)
- func (m *ASTModifier) InjectFuncPointPanic(f *Function) (uint32, error)
- func (m *ASTModifier) InjectFuncPointReturnStates(fn *Function) ([]uint32, error)
- func (m *ASTModifier) InsertFuncLines(fn *Function, cb func(i int, line string) (insertText string, keepGoing bool)) error
- func (m *ASTModifier) MaxPointId() int
- func (m *ASTModifier) Restore(goenv []string) (result []error)
- type AnalysisEngine
- type CallFrame
- type CallerAnalysisProvider
- type CallerFunction
- type Config
- type DefaultCallerAnalysisProvider
- type DefaultModuleChangeProvider
- type DefaultMutationTester
- type DefaultReportWriter
- type DefaultStorageProvider
- type DefaultTestProvider
- type DefaultTestResultAnalyzer
- type DefaultUpdateAnalysisProvider
- type FieldValue
- type FieldValues
- type Function
- type FunctionReturn
- type LensMonitorField
- type LensMonitorMessageError
- type LensMonitorMessagePoint
- type LensMonitorMessagePointPanic
- type LensMonitorMessagePointState
- type LimitingWaitGroup
- type MinimumTestFunction
- type ModuleChange
- type ModuleChangeProvider
- type ModuleFunction
- type ModuleMetrics
- type MutationResult
- type MutationTester
- type PerformanceChange
- type PerformanceTimeChange
- type ReachableModuleChange
- type ReportMap
- type ReportMetrics
- type ReportWriter
- type SingletonStorageProvider
- type StackFrame
- type Storage
- type StorageProvider
- type TargetModule
- type TestDetail
- type TestFunction
- type TestProvider
- type TestReport
- type TestResult
- type TestResultAnalyzer
- type UpdateAnalysisProvider
- type ValidationMetrics
Constants ¶
const ErrorLogPrefix = "!! "
ErrorLogPrefix is used to prefix unexpected error log messages.
const GeneratedTestFileSuffix = "_modlensgen_test.go"
const GeneratedTestFunctionPrefix = "TestGen_"
const (
HashFieldValuePrefix = "vsha1-"
)
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 ¶
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 CopyFile ¶
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 ¶
ErrGroupLimitCPU returns an errgroup limited to NumCPU.
func ExecGoTest ¶
ExecGoTest runs go test for a single test function in the given directory.
func FileExists ¶
FileExists reports whether the named file exists.
func FindModulePathInCache ¶ added in v0.1.0
FindModulePathInCache attempts to locate a module@version in the local module cache. Returns the filesystem directory where the module source is located.
func FindModuleVersion ¶
FindModuleVersion searches for modName across all go.mod files in projectDir.
func FindModuleVersionInGoMod ¶
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 IsGeneratedFile ¶
IsGeneratedFile returns true if the filename follows known patterns for generated go files.
func IsGoVersionBelowMinimum ¶ added in v0.1.12
IsGoVersionBelowMinimum returns true if goVersion is below MinGoVersion.
func IsNormalAstError ¶ added in v0.1.12
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 ¶
MakeFunctionIdent creates a normalized key with package and receiver type.
func MakeSSAFunctionIdent ¶ added in v0.1.0
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 ¶
NewProjectExec creates a command that runs in projectDir with env applied.
func NewProjectLoggedExec ¶
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 ¶
ProjectGoModFiles returns all go.mod files for the project directory, supporting workspaces via go.work.
func ProjectPackagePatterns ¶
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 ¶
SnappyCompress compresses a byte slice using snappy and returns the compressed data.
func SnappyDecompress ¶
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 ¶
WriteChmod adds write permissions for owner/group/others on every file and directory under root.
func ZstdCompress ¶
ZstdCompress compresses a byte slice using zstd and returns the compressed data.
func ZstdDecompress ¶
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.
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.
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 ¶
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
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.
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 ¶
KeyPrefixStorage wraps another Storage, prepending a fixed prefix to all keys. Its ListKeys and ListKeysPrefix methods strip the prefix before returning.
func NewBadgerStorage ¶
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 ¶
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.