Update go to 1.25 (#875)

Closes #872

* update go to 1.25

* update deprecated gomock

* remove deprecated ioutil

* update (and fix) ci

* add golang lint (as warning)

* enable formatters + freeze golang version
This commit is contained in:
mcarbonne
2026-02-09 05:46:36 +01:00
committed by GitHub
parent c6323fb7ce
commit 6362512406
39 changed files with 460 additions and 1024 deletions
+4 -8
View File
@@ -21,7 +21,6 @@ jobs:
test-backend: test-backend:
name: Test Backend name: Test Backend
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: ghcr.io/packagrio/packagr:latest-golang
# Service containers to run with `build` (Required for end-to-end testing) # Service containers to run with `build` (Required for end-to-end testing)
services: services:
influxdb: influxdb:
@@ -38,13 +37,10 @@ jobs:
env: env:
STATIC: true STATIC: true
steps: steps:
- name: Git - name: Add influxdb to hosts
run: | run: echo "127.0.0.1 influxdb" | sudo tee -a /etc/hosts
apt-get update && apt-get install -y software-properties-common
add-apt-repository ppa:git-core/ppa && apt-get update && apt-get install -y git
git --version
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v6
- name: Test Backend - name: Test Backend
run: | run: |
make binary-clean binary-test-coverage make binary-clean binary-test-coverage
@@ -102,7 +98,7 @@ jobs:
uses: actions/checkout@v2 uses: actions/checkout@v2
- uses: actions/setup-go@v3 - uses: actions/setup-go@v3
with: with:
go-version: '^1.20.1' go-version: '^1.25'
- name: Build Binaries - name: Build Binaries
run: | run: |
make binary-clean binary-all make binary-clean binary-all
+21
View File
@@ -0,0 +1,21 @@
name: golangci-lint
on:
push:
pull_request:
permissions:
contents: read
jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: 1.25
- name: golangci-lint
uses: golangci/golangci-lint-action@v9
with:
args: --issues-exit-code=0
+1 -1
View File
@@ -97,7 +97,7 @@ jobs:
name: workspace name: workspace
- uses: actions/setup-go@v6 - uses: actions/setup-go@v6
with: with:
go-version: '1.20.1' # The Go version to download (if necessary) and use. go-version: '1.25' # The Go version to download (if necessary) and use.
- name: Build Binaries - name: Build Binaries
run: | run: |
make binary-clean binary-all make binary-clean binary-all
+11
View File
@@ -0,0 +1,11 @@
version: "2"
formatters:
enable:
- gofmt
- goimports
linters:
enable:
- bodyclose
settings:
errcheck:
check-blank: true
+1 -1
View File
@@ -149,7 +149,7 @@ Depending on the functionality you are adding, you may need to setup a developme
# Modifying the Scrutiny Backend Server (API) # Modifying the Scrutiny Backend Server (API)
1. install the [Go runtime](https://go.dev/doc/install) (v1.20+) 1. install the [Go runtime](https://go.dev/doc/install) (v1.25)
2. download the `scrutiny-web-frontend.tar.gz` for 2. download the `scrutiny-web-frontend.tar.gz` for
the [latest release](https://github.com/AnalogJ/scrutiny/releases/latest). Extract to a folder named `dist` the [latest release](https://github.com/AnalogJ/scrutiny/releases/latest). Extract to a folder named `dist`
3. create a `scrutiny.yaml` config file 3. create a `scrutiny.yaml` config file
+6
View File
@@ -1,5 +1,6 @@
.ONESHELL: # Applies to every targets in the file! .ONESHELL instructs make to invoke a single instance of the shell and provide it with the entire recipe, regardless of how many lines it contains. .ONESHELL: # Applies to every targets in the file! .ONESHELL instructs make to invoke a single instance of the shell and provide it with the entire recipe, regardless of how many lines it contains.
.SHELLFLAGS = -ec .SHELLFLAGS = -ec
export GOTOOLCHAIN=go1.25.5
######################################################################################################################## ########################################################################################################################
# Global Env Settings # Global Env Settings
@@ -66,6 +67,11 @@ binary-dep:
binary-test: binary-dep binary-test: binary-dep
go test -v $(STATIC_TAGS) ./... go test -v $(STATIC_TAGS) ./...
.PHONY: lint
lint:
GOTOOLCHAIN=go1.25.5 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.8.0
golangci-lint run ./...
.PHONY: binary-test-coverage .PHONY: binary-test-coverage
binary-test-coverage: binary-dep binary-test-coverage: binary-dep
go test -coverprofile=coverage.txt -covermode=atomic -v $(STATIC_TAGS) ./... go test -coverprofile=coverage.txt -covermode=atomic -v $(STATIC_TAGS) ./...
@@ -3,17 +3,18 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/analogj/scrutiny/collector/pkg/collector"
"github.com/analogj/scrutiny/collector/pkg/config"
"github.com/analogj/scrutiny/collector/pkg/errors"
"github.com/analogj/scrutiny/webapp/backend/pkg/version"
"github.com/sirupsen/logrus"
"io" "io"
"log" "log"
"os" "os"
"strings" "strings"
"time" "time"
"github.com/analogj/scrutiny/collector/pkg/collector"
"github.com/analogj/scrutiny/collector/pkg/config"
"github.com/analogj/scrutiny/collector/pkg/errors"
"github.com/analogj/scrutiny/webapp/backend/pkg/version"
"github.com/sirupsen/logrus"
utils "github.com/analogj/go-util/utils" utils "github.com/analogj/go-util/utils"
"github.com/fatih/color" "github.com/fatih/color"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
@@ -81,7 +82,7 @@ OPTIONS:
subtitle := collectorMetrics + utils.LeftPad2Len(versionInfo, " ", 65-len(collectorMetrics)) subtitle := collectorMetrics + utils.LeftPad2Len(versionInfo, " ", 65-len(collectorMetrics))
color.New(color.FgGreen).Fprintf(c.App.Writer, fmt.Sprintf(utils.StripIndent( color.New(color.FgGreen).Fprintf(c.App.Writer, utils.StripIndent(
` `
___ ___ ____ __ __ ____ ____ _ _ _ _ ___ ___ ____ __ __ ____ ____ _ _ _ _
/ __) / __)( _ \( )( )(_ _)(_ _)( \( )( \/ ) / __) / __)( _ \( )( )(_ _)(_ _)( \( )( \/ )
@@ -89,7 +90,7 @@ OPTIONS:
(___/ \___)(_)\_)(______) (__) (____)(_)\_) (__) (___/ \___)(_)\_)(______) (__) (____)(_)\_) (__)
%s %s
`), subtitle)) `), subtitle)
return nil return nil
}, },
@@ -2,14 +2,15 @@ package main
import ( import (
"fmt" "fmt"
"github.com/analogj/scrutiny/collector/pkg/collector"
"github.com/analogj/scrutiny/webapp/backend/pkg/version"
"github.com/sirupsen/logrus"
"io" "io"
"log" "log"
"os" "os"
"time" "time"
"github.com/analogj/scrutiny/collector/pkg/collector"
"github.com/analogj/scrutiny/webapp/backend/pkg/version"
"github.com/sirupsen/logrus"
utils "github.com/analogj/go-util/utils" utils "github.com/analogj/go-util/utils"
"github.com/fatih/color" "github.com/fatih/color"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
@@ -57,7 +58,7 @@ OPTIONS:
subtitle := collectorSelfTest + utils.LeftPad2Len(versionInfo, " ", 65-len(collectorSelfTest)) subtitle := collectorSelfTest + utils.LeftPad2Len(versionInfo, " ", 65-len(collectorSelfTest))
color.New(color.FgGreen).Fprintf(c.App.Writer, fmt.Sprintf(utils.StripIndent( color.New(color.FgGreen).Fprintf(c.App.Writer, utils.StripIndent(
` `
___ ___ ____ __ __ ____ ____ _ _ _ _ ___ ___ ____ __ __ ____ ____ _ _ _ _
/ __) / __)( _ \( )( )(_ _)(_ _)( \( )( \/ ) / __) / __)( _ \( )( )(_ _)(_ _)( \( )( \/ )
@@ -65,7 +66,7 @@ OPTIONS:
(___/ \___)(_)\_)(______) (__) (____)(_)\_) (__) (___/ \___)(_)\_)(______) (__) (____)(_)\_) (__)
%s %s
`), subtitle)) `), subtitle)
return nil return nil
}, },
+2 -12
View File
@@ -3,9 +3,10 @@ package collector
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"github.com/sirupsen/logrus"
"net/http" "net/http"
"time" "time"
"github.com/sirupsen/logrus"
) )
var httpClient = &http.Client{Timeout: 60 * time.Second} var httpClient = &http.Client{Timeout: 60 * time.Second}
@@ -14,17 +15,6 @@ type BaseCollector struct {
logger *logrus.Entry logger *logrus.Entry
} }
func (c *BaseCollector) getJson(url string, target interface{}) error {
r, err := httpClient.Get(url)
if err != nil {
return err
}
defer r.Body.Close()
return json.NewDecoder(r.Body).Decode(target)
}
func (c *BaseCollector) postJson(url string, body interface{}, target interface{}) error { func (c *BaseCollector) postJson(url string, body interface{}, target interface{}) error {
requestBody, err := json.Marshal(body) requestBody, err := json.Marshal(body)
if err != nil { if err != nil {
+3 -2
View File
@@ -3,11 +3,12 @@ package shell
import ( import (
"bytes" "bytes"
"errors" "errors"
"github.com/sirupsen/logrus"
"io" "io"
"os/exec" "os/exec"
"path" "path"
"strings" "strings"
"github.com/sirupsen/logrus"
) )
type localShell struct{} type localShell struct{}
@@ -36,7 +37,7 @@ func (s *localShell) Command(logger *logrus.Entry, cmdName string, cmdArgs []str
if workingDir != "" && path.IsAbs(workingDir) { if workingDir != "" && path.IsAbs(workingDir) {
cmd.Dir = workingDir cmd.Dir = workingDir
} else if workingDir != "" { } else if workingDir != "" {
return "", errors.New("Working Directory must be an absolute path") return "", errors.New("working directory must be an absolute path")
} }
err := cmd.Run() err := cmd.Run()
@@ -7,8 +7,8 @@ package mock_shell
import ( import (
reflect "reflect" reflect "reflect"
gomock "github.com/golang/mock/gomock"
logrus "github.com/sirupsen/logrus" logrus "github.com/sirupsen/logrus"
gomock "go.uber.org/mock/gomock"
) )
// MockInterface is a mock of Interface interface. // MockInterface is a mock of Interface interface.
+8 -7
View File
@@ -2,15 +2,16 @@ package config
import ( import (
"fmt" "fmt"
"github.com/analogj/go-util/utils"
"github.com/analogj/scrutiny/collector/pkg/errors"
"github.com/analogj/scrutiny/collector/pkg/models"
"github.com/mitchellh/mapstructure"
"github.com/spf13/viper"
"log" "log"
"os" "os"
"sort" "sort"
"strings" "strings"
"github.com/analogj/go-util/utils"
"github.com/analogj/scrutiny/collector/pkg/errors"
"github.com/analogj/scrutiny/collector/pkg/models"
"github.com/go-viper/mapstructure/v2"
"github.com/spf13/viper"
) )
// When initializing this class the following methods must be called: // When initializing this class the following methods must be called:
@@ -167,7 +168,7 @@ func (c *configuration) GetCommandMetricsInfoArgs(deviceName string) string {
overrides := c.GetDeviceOverrides() overrides := c.GetDeviceOverrides()
for _, deviceOverrides := range overrides { for _, deviceOverrides := range overrides {
if strings.ToLower(deviceName) == strings.ToLower(deviceOverrides.Device) { if strings.EqualFold(deviceName, deviceOverrides.Device) {
//found matching device //found matching device
if len(deviceOverrides.Commands.MetricsInfoArgs) > 0 { if len(deviceOverrides.Commands.MetricsInfoArgs) > 0 {
return deviceOverrides.Commands.MetricsInfoArgs return deviceOverrides.Commands.MetricsInfoArgs
@@ -183,7 +184,7 @@ func (c *configuration) GetCommandMetricsSmartArgs(deviceName string) string {
overrides := c.GetDeviceOverrides() overrides := c.GetDeviceOverrides()
for _, deviceOverrides := range overrides { for _, deviceOverrides := range overrides {
if strings.ToLower(deviceName) == strings.ToLower(deviceOverrides.Device) { if strings.EqualFold(deviceName, deviceOverrides.Device) {
//found matching device //found matching device
if len(deviceOverrides.Commands.MetricsSmartArgs) > 0 { if len(deviceOverrides.Commands.MetricsSmartArgs) > 0 {
return deviceOverrides.Commands.MetricsSmartArgs return deviceOverrides.Commands.MetricsSmartArgs
+1 -1
View File
@@ -8,8 +8,8 @@ import (
reflect "reflect" reflect "reflect"
models "github.com/analogj/scrutiny/collector/pkg/models" models "github.com/analogj/scrutiny/collector/pkg/models"
gomock "github.com/golang/mock/gomock"
viper "github.com/spf13/viper" viper "github.com/spf13/viper"
gomock "go.uber.org/mock/gomock"
) )
// MockInterface is a mock of Interface interface. // MockInterface is a mock of Interface interface.
+2 -2
View File
@@ -107,8 +107,8 @@ func (d *Detect) SmartCtlInfo(device *models.Device) error {
if len(device.WWN) == 0 { if len(device.WWN) == 0 {
// no WWN populated after WWN lookup and fallback. we need to throw an error // no WWN populated after WWN lookup and fallback. we need to throw an error
errMsg := fmt.Sprintf("no WWN (or fallback) populated for device: %s. Device will be registered, but no data will be published for this device. ", device.DeviceName) errMsg := fmt.Sprintf("no WWN (or fallback) populated for device: %s. Device will be registered, but no data will be published for this device. ", device.DeviceName)
d.Logger.Errorf(errMsg) d.Logger.Errorf("%v", errMsg)
return fmt.Errorf(errMsg) return fmt.Errorf("%v", errMsg)
} }
return nil return nil
+1 -12
View File
@@ -9,16 +9,15 @@ import (
mock_config "github.com/analogj/scrutiny/collector/pkg/config/mock" mock_config "github.com/analogj/scrutiny/collector/pkg/config/mock"
"github.com/analogj/scrutiny/collector/pkg/detect" "github.com/analogj/scrutiny/collector/pkg/detect"
"github.com/analogj/scrutiny/collector/pkg/models" "github.com/analogj/scrutiny/collector/pkg/models"
"github.com/golang/mock/gomock"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
) )
func TestDetect_SmartctlScan(t *testing.T) { func TestDetect_SmartctlScan(t *testing.T) {
// setup // setup
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("") fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("")
fakeConfig.EXPECT().GetDeviceOverrides().AnyTimes().Return([]models.ScanOverride{}) fakeConfig.EXPECT().GetDeviceOverrides().AnyTimes().Return([]models.ScanOverride{})
@@ -48,7 +47,6 @@ func TestDetect_SmartctlScan(t *testing.T) {
func TestDetect_SmartctlScan_Megaraid(t *testing.T) { func TestDetect_SmartctlScan_Megaraid(t *testing.T) {
// setup // setup
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("") fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("")
fakeConfig.EXPECT().GetDeviceOverrides().AnyTimes().Return([]models.ScanOverride{}) fakeConfig.EXPECT().GetDeviceOverrides().AnyTimes().Return([]models.ScanOverride{})
@@ -81,7 +79,6 @@ func TestDetect_SmartctlScan_Megaraid(t *testing.T) {
func TestDetect_SmartctlScan_Nvme(t *testing.T) { func TestDetect_SmartctlScan_Nvme(t *testing.T) {
// setup // setup
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("") fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("")
fakeConfig.EXPECT().GetDeviceOverrides().AnyTimes().Return([]models.ScanOverride{}) fakeConfig.EXPECT().GetDeviceOverrides().AnyTimes().Return([]models.ScanOverride{})
@@ -113,7 +110,6 @@ func TestDetect_SmartctlScan_Nvme(t *testing.T) {
func TestDetect_TransformDetectedDevices_Empty(t *testing.T) { func TestDetect_TransformDetectedDevices_Empty(t *testing.T) {
// setup // setup
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("") fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("")
fakeConfig.EXPECT().GetDeviceOverrides().AnyTimes().Return([]models.ScanOverride{}) fakeConfig.EXPECT().GetDeviceOverrides().AnyTimes().Return([]models.ScanOverride{})
@@ -147,7 +143,6 @@ func TestDetect_TransformDetectedDevices_Empty(t *testing.T) {
func TestDetect_TransformDetectedDevices_Ignore(t *testing.T) { func TestDetect_TransformDetectedDevices_Ignore(t *testing.T) {
// setup // setup
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("") fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("")
fakeConfig.EXPECT().GetDeviceOverrides().AnyTimes().Return([]models.ScanOverride{{Device: "/dev/sda", DeviceType: nil, Ignore: true}}) fakeConfig.EXPECT().GetDeviceOverrides().AnyTimes().Return([]models.ScanOverride{{Device: "/dev/sda", DeviceType: nil, Ignore: true}})
@@ -180,7 +175,6 @@ func TestDetect_TransformDetectedDevices_Ignore(t *testing.T) {
func TestDetect_TransformDetectedDevices_Raid(t *testing.T) { func TestDetect_TransformDetectedDevices_Raid(t *testing.T) {
// setup // setup
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("") fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("")
fakeConfig.EXPECT().GetString("commands.metrics_smartctl_bin").AnyTimes().Return("smartctl") fakeConfig.EXPECT().GetString("commands.metrics_smartctl_bin").AnyTimes().Return("smartctl")
@@ -223,7 +217,6 @@ func TestDetect_TransformDetectedDevices_Raid(t *testing.T) {
func TestDetect_TransformDetectedDevices_Simple(t *testing.T) { func TestDetect_TransformDetectedDevices_Simple(t *testing.T) {
// setup // setup
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("") fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("")
fakeConfig.EXPECT().GetString("commands.metrics_smartctl_bin").AnyTimes().Return("smartctl") fakeConfig.EXPECT().GetString("commands.metrics_smartctl_bin").AnyTimes().Return("smartctl")
@@ -257,7 +250,6 @@ func TestDetect_TransformDetectedDevices_Simple(t *testing.T) {
func TestDetect_TransformDetectedDevices_WithoutDeviceTypeOverride(t *testing.T) { func TestDetect_TransformDetectedDevices_WithoutDeviceTypeOverride(t *testing.T) {
// setup // setup
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("") fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("")
fakeConfig.EXPECT().GetString("commands.metrics_smartctl_bin").AnyTimes().Return("smartctl") fakeConfig.EXPECT().GetString("commands.metrics_smartctl_bin").AnyTimes().Return("smartctl")
@@ -290,7 +282,6 @@ func TestDetect_TransformDetectedDevices_WithoutDeviceTypeOverride(t *testing.T)
func TestDetect_TransformDetectedDevices_WhenDeviceNotDetected(t *testing.T) { func TestDetect_TransformDetectedDevices_WhenDeviceNotDetected(t *testing.T) {
// setup // setup
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("") fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("")
fakeConfig.EXPECT().GetString("commands.metrics_smartctl_bin").AnyTimes().Return("smartctl") fakeConfig.EXPECT().GetString("commands.metrics_smartctl_bin").AnyTimes().Return("smartctl")
@@ -312,7 +303,6 @@ func TestDetect_TransformDetectedDevices_WhenDeviceNotDetected(t *testing.T) {
func TestDetect_TransformDetectedDevices_AllowListFilters(t *testing.T) { func TestDetect_TransformDetectedDevices_AllowListFilters(t *testing.T) {
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("") fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("")
@@ -353,7 +343,6 @@ func TestDetect_TransformDetectedDevices_AllowListFilters(t *testing.T) {
func TestDetect_SmartCtlInfo(t *testing.T) { func TestDetect_SmartCtlInfo(t *testing.T) {
t.Run("should report nvme info", func(t *testing.T) { t.Run("should report nvme info", func(t *testing.T) {
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
defer ctrl.Finish()
const ( const (
someArgs = "--info --json" someArgs = "--info --json"
+8 -9
View File
@@ -2,12 +2,13 @@ package detect
import ( import (
"fmt" "fmt"
"os"
"path/filepath"
"strings"
"github.com/analogj/scrutiny/collector/pkg/common/shell" "github.com/analogj/scrutiny/collector/pkg/common/shell"
"github.com/analogj/scrutiny/collector/pkg/models" "github.com/analogj/scrutiny/collector/pkg/models"
"github.com/jaypipes/ghw" "github.com/jaypipes/ghw"
"io/ioutil"
"path/filepath"
"strings"
) )
func DevicePrefix() string { func DevicePrefix() string {
@@ -23,7 +24,7 @@ func (d *Detect) Start() ([]models.Device, error) {
} }
//inflate device info for detected devices. //inflate device info for detected devices.
for ndx, _ := range detectedDevices { for ndx := range detectedDevices {
d.SmartCtlInfo(&detectedDevices[ndx]) //ignore errors. d.SmartCtlInfo(&detectedDevices[ndx]) //ignore errors.
populateUdevInfo(&detectedDevices[ndx]) //ignore errors. populateUdevInfo(&detectedDevices[ndx]) //ignore errors.
} }
@@ -31,7 +32,7 @@ func (d *Detect) Start() ([]models.Device, error) {
return detectedDevices, nil return detectedDevices, nil
} }
//WWN values NVMe and SCSI // WWN values NVMe and SCSI
func (d *Detect) wwnFallback(detectedDevice *models.Device) { func (d *Detect) wwnFallback(detectedDevice *models.Device) {
block, err := ghw.Block() block, err := ghw.Block()
if err == nil { if err == nil {
@@ -61,7 +62,7 @@ func (d *Detect) wwnFallback(detectedDevice *models.Device) {
func populateUdevInfo(detectedDevice *models.Device) error { func populateUdevInfo(detectedDevice *models.Device) error {
// Get device major:minor numbers // Get device major:minor numbers
// `cat /sys/class/block/sda/dev` // `cat /sys/class/block/sda/dev`
devNo, err := ioutil.ReadFile(filepath.Join("/sys/class/block/", detectedDevice.DeviceName, "dev")) devNo, err := os.ReadFile(filepath.Join("/sys/class/block/", detectedDevice.DeviceName, "dev"))
if err != nil { if err != nil {
return err return err
} }
@@ -69,7 +70,7 @@ func populateUdevInfo(detectedDevice *models.Device) error {
// Look up block device in udev runtime database // Look up block device in udev runtime database
// `cat /run/udev/data/b8:0` // `cat /run/udev/data/b8:0`
udevID := "b" + strings.TrimSpace(string(devNo)) udevID := "b" + strings.TrimSpace(string(devNo))
udevBytes, err := ioutil.ReadFile(filepath.Join("/run/udev/data/", udevID)) udevBytes, err := os.ReadFile(filepath.Join("/run/udev/data/", udevID))
if err != nil { if err != nil {
return err return err
} }
@@ -97,7 +98,5 @@ func populateUdevInfo(detectedDevice *models.Device) error {
detectedDevice.DeviceSerialID = fmt.Sprintf("%s-%s", udevInfo["ID_BUS"], deviceSerialID) detectedDevice.DeviceSerialID = fmt.Sprintf("%s-%s", udevInfo["ID_BUS"], deviceSerialID)
} }
return nil return nil
} }
+3 -4
View File
@@ -1,10 +1,10 @@
package detect_test package detect_test
import ( import (
"fmt" "testing"
"github.com/analogj/scrutiny/collector/pkg/detect" "github.com/analogj/scrutiny/collector/pkg/detect"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"testing"
) )
func TestWwn_FromStringTable(t *testing.T) { func TestWwn_FromStringTable(t *testing.T) {
@@ -25,8 +25,7 @@ func TestWwn_FromStringTable(t *testing.T) {
} }
//test //test
for _, tt := range tests { for _, tt := range tests {
testname := fmt.Sprintf("%s", tt.wwnStr) t.Run(tt.wwnStr, func(t *testing.T) {
t.Run(testname, func(t *testing.T) {
str := tt.wwn.ToString() str := tt.wwn.ToString()
require.Equal(t, tt.wwnStr, str) require.Equal(t, tt.wwnStr, str)
}) })
+1 -1
View File
@@ -12,7 +12,7 @@ RUN make binary-frontend
######## Build the backend ######## Build the backend
FROM golang:1.20-bookworm as backendbuild FROM golang:1.25-bookworm as backendbuild
WORKDIR /go/src/github.com/analogj/scrutiny WORKDIR /go/src/github.com/analogj/scrutiny
COPY --link . /go/src/github.com/analogj/scrutiny COPY --link . /go/src/github.com/analogj/scrutiny
+1 -1
View File
@@ -4,7 +4,7 @@
######## ########
FROM golang:1.20-bookworm as backendbuild FROM golang:1.25-bookworm as backendbuild
WORKDIR /go/src/github.com/analogj/scrutiny WORKDIR /go/src/github.com/analogj/scrutiny
+1 -1
View File
@@ -11,7 +11,7 @@ COPY --link . /go/src/github.com/analogj/scrutiny
RUN make binary-frontend RUN make binary-frontend
######## Build the backend ######## Build the backend
FROM golang:1.20-bookworm as backendbuild FROM golang:1.25-bookworm as backendbuild
WORKDIR /go/src/github.com/analogj/scrutiny WORKDIR /go/src/github.com/analogj/scrutiny
COPY --link . /go/src/github.com/analogj/scrutiny COPY --link . /go/src/github.com/analogj/scrutiny
+73 -61
View File
@@ -1,81 +1,93 @@
module github.com/analogj/scrutiny module github.com/analogj/scrutiny
go 1.20 go 1.25
require ( require (
github.com/analogj/go-util v0.0.0-20190301173314-5295e364eb14 github.com/analogj/go-util v0.0.0-20210417161720-39b497cca03b
github.com/containrrr/shoutrrr v0.8.0 github.com/containrrr/shoutrrr v0.8.0
github.com/fatih/color v1.15.0 github.com/fatih/color v1.18.0
github.com/gin-gonic/gin v1.6.3 github.com/gin-gonic/gin v1.11.0
github.com/glebarez/sqlite v1.4.5 github.com/glebarez/sqlite v1.11.0
github.com/go-gormigrate/gormigrate/v2 v2.0.0 github.com/go-gormigrate/gormigrate/v2 v2.1.5
github.com/golang/mock v1.6.0 github.com/go-viper/mapstructure/v2 v2.5.0
github.com/influxdata/influxdb-client-go/v2 v2.9.0 github.com/influxdata/influxdb-client-go/v2 v2.14.0
github.com/jaypipes/ghw v0.6.1 github.com/jaypipes/ghw v0.21.2
github.com/mitchellh/mapstructure v1.5.0 github.com/samber/lo v1.52.0
github.com/samber/lo v1.25.0 github.com/sirupsen/logrus v1.9.4
github.com/sirupsen/logrus v1.6.0 github.com/spf13/viper v1.21.0
github.com/spf13/viper v1.15.0 github.com/stretchr/testify v1.11.1
github.com/stretchr/testify v1.8.1 github.com/urfave/cli/v2 v2.27.7
github.com/urfave/cli/v2 v2.2.0 go.uber.org/mock v0.6.0
golang.org/x/sync v0.1.0 golang.org/x/sync v0.19.0
gorm.io/gorm v1.23.5 gorm.io/gorm v1.31.1
) )
require ( require (
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/bytedance/gopkg v0.1.3 // indirect
github.com/bytedance/sonic v1.15.0 // indirect
github.com/bytedance/sonic/loader v0.5.0 // indirect
github.com/cloudwego/base64x v0.1.6 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/deepmap/oapi-codegen v1.8.2 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/ghodss/yaml v1.0.0 // indirect github.com/gabriel-vasile/mimetype v1.4.13 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v1.1.0 // indirect
github.com/glebarez/go-sqlite v1.17.2 // indirect github.com/glebarez/go-sqlite v1.22.0 // indirect
github.com/go-ole/go-ole v1.2.4 // indirect github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-playground/locales v0.13.0 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.17.0 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.2.0 // indirect github.com/go-playground/validator/v10 v10.30.1 // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/goccy/go-json v0.10.5 // indirect
github.com/google/uuid v1.3.0 // indirect github.com/goccy/go-yaml v1.19.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/golang/protobuf v1.5.4 // indirect
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/jaypipes/pcidb v0.5.0 // indirect github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf // indirect
github.com/jaypipes/pcidb v1.1.1 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.4 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/kvz/logstreamer v0.0.0-20201023134116-02d20f4338f5 // indirect github.com/kvz/logstreamer v0.0.0-20221024075423-bf5cfbd32e39 // indirect
github.com/leodido/go-urn v1.2.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-isatty v0.0.18 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/oapi-codegen/runtime v1.1.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/quic-go/qpack v0.6.0 // indirect
github.com/quic-go/quic-go v0.59.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/spf13/afero v1.9.3 // indirect github.com/sagikazarmark/locafero v0.12.0 // indirect
github.com/spf13/cast v1.5.0 // indirect github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.10 // indirect
github.com/subosito/gotenv v1.4.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect
github.com/ugorji/go/codec v1.1.7 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
golang.org/x/crypto v0.1.0 // indirect github.com/ugorji/go/codec v1.3.1 // indirect
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 // indirect
golang.org/x/net v0.8.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect
golang.org/x/sys v0.7.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/term v0.6.0 // indirect golang.org/x/arch v0.23.0 // indirect
golang.org/x/text v0.8.0 // indirect golang.org/x/crypto v0.47.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect golang.org/x/exp v0.0.0-20260112195511-716be5621a96 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect golang.org/x/net v0.49.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/term v0.39.0 // indirect
golang.org/x/text v0.33.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
howett.net/plist v0.0.0-20181124034731-591f970eefbb // indirect howett.net/plist v1.0.2-0.20250314012144-ee69052608d9 // indirect
modernc.org/libc v1.16.8 // indirect modernc.org/libc v1.67.7 // indirect
modernc.org/mathutil v1.4.1 // indirect modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.1.1 // indirect modernc.org/memory v1.11.0 // indirect
modernc.org/sqlite v1.17.2 // indirect modernc.org/sqlite v1.44.3 // indirect
) )
+206 -772
View File
File diff suppressed because it is too large Load Diff
+7 -6
View File
@@ -3,15 +3,16 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"log"
"os"
"time"
"github.com/analogj/scrutiny/webapp/backend/pkg/config" "github.com/analogj/scrutiny/webapp/backend/pkg/config"
"github.com/analogj/scrutiny/webapp/backend/pkg/errors" "github.com/analogj/scrutiny/webapp/backend/pkg/errors"
"github.com/analogj/scrutiny/webapp/backend/pkg/version" "github.com/analogj/scrutiny/webapp/backend/pkg/version"
"github.com/analogj/scrutiny/webapp/backend/pkg/web" "github.com/analogj/scrutiny/webapp/backend/pkg/web"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"io"
"log"
"os"
"time"
utils "github.com/analogj/go-util/utils" utils "github.com/analogj/go-util/utils"
"github.com/fatih/color" "github.com/fatih/color"
@@ -81,7 +82,7 @@ OPTIONS:
subtitle := scrutiny + utils.LeftPad2Len(versionInfo, " ", 65-len(scrutiny)) subtitle := scrutiny + utils.LeftPad2Len(versionInfo, " ", 65-len(scrutiny))
color.New(color.FgGreen).Fprintf(c.App.Writer, fmt.Sprintf(utils.StripIndent( color.New(color.FgGreen).Fprintf(c.App.Writer, utils.StripIndent(
` `
___ ___ ____ __ __ ____ ____ _ _ _ _ ___ ___ ____ __ __ ____ ____ _ _ _ _
/ __) / __)( _ \( )( )(_ _)(_ _)( \( )( \/ ) / __) / __)( _ \( )( )(_ _)(_ _)( \( )( \/ )
@@ -89,7 +90,7 @@ OPTIONS:
(___/ \___)(_)\_)(______) (__) (____)(_)\_) (__) (___/ \___)(_)\_)(______) (__) (____)(_)\_) (__)
%s %s
`), subtitle)) `), subtitle)
return nil return nil
}, },
@@ -8,8 +8,8 @@ import (
reflect "reflect" reflect "reflect"
config "github.com/analogj/scrutiny/webapp/backend/pkg/config" config "github.com/analogj/scrutiny/webapp/backend/pkg/config"
gomock "github.com/golang/mock/gomock"
viper "github.com/spf13/viper" viper "github.com/spf13/viper"
gomock "go.uber.org/mock/gomock"
) )
// MockInterface is a mock of Interface interface. // MockInterface is a mock of Interface interface.
@@ -12,7 +12,7 @@ import (
models "github.com/analogj/scrutiny/webapp/backend/pkg/models" models "github.com/analogj/scrutiny/webapp/backend/pkg/models"
collector "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" collector "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector"
measurements "github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements" measurements "github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements"
gomock "github.com/golang/mock/gomock" gomock "go.uber.org/mock/gomock"
) )
// MockDeviceRepo is a mock of DeviceRepo interface. // MockDeviceRepo is a mock of DeviceRepo interface.
@@ -5,6 +5,11 @@ import (
"crypto/tls" "crypto/tls"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"net/http"
"net/url"
"time"
"github.com/analogj/scrutiny/webapp/backend/pkg/config" "github.com/analogj/scrutiny/webapp/backend/pkg/config"
"github.com/analogj/scrutiny/webapp/backend/pkg/models" "github.com/analogj/scrutiny/webapp/backend/pkg/models"
"github.com/glebarez/sqlite" "github.com/glebarez/sqlite"
@@ -13,10 +18,6 @@ import (
"github.com/influxdata/influxdb-client-go/v2/domain" "github.com/influxdata/influxdb-client-go/v2/domain"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"gorm.io/gorm" "gorm.io/gorm"
"io/ioutil"
"net/http"
"net/url"
"time"
) )
const ( const (
@@ -82,7 +83,7 @@ func NewScrutinyRepository(appConfig config.Interface, globalLogger logrus.Field
DisableForeignKeyConstraintWhenMigrating: true, DisableForeignKeyConstraintWhenMigrating: true,
}) })
if err != nil { if err != nil {
return nil, fmt.Errorf("Failed to connect to database! - %v", err) return nil, fmt.Errorf("failed to connect to database! - %v", err)
} }
globalLogger.Infof("Successfully connected to scrutiny sqlite db: %s\n", appConfig.GetString("web.database.location")) globalLogger.Infof("Successfully connected to scrutiny sqlite db: %s\n", appConfig.GetString("web.database.location"))
@@ -146,7 +147,7 @@ func NewScrutinyRepository(appConfig config.Interface, globalLogger logrus.Field
taskAPI := client.TasksAPI() taskAPI := client.TasksAPI()
if writeAPI == nil || queryAPI == nil || taskAPI == nil { if writeAPI == nil || queryAPI == nil || taskAPI == nil {
return nil, fmt.Errorf("Failed to connect to influxdb!") return nil, fmt.Errorf("failed to connect to influxdb")
} }
deviceRepo := scrutinyRepository{ deviceRepo := scrutinyRepository{
@@ -244,7 +245,7 @@ func InfluxSetupComplete(influxEndpoint string, tlsConfig *tls.Config) (bool, er
return false, err return false, err
} }
body, err := ioutil.ReadAll(res.Body) body, err := io.ReadAll(res.Body)
if err != nil { if err != nil {
return false, err return false, err
} }
@@ -3,11 +3,12 @@ package database
import ( import (
"context" "context"
"fmt" "fmt"
"time"
"github.com/analogj/scrutiny/webapp/backend/pkg" "github.com/analogj/scrutiny/webapp/backend/pkg"
"github.com/analogj/scrutiny/webapp/backend/pkg/models" "github.com/analogj/scrutiny/webapp/backend/pkg/models"
"github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector"
"gorm.io/gorm/clause" "gorm.io/gorm/clause"
"time"
) )
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -31,7 +32,7 @@ func (sr *scrutinyRepository) GetDevices(ctx context.Context) ([]models.Device,
//Get a list of all the active devices. //Get a list of all the active devices.
devices := []models.Device{} devices := []models.Device{}
if err := sr.gormClient.WithContext(ctx).Find(&devices).Error; err != nil { if err := sr.gormClient.WithContext(ctx).Find(&devices).Error; err != nil {
return nil, fmt.Errorf("Could not get device summary from DB: %v", err) return nil, fmt.Errorf("could not get device summary from DB: %v", err)
} }
return devices, nil return devices, nil
} }
@@ -40,7 +41,7 @@ func (sr *scrutinyRepository) GetDevices(ctx context.Context) ([]models.Device,
func (sr *scrutinyRepository) UpdateDevice(ctx context.Context, wwn string, collectorSmartData collector.SmartInfo) (models.Device, error) { func (sr *scrutinyRepository) UpdateDevice(ctx context.Context, wwn string, collectorSmartData collector.SmartInfo) (models.Device, error) {
var device models.Device var device models.Device
if err := sr.gormClient.WithContext(ctx).Where("wwn = ?", wwn).First(&device).Error; err != nil { if err := sr.gormClient.WithContext(ctx).Where("wwn = ?", wwn).First(&device).Error; err != nil {
return device, fmt.Errorf("Could not get device from DB: %v", err) return device, fmt.Errorf("could not get device from DB: %v", err)
} }
//TODO catch GormClient err //TODO catch GormClient err
@@ -55,7 +56,7 @@ func (sr *scrutinyRepository) UpdateDevice(ctx context.Context, wwn string, coll
func (sr *scrutinyRepository) UpdateDeviceStatus(ctx context.Context, wwn string, status pkg.DeviceStatus) (models.Device, error) { func (sr *scrutinyRepository) UpdateDeviceStatus(ctx context.Context, wwn string, status pkg.DeviceStatus) (models.Device, error) {
var device models.Device var device models.Device
if err := sr.gormClient.WithContext(ctx).Where("wwn = ?", wwn).First(&device).Error; err != nil { if err := sr.gormClient.WithContext(ctx).Where("wwn = ?", wwn).First(&device).Error; err != nil {
return device, fmt.Errorf("Could not get device from DB: %v", err) return device, fmt.Errorf("could not get device from DB: %v", err)
} }
device.DeviceStatus = pkg.DeviceStatusSet(device.DeviceStatus, status) device.DeviceStatus = pkg.DeviceStatusSet(device.DeviceStatus, status)
@@ -78,7 +79,7 @@ func (sr *scrutinyRepository) GetDeviceDetails(ctx context.Context, wwn string)
func (sr *scrutinyRepository) UpdateDeviceArchived(ctx context.Context, wwn string, archived bool) error { func (sr *scrutinyRepository) UpdateDeviceArchived(ctx context.Context, wwn string, archived bool) error {
var device models.Device var device models.Device
if err := sr.gormClient.WithContext(ctx).Where("wwn = ?", wwn).First(&device).Error; err != nil { if err := sr.gormClient.WithContext(ctx).Where("wwn = ?", wwn).First(&device).Error; err != nil {
return fmt.Errorf("Could not get device from DB: %v", err) return fmt.Errorf("could not get device from DB: %v", err)
} }
return sr.gormClient.Model(&device).Where("wwn = ?", wwn).Update("archived", archived).Error return sr.gormClient.Model(&device).Where("wwn = ?", wwn).Update("archived", archived).Error
@@ -647,7 +647,7 @@ func m20201107210306_FromPreInfluxDBSmartResultsCreatePostInfluxDBSmartResults(d
} }
postDeviceSmartData.ProcessScsiSmartInfo(postScsiGrownDefectList, postScsiErrorCounterLog) postDeviceSmartData.ProcessScsiSmartInfo(postScsiGrownDefectList, postScsiErrorCounterLog)
} else { } else {
return fmt.Errorf("Unknown device protocol: %s", preDevice.DeviceProtocol), postDeviceSmartData return fmt.Errorf("unknown device protocol: %s", preDevice.DeviceProtocol), postDeviceSmartData
} }
return nil, postDeviceSmartData return nil, postDeviceSmartData
@@ -3,17 +3,18 @@ package database
import ( import (
"context" "context"
"fmt" "fmt"
"strings"
"github.com/analogj/scrutiny/webapp/backend/pkg/config" "github.com/analogj/scrutiny/webapp/backend/pkg/config"
"github.com/analogj/scrutiny/webapp/backend/pkg/models" "github.com/analogj/scrutiny/webapp/backend/pkg/models"
"github.com/mitchellh/mapstructure" "github.com/go-viper/mapstructure/v2"
"strings"
) )
// LoadSettings will retrieve settings from the database, store them in the AppConfig object, and return a Settings struct // LoadSettings will retrieve settings from the database, store them in the AppConfig object, and return a Settings struct
func (sr *scrutinyRepository) LoadSettings(ctx context.Context) (*models.Settings, error) { func (sr *scrutinyRepository) LoadSettings(ctx context.Context) (*models.Settings, error) {
settingsEntries := []models.SettingEntry{} settingsEntries := []models.SettingEntry{}
if err := sr.gormClient.WithContext(ctx).Find(&settingsEntries).Error; err != nil { if err := sr.gormClient.WithContext(ctx).Find(&settingsEntries).Error; err != nil {
return nil, fmt.Errorf("Could not get settings from DB: %v", err) return nil, fmt.Errorf("could not get settings from DB: %v", err)
} }
// store retrieved settings in the AppConfig obj // store retrieved settings in the AppConfig obj
@@ -58,7 +59,7 @@ func (sr *scrutinyRepository) SaveSettings(ctx context.Context, settings models.
//retrieve current settings from the database //retrieve current settings from the database
settingsEntries := []models.SettingEntry{} settingsEntries := []models.SettingEntry{}
if err := sr.gormClient.WithContext(ctx).Find(&settingsEntries).Error; err != nil { if err := sr.gormClient.WithContext(ctx).Find(&settingsEntries).Error; err != nil {
return fmt.Errorf("Could not get settings from DB: %v", err) return fmt.Errorf("could not get settings from DB: %v", err)
} }
//update settingsEntries //update settingsEntries
@@ -1,10 +1,11 @@
package database package database
import ( import (
mock_config "github.com/analogj/scrutiny/webapp/backend/pkg/config/mock"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
"testing" "testing"
mock_config "github.com/analogj/scrutiny/webapp/backend/pkg/config/mock"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
) )
func Test_DownsampleScript_Weekly(t *testing.T) { func Test_DownsampleScript_Weekly(t *testing.T) {
@@ -12,7 +13,6 @@ func Test_DownsampleScript_Weekly(t *testing.T) {
//setup //setup
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes()
@@ -64,7 +64,6 @@ func Test_DownsampleScript_Monthly(t *testing.T) {
//setup //setup
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes()
@@ -116,7 +115,6 @@ func Test_DownsampleScript_Yearly(t *testing.T) {
//setup //setup
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes()
@@ -1,10 +1,11 @@
package database package database
import ( import (
mock_config "github.com/analogj/scrutiny/webapp/backend/pkg/config/mock"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
"testing" "testing"
mock_config "github.com/analogj/scrutiny/webapp/backend/pkg/config/mock"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
) )
func Test_aggregateTempQuery_Week(t *testing.T) { func Test_aggregateTempQuery_Week(t *testing.T) {
@@ -12,7 +13,6 @@ func Test_aggregateTempQuery_Week(t *testing.T) {
//setup //setup
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes()
@@ -45,7 +45,6 @@ func Test_aggregateTempQuery_Month(t *testing.T) {
//setup //setup
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes()
@@ -86,7 +85,6 @@ func Test_aggregateTempQuery_Year(t *testing.T) {
//setup //setup
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes()
@@ -134,7 +132,6 @@ func Test_aggregateTempQuery_Forever(t *testing.T) {
//setup //setup
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes()
@@ -2,13 +2,14 @@ package measurements
import ( import (
"fmt" "fmt"
"github.com/analogj/scrutiny/webapp/backend/pkg"
"github.com/analogj/scrutiny/webapp/backend/pkg/models/collector"
"github.com/analogj/scrutiny/webapp/backend/pkg/thresholds"
"log" "log"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/analogj/scrutiny/webapp/backend/pkg"
"github.com/analogj/scrutiny/webapp/backend/pkg/models/collector"
"github.com/analogj/scrutiny/webapp/backend/pkg/thresholds"
) )
type Smart struct { type Smart struct {
@@ -102,7 +103,7 @@ func NewSmartFromInfluxDB(attrs map[string]interface{}) (*Smart, error) {
} else if sm.DeviceProtocol == pkg.DeviceProtocolScsi { } else if sm.DeviceProtocol == pkg.DeviceProtocolScsi {
sm.Attributes[attributeId] = &SmartScsiAttribute{} sm.Attributes[attributeId] = &SmartScsiAttribute{}
} else { } else {
return nil, fmt.Errorf("Unknown Device Protocol: %s", sm.DeviceProtocol) return nil, fmt.Errorf("unknown Device Protocol: %s", sm.DeviceProtocol)
} }
} }
@@ -116,7 +117,7 @@ func NewSmartFromInfluxDB(attrs map[string]interface{}) (*Smart, error) {
return &sm, nil return &sm, nil
} }
//Parse Collector SMART data results and create Smart object (and associated SmartAtaAttribute entries) // Parse Collector SMART data results and create Smart object (and associated SmartAtaAttribute entries)
func (sm *Smart) FromCollectorSmartInfo(wwn string, info collector.SmartInfo) error { func (sm *Smart) FromCollectorSmartInfo(wwn string, info collector.SmartInfo) error {
sm.DeviceWWN = wwn sm.DeviceWWN = wwn
sm.Date = time.Unix(info.LocalTime.TimeT, 0) sm.Date = time.Unix(info.LocalTime.TimeT, 0)
@@ -143,7 +144,7 @@ func (sm *Smart) FromCollectorSmartInfo(wwn string, info collector.SmartInfo) er
return nil return nil
} }
//generate SmartAtaAttribute entries from Scrutiny Collector Smart data. // generate SmartAtaAttribute entries from Scrutiny Collector Smart data.
func (sm *Smart) ProcessAtaSmartInfo(tableItems []collector.AtaSmartAttributesTableItem) { func (sm *Smart) ProcessAtaSmartInfo(tableItems []collector.AtaSmartAttributesTableItem) {
for _, collectorAttr := range tableItems { for _, collectorAttr := range tableItems {
attrModel := SmartAtaAttribute{ attrModel := SmartAtaAttribute{
@@ -171,7 +172,7 @@ func (sm *Smart) ProcessAtaSmartInfo(tableItems []collector.AtaSmartAttributesTa
} }
} }
//generate SmartNvmeAttribute entries from Scrutiny Collector Smart data. // generate SmartNvmeAttribute entries from Scrutiny Collector Smart data.
func (sm *Smart) ProcessNvmeSmartInfo(nvmeSmartHealthInformationLog collector.NvmeSmartHealthInformationLog) { func (sm *Smart) ProcessNvmeSmartInfo(nvmeSmartHealthInformationLog collector.NvmeSmartHealthInformationLog) {
sm.Attributes = map[string]SmartAttribute{ sm.Attributes = map[string]SmartAttribute{
@@ -201,7 +202,7 @@ func (sm *Smart) ProcessNvmeSmartInfo(nvmeSmartHealthInformationLog collector.Nv
} }
} }
//generate SmartScsiAttribute entries from Scrutiny Collector Smart data. // generate SmartScsiAttribute entries from Scrutiny Collector Smart data.
func (sm *Smart) ProcessScsiSmartInfo(defectGrownList int64, scsiErrorCounterLog collector.ScsiErrorCounterLog) { func (sm *Smart) ProcessScsiSmartInfo(defectGrownList int64, scsiErrorCounterLog collector.ScsiErrorCounterLog) {
sm.Attributes = map[string]SmartAttribute{ sm.Attributes = map[string]SmartAttribute{
"scsi_grown_defect_list": (&SmartScsiAttribute{AttributeId: "scsi_grown_defect_list", Value: defectGrownList, Threshold: 0}).PopulateAttributeStatus(), "scsi_grown_defect_list": (&SmartScsiAttribute{AttributeId: "scsi_grown_defect_list", Value: defectGrownList, Threshold: 0}).PopulateAttributeStatus(),
@@ -91,7 +91,7 @@ func (sa *SmartAtaAttribute) Inflate(key string, val interface{}) {
} }
} }
//populate attribute status, using SMART Thresholds & Observed Metadata // populate attribute status, using SMART Thresholds & Observed Metadata
// Chainable // Chainable
func (sa *SmartAtaAttribute) PopulateAttributeStatus() *SmartAtaAttribute { func (sa *SmartAtaAttribute) PopulateAttributeStatus() *SmartAtaAttribute {
if strings.ToUpper(sa.WhenFailed) == pkg.AttributeWhenFailedFailingNow { if strings.ToUpper(sa.WhenFailed) == pkg.AttributeWhenFailedFailingNow {
@@ -165,6 +165,4 @@ func (sa *SmartAtaAttribute) ValidateThreshold(smartMetadata thresholds.AtaAttri
sa.Status = pkg.AttributeStatusSet(sa.Status, pkg.AttributeStatusWarningScrutiny) sa.Status = pkg.AttributeStatusSet(sa.Status, pkg.AttributeStatusWarningScrutiny)
sa.StatusReason = "Could not determine Observed Failure Rate for Critical Attribute" sa.StatusReason = "Could not determine Observed Failure Rate for Critical Attribute"
} }
return
} }
@@ -2,14 +2,15 @@ package measurements_test
import ( import (
"encoding/json" "encoding/json"
"io"
"os"
"testing"
"time"
"github.com/analogj/scrutiny/webapp/backend/pkg" "github.com/analogj/scrutiny/webapp/backend/pkg"
"github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector"
"github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements" "github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"io/ioutil"
"os"
"testing"
"time"
) )
func TestSmart_Flatten(t *testing.T) { func TestSmart_Flatten(t *testing.T) {
@@ -312,7 +313,7 @@ func TestFromCollectorSmartInfo(t *testing.T) {
var smartJson collector.SmartInfo var smartJson collector.SmartInfo
smartDataBytes, err := ioutil.ReadAll(smartDataFile) smartDataBytes, err := io.ReadAll(smartDataFile)
require.NoError(t, err) require.NoError(t, err)
err = json.Unmarshal(smartDataBytes, &smartJson) err = json.Unmarshal(smartDataBytes, &smartJson)
require.NoError(t, err) require.NoError(t, err)
@@ -344,7 +345,7 @@ func TestFromCollectorSmartInfo_Fail_Smart(t *testing.T) {
var smartJson collector.SmartInfo var smartJson collector.SmartInfo
smartDataBytes, err := ioutil.ReadAll(smartDataFile) smartDataBytes, err := io.ReadAll(smartDataFile)
require.NoError(t, err) require.NoError(t, err)
err = json.Unmarshal(smartDataBytes, &smartJson) err = json.Unmarshal(smartDataBytes, &smartJson)
require.NoError(t, err) require.NoError(t, err)
@@ -368,7 +369,7 @@ func TestFromCollectorSmartInfo_Fail_ScrutinySmart(t *testing.T) {
var smartJson collector.SmartInfo var smartJson collector.SmartInfo
smartDataBytes, err := ioutil.ReadAll(smartDataFile) smartDataBytes, err := io.ReadAll(smartDataFile)
require.NoError(t, err) require.NoError(t, err)
err = json.Unmarshal(smartDataBytes, &smartJson) err = json.Unmarshal(smartDataBytes, &smartJson)
require.NoError(t, err) require.NoError(t, err)
@@ -392,7 +393,7 @@ func TestFromCollectorSmartInfo_Fail_ScrutinyNonCriticalFailed(t *testing.T) {
var smartJson collector.SmartInfo var smartJson collector.SmartInfo
smartDataBytes, err := ioutil.ReadAll(smartDataFile) smartDataBytes, err := io.ReadAll(smartDataFile)
require.NoError(t, err) require.NoError(t, err)
err = json.Unmarshal(smartDataBytes, &smartJson) err = json.Unmarshal(smartDataBytes, &smartJson)
require.NoError(t, err) require.NoError(t, err)
@@ -425,7 +426,7 @@ func TestFromCollectorSmartInfo_NVMe_Fail_Scrutiny(t *testing.T) {
var smartJson collector.SmartInfo var smartJson collector.SmartInfo
smartDataBytes, err := ioutil.ReadAll(smartDataFile) smartDataBytes, err := io.ReadAll(smartDataFile)
require.NoError(t, err) require.NoError(t, err)
err = json.Unmarshal(smartDataBytes, &smartJson) err = json.Unmarshal(smartDataBytes, &smartJson)
require.NoError(t, err) require.NoError(t, err)
@@ -456,7 +457,7 @@ func TestFromCollectorSmartInfo_Nvme(t *testing.T) {
var smartJson collector.SmartInfo var smartJson collector.SmartInfo
smartDataBytes, err := ioutil.ReadAll(smartDataFile) smartDataBytes, err := io.ReadAll(smartDataFile)
require.NoError(t, err) require.NoError(t, err)
err = json.Unmarshal(smartDataBytes, &smartJson) err = json.Unmarshal(smartDataBytes, &smartJson)
require.NoError(t, err) require.NoError(t, err)
@@ -483,7 +484,7 @@ func TestFromCollectorSmartInfo_Scsi(t *testing.T) {
var smartJson collector.SmartInfo var smartJson collector.SmartInfo
smartDataBytes, err := ioutil.ReadAll(smartDataFile) smartDataBytes, err := io.ReadAll(smartDataFile)
require.NoError(t, err) require.NoError(t, err)
err = json.Unmarshal(smartDataBytes, &smartJson) err = json.Unmarshal(smartDataBytes, &smartJson)
require.NoError(t, err) require.NoError(t, err)
+2 -3
View File
@@ -5,7 +5,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"log" "log"
"net/http" "net/http"
"os" "os"
@@ -68,7 +67,7 @@ func SendPostRequest(url string, file io.Reader) ([]byte, error) {
log.Printf("%v\n", response.Status) log.Printf("%v\n", response.Status)
return ioutil.ReadAll(response.Body) return io.ReadAll(response.Body)
} }
// InfluxDB will throw an error/ignore any submitted data with a timestamp older than the // InfluxDB will throw an error/ignore any submitted data with a timestamp older than the
@@ -79,7 +78,7 @@ func readSmartDataFileFixTimestamp(daysToSubtract int, smartDataFilepath string)
return nil, err return nil, err
} }
metricsFileData, err := ioutil.ReadAll(metricsfile) metricsFileData, err := io.ReadAll(metricsfile)
if err != nil { if err != nil {
return nil, err return nil, err
} }
+3 -3
View File
@@ -64,7 +64,7 @@ func ShouldNotify(logger logrus.FieldLogger, device models.Device, smartAttrs me
var failingAttributes []string var failingAttributes []string
// Loop through the attributes to find the failing ones // Loop through the attributes to find the failing ones
for attrId, attrData := range smartAttrs.Attributes { for attrId, attrData := range smartAttrs.Attributes {
var status pkg.AttributeStatus = attrData.GetStatus() var status = attrData.GetStatus()
// Skip over passing attributes // Skip over passing attributes
if status == pkg.AttributeStatusPassed { if status == pkg.AttributeStatusPassed {
continue continue
@@ -147,7 +147,7 @@ func NewPayload(device models.Device, test bool, currentTime ...time.Time) Paylo
//validate that the Payload is populated //validate that the Payload is populated
var sendDate time.Time var sendDate time.Time
if currentTime != nil && len(currentTime) > 0 { if len(currentTime) > 0 {
sendDate = currentTime[0] sendDate = currentTime[0]
} else { } else {
sendDate = time.Now() sendDate = time.Now()
@@ -318,7 +318,7 @@ func (n *Notify) SendScriptNotification(scriptUrl string) error {
if !utils.FileExists(scriptPath) { if !utils.FileExists(scriptPath) {
n.Logger.Errorf("Script does not exist: %s", scriptPath) n.Logger.Errorf("Script does not exist: %s", scriptPath)
return errors.New(fmt.Sprintf("custom script path does not exist: %s", scriptPath)) return fmt.Errorf("custom script path does not exist: %s", scriptPath)
} }
copyEnv := os.Environ() copyEnv := os.Environ()
+1 -13
View File
@@ -12,9 +12,9 @@ import (
"github.com/analogj/scrutiny/webapp/backend/pkg/models" "github.com/analogj/scrutiny/webapp/backend/pkg/models"
"github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements" "github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/golang/mock/gomock"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
) )
func TestShouldNotify_MustSkipPassingDevices(t *testing.T) { func TestShouldNotify_MustSkipPassingDevices(t *testing.T) {
@@ -28,7 +28,6 @@ func TestShouldNotify_MustSkipPassingDevices(t *testing.T) {
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl) fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
//assert //assert
require.False(t, ShouldNotify(logrus.StandardLogger(), device, smartAttrs, statusThreshold, notifyFilterAttributes, true, &gin.Context{}, fakeDatabase)) require.False(t, ShouldNotify(logrus.StandardLogger(), device, smartAttrs, statusThreshold, notifyFilterAttributes, true, &gin.Context{}, fakeDatabase))
@@ -44,7 +43,6 @@ func TestShouldNotify_MetricsStatusThresholdBoth_FailingSmartDevice(t *testing.T
statusThreshold := pkg.MetricsStatusThresholdBoth statusThreshold := pkg.MetricsStatusThresholdBoth
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl) fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
//assert //assert
require.True(t, ShouldNotify(logrus.StandardLogger(), device, smartAttrs, statusThreshold, notifyFilterAttributes, true, &gin.Context{}, fakeDatabase)) require.True(t, ShouldNotify(logrus.StandardLogger(), device, smartAttrs, statusThreshold, notifyFilterAttributes, true, &gin.Context{}, fakeDatabase))
@@ -60,7 +58,6 @@ func TestShouldNotify_MetricsStatusThresholdSmart_FailingSmartDevice(t *testing.
statusThreshold := pkg.MetricsStatusThresholdSmart statusThreshold := pkg.MetricsStatusThresholdSmart
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl) fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
//assert //assert
require.True(t, ShouldNotify(logrus.StandardLogger(), device, smartAttrs, statusThreshold, notifyFilterAttributes, true, &gin.Context{}, fakeDatabase)) require.True(t, ShouldNotify(logrus.StandardLogger(), device, smartAttrs, statusThreshold, notifyFilterAttributes, true, &gin.Context{}, fakeDatabase))
@@ -76,7 +73,6 @@ func TestShouldNotify_MetricsStatusThresholdScrutiny_FailingSmartDevice(t *testi
statusThreshold := pkg.MetricsStatusThresholdScrutiny statusThreshold := pkg.MetricsStatusThresholdScrutiny
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl) fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
//assert //assert
require.False(t, ShouldNotify(logrus.StandardLogger(), device, smartAttrs, statusThreshold, notifyFilterAttributes, true, &gin.Context{}, fakeDatabase)) require.False(t, ShouldNotify(logrus.StandardLogger(), device, smartAttrs, statusThreshold, notifyFilterAttributes, true, &gin.Context{}, fakeDatabase))
@@ -96,7 +92,6 @@ func TestShouldNotify_MetricsStatusFilterAttributesCritical_WithCriticalAttrs(t
statusThreshold := pkg.MetricsStatusThresholdBoth statusThreshold := pkg.MetricsStatusThresholdBoth
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesCritical notifyFilterAttributes := pkg.MetricsStatusFilterAttributesCritical
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl) fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
//assert //assert
@@ -120,7 +115,6 @@ func TestShouldNotify_MetricsStatusFilterAttributesCritical_WithMultipleCritical
statusThreshold := pkg.MetricsStatusThresholdBoth statusThreshold := pkg.MetricsStatusThresholdBoth
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesCritical notifyFilterAttributes := pkg.MetricsStatusFilterAttributesCritical
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl) fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
//assert //assert
@@ -141,7 +135,6 @@ func TestShouldNotify_MetricsStatusFilterAttributesCritical_WithNoCriticalAttrs(
statusThreshold := pkg.MetricsStatusThresholdBoth statusThreshold := pkg.MetricsStatusThresholdBoth
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesCritical notifyFilterAttributes := pkg.MetricsStatusFilterAttributesCritical
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl) fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
//assert //assert
@@ -162,7 +155,6 @@ func TestShouldNotify_MetricsStatusFilterAttributesCritical_WithNoFailingCritica
statusThreshold := pkg.MetricsStatusThresholdBoth statusThreshold := pkg.MetricsStatusThresholdBoth
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesCritical notifyFilterAttributes := pkg.MetricsStatusFilterAttributesCritical
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl) fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
//assert //assert
@@ -186,7 +178,6 @@ func TestShouldNotify_MetricsStatusFilterAttributesCritical_MetricsStatusThresho
statusThreshold := pkg.MetricsStatusThresholdSmart statusThreshold := pkg.MetricsStatusThresholdSmart
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesCritical notifyFilterAttributes := pkg.MetricsStatusFilterAttributesCritical
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl) fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
//assert //assert
@@ -206,7 +197,6 @@ func TestShouldNotify_NoRepeat_DatabaseFailure(t *testing.T) {
statusThreshold := pkg.MetricsStatusThresholdBoth statusThreshold := pkg.MetricsStatusThresholdBoth
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl) fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
fakeDatabase.EXPECT().GetSmartAttributeHistory(&gin.Context{}, "", database.DURATION_KEY_FOREVER, 1, 1, []string{"5"}).Return([]measurements.Smart{}, errors.New("")).Times(1) fakeDatabase.EXPECT().GetSmartAttributeHistory(&gin.Context{}, "", database.DURATION_KEY_FOREVER, 1, 1, []string{"5"}).Return([]measurements.Smart{}, errors.New("")).Times(1)
@@ -228,7 +218,6 @@ func TestShouldNotify_NoRepeat_NoDatabaseData(t *testing.T) {
statusThreshold := pkg.MetricsStatusThresholdBoth statusThreshold := pkg.MetricsStatusThresholdBoth
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl) fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
fakeDatabase.EXPECT().GetSmartAttributeHistory(&gin.Context{}, "", database.DURATION_KEY_FOREVER, 1, 1, []string{"5"}).Return([]measurements.Smart{}, nil).Times(1) fakeDatabase.EXPECT().GetSmartAttributeHistory(&gin.Context{}, "", database.DURATION_KEY_FOREVER, 1, 1, []string{"5"}).Return([]measurements.Smart{}, nil).Times(1)
@@ -250,7 +239,6 @@ func TestShouldNotify_NoRepeat(t *testing.T) {
statusThreshold := pkg.MetricsStatusThresholdBoth statusThreshold := pkg.MetricsStatusThresholdBoth
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl) fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
fakeDatabase.EXPECT().GetSmartAttributeHistory(&gin.Context{}, "", database.DURATION_KEY_FOREVER, 1, 1, []string{"5"}).Return([]measurements.Smart{smartAttrs}, nil).Times(1) fakeDatabase.EXPECT().GetSmartAttributeHistory(&gin.Context{}, "", database.DURATION_KEY_FOREVER, 1, 1, []string{"5"}).Return([]measurements.Smart{smartAttrs}, nil).Times(1)
+6 -6
View File
@@ -3,15 +3,15 @@ package middleware
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"io" "io"
"io/ioutil"
"math" "math"
"net/http" "net/http"
"os" "os"
"strings" "strings"
"time" "time"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
) )
// Middleware based on https://github.com/toorop/gin-logrus/blob/master/logger.go // Middleware based on https://github.com/toorop/gin-logrus/blob/master/logger.go
@@ -40,9 +40,9 @@ func LoggerMiddleware(logger *logrus.Entry) gin.HandlerFunc {
//clone the request body reader. //clone the request body reader.
var reqBody string var reqBody string
if c.Request.Body != nil { if c.Request.Body != nil {
buf, _ := ioutil.ReadAll(c.Request.Body) buf, _ := io.ReadAll(c.Request.Body)
reqBodyReader1 := ioutil.NopCloser(bytes.NewBuffer(buf)) reqBodyReader1 := io.NopCloser(bytes.NewBuffer(buf))
reqBodyReader2 := ioutil.NopCloser(bytes.NewBuffer(buf)) //We have to create a new Buffer, because reqBodyReader1 will be read. reqBodyReader2 := io.NopCloser(bytes.NewBuffer(buf)) //We have to create a new Buffer, because reqBodyReader1 will be read.
c.Request.Body = reqBodyReader2 c.Request.Body = reqBodyReader2
reqBody = readBody(reqBodyReader1) reqBody = readBody(reqBodyReader1)
} }
+12 -23
View File
@@ -5,7 +5,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"os" "os"
@@ -20,10 +19,10 @@ import (
"github.com/analogj/scrutiny/webapp/backend/pkg/models" "github.com/analogj/scrutiny/webapp/backend/pkg/models"
"github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector"
"github.com/analogj/scrutiny/webapp/backend/pkg/web" "github.com/analogj/scrutiny/webapp/backend/pkg/web"
"github.com/golang/mock/gomock"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
"go.uber.org/mock/gomock"
) )
/* /*
@@ -52,7 +51,7 @@ func helperReadSmartDataFileFixTimestamp(t *testing.T, smartDataFilepath string)
metricsfile, err := os.Open(smartDataFilepath) metricsfile, err := os.Open(smartDataFilepath)
require.NoError(t, err) require.NoError(t, err)
metricsFileData, err := ioutil.ReadAll(metricsfile) metricsFileData, err := io.ReadAll(metricsfile)
require.NoError(t, err) require.NoError(t, err)
//unmarshal because we need to change the timestamp //unmarshal because we need to change the timestamp
@@ -87,10 +86,9 @@ func TestServerTestSuite_WithCustomBasePath(t *testing.T) {
func (suite *ServerTestSuite) TestHealthRoute() { func (suite *ServerTestSuite) TestHealthRoute() {
//setup //setup
parentPath, _ := ioutil.TempDir("", "") parentPath, _ := os.MkdirTemp("", "")
defer os.RemoveAll(parentPath) defer os.RemoveAll(parentPath)
mockCtrl := gomock.NewController(suite.T()) mockCtrl := gomock.NewController(suite.T())
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().SetDefault(gomock.Any(), gomock.Any()).AnyTimes() fakeConfig.EXPECT().SetDefault(gomock.Any(), gomock.Any()).AnyTimes()
fakeConfig.EXPECT().UnmarshalKey(gomock.Any(), gomock.Any()).AnyTimes().Return(nil) fakeConfig.EXPECT().UnmarshalKey(gomock.Any(), gomock.Any()).AnyTimes().Return(nil)
@@ -131,10 +129,9 @@ func (suite *ServerTestSuite) TestHealthRoute() {
func (suite *ServerTestSuite) TestRegisterDevicesRoute() { func (suite *ServerTestSuite) TestRegisterDevicesRoute() {
//setup //setup
parentPath, _ := ioutil.TempDir("", "") parentPath, _ := os.MkdirTemp("", "")
defer os.RemoveAll(parentPath) defer os.RemoveAll(parentPath)
mockCtrl := gomock.NewController(suite.T()) mockCtrl := gomock.NewController(suite.T())
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().SetDefault(gomock.Any(), gomock.Any()).AnyTimes() fakeConfig.EXPECT().SetDefault(gomock.Any(), gomock.Any()).AnyTimes()
fakeConfig.EXPECT().UnmarshalKey(gomock.Any(), gomock.Any()).AnyTimes().Return(nil) fakeConfig.EXPECT().UnmarshalKey(gomock.Any(), gomock.Any()).AnyTimes().Return(nil)
@@ -174,10 +171,9 @@ func (suite *ServerTestSuite) TestRegisterDevicesRoute() {
func (suite *ServerTestSuite) TestUploadDeviceMetricsRoute() { func (suite *ServerTestSuite) TestUploadDeviceMetricsRoute() {
//setup //setup
parentPath, _ := ioutil.TempDir("", "") parentPath, _ := os.MkdirTemp("", "")
defer os.RemoveAll(parentPath) defer os.RemoveAll(parentPath)
mockCtrl := gomock.NewController(suite.T()) mockCtrl := gomock.NewController(suite.T())
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().SetDefault(gomock.Any(), gomock.Any()).AnyTimes() fakeConfig.EXPECT().SetDefault(gomock.Any(), gomock.Any()).AnyTimes()
fakeConfig.EXPECT().UnmarshalKey(gomock.Any(), gomock.Any()).AnyTimes().Return(nil) fakeConfig.EXPECT().UnmarshalKey(gomock.Any(), gomock.Any()).AnyTimes().Return(nil)
@@ -229,10 +225,9 @@ func (suite *ServerTestSuite) TestUploadDeviceMetricsRoute() {
func (suite *ServerTestSuite) TestPopulateMultiple() { func (suite *ServerTestSuite) TestPopulateMultiple() {
//setup //setup
parentPath, _ := ioutil.TempDir("", "") parentPath, _ := os.MkdirTemp("", "")
defer os.RemoveAll(parentPath) defer os.RemoveAll(parentPath)
mockCtrl := gomock.NewController(suite.T()) mockCtrl := gomock.NewController(suite.T())
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().SetDefault(gomock.Any(), gomock.Any()).AnyTimes() fakeConfig.EXPECT().SetDefault(gomock.Any(), gomock.Any()).AnyTimes()
fakeConfig.EXPECT().UnmarshalKey(gomock.Any(), gomock.Any()).AnyTimes().Return(nil) fakeConfig.EXPECT().UnmarshalKey(gomock.Any(), gomock.Any()).AnyTimes().Return(nil)
@@ -311,10 +306,9 @@ func (suite *ServerTestSuite) TestPopulateMultiple() {
//TODO: this test should use a recorded request/response playback. //TODO: this test should use a recorded request/response playback.
//func TestSendTestNotificationRoute(t *testing.T) { //func TestSendTestNotificationRoute(t *testing.T) {
// //setup // //setup
// parentPath, _ := ioutil.TempDir("", "") // parentPath, _ := os.MkdirTemp("", "")
// defer os.RemoveAll(parentPath) // defer os.RemoveAll(parentPath)
// mockCtrl := gomock.NewController(t) // mockCtrl := gomock.NewController(t)
// defer mockCtrl.Finish()
// fakeConfig := mock_config.NewMockInterface(mockCtrl) // fakeConfig := mock_config.NewMockInterface(mockCtrl)
// fakeConfig.EXPECT().GetString("web.database.location").AnyTimes().Return(path.Join(parentPath, "scrutiny_test.db")) // fakeConfig.EXPECT().GetString("web.database.location").AnyTimes().Return(path.Join(parentPath, "scrutiny_test.db"))
// fakeConfig.EXPECT().GetString("web.src.frontend.path").AnyTimes().Return(parentPath) // fakeConfig.EXPECT().GetString("web.src.frontend.path").AnyTimes().Return(parentPath)
@@ -335,10 +329,9 @@ func (suite *ServerTestSuite) TestPopulateMultiple() {
func (suite *ServerTestSuite) TestSendTestNotificationRoute_WebhookFailure() { func (suite *ServerTestSuite) TestSendTestNotificationRoute_WebhookFailure() {
//setup //setup
parentPath, _ := ioutil.TempDir("", "") parentPath, _ := os.MkdirTemp("", "")
defer os.RemoveAll(parentPath) defer os.RemoveAll(parentPath)
mockCtrl := gomock.NewController(suite.T()) mockCtrl := gomock.NewController(suite.T())
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().SetDefault(gomock.Any(), gomock.Any()).AnyTimes() fakeConfig.EXPECT().SetDefault(gomock.Any(), gomock.Any()).AnyTimes()
fakeConfig.EXPECT().UnmarshalKey(gomock.Any(), gomock.Any()).AnyTimes().Return(nil) fakeConfig.EXPECT().UnmarshalKey(gomock.Any(), gomock.Any()).AnyTimes().Return(nil)
@@ -381,10 +374,9 @@ func (suite *ServerTestSuite) TestSendTestNotificationRoute_WebhookFailure() {
func (suite *ServerTestSuite) TestSendTestNotificationRoute_ScriptFailure() { func (suite *ServerTestSuite) TestSendTestNotificationRoute_ScriptFailure() {
//setup //setup
parentPath, _ := ioutil.TempDir("", "") parentPath, _ := os.MkdirTemp("", "")
defer os.RemoveAll(parentPath) defer os.RemoveAll(parentPath)
mockCtrl := gomock.NewController(suite.T()) mockCtrl := gomock.NewController(suite.T())
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().SetDefault(gomock.Any(), gomock.Any()).AnyTimes() fakeConfig.EXPECT().SetDefault(gomock.Any(), gomock.Any()).AnyTimes()
fakeConfig.EXPECT().UnmarshalKey(gomock.Any(), gomock.Any()).AnyTimes().Return(nil) fakeConfig.EXPECT().UnmarshalKey(gomock.Any(), gomock.Any()).AnyTimes().Return(nil)
@@ -427,10 +419,9 @@ func (suite *ServerTestSuite) TestSendTestNotificationRoute_ScriptFailure() {
func (suite *ServerTestSuite) TestSendTestNotificationRoute_ScriptSuccess() { func (suite *ServerTestSuite) TestSendTestNotificationRoute_ScriptSuccess() {
//setup //setup
parentPath, _ := ioutil.TempDir("", "") parentPath, _ := os.MkdirTemp("", "")
defer os.RemoveAll(parentPath) defer os.RemoveAll(parentPath)
mockCtrl := gomock.NewController(suite.T()) mockCtrl := gomock.NewController(suite.T())
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().SetDefault(gomock.Any(), gomock.Any()).AnyTimes() fakeConfig.EXPECT().SetDefault(gomock.Any(), gomock.Any()).AnyTimes()
fakeConfig.EXPECT().UnmarshalKey(gomock.Any(), gomock.Any()).AnyTimes().Return(nil) fakeConfig.EXPECT().UnmarshalKey(gomock.Any(), gomock.Any()).AnyTimes().Return(nil)
@@ -473,10 +464,9 @@ func (suite *ServerTestSuite) TestSendTestNotificationRoute_ScriptSuccess() {
func (suite *ServerTestSuite) TestSendTestNotificationRoute_ShoutrrrFailure() { func (suite *ServerTestSuite) TestSendTestNotificationRoute_ShoutrrrFailure() {
//setup //setup
parentPath, _ := ioutil.TempDir("", "") parentPath, _ := os.MkdirTemp("", "")
defer os.RemoveAll(parentPath) defer os.RemoveAll(parentPath)
mockCtrl := gomock.NewController(suite.T()) mockCtrl := gomock.NewController(suite.T())
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().SetDefault(gomock.Any(), gomock.Any()).AnyTimes() fakeConfig.EXPECT().SetDefault(gomock.Any(), gomock.Any()).AnyTimes()
fakeConfig.EXPECT().UnmarshalKey(gomock.Any(), gomock.Any()).AnyTimes().Return(nil) fakeConfig.EXPECT().UnmarshalKey(gomock.Any(), gomock.Any()).AnyTimes().Return(nil)
@@ -518,10 +508,9 @@ func (suite *ServerTestSuite) TestSendTestNotificationRoute_ShoutrrrFailure() {
func (suite *ServerTestSuite) TestGetDevicesSummaryRoute_Nvme() { func (suite *ServerTestSuite) TestGetDevicesSummaryRoute_Nvme() {
//setup //setup
parentPath, _ := ioutil.TempDir("", "") parentPath, _ := os.MkdirTemp("", "")
defer os.RemoveAll(parentPath) defer os.RemoveAll(parentPath)
mockCtrl := gomock.NewController(suite.T()) mockCtrl := gomock.NewController(suite.T())
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().SetDefault(gomock.Any(), gomock.Any()).AnyTimes() fakeConfig.EXPECT().SetDefault(gomock.Any(), gomock.Any()).AnyTimes()
fakeConfig.EXPECT().UnmarshalKey(gomock.Any(), gomock.Any()).AnyTimes().Return(nil) fakeConfig.EXPECT().UnmarshalKey(gomock.Any(), gomock.Any()).AnyTimes().Return(nil)