pkg/degradation-detector/setting/unitTestsSettings.go (198 lines of code) (raw):
package setting
import (
"log/slog"
"net/http"
"strings"
detector "github.com/JetBrains/ij-perf-report-aggregator/pkg/degradation-detector"
)
// teamConfig represents the configuration for a team
type teamConfig struct {
Team string
Packages []string
SlackChannel string
AnalysisSettings *detector.AnalysisSettings
}
var teamConfigs = []teamConfig{
{
Team: "ultimate",
SlackChannel: "ij-u-team-performance-issues-check",
Packages: []string{
"com.intellij.freemarker", "com.intellij.reactivestreams", "com.intellij.httpClient", "com.intellij.spring",
"com.intellij.swagger", "com.intellij.util.xml", "com.intellij.grpc", "com.intellij.guice",
"com.intellij.helidon", "com.intellij.hibernate", "com.intellij.jdbi", "com.intellij.ktor",
"com.intellij.micronaut", "com.intellij.openRewrite", "com.intellij.quarkus", "com.intellij.frameworks.thymeleaf",
"com.intellij.wiremock", "com.intellij.ee", "com.intellij.jsp", "com.jetbrains.jsonSchema",
},
},
{
Team: "vcs",
SlackChannel: "vcs-perf-tests",
Packages: []string{
"com.intellij.diff", "com.intellij.openapi.vcs",
},
},
{
Team: "java",
SlackChannel: "idea-java-alerts",
Packages: []string{
"com.intellij.java", "org.jetbrains.plugins.groovy", "org.jetbrains.uast.test.java",
"com.intellij.lang.properties", "com.intellij.structuralsearch", "org.jetbrains.java",
"org.jetbrains.plugins.cucumber.java",
},
},
{
Team: "cloudsAndDeployment",
SlackChannel: "kubernetes-ui-tests-failures",
Packages: []string{
"com.intellij.kubernetes", "org.jetbrains.yaml",
},
},
{
Team: "datagrip",
SlackChannel: "datagrip",
Packages: []string{
"com.intellij.sql",
},
},
{
Team: "webstorm",
SlackChannel: "webstorm-test-degradations",
Packages: []string{
"com.intellij.lang.javascript", "com.intellij.html", "org.angular2.lang", "css", "org.jetbrains.vuejs",
"org.angularjs.performance", "com.intellij.flex.completion", "com.intellij.htmltools",
"org.jetbrains.plugins.sass", "org.jetbrains.plugins.scss", "org.jetbrains.astro.lang", "com.intellij.psi.html",
"com.intellij.plugins.watcher", "com.intellij.javascript",
},
},
{
Team: "buildTools",
SlackChannel: "ij-build-tools-perf-tests",
Packages: []string{
"org.jetbrains.osgi.maven", "org.jetbrains.plugins.gradle",
},
},
{
Team: "rubymine",
SlackChannel: "rubymine-performance-alerts",
Packages: []string{
"org.jetbrains.plugins.ruby",
},
},
{
Team: "lsp",
SlackChannel: "kotlin-lsp-alerts",
Packages: []string{
"com.jetbrains.ls",
},
},
}
func GenerateAllUnitTestsSettings(backendUrl string, client *http.Client) []detector.PerformanceSettings {
settings := make([]detector.PerformanceSettings, 0, 1000)
mainSettings := detector.PerformanceSettings{
Db: "perfUnitTests",
Table: "report",
BaseSettings: detector.BaseSettings{
Branch: "master",
Machine: "intellij-linux-%-hetzner-%",
Metric: "attempt.mean.ms",
},
}
tests, err := detector.FetchAllTests(backendUrl, client, mainSettings)
if err != nil {
slog.Error("error while getting tests", "error", err)
return settings
}
// Iterate over team configurations
for _, config := range teamConfigs {
teamSettings := generateProductTestsSettings(
tests,
mainSettings,
config,
)
settings = append(settings, teamSettings...)
}
// Collect all packages to exclude from default settings
allPackages := collectAllPackages(teamConfigs)
// Generate default settings (excluding specified packages)
defaultSlackSettings := detector.SlackSettings{
Channel: "ij-perf-unit-tests-alerts",
ProductLink: "perfUnit",
}
defaultTests := filterTests(tests, allPackages, false)
for _, test := range defaultTests {
settings = append(settings, detector.PerformanceSettings{
Project: test,
Db: mainSettings.Db,
Table: mainSettings.Table,
BaseSettings: detector.BaseSettings{
Branch: mainSettings.Branch,
Machine: mainSettings.Machine,
Metric: mainSettings.Metric,
SlackSettings: defaultSlackSettings,
AnalysisSettings: detector.AnalysisSettings{
MinimumSegmentLength: 30,
MedianDifferenceThreshold: 20,
EffectSizeThreshold: 2,
},
},
})
}
return settings
}
func generateProductTestsSettings(
allTests []string,
mainSettings detector.PerformanceSettings,
config teamConfig,
) []detector.PerformanceSettings {
// Filter tests for the team
teamTests := filterTests(allTests, config.Packages, true)
// Set default AnalysisSettings if nil
if config.AnalysisSettings == nil {
config.AnalysisSettings = &detector.AnalysisSettings{
MinimumSegmentLength: 30,
MedianDifferenceThreshold: 20,
EffectSizeThreshold: 2,
}
}
slackSettings := detector.SlackSettings{
Channel: config.SlackChannel,
ProductLink: "perfUnit",
}
settings := make([]detector.PerformanceSettings, 0, len(teamTests))
for _, test := range teamTests {
settings = append(settings, detector.PerformanceSettings{
Project: test,
Db: mainSettings.Db,
Table: mainSettings.Table,
BaseSettings: detector.BaseSettings{
Branch: mainSettings.Branch,
Machine: mainSettings.Machine,
Metric: mainSettings.Metric,
SlackSettings: slackSettings,
AnalysisSettings: *config.AnalysisSettings,
},
})
}
return settings
}
// filterTests returns a new slice of tests based on inclusion or exclusion of packages.
// If include is true, we keep tests that match the packages
// If include is false, we remove tests that match the packages
func filterTests(tests []string, packages []string, include bool) []string {
var filtered []string
for _, test := range tests {
matches := false
for _, pkg := range packages {
if strings.HasPrefix(test, pkg+".") {
matches = true
break
}
}
if (include && matches) || (!include && !matches) {
filtered = append(filtered, test)
}
}
return filtered
}
func collectAllPackages(teamConfigs []teamConfig) []string {
// pre-allocation calculation
totalLen := 0
for _, config := range teamConfigs {
totalLen += len(config.Packages)
}
allPackages := make([]string, 0, totalLen)
for _, config := range teamConfigs {
allPackages = append(allPackages, config.Packages...)
}
return allPackages
}