1// Copyright 2017 Istio Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package perftests
16
17import (
18	"testing"
19
20	"istio.io/istio/mixer/pkg/perf"
21	spyadapter "istio.io/istio/mixer/test/spyAdapter"
22)
23
24// Tests single check call into Mixer that dispatches instances to multiple noop inproc adapters.
25func Benchmark_Check_1Client_1Call(b *testing.B) {
26	settings, spyAdapter := settingsWithAdapterAndTmpls()
27	settings.RunMode = perf.InProcess
28
29	setup := perf.Setup{
30		Config: perf.Config{
31			Global:  mixerGlobalCfg,
32			Service: checkInstToSpyAdapter + attrGenToSpyAdapter,
33		},
34
35		Loads: []perf.Load{{
36			Multiplier: 1,
37			Requests: []perf.Request{
38				perf.BuildBasicCheck(baseAttr, nil),
39			},
40		}},
41	}
42
43	perf.Run(b, &setup, settings)
44	validateCheckBehavior(spyAdapter, b)
45}
46
47// Tests 5 synchronous identical check call into Mixer that dispatches instances to multiple noop inproc adapters.
48func Benchmark_Check_1Client_5SameCalls(b *testing.B) {
49	settings, spyAdapter := settingsWithAdapterAndTmpls()
50	settings.RunMode = perf.InProcess
51
52	setup := perf.Setup{
53		Config: perf.Config{
54			Global:  mixerGlobalCfg,
55			Service: checkInstToSpyAdapter + attrGenToSpyAdapter,
56		},
57
58		Loads: []perf.Load{{
59			Multiplier: 5,
60			Requests: []perf.Request{
61				perf.BuildBasicCheck(baseAttr, nil),
62			},
63		}},
64	}
65
66	perf.Run(b, &setup, settings)
67	validateCheckBehavior(spyAdapter, b)
68}
69
70// Tests 5 synchronous different check call into Mixer that dispatches instances to multiple noop inproc adapters.
71func Benchmark_Check_1Client_5DifferentCalls(b *testing.B) {
72	settings, spyAdapter := settingsWithAdapterAndTmpls()
73	settings.RunMode = perf.InProcess
74
75	setup := perf.Setup{
76		Config: perf.Config{
77			Global:  mixerGlobalCfg,
78			Service: checkInstToSpyAdapter + attrGenToSpyAdapter,
79		},
80
81		Loads: []perf.Load{
82			{
83				Multiplier: 1,
84				Requests: []perf.Request{
85					perf.BuildBasicCheck(attr1, nil),
86					perf.BuildBasicCheck(attr2, nil),
87					perf.BuildBasicCheck(attr3, nil),
88					perf.BuildBasicCheck(attr4, nil),
89					perf.BuildBasicCheck(attr5, nil),
90				},
91			},
92		},
93	}
94
95	perf.Run(b, &setup, settings)
96	validateCheckBehavior(spyAdapter, b)
97}
98
99// Tests 4 async client, each sending 5 identical check call into Mixer that dispatches instances to
100// multiple noop inproc adapters.
101func Benchmark_Check_4Clients_5SameCallsEach(b *testing.B) {
102	settings, spyAdapter := settingsWithAdapterAndTmpls()
103	settings.RunMode = perf.InProcess
104	setup := perf.Setup{
105		Config: perf.Config{
106			Global:  mixerGlobalCfg,
107			Service: checkInstToSpyAdapter + attrGenToSpyAdapter,
108		},
109
110		Loads: []perf.Load{
111			{
112				Multiplier: 5,
113				Requests: []perf.Request{
114					perf.BuildBasicCheck(baseAttr, nil),
115				},
116			},
117			{
118				Multiplier: 5,
119				Requests: []perf.Request{
120					perf.BuildBasicCheck(baseAttr, nil),
121				},
122			},
123			{
124				Multiplier: 5,
125				Requests: []perf.Request{
126					perf.BuildBasicCheck(baseAttr, nil),
127				},
128			},
129			{
130				Multiplier: 5,
131				Requests: []perf.Request{
132					perf.BuildBasicCheck(baseAttr, nil),
133				},
134			},
135		},
136	}
137
138	perf.Run(b, &setup, settings)
139	validateCheckBehavior(spyAdapter, b)
140}
141
142// Tests 4 async client, each sending 5 different check call into Mixer that dispatches instances to
143// multiple noop inproc adapters.
144func Benchmark_Check_4Clients_5DifferentCallsEach(b *testing.B) {
145	settings, spyAdapter := settingsWithAdapterAndTmpls()
146	settings.RunMode = perf.InProcess
147	setup := perf.Setup{
148		Config: perf.Config{
149			Global:  mixerGlobalCfg,
150			Service: checkInstToSpyAdapter + attrGenToSpyAdapter,
151		},
152
153		Loads: []perf.Load{
154			{
155				Multiplier: 1,
156				Requests: []perf.Request{
157					perf.BuildBasicCheck(attr1, nil),
158					perf.BuildBasicCheck(attr2, nil),
159					perf.BuildBasicCheck(attr3, nil),
160					perf.BuildBasicCheck(attr4, nil),
161					perf.BuildBasicCheck(attr5, nil),
162				},
163			},
164			{
165				Multiplier: 1,
166				Requests: []perf.Request{
167					perf.BuildBasicCheck(attr1, nil),
168					perf.BuildBasicCheck(attr2, nil),
169					perf.BuildBasicCheck(attr3, nil),
170					perf.BuildBasicCheck(attr4, nil),
171					perf.BuildBasicCheck(attr5, nil),
172				},
173			},
174			{
175				Multiplier: 1,
176				Requests: []perf.Request{
177					perf.BuildBasicCheck(attr1, nil),
178					perf.BuildBasicCheck(attr2, nil),
179					perf.BuildBasicCheck(attr3, nil),
180					perf.BuildBasicCheck(attr4, nil),
181					perf.BuildBasicCheck(attr5, nil),
182				},
183			},
184			{
185				Multiplier: 1,
186				Requests: []perf.Request{
187					perf.BuildBasicCheck(attr1, nil),
188					perf.BuildBasicCheck(attr2, nil),
189					perf.BuildBasicCheck(attr3, nil),
190					perf.BuildBasicCheck(attr4, nil),
191					perf.BuildBasicCheck(attr5, nil),
192				},
193			},
194		},
195	}
196
197	perf.Run(b, &setup, settings)
198	validateCheckBehavior(spyAdapter, b)
199}
200
201// Tests 4 async client, each sending 5 identical check call into Mixer that dispatches instances to
202// multiple noop inproc adapters. The APA in this case is a slow by 1ms.
203func Benchmark_Check_4Clients_5SameCallsEach_1MilliSecSlowApa(b *testing.B) {
204	settings, spyAdapter := settingsWith1milliSecApaAdapterAndTmpls()
205	settings.RunMode = perf.InProcess
206	setup := perf.Setup{
207		Config: perf.Config{
208			Global:  mixerGlobalCfg,
209			Service: checkInstToSpyAdapter + attrGenToSpyAdapter,
210		},
211
212		Loads: []perf.Load{
213			{
214				Multiplier: 5,
215				Requests: []perf.Request{
216					perf.BuildBasicCheck(baseAttr, nil),
217				},
218			},
219			{
220				Multiplier: 5,
221				Requests: []perf.Request{
222					perf.BuildBasicCheck(baseAttr, nil),
223				},
224			},
225			{
226				Multiplier: 5,
227				Requests: []perf.Request{
228					perf.BuildBasicCheck(baseAttr, nil),
229				},
230			},
231			{
232				Multiplier: 5,
233				Requests: []perf.Request{
234					perf.BuildBasicCheck(baseAttr, nil),
235				},
236			},
237		},
238	}
239
240	perf.Run(b, &setup, settings)
241	validateCheckBehavior(spyAdapter, b)
242}
243
244func validateCheckBehavior(spyAdapter *spyadapter.Adapter, b *testing.B) {
245	// validate all went as expected.
246	//
247	// based on the config, there must be, for each Check call from client,
248	// * single attribute generation call
249	// * single list check call
250	foundAttrGenCall := false
251	foundCheckCall := false
252	for _, cc := range spyAdapter.HandlerData.CapturedCalls {
253		if cc.Name == "HandleSampleApaAttributes" && len(cc.Instances) == 1 {
254			foundAttrGenCall = true
255		}
256		if cc.Name == "HandleSampleCheck" && len(cc.Instances) == 1 {
257			foundCheckCall = true
258		}
259	}
260
261	if !foundAttrGenCall || !foundCheckCall {
262		b.Errorf("got spy adapter calls %v; want calls  with HandleSampleApaAttributes:1 & HandleSampleCheck:1",
263			spyAdapter.HandlerData.CapturedCalls)
264	}
265}
266
267const (
268	// contains 1 rules that pass 1 instance to a check adapter
269	checkInstToSpyAdapter = `
270apiVersion: "config.istio.io/v1alpha2"
271kind: spyadapter
272metadata:
273  name: spyadapterHandler
274  namespace: istio-system
275spec:
276
277---
278apiVersion: "config.istio.io/v1alpha2"
279kind: samplecheck
280metadata:
281  name: samplecheckInst
282  namespace: istio-system
283spec:
284  stringPrimitive: source.labels["version"] | "unknown"
285---
286apiVersion: "config.istio.io/v1alpha2"
287kind: rule
288metadata:
289  name: listEntryRule
290  namespace: istio-system
291spec:
292  match: context.protocol == "http"
293  actions:
294  - handler: spyadapterHandler.spyadapter
295    instances:
296    - samplecheckInst.samplecheck
297---
298`
299)
300