Merge branch 'master' into BASEPATH

This commit is contained in:
Jason Kulatunga
2022-05-09 14:29:48 -07:00
committed by GitHub
125 changed files with 26973 additions and 14987 deletions
@@ -1,53 +1,44 @@
package handler
import (
"github.com/analogj/scrutiny/webapp/backend/pkg/metadata"
dbModels "github.com/analogj/scrutiny/webapp/backend/pkg/models/db"
"github.com/analogj/scrutiny/webapp/backend/pkg/database"
"github.com/analogj/scrutiny/webapp/backend/pkg/thresholds"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
"net/http"
)
func GetDeviceDetails(c *gin.Context) {
db := c.MustGet("DB").(*gorm.DB)
logger := c.MustGet("LOGGER").(logrus.FieldLogger)
device := dbModels.Device{}
if err := db.Preload("SmartResults", func(db *gorm.DB) *gorm.DB {
return db.Order("smarts.created_at DESC").Limit(40)
}).
Preload("SmartResults.AtaAttributes").
Preload("SmartResults.NvmeAttributes").
Preload("SmartResults.ScsiAttributes").
Where("wwn = ?", c.Param("wwn")).
First(&device).Error; err != nil {
deviceRepo := c.MustGet("DEVICE_REPOSITORY").(database.DeviceRepo)
device, err := deviceRepo.GetDeviceDetails(c, c.Param("wwn"))
if err != nil {
logger.Errorln("An error occurred while retrieving device details", err)
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
return
}
if err := device.SquashHistory(); err != nil {
logger.Errorln("An error occurred while squashing device history", err)
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
return
durationKey, exists := c.GetQuery("duration_key")
if !exists {
durationKey = "forever"
}
if err := device.ApplyMetadataRules(); err != nil {
logger.Errorln("An error occurred while applying scrutiny thresholds & rules", err)
smartResults, err := deviceRepo.GetSmartAttributeHistory(c, c.Param("wwn"), durationKey, nil)
if err != nil {
logger.Errorln("An error occurred while retrieving device smart results", err)
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
return
}
var deviceMetadata interface{}
if device.IsAta() {
deviceMetadata = metadata.AtaMetadata
deviceMetadata = thresholds.AtaMetadata
} else if device.IsNvme() {
deviceMetadata = metadata.NmveMetadata
deviceMetadata = thresholds.NmveMetadata
} else if device.IsScsi() {
deviceMetadata = metadata.ScsiMetadata
deviceMetadata = thresholds.ScsiMetadata
}
c.JSON(http.StatusOK, gin.H{"success": true, "data": device, "metadata": deviceMetadata})
c.JSON(http.StatusOK, gin.H{"success": true, "data": map[string]interface{}{"device": device, "smart_results": smartResults}, "metadata": deviceMetadata})
}
@@ -1,31 +1,28 @@
package handler
import (
dbModels "github.com/analogj/scrutiny/webapp/backend/pkg/models/db"
"github.com/analogj/scrutiny/webapp/backend/pkg/database"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
"net/http"
)
func GetDevicesSummary(c *gin.Context) {
db := c.MustGet("DB").(*gorm.DB)
logger := c.MustGet("LOGGER").(logrus.FieldLogger)
devices := []dbModels.Device{}
deviceRepo := c.MustGet("DEVICE_REPOSITORY").(database.DeviceRepo)
//We need the last x (for now all) Smart objects for each Device, so that we can graph Temperature
//We also need the last
if err := db.Preload("SmartResults", func(db *gorm.DB) *gorm.DB {
return db.Order("smarts.created_at DESC") //OLD: .Limit(devicesCount)
}).
Find(&devices).Error; err != nil {
logger.Errorln("Could not get device summary from DB", err)
summary, err := deviceRepo.GetSummary(c)
if err != nil {
logger.Errorln("An error occurred while retrieving device summary", err)
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": devices,
"data": map[string]interface{}{
"summary": summary,
//"temperature": tem
},
})
}
@@ -0,0 +1,32 @@
package handler
import (
"github.com/analogj/scrutiny/webapp/backend/pkg/database"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"net/http"
)
func GetDevicesSummaryTempHistory(c *gin.Context) {
logger := c.MustGet("LOGGER").(logrus.FieldLogger)
deviceRepo := c.MustGet("DEVICE_REPOSITORY").(database.DeviceRepo)
durationKey, exists := c.GetQuery("duration_key")
if !exists {
durationKey = "week"
}
tempHistory, err := deviceRepo.GetSmartTemperatureHistory(c, durationKey)
if err != nil {
logger.Errorln("An error occurred while retrieving summary/temp history", err)
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": map[string]interface{}{
"temp_history": tempHistory,
},
})
}
@@ -1,22 +1,20 @@
package handler
import (
dbModels "github.com/analogj/scrutiny/webapp/backend/pkg/models/db"
"github.com/analogj/scrutiny/webapp/backend/pkg/database"
"github.com/analogj/scrutiny/webapp/backend/pkg/models"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"github.com/sirupsen/logrus"
"net/http"
)
// register devices that are detected by various collectors.
// This function is run everytime a collector is about to start a run. It can be used to update device data.
// This function is run everytime a collector is about to start a run. It can be used to update device metadata.
func RegisterDevices(c *gin.Context) {
db := c.MustGet("DB").(*gorm.DB)
deviceRepo := c.MustGet("DEVICE_REPOSITORY").(database.DeviceRepo)
logger := c.MustGet("LOGGER").(logrus.FieldLogger)
var collectorDeviceWrapper dbModels.DeviceWrapper
var collectorDeviceWrapper models.DeviceWrapper
err := c.BindJSON(&collectorDeviceWrapper)
if err != nil {
logger.Errorln("Cannot parse detected devices", err)
@@ -28,11 +26,7 @@ func RegisterDevices(c *gin.Context) {
for _, dev := range collectorDeviceWrapper.Data {
//insert devices into DB (and update specified columns if device is already registered)
// update device fields that may change: (DeviceType, HostID)
if err := db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "wwn"}},
DoUpdates: clause.AssignmentColumns([]string{"host_id", "device_name", "device_type"}),
}).Create(&dev).Error; err != nil {
if err := deviceRepo.RegisterDevice(c, dev); err != nil {
errs = append(errs, err)
}
}
@@ -44,7 +38,7 @@ func RegisterDevices(c *gin.Context) {
})
return
} else {
c.JSON(http.StatusOK, dbModels.DeviceWrapper{
c.JSON(http.StatusOK, models.DeviceWrapper{
Success: true,
Data: collectorDeviceWrapper.Data,
})
@@ -1,8 +1,9 @@
package handler
import (
"github.com/analogj/scrutiny/webapp/backend/pkg"
"github.com/analogj/scrutiny/webapp/backend/pkg/config"
dbModels "github.com/analogj/scrutiny/webapp/backend/pkg/models/db"
"github.com/analogj/scrutiny/webapp/backend/pkg/models"
"github.com/analogj/scrutiny/webapp/backend/pkg/notify"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
@@ -20,7 +21,7 @@ func SendTestNotification(c *gin.Context) {
Payload: notify.Payload{
FailureType: "EmailTest",
DeviceSerial: "FAKEWDDJ324KSO",
DeviceType: dbModels.DeviceProtocolAta,
DeviceType: pkg.DeviceProtocolAta,
DeviceName: "/dev/sda",
Test: true,
},
@@ -33,7 +34,7 @@ func SendTestNotification(c *gin.Context) {
"errors": []string{err.Error()},
})
} else {
c.JSON(http.StatusOK, dbModels.DeviceWrapper{
c.JSON(http.StatusOK, models.DeviceWrapper{
Success: true,
})
}
@@ -1,20 +1,24 @@
package handler
import (
"github.com/analogj/scrutiny/webapp/backend/pkg"
"github.com/analogj/scrutiny/webapp/backend/pkg/config"
"github.com/analogj/scrutiny/webapp/backend/pkg/database"
"github.com/analogj/scrutiny/webapp/backend/pkg/models/collector"
dbModels "github.com/analogj/scrutiny/webapp/backend/pkg/models/db"
"github.com/analogj/scrutiny/webapp/backend/pkg/notify"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
"net/http"
)
func UploadDeviceMetrics(c *gin.Context) {
db := c.MustGet("DB").(*gorm.DB)
//db := c.MustGet("DB").(*gorm.DB)
logger := c.MustGet("LOGGER").(logrus.FieldLogger)
appConfig := c.MustGet("CONFIG").(config.Interface)
//influxWriteDb := c.MustGet("INFLUXDB_WRITE").(*api.WriteAPIBlocking)
deviceRepo := c.MustGet("DEVICE_REPOSITORY").(database.DeviceRepo)
//appConfig := c.MustGet("CONFIG").(config.Interface)
var collectorSmartData collector.SmartInfo
err := c.BindJSON(&collectorSmartData)
@@ -25,39 +29,49 @@ func UploadDeviceMetrics(c *gin.Context) {
}
//update the device information if necessary
var device dbModels.Device
db.Where("wwn = ?", c.Param("wwn")).First(&device)
device.UpdateFromCollectorSmartInfo(collectorSmartData)
if err := db.Model(&device).Updates(device).Error; err != nil {
logger.Errorln("An error occurred while updating device data from smartctl metrics", err)
updatedDevice, err := deviceRepo.UpdateDevice(c, c.Param("wwn"), collectorSmartData)
if err != nil {
logger.Errorln("An error occurred while updating device data from smartctl metrics:", err)
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
return
}
// insert smart info
deviceSmartData := dbModels.Smart{}
err = deviceSmartData.FromCollectorSmartInfo(c.Param("wwn"), collectorSmartData)
smartData, err := deviceRepo.SaveSmartAttributes(c, c.Param("wwn"), collectorSmartData)
if err != nil {
logger.Errorln("Could not process SMART metrics", err)
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
return
}
if err := db.Create(&deviceSmartData).Error; err != nil {
logger.Errorln("An error occurred while saving smartctl metrics", err)
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
return
}
if smartData.Status != pkg.DeviceStatusPassed {
//there is a failure detected by Scrutiny, update the device status on the homepage.
updatedDevice, err = deviceRepo.UpdateDeviceStatus(c, c.Param("wwn"), smartData.Status)
if err != nil {
logger.Errorln("An error occurred while updating device status", err)
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
return
}
}
// save smart temperature data (ignore failures)
err = deviceRepo.SaveSmartTemperature(c, c.Param("wwn"), updatedDevice.DeviceProtocol, collectorSmartData)
if err != nil {
logger.Errorln("An error occurred while saving smartctl temp data", err)
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
return
}
//check for error
if deviceSmartData.SmartStatus == dbModels.SmartStatusFailed {
if updatedDevice.DeviceStatus != pkg.DeviceStatusPassed {
//send notifications
testNotify := notify.Notify{
Config: appConfig,
Payload: notify.Payload{
FailureType: notify.NotifyFailureTypeSmartFailure,
DeviceName: device.DeviceName,
DeviceType: device.DeviceProtocol,
DeviceSerial: device.SerialNumber,
DeviceName: updatedDevice.DeviceName,
DeviceType: updatedDevice.DeviceProtocol,
DeviceSerial: updatedDevice.SerialNumber,
Test: false,
},
Logger: logger,
@@ -0,0 +1,22 @@
package middleware
import (
"github.com/analogj/scrutiny/webapp/backend/pkg/config"
"github.com/analogj/scrutiny/webapp/backend/pkg/database"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)
func RepositoryMiddleware(appConfig config.Interface, globalLogger logrus.FieldLogger) gin.HandlerFunc {
deviceRepo, err := database.NewScrutinyRepository(appConfig, globalLogger)
if err != nil {
panic(err)
}
//TODO: determine where we can call defer deviceRepo.Close()
return func(c *gin.Context) {
c.Set("DEVICE_REPOSITORY", deviceRepo)
c.Next()
}
}
@@ -1,59 +0,0 @@
package middleware
import (
"fmt"
"github.com/analogj/scrutiny/webapp/backend/pkg/config"
"github.com/analogj/scrutiny/webapp/backend/pkg/models/db"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
func DatabaseMiddleware(appConfig config.Interface, globalLogger logrus.FieldLogger) gin.HandlerFunc {
//var database *gorm.DB
fmt.Printf("Trying to connect to database stored: %s\n", appConfig.GetString("web.database.location"))
database, err := gorm.Open(sqlite.Open(appConfig.GetString("web.database.location")), &gorm.Config{
//TODO: figure out how to log database queries again.
//Logger: logger
})
if err != nil {
panic("Failed to connect to database!")
}
//database.SetLogger()
database.AutoMigrate(&db.Device{})
database.AutoMigrate(&db.SelfTest{})
database.AutoMigrate(&db.Smart{})
database.AutoMigrate(&db.SmartAtaAttribute{})
database.AutoMigrate(&db.SmartNvmeAttribute{})
database.AutoMigrate(&db.SmartScsiAttribute{})
//TODO: detrmine where we can call defer database.Close()
return func(c *gin.Context) {
c.Set("DB", database)
c.Next()
}
}
// GormLogger is a custom logger for Gorm, making it use logrus.
type GormLogger struct{ Logger logrus.FieldLogger }
// Print handles log events from Gorm for the custom logger.
func (gl *GormLogger) Print(v ...interface{}) {
switch v[0] {
case "sql":
gl.Logger.WithFields(
logrus.Fields{
"module": "gorm",
"type": "sql",
"rows": v[5],
"src_ref": v[1],
"values": v[4],
},
).Debug(v[3])
case "log":
gl.Logger.WithFields(logrus.Fields{"module": "gorm", "type": "log"}).Print(v[2])
}
}
+7 -6
View File
@@ -23,7 +23,7 @@ func (ae *AppEngine) Setup(logger logrus.FieldLogger) *gin.Engine {
r := gin.New()
r.Use(middleware.LoggerMiddleware(logger))
r.Use(middleware.DatabaseMiddleware(ae.Config, logger))
r.Use(middleware.RepositoryMiddleware(ae.Config, logger))
r.Use(middleware.ConfigMiddleware(ae.Config))
r.Use(gin.Recovery())
@@ -40,11 +40,12 @@ func (ae *AppEngine) Setup(logger logrus.FieldLogger) *gin.Engine {
})
api.POST("/health/notify", handler.SendTestNotification) //check if notifications are configured correctly
api.POST("/devices/register", handler.RegisterDevices) //used by Collector to register new devices and retrieve filtered list
api.GET("/summary", handler.GetDevicesSummary) //used by Dashboard
api.POST("/device/:wwn/smart", handler.UploadDeviceMetrics) //used by Collector to upload data
api.POST("/device/:wwn/selftest", handler.UploadDeviceSelfTests)
api.GET("/device/:wwn/details", handler.GetDeviceDetails) //used by Details
api.POST("/devices/register", handler.RegisterDevices) //used by Collector to register new devices and retrieve filtered list
api.GET("/summary", handler.GetDevicesSummary) //used by Dashboard
api.GET("/summary/temp", handler.GetDevicesSummaryTempHistory) //used by Dashboard (Temperature history dropdown)
api.POST("/device/:wwn/smart", handler.UploadDeviceMetrics) //used by Collector to upload data
api.POST("/device/:wwn/selftest", handler.UploadDeviceSelfTests)
api.GET("/device/:wwn/details", handler.GetDeviceDetails) //used by Details
}
}
+347 -284
View File
@@ -1,14 +1,17 @@
package web_test
import (
"bytes"
"encoding/json"
"fmt"
"github.com/analogj/scrutiny/webapp/backend/pkg"
mock_config "github.com/analogj/scrutiny/webapp/backend/pkg/config/mock"
dbModels "github.com/analogj/scrutiny/webapp/backend/pkg/models/db"
"github.com/analogj/scrutiny/webapp/backend/pkg/models"
"github.com/analogj/scrutiny/webapp/backend/pkg/models/collector"
"github.com/analogj/scrutiny/webapp/backend/pkg/web"
"github.com/golang/mock/gomock"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/require"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
@@ -16,12 +19,76 @@ import (
"path"
"strings"
"testing"
"time"
)
const (
emptyBasePath = ""
notEmptyBasePath = "/basepath"
)
/*
All tests in this file require the existance of a influxDB listening on port 8086
docker run --rm -it -p 8086:8086 \
-e DOCKER_INFLUXDB_INIT_MODE=setup \
-e DOCKER_INFLUXDB_INIT_USERNAME=admin \
-e DOCKER_INFLUXDB_INIT_PASSWORD=password12345 \
-e DOCKER_INFLUXDB_INIT_ORG=scrutiny \
-e DOCKER_INFLUXDB_INIT_BUCKET=metrics \
-e DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=my-super-secret-auth-token \
influxdb:2.0
*/
//func TestMain(m *testing.M) {
// setup()
// code := m.Run()
// shutdown()
// os.Exit(code)
//}
// InfluxDB will throw an error/ignore any submitted data with a timestamp older than the
// retention period. Lets fix this by opening test files, modifying the timestamp and returning an io.Reader
func helperReadSmartDataFileFixTimestamp(t *testing.T, smartDataFilepath string) io.Reader {
metricsfile, err := os.Open(smartDataFilepath)
require.NoError(t, err)
metricsFileData, err := ioutil.ReadAll(metricsfile)
require.NoError(t, err)
//unmarshal because we need to change the timestamp
var smartData collector.SmartInfo
err = json.Unmarshal(metricsFileData, &smartData)
require.NoError(t, err)
smartData.LocalTime.TimeT = time.Now().Unix()
updatedSmartDataBytes, err := json.Marshal(smartData)
return bytes.NewReader(updatedSmartDataBytes)
}
func TestHealthRoute(t *testing.T) {
//setup
parentPath, _ := ioutil.TempDir("", "")
defer os.RemoveAll(parentPath)
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("web.database.location").Return(path.Join(parentPath, "scrutiny_test.db")).AnyTimes()
fakeConfig.EXPECT().GetString("web.src.frontend.path").Return(parentPath).AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.port").Return("8086").AnyTimes()
fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes()
fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes()
if _, isGithubActions := os.LookupEnv("GITHUB_ACTIONS"); isGithubActions {
// when running test suite in github actions, we run an influxdb service as a sidecar.
fakeConfig.EXPECT().GetString("web.influxdb.host").Return("influxdb").AnyTimes()
} else {
fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes()
}
ae := web.AppEngine{
Config: fakeConfig,
}
router := ae.Setup(logrus.New())
var basePathTestCases = []string{
emptyBasePath,
@@ -62,145 +129,146 @@ func TestHealthRoute(t *testing.T) {
}
func TestRegisterDevicesRoute(t *testing.T) {
for _, basePath := range basePathTestCases {
t.Run(fmt.Sprintf(`with basePath "%s"`, basePath), func (tt *testing.T) {
//setup
parentPath, _ := ioutil.TempDir("", "")
mockCtrl := gomock.NewController(tt)
fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("web.database.location").Return(path.Join(parentPath, "scrutiny_test.db")).AnyTimes()
fakeConfig.EXPECT().GetString("web.src.frontend.path").Return(parentPath).AnyTimes()
fakeConfig.EXPECT().GetString("web.src.backend.basepath").Return(basePath).AnyTimes()
ae := web.AppEngine{
Config: fakeConfig,
}
router := ae.Setup(logrus.New())
file, err := os.Open("testdata/register-devices-req.json")
require.NoError(tt, err)
//setup
parentPath, _ := ioutil.TempDir("", "")
defer os.RemoveAll(parentPath)
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("web.database.location").Return(path.Join(parentPath, "scrutiny_test.db")).AnyTimes()
fakeConfig.EXPECT().GetString("web.src.frontend.path").Return(parentPath).AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.port").Return("8086").AnyTimes()
fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes()
fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes()
if _, isGithubActions := os.LookupEnv("GITHUB_ACTIONS"); isGithubActions {
// when running test suite in github actions, we run an influxdb service as a sidecar.
fakeConfig.EXPECT().GetString("web.influxdb.host").Return("influxdb").AnyTimes()
} else {
fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes()
}
//test
w := httptest.NewRecorder()
req, _ := http.NewRequest("POST", basePath + "/api/devices/register", file)
router.ServeHTTP(w, req)
//assert
require.Equal(tt, 200, w.Code)
// tear down
mockCtrl.Finish()
os.RemoveAll(parentPath)
})
ae := web.AppEngine{
Config: fakeConfig,
}
}
func TestUploadDeviceMetricsRoute(t *testing.T) {
for _, basePath := range basePathTestCases {
t.Run(fmt.Sprintf(`with basePath "%s"`, basePath), func(tt *testing.T) {
//setup
parentPath, _ := ioutil.TempDir("", "")
mockCtrl := gomock.NewController(tt)
fakeConfig := mock_config.NewMockInterface(mockCtrl)
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.backend.basepath").Return(basePath).AnyTimes()
ae := web.AppEngine{
Config: fakeConfig,
}
router := ae.Setup(logrus.New())
devicesfile, err := os.Open("testdata/register-devices-single-req.json")
require.NoError(tt, err)
metricsfile, err := os.Open("testdata/upload-device-metrics-req.json")
require.NoError(tt, err)
//test
wr := httptest.NewRecorder()
req, _ := http.NewRequest("POST", basePath + "/api/devices/register", devicesfile)
router.ServeHTTP(wr, req)
require.Equal(tt, 200, wr.Code)
mr := httptest.NewRecorder()
req, _ = http.NewRequest("POST", basePath + "/api/device/0x5000cca264eb01d7/smart", metricsfile)
router.ServeHTTP(mr, req)
require.Equal(tt, 200, mr.Code)
//assert
// tear down
mockCtrl.Finish()
os.RemoveAll(parentPath)
})
//setup
parentPath, _ := ioutil.TempDir("", "")
defer os.RemoveAll(parentPath)
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl)
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.influxdb.port").Return("8086").AnyTimes()
fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes()
fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes()
if _, isGithubActions := os.LookupEnv("GITHUB_ACTIONS"); isGithubActions {
// when running test suite in github actions, we run an influxdb service as a sidecar.
fakeConfig.EXPECT().GetString("web.influxdb.host").Return("influxdb").AnyTimes()
} else {
fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes()
}
ae := web.AppEngine{
Config: fakeConfig,
}
router := ae.Setup(logrus.New())
devicesfile, err := os.Open("testdata/register-devices-single-req.json")
require.NoError(t, err)
metricsfile := helperReadSmartDataFileFixTimestamp(t, "testdata/upload-device-metrics-req.json")
//test
wr := httptest.NewRecorder()
req, _ := http.NewRequest("POST", "/api/devices/register", devicesfile)
router.ServeHTTP(wr, req)
require.Equal(t, 200, wr.Code)
mr := httptest.NewRecorder()
req, _ = http.NewRequest("POST", "/api/device/0x5000cca264eb01d7/smart", metricsfile)
router.ServeHTTP(mr, req)
require.Equal(t, 200, mr.Code)
//assert
}
func TestPopulateMultiple(t *testing.T) {
for _, basePath := range basePathTestCases {
t.Run(fmt.Sprintf(`with basePath "%s"`, basePath), func(tt *testing.T) {
//setup
parentPath, _ := ioutil.TempDir("", "")
mockCtrl := gomock.NewController(tt)
fakeConfig := mock_config.NewMockInterface(mockCtrl)
//fakeConfig.EXPECT().GetString("web.database.location").AnyTimes().Return("testdata/scrutiny_test.db")
fakeConfig.EXPECT().GetStringSlice("notify.urls").Return([]string{}).AnyTimes()
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.backend.basepath").Return(basePath).AnyTimes()
ae := web.AppEngine{
Config: fakeConfig,
}
router := ae.Setup(logrus.New())
devicesfile, err := os.Open("testdata/register-devices-req.json")
require.NoError(tt, err)
metricsfile, err := os.Open("../models/testdata/smart-ata.json")
require.NoError(tt, err)
failfile, err := os.Open("../models/testdata/smart-fail2.json")
require.NoError(tt, err)
nvmefile, err := os.Open("../models/testdata/smart-nvme.json")
require.NoError(tt, err)
scsifile, err := os.Open("../models/testdata/smart-scsi.json")
require.NoError(tt, err)
scsi2file, err := os.Open("../models/testdata/smart-scsi2.json")
require.NoError(tt, err)
//test
wr := httptest.NewRecorder()
req, _ := http.NewRequest("POST", basePath + "/api/devices/register", devicesfile)
router.ServeHTTP(wr, req)
require.Equal(tt, 200, wr.Code)
mr := httptest.NewRecorder()
req, _ = http.NewRequest("POST", basePath + "/api/device/0x5000cca264eb01d7/smart", metricsfile)
router.ServeHTTP(mr, req)
require.Equal(tt, 200, mr.Code)
fr := httptest.NewRecorder()
req, _ = http.NewRequest("POST", basePath + "/api/device/0x5000cca264ec3183/smart", failfile)
router.ServeHTTP(fr, req)
require.Equal(tt, 200, fr.Code)
nr := httptest.NewRecorder()
req, _ = http.NewRequest("POST", basePath + "/api/device/0x5002538e40a22954/smart", nvmefile)
router.ServeHTTP(nr, req)
require.Equal(tt, 200, nr.Code)
sr := httptest.NewRecorder()
req, _ = http.NewRequest("POST", basePath + "/api/device/0x5000cca252c859cc/smart", scsifile)
router.ServeHTTP(sr, req)
require.Equal(tt, 200, sr.Code)
s2r := httptest.NewRecorder()
req, _ = http.NewRequest("POST", basePath + "/api/device/0x5000cca264ebc248/smart", scsi2file)
router.ServeHTTP(s2r, req)
require.Equal(tt, 200, s2r.Code)
//assert
// tear down
mockCtrl.Finish()
os.RemoveAll(parentPath)
})
//setup
parentPath, _ := ioutil.TempDir("", "")
defer os.RemoveAll(parentPath)
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl)
//fakeConfig.EXPECT().GetString("web.database.location").AnyTimes().Return("testdata/scrutiny_test.db")
fakeConfig.EXPECT().GetStringSlice("notify.urls").Return([]string{}).AnyTimes()
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.influxdb.port").Return("8086").AnyTimes()
fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes()
fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes()
if _, isGithubActions := os.LookupEnv("GITHUB_ACTIONS"); isGithubActions {
// when running test suite in github actions, we run an influxdb service as a sidecar.
fakeConfig.EXPECT().GetString("web.influxdb.host").Return("influxdb").AnyTimes()
} else {
fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes()
}
ae := web.AppEngine{
Config: fakeConfig,
}
router := ae.Setup(logrus.New())
devicesfile, err := os.Open("testdata/register-devices-req.json")
require.NoError(t, err)
metricsfile := helperReadSmartDataFileFixTimestamp(t, "../models/testdata/smart-ata.json")
failfile := helperReadSmartDataFileFixTimestamp(t, "../models/testdata/smart-fail2.json")
nvmefile := helperReadSmartDataFileFixTimestamp(t, "../models/testdata/smart-nvme.json")
scsifile := helperReadSmartDataFileFixTimestamp(t, "../models/testdata/smart-scsi.json")
scsi2file := helperReadSmartDataFileFixTimestamp(t, "../models/testdata/smart-scsi2.json")
//test
wr := httptest.NewRecorder()
req, _ := http.NewRequest("POST", "/api/devices/register", devicesfile)
router.ServeHTTP(wr, req)
require.Equal(t, 200, wr.Code)
mr := httptest.NewRecorder()
req, _ = http.NewRequest("POST", "/api/device/0x5000cca264eb01d7/smart", metricsfile)
router.ServeHTTP(mr, req)
require.Equal(t, 200, mr.Code)
fr := httptest.NewRecorder()
req, _ = http.NewRequest("POST", "/api/device/0x5000cca264ec3183/smart", failfile)
router.ServeHTTP(fr, req)
require.Equal(t, 200, fr.Code)
nr := httptest.NewRecorder()
req, _ = http.NewRequest("POST", "/api/device/0x5002538e40a22954/smart", nvmefile)
router.ServeHTTP(nr, req)
require.Equal(t, 200, nr.Code)
sr := httptest.NewRecorder()
req, _ = http.NewRequest("POST", "/api/device/0x5000cca252c859cc/smart", scsifile)
router.ServeHTTP(sr, req)
require.Equal(t, 200, sr.Code)
s2r := httptest.NewRecorder()
req, _ = http.NewRequest("POST", "/api/device/0x5000cca264ebc248/smart", scsi2file)
router.ServeHTTP(s2r, req)
require.Equal(t, 200, s2r.Code)
//assert
}
//TODO: this test should use a recorded request/response playback.
@@ -229,173 +297,168 @@ func TestPopulateMultiple(t *testing.T) {
//}
func TestSendTestNotificationRoute_WebhookFailure(t *testing.T) {
for _, basePath := range basePathTestCases {
t.Run(fmt.Sprintf(`with basePath "%s"`, basePath), func(tt *testing.T) {
//setup
parentPath, _ := ioutil.TempDir("", "")
mockCtrl := gomock.NewController(tt)
fakeConfig := mock_config.NewMockInterface(mockCtrl)
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.backend.basepath").Return(basePath).AnyTimes()
fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{"https://unroutable.domain.example.asdfghj"})
ae := web.AppEngine{
Config: fakeConfig,
}
router := ae.Setup(logrus.New())
//setup
parentPath, _ := ioutil.TempDir("", "")
defer os.RemoveAll(parentPath)
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl)
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.influxdb.port").Return("8086").AnyTimes()
fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes()
fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes()
fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{"https://unroutable.domain.example.asdfghj"})
if _, isGithubActions := os.LookupEnv("GITHUB_ACTIONS"); isGithubActions {
// when running test suite in github actions, we run an influxdb service as a sidecar.
fakeConfig.EXPECT().GetString("web.influxdb.host").Return("influxdb").AnyTimes()
} else {
fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes()
}
//test
wr := httptest.NewRecorder()
req, _ := http.NewRequest("POST", basePath + "/api/health/notify", strings.NewReader("{}"))
router.ServeHTTP(wr, req)
//assert
require.Equal(tt, 500, wr.Code)
// tear down
mockCtrl.Finish()
os.RemoveAll(parentPath)
})
ae := web.AppEngine{
Config: fakeConfig,
}
}
func TestSendTestNotificationRoute_ScriptFailure(t *testing.T) {
for _, basePath := range basePathTestCases {
t.Run(fmt.Sprintf(`with basePath "%s"`, basePath), func(tt *testing.T) {
//setup
parentPath, _ := ioutil.TempDir("", "")
mockCtrl := gomock.NewController(tt)
fakeConfig := mock_config.NewMockInterface(mockCtrl)
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.backend.basepath").Return(basePath).AnyTimes()
fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{"script:///missing/path/on/disk"})
ae := web.AppEngine{
Config: fakeConfig,
}
router := ae.Setup(logrus.New())
//setup
parentPath, _ := ioutil.TempDir("", "")
defer os.RemoveAll(parentPath)
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl)
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.influxdb.port").Return("8086").AnyTimes()
fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes()
fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes()
fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{"script:///missing/path/on/disk"})
if _, isGithubActions := os.LookupEnv("GITHUB_ACTIONS"); isGithubActions {
// when running test suite in github actions, we run an influxdb service as a sidecar.
fakeConfig.EXPECT().GetString("web.influxdb.host").Return("influxdb").AnyTimes()
} else {
fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes()
}
//test
wr := httptest.NewRecorder()
req, _ := http.NewRequest("POST", basePath + "/api/health/notify", strings.NewReader("{}"))
router.ServeHTTP(wr, req)
//assert
require.Equal(tt, 500, wr.Code)
// tear down
mockCtrl.Finish()
os.RemoveAll(parentPath)
})
ae := web.AppEngine{
Config: fakeConfig,
}
}
func TestSendTestNotificationRoute_ScriptSuccess(t *testing.T) {
for _, basePath := range basePathTestCases {
t.Run(fmt.Sprintf(`with basePath "%s"`, basePath), func(tt *testing.T) {
//setup
//setup
parentPath, _ := ioutil.TempDir("", "")
defer os.RemoveAll(parentPath)
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl)
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.backend.basepath").Return(basePath).AnyTimes()
fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{"script:///usr/bin/env"})
ae := web.AppEngine{
Config: fakeConfig,
}
router := ae.Setup(logrus.New())
//setup
parentPath, _ := ioutil.TempDir("", "")
defer os.RemoveAll(parentPath)
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl)
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.influxdb.port").Return("8086").AnyTimes()
fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes()
fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes()
fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{"script:///usr/bin/env"})
if _, isGithubActions := os.LookupEnv("GITHUB_ACTIONS"); isGithubActions {
// when running test suite in github actions, we run an influxdb service as a sidecar.
fakeConfig.EXPECT().GetString("web.influxdb.host").Return("influxdb").AnyTimes()
} else {
fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes()
}
//test
wr := httptest.NewRecorder()
req, _ := http.NewRequest("POST", basePath + "/api/health/notify", strings.NewReader("{}"))
router.ServeHTTP(wr, req)
//assert
require.Equal(t, 200, wr.Code)
})
ae := web.AppEngine{
Config: fakeConfig,
}
}
func TestSendTestNotificationRoute_ShoutrrrFailure(t *testing.T) {
for _, basePath := range basePathTestCases {
t.Run(fmt.Sprintf(`with basePath "%s"`, basePath), func(tt *testing.T) {
//setup
parentPath, _ := ioutil.TempDir("", "")
mockCtrl := gomock.NewController(tt)
fakeConfig := mock_config.NewMockInterface(mockCtrl)
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.backend.basepath").Return(basePath).AnyTimes()
fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{"discord://invalidtoken@channel"})
ae := web.AppEngine{
Config: fakeConfig,
}
router := ae.Setup(logrus.New())
//test
wr := httptest.NewRecorder()
req, _ := http.NewRequest("POST", basePath + "/api/health/notify", strings.NewReader("{}"))
router.ServeHTTP(wr, req)
//assert
require.Equal(tt, 500, wr.Code)
// tear down
mockCtrl.Finish()
os.RemoveAll(parentPath)
})
//setup
parentPath, _ := ioutil.TempDir("", "")
defer os.RemoveAll(parentPath)
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl)
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.influxdb.port").Return("8086").AnyTimes()
fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes()
fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes()
fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{"discord://invalidtoken@channel"})
if _, isGithubActions := os.LookupEnv("GITHUB_ACTIONS"); isGithubActions {
// when running test suite in github actions, we run an influxdb service as a sidecar.
fakeConfig.EXPECT().GetString("web.influxdb.host").Return("influxdb").AnyTimes()
} else {
fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes()
}
ae := web.AppEngine{
Config: fakeConfig,
}
}
func TestGetDevicesSummaryRoute_Nvme(t *testing.T) {
for _, basePath := range basePathTestCases {
t.Run(fmt.Sprintf(`with basePath "%s"`, basePath), func(tt *testing.T) {
//setup
parentPath, _ := ioutil.TempDir("", "")
mockCtrl := gomock.NewController(tt)
fakeConfig := mock_config.NewMockInterface(mockCtrl)
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.backend.basepath").Return(basePath).AnyTimes()
ae := web.AppEngine{
Config: fakeConfig,
}
router := ae.Setup(logrus.New())
devicesfile, err := os.Open("testdata/register-devices-req-2.json")
require.NoError(tt, err)
metricsfile, err := os.Open("../models/testdata/smart-nvme2.json")
require.NoError(tt, err)
//test
wr := httptest.NewRecorder()
req, _ := http.NewRequest("POST", basePath + "/api/devices/register", devicesfile)
router.ServeHTTP(wr, req)
require.Equal(tt, 200, wr.Code)
mr := httptest.NewRecorder()
req, _ = http.NewRequest("POST", basePath + "/api/device/a4c8e8ed-11a0-4c97-9bba-306440f1b944/smart", metricsfile)
router.ServeHTTP(mr, req)
require.Equal(tt, 200, mr.Code)
sr := httptest.NewRecorder()
req, _ = http.NewRequest("GET", basePath + "/api/summary", nil)
router.ServeHTTP(sr, req)
require.Equal(t, 200, sr.Code)
var device dbModels.DeviceWrapper
json.Unmarshal(sr.Body.Bytes(), &device)
//assert
require.Equal(tt, "a4c8e8ed-11a0-4c97-9bba-306440f1b944", device.Data[0].WWN)
require.Equal(tt, "passed", device.Data[0].SmartResults[0].SmartStatus)
// tear down
mockCtrl.Finish()
os.RemoveAll(parentPath)
})
//setup
parentPath, _ := ioutil.TempDir("", "")
defer os.RemoveAll(parentPath)
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeConfig := mock_config.NewMockInterface(mockCtrl)
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.influxdb.port").Return("8086").AnyTimes()
fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes()
fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes()
fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes()
fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{})
if _, isGithubActions := os.LookupEnv("GITHUB_ACTIONS"); isGithubActions {
// when running test suite in github actions, we run an influxdb service as a sidecar.
fakeConfig.EXPECT().GetString("web.influxdb.host").Return("influxdb").AnyTimes()
} else {
fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes()
}
ae := web.AppEngine{
Config: fakeConfig,
}
router := ae.Setup(logrus.New())
devicesfile, err := os.Open("testdata/register-devices-req-2.json")
require.NoError(t, err)
metricsfile := helperReadSmartDataFileFixTimestamp(t, "../models/testdata/smart-nvme2.json")
//test
wr := httptest.NewRecorder()
req, _ := http.NewRequest("POST", "/api/devices/register", devicesfile)
router.ServeHTTP(wr, req)
require.Equal(t, 200, wr.Code)
mr := httptest.NewRecorder()
req, _ = http.NewRequest("POST", "/api/device/a4c8e8ed-11a0-4c97-9bba-306440f1b944/smart", metricsfile)
router.ServeHTTP(mr, req)
require.Equal(t, 200, mr.Code)
sr := httptest.NewRecorder()
req, _ = http.NewRequest("GET", "/api/summary", nil)
router.ServeHTTP(sr, req)
require.Equal(t, 200, sr.Code)
var deviceSummary models.DeviceSummaryWrapper
err = json.Unmarshal(sr.Body.Bytes(), &deviceSummary)
require.NoError(t, err)
//assert
require.Equal(t, "a4c8e8ed-11a0-4c97-9bba-306440f1b944", deviceSummary.Data.Summary["a4c8e8ed-11a0-4c97-9bba-306440f1b944"].Device.WWN)
require.Equal(t, pkg.DeviceStatusFailedScrutiny, deviceSummary.Data.Summary["a4c8e8ed-11a0-4c97-9bba-306440f1b944"].Device.DeviceStatus)
}