portainer/pkg/libkubectl/delete_test.go

138 lines
4.1 KiB
Go

package libkubectl
import (
"os"
"path/filepath"
"runtime"
"testing"
)
// BenchmarkDeleteDynamic tests require a Kubernetes cluster.
// BenchmarkDeleteDynamic measures the performance and memory allocation of the DeleteDynamic function.
// The resource is recreated before each delete (using StopTimer/StartTimer to exclude setup time),
// so all iterations measure actual delete performance, not "not found" handling.
func BenchmarkDeleteDynamic(b *testing.B) {
kubeconfig := skipIfNoKubeconfig(b)
client, err := NewClient(&ClientAccess{}, "default", kubeconfig, false)
if err != nil {
b.Fatalf("Failed to create client: %v", err)
}
manifests := []string{
`apiVersion: v1
kind: ConfigMap
metadata:
name: benchmark-delete-test-config
namespace: default
data:
key: value`,
}
// Apply the manifest once BEFORE the benchmark loop
_, err = client.ApplyDynamic(b.Context(), manifests)
if err != nil {
b.Fatalf("Failed to apply initial manifest: %v", err)
}
// Force GC and measure memory before benchmark
runtime.GC()
var memBefore runtime.MemStats
runtime.ReadMemStats(&memBefore)
for b.Loop() {
// Recreate the resource before each delete to ensure it always exists
b.StopTimer()
_, err = client.ApplyDynamic(b.Context(), manifests)
if err != nil {
b.Fatalf("Failed to apply manifest: %v", err)
}
b.StartTimer()
// Delete the resource (always exists)
_, err = client.DeleteDynamic(b.Context(), manifests)
if err != nil {
b.Errorf("Failed to delete dynamic manifests: %v", err)
}
}
// Force GC and measure memory after benchmark
runtime.GC()
var memAfter runtime.MemStats
runtime.ReadMemStats(&memAfter)
// Report retained memory (key metric for leak detection)
retained := int64(memAfter.Alloc) - int64(memBefore.Alloc)
retainedMB := float64(retained) / 1024 / 1024
b.ReportMetric(float64(retained), "B-retained")
b.ReportMetric(retainedMB, "MB-retained")
}
// BenchmarkDelete tests require a Kubernetes cluster.
// BenchmarkDelete measures the performance and memory allocation of the Delete function.
// The resource is recreated before each delete (using StopTimer/StartTimer to exclude setup time),
// so all iterations measure actual delete performance, not "not found" handling.
func BenchmarkDelete(b *testing.B) {
kubeconfig := skipIfNoKubeconfig(b)
client, err := NewClient(&ClientAccess{}, "default", kubeconfig, false)
if err != nil {
b.Fatalf("Failed to create client: %v", err)
}
// Delete expects file paths, so create a temp file
tmpDir := b.TempDir()
manifestFile := filepath.Join(tmpDir, "manifest.yaml")
manifestContent := `apiVersion: v1
kind: ConfigMap
metadata:
name: benchmark-delete-file-test-config
namespace: default
data:
key: value`
if err := os.WriteFile(manifestFile, []byte(manifestContent), 0644); err != nil {
b.Fatalf("Failed to create manifest file: %v", err)
}
manifests := []string{manifestFile}
manifestsInline := []string{manifestContent}
// Apply the manifest once BEFORE the benchmark loop using ApplyDynamic
_, err = client.ApplyDynamic(b.Context(), manifestsInline)
if err != nil {
b.Fatalf("Failed to apply initial manifest: %v", err)
}
// Force GC and measure memory before benchmark
runtime.GC()
var memBefore runtime.MemStats
runtime.ReadMemStats(&memBefore)
for b.Loop() {
// Recreate the resource before each delete to ensure it always exists
b.StopTimer()
_, err = client.ApplyDynamic(b.Context(), manifestsInline)
if err != nil {
b.Fatalf("Failed to apply manifest: %v", err)
}
b.StartTimer()
// Delete the resource using Delete (file-based, always exists)
_, err = client.Delete(b.Context(), manifests)
if err != nil {
b.Errorf("Failed to delete manifests: %v", err)
}
}
// Force GC and measure memory after benchmark
runtime.GC()
var memAfter runtime.MemStats
runtime.ReadMemStats(&memAfter)
// Report retained memory (key metric for leak detection)
retained := int64(memAfter.Alloc) - int64(memBefore.Alloc)
retainedMB := float64(retained) / 1024 / 1024
b.ReportMetric(float64(retained), "B-retained")
b.ReportMetric(retainedMB, "MB-retained")
}