You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
341 lines
12 KiB
341 lines
12 KiB
package notify
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/analogj/scrutiny/webapp/backend/pkg"
|
|
"github.com/analogj/scrutiny/webapp/backend/pkg/database"
|
|
mock_database "github.com/analogj/scrutiny/webapp/backend/pkg/database/mock"
|
|
"github.com/analogj/scrutiny/webapp/backend/pkg/models"
|
|
"github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/golang/mock/gomock"
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestShouldNotify_MustSkipPassingDevices(t *testing.T) {
|
|
t.Parallel()
|
|
//setup
|
|
device := models.Device{
|
|
DeviceStatus: pkg.DeviceStatusPassed,
|
|
}
|
|
smartAttrs := measurements.Smart{}
|
|
statusThreshold := pkg.MetricsStatusThresholdBoth
|
|
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll
|
|
|
|
mockCtrl := gomock.NewController(t)
|
|
defer mockCtrl.Finish()
|
|
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
|
|
//assert
|
|
require.False(t, ShouldNotify(logrus.StandardLogger(), device, smartAttrs, statusThreshold, notifyFilterAttributes, true, &gin.Context{}, fakeDatabase))
|
|
}
|
|
|
|
func TestShouldNotify_MetricsStatusThresholdBoth_FailingSmartDevice(t *testing.T) {
|
|
t.Parallel()
|
|
//setupD
|
|
device := models.Device{
|
|
DeviceStatus: pkg.DeviceStatusFailedSmart,
|
|
}
|
|
smartAttrs := measurements.Smart{}
|
|
statusThreshold := pkg.MetricsStatusThresholdBoth
|
|
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll
|
|
mockCtrl := gomock.NewController(t)
|
|
defer mockCtrl.Finish()
|
|
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
|
|
//assert
|
|
require.True(t, ShouldNotify(logrus.StandardLogger(), device, smartAttrs, statusThreshold, notifyFilterAttributes, true, &gin.Context{}, fakeDatabase))
|
|
}
|
|
|
|
func TestShouldNotify_MetricsStatusThresholdSmart_FailingSmartDevice(t *testing.T) {
|
|
t.Parallel()
|
|
//setup
|
|
device := models.Device{
|
|
DeviceStatus: pkg.DeviceStatusFailedSmart,
|
|
}
|
|
smartAttrs := measurements.Smart{}
|
|
statusThreshold := pkg.MetricsStatusThresholdSmart
|
|
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll
|
|
mockCtrl := gomock.NewController(t)
|
|
defer mockCtrl.Finish()
|
|
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
|
|
//assert
|
|
require.True(t, ShouldNotify(logrus.StandardLogger(), device, smartAttrs, statusThreshold, notifyFilterAttributes, true, &gin.Context{}, fakeDatabase))
|
|
}
|
|
|
|
func TestShouldNotify_MetricsStatusThresholdScrutiny_FailingSmartDevice(t *testing.T) {
|
|
t.Parallel()
|
|
//setup
|
|
device := models.Device{
|
|
DeviceStatus: pkg.DeviceStatusFailedSmart,
|
|
}
|
|
smartAttrs := measurements.Smart{}
|
|
statusThreshold := pkg.MetricsStatusThresholdScrutiny
|
|
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll
|
|
mockCtrl := gomock.NewController(t)
|
|
defer mockCtrl.Finish()
|
|
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
|
|
//assert
|
|
require.False(t, ShouldNotify(logrus.StandardLogger(), device, smartAttrs, statusThreshold, notifyFilterAttributes, true, &gin.Context{}, fakeDatabase))
|
|
}
|
|
|
|
func TestShouldNotify_MetricsStatusFilterAttributesCritical_WithCriticalAttrs(t *testing.T) {
|
|
t.Parallel()
|
|
//setup
|
|
device := models.Device{
|
|
DeviceStatus: pkg.DeviceStatusFailedSmart,
|
|
}
|
|
smartAttrs := measurements.Smart{Attributes: map[string]measurements.SmartAttribute{
|
|
"5": &measurements.SmartAtaAttribute{
|
|
Status: pkg.AttributeStatusFailedSmart,
|
|
},
|
|
}}
|
|
statusThreshold := pkg.MetricsStatusThresholdBoth
|
|
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesCritical
|
|
mockCtrl := gomock.NewController(t)
|
|
defer mockCtrl.Finish()
|
|
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
|
|
|
|
//assert
|
|
require.True(t, ShouldNotify(logrus.StandardLogger(), device, smartAttrs, statusThreshold, notifyFilterAttributes, true, &gin.Context{}, fakeDatabase))
|
|
}
|
|
|
|
func TestShouldNotify_MetricsStatusFilterAttributesCritical_WithMultipleCriticalAttrs(t *testing.T) {
|
|
t.Parallel()
|
|
//setup
|
|
device := models.Device{
|
|
DeviceStatus: pkg.DeviceStatusFailedSmart,
|
|
}
|
|
smartAttrs := measurements.Smart{Attributes: map[string]measurements.SmartAttribute{
|
|
"5": &measurements.SmartAtaAttribute{
|
|
Status: pkg.AttributeStatusPassed,
|
|
},
|
|
"10": &measurements.SmartAtaAttribute{
|
|
Status: pkg.AttributeStatusFailedScrutiny,
|
|
},
|
|
}}
|
|
statusThreshold := pkg.MetricsStatusThresholdBoth
|
|
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesCritical
|
|
mockCtrl := gomock.NewController(t)
|
|
defer mockCtrl.Finish()
|
|
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
|
|
|
|
//assert
|
|
require.True(t, ShouldNotify(logrus.StandardLogger(), device, smartAttrs, statusThreshold, notifyFilterAttributes, true, &gin.Context{}, fakeDatabase))
|
|
}
|
|
|
|
func TestShouldNotify_MetricsStatusFilterAttributesCritical_WithNoCriticalAttrs(t *testing.T) {
|
|
t.Parallel()
|
|
//setup
|
|
device := models.Device{
|
|
DeviceStatus: pkg.DeviceStatusFailedSmart,
|
|
}
|
|
smartAttrs := measurements.Smart{Attributes: map[string]measurements.SmartAttribute{
|
|
"1": &measurements.SmartAtaAttribute{
|
|
Status: pkg.AttributeStatusFailedSmart,
|
|
},
|
|
}}
|
|
statusThreshold := pkg.MetricsStatusThresholdBoth
|
|
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesCritical
|
|
mockCtrl := gomock.NewController(t)
|
|
defer mockCtrl.Finish()
|
|
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
|
|
|
|
//assert
|
|
require.False(t, ShouldNotify(logrus.StandardLogger(), device, smartAttrs, statusThreshold, notifyFilterAttributes, true, &gin.Context{}, fakeDatabase))
|
|
}
|
|
|
|
func TestShouldNotify_MetricsStatusFilterAttributesCritical_WithNoFailingCriticalAttrs(t *testing.T) {
|
|
t.Parallel()
|
|
//setup
|
|
device := models.Device{
|
|
DeviceStatus: pkg.DeviceStatusFailedSmart,
|
|
}
|
|
smartAttrs := measurements.Smart{Attributes: map[string]measurements.SmartAttribute{
|
|
"5": &measurements.SmartAtaAttribute{
|
|
Status: pkg.AttributeStatusPassed,
|
|
},
|
|
}}
|
|
statusThreshold := pkg.MetricsStatusThresholdBoth
|
|
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesCritical
|
|
mockCtrl := gomock.NewController(t)
|
|
defer mockCtrl.Finish()
|
|
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
|
|
|
|
//assert
|
|
require.False(t, ShouldNotify(logrus.StandardLogger(), device, smartAttrs, statusThreshold, notifyFilterAttributes, true, &gin.Context{}, fakeDatabase))
|
|
}
|
|
|
|
func TestShouldNotify_MetricsStatusFilterAttributesCritical_MetricsStatusThresholdSmart_WithCriticalAttrsFailingScrutiny(t *testing.T) {
|
|
t.Parallel()
|
|
//setup
|
|
device := models.Device{
|
|
DeviceStatus: pkg.DeviceStatusFailedSmart,
|
|
}
|
|
smartAttrs := measurements.Smart{Attributes: map[string]measurements.SmartAttribute{
|
|
"5": &measurements.SmartAtaAttribute{
|
|
Status: pkg.AttributeStatusPassed,
|
|
},
|
|
"10": &measurements.SmartAtaAttribute{
|
|
Status: pkg.AttributeStatusFailedScrutiny,
|
|
},
|
|
}}
|
|
statusThreshold := pkg.MetricsStatusThresholdSmart
|
|
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesCritical
|
|
mockCtrl := gomock.NewController(t)
|
|
defer mockCtrl.Finish()
|
|
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
|
|
|
|
//assert
|
|
require.False(t, ShouldNotify(logrus.StandardLogger(), device, smartAttrs, statusThreshold, notifyFilterAttributes, true, &gin.Context{}, fakeDatabase))
|
|
}
|
|
func TestShouldNotify_NoRepeat_DatabaseFailure(t *testing.T) {
|
|
t.Parallel()
|
|
//setup
|
|
device := models.Device{
|
|
DeviceStatus: pkg.DeviceStatusFailedScrutiny,
|
|
}
|
|
smartAttrs := measurements.Smart{Attributes: map[string]measurements.SmartAttribute{
|
|
"5": &measurements.SmartAtaAttribute{
|
|
Status: pkg.AttributeStatusFailedScrutiny,
|
|
},
|
|
}}
|
|
statusThreshold := pkg.MetricsStatusThresholdBoth
|
|
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll
|
|
mockCtrl := gomock.NewController(t)
|
|
defer mockCtrl.Finish()
|
|
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)
|
|
|
|
//assert
|
|
require.True(t, ShouldNotify(logrus.StandardLogger(), device, smartAttrs, statusThreshold, notifyFilterAttributes, false, &gin.Context{}, fakeDatabase))
|
|
}
|
|
|
|
func TestShouldNotify_NoRepeat_NoDatabaseData(t *testing.T) {
|
|
t.Parallel()
|
|
//setup
|
|
device := models.Device{
|
|
DeviceStatus: pkg.DeviceStatusFailedScrutiny,
|
|
}
|
|
smartAttrs := measurements.Smart{Attributes: map[string]measurements.SmartAttribute{
|
|
"5": &measurements.SmartAtaAttribute{
|
|
Status: pkg.AttributeStatusFailedScrutiny,
|
|
},
|
|
}}
|
|
statusThreshold := pkg.MetricsStatusThresholdBoth
|
|
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll
|
|
mockCtrl := gomock.NewController(t)
|
|
defer mockCtrl.Finish()
|
|
fakeDatabase := mock_database.NewMockDeviceRepo(mockCtrl)
|
|
fakeDatabase.EXPECT().GetSmartAttributeHistory(&gin.Context{}, "", database.DURATION_KEY_FOREVER, 1, 1, []string{"5"}).Return([]measurements.Smart{}, nil).Times(1)
|
|
|
|
//assert
|
|
require.True(t, ShouldNotify(logrus.StandardLogger(), device, smartAttrs, statusThreshold, notifyFilterAttributes, false, &gin.Context{}, fakeDatabase))
|
|
}
|
|
func TestShouldNotify_NoRepeat(t *testing.T) {
|
|
t.Parallel()
|
|
//setup
|
|
device := models.Device{
|
|
DeviceStatus: pkg.DeviceStatusFailedScrutiny,
|
|
}
|
|
smartAttrs := measurements.Smart{Attributes: map[string]measurements.SmartAttribute{
|
|
"5": &measurements.SmartAtaAttribute{
|
|
Status: pkg.AttributeStatusFailedScrutiny,
|
|
TransformedValue: 0,
|
|
},
|
|
}}
|
|
statusThreshold := pkg.MetricsStatusThresholdBoth
|
|
notifyFilterAttributes := pkg.MetricsStatusFilterAttributesAll
|
|
mockCtrl := gomock.NewController(t)
|
|
defer mockCtrl.Finish()
|
|
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)
|
|
|
|
//assert
|
|
require.False(t, ShouldNotify(logrus.StandardLogger(), device, smartAttrs, statusThreshold, notifyFilterAttributes, false, &gin.Context{}, fakeDatabase))
|
|
}
|
|
|
|
func TestNewPayload(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
//setup
|
|
device := models.Device{
|
|
SerialNumber: "FAKEWDDJ324KSO",
|
|
DeviceType: pkg.DeviceProtocolAta,
|
|
DeviceName: "/dev/sda",
|
|
DeviceStatus: pkg.DeviceStatusFailedScrutiny,
|
|
}
|
|
currentTime := time.Now()
|
|
//test
|
|
|
|
payload := NewPayload(device, false, currentTime)
|
|
|
|
//assert
|
|
require.Equal(t, "Scrutiny SMART error (ScrutinyFailure) detected on device: /dev/sda", payload.Subject)
|
|
require.Equal(t, fmt.Sprintf(`Scrutiny SMART error notification for device: /dev/sda
|
|
Failure Type: ScrutinyFailure
|
|
Device Name: /dev/sda
|
|
Device Serial: FAKEWDDJ324KSO
|
|
Device Type: ATA
|
|
|
|
Date: %s`, currentTime.Format(time.RFC3339)), payload.Message)
|
|
}
|
|
|
|
func TestNewPayload_TestMode(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
//setup
|
|
device := models.Device{
|
|
SerialNumber: "FAKEWDDJ324KSO",
|
|
DeviceType: pkg.DeviceProtocolAta,
|
|
DeviceName: "/dev/sda",
|
|
DeviceStatus: pkg.DeviceStatusFailedScrutiny,
|
|
}
|
|
currentTime := time.Now()
|
|
//test
|
|
|
|
payload := NewPayload(device, true, currentTime)
|
|
|
|
//assert
|
|
require.Equal(t, "Scrutiny SMART error (EmailTest) detected on device: /dev/sda", payload.Subject)
|
|
require.Equal(t, fmt.Sprintf(`TEST NOTIFICATION:
|
|
Scrutiny SMART error notification for device: /dev/sda
|
|
Failure Type: EmailTest
|
|
Device Name: /dev/sda
|
|
Device Serial: FAKEWDDJ324KSO
|
|
Device Type: ATA
|
|
|
|
Date: %s`, currentTime.Format(time.RFC3339)), payload.Message)
|
|
}
|
|
|
|
func TestNewPayload_WithHostId(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
//setup
|
|
device := models.Device{
|
|
SerialNumber: "FAKEWDDJ324KSO",
|
|
DeviceType: pkg.DeviceProtocolAta,
|
|
DeviceName: "/dev/sda",
|
|
DeviceStatus: pkg.DeviceStatusFailedScrutiny,
|
|
HostId: "custom-host",
|
|
}
|
|
currentTime := time.Now()
|
|
//test
|
|
|
|
payload := NewPayload(device, false, currentTime)
|
|
|
|
//assert
|
|
require.Equal(t, "Scrutiny SMART error (ScrutinyFailure) detected on [host]device: [custom-host]/dev/sda", payload.Subject)
|
|
require.Equal(t, fmt.Sprintf(`Scrutiny SMART error notification for device: /dev/sda
|
|
Host Id: custom-host
|
|
Failure Type: ScrutinyFailure
|
|
Device Name: /dev/sda
|
|
Device Serial: FAKEWDDJ324KSO
|
|
Device Type: ATA
|
|
|
|
Date: %s`, currentTime.Format(time.RFC3339)), payload.Message)
|
|
}
|