Skip to content

Commit

Permalink
Performance test snapshot generation (#8415)
Browse files Browse the repository at this point in the history
* switch to builder paradigm

* sub-resource builders

* unit test resource builders

* cleanup

* codegen

* changelog

* fix sniPattern enum

* builder filestructure

* zero-indexed names

* export builder types

* Build in test body

* fmt

* fix type names
  • Loading branch information
bewebi authored Jun 23, 2023
1 parent 5178ca2 commit 8cdcda3
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 50 deletions.
8 changes: 8 additions & 0 deletions changelog/v1.15.0-beta15/scaled-snapshot-builder.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
changelog:
- type: NON_USER_FACING
issueLink: https://github.com/solo-io/solo-projects/issues/5116
resolvesIssue: true
description: >-
Generate scaled snapshots for performance tests via Builder paradigm for improved usability and extensibility
skipCI-kube-tests:true
skipCI-docs-build:true
42 changes: 20 additions & 22 deletions projects/gloo/pkg/translator/performance_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,10 @@ var _ = Describe("Translation - Benchmarking Tests", Serial, Label(labels.Perfor
// We measure the duration of the translation of the snapshot, benchmarking according to the benchmarkConfig
// Labels are used to add context to the entry description
DescribeTable("Benchmark table",
func(apiSnap *v1snap.ApiSnapshot, config benchmarkConfig, labels ...string) {
func(snapBuilder *gloohelpers.ScaledSnapshotBuilder, config benchmarkConfig, labels ...string) {
var (
proxy *v1.Proxy
apiSnap *v1snap.ApiSnapshot
proxy *v1.Proxy

snap cache.Snapshot
errs reporter.ResourceReports
Expand All @@ -99,6 +100,8 @@ var _ = Describe("Translation - Benchmarking Tests", Serial, Label(labels.Perfor
tooFastWarningCount int
)

apiSnap = snapBuilder.Build()

params := plugins.Params{
Ctx: context.Background(),
Snapshot: apiSnap,
Expand Down Expand Up @@ -150,26 +153,15 @@ var _ = Describe("Translation - Benchmarking Tests", Serial, Label(labels.Perfor
},
generateDesc, // generate descriptions for table entries with nil descriptions
Entry("basic", basicSnap, basicConfig),
Entry(nil, gloohelpers.ScaledSnapshot(gloohelpers.ScaleConfig{
Upstreams: 10,
Endpoints: 1,
}), basicConfig, "upstream scale"),
Entry(nil, gloohelpers.ScaledSnapshot(gloohelpers.ScaleConfig{
Upstreams: 1000,
Endpoints: 1,
}), oneKUpstreamsConfig, "upstream scale"),
Entry(nil, gloohelpers.ScaledSnapshot(gloohelpers.ScaleConfig{
Upstreams: 1,
Endpoints: 10,
}), basicConfig, "endpoint scale"),
Entry(nil, gloohelpers.ScaledSnapshot(gloohelpers.ScaleConfig{
Upstreams: 1,
Endpoints: 1000,
}), basicConfig, "endpoint scale"),
Entry(nil, gloohelpers.ScaledSnapshot(gloohelpers.ScaleConfig{
Upstreams: 10,
Endpoints: 10,
}), basicConfig, "endpoint scale", "upstream scale"),
Entry(nil, gloohelpers.NewScaledSnapshotBuilder().WithUpstreamCount(10).WithEndpointCount(1), basicConfig, "upstream scale"),
Entry(nil, gloohelpers.NewScaledSnapshotBuilder().WithUpstreamCount(1000).WithEndpointCount(1), oneKUpstreamsConfig, "upstream scale"),
Entry(nil, gloohelpers.NewScaledSnapshotBuilder().WithUpstreamCount(1).WithEndpointCount(10), basicConfig, "endpoint scale"),
Entry(nil, gloohelpers.NewScaledSnapshotBuilder().WithUpstreamCount(1).WithEndpointCount(1000), basicConfig, "endpoint scale"),
Entry(nil, gloohelpers.NewScaledSnapshotBuilder().WithUpstreamCount(10).WithEndpointCount(10), basicConfig, "endpoint scale", "upstream scale"),
Entry(nil, gloohelpers.NewScaledSnapshotBuilder().WithUpstreamCount(10).WithEndpointCount(1).
WithUpstreamBuilder(consistentSniUsBuilder), basicConfig, "consistent SNI", "upstream scale"),
Entry(nil, gloohelpers.NewScaledSnapshotBuilder().WithUpstreamCount(10).WithEndpointCount(1).
WithUpstreamBuilder(uniqueSniUsBuilder), basicConfig, "unique SNI", "upstream scale"),
)
})

Expand Down Expand Up @@ -218,3 +210,9 @@ var oneKUpstreamsConfig = benchmarkConfig{
matchers.HavePercentileLessThan(90, 2*time.Second),
},
}

/* Upstream SNI Test */
var (
consistentSniUsBuilder = gloohelpers.NewUpstreamBuilder().WithConsistentSni()
uniqueSniUsBuilder = gloohelpers.NewUpstreamBuilder().WithUniqueSni()
)
15 changes: 15 additions & 0 deletions test/helpers/endpoints.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package helpers

import v1 "github.com/solo-io/gloo/projects/gloo/pkg/api/v1"

// EndpointBuilder contains options for building Endpoints to be included in scaled Snapshots
// there are no options currently configurable for the endpointBuilder
type EndpointBuilder struct{}

func NewEndpointBuilder() *EndpointBuilder {
return &EndpointBuilder{}
}

func (b *EndpointBuilder) Build(i int) *v1.Endpoint {
return Endpoint(i)
}
87 changes: 59 additions & 28 deletions test/helpers/resources.go → test/helpers/scaled_snapshots.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,77 @@ package helpers
import (
"fmt"

"github.com/solo-io/gloo/projects/gloo/pkg/api/v1/gloosnapshot"

"github.com/solo-io/gloo/projects/gloo/pkg/defaults"

"github.com/golang/protobuf/ptypes/wrappers"
v3 "github.com/solo-io/gloo/projects/gloo/pkg/api/external/envoy/config/core/v3"
v1 "github.com/solo-io/gloo/projects/gloo/pkg/api/v1"
"github.com/solo-io/gloo/projects/gloo/pkg/api/v1/core/matchers"
"github.com/solo-io/gloo/projects/gloo/pkg/api/v1/gloosnapshot"
v1static "github.com/solo-io/gloo/projects/gloo/pkg/api/v1/options/static"
"github.com/solo-io/gloo/projects/gloo/pkg/api/v1/ssl"
"github.com/solo-io/solo-kit/pkg/api/v1/resources/core"
)

// ScaleConfig enumerates the number of each type of resource that should be included in a snapshot as generated by
// ScaledSnapshot
// ScaledSnapshotBuilder enumerates the number of each type of resource that should be included in a snapshot and
// contains a builder for each sub-resource type which is responsible for building instances of that resource
// Additional fields should be added as needed
type ScaleConfig struct {
Endpoints int
Upstreams int
type ScaledSnapshotBuilder struct {
epCount int
usCount int

epBuilder *EndpointBuilder
usBuilder *UpstreamBuilder
}

func NewScaledSnapshotBuilder() *ScaledSnapshotBuilder {
return &ScaledSnapshotBuilder{
epBuilder: NewEndpointBuilder(),
usBuilder: NewUpstreamBuilder(),
}
}

func (b *ScaledSnapshotBuilder) WithUpstreamCount(n int) *ScaledSnapshotBuilder {
b.usCount = n
return b
}

func (b *ScaledSnapshotBuilder) WithUpstreamBuilder(ub *UpstreamBuilder) *ScaledSnapshotBuilder {
b.usBuilder = ub
return b
}

func (b *ScaledSnapshotBuilder) WithEndpointCount(n int) *ScaledSnapshotBuilder {
b.epCount = n
return b
}

func (b *ScaledSnapshotBuilder) WithEndpointBuilder(eb *EndpointBuilder) *ScaledSnapshotBuilder {
b.epBuilder = eb
return b
}

// Build generates a snapshot populated with the specified number of each resource for the builder, using the
// sub-resource builders to build each sub-resource
func (b *ScaledSnapshotBuilder) Build() *gloosnapshot.ApiSnapshot {
endpointList := make(v1.EndpointList, b.epCount)
for i := 0; i < b.epCount; i++ {
endpointList[i] = b.epBuilder.Build(i)
}

upstreamList := make(v1.UpstreamList, b.usCount)
for i := 0; i < b.usCount; i++ {
upstreamList[i] = b.usBuilder.Build(i)
}

return &gloosnapshot.ApiSnapshot{
// The proxy should contain a route for each upstream
Proxies: []*v1.Proxy{Proxy(b.usCount)},

Endpoints: endpointList,
Upstreams: upstreamList,
}
}

func upMeta(i int) *core.Metadata {
Expand Down Expand Up @@ -236,25 +289,3 @@ func Proxy(numRoutes int) *v1.Proxy {
},
}
}

// ScaledSnapshot generates a snapshot populated with particular numbers of each resource types as determined by the
// passed config
func ScaledSnapshot(config ScaleConfig) *gloosnapshot.ApiSnapshot {
endpointList := make(v1.EndpointList, config.Endpoints)
for i := 0; i < config.Endpoints; i++ {
endpointList[i] = Endpoint(i + 1) // names are 1-indexed
}

upstreamList := make(v1.UpstreamList, config.Upstreams)
for i := 0; i < config.Upstreams; i++ {
upstreamList[i] = Upstream(i + 1) // names are 1-indexed
}

return &gloosnapshot.ApiSnapshot{
// The proxy should contain a route for each upstream
Proxies: []*v1.Proxy{Proxy(config.Upstreams)},

Endpoints: endpointList,
Upstreams: upstreamList,
}
}
56 changes: 56 additions & 0 deletions test/helpers/scaled_snapshots_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package helpers_test

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/solo-io/gloo/test/helpers"
)

var _ = Describe("ScaledSnapshotBuilder", func() {
When("with endpoints", func() {
It("generates a snapshot with the expected number of endpoints", func() {
snap := helpers.NewScaledSnapshotBuilder().WithEndpointCount(10).Build()
Expect(snap.Endpoints).To(HaveLen(10))
Expect(snap.Upstreams).To(HaveLen(0))
})
})

When("with upstreams", func() {
It("generates a snapshot with the expected number of upstreams", func() {
snap := helpers.NewScaledSnapshotBuilder().WithUpstreamCount(10).Build()
Expect(snap.Endpoints).To(HaveLen(0))
Expect(snap.Upstreams).To(HaveLen(10))
})
})

When("with upstream builder", func() {
When("with consistent SNI", func() {
It("generates a snapshot with upstreams that all have the same SNI", func() {
snap := helpers.NewScaledSnapshotBuilder().WithUpstreamCount(10).
WithUpstreamBuilder(helpers.NewUpstreamBuilder().WithConsistentSni()).Build()
Expect(snap.Upstreams).To(HaveLen(10))
Expect(snap.Upstreams[0].SslConfig).NotTo(BeNil())
firstSNI := snap.Upstreams[0].SslConfig.Sni
for i := 1; i < len(snap.Upstreams); i++ {
Expect(snap.Upstreams[i].SslConfig).NotTo(BeNil())
Expect(snap.Upstreams[i].SslConfig.Sni).To(Equal(firstSNI))
}
})
})

When("with unique SNI", func() {
It("generates a snapshot with upstreams that all have unique SNI", func() {
snap := helpers.NewScaledSnapshotBuilder().WithUpstreamCount(10).
WithUpstreamBuilder(helpers.NewUpstreamBuilder().WithUniqueSni()).Build()
Expect(snap.Upstreams).To(HaveLen(10))
foundSNI := map[string]bool{}
for i := 0; i < len(snap.Upstreams); i++ {
Expect(snap.Upstreams[i].SslConfig).NotTo(BeNil())
_, ok := foundSNI[snap.Upstreams[i].SslConfig.Sni]
Expect(ok).To(BeFalse())
foundSNI[snap.Upstreams[i].SslConfig.Sni] = true
}
})
})
})
})
52 changes: 52 additions & 0 deletions test/helpers/upstreams.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package helpers

import (
"fmt"

v1 "github.com/solo-io/gloo/projects/gloo/pkg/api/v1"
"github.com/solo-io/gloo/projects/gloo/pkg/api/v1/ssl"
)

// UpstreamBuilder contains options for building Upstreams to be included in scaled Snapshots
type UpstreamBuilder struct {
sniPattern sniPattern
}

type sniPattern int

const (
noSni sniPattern = iota
uniqueSni
consistentSni
)

func NewUpstreamBuilder() *UpstreamBuilder {
return &UpstreamBuilder{}
}

func (b *UpstreamBuilder) WithUniqueSni() *UpstreamBuilder {
b.sniPattern = uniqueSni
return b
}

func (b *UpstreamBuilder) WithConsistentSni() *UpstreamBuilder {
b.sniPattern = consistentSni
return b
}

func (b *UpstreamBuilder) Build(i int) *v1.Upstream {
up := Upstream(i)

switch b.sniPattern {
case uniqueSni:
up.SslConfig = &ssl.UpstreamSslConfig{
Sni: fmt.Sprintf("unique-domain-%d", i),
}
case consistentSni:
up.SslConfig = &ssl.UpstreamSslConfig{
Sni: "consistent-domain",
}
}

return up
}
39 changes: 39 additions & 0 deletions test/helpers/upstreams_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package helpers_test

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/solo-io/gloo/test/helpers"
)

var _ = Describe("UpstreamBuilder", func() {
When("using the base builder", func() {
It("generates an upstream without SslConfig", func() {
up := helpers.NewUpstreamBuilder().Build(1)
Expect(up.SslConfig).To(BeNil())
})
})

When("with consistent SNI", func() {
It("generates an upstream with the same SNI for any i", func() {
up1 := helpers.NewUpstreamBuilder().WithConsistentSni().Build(1)
Expect(up1.SslConfig).NotTo(BeNil())
up2 := helpers.NewUpstreamBuilder().WithConsistentSni().Build(2)
Expect(up2.SslConfig).NotTo(BeNil())

Expect(up1.SslConfig.Sni).To(Equal(up2.SslConfig.Sni))
})
})

When("with unique SNI", func() {
It("generates an upstream with unique SNI for a given i", func() {
up1 := helpers.NewUpstreamBuilder().WithUniqueSni().Build(1)
Expect(up1.SslConfig).NotTo(BeNil())
up2 := helpers.NewUpstreamBuilder().WithUniqueSni().Build(2)
Expect(up2.SslConfig).NotTo(BeNil())

Expect(up1.SslConfig.Sni).NotTo(Equal(up2.SslConfig.Sni))
})
})

})

0 comments on commit 8cdcda3

Please sign in to comment.