1// Copyright 2018 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	"fmt"
19	"io/ioutil"
20	"path"
21	"path/filepath"
22	"runtime"
23	"testing"
24
25	adptModel "istio.io/api/mixer/adapter/model/v1beta1"
26	"istio.io/istio/mixer/pkg/perf"
27	spyadapter "istio.io/istio/mixer/test/spyAdapter"
28	reportTmpl "istio.io/istio/mixer/test/spyAdapter/template/report"
29	"istio.io/istio/mixer/test/spybackend"
30)
31
32// Test single report dispatch to IBP spybackend.
33func Benchmark_IBP_Adapter_Report(b *testing.B) {
34	s := initOOPAdapter()
35	defer s.Close()
36	oopAdapterCfg, err := getOOPAdapterAndTempls()
37	setting := perf.Settings{
38		RunMode: perf.InProcessBypassGrpc,
39	}
40	if err != nil {
41		b.Errorf("cannot load spyadapter template config %v", err)
42	}
43	setup := perf.Setup{
44		Config: perf.Config{
45			Global:  mixerGlobalCfg,
46			Service: oopAdapterCfg + metricsToOOPSpyAdapter,
47		},
48
49		Loads: reportLoad,
50	}
51
52	perf.Run(b, &setup, setting)
53	validateOOPReportBehavior(s, b)
54}
55
56// Test single report dispatch to in process spyadapter.
57func Benchmark_Inproc_Adapter_Report(b *testing.B) {
58	settings, spyAdapter := settingsWithAdapterAndTmpls()
59	settings.RunMode = perf.InProcessBypassGrpc
60	setup := perf.Setup{
61		Config: perf.Config{
62			Global:  mixerGlobalCfg,
63			Service: metricsToInprocSpyAdapter,
64		},
65
66		Loads: reportLoad,
67	}
68
69	perf.Run(b, &setup, settings)
70	validateInprocReportBehavior(spyAdapter, b)
71}
72
73func getOOPAdapterAndTempls() (string, error) {
74	_, filename, _, _ := runtime.Caller(0)
75	dymanicTemplates := []string{
76		"../spyAdapter/template/report/reporttmpl.yaml",
77		"../spyAdapter/template/quota/quotatmpl.yaml",
78		"../spyAdapter/template/check/tmpl.yaml",
79		"../spybackend/nosession-perf.yaml",
80	}
81
82	data := ""
83	for _, fileRelativePath := range dymanicTemplates {
84		if f, err := filepath.Abs(path.Join(path.Dir(filename), fileRelativePath)); err != nil {
85			return "", fmt.Errorf("cannot load attributes.yaml: %v", err)
86		} else if f, err := ioutil.ReadFile(f); err != nil {
87			return "", fmt.Errorf("cannot load attributes.yaml: %v", err)
88		} else {
89			data += string(f)
90		}
91	}
92	return data, nil
93}
94
95func initOOPAdapter() spybackend.Server {
96	a := &spybackend.Args{
97		Behavior: &spybackend.Behavior{
98			HandleSampleReportResult: &adptModel.ReportResult{},
99		},
100		Requests: &spybackend.Requests{
101			HandleSampleReportRequest: []*reportTmpl.HandleSampleReportRequest{},
102		},
103	}
104	s, _ := spybackend.NewNoSessionServer(a)
105	s.Run()
106	return s
107}
108
109func validateOOPReportBehavior(s spybackend.Server, b *testing.B) {
110	cc := s.GetCapturedCalls()
111
112	for _, e := range cc {
113		if e.Name == "HandleSampleReport" && len(e.Instances) == 1 {
114			return
115		}
116	}
117	b.Errorf("got spy adapter calls %v; want calls HandleSampleReport:1", cc)
118}
119
120func validateInprocReportBehavior(spyAdapter *spyadapter.Adapter, b *testing.B) {
121	for _, cc := range spyAdapter.HandlerData.CapturedCalls {
122		if cc.Name == "HandleSampleReport" && len(cc.Instances) == 1 {
123			return
124		}
125	}
126
127	b.Errorf("got spy adapter calls %v; want calls with HandleSampleReport:1",
128		spyAdapter.HandlerData.CapturedCalls)
129}
130
131var reportLoad = []perf.Load{
132	{
133		Multiplier: 1,
134		Requests: []perf.Request{
135			perf.BuildBasicReport(attr1),
136		},
137	},
138}
139
140const (
141	metricsToOOPSpyAdapter = `
142apiVersion: "config.istio.io/v1alpha2"
143kind: instance
144metadata:
145  name: requestcount
146  namespace: istio-system
147spec:
148  template: report
149  params:
150    value: "1"
151    dimensions:
152      source_service: source.service | "unknown"
153      source_version: source.labels["version"] | "unknown"
154      destination_service: destination.service | "unknown"
155      destination_version: destination.labels["version"] | "unknown"
156      response_code: response.code | 200
157      connection_mtls: connection.mtls | false
158      request_host: request.host | "unknown"
159      request_method: request.method | "unknown"
160      request_path: request.path | "unknown"
161      request_scheme: request.scheme | "unknown"
162      request_useragent: request.useragent | "unknown"
163      context_protocol: context.protocol | "unknown"
164      destination_uid: destination.uid | "unknown"
165---
166apiVersion: "config.istio.io/v1alpha2"
167kind: handler
168metadata:
169  name: spyadapter
170  namespace: istio-system
171spec:
172  adapter: spybackend-nosession
173  connection:
174    address: "localhost:50051"
175---
176apiVersion: "config.istio.io/v1alpha2"
177kind: rule
178metadata:
179  name: spyadapter-rule
180  namespace: istio-system
181spec:
182  match: context.protocol == "http"
183  actions:
184  - handler: spyadapter.handler
185    instances:
186    - requestcount.instance
187---
188`
189
190	metricsToInprocSpyAdapter = `
191apiVersion: "config.istio.io/v1alpha2"
192kind: samplereport
193metadata:
194  name: requestcount
195  namespace: istio-system
196spec:
197  value: "1"
198  dimensions:
199    source_service: source.service | "unknown"
200    source_version: source.labels["version"] | "unknown"
201    destination_service: destination.service | "unknown"
202    destination_version: destination.labels["version"] | "unknown"
203    response_code: response.code | 200
204    connection_mtls: connection.mtls | false
205    request_host: request.host | "unknown"
206    request_method: request.method | "unknown"
207    request_path: request.path | "unknown"
208    request_scheme: request.scheme | "unknown"
209    request_useragent: request.useragent | "unknown"
210    context_protocol: context.protocol | "unknown"
211    destination_uid: destination.uid | "unknown"
212---
213apiVersion: "config.istio.io/v1alpha2"
214kind: spyadapter
215metadata:
216  name: handler
217  namespace: istio-system
218spec:
219---
220apiVersion: "config.istio.io/v1alpha2"
221kind: rule
222metadata:
223  name: promhttp
224  namespace: istio-system
225spec:
226  match: context.protocol == "http"
227  actions:
228  - handler: handler.spyadapter
229    instances:
230    - requestcount.samplereport
231---
232`
233)
234