master
go 232 lines 5.89 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package dnsquery
4
5 import (
6 "context"
7 "errors"
8 "os"
9 "testing"
10 "time"
11
12 "github.com/miekg/dns"
13 "github.com/stretchr/testify/assert"
14 "github.com/stretchr/testify/require"
15
16 "github.com/netdata/netdata/go/plugins/pkg/confopt"
17 "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/collecttest"
18 )
19
20 var (
21 dataConfigJSON, _ = os.ReadFile("testdata/config.json")
22 dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
23 )
24
25 func Test_testDataIsValid(t *testing.T) {
26 for name, data := range map[string][]byte{
27 "dataConfigJSON": dataConfigJSON,
28 "dataConfigYAML": dataConfigYAML,
29 } {
30 require.NotNil(t, data, name)
31 }
32 }
33
34 func TestCollector_ConfigurationSerialize(t *testing.T) {
35 collecttest.TestConfigurationSerialize(t, &Collector{}, dataConfigJSON, dataConfigYAML)
36 }
37
38 func TestCollector_Init(t *testing.T) {
39 tests := map[string]struct {
40 wantFail bool
41 config Config
42 }{
43 "success when all set": {
44 wantFail: false,
45 config: Config{
46 Domains: []string{"example.com"},
47 Servers: []string{"192.0.2.0"},
48 Network: "udp",
49 RecordTypes: []string{"A"},
50 Port: 53,
51 Timeout: confopt.Duration(time.Second),
52 },
53 },
54 "success when using deprecated record_type": {
55 wantFail: false,
56 config: Config{
57 Domains: []string{"example.com"},
58 Servers: []string{"192.0.2.0"},
59 Network: "udp",
60 RecordType: "A",
61 Port: 53,
62 Timeout: confopt.Duration(time.Second),
63 },
64 },
65 "fail with default": {
66 wantFail: true,
67 config: New().Config,
68 },
69 "fail when domains not set": {
70 wantFail: true,
71 config: Config{
72 Domains: nil,
73 Servers: []string{"192.0.2.0"},
74 Network: "udp",
75 RecordTypes: []string{"A"},
76 Port: 53,
77 Timeout: confopt.Duration(time.Second),
78 },
79 },
80 "fail when network is invalid": {
81 wantFail: true,
82 config: Config{
83 Domains: []string{"example.com"},
84 Servers: []string{"192.0.2.0"},
85 Network: "gcp",
86 RecordTypes: []string{"A"},
87 Port: 53,
88 Timeout: confopt.Duration(time.Second),
89 },
90 },
91 "fail when record_type is invalid": {
92 wantFail: true,
93 config: Config{
94 Domains: []string{"example.com"},
95 Servers: []string{"192.0.2.0"},
96 Network: "udp",
97 RecordTypes: []string{"B"},
98 Port: 53,
99 Timeout: confopt.Duration(time.Second),
100 },
101 },
102 }
103
104 for name, test := range tests {
105 t.Run(name, func(t *testing.T) {
106 collr := New()
107 collr.Config = test.config
108
109 if test.wantFail {
110 assert.Error(t, collr.Init(context.Background()))
111 } else {
112 assert.NoError(t, collr.Init(context.Background()))
113 }
114 })
115 }
116 }
117
118 func TestCollector_Check(t *testing.T) {
119 tests := map[string]struct {
120 wantFail bool
121 prepare func() *Collector
122 }{
123 "success when DNS query successful": {
124 wantFail: false,
125 prepare: caseDNSClientOK,
126 },
127 "success when DNS query returns an error": {
128 wantFail: false,
129 prepare: caseDNSClientErr,
130 },
131 }
132
133 for name, test := range tests {
134 t.Run(name, func(t *testing.T) {
135 collr := test.prepare()
136
137 require.NoError(t, collr.Init(context.Background()))
138
139 if test.wantFail {
140 assert.Error(t, collr.Check(context.Background()))
141 } else {
142 assert.NoError(t, collr.Check(context.Background()))
143 }
144 })
145 }
146 }
147
148 func TestCollector_Charts(t *testing.T) {
149 collr := New()
150
151 collr.Domains = []string{"google.com"}
152 collr.Servers = []string{"192.0.2.0", "192.0.2.1"}
153 require.NoError(t, collr.Init(context.Background()))
154
155 assert.NotNil(t, collr.Charts())
156 assert.Len(t, *collr.Charts(), len(dnsChartsTmpl)*len(collr.Servers))
157 }
158
159 func TestCollector_Collect(t *testing.T) {
160 tests := map[string]struct {
161 prepare func() *Collector
162 wantMetrics map[string]int64
163 }{
164 "success when DNS query successful": {
165 prepare: caseDNSClientOK,
166 wantMetrics: map[string]int64{
167 "server_192.0.2.0_record_A_query_status_dns_error": 0,
168 "server_192.0.2.0_record_A_query_status_network_error": 0,
169 "server_192.0.2.0_record_A_query_status_success": 1,
170 "server_192.0.2.0_record_A_query_time": 1000000000,
171 "server_192.0.2.1_record_A_query_status_dns_error": 0,
172 "server_192.0.2.1_record_A_query_status_network_error": 0,
173 "server_192.0.2.1_record_A_query_status_success": 1,
174 "server_192.0.2.1_record_A_query_time": 1000000000,
175 },
176 },
177 "fail when DNS query returns an error": {
178 prepare: caseDNSClientErr,
179 wantMetrics: map[string]int64{
180 "server_192.0.2.0_record_A_query_status_dns_error": 0,
181 "server_192.0.2.0_record_A_query_status_network_error": 1,
182 "server_192.0.2.0_record_A_query_status_success": 0,
183 "server_192.0.2.1_record_A_query_status_dns_error": 0,
184 "server_192.0.2.1_record_A_query_status_network_error": 1,
185 "server_192.0.2.1_record_A_query_status_success": 0,
186 },
187 },
188 }
189
190 for name, test := range tests {
191 t.Run(name, func(t *testing.T) {
192 collr := test.prepare()
193
194 require.NoError(t, collr.Init(context.Background()))
195
196 mx := collr.Collect(context.Background())
197
198 require.Equal(t, test.wantMetrics, mx)
199 })
200 }
201 }
202
203 func caseDNSClientOK() *Collector {
204 collr := New()
205 collr.Domains = []string{"example.com"}
206 collr.Servers = []string{"192.0.2.0", "192.0.2.1"}
207 collr.newDNSClient = func(_ string, _ time.Duration) dnsClient {
208 return mockDNSClient{errOnExchange: false}
209 }
210 return collr
211 }
212
213 func caseDNSClientErr() *Collector {
214 collr := New()
215 collr.Domains = []string{"example.com"}
216 collr.Servers = []string{"192.0.2.0", "192.0.2.1"}
217 collr.newDNSClient = func(_ string, _ time.Duration) dnsClient {
218 return mockDNSClient{errOnExchange: true}
219 }
220 return collr
221 }
222
223 type mockDNSClient struct {
224 errOnExchange bool
225 }
226
227 func (m mockDNSClient) Exchange(_ *dns.Msg, _ string) (response *dns.Msg, rtt time.Duration, err error) {
228 if m.errOnExchange {
229 return nil, time.Second, errors.New("mock.Exchange() error")
230 }
231 return nil, time.Second, nil
232 }