github.com/netdata/go.d.plugin@v0.58.1/modules/nvme/nvme_test.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package nvme
     4  
     5  import (
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"os"
    10  	"testing"
    11  
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  var (
    17  	dataNVMeListJSON, _           = os.ReadFile("testdata/nvme-list.json")
    18  	dataNVMeListEmptyJSON, _      = os.ReadFile("testdata/nvme-list-empty.json")
    19  	dataNVMeSmartLogJSON, _       = os.ReadFile("testdata/nvme-smart-log.json")
    20  	dataNVMeSmartLogStringJSON, _ = os.ReadFile("testdata/nvme-smart-log-string.json")
    21  	dataNVMeSmartLogFloatJSON, _  = os.ReadFile("testdata/nvme-smart-log-float.json")
    22  )
    23  
    24  func Test_testDataIsValid(t *testing.T) {
    25  	for name, data := range map[string][]byte{
    26  		"dataNVMeListJSON":           dataNVMeListJSON,
    27  		"dataNVMeListEmptyJSON":      dataNVMeListEmptyJSON,
    28  		"dataNVMeSmartLogStringJSON": dataNVMeSmartLogStringJSON,
    29  		"dataNVMeSmartLogFloatJSON":  dataNVMeSmartLogFloatJSON,
    30  	} {
    31  		require.NotNilf(t, data, name)
    32  	}
    33  }
    34  
    35  func TestNVMe_Init(t *testing.T) {
    36  	tests := map[string]struct {
    37  		prepare  func(n *NVMe)
    38  		wantFail bool
    39  	}{
    40  		"fails if 'binary_path' not set": {
    41  			wantFail: true,
    42  			prepare: func(n *NVMe) {
    43  				n.BinaryPath = ""
    44  			},
    45  		},
    46  		"fails if can't locate nvme-cli": {
    47  			wantFail: true,
    48  			prepare: func(n *NVMe) {
    49  				n.BinaryPath += "!!!"
    50  			},
    51  		},
    52  	}
    53  
    54  	for name, test := range tests {
    55  		t.Run(name, func(t *testing.T) {
    56  			nv := New()
    57  
    58  			test.prepare(nv)
    59  
    60  			if test.wantFail {
    61  				assert.False(t, nv.Init())
    62  			} else {
    63  				assert.True(t, nv.Init())
    64  			}
    65  		})
    66  	}
    67  }
    68  
    69  func TestNVMe_Charts(t *testing.T) {
    70  	assert.NotNil(t, New().Charts())
    71  }
    72  
    73  func TestNVMe_Cleanup(t *testing.T) {
    74  	assert.NotPanics(t, New().Cleanup)
    75  }
    76  
    77  func TestNVMe_Check(t *testing.T) {
    78  	tests := map[string]struct {
    79  		wantFail bool
    80  		prepare  func(n *NVMe)
    81  	}{
    82  		"success if all calls successful": {
    83  			wantFail: false,
    84  			prepare:  prepareCaseOK,
    85  		},
    86  		"fails if 'nvme list' returns an empty list": {
    87  			wantFail: true,
    88  			prepare:  prepareCaseEmptyList,
    89  		},
    90  		"fails if 'nvme list' returns an error": {
    91  			wantFail: true,
    92  			prepare:  prepareCaseErrOnList,
    93  		},
    94  		"fails if 'nvme smart-log' returns an error": {
    95  			wantFail: true,
    96  			prepare:  prepareCaseErrOnSmartLog,
    97  		},
    98  	}
    99  
   100  	for name, test := range tests {
   101  		t.Run(name, func(t *testing.T) {
   102  			n := New()
   103  
   104  			test.prepare(n)
   105  
   106  			if test.wantFail {
   107  				assert.False(t, n.Check())
   108  			} else {
   109  				assert.True(t, n.Check())
   110  			}
   111  		})
   112  	}
   113  }
   114  
   115  func TestNVMe_Collect(t *testing.T) {
   116  	type testCaseStep struct {
   117  		prepare func(n *NVMe)
   118  		check   func(t *testing.T, n *NVMe)
   119  	}
   120  
   121  	tests := map[string][]testCaseStep{
   122  		"success if all calls successful": {
   123  			{
   124  				prepare: prepareCaseOK,
   125  				check: func(t *testing.T, n *NVMe) {
   126  					mx := n.Collect()
   127  
   128  					expected := map[string]int64{
   129  						"device_nvme0n1_available_spare":                              100,
   130  						"device_nvme0n1_controller_busy_time":                         497040,
   131  						"device_nvme0n1_critical_comp_time":                           0,
   132  						"device_nvme0n1_critical_warning_available_spare":             0,
   133  						"device_nvme0n1_critical_warning_nvm_subsystem_reliability":   0,
   134  						"device_nvme0n1_critical_warning_persistent_memory_read_only": 0,
   135  						"device_nvme0n1_critical_warning_read_only":                   0,
   136  						"device_nvme0n1_critical_warning_temp_threshold":              0,
   137  						"device_nvme0n1_critical_warning_volatile_mem_backup_failed":  0,
   138  						"device_nvme0n1_data_units_read":                              5068041216000,
   139  						"device_nvme0n1_data_units_written":                           69712734208000,
   140  						"device_nvme0n1_host_read_commands":                           313528805,
   141  						"device_nvme0n1_host_write_commands":                          1928062610,
   142  						"device_nvme0n1_media_errors":                                 0,
   143  						"device_nvme0n1_num_err_log_entries":                          110,
   144  						"device_nvme0n1_percentage_used":                              2,
   145  						"device_nvme0n1_power_cycles":                                 64,
   146  						"device_nvme0n1_power_on_time":                                17906400,
   147  						"device_nvme0n1_temperature":                                  36,
   148  						"device_nvme0n1_thm_temp1_total_time":                         0,
   149  						"device_nvme0n1_thm_temp1_trans_count":                        0,
   150  						"device_nvme0n1_thm_temp2_total_time":                         0,
   151  						"device_nvme0n1_thm_temp2_trans_count":                        0,
   152  						"device_nvme0n1_unsafe_shutdowns":                             39,
   153  						"device_nvme0n1_warning_temp_time":                            0,
   154  						"device_nvme1n1_available_spare":                              100,
   155  						"device_nvme1n1_controller_busy_time":                         497040,
   156  						"device_nvme1n1_critical_comp_time":                           0,
   157  						"device_nvme1n1_critical_warning_available_spare":             0,
   158  						"device_nvme1n1_critical_warning_nvm_subsystem_reliability":   0,
   159  						"device_nvme1n1_critical_warning_persistent_memory_read_only": 0,
   160  						"device_nvme1n1_critical_warning_read_only":                   0,
   161  						"device_nvme1n1_critical_warning_temp_threshold":              0,
   162  						"device_nvme1n1_critical_warning_volatile_mem_backup_failed":  0,
   163  						"device_nvme1n1_data_units_read":                              5068041216000,
   164  						"device_nvme1n1_data_units_written":                           69712734208000,
   165  						"device_nvme1n1_host_read_commands":                           313528805,
   166  						"device_nvme1n1_host_write_commands":                          1928062610,
   167  						"device_nvme1n1_media_errors":                                 0,
   168  						"device_nvme1n1_num_err_log_entries":                          110,
   169  						"device_nvme1n1_percentage_used":                              2,
   170  						"device_nvme1n1_power_cycles":                                 64,
   171  						"device_nvme1n1_power_on_time":                                17906400,
   172  						"device_nvme1n1_temperature":                                  36,
   173  						"device_nvme1n1_thm_temp1_total_time":                         0,
   174  						"device_nvme1n1_thm_temp1_trans_count":                        0,
   175  						"device_nvme1n1_thm_temp2_total_time":                         0,
   176  						"device_nvme1n1_thm_temp2_trans_count":                        0,
   177  						"device_nvme1n1_unsafe_shutdowns":                             39,
   178  						"device_nvme1n1_warning_temp_time":                            0,
   179  					}
   180  
   181  					assert.Equal(t, expected, mx)
   182  				},
   183  			},
   184  		},
   185  		"success if all calls successful with string values": {
   186  			{
   187  				prepare: prepareCaseStringValuesOK,
   188  				check: func(t *testing.T, n *NVMe) {
   189  					mx := n.Collect()
   190  
   191  					expected := map[string]int64{
   192  						"device_nvme0n1_available_spare":                              100,
   193  						"device_nvme0n1_controller_busy_time":                         497040,
   194  						"device_nvme0n1_critical_comp_time":                           0,
   195  						"device_nvme0n1_critical_warning_available_spare":             0,
   196  						"device_nvme0n1_critical_warning_nvm_subsystem_reliability":   0,
   197  						"device_nvme0n1_critical_warning_persistent_memory_read_only": 0,
   198  						"device_nvme0n1_critical_warning_read_only":                   0,
   199  						"device_nvme0n1_critical_warning_temp_threshold":              0,
   200  						"device_nvme0n1_critical_warning_volatile_mem_backup_failed":  0,
   201  						"device_nvme0n1_data_units_read":                              5068041216000,
   202  						"device_nvme0n1_data_units_written":                           69712734208000,
   203  						"device_nvme0n1_host_read_commands":                           313528805,
   204  						"device_nvme0n1_host_write_commands":                          1928062610,
   205  						"device_nvme0n1_media_errors":                                 0,
   206  						"device_nvme0n1_num_err_log_entries":                          110,
   207  						"device_nvme0n1_percentage_used":                              2,
   208  						"device_nvme0n1_power_cycles":                                 64,
   209  						"device_nvme0n1_power_on_time":                                17906400,
   210  						"device_nvme0n1_temperature":                                  36,
   211  						"device_nvme0n1_thm_temp1_total_time":                         0,
   212  						"device_nvme0n1_thm_temp1_trans_count":                        0,
   213  						"device_nvme0n1_thm_temp2_total_time":                         0,
   214  						"device_nvme0n1_thm_temp2_trans_count":                        0,
   215  						"device_nvme0n1_unsafe_shutdowns":                             39,
   216  						"device_nvme0n1_warning_temp_time":                            0,
   217  						"device_nvme1n1_available_spare":                              100,
   218  						"device_nvme1n1_controller_busy_time":                         497040,
   219  						"device_nvme1n1_critical_comp_time":                           0,
   220  						"device_nvme1n1_critical_warning_available_spare":             0,
   221  						"device_nvme1n1_critical_warning_nvm_subsystem_reliability":   0,
   222  						"device_nvme1n1_critical_warning_persistent_memory_read_only": 0,
   223  						"device_nvme1n1_critical_warning_read_only":                   0,
   224  						"device_nvme1n1_critical_warning_temp_threshold":              0,
   225  						"device_nvme1n1_critical_warning_volatile_mem_backup_failed":  0,
   226  						"device_nvme1n1_data_units_read":                              5068041216000,
   227  						"device_nvme1n1_data_units_written":                           69712734208000,
   228  						"device_nvme1n1_host_read_commands":                           313528805,
   229  						"device_nvme1n1_host_write_commands":                          1928062610,
   230  						"device_nvme1n1_media_errors":                                 0,
   231  						"device_nvme1n1_num_err_log_entries":                          110,
   232  						"device_nvme1n1_percentage_used":                              2,
   233  						"device_nvme1n1_power_cycles":                                 64,
   234  						"device_nvme1n1_power_on_time":                                17906400,
   235  						"device_nvme1n1_temperature":                                  36,
   236  						"device_nvme1n1_thm_temp1_total_time":                         0,
   237  						"device_nvme1n1_thm_temp1_trans_count":                        0,
   238  						"device_nvme1n1_thm_temp2_total_time":                         0,
   239  						"device_nvme1n1_thm_temp2_trans_count":                        0,
   240  						"device_nvme1n1_unsafe_shutdowns":                             39,
   241  						"device_nvme1n1_warning_temp_time":                            0,
   242  					}
   243  
   244  					assert.Equal(t, expected, mx)
   245  				},
   246  			},
   247  		},
   248  		"success if all calls successful with float values": {
   249  			{
   250  				prepare: prepareCaseFloatValuesOK,
   251  				check: func(t *testing.T, n *NVMe) {
   252  					mx := n.Collect()
   253  
   254  					expected := map[string]int64{
   255  						"device_nvme0n1_available_spare":                              100,
   256  						"device_nvme0n1_controller_busy_time":                         497040,
   257  						"device_nvme0n1_critical_comp_time":                           0,
   258  						"device_nvme0n1_critical_warning_available_spare":             0,
   259  						"device_nvme0n1_critical_warning_nvm_subsystem_reliability":   0,
   260  						"device_nvme0n1_critical_warning_persistent_memory_read_only": 0,
   261  						"device_nvme0n1_critical_warning_read_only":                   0,
   262  						"device_nvme0n1_critical_warning_temp_threshold":              0,
   263  						"device_nvme0n1_critical_warning_volatile_mem_backup_failed":  0,
   264  						"device_nvme0n1_data_units_read":                              5068041216000,
   265  						"device_nvme0n1_data_units_written":                           69712734208000,
   266  						"device_nvme0n1_host_read_commands":                           313528805,
   267  						"device_nvme0n1_host_write_commands":                          1928062610,
   268  						"device_nvme0n1_media_errors":                                 0,
   269  						"device_nvme0n1_num_err_log_entries":                          110,
   270  						"device_nvme0n1_percentage_used":                              2,
   271  						"device_nvme0n1_power_cycles":                                 64,
   272  						"device_nvme0n1_power_on_time":                                17906400,
   273  						"device_nvme0n1_temperature":                                  36,
   274  						"device_nvme0n1_thm_temp1_total_time":                         0,
   275  						"device_nvme0n1_thm_temp1_trans_count":                        0,
   276  						"device_nvme0n1_thm_temp2_total_time":                         0,
   277  						"device_nvme0n1_thm_temp2_trans_count":                        0,
   278  						"device_nvme0n1_unsafe_shutdowns":                             39,
   279  						"device_nvme0n1_warning_temp_time":                            0,
   280  						"device_nvme1n1_available_spare":                              100,
   281  						"device_nvme1n1_controller_busy_time":                         497040,
   282  						"device_nvme1n1_critical_comp_time":                           0,
   283  						"device_nvme1n1_critical_warning_available_spare":             0,
   284  						"device_nvme1n1_critical_warning_nvm_subsystem_reliability":   0,
   285  						"device_nvme1n1_critical_warning_persistent_memory_read_only": 0,
   286  						"device_nvme1n1_critical_warning_read_only":                   0,
   287  						"device_nvme1n1_critical_warning_temp_threshold":              0,
   288  						"device_nvme1n1_critical_warning_volatile_mem_backup_failed":  0,
   289  						"device_nvme1n1_data_units_read":                              5068041216000,
   290  						"device_nvme1n1_data_units_written":                           69712734208000,
   291  						"device_nvme1n1_host_read_commands":                           313528805,
   292  						"device_nvme1n1_host_write_commands":                          1928062610,
   293  						"device_nvme1n1_media_errors":                                 0,
   294  						"device_nvme1n1_num_err_log_entries":                          110,
   295  						"device_nvme1n1_percentage_used":                              2,
   296  						"device_nvme1n1_power_cycles":                                 64,
   297  						"device_nvme1n1_power_on_time":                                17906400,
   298  						"device_nvme1n1_temperature":                                  36,
   299  						"device_nvme1n1_thm_temp1_total_time":                         0,
   300  						"device_nvme1n1_thm_temp1_trans_count":                        0,
   301  						"device_nvme1n1_thm_temp2_total_time":                         0,
   302  						"device_nvme1n1_thm_temp2_trans_count":                        0,
   303  						"device_nvme1n1_unsafe_shutdowns":                             39,
   304  						"device_nvme1n1_warning_temp_time":                            0,
   305  					}
   306  
   307  					assert.Equal(t, expected, mx)
   308  				},
   309  			},
   310  		},
   311  		"fail if 'nvme list' returns an empty list": {
   312  			{
   313  				prepare: prepareCaseEmptyList,
   314  				check: func(t *testing.T, n *NVMe) {
   315  					mx := n.Collect()
   316  
   317  					assert.Equal(t, (map[string]int64)(nil), mx)
   318  				},
   319  			},
   320  		},
   321  		"fail if 'nvme list' returns an error": {
   322  			{
   323  				prepare: prepareCaseErrOnList,
   324  				check: func(t *testing.T, n *NVMe) {
   325  					mx := n.Collect()
   326  
   327  					assert.Equal(t, (map[string]int64)(nil), mx)
   328  				},
   329  			},
   330  		},
   331  		"fail if 'nvme smart-log' returns an error": {
   332  			{
   333  				prepare: prepareCaseErrOnSmartLog,
   334  				check: func(t *testing.T, n *NVMe) {
   335  					mx := n.Collect()
   336  
   337  					assert.Equal(t, (map[string]int64)(nil), mx)
   338  				},
   339  			},
   340  		},
   341  	}
   342  
   343  	for name, test := range tests {
   344  		t.Run(name, func(t *testing.T) {
   345  			n := New()
   346  
   347  			for i, step := range test {
   348  				t.Run(fmt.Sprintf("step[%d]", i), func(t *testing.T) {
   349  					step.prepare(n)
   350  					step.check(t, n)
   351  				})
   352  			}
   353  		})
   354  	}
   355  }
   356  
   357  func prepareCaseOK(n *NVMe) {
   358  	n.exec = &mockNVMeCLIExec{}
   359  }
   360  
   361  func prepareCaseStringValuesOK(n *NVMe) {
   362  	n.exec = &mockNVMeCLIExec{smartLogString: true}
   363  }
   364  
   365  func prepareCaseFloatValuesOK(n *NVMe) {
   366  	n.exec = &mockNVMeCLIExec{smartLogFloat: true}
   367  }
   368  
   369  func prepareCaseEmptyList(n *NVMe) {
   370  	n.exec = &mockNVMeCLIExec{emptyList: true}
   371  }
   372  
   373  func prepareCaseErrOnList(n *NVMe) {
   374  	n.exec = &mockNVMeCLIExec{errOnList: true}
   375  }
   376  
   377  func prepareCaseErrOnSmartLog(n *NVMe) {
   378  	n.exec = &mockNVMeCLIExec{errOnSmartLog: true}
   379  }
   380  
   381  type mockNVMeCLIExec struct {
   382  	errOnList      bool
   383  	errOnSmartLog  bool
   384  	emptyList      bool
   385  	smartLogString bool
   386  	smartLogFloat  bool
   387  }
   388  
   389  func (m *mockNVMeCLIExec) list() (*nvmeDeviceList, error) {
   390  	if m.errOnList {
   391  		return nil, errors.New("mock.list() error")
   392  	}
   393  
   394  	data := dataNVMeListJSON
   395  	if m.emptyList {
   396  		data = dataNVMeListEmptyJSON
   397  	}
   398  
   399  	var v nvmeDeviceList
   400  	if err := json.Unmarshal(data, &v); err != nil {
   401  		return nil, err
   402  	}
   403  
   404  	return &v, nil
   405  }
   406  
   407  func (m *mockNVMeCLIExec) smartLog(_ string) (*nvmeDeviceSmartLog, error) {
   408  	if m.errOnSmartLog {
   409  		return nil, errors.New("mock.smartLog() error")
   410  	}
   411  	if m.emptyList {
   412  		return nil, errors.New("mock.smartLog() no devices error")
   413  	}
   414  
   415  	data := dataNVMeSmartLogJSON
   416  	if m.smartLogString {
   417  		data = dataNVMeSmartLogStringJSON
   418  	}
   419  	if m.smartLogFloat {
   420  		data = dataNVMeSmartLogFloatJSON
   421  	}
   422  
   423  	var v nvmeDeviceSmartLog
   424  	if err := json.Unmarshal(data, &v); err != nil {
   425  		return nil, err
   426  	}
   427  
   428  	return &v, nil
   429  }