Last active
September 14, 2020 05:45
-
-
Save knight42/73c13a0166a5d0884545f78bafc64acc to your computer and use it in GitHub Desktop.
scan non-synced shared informer factory in k8s unit tests
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"fmt" | |
"os" | |
"path/filepath" | |
"strings" | |
"sync" | |
) | |
func shouldSkipLine(line string) bool { | |
return len(line) == 0 || strings.HasPrefix(line, "//") | |
} | |
type State int | |
const ( | |
Initial State = iota | |
ImportBlock | |
TestFunc | |
) | |
func processFile(fp string, output chan<- string) error { | |
f, err := os.Open(fp) | |
if err != nil { | |
return err | |
} | |
defer f.Close() | |
scanner := bufio.NewScanner(f) | |
s := Initial | |
informerImported := false | |
createdSharedFactory := false | |
startedInformer := false | |
waitForCache := false | |
currentTestFunc := "" | |
for scanner.Scan() { | |
line := strings.TrimRight(scanner.Text(), " \t") | |
stripped := strings.TrimSpace(line) | |
if shouldSkipLine(stripped) { | |
continue | |
} | |
switch s { | |
case Initial: | |
if strings.HasPrefix(line, "import (") { | |
s = ImportBlock | |
continue | |
} | |
if strings.HasPrefix(line, "func Test") { | |
s = TestFunc | |
currentTestFunc = strings.TrimPrefix(line, "func ") | |
idx := strings.IndexByte(currentTestFunc, '(') | |
currentTestFunc = currentTestFunc[:idx] | |
continue | |
} | |
case ImportBlock: | |
if stripped == `"k8s.io/client-go/informers"` { | |
informerImported = true | |
continue | |
} | |
if line == ")" { | |
if !informerImported { | |
return nil | |
} | |
s = Initial | |
continue | |
} | |
case TestFunc: | |
if line == "}" { | |
if startedInformer && !waitForCache { | |
output <- fp + " " + currentTestFunc | |
} | |
s = Initial | |
createdSharedFactory = false | |
waitForCache = false | |
startedInformer = false | |
currentTestFunc = "" | |
continue | |
} | |
if strings.Contains(line, ".NewSharedInformerFactory(") { | |
createdSharedFactory = true | |
continue | |
} | |
if createdSharedFactory && strings.Contains(line, ".Start(") { | |
startedInformer = true | |
continue | |
} | |
if startedInformer && strings.Contains(line, ".WaitForCacheSync(") { | |
waitForCache = true | |
} | |
} | |
} | |
return nil | |
} | |
func worker(tasks <-chan string, output chan<- string, wg *sync.WaitGroup) { | |
defer wg.Done() | |
for fp := range tasks { | |
err := processFile(fp, output) | |
if err != nil { | |
fmt.Fprintf(os.Stderr, "Failed to process %s\n", fp) | |
} | |
} | |
} | |
func main() { | |
var wg sync.WaitGroup | |
const workers = 5 | |
tasks := make(chan string, workers) | |
output := make(chan string, 10) | |
done := make(chan struct{}) | |
for i := 0; i < workers; i++ { | |
wg.Add(1) | |
go worker(tasks, output, &wg) | |
} | |
go func() { | |
for s := range output { | |
fmt.Println(s) | |
} | |
close(done) | |
}() | |
filepath.Walk(os.Args[1], func(path string, info os.FileInfo, err error) error { | |
if err != nil { | |
return err | |
} | |
name := info.Name() | |
isDir := info.IsDir() | |
if isDir && strings.HasPrefix(name, ".") { | |
return filepath.SkipDir | |
} | |
if isDir || !strings.HasSuffix(name, "_test.go") { | |
return nil | |
} | |
if info.Mode().IsRegular() { | |
tasks <- path | |
} | |
return nil | |
}) | |
close(tasks) | |
wg.Wait() | |
close(output) | |
<-done | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment