Skip to content

Commit

Permalink
feat: add retina mode support for perf-test and abstract common e2e s…
Browse files Browse the repository at this point in the history
…etups (#1244)

# Description

This pull request includes several changes to the end-to-end (E2E)
testing framework for the retina project. The main update is addition of
running perf tests in advanced mode for Retina. The other updates
involve the addition of new utility functions, refactoring of existing
code for better modularity, and improvements to the performance testing
workflow.

### New Utility Functions:
* Added `RetinaChartPath`, `RetinaAdvancedProfilePath`, and
`KubeConfigFilePath` functions to dynamically generate file paths.
(`test/e2e/common/common.go`)

### Refactoring:
* Moved the `CreateAzureTempK8sInfra` function to a new file
`azure_temp_infra_setup.go` to modularize infrastructure setup.
(`test/e2e/infra/azure_temp_infra_setup.go`)
* Removed redundant code and simplified the `TestE2ERetina` and
`TestE2EPerfRetina` functions by using new utility functions and the
`CreateAzureTempK8sInfra` function. (`test/e2e/retina_e2e_test.go`,
`test/e2e/retina_perf_test.go`)
[[1]](diffhunk://#diff-66cf931d4cbc2a8832e1fcb70af2838ef6913eedb0294d0666fec1aa6787999bL24-R46)
[[2]](diffhunk://#diff-4c195fe24e6f8e7cfb68381dd2d389ca275dc11282f0dfe785526a503dae509eL6-R62)

### Performance Testing:
* Moved the performance test logic to a new file `perf.go` and added
support for running tests in different retina modes (basic, advanced).
(`test/e2e/jobs/perf.go`)
* Updated the `PublishPerfResults` function to include the retina mode
in telemetry data. (`test/e2e/scenarios/perf/publish-perf-results.go`)

### Code Cleanup:
* Removed unused imports and redundant code blocks from various files to
improve readability and maintainability. (`test/e2e/jobs/jobs.go`,
`test/e2e/scale_test.go`)
[[1]](diffhunk://#diff-96a5238dd492978468cfd659ceca6877583744425053d5f2ebbf9a62ae47e535L16)
[[2]](diffhunk://#diff-cb7aaaca572345df6e4fbb0f6d5e54f8f392870192227f9746a244e095dcdaa8L52-R56)

These changes collectively enhance the modularity, readability, and
functionality of the E2E testing framework, making it easier to maintain
and extend in the future.

## Checklist

- [X] I have read the [contributing
documentation](https://retina.sh/docs/contributing).
- [X] I signed and signed-off the commits (`git commit -S -s ...`). See
[this
documentation](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification)
on signing commits.
- [X] I have correctly attributed the author(s) of the code.
- [X] I have tested the changes locally.
- [X] I have followed the project's style guidelines.
- [] I have updated the documentation, if necessary.
- [] I have added tests, if applicable.

## Screenshots (if applicable) or Testing Completed

I have tested the relevant changes locally and have verified that it
works as nintended.

## Additional Notes

Add any additional notes or context about the pull request here.

---

Please refer to the [CONTRIBUTING.md](../CONTRIBUTING.md) file for more
information on how to contribute to this project.
  • Loading branch information
ritwikranjan authored Jan 22, 2025
1 parent 8928514 commit 8fb1c57
Show file tree
Hide file tree
Showing 9 changed files with 217 additions and 143 deletions.
17 changes: 17 additions & 0 deletions test/e2e/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"flag"
"os"
"os/user"
"path/filepath"
"strconv"
"testing"
"time"
Expand All @@ -30,6 +31,22 @@ var (
Architectures = []string{"amd64", "arm64"}
CreateInfra = flag.Bool("create-infra", true, "create a Resource group, vNET and AKS cluster for testing")
DeleteInfra = flag.Bool("delete-infra", true, "delete a Resource group, vNET and AKS cluster for testing")

// kubeconfig: path to kubeconfig file, in not provided,
// a new k8s cluster will be created
KubeConfig = flag.String("kubeConfig", "", "Path to kubeconfig file")
)

var (
RetinaChartPath = func(rootDir string) string {
return filepath.Join(rootDir, "deploy", "legacy", "manifests", "controller", "helm", "retina")
}
RetinaAdvancedProfilePath = func(rootDir string) string {
return filepath.Join(rootDir, "test", "profiles", "advanced", "values.yaml")
}
KubeConfigFilePath = func(rootDir string) string {
return filepath.Join(rootDir, "test", "e2e", "test.pem")
}
)

func ClusterNameForE2ETest(t *testing.T) string {
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/framework/kubernetes/validate-service.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func (v *ValidateResource) Run() error {
return nil
}

func serviceExists(ctx context.Context, clientset *kubernetes.Clientset, namespace, serviceName, labels string) (bool, error) {
func serviceExists(ctx context.Context, clientset *kubernetes.Clientset, namespace, _, labels string) (bool, error) {
var serviceList *corev1.ServiceList
serviceList, err := clientset.CoreV1().Services(namespace).List(ctx, metav1.ListOptions{LabelSelector: labels})
if err != nil {
Expand Down
49 changes: 49 additions & 0 deletions test/e2e/infra/azure_temp_infra_setup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package infra

import (
"context"
"crypto/rand"
"math/big"
"os"
"testing"

"github.com/microsoft/retina/test/e2e/common"
"github.com/microsoft/retina/test/e2e/framework/types"
jobs "github.com/microsoft/retina/test/e2e/jobs"
"github.com/stretchr/testify/require"
)

func CreateAzureTempK8sInfra(ctx context.Context, t *testing.T, rootDir string) string {
kubeConfigFilePath := common.KubeConfigFilePath(rootDir)
clusterName := common.ClusterNameForE2ETest(t)

subID := os.Getenv("AZURE_SUBSCRIPTION_ID")
require.NotEmpty(t, subID, "AZURE_SUBSCRIPTION_ID environment variable must be set")

location := os.Getenv("AZURE_LOCATION")
if location == "" {
nBig, err := rand.Int(rand.Reader, big.NewInt(int64(len(common.AzureLocations))))
if err != nil {
t.Fatal("Failed to generate a secure random index", err)
}
location = common.AzureLocations[nBig.Int64()]
}

rg := os.Getenv("AZURE_RESOURCE_GROUP")
if rg == "" {
// Use the cluster name as the resource group name by default.
rg = clusterName
}

// CreateTestInfra
createTestInfra := types.NewRunner(t, jobs.CreateTestInfra(subID, rg, clusterName, location, kubeConfigFilePath, *common.CreateInfra))
createTestInfra.Run(ctx)

t.Cleanup(func() {
err := jobs.DeleteTestInfra(subID, rg, location, *common.DeleteInfra).Run()
if err != nil {
t.Logf("Failed to delete test infrastructure: %v", err)
}
})
return kubeConfigFilePath
}
72 changes: 14 additions & 58 deletions test/e2e/jobs/jobs.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package retina

import (
"fmt"
"time"

"github.com/microsoft/retina/test/e2e/common"
"github.com/microsoft/retina/test/e2e/framework/azure"
"github.com/microsoft/retina/test/e2e/framework/generic"
Expand All @@ -13,7 +10,6 @@ import (
"github.com/microsoft/retina/test/e2e/scenarios/dns"
"github.com/microsoft/retina/test/e2e/scenarios/drop"
"github.com/microsoft/retina/test/e2e/scenarios/latency"
"github.com/microsoft/retina/test/e2e/scenarios/perf"
tcp "github.com/microsoft/retina/test/e2e/scenarios/tcp"
"github.com/microsoft/retina/test/e2e/scenarios/windows"
)
Expand Down Expand Up @@ -59,23 +55,19 @@ func CreateTestInfra(subID, rg, clusterName, location, kubeConfigFilePath string
}, nil)
}

job.AddStep(&generic.LoadFlags{
TagEnv: generic.DefaultTagEnv,
ImageNamespaceEnv: generic.DefaultImageNamespace,
ImageRegistryEnv: generic.DefaultImageRegistry,
}, nil)

return job
}

func DeleteTestInfra(subID, rg, clusterName, location string) *types.Job {
func DeleteTestInfra(subID, rg, location string, deleteInfra bool) *types.Job {
job := types.NewJob("Delete e2e test infrastructure")

job.AddStep(&azure.DeleteResourceGroup{
SubscriptionID: subID,
ResourceGroupName: rg,
Location: location,
}, nil)
if deleteInfra {
job.AddStep(&azure.DeleteResourceGroup{
SubscriptionID: subID,
ResourceGroupName: rg,
Location: location,
}, nil)
}

return job
}
Expand Down Expand Up @@ -274,50 +266,14 @@ func ValidateHubble(kubeConfigFilePath, chartPath string, testPodNamespace strin
return job
}

func RunPerfTest(kubeConfigFilePath string, chartPath string) *types.Job {
job := types.NewJob("Run performance tests")

benchmarkFile := fmt.Sprintf("netperf-benchmark-%s.json", time.Now().Format("20060102150405"))
resultFile := fmt.Sprintf("netperf-result-%s.json", time.Now().Format("20060102150405"))
regressionFile := fmt.Sprintf("netperf-regression-%s.json", time.Now().Format("20060102150405"))
func LoadGenericFlags() *types.Job {
job := types.NewJob("Loading Generic Flags to env")

job.AddStep(&perf.GetNetworkPerformanceMeasures{
KubeConfigFilePath: kubeConfigFilePath,
ResultTag: "no-retina",
JsonOutputFile: benchmarkFile,
}, &types.StepOptions{
SkipSavingParametersToJob: true,
})

job.AddStep(&kubernetes.InstallHelmChart{
Namespace: "kube-system",
ReleaseName: "retina",
KubeConfigFilePath: kubeConfigFilePath,
ChartPath: chartPath,
TagEnv: generic.DefaultTagEnv,
job.AddStep(&generic.LoadFlags{
TagEnv: generic.DefaultTagEnv,
ImageNamespaceEnv: generic.DefaultImageNamespace,
ImageRegistryEnv: generic.DefaultImageRegistry,
}, nil)

job.AddStep(&perf.GetNetworkPerformanceMeasures{
KubeConfigFilePath: kubeConfigFilePath,
ResultTag: "retina",
JsonOutputFile: resultFile,
}, &types.StepOptions{
SkipSavingParametersToJob: true,
})

job.AddStep(&perf.GetNetworkRegressionResults{
BaseResultsFile: benchmarkFile,
NewResultsFile: resultFile,
RegressionResultsFile: regressionFile,
}, &types.StepOptions{
SkipSavingParametersToJob: true,
})

job.AddStep(&perf.PublishPerfResults{
ResultsFile: regressionFile,
}, &types.StepOptions{
SkipSavingParametersToJob: true,
})

return job
}
73 changes: 73 additions & 0 deletions test/e2e/jobs/perf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package retina

import (
"fmt"
"time"

"github.com/microsoft/retina/test/e2e/framework/generic"
"github.com/microsoft/retina/test/e2e/framework/kubernetes"
"github.com/microsoft/retina/test/e2e/framework/types"
"github.com/microsoft/retina/test/e2e/scenarios/perf"
)

func RunPerfTest(kubeConfigFilePath, chartPath, advancedValuePath, retinaMode string) *types.Job {
job := types.NewJob("Run performance tests")

benchmarkFile := fmt.Sprintf("netperf-benchmark-%s.json", time.Now().Format("20060102150405"))
resultFile := fmt.Sprintf("netperf-result-%s.json", time.Now().Format("20060102150405"))
regressionFile := fmt.Sprintf("netperf-regression-%s.json", time.Now().Format("20060102150405"))

job.AddStep(&perf.GetNetworkPerformanceMeasures{
KubeConfigFilePath: kubeConfigFilePath,
ResultTag: "no-retina",
JsonOutputFile: benchmarkFile,
}, &types.StepOptions{
SkipSavingParametersToJob: true,
})

job.AddStep(&kubernetes.InstallHelmChart{
Namespace: "kube-system",
ReleaseName: "retina",
KubeConfigFilePath: kubeConfigFilePath,
ChartPath: chartPath,
TagEnv: generic.DefaultTagEnv,
}, nil)

if retinaMode == "advanced" {
job.AddStep(&kubernetes.UpgradeRetinaHelmChart{
Namespace: "kube-system",
ReleaseName: "retina",
KubeConfigFilePath: kubeConfigFilePath,
ChartPath: chartPath,
ValuesFile: advancedValuePath,
TagEnv: generic.DefaultTagEnv,
}, &types.StepOptions{
SkipSavingParametersToJob: true,
})
}

job.AddStep(&perf.GetNetworkPerformanceMeasures{
KubeConfigFilePath: kubeConfigFilePath,
ResultTag: "retina",
JsonOutputFile: resultFile,
}, &types.StepOptions{
SkipSavingParametersToJob: true,
})

job.AddStep(&perf.GetNetworkRegressionResults{
BaseResultsFile: benchmarkFile,
NewResultsFile: resultFile,
RegressionResultsFile: regressionFile,
}, &types.StepOptions{
SkipSavingParametersToJob: true,
})

job.AddStep(&perf.PublishPerfResults{
ResultsFile: regressionFile,
RetinaMode: retinaMode,
}, &types.StepOptions{
SkipSavingParametersToJob: true,
})

return job
}
62 changes: 25 additions & 37 deletions test/e2e/retina_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
package retina

import (
"crypto/rand"
"math/big"
"os"
"path/filepath"
"testing"

"github.com/microsoft/retina/test/e2e/common"
"github.com/microsoft/retina/test/e2e/framework/helpers"
"github.com/microsoft/retina/test/e2e/framework/types"
"github.com/microsoft/retina/test/e2e/infra"
jobs "github.com/microsoft/retina/test/e2e/jobs"
"github.com/stretchr/testify/require"
)
Expand All @@ -21,57 +20,46 @@ func TestE2ERetina(t *testing.T) {
ctx, cancel := helpers.Context(t)
defer cancel()

// Truncate the username to 8 characters
clusterName := common.ClusterNameForE2ETest(t)

subID := os.Getenv("AZURE_SUBSCRIPTION_ID")
require.NotEmpty(t, subID)

location := os.Getenv("AZURE_LOCATION")
if location == "" {
nBig, err := rand.Int(rand.Reader, big.NewInt(int64(len(common.AzureLocations))))
if err != nil {
t.Fatalf("Failed to generate a secure random index: %v", err)
}
location = common.AzureLocations[nBig.Int64()]
}

rg := os.Getenv("AZURE_RESOURCE_GROUP")
if rg == "" {
// Use the cluster name as the resource group name by default.
rg = clusterName
}

cwd, err := os.Getwd()
require.NoError(t, err)

// Get to root of the repo by going up two directories
rootDir := filepath.Dir(filepath.Dir(cwd))

chartPath := filepath.Join(rootDir, "deploy", "legacy", "manifests", "controller", "helm", "retina")
hubblechartPath := filepath.Join(rootDir, "deploy", "hubble", "manifests", "controller", "helm", "retina")
profilePath := filepath.Join(rootDir, "test", "profiles", "advanced", "values.yaml")
kubeConfigFilePath := filepath.Join(rootDir, "test", "e2e", "test.pem")

// CreateTestInfra
createTestInfra := types.NewRunner(t, jobs.CreateTestInfra(subID, rg, clusterName, location, kubeConfigFilePath, *common.CreateInfra))
createTestInfra.Run(ctx)
err = jobs.LoadGenericFlags().Run()
require.NoError(t, err, "failed to load generic flags")

t.Cleanup(func() {
if *common.DeleteInfra {
_ = jobs.DeleteTestInfra(subID, rg, clusterName, location).Run()
}
})
if *common.KubeConfig == "" {
*common.KubeConfig = infra.CreateAzureTempK8sInfra(ctx, t, rootDir)
}

// Install and test Retina basic metrics
basicMetricsE2E := types.NewRunner(t, jobs.InstallAndTestRetinaBasicMetrics(kubeConfigFilePath, chartPath, common.TestPodNamespace))
basicMetricsE2E := types.NewRunner(t,
jobs.InstallAndTestRetinaBasicMetrics(
common.KubeConfigFilePath(rootDir),
common.RetinaChartPath(rootDir),
common.TestPodNamespace),
)
basicMetricsE2E.Run(ctx)

// Upgrade and test Retina with advanced metrics
advanceMetricsE2E := types.NewRunner(t, jobs.UpgradeAndTestRetinaAdvancedMetrics(kubeConfigFilePath, chartPath, profilePath, common.TestPodNamespace))
advanceMetricsE2E := types.NewRunner(t,
jobs.UpgradeAndTestRetinaAdvancedMetrics(
common.KubeConfigFilePath(rootDir),
common.RetinaChartPath(rootDir),
common.RetinaAdvancedProfilePath(rootDir),
common.TestPodNamespace),
)
advanceMetricsE2E.Run(ctx)

// Install and test Hubble basic metrics
validatehubble := types.NewRunner(t, jobs.ValidateHubble(kubeConfigFilePath, hubblechartPath, common.TestPodNamespace))
validatehubble := types.NewRunner(t,
jobs.ValidateHubble(
common.KubeConfigFilePath(rootDir),
hubblechartPath,
common.TestPodNamespace),
)
validatehubble.Run(ctx)
}
Loading

0 comments on commit 8fb1c57

Please sign in to comment.