Skip to content
This repository was archived by the owner on Jul 11, 2023. It is now read-only.

Commit c7036e7

Browse files
committed
test((benchmark): add Golang benchmark test cases
Add test cases that profiles CPU and memory usage with pprof. In benchmark test cases, actual OSM components are used compared to mocks in functional unit tests. Signed-off-by: Allen Leigh <[email protected]>
1 parent fa17242 commit c7036e7

12 files changed

+545
-3
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ bootstrap.yaml
6565

6666
# Test result folders
6767
test-[0-9]*/
68+
bm_profiles/
6869

6970
# hugo static site generator
7071
.DS_Store
@@ -83,4 +84,4 @@ rootfs/
8384
envoy_*.json
8485

8586
# Interim files that can stick around from a bad mockgen run.
86-
gomock_reflect_*/
87+
gomock_reflect_*/

Makefile

+4
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ go-test: cmd/cli/chart.tgz
118118
go-test-coverage: embed-files
119119
./scripts/test-w-coverage.sh
120120

121+
.PHONY: go-benchmark
122+
go-benchmark: embed-files
123+
./scripts/go-benchmark.sh
124+
121125
.PHONY: kind-up
122126
kind-up:
123127
./scripts/kind-with-registry.sh

pkg/certificate/providers/tresor/ca_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func TestNewCA(t *testing.T) {
1414
assert := tassert.New(t)
1515
rootCertCountry := "US"
1616
rootCertLocality := "CA"
17-
rootCertOrganization := "Open Service Mesh Tresor"
17+
rootCertOrganization := testCertOrgName
1818

1919
cert, err := NewCA("Tresor CA for Testing", 2*time.Second, rootCertCountry, rootCertLocality, rootCertOrganization)
2020
assert.Nil(err)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package tresor
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/openservicemesh/osm/pkg/certificate"
8+
"github.com/openservicemesh/osm/pkg/logger"
9+
)
10+
11+
var bmCert *certificate.Certificate
12+
13+
func BenchmarkIssueCertificate(b *testing.B) {
14+
if err := logger.SetLogLevel("error"); err != nil {
15+
b.Logf("Failed to set log level to error: %s", err)
16+
}
17+
18+
serviceFQDN := certificate.CommonName("a.b.c")
19+
validity := 3 * time.Second
20+
cn := certificate.CommonName("Test CA")
21+
rootCertCountry := "US"
22+
rootCertLocality := "CA"
23+
rootCertOrganization := testCertOrgName
24+
25+
rootCert, err := NewCA(cn, 1*time.Hour, rootCertCountry, rootCertLocality, rootCertOrganization)
26+
if err != nil {
27+
b.Fatalf("Error loading CA from files %s and %s: %s", rootCertPem, rootKeyPem, err.Error())
28+
}
29+
30+
m, newCertError := New(
31+
rootCert,
32+
"org",
33+
2048,
34+
)
35+
if newCertError != nil {
36+
b.Fatalf("Error creating new certificate manager: %s", newCertError.Error())
37+
}
38+
39+
b.ResetTimer()
40+
b.StartTimer()
41+
for i := 0; i < b.N; i++ {
42+
bmCert, _ = m.IssueCertificate(serviceFQDN, validity)
43+
}
44+
b.StopTimer()
45+
}

pkg/certificate/providers/tresor/certificate_manager_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ var _ = Describe("Test Certificate Manager", func() {
2424
cn := certificate.CommonName("Test CA")
2525
rootCertCountry := "US"
2626
rootCertLocality := "CA"
27-
rootCertOrganization := "Open Service Mesh Tresor"
27+
rootCertOrganization := testCertOrgName
2828

2929
rootCert, err := NewCA(cn, 1*time.Hour, rootCertCountry, rootCertLocality, rootCertOrganization)
3030
if err != nil {

pkg/certificate/providers/tresor/types.go

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ const (
1414

1515
// How many bits in the certificate serial number
1616
certSerialNumberBits = 128
17+
18+
testCertOrgName = "Open Service Mesh Tresor"
1719
)
1820

1921
var (
+193
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
package ads
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"testing"
7+
8+
mapset "github.com/deckarep/golang-set"
9+
xds_discovery "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
10+
"github.com/google/uuid"
11+
corev1 "k8s.io/api/core/v1"
12+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+
k8sClientFake "k8s.io/client-go/kubernetes/fake"
14+
15+
configv1alpha2 "github.com/openservicemesh/osm/pkg/apis/config/v1alpha2"
16+
"github.com/openservicemesh/osm/pkg/catalog"
17+
"github.com/openservicemesh/osm/pkg/endpoint"
18+
"github.com/openservicemesh/osm/pkg/k8s/informers"
19+
"github.com/openservicemesh/osm/pkg/logger"
20+
"github.com/openservicemesh/osm/pkg/messaging"
21+
"github.com/openservicemesh/osm/pkg/policy"
22+
"github.com/openservicemesh/osm/pkg/providers/kube"
23+
"github.com/openservicemesh/osm/pkg/signals"
24+
"github.com/openservicemesh/osm/pkg/smi"
25+
26+
"github.com/openservicemesh/osm/pkg/certificate"
27+
28+
"github.com/openservicemesh/osm/pkg/configurator"
29+
"github.com/openservicemesh/osm/pkg/constants"
30+
"github.com/openservicemesh/osm/pkg/envoy"
31+
"github.com/openservicemesh/osm/pkg/envoy/registry"
32+
configFake "github.com/openservicemesh/osm/pkg/gen/client/config/clientset/versioned/fake"
33+
policyFake "github.com/openservicemesh/osm/pkg/gen/client/policy/clientset/versioned/fake"
34+
"github.com/openservicemesh/osm/pkg/k8s"
35+
"github.com/openservicemesh/osm/pkg/service"
36+
"github.com/openservicemesh/osm/pkg/tests"
37+
)
38+
39+
var (
40+
proxy *envoy.Proxy
41+
server xds_discovery.AggregatedDiscoveryService_StreamAggregatedResourcesServer
42+
osmConfigurator *configurator.Client
43+
adsServer *Server
44+
)
45+
46+
func setupTestServer(b *testing.B) {
47+
stop := signals.RegisterExitHandlers()
48+
msgBroker := messaging.NewBroker(stop)
49+
kubeClient := k8sClientFake.NewSimpleClientset()
50+
configClient := configFake.NewSimpleClientset()
51+
policyClient := policyFake.NewSimpleClientset()
52+
informerCollection, err := informers.NewInformerCollection(tests.MeshName, stop,
53+
informers.WithKubeClient(kubeClient),
54+
informers.WithConfigClient(configClient, tests.OsmMeshConfigName, tests.OsmNamespace),
55+
)
56+
if err != nil {
57+
b.Fatalf("Failed to create informer collection: %s", err)
58+
}
59+
kubeController := k8s.NewKubernetesController(informerCollection, policyClient, msgBroker)
60+
policyController := policy.NewPolicyController(informerCollection, kubeController, msgBroker)
61+
osmConfigurator = configurator.NewConfigurator(informerCollection, tests.OsmNamespace, tests.OsmMeshConfigName, msgBroker)
62+
kubeProvider := kube.NewClient(kubeController, osmConfigurator)
63+
64+
meshConfig := configv1alpha2.MeshConfig{
65+
TypeMeta: metav1.TypeMeta{
66+
APIVersion: "config.openservicemesh.io",
67+
Kind: "MeshConfig",
68+
},
69+
ObjectMeta: metav1.ObjectMeta{
70+
Namespace: tests.OsmNamespace,
71+
Name: tests.OsmMeshConfigName,
72+
}, Spec: configv1alpha2.MeshConfigSpec{
73+
Certificate: configv1alpha2.CertificateSpec{
74+
CertKeyBitSize: 2048,
75+
ServiceCertValidityDuration: "1h",
76+
},
77+
Traffic: configv1alpha2.TrafficSpec{
78+
EnableEgress: true,
79+
EnablePermissiveTrafficPolicyMode: true,
80+
},
81+
Observability: configv1alpha2.ObservabilitySpec{
82+
EnableDebugServer: false,
83+
Tracing: configv1alpha2.TracingSpec{
84+
Enable: false,
85+
},
86+
},
87+
FeatureFlags: configv1alpha2.FeatureFlags{
88+
EnableWASMStats: false,
89+
EnableEgressPolicy: false,
90+
},
91+
},
92+
}
93+
_, err = configClient.ConfigV1alpha2().MeshConfigs(tests.OsmNamespace).Create(context.Background(), &meshConfig, metav1.CreateOptions{})
94+
if err != nil {
95+
b.Fatalf("Failed to create mesh config: %v", err)
96+
}
97+
98+
certManager, err := certificate.FakeCertManager()
99+
if err != nil {
100+
b.Fatalf("Failed to create fake cert manager: %v", err)
101+
}
102+
103+
// --- setup
104+
namespace := tests.Namespace
105+
proxyService := service.MeshService{
106+
Name: tests.BookstoreV1ServiceName,
107+
Namespace: namespace,
108+
}
109+
proxySvcAccount := tests.BookstoreServiceAccount
110+
111+
certPEM, _ := certManager.IssueCertificate(proxySvcAccount.ToServiceIdentity().String(), certificate.Service)
112+
cert, _ := certificate.DecodePEMCertificate(certPEM.GetCertificateChain())
113+
server, _ = tests.NewFakeXDSServer(cert, nil, nil)
114+
115+
proxyUUID := uuid.New()
116+
labels := map[string]string{constants.EnvoyUniqueIDLabelName: proxyUUID.String()}
117+
meshSpec := smi.NewSMIClient(informerCollection, tests.OsmNamespace, kubeController, msgBroker)
118+
mc := catalog.NewMeshCatalog(
119+
kubeController,
120+
meshSpec,
121+
certManager,
122+
policyController,
123+
stop,
124+
osmConfigurator,
125+
[]service.Provider{kubeProvider},
126+
[]endpoint.Provider{kubeProvider},
127+
msgBroker,
128+
)
129+
130+
proxyRegistry := registry.NewProxyRegistry(registry.ExplicitProxyServiceMapper(func(*envoy.Proxy) ([]service.MeshService, error) {
131+
return nil, nil
132+
}), nil)
133+
134+
pod := tests.NewPodFixture(namespace, fmt.Sprintf("pod-0-%s", proxyUUID), tests.BookstoreServiceAccountName, tests.PodLabels)
135+
pod.Labels[constants.EnvoyUniqueIDLabelName] = proxyUUID.String()
136+
_, err = kubeClient.CoreV1().Pods(namespace).Create(context.Background(), pod, metav1.CreateOptions{})
137+
if err != nil {
138+
b.Fatalf("Failed to create pod: %v", err)
139+
}
140+
141+
// monitor namespace
142+
nsObj := corev1.Namespace{
143+
ObjectMeta: metav1.ObjectMeta{
144+
Name: namespace,
145+
Labels: map[string]string{constants.OSMKubeResourceMonitorAnnotation: tests.MeshName},
146+
},
147+
}
148+
if err := informerCollection.Add(informers.InformerKeyNamespace, &nsObj, &testing.T{}); err != nil {
149+
b.Fatalf("Failed to add namespace to informer collection: %s", err)
150+
}
151+
152+
svc := tests.NewServiceFixture(proxyService.Name, namespace, labels)
153+
_, err = kubeClient.CoreV1().Services(namespace).Create(context.Background(), svc, metav1.CreateOptions{})
154+
if err != nil {
155+
b.Fatalf("Failed to create service: %v", err)
156+
}
157+
158+
proxy = envoy.NewProxy(envoy.KindSidecar, proxyUUID, proxySvcAccount.ToServiceIdentity(), nil)
159+
160+
adsServer = NewADSServer(mc, proxyRegistry, true, tests.Namespace, osmConfigurator, certManager, kubeController, nil)
161+
}
162+
163+
func BenchmarkSendXDSResponse(b *testing.B) {
164+
// TODO(allenlsy): Add EDS to the list
165+
testingXdsTypes := []envoy.TypeURI{
166+
envoy.TypeLDS,
167+
envoy.TypeSDS,
168+
envoy.TypeRDS,
169+
envoy.TypeCDS,
170+
}
171+
172+
if err := logger.SetLogLevel("error"); err != nil {
173+
b.Logf("Failed to set log level to error: %s", err)
174+
}
175+
176+
for _, xdsType := range testingXdsTypes {
177+
b.Run(string(xdsType), func(b *testing.B) {
178+
setupTestServer(b)
179+
180+
// Set subscribed resources
181+
proxy.SetSubscribedResources(xdsType, mapset.NewSetWith("service-cert:default/bookstore", "root-cert-for-mtls-inbound:default/bookstore|80"))
182+
183+
b.ResetTimer()
184+
b.StartTimer()
185+
for i := 0; i < b.N; i++ {
186+
if err := adsServer.sendResponse(proxy, &server, nil, osmConfigurator, xdsType); err != nil {
187+
b.Fatalf("Failed to send response: %s", err)
188+
}
189+
}
190+
b.StopTimer()
191+
})
192+
}
193+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package bootstrap
2+
3+
import (
4+
"testing"
5+
6+
tassert "github.com/stretchr/testify/assert"
7+
8+
tresorFake "github.com/openservicemesh/osm/pkg/certificate/providers/tresor/fake"
9+
"github.com/openservicemesh/osm/pkg/logger"
10+
"github.com/openservicemesh/osm/pkg/models"
11+
)
12+
13+
func BenchmarkBuildEnvoyBootstrapConfig(b *testing.B) {
14+
if err := logger.SetLogLevel("error"); err != nil {
15+
b.Logf("Failed to set log level to error: %s", err)
16+
}
17+
18+
assert := tassert.New(b)
19+
20+
cert := tresorFake.NewFakeCertificate()
21+
builder := &Builder{
22+
NodeID: cert.GetCommonName().String(),
23+
XDSHost: "osm-controller.osm-system.svc.cluster.local",
24+
TLSMinProtocolVersion: "TLSv1_0",
25+
TLSMaxProtocolVersion: "TLSv1_2",
26+
CipherSuites: []string{"abc", "xyz"},
27+
ECDHCurves: []string{"ABC", "XYZ"},
28+
OriginalHealthProbes: models.HealthProbes{
29+
Liveness: &models.HealthProbe{Path: "/liveness", Port: 81, IsHTTP: true},
30+
Readiness: &models.HealthProbe{Path: "/readiness", Port: 82, IsHTTP: true},
31+
Startup: &models.HealthProbe{Path: "/startup", Port: 83, IsHTTP: true},
32+
},
33+
}
34+
35+
b.ResetTimer()
36+
b.StartTimer()
37+
for i := 0; i < b.N; i++ {
38+
bootstrapConfig, err := builder.Build()
39+
assert.Nil(err)
40+
assert.NotNil(bootstrapConfig)
41+
}
42+
43+
b.StopTimer()
44+
}

0 commit comments

Comments
 (0)