1
0
Fork 0
telegraf/plugins/inputs/intel_pmu/config_test.go

237 lines
8.5 KiB
Go
Raw Normal View History

//go:build linux && amd64
package intel_pmu
import (
"errors"
"fmt"
"math"
"testing"
ia "github.com/intel/iaevents"
"github.com/stretchr/testify/require"
"github.com/influxdata/telegraf/testutil"
)
func TestConfigParser_parseEntities(t *testing.T) {
mSysInfo := &mockSysInfoProvider{}
mConfigParser := &configParser{
sys: mSysInfo,
log: testutil.Logger{},
}
e := ia.CustomizableEvent{}
t.Run("no entities", func(t *testing.T) {
err := mConfigParser.parseEntities(nil, nil)
require.Error(t, err)
require.Contains(t, err.Error(), "neither core nor uncore entities configured")
})
// more specific parsing cases in TestConfigParser_parseIntRanges and TestConfigParser_parseEvents
coreTests := []struct {
name string
coreEntity *coreEventEntity
parsedCoreEvents []*eventWithQuals
parsedCores []int
coreAll bool
uncoreEntity *uncoreEventEntity
parsedUncoreEvents []*eventWithQuals
parsedSockets []int
uncoreAll bool
failMsg string
}{
{"no events provided",
&coreEventEntity{Events: nil, Cores: []string{"1"}}, nil, []int{1}, true,
&uncoreEventEntity{Events: nil, Sockets: []string{"0"}}, nil, []int{0}, true,
""},
{"uncore entity is nil",
&coreEventEntity{Events: []string{"EVENT"}, Cores: []string{"1,2"}}, []*eventWithQuals{{"EVENT", nil, e}}, []int{1, 2}, false,
nil, nil, nil, false,
"uncore entity is nil"},
{"core entity is nil",
nil, nil, nil, false,
&uncoreEventEntity{Events: []string{"EVENT"}, Sockets: []string{"1,2"}}, []*eventWithQuals{{"EVENT", nil, e}}, []int{1, 2}, false,
"core entity is nil"},
{"error parsing sockets",
&coreEventEntity{Events: nil, Cores: []string{"1,2"}}, nil, []int{1, 2}, true,
&uncoreEventEntity{Events: []string{"E"}, Sockets: []string{"wrong sockets"}}, []*eventWithQuals{{"E", nil, e}}, nil, false,
"error during sockets parsing"},
{"error parsing cores",
&coreEventEntity{Events: nil, Cores: []string{"wrong cpus"}}, nil, nil, true,
&uncoreEventEntity{Events: nil, Sockets: []string{"0,1"}}, nil, []int{0, 1}, true,
"error during cores parsing"},
{"valid settings",
&coreEventEntity{
Events: []string{"E1", "E2:config=123"},
Cores: []string{"1-5"},
}, []*eventWithQuals{{"E1", nil, e}, {"E2", []string{"config=123"}, e}}, []int{1, 2, 3, 4, 5}, false,
&uncoreEventEntity{
Events: []string{"E1", "E2", "E3"},
Sockets: []string{"0,2-6"},
}, []*eventWithQuals{{"E1", nil, e}, {"E2", nil, e}, {"E3", nil, e}}, []int{0, 2, 3, 4, 5, 6}, false,
""},
}
for _, test := range coreTests {
t.Run(test.name, func(t *testing.T) {
coreEntities := []*coreEventEntity{test.coreEntity}
uncoreEntities := []*uncoreEventEntity{test.uncoreEntity}
err := mConfigParser.parseEntities(coreEntities, uncoreEntities)
if len(test.failMsg) > 0 {
require.Error(t, err)
require.Contains(t, err.Error(), test.failMsg)
return
}
require.NoError(t, err)
require.Equal(t, test.coreAll, test.coreEntity.allEvents)
require.Equal(t, test.parsedCores, test.coreEntity.parsedCores)
require.Equal(t, test.parsedCoreEvents, test.coreEntity.parsedEvents)
require.Equal(t, test.uncoreAll, test.uncoreEntity.allEvents)
require.Equal(t, test.parsedSockets, test.uncoreEntity.parsedSockets)
require.Equal(t, test.parsedUncoreEvents, test.uncoreEntity.parsedEvents)
})
}
}
func TestConfigParser_parseCores(t *testing.T) {
mSysInfo := &mockSysInfoProvider{}
mConfigParser := &configParser{
sys: mSysInfo,
log: testutil.Logger{},
}
t.Run("no cores provided", func(t *testing.T) {
t.Run("system info provider is nil", func(t *testing.T) {
result, err := (&configParser{}).parseCores(nil)
require.Error(t, err)
require.Contains(t, err.Error(), "system info provider is nil")
require.Nil(t, result)
})
t.Run("cannot gather all cpus info", func(t *testing.T) {
mSysInfo.On("allCPUs").Return(nil, errors.New("all cpus error")).Once()
result, err := mConfigParser.parseCores(nil)
require.Error(t, err)
require.Contains(t, err.Error(), "cannot obtain all cpus")
require.Nil(t, result)
mSysInfo.AssertExpectations(t)
})
t.Run("all cpus gathering succeeded", func(t *testing.T) {
allCPUs := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
mSysInfo.On("allCPUs").Return(allCPUs, nil).Once()
result, err := mConfigParser.parseCores(nil)
require.NoError(t, err)
require.Equal(t, allCPUs, result)
mSysInfo.AssertExpectations(t)
})
})
}
func TestConfigParser_parseSockets(t *testing.T) {
mSysInfo := &mockSysInfoProvider{}
mConfigParser := &configParser{
sys: mSysInfo,
log: testutil.Logger{},
}
t.Run("no sockets provided", func(t *testing.T) {
t.Run("system info provider is nil", func(t *testing.T) {
result, err := (&configParser{}).parseSockets(nil)
require.Error(t, err)
require.Contains(t, err.Error(), "system info provider is nil")
require.Nil(t, result)
})
t.Run("cannot gather all sockets info", func(t *testing.T) {
mSysInfo.On("allSockets").Return(nil, errors.New("all sockets error")).Once()
result, err := mConfigParser.parseSockets(nil)
require.Error(t, err)
require.Contains(t, err.Error(), "cannot obtain all sockets")
require.Nil(t, result)
mSysInfo.AssertExpectations(t)
})
t.Run("all cpus gathering succeeded", func(t *testing.T) {
allSockets := []int{0, 1, 2, 3, 4}
mSysInfo.On("allSockets").Return(allSockets, nil).Once()
result, err := mConfigParser.parseSockets(nil)
require.NoError(t, err)
require.Equal(t, allSockets, result)
mSysInfo.AssertExpectations(t)
})
})
}
func TestConfigParser_parseEvents(t *testing.T) {
mConfigParser := &configParser{log: testutil.Logger{}}
e := ia.CustomizableEvent{}
tests := []struct {
name string
input []string
result []*eventWithQuals
}{
{"no events", nil, nil},
{"single string", []string{"mock string"}, []*eventWithQuals{{"mock string", nil, e}}},
{"two events", []string{"EVENT.FIRST", "EVENT.SECOND"}, []*eventWithQuals{{"EVENT.FIRST", nil, e}, {"EVENT.SECOND", nil, e}}},
{"event with configs", []string{"EVENT.SECOND:config1=0x404300k:config2=0x404300k"},
[]*eventWithQuals{{"EVENT.SECOND", []string{"config1=0x404300k", "config2=0x404300k"}, e}}},
{"two events with modifiers", []string{"EVENT.FIRST:config1=0x200300:config2=0x231100:u:H", "EVENT.SECOND:K:p"},
[]*eventWithQuals{{"EVENT.FIRST", []string{"config1=0x200300", "config2=0x231100", "u", "H"}, e}, {"EVENT.SECOND", []string{"K", "p"}, e}}},
{"duplicates", []string{"EVENT1", "EVENT1", "EVENT2"}, []*eventWithQuals{{"EVENT1", nil, e}, {"EVENT2", nil, e}}},
{"duplicates with different configs", []string{"EVENT1:config1", "EVENT1:config2"},
[]*eventWithQuals{{"EVENT1", []string{"config1"}, e}, {"EVENT1", []string{"config2"}, e}}},
{"duplicates with the same modifiers", []string{"EVENT1:config1", "EVENT1:config1"},
[]*eventWithQuals{{"EVENT1", []string{"config1"}, e}}},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
result := mConfigParser.parseEvents(test.input)
require.Equal(t, test.result, result)
})
}
}
func TestConfigParser_parseIntRanges(t *testing.T) {
mConfigParser := &configParser{log: testutil.Logger{}}
tests := []struct {
name string
input []string
result []int
failMsg string
}{
{"coma separated", []string{"0,1,2,3,4"}, []int{0, 1, 2, 3, 4}, ""},
{"range", []string{"0-10"}, []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, ""},
{"mixed", []string{"0-3", "4", "12-16"}, []int{0, 1, 2, 3, 4, 12, 13, 14, 15, 16}, ""},
{"min and max values", []string{"-2147483648", "2147483647"}, []int{math.MinInt32, math.MaxInt32}, ""},
{"should remove duplicates", []string{"1-5", "2-6"}, []int{1, 2, 3, 4, 5, 6}, ""},
{"wrong format", []string{"1,2,3%$S,-100"}, nil, "wrong format for id"},
{"start is greater than end", []string{"10-3"}, nil, "`10` is equal or greater than `3"},
{"too big value", []string{"18446744073709551615"}, nil, "wrong format for id"},
{"too much numbers", []string{fmt.Sprintf("0-%d", maxIDsSize)}, nil,
fmt.Sprintf("requested number of IDs exceeds max size `%d`", maxIDsSize)},
{"too much numbers mixed", []string{fmt.Sprintf("1-%d", maxIDsSize), "0"}, nil,
fmt.Sprintf("requested number of IDs exceeds max size `%d`", maxIDsSize)},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
result, err := mConfigParser.parseIntRanges(test.input)
require.Equal(t, test.result, result)
if len(test.failMsg) > 0 {
require.Error(t, err)
require.Contains(t, err.Error(), test.failMsg)
return
}
require.NoError(t, err)
})
}
}