master
go 550 lines 21.7 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 //go:build linux || freebsd || openbsd || netbsd || dragonfly
4
5 package zfspool
6
7 import (
8 "context"
9 "errors"
10 "os"
11 "strings"
12 "testing"
13
14 "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi"
15 "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/collecttest"
16
17 "github.com/stretchr/testify/assert"
18 "github.com/stretchr/testify/require"
19 )
20
21 var (
22 dataConfigJSON, _ = os.ReadFile("testdata/config.json")
23 dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
24
25 dataZpoolList, _ = os.ReadFile("testdata/zpool-list.txt")
26 dataZpoolListWithVdev, _ = os.ReadFile("testdata/zpool-list-vdev.txt")
27 dataZpoolListWithVdevLogsCache, _ = os.ReadFile("testdata/zpool-list-vdev-logs-cache.txt")
28 )
29
30 func Test_testDataIsValid(t *testing.T) {
31 for name, data := range map[string][]byte{
32 "dataConfigJSON": dataConfigJSON,
33 "dataConfigYAML": dataConfigYAML,
34
35 "dataZpoolList": dataZpoolList,
36 "dataZpoolListWithVdev": dataZpoolListWithVdev,
37 "dataZpoolListWithVdevLogsCache": dataZpoolListWithVdevLogsCache,
38 } {
39 require.NotNil(t, data, name)
40
41 }
42 }
43
44 func TestCollector_Configuration(t *testing.T) {
45 collecttest.TestConfigurationSerialize(t, &Collector{}, dataConfigJSON, dataConfigYAML)
46 }
47
48 func TestCollector_Init(t *testing.T) {
49 tests := map[string]struct {
50 config Config
51 wantFail bool
52 }{
53 "fails if 'binary_path' is not set": {
54 wantFail: true,
55 config: Config{
56 BinaryPath: "",
57 },
58 },
59 "fails if failed to find binary": {
60 wantFail: true,
61 config: Config{
62 BinaryPath: "zpool!!!",
63 },
64 },
65 }
66
67 for name, test := range tests {
68 t.Run(name, func(t *testing.T) {
69 collr := New()
70 collr.Config = test.config
71
72 if test.wantFail {
73 assert.Error(t, collr.Init(context.Background()))
74 } else {
75 assert.NoError(t, collr.Init(context.Background()))
76 }
77 })
78 }
79 }
80
81 func TestCollector_Cleanup(t *testing.T) {
82 tests := map[string]struct {
83 prepare func() *Collector
84 }{
85 "not initialized exec": {
86 prepare: func() *Collector {
87 return New()
88 },
89 },
90 "after check": {
91 prepare: func() *Collector {
92 collr := New()
93 collr.exec = prepareMockOk()
94 _ = collr.Check(context.Background())
95 return collr
96 },
97 },
98 "after collect": {
99 prepare: func() *Collector {
100 collr := New()
101 collr.exec = prepareMockOk()
102 _ = collr.Collect(context.Background())
103 return collr
104 },
105 },
106 }
107
108 for name, test := range tests {
109 t.Run(name, func(t *testing.T) {
110 collr := test.prepare()
111
112 assert.NotPanics(t, func() { collr.Cleanup(context.Background()) })
113 })
114 }
115 }
116
117 func TestCollector_Charts(t *testing.T) {
118 assert.NotNil(t, New().Charts())
119 }
120
121 func TestCollector_Check(t *testing.T) {
122 tests := map[string]struct {
123 prepareMock func() *mockZpoolCLIExec
124 wantFail bool
125 }{
126 "success case": {
127 prepareMock: prepareMockOk,
128 wantFail: false,
129 },
130 "error on list call": {
131 prepareMock: prepareMockErrOnList,
132 wantFail: true,
133 },
134 "empty response": {
135 prepareMock: prepareMockEmptyResponse,
136 wantFail: true,
137 },
138 "unexpected response": {
139 prepareMock: prepareMockUnexpectedResponse,
140 wantFail: true,
141 },
142 }
143
144 for name, test := range tests {
145 t.Run(name, func(t *testing.T) {
146 collr := New()
147 mock := test.prepareMock()
148 collr.exec = mock
149
150 if test.wantFail {
151 assert.Error(t, collr.Check(context.Background()))
152 } else {
153 assert.NoError(t, collr.Check(context.Background()))
154 }
155 })
156 }
157 }
158
159 func TestCollector_Collect(t *testing.T) {
160 tests := map[string]struct {
161 prepareMock func() *mockZpoolCLIExec
162 wantMetrics map[string]int64
163 }{
164 "success case": {
165 prepareMock: prepareMockOk,
166 wantMetrics: map[string]int64{
167 "vdev_rpool/mirror-0/nvme0n1p3_health_state_degraded": 0,
168 "vdev_rpool/mirror-0/nvme0n1p3_health_state_faulted": 0,
169 "vdev_rpool/mirror-0/nvme0n1p3_health_state_offline": 0,
170 "vdev_rpool/mirror-0/nvme0n1p3_health_state_online": 1,
171 "vdev_rpool/mirror-0/nvme0n1p3_health_state_removed": 0,
172 "vdev_rpool/mirror-0/nvme0n1p3_health_state_suspended": 0,
173 "vdev_rpool/mirror-0/nvme0n1p3_health_state_unavail": 0,
174 "vdev_rpool/mirror-0/nvme2n1p3_health_state_degraded": 0,
175 "vdev_rpool/mirror-0/nvme2n1p3_health_state_faulted": 0,
176 "vdev_rpool/mirror-0/nvme2n1p3_health_state_offline": 0,
177 "vdev_rpool/mirror-0/nvme2n1p3_health_state_online": 1,
178 "vdev_rpool/mirror-0/nvme2n1p3_health_state_removed": 0,
179 "vdev_rpool/mirror-0/nvme2n1p3_health_state_suspended": 0,
180 "vdev_rpool/mirror-0/nvme2n1p3_health_state_unavail": 0,
181 "vdev_rpool/mirror-0_health_state_degraded": 0,
182 "vdev_rpool/mirror-0_health_state_faulted": 0,
183 "vdev_rpool/mirror-0_health_state_offline": 0,
184 "vdev_rpool/mirror-0_health_state_online": 1,
185 "vdev_rpool/mirror-0_health_state_removed": 0,
186 "vdev_rpool/mirror-0_health_state_suspended": 0,
187 "vdev_rpool/mirror-0_health_state_unavail": 0,
188 "vdev_zion/mirror-0/nvme0n1p3_health_state_degraded": 0,
189 "vdev_zion/mirror-0/nvme0n1p3_health_state_faulted": 0,
190 "vdev_zion/mirror-0/nvme0n1p3_health_state_offline": 0,
191 "vdev_zion/mirror-0/nvme0n1p3_health_state_online": 1,
192 "vdev_zion/mirror-0/nvme0n1p3_health_state_removed": 0,
193 "vdev_zion/mirror-0/nvme0n1p3_health_state_suspended": 0,
194 "vdev_zion/mirror-0/nvme0n1p3_health_state_unavail": 0,
195 "vdev_zion/mirror-0/nvme2n1p3_health_state_degraded": 0,
196 "vdev_zion/mirror-0/nvme2n1p3_health_state_faulted": 0,
197 "vdev_zion/mirror-0/nvme2n1p3_health_state_offline": 0,
198 "vdev_zion/mirror-0/nvme2n1p3_health_state_online": 1,
199 "vdev_zion/mirror-0/nvme2n1p3_health_state_removed": 0,
200 "vdev_zion/mirror-0/nvme2n1p3_health_state_suspended": 0,
201 "vdev_zion/mirror-0/nvme2n1p3_health_state_unavail": 0,
202 "vdev_zion/mirror-0_health_state_degraded": 0,
203 "vdev_zion/mirror-0_health_state_faulted": 0,
204 "vdev_zion/mirror-0_health_state_offline": 0,
205 "vdev_zion/mirror-0_health_state_online": 1,
206 "vdev_zion/mirror-0_health_state_removed": 0,
207 "vdev_zion/mirror-0_health_state_suspended": 0,
208 "vdev_zion/mirror-0_health_state_unavail": 0,
209 "zpool_rpool_alloc": 9051643576,
210 "zpool_rpool_cap": 42,
211 "zpool_rpool_frag": 33,
212 "zpool_rpool_free": 12240656794,
213 "zpool_rpool_health_state_degraded": 0,
214 "zpool_rpool_health_state_faulted": 0,
215 "zpool_rpool_health_state_offline": 0,
216 "zpool_rpool_health_state_online": 1,
217 "zpool_rpool_health_state_removed": 0,
218 "zpool_rpool_health_state_suspended": 0,
219 "zpool_rpool_health_state_unavail": 0,
220 "zpool_rpool_size": 21367462298,
221 "zpool_zion_health_state_degraded": 0,
222 "zpool_zion_health_state_faulted": 1,
223 "zpool_zion_health_state_offline": 0,
224 "zpool_zion_health_state_online": 0,
225 "zpool_zion_health_state_removed": 0,
226 "zpool_zion_health_state_suspended": 0,
227 "zpool_zion_health_state_unavail": 0,
228 },
229 },
230 "success case vdev logs and cache": {
231 prepareMock: prepareMockOkVdevLogsCache,
232 wantMetrics: map[string]int64{
233 "vdev_rpool/cache/sdb2_health_state_degraded": 0,
234 "vdev_rpool/cache/sdb2_health_state_faulted": 0,
235 "vdev_rpool/cache/sdb2_health_state_offline": 0,
236 "vdev_rpool/cache/sdb2_health_state_online": 1,
237 "vdev_rpool/cache/sdb2_health_state_removed": 0,
238 "vdev_rpool/cache/sdb2_health_state_suspended": 0,
239 "vdev_rpool/cache/sdb2_health_state_unavail": 0,
240 "vdev_rpool/cache/wwn-0x500151795954c095-part2_health_state_degraded": 0,
241 "vdev_rpool/cache/wwn-0x500151795954c095-part2_health_state_faulted": 0,
242 "vdev_rpool/cache/wwn-0x500151795954c095-part2_health_state_offline": 0,
243 "vdev_rpool/cache/wwn-0x500151795954c095-part2_health_state_online": 0,
244 "vdev_rpool/cache/wwn-0x500151795954c095-part2_health_state_removed": 0,
245 "vdev_rpool/cache/wwn-0x500151795954c095-part2_health_state_suspended": 0,
246 "vdev_rpool/cache/wwn-0x500151795954c095-part2_health_state_unavail": 1,
247 "vdev_rpool/logs/mirror-1/14807975228228307538_health_state_degraded": 0,
248 "vdev_rpool/logs/mirror-1/14807975228228307538_health_state_faulted": 0,
249 "vdev_rpool/logs/mirror-1/14807975228228307538_health_state_offline": 0,
250 "vdev_rpool/logs/mirror-1/14807975228228307538_health_state_online": 0,
251 "vdev_rpool/logs/mirror-1/14807975228228307538_health_state_removed": 0,
252 "vdev_rpool/logs/mirror-1/14807975228228307538_health_state_suspended": 0,
253 "vdev_rpool/logs/mirror-1/14807975228228307538_health_state_unavail": 1,
254 "vdev_rpool/logs/mirror-1/sdb1_health_state_degraded": 0,
255 "vdev_rpool/logs/mirror-1/sdb1_health_state_faulted": 0,
256 "vdev_rpool/logs/mirror-1/sdb1_health_state_offline": 0,
257 "vdev_rpool/logs/mirror-1/sdb1_health_state_online": 1,
258 "vdev_rpool/logs/mirror-1/sdb1_health_state_removed": 0,
259 "vdev_rpool/logs/mirror-1/sdb1_health_state_suspended": 0,
260 "vdev_rpool/logs/mirror-1/sdb1_health_state_unavail": 0,
261 "vdev_rpool/logs/mirror-1_health_state_degraded": 1,
262 "vdev_rpool/logs/mirror-1_health_state_faulted": 0,
263 "vdev_rpool/logs/mirror-1_health_state_offline": 0,
264 "vdev_rpool/logs/mirror-1_health_state_online": 0,
265 "vdev_rpool/logs/mirror-1_health_state_removed": 0,
266 "vdev_rpool/logs/mirror-1_health_state_suspended": 0,
267 "vdev_rpool/logs/mirror-1_health_state_unavail": 0,
268 "vdev_rpool/mirror-0/sdc2_health_state_degraded": 0,
269 "vdev_rpool/mirror-0/sdc2_health_state_faulted": 0,
270 "vdev_rpool/mirror-0/sdc2_health_state_offline": 0,
271 "vdev_rpool/mirror-0/sdc2_health_state_online": 1,
272 "vdev_rpool/mirror-0/sdc2_health_state_removed": 0,
273 "vdev_rpool/mirror-0/sdc2_health_state_suspended": 0,
274 "vdev_rpool/mirror-0/sdc2_health_state_unavail": 0,
275 "vdev_rpool/mirror-0/sdd2_health_state_degraded": 0,
276 "vdev_rpool/mirror-0/sdd2_health_state_faulted": 0,
277 "vdev_rpool/mirror-0/sdd2_health_state_offline": 0,
278 "vdev_rpool/mirror-0/sdd2_health_state_online": 1,
279 "vdev_rpool/mirror-0/sdd2_health_state_removed": 0,
280 "vdev_rpool/mirror-0/sdd2_health_state_suspended": 0,
281 "vdev_rpool/mirror-0/sdd2_health_state_unavail": 0,
282 "vdev_rpool/mirror-0_health_state_degraded": 0,
283 "vdev_rpool/mirror-0_health_state_faulted": 0,
284 "vdev_rpool/mirror-0_health_state_offline": 0,
285 "vdev_rpool/mirror-0_health_state_online": 1,
286 "vdev_rpool/mirror-0_health_state_removed": 0,
287 "vdev_rpool/mirror-0_health_state_suspended": 0,
288 "vdev_rpool/mirror-0_health_state_unavail": 0,
289 "vdev_zion/cache/sdb2_health_state_degraded": 0,
290 "vdev_zion/cache/sdb2_health_state_faulted": 0,
291 "vdev_zion/cache/sdb2_health_state_offline": 0,
292 "vdev_zion/cache/sdb2_health_state_online": 1,
293 "vdev_zion/cache/sdb2_health_state_removed": 0,
294 "vdev_zion/cache/sdb2_health_state_suspended": 0,
295 "vdev_zion/cache/sdb2_health_state_unavail": 0,
296 "vdev_zion/cache/wwn-0x500151795954c095-part2_health_state_degraded": 0,
297 "vdev_zion/cache/wwn-0x500151795954c095-part2_health_state_faulted": 0,
298 "vdev_zion/cache/wwn-0x500151795954c095-part2_health_state_offline": 0,
299 "vdev_zion/cache/wwn-0x500151795954c095-part2_health_state_online": 0,
300 "vdev_zion/cache/wwn-0x500151795954c095-part2_health_state_removed": 0,
301 "vdev_zion/cache/wwn-0x500151795954c095-part2_health_state_suspended": 0,
302 "vdev_zion/cache/wwn-0x500151795954c095-part2_health_state_unavail": 1,
303 "vdev_zion/logs/mirror-1/14807975228228307538_health_state_degraded": 0,
304 "vdev_zion/logs/mirror-1/14807975228228307538_health_state_faulted": 0,
305 "vdev_zion/logs/mirror-1/14807975228228307538_health_state_offline": 0,
306 "vdev_zion/logs/mirror-1/14807975228228307538_health_state_online": 0,
307 "vdev_zion/logs/mirror-1/14807975228228307538_health_state_removed": 0,
308 "vdev_zion/logs/mirror-1/14807975228228307538_health_state_suspended": 0,
309 "vdev_zion/logs/mirror-1/14807975228228307538_health_state_unavail": 1,
310 "vdev_zion/logs/mirror-1/sdb1_health_state_degraded": 0,
311 "vdev_zion/logs/mirror-1/sdb1_health_state_faulted": 0,
312 "vdev_zion/logs/mirror-1/sdb1_health_state_offline": 0,
313 "vdev_zion/logs/mirror-1/sdb1_health_state_online": 1,
314 "vdev_zion/logs/mirror-1/sdb1_health_state_removed": 0,
315 "vdev_zion/logs/mirror-1/sdb1_health_state_suspended": 0,
316 "vdev_zion/logs/mirror-1/sdb1_health_state_unavail": 0,
317 "vdev_zion/logs/mirror-1_health_state_degraded": 1,
318 "vdev_zion/logs/mirror-1_health_state_faulted": 0,
319 "vdev_zion/logs/mirror-1_health_state_offline": 0,
320 "vdev_zion/logs/mirror-1_health_state_online": 0,
321 "vdev_zion/logs/mirror-1_health_state_removed": 0,
322 "vdev_zion/logs/mirror-1_health_state_suspended": 0,
323 "vdev_zion/logs/mirror-1_health_state_unavail": 0,
324 "vdev_zion/mirror-0/sdc2_health_state_degraded": 0,
325 "vdev_zion/mirror-0/sdc2_health_state_faulted": 0,
326 "vdev_zion/mirror-0/sdc2_health_state_offline": 0,
327 "vdev_zion/mirror-0/sdc2_health_state_online": 1,
328 "vdev_zion/mirror-0/sdc2_health_state_removed": 0,
329 "vdev_zion/mirror-0/sdc2_health_state_suspended": 0,
330 "vdev_zion/mirror-0/sdc2_health_state_unavail": 0,
331 "vdev_zion/mirror-0/sdd2_health_state_degraded": 0,
332 "vdev_zion/mirror-0/sdd2_health_state_faulted": 0,
333 "vdev_zion/mirror-0/sdd2_health_state_offline": 0,
334 "vdev_zion/mirror-0/sdd2_health_state_online": 1,
335 "vdev_zion/mirror-0/sdd2_health_state_removed": 0,
336 "vdev_zion/mirror-0/sdd2_health_state_suspended": 0,
337 "vdev_zion/mirror-0/sdd2_health_state_unavail": 0,
338 "vdev_zion/mirror-0_health_state_degraded": 0,
339 "vdev_zion/mirror-0_health_state_faulted": 0,
340 "vdev_zion/mirror-0_health_state_offline": 0,
341 "vdev_zion/mirror-0_health_state_online": 1,
342 "vdev_zion/mirror-0_health_state_removed": 0,
343 "vdev_zion/mirror-0_health_state_suspended": 0,
344 "vdev_zion/mirror-0_health_state_unavail": 0,
345 "zpool_rpool_alloc": 9051643576,
346 "zpool_rpool_cap": 42,
347 "zpool_rpool_frag": 33,
348 "zpool_rpool_free": 12240656794,
349 "zpool_rpool_health_state_degraded": 0,
350 "zpool_rpool_health_state_faulted": 0,
351 "zpool_rpool_health_state_offline": 0,
352 "zpool_rpool_health_state_online": 1,
353 "zpool_rpool_health_state_removed": 0,
354 "zpool_rpool_health_state_suspended": 0,
355 "zpool_rpool_health_state_unavail": 0,
356 "zpool_rpool_size": 21367462298,
357 "zpool_zion_health_state_degraded": 0,
358 "zpool_zion_health_state_faulted": 1,
359 "zpool_zion_health_state_offline": 0,
360 "zpool_zion_health_state_online": 0,
361 "zpool_zion_health_state_removed": 0,
362 "zpool_zion_health_state_suspended": 0,
363 "zpool_zion_health_state_unavail": 0,
364 },
365 },
366 "error on list call": {
367 prepareMock: prepareMockErrOnList,
368 wantMetrics: nil,
369 },
370 "empty response": {
371 prepareMock: prepareMockEmptyResponse,
372 wantMetrics: nil,
373 },
374 "unexpected response": {
375 prepareMock: prepareMockUnexpectedResponse,
376 wantMetrics: nil,
377 },
378 }
379
380 for name, test := range tests {
381 t.Run(name, func(t *testing.T) {
382 collr := New()
383 mock := test.prepareMock()
384 collr.exec = mock
385
386 mx := collr.Collect(context.Background())
387
388 assert.Equal(t, test.wantMetrics, mx)
389
390 if len(test.wantMetrics) > 0 {
391 want := len(zpoolChartsTmpl)*len(collr.seenZpools) + len(vdevChartsTmpl)*len(collr.seenVdevs)
392
393 assert.Len(t, *collr.Charts(), want, "want charts")
394
395 collecttest.TestMetricsHasAllChartsDimsSkip(t, collr.Charts(), mx, func(chart *collectorapi.Chart, _ *collectorapi.Dim) bool {
396 return strings.HasPrefix(chart.ID, "zfspool_zion") && !strings.HasSuffix(chart.ID, "health_state")
397 })
398 }
399 })
400 }
401 }
402
403 func TestCollector_parseZpoolListDevOutput(t *testing.T) {
404 tests := map[string]struct {
405 input string
406 want []vdevEntry
407 }{
408 "": {
409 input: `
410 NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
411 store 9981503995904 3046188658688 6935315337216 - - 9 30 1.00 DEGRADED -
412 mirror-0 9981503995904 3046188658688 6935315337216 - - 9 30 - ONLINE
413 sdc2 9998683602944 - - - - - - - ONLINE
414 sdd2 9998683602944 - - - - - - - ONLINE
415 logs - - - - - - - - -
416 mirror-1 17716740096 393216 17716346880 - - 0 0 - DEGRADED
417 sdb1 17951621120 - - - - - - - ONLINE
418 14807975228228307538 - - - - - - - - UNAVAIL
419 cache - - - - - - - - -
420 sdb2 99000254464 98755866624 239665152 - - 0 99 - ONLINE
421 wwn-0x500151795954c095-part2 - - - - - - - - UNAVAIL
422 `,
423 want: []vdevEntry{
424 {
425 name: "mirror-0",
426 health: "online",
427 vdev: "store/mirror-0",
428 level: 2,
429 },
430 {
431 name: "sdc2",
432 health: "online",
433 vdev: "store/mirror-0/sdc2",
434 level: 4,
435 },
436 {
437 name: "sdd2",
438 health: "online",
439 vdev: "store/mirror-0/sdd2",
440 level: 4,
441 },
442 {
443 name: "logs",
444 health: "-",
445 vdev: "store/logs",
446 level: 0,
447 },
448 {
449 name: "mirror-1",
450 health: "degraded",
451 vdev: "store/logs/mirror-1",
452 level: 2,
453 },
454 {
455 name: "sdb1",
456 health: "online",
457 vdev: "store/logs/mirror-1/sdb1",
458 level: 4,
459 },
460 {
461 name: "14807975228228307538",
462 health: "unavail",
463 vdev: "store/logs/mirror-1/14807975228228307538",
464 level: 4,
465 },
466 {
467 name: "cache",
468 health: "-",
469 vdev: "store/cache",
470 level: 0,
471 },
472 {
473 name: "sdb2",
474 health: "online",
475 vdev: "store/cache/sdb2",
476 level: 2,
477 },
478 {
479 name: "wwn-0x500151795954c095-part2",
480 health: "unavail",
481 vdev: "store/cache/wwn-0x500151795954c095-part2",
482 level: 2,
483 },
484 },
485 },
486 }
487
488 for name, test := range tests {
489 t.Run(name, func(t *testing.T) {
490 v, err := parseZpoolListVdevOutput([]byte(test.input))
491 require.NoError(t, err)
492 assert.Equal(t, test.want, v)
493 })
494 }
495 }
496
497 func prepareMockOk() *mockZpoolCLIExec {
498 return &mockZpoolCLIExec{
499 listData: dataZpoolList,
500 listWithVdevData: dataZpoolListWithVdev,
501 }
502 }
503
504 func prepareMockOkVdevLogsCache() *mockZpoolCLIExec {
505 return &mockZpoolCLIExec{
506 listData: dataZpoolList,
507 listWithVdevData: dataZpoolListWithVdevLogsCache,
508 }
509 }
510
511 func prepareMockErrOnList() *mockZpoolCLIExec {
512 return &mockZpoolCLIExec{
513 errOnList: true,
514 }
515 }
516
517 func prepareMockEmptyResponse() *mockZpoolCLIExec {
518 return &mockZpoolCLIExec{}
519 }
520
521 func prepareMockUnexpectedResponse() *mockZpoolCLIExec {
522 return &mockZpoolCLIExec{
523 listData: []byte(`
524 Lorem ipsum dolor sit amet, consectetur adipiscing elit.
525 Nulla malesuada erat id magna mattis, eu viverra tellus rhoncus.
526 Fusce et felis pulvinar, posuere sem non, porttitor eros.
527 `),
528 }
529 }
530
531 type mockZpoolCLIExec struct {
532 errOnList bool
533 listData []byte
534 listWithVdevData []byte
535 }
536
537 func (m *mockZpoolCLIExec) list() ([]byte, error) {
538 if m.errOnList {
539 return nil, errors.New("mock.list() error")
540 }
541
542 return m.listData, nil
543 }
544
545 func (m *mockZpoolCLIExec) listWithVdev(pool string) ([]byte, error) {
546 s := string(m.listWithVdevData)
547 s = strings.Replace(s, "rpool", pool, 1)
548
549 return []byte(s), nil
550 }