forked from influxdata/telegraf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
all_test.go
115 lines (100 loc) · 3.5 KB
/
all_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package all
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"io/fs"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
// exceptionMap holds those plugins which differ in conventions when defining plugins.
// Most plugins follow the convention of pkg-name to plugin-name.
// For ex, Pivot processor pkg github.com/influxdata/telegraf/plugins/processors/pivot maps directly to
// the last element of the pkg i.e "pivot"
// But in case of "aws_ec2" processor, the pkg is defined as "github.com/influxdata/telegraf/plugins/processors/aws/ec2".
// This ensures package names are not tied with plugin names.
// it should be of the form <pkg-name>: <plugin-name>
var exceptionMap = map[string]string{
"github.com/influxdata/telegraf/plugins/processors/aws/ec2": "aws_ec2",
}
func Test_AllPlugins(t *testing.T) {
pluginDirs := []string{"aggregators", "inputs", "outputs", "parsers", "processors", "secretstores"}
for _, dir := range pluginDirs {
testPluginDirectory(t, dir)
}
}
func testPluginDirectory(t *testing.T, directory string) {
allDir := filepath.Join(directory, "all")
err := filepath.WalkDir(allDir, func(goPluginFile string, d fs.DirEntry, walkErr error) error {
require.NoError(t, walkErr)
if d.IsDir() || strings.HasSuffix(d.Name(), "_test.go") || strings.EqualFold(d.Name(), "all.go") {
return nil
}
t.Run(goPluginFile, func(t *testing.T) {
parseSourceFile(t, goPluginFile, directory)
})
return nil
})
require.NoError(t, err)
}
func parseSourceFile(t *testing.T, goPluginFile, pluginCategory string) {
fset := token.NewFileSet()
node, err := parser.ParseFile(fset, goPluginFile, nil, parser.ParseComments)
require.NoError(t, err)
foundGoBuild := false
for _, cg := range node.Comments {
for _, comm := range cg.List {
if !strings.HasPrefix(comm.Text, "//go:build") {
continue
}
foundGoBuild = true
plugin := resolvePluginFromImports(t, node.Imports)
testBuildTags(t, comm.Text, pluginCategory, plugin)
}
}
require.Truef(t, foundGoBuild, "%s does not contain go:build tag", goPluginFile)
}
func resolvePluginFromImports(t *testing.T, imports []*ast.ImportSpec) string {
// should contain one or more import statements
require.NotEmpty(t, imports)
// trim the path surrounded by quotes
importPath := strings.Trim(imports[0].Path.Value, "\"")
// check if present in exceptionMap
plugin, ok := exceptionMap[importPath]
if ok {
return plugin
}
return filepath.Base(importPath)
}
func testBuildTags(t *testing.T, buildComment, pluginCategory, plugin string) {
tags := strings.Split(buildComment, "||")
// tags might contain spaces and hence trim
tags = stringMap(tags, strings.TrimSpace)
require.Len(t, tags, 3)
require.Contains(t, tags, "!custom")
require.Contains(t, tags, pluginCategory)
actual := getPluginBuildTag(tags, pluginCategory)
expected := fmt.Sprintf("%s.%s", pluginCategory, plugin)
require.Equal(t, expected, actual, "invalid build tag")
}
// getPluginBuildTag takes a slice of tags and returns the build tag corresponding to this plugin type.
//
// For ex ["!custom", "inputs", "inputs.docker"] returns "inputs.docker"
func getPluginBuildTag(tags []string, pluginCategory string) string {
for _, tag := range tags {
if strings.HasPrefix(tag, pluginCategory+".") {
return tag
}
}
return ""
}
func stringMap(elems []string, transFormFunc func(string) string) []string {
result := make([]string, len(elems))
for i, elem := range elems {
result[i] = strings.TrimPrefix(transFormFunc(elem), "//go:build ")
}
return result
}