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**/
19package resultcache
20
21import (
22	"encoding/json"
23	"errors"
24	"reflect"
25	"testing"
26	"time"
27
28	"zabbix.com/internal/agent"
29	"zabbix.com/pkg/log"
30	"zabbix.com/pkg/plugin"
31)
32
33type mockWriter struct {
34	counter int
35	lastid  uint64
36	t       *testing.T
37}
38
39func (w *mockWriter) Write(data []byte, timeout time.Duration) (err error) {
40	log.Debugf("%s", string(data))
41	if w.counter&1 != 0 {
42		err = errors.New("mock error")
43	} else {
44		var request AgentDataRequest
45		_ = json.Unmarshal(data, &request)
46		for _, d := range request.Data {
47			if d.Id != w.lastid {
48				w.t.Errorf("Expected %d data id while got %d", w.lastid, d.Id)
49				w.t.Fail()
50			}
51			w.lastid++
52		}
53	}
54
55	w.counter++
56	return
57}
58
59func (w *mockWriter) Addr() string {
60	return ""
61}
62
63func (w *mockWriter) CanRetry() bool {
64	return false
65}
66
67func (w *mockWriter) Hostname() string {
68	return ""
69}
70
71func TestResultCache(t *testing.T) {
72	agent.Options.BufferSize = 10
73	agent.Options.EnablePersistentBuffer = 0
74	_ = log.Open(log.Console, log.Debug, "", 0)
75
76	writer := mockWriter{lastid: 1, t: t}
77	c := New(&agent.Options, 0, nil)
78	cache := c.(*MemoryCache)
79
80	value := "xyz"
81	result := plugin.Result{
82		Itemid: 1,
83		Value:  &value,
84		Ts:     time.Now(),
85	}
86
87	cache.write(&result)
88	cache.flushOutput(&writer)
89
90	cache.write(&result)
91	cache.write(&result)
92	cache.flushOutput(&writer)
93
94	cache.write(&result)
95	cache.write(&result)
96	cache.write(&result)
97	cache.write(&result)
98	cache.flushOutput(&writer)
99}
100
101func TestToken(t *testing.T) {
102	tokens := make(map[string]bool)
103	for i := 0; i < 100000; i++ {
104		token := newToken()
105		if len(token) != 32 {
106			t.Errorf("Expected token length 32 while got %d", len(token))
107			return
108		}
109		if _, ok := tokens[token]; ok {
110			t.Errorf("Duplicated token detected")
111		}
112		tokens[token] = true
113	}
114}
115
116func checkBuffer(t *testing.T, c *MemoryCache, input []*plugin.Result, expected []*AgentData) {
117	for _, r := range input {
118		c.write(r)
119	}
120
121	if !reflect.DeepEqual(c.results, expected) {
122		t.Errorf("Expected:")
123		for _, d := range expected {
124			t.Errorf("    %+v", *d)
125		}
126		t.Errorf("While got:")
127		for _, d := range c.results {
128			t.Errorf("    %+v", *d)
129		}
130	}
131}
132
133func TestBuffer(t *testing.T) {
134	input := []*plugin.Result{
135		{Itemid: 1},
136		{Itemid: 2},
137		{Itemid: 3},
138		{Itemid: 4},
139		{Itemid: 5},
140		{Itemid: 6},
141		{Itemid: 7},
142		{Itemid: 8},
143		{Itemid: 9},
144		{Itemid: 10},
145	}
146
147	expected := []*AgentData{
148		{Id: 1, Itemid: 1},
149		{Id: 2, Itemid: 2},
150		{Id: 3, Itemid: 3},
151		{Id: 4, Itemid: 4},
152		{Id: 5, Itemid: 5},
153		{Id: 6, Itemid: 6},
154		{Id: 7, Itemid: 7},
155		{Id: 8, Itemid: 8},
156		{Id: 9, Itemid: 9},
157		{Id: 10, Itemid: 10},
158	}
159
160	_ = log.Open(log.Console, log.Debug, "", 0)
161	agent.Options.BufferSize = 10
162	agent.Options.EnablePersistentBuffer = 0
163	c := New(&agent.Options, 0, nil)
164	cache := c.(*MemoryCache)
165	checkBuffer(t, cache, input, expected)
166}
167
168func TestBufferFull5(t *testing.T) {
169	input := []*plugin.Result{
170		{Itemid: 1},
171		{Itemid: 2},
172		{Itemid: 3},
173		{Itemid: 4},
174		{Itemid: 5},
175		{Itemid: 6},
176		{Itemid: 7},
177		{Itemid: 8},
178		{Itemid: 9},
179		{Itemid: 10},
180		{Itemid: 11},
181		{Itemid: 12},
182		{Itemid: 13},
183		{Itemid: 14},
184		{Itemid: 15},
185	}
186
187	expected := []*AgentData{
188		{Id: 6, Itemid: 6},
189		{Id: 7, Itemid: 7},
190		{Id: 8, Itemid: 8},
191		{Id: 9, Itemid: 9},
192		{Id: 10, Itemid: 10},
193		{Id: 11, Itemid: 11},
194		{Id: 12, Itemid: 12},
195		{Id: 13, Itemid: 13},
196		{Id: 14, Itemid: 14},
197		{Id: 15, Itemid: 15},
198	}
199
200	_ = log.Open(log.Console, log.Debug, "", 0)
201	agent.Options.BufferSize = 10
202	agent.Options.EnablePersistentBuffer = 0
203	c := New(&agent.Options, 0, nil)
204	cache := c.(*MemoryCache)
205	checkBuffer(t, cache, input, expected)
206}
207
208func TestBufferFull5ReplaceFirst(t *testing.T) {
209	input := []*plugin.Result{
210		{Itemid: 1},
211		{Itemid: 2},
212		{Itemid: 3},
213		{Itemid: 4},
214		{Itemid: 5},
215		{Itemid: 6},
216		{Itemid: 7},
217		{Itemid: 8},
218		{Itemid: 9},
219		{Itemid: 10},
220		{Itemid: 1},
221		{Itemid: 2},
222		{Itemid: 3},
223		{Itemid: 4},
224		{Itemid: 5},
225	}
226
227	expected := []*AgentData{
228		{Id: 6, Itemid: 6},
229		{Id: 7, Itemid: 7},
230		{Id: 8, Itemid: 8},
231		{Id: 9, Itemid: 9},
232		{Id: 10, Itemid: 10},
233		{Id: 11, Itemid: 1},
234		{Id: 12, Itemid: 2},
235		{Id: 13, Itemid: 3},
236		{Id: 14, Itemid: 4},
237		{Id: 15, Itemid: 5},
238	}
239
240	_ = log.Open(log.Console, log.Debug, "", 0)
241	agent.Options.BufferSize = 10
242	agent.Options.EnablePersistentBuffer = 0
243	c := New(&agent.Options, 0, nil)
244	cache := c.(*MemoryCache)
245	checkBuffer(t, cache, input, expected)
246}
247
248func TestBufferFull5ReplaceLast(t *testing.T) {
249	input := []*plugin.Result{
250		{Itemid: 1},
251		{Itemid: 2},
252		{Itemid: 3},
253		{Itemid: 4},
254		{Itemid: 5},
255		{Itemid: 6},
256		{Itemid: 7},
257		{Itemid: 8},
258		{Itemid: 9},
259		{Itemid: 10},
260		{Itemid: 6},
261		{Itemid: 7},
262		{Itemid: 8},
263		{Itemid: 9},
264		{Itemid: 10},
265	}
266
267	expected := []*AgentData{
268		{Id: 1, Itemid: 1},
269		{Id: 2, Itemid: 2},
270		{Id: 3, Itemid: 3},
271		{Id: 4, Itemid: 4},
272		{Id: 5, Itemid: 5},
273		{Id: 11, Itemid: 6},
274		{Id: 12, Itemid: 7},
275		{Id: 13, Itemid: 8},
276		{Id: 14, Itemid: 9},
277		{Id: 15, Itemid: 10},
278	}
279
280	_ = log.Open(log.Console, log.Debug, "", 0)
281	agent.Options.BufferSize = 10
282	agent.Options.EnablePersistentBuffer = 0
283	c := New(&agent.Options, 0, nil)
284	cache := c.(*MemoryCache)
285	checkBuffer(t, cache, input, expected)
286}
287
288func TestBufferFull5ReplacInterleaved(t *testing.T) {
289	input := []*plugin.Result{
290		{Itemid: 1},
291		{Itemid: 2},
292		{Itemid: 3},
293		{Itemid: 4},
294		{Itemid: 5},
295		{Itemid: 6},
296		{Itemid: 7},
297		{Itemid: 8},
298		{Itemid: 9},
299		{Itemid: 10},
300		{Itemid: 1},
301		{Itemid: 3},
302		{Itemid: 5},
303		{Itemid: 7},
304		{Itemid: 9},
305	}
306
307	expected := []*AgentData{
308		{Id: 2, Itemid: 2},
309		{Id: 4, Itemid: 4},
310		{Id: 6, Itemid: 6},
311		{Id: 8, Itemid: 8},
312		{Id: 10, Itemid: 10},
313		{Id: 11, Itemid: 1},
314		{Id: 12, Itemid: 3},
315		{Id: 13, Itemid: 5},
316		{Id: 14, Itemid: 7},
317		{Id: 15, Itemid: 9},
318	}
319
320	_ = log.Open(log.Console, log.Debug, "", 0)
321	agent.Options.BufferSize = 10
322	agent.Options.EnablePersistentBuffer = 0
323	c := New(&agent.Options, 0, nil)
324	cache := c.(*MemoryCache)
325	checkBuffer(t, cache, input, expected)
326}
327
328func TestBufferFull5OneItem(t *testing.T) {
329	input := []*plugin.Result{
330		{Itemid: 1},
331		{Itemid: 2},
332		{Itemid: 3},
333		{Itemid: 4},
334		{Itemid: 5},
335		{Itemid: 6},
336		{Itemid: 7},
337		{Itemid: 8},
338		{Itemid: 9},
339		{Itemid: 10},
340		{Itemid: 1},
341		{Itemid: 1},
342		{Itemid: 1},
343		{Itemid: 1},
344		{Itemid: 1},
345	}
346
347	expected := []*AgentData{
348		{Id: 2, Itemid: 2},
349		{Id: 3, Itemid: 3},
350		{Id: 4, Itemid: 4},
351		{Id: 5, Itemid: 5},
352		{Id: 6, Itemid: 6},
353		{Id: 7, Itemid: 7},
354		{Id: 8, Itemid: 8},
355		{Id: 9, Itemid: 9},
356		{Id: 10, Itemid: 10},
357		{Id: 15, Itemid: 1},
358	}
359
360	_ = log.Open(log.Console, log.Debug, "", 0)
361	agent.Options.BufferSize = 10
362	agent.Options.EnablePersistentBuffer = 0
363	c := New(&agent.Options, 0, nil)
364	cache := c.(*MemoryCache)
365	checkBuffer(t, cache, input, expected)
366}
367
368func TestBufferFull4OneItemPersistent(t *testing.T) {
369	input := []*plugin.Result{
370		{Itemid: 1, Persistent: true},
371		{Itemid: 2},
372		{Itemid: 3},
373		{Itemid: 4},
374		{Itemid: 5},
375		{Itemid: 6},
376		{Itemid: 7},
377		{Itemid: 8},
378		{Itemid: 9},
379		{Itemid: 10},
380		{Itemid: 1, Persistent: true},
381		{Itemid: 1, Persistent: true},
382		{Itemid: 1, Persistent: true},
383		{Itemid: 1, Persistent: true},
384	}
385
386	expected := []*AgentData{
387		{Id: 1, Itemid: 1, persistent: true},
388		{Id: 6, Itemid: 6},
389		{Id: 7, Itemid: 7},
390		{Id: 8, Itemid: 8},
391		{Id: 9, Itemid: 9},
392		{Id: 10, Itemid: 10},
393		{Id: 11, Itemid: 1, persistent: true},
394		{Id: 12, Itemid: 1, persistent: true},
395		{Id: 13, Itemid: 1, persistent: true},
396		{Id: 14, Itemid: 1, persistent: true},
397	}
398
399	_ = log.Open(log.Console, log.Debug, "", 0)
400	agent.Options.BufferSize = 10
401	agent.Options.EnablePersistentBuffer = 0
402	c := New(&agent.Options, 0, nil)
403	cache := c.(*MemoryCache)
404	checkBuffer(t, cache, input, expected)
405}
406
407func TestBufferFull5OneItemPersistent(t *testing.T) {
408	input := []*plugin.Result{
409		{Itemid: 1, Persistent: true},
410		{Itemid: 2},
411		{Itemid: 3},
412		{Itemid: 4},
413		{Itemid: 5},
414		{Itemid: 6},
415		{Itemid: 7},
416		{Itemid: 8},
417		{Itemid: 9},
418		{Itemid: 10},
419		{Itemid: 1, Persistent: true},
420		{Itemid: 1, Persistent: true},
421		{Itemid: 1, Persistent: true},
422		{Itemid: 1, Persistent: true},
423		{Itemid: 1, Persistent: true},
424	}
425
426	expected := []*AgentData{
427		{Id: 1, Itemid: 1, persistent: true},
428		{Id: 6, Itemid: 6},
429		{Id: 7, Itemid: 7},
430		{Id: 8, Itemid: 8},
431		{Id: 9, Itemid: 9},
432		{Id: 10, Itemid: 10},
433		{Id: 11, Itemid: 1, persistent: true},
434		{Id: 12, Itemid: 1, persistent: true},
435		{Id: 13, Itemid: 1, persistent: true},
436		{Id: 14, Itemid: 1, persistent: true},
437		{Id: 15, Itemid: 1, persistent: true},
438	}
439
440	_ = log.Open(log.Console, log.Debug, "", 0)
441	agent.Options.BufferSize = 10
442	agent.Options.EnablePersistentBuffer = 0
443	c := New(&agent.Options, 0, nil)
444	cache := c.(*MemoryCache)
445	checkBuffer(t, cache, input, expected)
446}
447
448func TestBufferFull10PersistentAndNormal(t *testing.T) {
449	input := []*plugin.Result{
450		{Itemid: 1, Persistent: true},
451		{Itemid: 2},
452		{Itemid: 3},
453		{Itemid: 4},
454		{Itemid: 5},
455		{Itemid: 6},
456		{Itemid: 7},
457		{Itemid: 8},
458		{Itemid: 9},
459		{Itemid: 10},
460		{Itemid: 1, Persistent: true},
461		{Itemid: 1, Persistent: true},
462		{Itemid: 1, Persistent: true},
463		{Itemid: 1, Persistent: true},
464		{Itemid: 1, Persistent: true},
465		{Itemid: 6},
466		{Itemid: 6},
467		{Itemid: 11},
468		{Itemid: 12},
469		{Itemid: 13},
470	}
471
472	expected := []*AgentData{
473		{Id: 1, Itemid: 1, persistent: true},
474		{Id: 10, Itemid: 10},
475		{Id: 11, Itemid: 1, persistent: true},
476		{Id: 12, Itemid: 1, persistent: true},
477		{Id: 13, Itemid: 1, persistent: true},
478		{Id: 14, Itemid: 1, persistent: true},
479		{Id: 15, Itemid: 1, persistent: true},
480		{Id: 17, Itemid: 6},
481		{Id: 18, Itemid: 11},
482		{Id: 19, Itemid: 12},
483		{Id: 20, Itemid: 13},
484	}
485
486	_ = log.Open(log.Console, log.Debug, "", 0)
487	agent.Options.BufferSize = 10
488	agent.Options.EnablePersistentBuffer = 0
489	c := New(&agent.Options, 0, nil)
490	cache := c.(*MemoryCache)
491	checkBuffer(t, cache, input, expected)
492}
493