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