1/*
2** Zabbix
3** Copyright (C) 2001-2021 Zabbix SIA
4**
5** This program is free software; you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation; either version 2 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program; if not, write to the Free Software
17** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18**/
19
20package metric
21
22import (
23	"reflect"
24	"testing"
25
26	"zabbix.com/pkg/conf"
27)
28
29var (
30	paramURI              = NewConnParam("URI", "Description.").WithDefault("localhost:1521").WithSession()
31	paramUsername         = NewConnParam("User", "Description.").WithDefault("")
32	paramRequiredUsername = NewConnParam("User", "Description.").SetRequired()
33	paramUserValidation   = NewConnParam("User", "Description.").WithDefault("").WithValidator(
34		SetValidator{Set: []string{"", "supervisor", "admin", "guest"}})
35	paramPassword = NewConnParam("Password", "Description.").WithDefault("")
36	paramGeneral  = NewParam("GeneralParam", "Description.")
37)
38
39var metricSet = MetricSet{
40	"metric.foo": New("Foo description.",
41		[]*Param{paramURI, paramUsername, paramPassword,
42			NewParam("Param1", "Description.").WithDefault("60").WithValidator(SetValidator{Set: []string{"15", "60"}}),
43		}, false),
44	"metric.query": New("Query description.",
45		[]*Param{paramURI, paramUsername, paramPassword,
46			NewParam("QueryName", "Description.").SetRequired(),
47		}, true),
48	"metric.requiredSessionParam": New("RequiredSessionParam description.",
49		[]*Param{paramURI, paramRequiredUsername, paramPassword}, false),
50	"metric.withoutPassword": New("WithoutPassword description.",
51		[]*Param{paramURI, paramUsername}, false),
52	"metric.userValidation": New("UserValidation description.",
53		[]*Param{paramURI, paramUserValidation, paramPassword}, false),
54}
55
56func TestMetric_EvalParams(t *testing.T) {
57	type args struct {
58		rawParams []string
59		sessions  interface{}
60	}
61	tests := []struct {
62		name      string
63		m         *Metric
64		args      args
65		want      map[string]string
66		wantErr   bool
67		wantPanic bool
68	}{
69		{
70			name: "Must fail if too many parameters passed",
71			m:    metricSet["metric.foo"],
72			args: args{
73				rawParams: []string{"localhost", "user", "password", "15", "excessParam"},
74				sessions:  map[string]conf.Session{},
75			},
76			want:      nil,
77			wantErr:   true,
78			wantPanic: false,
79		},
80		{
81			name: "Must not fail if passed more parameters than described, but the metric has the varParam enabled",
82			m:    metricSet["metric.query"],
83			args: args{
84				rawParams: []string{"localhost", "user", "password", "queryName", "queryParam1", "queryParam2"},
85				sessions:  map[string]conf.Session{},
86			},
87			want:      map[string]string{"Password": "password", "QueryName": "queryName", "URI": "localhost", "User": "user"},
88			wantErr:   false,
89			wantPanic: false,
90		},
91		{
92			name: "Must fail if a required parameter is not specified",
93			m:    metricSet["metric.query"],
94			args: args{
95				rawParams: []string{"localhost", "user", "password", "", "queryParam1"},
96				sessions:  map[string]conf.Session{},
97			},
98			want:      nil,
99			wantErr:   true,
100			wantPanic: false,
101		},
102		{
103			name: "Must fail if validation failed",
104			m:    metricSet["metric.foo"],
105			args: args{
106				rawParams: []string{"localhost", "user", "password", "wrongValue"},
107				sessions:  map[string]conf.Session{},
108			},
109			want:      nil,
110			wantErr:   true,
111			wantPanic: false,
112		},
113		{
114			name: "Must fail if a session parameter did not pass validation",
115			m:    metricSet["metric.userValidation"],
116			args: args{
117				rawParams: []string{"Session1"},
118				sessions: map[string]conf.Session{
119					"Session1": {URI: "localhost", User: "bob", Password: "password"},
120				},
121			},
122			want:      nil,
123			wantErr:   true,
124			wantPanic: false,
125		},
126		{
127			name: "Must fail if a connection parameter passed along with a session",
128			m:    metricSet["metric.foo"],
129			args: args{
130				rawParams: []string{"Session1", "", "password"},
131				sessions: map[string]conf.Session{
132					"Session1": {URI: "localhost", User: "user", Password: "password"},
133				},
134			},
135			want:      nil,
136			wantErr:   true,
137			wantPanic: false,
138		},
139		{
140			name: "Must fail if a required parameter is omitted in a session",
141			m:    metricSet["metric.requiredSessionParam"],
142			args: args{
143				rawParams: []string{"Session1"},
144				sessions: map[string]conf.Session{
145					"Session1": {URI: "localhost", Password: "password"},
146				},
147			},
148			want:      nil,
149			wantErr:   true,
150			wantPanic: false,
151		},
152		{
153			name: "Must panic if cannot find any session's parameter in a schema",
154			m:    metricSet["metric.withoutPassword"],
155			args: args{
156				rawParams: []string{"Session1"},
157				sessions: map[string]conf.Session{
158					"Session1": {URI: "localhost", User: "user", Password: "password"},
159				},
160			},
161			want:      nil,
162			wantErr:   false,
163			wantPanic: true,
164		},
165		{
166			name: "Must successfully return parsed parameters (without session)",
167			m:    metricSet["metric.foo"],
168			args: args{
169				rawParams: []string{"localhost", "user", "password", "15"},
170				sessions:  map[string]conf.Session{},
171			},
172			want:      map[string]string{"URI": "localhost", "User": "user", "Password": "password", "Param1": "15"},
173			wantErr:   false,
174			wantPanic: false,
175		},
176		{
177			name: "Must successfully return parsed parameters (with session)",
178			m:    metricSet["metric.foo"],
179			args: args{
180				rawParams: []string{"Session1", "", "", "15"},
181				sessions: map[string]conf.Session{
182					"Session1": {URI: "localhost", User: "user", Password: "password"},
183				},
184			},
185			want: map[string]string{
186				"URI": "localhost", "User": "user", "Password": "password", "Param1": "15", "sessionName": "Session1",
187			},
188			wantErr:   false,
189			wantPanic: false,
190		},
191	}
192	for _, tt := range tests {
193		t.Run(tt.name, func(t *testing.T) {
194			if tt.wantPanic {
195				defer func() {
196					if r := recover(); r == nil {
197						t.Error("Metric.EvalParams() must panic with runtime error")
198					}
199				}()
200			}
201
202			gotParams, err := tt.m.EvalParams(tt.args.rawParams, tt.args.sessions)
203			if (err != nil) != tt.wantErr {
204				t.Errorf("EvalParams() error = %v, wantErr %v", err, tt.wantErr)
205				return
206			}
207			if !reflect.DeepEqual(gotParams, tt.want) {
208				t.Errorf("EvalParams() got = %v, want %v", gotParams, tt.want)
209			}
210		})
211	}
212}
213
214func TestNew(t *testing.T) {
215	type args struct {
216		description string
217		params      []*Param
218		varParam    bool
219	}
220	tests := []struct {
221		name      string
222		args      args
223		want      *Metric
224		wantPanic bool
225	}{
226		{
227			name: "Must fail if a parameter has a non-unique name",
228			args: args{
229				"Metric description.",
230				[]*Param{paramURI, paramUsername, paramUsername, paramPassword, NewParam("Param", "Description.")},
231				false,
232			},
233			want:      nil,
234			wantPanic: true,
235		},
236		{
237			name: "Must fail if a session placed not first",
238			args: args{
239				"Metric description.",
240				[]*Param{paramUsername, paramPassword, paramURI, NewParam("Param", "Description.")},
241				false,
242			},
243			want:      nil,
244			wantPanic: true,
245		},
246		{
247			name: "Must fail if parameters describing a connection placed not in a row",
248			args: args{
249				"Metric description.",
250				[]*Param{paramURI, paramUsername, NewParam("Param", "Description."), paramPassword},
251				false,
252			},
253			want:      nil,
254			wantPanic: true,
255		},
256		{
257			name: "Must successfully return a new metric",
258			args: args{
259				"Metric description.",
260				[]*Param{paramURI, paramUsername, paramPassword, paramGeneral},
261				false,
262			},
263			want: &Metric{
264				description: "Metric description.",
265				params:      []*Param{paramURI, paramUsername, paramPassword, paramGeneral},
266				varParam:    false,
267			},
268			wantPanic: false,
269		},
270	}
271	for _, tt := range tests {
272		t.Run(tt.name, func(t *testing.T) {
273			if tt.wantPanic {
274				defer func() {
275					if r := recover(); r == nil {
276						t.Error("New() must panic with runtime error")
277					}
278				}()
279			}
280
281			if got := New(tt.args.description, tt.args.params, tt.args.varParam); !reflect.DeepEqual(got, tt.want) {
282				t.Errorf("New() = %v, want %v", got, tt.want)
283			}
284		})
285	}
286}
287